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

11

У меня есть 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 или более таких черных перерывов сцены. Время начала и продолжительность должны быть точными до доли секунды. Формат ЧЧ: ММ: СС недостаточно точен.
  3. Затем я смогу вручную дважды проверить эти текстовые файлы, чтобы увидеть, правильно ли они идентифицируют изменения сцены (черные сегменты). Я могу настроить время, если я хочу.
  4. Другой скрипт будет читать каждый файл mp4 и его текстовый файл и разбивать (очень быстро и без потерь) 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.

Райан
источник

Ответы:

11

Вот два сценария 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>и мы хотим исключить их.

Он ищет все черные сцены и записывает метку времени начала и длительность черной сцены в новый файл 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 e.g "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



Ссылки



Делать

  • Спросите у OP, лучше ли формат CSV, чем текстовый файл, как файл с точками обрезки, чтобы вы могли редактировать их в Excel немного проще
    »
  • Реализовать способ форматирования временных меток как [чч]: [мм]: [сс], [миллисекунды], а не только как секунды
    ». Реализовано
  • Реализуйте команду ffmpeg для создания png-файлов мозаики для каждой главы
    »Реализовано
  • Уточните, если этого -c copyдостаточно для сценария ОП или нам нужно полностью перекодировать.
    Похоже, Райан уже на нем .
nixda
источник
Какой исчерпывающий ответ! Я ценю это! К сожалению, я сейчас на Mac, и мне нужно сначала выяснить, как перевести это на Bash.
Райан
Я не смог заставить это работать в PowerShell вообще. Файлы журнала остаются пустыми.
Райан
Я посмотрю, что я могу загрузить, чтобы быть полезным. Следите за обновлениями. Спасибо за интерес!
Райан
Я добавил образец mp4 к вопросу. Спасибо за вашу помощь!
Райан
В целях конфиденциальности я не буду загружать истинный источник MOV. Я хотел бы нарезать его и удалить аудио (как я сделал для mp4). Так что, в любом случае, это не будет настоящий первоисточник. Несмотря на это, он был бы слишком большим для загрузки. И шаг разделения сцены, вероятно, должен произойти в файлах mp4 вместо файлов MOV в любом случае для дискового пространства. Спасибо!
Райан
3

Вот бонус: этот третий скрипт 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)). Да!

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

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

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

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

nixda
источник
Очень круто! Я посмотрю на это. Я сегодня тоже потратил часы, пытаясь добраться select='gt(scene\,0.4)'до работы. И я тоже не смог добраться fps="fps=1/600"до работы. Кстати, у вас есть идеи о superuser.com/questions/725734 ? Большое спасибо за вашу помощь. Я очень рад помочь моей семье обнаружить тонны старых воспоминаний.
Райан
Вы пробовали эти 5 других вариантов кодирования, которые я перечислил внизу ? Я добавил рабочий пример для опции «сцена». Забудьте о фильтре FPS. Мне удалось убрать большую часть размытых больших пальцев :)
nixda
0

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

Тем не менее, у меня были некоторые проблемы с видео, которые не показывают правильное время после этого, и я не мог перейти к определенному времени. Одним из решений было демультиплексирование, а затем мультиплексирование потоков с помощью 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 e.g "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
}

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

Энди Гебауэр
источник
-2

Я надеюсь, что ошибаюсь, но я не думаю, что ваш вопрос возможен. Это может быть возможно при перекодировании видео, но как «простой фрагмент без потерь» я не знаю ни одного способа.

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

Удачи!

tbenz9
источник
Это абсолютно возможно. Вы можете нарезать видео без потерь без проблем (например, с помощью мультиплексора сегментов в ffmpeg , см. Также вики ffmpeg по вырезанию видео ). Любая приличная программа для редактирования видео должна уметь это делать. Единственная проблема - обнаружение изменений сцены.
Slhck
1
На самом деле вы не можете. Самые большие проблемы могут быть ключевыми кадрами. Все клипы должны начинаться с ключевого кадра, чтобы их можно было правильно воспроизвести при воспроизведении даже в инструментах редактирования. Если черные кадры не начинаются с ключевых кадров, то при использовании разрезов без потерь будет несовместимость.
JasonXA