У меня есть короткое видео, и я пытаюсь вырезать все пустые или почти пустые кадры. Это не тот случай, когда меня волнуют перерывы в видео, которые могут быть темными. Я буквально хочу убрать все почти черные рамки.
Что я сначала не понял с ffmpeg, так это то, что фильтры «черный кадр» или «черный детектор» на самом деле не фильтруют. Кажется, они просто показывают вам, что вы можете отфильтровать с помощью других команд.
Каков наилучший способ в «Windows» отфильтровать найденные кадры?
Таким образом, с помощью ffmpeg я на самом деле объединяю прямое и обратное направление одного и того же файла, чем запускаю некоторые фильтры для этих файлов. Смотрите мою текущую команду:
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"
Затем я получаю этот вывод: (В любом случае, это только конец...)
[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%
Итак, что мне делать с этой информацией о черном фрейме в Windows? Или есть лучший метод с фильтром 'blackdetect'?
Вот как это сделать с помощью фильтров blackdetect
и .trim
Во-первых, лучший способ получить blackdetect
вывод — через, ffprobe
потому что он способен записывать структурированные данные, такие как XML
, JSON
или по одному key=value
в строке.
Вы делаете это с помощью внедрения метаданных:
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
Как видите, он возвращает время начала и окончания каждой черной секции. Вы используете возвращенную информацию для trim
сегментов между каждым end
и следующим 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
Вы можете объединить несколько trim
фильтров в одну команду. См. этот ответ для подробного примера.
Чтобы автоматизировать это в Windows, вы можете установить и использовать PowerShell или другой язык сценариев по вашему выбору (PHP, Python и т. д.).
Я собрал скрипт Python, который сделает все это. Генерирует команды ffprobe
и ffmpeg
и запускает их И выводит файл без черных клипов
Репозиторий GitHub: https://github.com/FarisHijazi/deblack
GitHub суть (из архива): 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)
Объединение нескольких ответов вместе:
Роберт Кернке
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
но записи вообще не появляются. Может ли это быть из-за того, что рассматриваемые кадры недостаточно черные, или я что-то не так делаю? Я не понимаю некоторые команды.эргисталь
blackdetect
, проверьте его аргументы и пример на ffmpeg.org/ffmpeg-filters.html#blackdetect . Убедитесь, что у вас также установлена последняя версия,ffmpeg
а не установка дистрибутива по умолчанию.эргисталь
blackdetect
, показывать толькоblack_start
иblack_end
теги, использовать формат вывода по умолчанию-of default
без обертокnw=1
и подавлять весь остальной вывод .-v quiet
Роберт Кернке
-v quiet
и получаю следующее: [Parsed_movie_0 @ 0056f560] Failed to avformat_open_input 'C' [lavfi @ 0056e2a0] Ошибка инициализации фильтра 'movie' с аргументами '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]: Нет такого файла или каталога`Роберт Кернке
-v quiet
сообщений об ошибках.Роберт Кернке
Роберт Кернке
эргисталь
Роберт Кернке
Error initializing filter 'movie' with args
- Альтернативой является копирование в локальный каталог ffprobe/ffmpeg в качестве временного файла, обработка его там, а затем переместите обработанную версию туда, где она мне нужна. Спасибо.Роберт Кернке