Bearbeiten Sie Performance-Videos einfach mit ffmpeg mit Ruby

1. Zuallererst

Als aktueller Trend bei Musik-Playern gibt es einen Trend, bei dem sich Menschen nicht an einem Ort versammeln und zusammen spielen können. Daher nehmen sie jeweils ein Video und bearbeiten es später, um ein Video zu erstellen und es zu veröffentlichen. Ich habe nicht viel Musikwissen und spiele es im Grunde nicht selbst. Es gibt jedoch Leute in meiner Umgebung, die mit Musik zu tun haben, und ich werde oft gebeten, Videos zu bearbeiten. Um dies zu unterstützen, habe ich mit Ruby ffmpeg ausgeführt und eine Umgebung erstellt, in der die Videobearbeitung halbautomatisch durchgeführt werden kann.

ruby_movie_ffmpeg.png

2. Verarbeitungsablauf

Jetzt können auch Personen ohne Wissen problemlos Performance-Videos mit Smartphones aufnehmen. … Das bedeutet aber auch, dass jeder Videos in verschiedenen Formaten, Videogrößen und Bildraten sendet. Ich denke, es gibt einen besseren Weg, um die Verschlechterung des Videos zu verhindern, aber es wird wie folgt schrittweise verarbeitet.

3. Quelle

Da davon ausgegangen wird, dass es in einer Windows-Umgebung ausgeführt wird, sollten diejenigen, die darauf verweisen, vorsichtig sein, wie das Zeichen \ verwendet wird.

movie_on_playing.rb


control_file = ARGV[0]
cfile = File.open(control_file, "r")

def system_log( exe, workd )
  fho = File.open("#{workd}\\log.txt", "a")
  fho.write("#{exe}\n")
  fho.close
  res = system( exe )
  unless(res)
    puts "# Error! ffmpeg failed. See #{workd}\\log.txt to confirm command."
    exit
  end
end

out_width  = 0
out_height = 0
movie      = []
resize     = []
volume     = []
fadein     = []
delay      = []
delay_f    = []
to_time    = []
blackf     = []
crop_xy    = []
crop_size  = []
skip       = []
row_div    = []
row_flag   = true
ri = 0

for s1 in cfile
  next if s1 =~ /^#/
  a1 = s1.chomp.split(" ")
  if(a1[0] == "ffmpeg")
    ffmpeg = a1[1]
    next
  end
  if(a1[0] == "work")
    workd = a1[1]
    next
  end
  if(a1[0] == "out")
    out_file_name = a1[1]
    system("title #{out_file_name}")
    next
  end
  if(a1[0] == "movie")
    movie << a1[1]
    next
  end
  if(a1[0] == "resize")
    resize << a1[1]
    next
  end
  if(a1[0] == "volume")
    volume << a1[1]
    next
  end
  if(a1[0] == "fadein")
    fadein << a1[1]
    next
  end
  if(a1[0] == "delay")
    delay << a1[1]
    delay_f << a1[2] if(a1[1].to_f > 0)
    next
  end
  if(a1[0] == "time")
    to_time << a1[1]
    next
  end
  if(a1[0] == "crop")
    crop_xy << a1[1]
    crop_size << a1[2]
    if(row_div.size == 0)
      out_width = out_width + a1[2].split("x")[0].to_i
    end
    if row_flag
      out_height = out_height + a1[2].split("x")[1].to_i
      row_flag = false
    end
    next
  end
  if(a1[0] == "skip")
    skip << a1[1]
    next
  end
  if(a1[0] == "row_div")
    row_div << movie.size
    row_flag = true
    next
  end
end

cfile.close

Dir.mkdir(workd) unless File.exist?(workd)
efile_mp4 = []
efile_mp3 = []
ovl_vx = 0
ovl_vy = 0
ovl_a = []

fho = File.open("#{workd}\\log.txt", "a")
fho.write("\n#{Time.now}\n")
fho.close

out_width_e = out_width
out_height_e = out_height
fi = 0
w_reset = false
row_div << 9999

for i in 0...movie.size
  filen = movie[i].split("\\")[-1].split(".")[0]
  filee = movie[i].split("\\")[-1].split(".")[1]
  file_rsz = "#{filen}_#{resize[i]}"
  rx = resize[i].split("x")[0]
  ry = resize[i].split("x")[1]
  ####################
  #### resize part ###
  ####################
  
  if(delay[i].to_f > 0.0)
    fade_time = 0
  else
    fade_time = -1 * delay[i].to_f
  end
  if(delay[i].to_f > 0)
    if(fadein[i].to_i > 0)
      fade_in = "fade=in:0:#{fadein[i]},"
    else
      fade_in = ""
    end
    system_log( "#{ffmpeg} -y -i \"#{movie[i]}\" -vf \"#{fade_in}scale=#{rx}:#{ry}\" \"#{workd}\\#{file_rsz}.#{filee}\"", workd ) if(skip[i] == "off")
  else
    system_log( "#{ffmpeg} -y -i \"#{movie[i]}\" -vf \"scale=#{rx}:#{ry}\" \"#{workd}\\#{file_rsz}.#{filee}\"", workd ) if(skip[i] == "off")
  end
  ######################
  ### black mov part ###
  ######################
  if(delay[i].to_f > 0.0)
    dname = delay[i].gsub(".","p")
    bfile = "black_#{resize[i]}_#{dname}.#{filee}"
    if(delay_f[fi] == nil)
      frate = "30000/1001"
    else
      frate = delay_f[fi]
    end
    system_log( "#{ffmpeg} -y -f lavfi -i \"color=c=black:s=#{resize[i]}:r=#{frate}:d=#{delay[i]}\" -f lavfi -i \"aevalsrc=0|0:c=stereo:s=44100:d=#{delay[i]}\" \"#{workd}\\#{bfile}\"", workd ) if(skip[i] == "off")
    blackf << bfile
    fi = fi + 1
  else
    blackf << "black_0"
  end
  #######################
  ### concat/cut part ###
  #######################
  if(blackf[i] != "black_0")
    # add plus delay
    con_filen = "#{workd}\\concat_#{i}.txt"
    con_file = File.open(con_filen, "w")
    con_file.write("file #{workd}/#{blackf[i]}\n")
    con_file.write("file #{workd}/#{file_rsz}.#{filee}\n")
    con_file.close
    file_cn = "#{file_rsz}_con"
    system_log( "#{ffmpeg} -y -safe 0 -f concat -i \"#{con_filen}\" -c:v copy -c:a copy -map 0:v -map 0:a \"#{workd}\\#{file_cn}.#{filee}\"", workd ) if(skip[i] == "off")
  elsif(delay[i].to_f < 0)
    # add minus delay
    cut_time = -1 * delay[i].to_f
    file_ct  = "#{filen}_cut"
    system_log( "#{ffmpeg} -y -i \"#{workd}\\#{file_rsz}.#{filee}\" -ss #{cut_time} \"#{workd}\\#{file_ct}.#{filee}\"", workd ) if(skip[i] == "off")
    file_cn = file_ct
  else
    # not add delay
    file_cn = file_rsz
  end
  ###########################
  ### fade, crop, to part ###
  ###########################

  crop_x = crop_xy[i].split("x")[0]
  crop_y = crop_xy[i].split("x")[1]
  crop_w = crop_size[i].split("x")[0]
  crop_h = crop_size[i].split("x")[1]
  cropt = "crop=#{crop_w}:#{crop_h}:#{crop_x}:#{crop_y}"
  
  if(w_reset)
    out_width_e = out_width
    out_height_e = out_height_e - crop_h.to_i
    w_reset = false
  end

  if( out_width_e - crop_w.to_i > 0 || out_height_e - crop_h.to_i > 0)
    padt = ",pad=#{out_width_e}:#{out_height_e}:0:0"
  else
    padt = ""
  end
  if(to_time[i].to_f > 0)
    tot = "-to #{to_time[i].to_f + delay[i].to_f}"
  else
    tot = ""
  end
  file_crp = "#{file_rsz}_cropped"
  if(delay[i].to_f > 0)
    system_log( "#{ffmpeg} -y -i \"#{workd}\\#{file_cn}.#{filee}\" -vf \"#{cropt}#{padt}\" #{tot} \"#{workd}\\#{file_crp}.#{filee}\"", workd ) if(skip[i] == "off")
  else
    if(fadein[i].to_i > 0)
      fade_in = "fade=in:0:#{fadein[i]},"
    else
      fade_in = ""
    end
    system_log( "#{ffmpeg} -y -i \"#{workd}\\#{file_cn}.#{filee}\" -vf \"#{fade_in}#{cropt}#{padt}\" #{tot} \"#{workd}\\#{file_crp}.#{filee}\"", workd ) if(skip[i] == "off")
  end
  
  out_width_e = out_width_e - crop_w.to_i
  if(row_div.size > 0)
    if(i == row_div[ri] - 1)
      ovl_vx = 0
      ovl_vy = ovl_vy + crop_h.to_i
      ri = ri + 1
      w_reset = true
    else
      ovl_vx = ovl_vx + crop_w.to_i
    end
  else
    ovl_vx = ovl_vx + crop_w.to_i
  end
  ovl_a << [ovl_vx, ovl_vy]
  ############################
  ### mp3 out, volume part ###
  ############################
  vol_e = volume[i].to_f / 100
  system_log( "#{ffmpeg} -y -i \"#{workd}\\#{file_crp}.#{filee}\" -vn -acodec libmp3lame -ar 44100 -ab 256k -af \"volume=#{vol_e}\" \"#{workd}\\#{filen}.mp3\"", workd ) if(skip[i] == "off")
  efile_mp3 << "#{workd}\\#{filen}.mp3"
  efile_mp4 << "#{workd}\\#{file_crp}.#{filee}"
end

####################
### overlay part ###
####################
in_file = ""
for efile in efile_mp4
  in_file = "#{in_file} -i \"#{efile}\""
end
ovlt = ""
for i in 0...ovl_a.size - 1
  if(ovlt == "")
    ovlt = "overlay=x=#{ovl_a[i][0]}:y=#{ovl_a[i][1]}"
  else
    ovlt = "#{ovlt},overlay=x=#{ovl_a[i][0]}:y=#{ovl_a[i][1]}"
  end
end
system_log( "#{ffmpeg} -y#{in_file} -filter_complex \"#{ovlt}\" -an \"#{workd}\\out_movie.#{filee}\"", workd )
######################
### add audio part ###
######################
in_file = ""
for efile in efile_mp3
  in_file = "#{in_file} -i \"#{efile}\""
end
system_log( "#{ffmpeg} -y -i \"#{workd}\\out_movie.#{filee}\" #{in_file} -filter_complex \"amix=inputs=#{efile_mp3.size}:duration=longest:dropout_transition=2\" \"#{out_file_name}\"", workd )

3.1 Control file Eine Steuerdatei wurde erstellt und gelesen, um den Speicherort der Videodatei und die Bearbeitungsmethode anzugeben. Das Folgende ist ein Beispiel. Außerdem wird das Video nach Eingabe des Schlüsselworts "row_div" vertikal statt horizontal verbunden.

control.txt


ffmpeg C:\ffmpeg\bin\ffmpeg.exe
work   work
out    out.mp4

movie  org_data\a-san.mp4
resize 1280x720
volume 100
fadein 60
delay  1.5
time   208.5
crop   0x0 640x720
skip   off

movie  org_data\b-san.mp4
resize 1280x720
volume 120
fadein 60
delay  -2.5
time   212.5
crop   320x0 640x720
skip   off
ruby movie_on_playing.rb control.txt

Mit Befehlen wie werden ffmpeg-Befehle nacheinander generiert und basierend auf den Steuerinformationen ausgeführt.

4. Erläuterung der Verarbeitung

Die Verarbeitung jedes Teils wird gemäß dem Abschnitt ○○ des Kommentarbereichs erläutert.

4.1. Resize part Ändern Sie die Größe des Videos gemäß der Einstellung "Größe ändern" in der Steuerdatei. Setzen Sie den Größenänderungswert nach "scale =" und generieren Sie den folgenden Befehl.

ffmpeg.exe -y -i "org_data\a-san.mp4" -vf "scale=1280:720" "work\a-san_1280x720.mp4"

Wenn der Wert für "Verzögerung" + ist, wird das Video, das zuvor nichts gezeigt hat, verlinkt, sodass auch hier das Einblenden eingestellt wird.

ffmpeg.exe -y -i "org_data\a-san.mp4" -vf "fade=in:0:30,scale=1280:720" "work\a-san_1280x720.mp4"

4.2. Black movie part Wenn der Wert für "Verzögerung" + ist (um den Start des Videos zu verzögern), wird ein Video ohne Video erstellt, wenn für die angegebene Anzahl von Sekunden kein Ton zu hören ist (Hinweis: nicht ohne Ton). Setzen Sie den Wert nach "d =" und generieren Sie den folgenden Befehl.

ffmpeg.exe -y -f lavfi -i "color=c=black:s=1280x720:r=30000/1001:d=1.5" -f lavfi -i "aevalsrc=0|0:c=stereo:s=44100:d=1.5" "work\black_1280x720_1p5.mp4"

Da dieser Vorgang nach der Verkettung zu Problemen im Video führt, kann der Frame in der 3. Spalte mit "Verzögerung [Sekunden] [Framerate]" geändert werden. Diese Methode funktioniert jedoch möglicherweise nicht gut. Wenn Sie ein Video mit ffmpeg bearbeiten, ist es einfacher, mit einem ausreichenden Rand des Originalvideos aufzunehmen und es dann auszuschneiden. Wenn Sie von nun an ein Video aufnehmen möchten, teilen Sie dem Darsteller mit: "Drücken Sie die Aufnahmetaste, warten Sie etwa 5 Sekunden und spielen Sie dann ab."

4.3. Concat/cut part Wenn der Wert von "delay "- ist (um das Video vorzeitig zu starten), setzen Sie ihn in den Wert von" -ss "und generieren Sie den folgenden Befehl.

ffmpeg.exe -y -i "work\a-san_1280x720.mp4" -ss 2.5 "work\a-san_1280x720_cut.mp4"

Wenn der Wert für "Verzögerung" + ist, wird er mit dem vorherigen Video ohne Video verknüpft.

ffmpeg.exe -y -safe 0 -f concat -i "work\concat_1.txt" -c:v copy -c:a copy -map 0:v -map 0:a "work\a-san_1280x720_con.mp4"

4.4. Fade, crop, to part Hier können Sie das Video zuschneiden und die Endzeit angeben. Wenn der Wert für "Verzögerung" ist, stellen Sie hier Einblenden ein. In ffmpeg werden die Größe nach dem Zuschneiden und die Zuschneideposition in dieser Reihenfolge angegeben. Da es jedoch persönlich etwas schwierig zu verstehen war, verwendet die Steuerdatei das Format "Zuschneiden [Zuschneideposition] [Größe nach dem Zuschneiden]". Es wird konvertiert als "Ernte (X1) x (Y1) (X2) x (Y2)" → ffmpeg "Ernte = (X2): (Y2): (X1): (Y1)". Eine der Stärken bei der Verwendung von Ruby ist, dass Sie das Format nach Ihren Wünschen selbst bestimmen können.

Der Wert von "pad =" wird aus der zugeschnittenen Größe jedes Videos berechnet. "-to" wird aus den Werten "Zeit" und "Verzögerung" in der Steuerdatei berechnet.

ffmpeg.exe -y -i "work\a-san_1280x720_cut.mp4" -vf "fade=in:0:30,crop=640:720:0:0,pad=1280:720:0:0" -to 210.0 "work\a-san_1280x720_cropped.mp4"

4.5. Mp3 out, volume part Extrahiert Nur-Ton-Dateien aus zeitgesteuerten Videos (mit -ss und -to). In ffmpeg ist 100% Volumen "1.0", in Kontrolldatei ist 100% "100". Setzen Sie "Einstellwert / 100" nach "volume =" und generieren Sie den folgenden Befehl.

ffmpeg.exe -y -i "work\a-san_1280x720_cropped.mp4" -vn -acodec libmp3lame -ar 44100 -ab 256k -af "volume=1.0" "work\a-san.mp3"

4.6. Overlay part Die individuell angepassten Videos werden per Overlay zu einem Video zusammengefasst. Berechnen Sie aus dem Wert der Ernte und generieren Sie den folgenden Befehl.

ffmpeg.exe -y -i "work\a-san_1280x720_cropped.mp4" -i "work\b-san_1280x720_cropped.mp4" -filter_complex "overlay=x=640:y=0" -an "work\out_movie.mp4"

4.7. Add audio part Geben Sie zum Schluss alle Sounds ein und Sie sind fertig. Halten Sie den MP3-Dateinamen als Array, verbinden Sie sie in der Reihenfolge mit -i, geben Sie die Größe des Arrays als Wert für "amix = input =" ein und generieren Sie den folgenden Befehl.

ffmpeg.exe -y -i "work\out_movie.mp4" -i "work\a-san.mp3" -i "work\a-san.mp3" -filter_complex "amix=inputs=2:duration=longest:dropout_transition=2" "out.mp4"

Dieses "out.mp4" ist ein fertiges Video.

5. Andere

Einer der Hauptnachteile bei der Eingabe von Befehlen in CUI und beim Bearbeiten von Videos besteht darin, dass Sie nicht bearbeiten können, während Sie das Timing und die Lautstärke ansehen oder anhören. Daher ist das mit der obigen Methode erstellte Video

Usw. kann angefordert werden. Um das ** nicht angepasste Video mit dem vorherigen Ergebnis ** zu beschleunigen, erstellen Sie zu diesem Zeitpunkt ein Element mit dem Namen "Überspringen" in der Steuerdatei. Wenn dies "Ein" ist, überspringen Sie die Verarbeitung dieses Videos. Ich mache es.

6. Am Ende

ffmpeg ist ein sehr ausgeklügeltes und benutzerfreundliches Tool, das ich seit langer Zeit verwende, aber es ist eine Menge Arbeit, Dutzende oder Hunderte von Befehlen einzugeben, insbesondere um Informationen in Bezug auf die Videogröße zu berechnen und einzugeben. Wird benötigt. Ich hoffe, dieser Artikel hat Ihnen geholfen, diese Bemühungen zu erleichtern.

Recommended Posts

Bearbeiten Sie Performance-Videos einfach mit ffmpeg mit Ruby
Hinweise zur Verwendung von FCM mit Ruby on Rails
Versuchen Sie es mit einem GPS-Empfänger-Kit mit Raspberry Pi 3 (Ruby).
Fühlen Sie den Grundtyp und Referenztyp leicht mit Rubin
Fühlen Sie den Grundtyp und Referenztyp leicht mit Rubin 2