Wie schneide ich schwarze Rahmen mit ffmpeg unter Windows aus?

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?

Antworten (2)

Hier ist eine Möglichkeit, dies mit den Filtern blackdetectund zu tun.trim

Erstens ist ein besserer Weg, um die blackdetectAusgabe zu erhalten, via ffprobe, da es in der Lage ist, strukturierte Daten wie XML, JSONoder eine key=valuepro 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 trimden Segmenten zwischen jedem endund 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 trimFilter 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.

Ihre Hilfe wird geschätzt und scheint der richtige Weg zu sein. Ich habe jedoch den von Ihnen vorgeschlagenen ffprobe-Befehl ausprobiert: 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 quietEs 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.
@RobertKoernke Ich habe die Standardeinstellungen blackdetectverwendet, überprüfen Sie die Argumente und das Beispiel auf ffmpeg.org/ffmpeg-filters.html#blackdetect . Stellen Sie sicher, dass Sie auch eine aktuelle Version von ffmpegund keine Standard-Distributionsinstallation haben.
Der Befehl bedeutet: do blackdetect, nur black_startund black_endTags anzeigen, das Standardausgabeformat -of defaultohne Wrapper verwenden nw=1und alle anderen Ausgaben unterdrücken-v quiet
btw ... Sie geben mir Windows-Anweisungen richtig? Ok, ich habe das vorübergehend entfernt -v quietund 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`
Das -v quietunterdrückte die Fehlermeldungen.
Ich habe es ... Ich habe das Video in dasselbe Verzeichnis gestellt und es ausgeführt, und es funktioniert. Also werde ich weiter testen..Danke
Ich habe viele verschiedene Artikel in meinen Tests ausprobiert. Oft bekomme ich "Datei nicht gefunden", wenn die Datei eindeutig vorhanden ist. Wie ich gezeigt habe, habe ich alte DOS-Dateitypen ausprobiert. Was verursacht das Problem hier: "movie=C:\Users\INSPIR~1\DOCUME~1\a2d2\A2D2DE~1\MAC_SP~1.com\videos\2013-10-14_14-30-55.mov,blackdetect [out0]"
Wenn Sie einen Pfad innerhalb eines Befehlsarguments verwenden, müssen Sie die Sonderzeichen maskieren oder in Anführungszeichen setzen oder kürzere, einfache Pfade verwenden. ffmpeg.org/ffmpeg-utils.html#toc-Quoting-and-escaping
Kein Escaping \\..\\ scheint zu funktionieren. Es zeigt weiterhin den Fehler: 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.
Endlich herausgefunden, hierher zu entkommen. Ich habe es endlich gebraucht: "movie=\'C:\\Users\\Inspiron 560\\Documents\\temp.wmv\',blackdetect[out0]" Also so... Die oben verlinkte Hilfeseite war vage und tat es nicht zeigen den Weg für ffprobe-movie.

Ich habe ein Python-Skript zusammengestellt, das all dies tun wird. Erzeugt die Befehle ffprobeund ffmpegund 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: