Ich habe ein kurzes Video und versuche, alle leeren oder fast leeren Frames auszuschneiden. Dies ist kein Fall, in dem ich mich um die Unterbrechungen in einem Video kümmere, die dunkel sein könnten. Ich möchte buchstäblich alle fast schwarzen Rahmen aus.
Was mir bei ffmpeg zunächst nicht klar war, war, dass die Filter „Blackframe“ oder „Blackdetect“ nicht wirklich filterten. Sie scheinen Ihnen nur zu zeigen, was Sie möglicherweise mit anderen Befehlen filtern können.
Was ist der beste Weg in 'Windows', um die resultierenden gefundenen Frames tatsächlich herauszufiltern?
Mit ffmpeg konkatiere ich also tatsächlich die Vorwärts- und Rückwärtsrichtung derselben Datei, als ich einige Filter für diese Dateien ausführe. Siehe meinen aktuellen Befehl:
ffmpeg.exe -y -i "2013-10-14_14-30-55.mov" -filter_complex "[0:v]transpose=3,split[tp][tp2];[tp]reverse[vr];[tp2][vr]concat=n=2:v=1:a=0[vbf];[vbf]blackframe=98:32[v]" -map "[v]" -vcodec wmv2 -q 10 -trellis 2 -r 16 "g:\gd5.wmv"
Dann bekomme ich diese Ausgabe: (Nur das Ende davon sowieso ...)
[Parsed_blackframe_4 @ 00000000003bf320] frame:650 pblack:99 pts:21821999 t:21.821999 type:B last_keyframe:639
[Parsed_blackframe_4 @ 00000000003bf320] frame:651 pblack:99 pts:21855366 t:21.855366 type:P last_keyframe:639
[Parsed_blackframe_4 @ 00000000003bf320] frame:652 pblack:99 pts:21888733 t:21.888733 type:B last_keyframe:639
[Parsed_blackframe_4 @ 00000000003bf320] frame:653 pblack:99 pts:21922099 t:21.922099 type:B last_keyframe:639
[Parsed_blackframe_4 @ 00000000003bf320] frame:654 pblack:99 pts:21955466 t:21.955466 type:I last_keyframe:654
[Parsed_blackframe_4 @ 00000000003bf320] frame:655 pblack:99 pts:21988833 t:21.988833 type:B last_keyframe:654
[Parsed_blackframe_4 @ 00000000003bf320] frame:656 pblack:99 pts:22022199 t:22.022199 type:B last_keyframe:654
[Parsed_blackframe_4 @ 00000000003bf320] frame:657 pblack:99 pts:22055566 t:22.055566 type:P last_keyframe:654
[Parsed_blackframe_4 @ 00000000003bf320] frame:658 pblack:99 pts:22088933 t:22.088933 type:B last_keyframe:654
[Parsed_blackframe_4 @ 00000000003bf320] frame:659 pblack:99 pts:22122299 t:22.122299 type:B last_keyframe:654
[Parsed_blackframe_4 @ 00000000003bf320] frame:660 pblack:99 pts:22155666 t:22.155666 type:P last_keyframe:654
[Parsed_blackframe_4 @ 00000000003bf320] frame:661 pblack:99 pts:22189033 t:22.189033 type:B last_keyframe:654
[Parsed_blackframe_4 @ 00000000003bf320] frame:662 pblack:99 pts:22222399 t:22.222399 type:B last_keyframe:654
[Parsed_blackframe_4 @ 00000000003bf320] frame:663 pblack:99 pts:22255766 t:22.255766 type:P last_keyframe:654
[Parsed_blackframe_4 @ 00000000003bf320] frame:664 pblack:99 pts:22289133 t:22.289133 type:B last_keyframe:654
[Parsed_blackframe_4 @ 00000000003bf320] frame:665 pblack:99 pts:22322499 t:22.322499 type:B last_keyframe:654
[Parsed_blackframe_4 @ 00000000003bf320] frame:666 pblack:99 pts:22355866 t:22.355866 type:P last_keyframe:654
[Parsed_blackframe_4 @ 00000000003bf320] frame:667 pblack:99 pts:22389233 t:22.389233 type:B last_keyframe:654
[Parsed_blackframe_4 @ 00000000003bf320] frame:668 pblack:99 pts:22422599 t:22.422599 type:B last_keyframe:654
[Parsed_blackframe_4 @ 00000000003bf320] frame:669 pblack:99 pts:22455966 t:22.455966 type:I last_keyframe:669
frame= 362 fps= 14 q=10.0 Lsize= 9004kB time=00:00:22.62 bitrate=3260.2kbits/s dup=1 drop=309
video:8922kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.918756%
Was mache ich also mit diesen Blackframe-Informationen in Windows? Oder gibt es eine bessere Methode mit dem 'Blackdetect'-Filter?
Hier ist eine Möglichkeit, dies mit den Filtern blackdetect
und zu tun.trim
Erstens ist ein besserer Weg, um die blackdetect
Ausgabe zu erhalten, via ffprobe
, da es in der Lage ist, strukturierte Daten wie XML
, JSON
oder eine key=value
pro Zeile zu schreiben.
Sie tun dies mithilfe von Metadata Injection:
ffprobe -f lavfi -i "movie=/path/to/input.mp4,blackdetect[out0]" -show_entries tags=lavfi.black_start,lavfi.black_end -of default=nw=1 -v quiet TAG:lavfi.black_start=0 TAG:lavfi.black_end=5.42208 TAG:lavfi.black_start=73.4067
Wie Sie sehen können, gibt es die Start- und Endzeit jedes schwarzen Abschnitts zurück. Sie verwenden die zurückgegebenen Informationen zu trim
den Segmenten zwischen jedem end
und dem nächsten start
:
ffmpeg -i /path/to/input.mp4 -filter_complex "[0:v]trim=start=5.42208:end=73.4067,setpts=PTS-STARTPTS[v1];[0:a]atrim=start=5.42208:end=73.4067,asetpts=PTS-STARTPTS[a1]" -map [v1] -map [a1] output.mp4
Sie können mehrere trim
Filter im selben Befehl verketten. Siehe diese Antwort für ein detailliertes Beispiel.
Um dies in Windows zu automatisieren, können Sie PowerShell oder eine andere Skriptsprache Ihrer Wahl (PHP, Python usw.) installieren und verwenden.
Ich habe ein Python-Skript zusammengestellt, das all dies tun wird. Erzeugt die Befehle ffprobe
und ffmpeg
und führt sie aus und gibt eine Datei ohne schwarze Clips aus
GitHub-Repository: https://github.com/FarisHijazi/deblack
GitHub-Zusammenfassung (archiviert): https://gist.github.com/FarisHijazi/eff7a7979440faa84a63657e085ec504
"""
@author: https://github.com/FarisHijazi
Use ffprobe to extract black frames and ffmpeg to trim them and output a new video
"""
# help from:
# https://video.stackexchange.com/questions/16564/how-to-trim-out-black-frames-with-ffmpeg-on-windows#new-answer?newreg=d534934be5774bd1938b535cd76608cd
# https://github.com/kkroening/ffmpeg-python/issues/184#issuecomment-493847192
import argparse
import os
import shlex
import subprocess
parser = argparse.ArgumentParser(__doc__, formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('input', type=str, help='input video file')
parser.add_argument('--invert', action='store_true', help='remove nonblack instead of removing black')
args = parser.parse_args()
##FIXME: sadly you must chdir so that the ffprobe command will work
os.chdir(os.path.split(args.input)[0])
args.input = os.path.split(args.input)[1]
spl = args.input.split('.')
outpath = '.'.join(spl[:-1]) + '.' + ('invert' if args.invert else '') + 'out.' + spl[-1]
def delete_back2back(l):
from itertools import groupby
return [x[0] for x in groupby(l)]
def construct_ffmpeg_trim_cmd(timepairs, inpath, outpath):
cmd = f'ffmpeg -i "{inpath}" -y -filter_complex '
cmd += '"'
for i, (start, end) in enumerate(timepairs):
cmd += (f"[0:v]trim=start={start}:end={end},setpts=PTS-STARTPTS,format=yuv420p[{i}v]; " +
f"[0:a]atrim=start={start}:end={end},asetpts=PTS-STARTPTS[{i}a]; ")
for i, (start, end) in enumerate(timepairs):
cmd += f"[{i}v][{i}a]"
cmd += f'concat=n={len(timepairs)}:v=1:a=1[outv][outa]'
cmd += '"'
cmd += f' -map [outv] -map [outa] "{outpath}"'
return cmd
def get_blackdetect(inpath, invert=False):
ffprobe_cmd = f"ffprobe -f lavfi -i \"movie={inpath},blackdetect[out0]\" -show_entries tags=lavfi.black_start,lavfi.black_end -of default=nw=1 -v quiet"
print('ffprobe_cmd:', ffprobe_cmd)
lines = subprocess.check_output(shlex.split(ffprobe_cmd)).decode('utf-8').split('\n')
times = [float(x.split('=')[1].strip()) for x in delete_back2back(lines) if x]
assert len(times), 'no black detected'
if not invert:
times = [0] + times[:-1]
timepairs = [(times[i], times[i + 1]) for i in range(0, len(times) // 2, 2)]
return timepairs
timepairs = get_blackdetect(args.input, invert=args.invert)
cmd = construct_ffmpeg_trim_cmd(timepairs, args.input, outpath)
print(cmd)
os.system(cmd)
Mehrere Antworten miteinander kombinieren:
Robert Körke
ffprobe -f lavfi -i "movie=2013-10-14_14-30-55.mov,blackdetect[out0]" -show_entries tags=lavfi.black_start,lavfi.black_end -of default=nw=1 -v quiet
Es werden jedoch überhaupt keine Einträge angezeigt. Kann das daran liegen, dass die betreffenden Rahmen nicht schwarz genug sind, oder mache ich das falsch? Ich verstehe einige Befehle nicht.aergistal
blackdetect
verwendet, überprüfen Sie die Argumente und das Beispiel auf ffmpeg.org/ffmpeg-filters.html#blackdetect . Stellen Sie sicher, dass Sie auch eine aktuelle Version vonffmpeg
und keine Standard-Distributionsinstallation haben.aergistal
blackdetect
, nurblack_start
undblack_end
Tags anzeigen, das Standardausgabeformat-of default
ohne Wrapper verwendennw=1
und alle anderen Ausgaben unterdrücken-v quiet
Robert Körke
-v quiet
und bekomme Folgendes: [Parsed_movie_0 @ 0056f560] Failed to avformat_open_input 'C' [lavfi @ 0056e2a0] Error initializing filter 'movie' with args 'C:UsersDOCUME~12013-10-14_14-30-55. mov' movie=C:\Users\DOCUME~1\2013-10-14_14-30-55.mov,blackdetect=d=0:pix_th=51.80[out0]: No such file or directory`Robert Körke
-v quiet
unterdrückte die Fehlermeldungen.Robert Körke
Robert Körke
aergistal
Robert Körke
Error initializing filter 'movie' with args
- Die Alternative ist, dass ich sie als temporäre Datei in das lokale ffprobe/ffmpeg-Verzeichnis kopieren und dort verarbeiten werde. und dann die verarbeitete Version dorthin verschieben, wo ich sie brauche. Danke.Robert Körke