Автоматически разделять большие .mov видеофайлы на более мелкие файлы на черных кадрах (смена сцены)?

У меня 65.mov видеофайлов с именем tape_01.mov, tape_02.mov, …, tape_65.mov. Каждый из них составляет около 2,5 часов и занимает много гигабайт. Это цифровые копии того, что было VHS-лентами (домашними фильмами моей семьи).

Каждый 2.5-часовый видеофайл .mov содержит много «глав» (в том смысле, что иногда сцена заканчивается на увядке с черным экраном, а затем исчезает новая сцена).

Моя главная цель – иметь 65 больших файлов, разрезанных на меньшие файлы по разделам. И я хочу, чтобы это было сделано автоматически через обнаружение черных кадров между «сценами».

Могу ли я использовать ffmpeg (или что-нибудь еще) для передачи в 65 оригинальных имен файлов и автоматически перебирать их по каждому видео и рубить его, называя результирующие фигуры tape_01-ch_01.mov, tape_01-ch_02.mov, tape_01-ch_03.mov, и т.д? И я хочу, чтобы это делалось без повторного кодирования (я хочу, чтобы это был простой фрагмент без потерь).

Как я могу это сделать?

Вот шаги, которые я хочу:

  1. Перейдите по папке .mov-файлов (с именем tape_01.mov, tape_02.mov, …, tape_65.mov), чтобы экспортировать их в виде файлов mp4 (с именем tape_01.mp4, tape_02.mp4, …, tape_65.mp4) , Я хочу, чтобы настройки сжатия были легко настраиваться для этого шага. Исходные .mov-файлы должны по-прежнему существовать после создания файлов .mp4.
  2. Итерации над файлами mp4: для каждого файла mp4 сгенерируйте текстовый файл, который указывает время начала и продолжительность черных сегментов между «сценами». Каждый mp4 может иметь 0 или более из этих черных разрывов сцены. Время начала и продолжительность должны быть точными до доли секунды. HH: MM: формат SS недостаточно точен.
  3. Затем я смогу вручную дважды проверить эти текстовые файлы, чтобы определить, правильно ли они определяют изменения сцены (черные сегменты). Я могу настроить тайминги, если захочу.
  4. Другой скрипт будет читать каждый файл mp4 и его txt-файл и разделять (в супербыстро и без потерь) mp4 на столько частей, сколько необходимо, на основе строк текстового файла (указанные там тайминги). Разделения должны происходить в середине каждого черного сегмента. Вот пример файла mp4 (со звуком, удаленным для целей конфиденциальности), который имеет изменения сцены с изменением цвета. Оригинальные файлы mp4 должны оставаться нетронутыми, так как создаются файлы меньшего размера mp4. Меньшие файлы mp4 должны иметь схему именования tape_01_001.mp4, tape_01_002.mp4, tape_01_003.mp4 и т. Д.
  5. Бонус! Было бы здорово, если бы другой скрипт мог затем перебирать небольшие файлы mp4 и генерировать одно .png изображение для каждого, что является мозаикой скриншотов, как этот человек пытается: Значимые миниатюры для видео с использованием FFmpeg

Я бы хотел, чтобы эти сценарии были сценариями оболочки, которые можно запускать в Mac, Ubuntu и Windows Git Bash.

Вот два сценария PowerShell для разделения длинных видео на более мелкие главы черными сценами.

Сохраните их как Detect_black.ps1 и Cut_black.ps1. Скачайте ffmpeg для Windows и сообщите сценарию путь к файлу ffmpeg.exe и вашей видеопанели в разделе параметров.

Введите описание изображения здесь

Оба сценария не будут касаться существующих видеофайлов, они остаются нетронутыми.
Тем не менее, вы получите пару новых файлов в том же месте, где ваши входные видеоролики будут

  • Файл журнала на видео с выходом консоли для обеих команд ffmpeg
  • CSV-файл на видео со всеми отметками времени черного для ручной точной настройки
  • Несколько новых видеороликов в зависимости от того, сколько черных сцен обнаружено ранее

Введите описание изображения здесь

Первый скрипт для запуска: Detect_black.ps1

### Options __________________________________________________________________________________________________________ $ffmpeg = ".\ffmpeg.exe" # Set path to your ffmpeg.exe; Build Version: git-45581ed (2014-02-16) $folder = ".\Videos\*" # Set path to your video folder; '\*' must be appended $filter = @("*.mov","*.mp4") # Set which file extensions should be processed $dur = 4 # Set the minimum detected black duration (in seconds) $pic = 0.98 # Set the threshold for considering a picture as "black" (in percent) $pix = 0.15 # Set the threshold for considering a pixel "black" (in luminance) ### Main Program ______________________________________________________________________________________________________ foreach ($video in dir $folder -include $filter -exclude "*_???.*" -r){ ### Set path to logfile $logfile = "$($video.FullName)_ffmpeg.log" ### analyse each video with ffmpeg and search for black scenes & $ffmpeg -i $video -vf blackdetect=d=`"$dur`":pic_th=`"$pic`":pix_th=`"$pix`" -an -f null - 2> $logfile ### Use regex to extract timings from logfile $report = @() Select-String 'black_start:.*black_end:' $logfile | % { $black = "" | Select start, end, cut # extract start time of black scene $start_s = $_.line -match '(?<=black_start:)\S*(?= black_end:)' | % {$matches[0]} $start_ts = [timespan]::fromseconds($start_s) $black.start = "{0:HH:mm:ss.fff}" -f ([datetime]$start_ts.Ticks) # extract duration of black scene $end_s = $_.line -match '(?<=black_end:)\S*(?= black_duration:)' | % {$matches[0]} $end_ts = [timespan]::fromseconds($end_s) $black.end = "{0:HH:mm:ss.fff}" -f ([datetime]$end_ts.Ticks) # calculate cut point: black start time + black duration / 2 $cut_s = ([double]$start_s + [double]$end_s) / 2 $cut_ts = [timespan]::fromseconds($cut_s) $black.cut = "{0:HH:mm:ss.fff}" -f ([datetime]$cut_ts.Ticks) $report += $black } ### Write start time, duration and the cut point for each black scene to a seperate CSV $report | Export-Csv -path "$($video.FullName)_cutpoints.csv" –NoTypeInformation } 

Как это работает

Первый скрипт выполняет итерацию по всем видеофайлам, которые соответствуют указанному расширению и не соответствуют шаблону *_???.* , Поскольку новые главы видео были названы <filename>_###.<ext> и мы хотим исключить их.

Он ищет все черные сцены и записывает начальную <video_name>_cutpoints.txt метку и длительность черной сцены в новый CSV-файл с именем <video_name>_cutpoints.txt

Он также вычисляет точки резания, как показано: cutpoint = black_start + black_duration / 2 . Позже видео сегментируется на этих временных отметках.

Файл cutpoints.txt для вашего примера видео покажет:

 start end cut 00:03:56.908 00:04:02.247 00:03:59.578 00:08:02.525 00:08:10.233 00:08:06.379 

После прогона вы можете вручную манипулировать пунктами резки, если хотите. Если вы снова запустите скрипт, весь старый контент будет перезаписан. Будьте осторожны при ручном редактировании и сохранении вашей работы в другом месте.

Для примера видео команда ffmpeg для обнаружения черных сцен

 $ffmpeg -i "Tape_10_3b.mp4" -vf blackdetect=d=4:pic_th=0.98:pix_th=0.15 -an -f null 

Есть 3 важных номера, которые редактируются в разделе параметров скрипта

  • d=4 означает, что обнаружены только черные сцены более 4 секунд
  • pic_th=0.98 является порогом для рассмотрения изображения как «черного» (в процентах)
  • pix=0.15 устанавливает порог для рассмотрения пикселя как «черного» (в яркости). Поскольку у вас есть старые видео VHS, у вас нет абсолютно черных сцен в ваших видео. Значение по умолчанию 10 не будет работать, и мне пришлось немного увеличить порог

Если что-то пойдет не так, проверьте соответствующий файл журнала с именем <video_name>__ffmpeg.log . Если отсутствуют следующие строки, увеличьте числа, упомянутые выше, до тех пор, пока вы не обнаружите все черные сцены:

 [blackdetect @ 0286ec80] black_start:236.908 black_end:242.247 black_duration:5.33877 

Второй скрипт для запуска: cut_black.ps1

 ### Options __________________________________________________________________________________________________________ $ffmpeg = ".\ffmpeg.exe" # Set path to your ffmpeg.exe; Build Version: git-45581ed (2014-02-16) $folder = ".\Videos\*" # Set path to your video folder; '\*' must be appended $filter = @("*.mov","*.mp4") # Set which file extensions should be processed ### Main Program ______________________________________________________________________________________________________ foreach ($video in dir $folder -include $filter -exclude "*_???.*" -r){ ### Set path to logfile $logfile = "$($video.FullName)_ffmpeg.log" ### Read in all cutpoints from *_cutpoints.csv; concat to string eg "00:03:23.014,00:06:32.289,..." $cuts = ( Import-Csv "$($video.FullName)_cutpoints.csv" | % {$_.cut} ) -join "," ### put together the correct new name, "%03d" is a generic number placeholder for ffmpeg $output = $video.directory.Fullname + "\" + $video.basename + "_%03d" + $video.extension ### use ffmpeg to split current video in parts according to their cut points & $ffmpeg -i $video -f segment -segment_times $cuts -c copy -map 0 $output 2> $logfile } 

Как это работает

Второй скрипт выполняет итерацию по всем видеофайлам таким же образом, как это сделал первый скрипт. Он считывает только временные метки среза из соответствующего cutpoints.txt видео.

Затем он сопоставляет подходящее имя файла для файлов глав и сообщает ffmpeg о сегменте видео. В настоящее время видео разрезаются без повторного кодирования (сверхбыстрые и без потерь). Из-за этого может возникнуть погрешность с точностью до 1-2 с временными метками точки вырезания, поскольку ffmpeg может только разрезать на key_frames. Поскольку мы просто копируем и не перекодируем, мы не можем вставлять key_frames самостоятельно.

Команда для образца видео будет

 $ffmpeg -i "Tape_10_3b.mp4" -f segment -segment_times "00:03:59.578,00:08:06.379" -c copy -map 0 "Tape_10_3b_(%03d).mp4" 

Если что-то пойдет не так, посмотрите на соответствующий ffmpeg.log

Рекомендации

  • FFmpeg скачать бесплатно для Windows
  • Сегментная документация: segment_times и segment_frames – это параметры

Делать

  • Задайте OP, если формат CSV лучше, чем текстовый файл, как файл точки, так что вы можете редактировать их с помощью Excel немного проще
    »Выполнено
  • Реализовать способ форматирования временных меток как [hh]: [mm]: [ss], [миллисекунды], а не только секунды
    »Выполнено
  • Внедрить команду ffmpeg для создания файлов mosaik png для каждой главы
    »Выполнено
  • Разработайте, если для сценария OP достаточно -c copy , или нам нужно полностью перекодировать.
    Похоже, Райан уже на нем .

Вот бонус: этот третий скрипт PowerShell создает мозаичное миниатюрное изображение

Вы получите одно изображение на видео главы, все из которых выглядят как пример ниже.

 ### Options __________________________________________________________________________________________________________ $ffmpeg = ".\ffmpeg.exe" # Set path to your ffmpeg.exe; Build Version: git-45581ed (2014-02-16) $folder = ".\Videos\*" # Set path to your video folder; '\*' must be appended $x = 5 # Set how many images per x-axis $y = 4 # Set how many images per y-axis $w = 384 # Set thumbnail width in px (full image width: 384px x 5 = 1920px,) ### Main Program ______________________________________________________________________________________________________ foreach ($video in dir $folder -include "*_???.mp4" -r){ ### get video length in frames, an ingenious method $log = & $ffmpeg -i $video -vcodec copy -an -f null $video 2>&1 $frames = $log | Select-String '(?<=frame=.*)\S+(?=.*fps=)' | % { $_.Matches } | % { $_.Value } $frame = [Math]::floor($frames / ($x * $y)) ### put together the correct new picture name $output = $video.directory.Fullname + "\" + $video.basename + ".jpg" ### use ffmpeg to create one mosaic png per video file ### Basic explanation for -vf options: http://trac.ffmpeg.org/wiki/FilteringGuide #1 & $ffmpeg -y -i $video -vf "select=not(mod(n\,`"$frame`")),scale=`"$w`":-1,tile=`"$x`"x`"$y`"" -frames:v 1 $output #2 & $ffmpeg -y -i $video -vf "yadif,select=not(mod(n\,`"$frame`")),scale=`"$w`":-1,tile=`"$x`"x`"$y`"" -frames:v 1 $output & $ffmpeg -y -i $video -vf "mpdecimate,yadif,select=not(mod(n\,`"$frame`")),scale=`"$w`":-1,tile=`"$x`"x`"$y`"" -frames:v 1 $output #4 & $ffmpeg -y -i $video -vf "select='gt(scene\,0.06)',scale=`"$w`":-1,tile=`"$x`"x`"$y`"" -frames:v 1 -vsync vfr $output #5 & $ffmpeg -y -i $video -vf "yadif,select='gt(scene\,0.06)',scale=`"$w`":-1,tile=`"$x`"x`"$y`"" -frames:v 1 -vsync vfr $output #6 & $ffmpeg -y -i $video -vf "mpdecimate,yadif,select='gt(scene\,0.06)',scale=`"$w`":-1,tile=`"$x`"x`"$y`"" -frames:v 1 -vsync vfr $output #7 & $ffmpeg -y -i $video -vf "thumbnail,scale=`"$w`":-1,tile=`"$x`"x`"$y`"" -frames:v 1 $output #8 & $ffmpeg -y -i $video -vf "yadif,thumbnail,scale=`"$w`":-1,tile=`"$x`"x`"$y`"" -frames:v 1 $output #9 & $ffmpeg -y -i $video -vf "mpdecimate,yadif,thumbnail,scale=`"$w`":-1,tile=`"$x`"x`"$y`"" -frames:v 1 $output } 

Основная идея – получить непрерывный поток изображений по всему видео. Мы делаем это с помощью опции выбора ffmpeg.

Во-первых, мы получаем полный счетчик кадров с помощью изобретательного метода (например, 2000) и делим его на наш счет по умолчанию (например, 5 x 4 = 20). Поэтому мы хотим создать одно изображение каждые 100 кадров с 2000 / 20 = 100

Полученная команда ffmpeg для создания миниатюры может выглядеть так:

 ffmpeg -y -i input.mp4 -vf "mpdecimate,yadif,select=not(mod(n\,100)),scale=384:-1,tile=5x4" -frames:v 1 output.png 

В приведенном выше коде вы видите 9 различных комбинаций -vf состоящих из

  • select=not(mod(n\,XXX)) где XXX – вычисленная частота кадров
  • thumbnail которая автоматически выбирает наиболее представительные кадры
  • select='gt(scene\,XXX) + -vsync vfr где XXX – это порог, с которым вы должны играть
  • mpdecimate – Удалять почти дублированные фреймы. Хорошо против черных сцен
  • yadif – Деинтерлейсировать входное изображение. Не знаю почему, но он работает

Версия 3 – лучший выбор, на мой взгляд. Все остальные закомментированы, но вы все еще можете попробовать их. Я смог удалить большинство размытых миниатюр, используя mpdecimate , yadif и select=not(mod(n\,XXX)) . Да!

Для вашего образца видео я получаю эти превью

Введите описание изображения здесь
нажмите, чтобы увеличить

Введите описание изображения здесь
нажмите, чтобы увеличить

Я загрузил все миниатюры, созданные этими версиями. Посмотрите на них для полного сравнения.

Оцените оба сценария, отличный способ разделить видео.

Тем не менее, у меня были проблемы с видеороликами, которые не показывали правильное время после этого, и я не смог перейти к определенному времени. Одним из решений было demux, а затем mux-потоки с использованием Mp4Box.

Другим, более простым способом для меня было использование mkvmerge для разделения. Поэтому оба сценария должны были быть изменены. Для detect_black.ps1 в параметр фильтра нужно было добавить только «* .mkv», но это не обязательно, если вы начинаете только с файлов mp4.

 ### Options $mkvmerge = ".\mkvmerge.exe" # Set path to mkvmerge.exe $folder = ".\*" # Set path to your video folder; '\*' must be appended $filter = @("*.mov", "*.mp4", "*.mkv") # Set which file extensions should be processed ### Main Program foreach ($video in dir $folder -include $filter -exclude "*_???.*" -r){ ### Set path to logfile $logfile = "$($video.FullName)_ffmpeg.log" ### Read in all cutpoints from *_cutpoints.csv; concat to string eg "00:03:23.014,00:06:32.289,..." $cuts = ( Import-Csv "$($video.FullName)_cutpoints.csv" | % {$_.cut} ) -join "," ### put together the correct new name, "%03d" is a generic number placeholder for mkvmerge $output = $video.directory.Fullname + "\" + $video.basename + "-%03d" + ".mkv" ### use mkvmerge to split current video in parts according to their cut points and convert to mkv & $mkvmerge -o $output --split timecodes:$cuts $video } 

Функция такая же, но никаких проблем с видеороликами пока нет. Спасибо за вдохновение.

Надеюсь, я ошибаюсь, но я не думаю, что ваше задание возможно. Возможно, это будет возможно при повторном кодировании видео, но как «простой кусочек без потерь», я не знаю никоим образом.

Многие программы редактирования видео будут иметь функцию автоматического анализа или что-то эквивалентное, которое может разделить ваши видео на черных кадрах, но для этого потребуется повторное кодирование видео.

Удачи!

  • Как удалить несколько сегментов из видео с помощью FFmpeg?
  • Недействительная спецификация продолжительности с FFMPEG - что может быть причиной?
  • Текст цикла, который стирает слева направо, используя фильтр FFMPEG drawtext
  • Рабочий способ сделать видео с изображений в C #
  • Объединение нескольких файлов WAV с использованием одной команды без дополнительного файла
  • Резервное / автономное потоковое изображение с ffmpeg / nginx RTMP
  • Какие кодеки наиболее подходят для воспроизведения с помощью Windows Media Player в Windows XP?
  • Почему FFmpeg добавляет пустое черное видео в конец моих файлов MP4 при сжатии из MOV?
  • ffmpeg C API-документация / учебник
  • Как создать синусоидальную волну с ffmpeg?
  • Как конвертировать RGB из YUV420p для ffmpeg encoder?
  • Давайте будем гением компьютера.