Может ли ffmpeg записать тайм-код?

Мне нужно записать временной код в видео, и мне интересно, на что способен ffmpeg?


person spinon    schedule 03.07.2010    source источник
comment
Итак, я предполагаю, что вы хотите записать текущее время видео в само видео? Или вы хотите использовать libav* для добавления текста к видео со своим собственным временным кодом?   -  person rogerdpack    schedule 03.12.2013


Ответы (7)


Короткий ответ, нет.

Длинный ответ, да, но не без использования отдельной библиотеки для создания кадров с отображаемым временным кодом на них, с прозрачностью, заполняющей остальную часть кадра, а затем с использованием FFmpeg для наложения кадров на существующее видео. Навскидку я не знаю, как это сделать, но я уверен, что если вы творческий человек, вы можете понять это.

Редактировать: я работаю над этой проблемой, потому что это интересный вопрос/проект для меня. Я немного продвинулся в решении, написав скрипт Perl, который будет генерировать .srt файл со встроенным временным кодом в нем для любого данного видеофайла, из которого FFmpeg настроен на чтение метаданных. Он использует библиотеку Video::FFmpeg для чтения длительности и сохраняет файл субтитров как ${video}.srt. Это сделает так, что он будет автоматически отображаться в Mplayer, если вы вставите следующие строки в свой ~/.mplayer/config:

# select subtitle files automatically in the current directory, all files
# matching the basename of the current playing file
sub-fuzziness=1

Все еще работаю над тем, как расположить и наложить отрендеренные субтитры на видео и перекодировать в том же формате. Я обновлю этот пост, когда узнаю больше.

person amphetamachine    schedule 03.07.2010
comment
Это интересный подход. Любые зацепки библиотек, которые могут это сделать? Если нет, я могу осмотреться. - person spinon; 03.07.2010
comment
Я должен добавить одну вещь, поскольку вы, очевидно, проделываете здесь большую работу. Это то, что я в конечном итоге хочу сделать, это создать новое видео с присутствующими на нем временными кодами. Поэтому не просто воспроизводите их в плеере, а создавайте новое видео, чтобы его можно было воспроизвести в любом плеере. Я добавлю щедрость к вопросу, так как вы приложили к этому столько усилий. - person spinon; 06.07.2010
comment
Очевидно, теперь это возможно с видеофильтрами. См. gist.github.com/reidransom/2630650. - person Neil Slater; 12.10.2016

У меня работает фильтр drawtext FFMPEG, вы указываете начальный тайм-код и его формат таким образом:

-vf drawtext="fontsize=15:fontfile=/Library/Fonts/DroidSansMono.ttf:\
timecode='00\:00\:00\:00':rate=25:text='TCR\:':fontsize=72:fontcolor='white':\
boxcolor=0x000000AA:box=1:x=860-text_w/2:y=960"

вы должны указать формат тайм-кода в виде чч:мм:сс[:;,]ff. Обратите внимание, что вы должны избегать двоеточий в строке формата тайм-кода, и вы должны указать скорость тайм-кода (здесь 25fps). Также можно указать дополнительный текст — здесь это «TCR:»

Вы можете получить частоту кадров с помощью ffprobe и немного шелл-фу:

frame_rate=$(ffprobe -i "movie.mov" -show_streams 2>&1|grep fps|sed "s/.*, \([0-9.]*\) fps,.*/\1/")

Таким образом, вы можете легко объединить все это в сценарий пакетной обработки, например

for i in *.mov
frame_rate=$(ffprobe -i "$i" -show_streams 2>&1|grep fps|sed "s/.*, \([0-9.]*\) fps,.*/\1/")
clipname=${(basename "$i")/\.*/}
ffmpeg -i "$i" -vcodec whatever -acodec whatever \
-vf drawtext="fontsize=15:fontfile=/Library/Fonts/DroidSansMono.ttf:\
timecode='00\:00\:00\:00':rate=$frame_rate:text='$clipname' TCR:':\
fontsize=72:fontcolor='white':boxcolor=0x000000AA:\
box=1:x=860-text_w/2:y=960" "${i/.mov/_tc.mov}"
done

Это добавит название клипа и скользящий тайм-код в полупрозрачное поле внизу по центру кадра 1920x1080.

Редактировать Поскольку я перешел на темную сторону, теперь я делаю это в среде Windows Powershell, и вот что я использую:

ls -R -File -filter *.M*|%{
ffmpeg -n -i $_.fullname -vf drawtext="fontsize=72:x=12:y=12:`
timecode='00\:00\:00\:00':rate=25:fontcolor='white':`
boxcolor=0x000000AA:box=1" `
("c:\path\to\destination\{0}" -F ($_.name -replace 'M[OPT][V4S]', 'mp4'))}

Это создает файлы mp4 с учетом папки, содержащей файлы .MOV, .MP4 и .MTS (используя команду -filter, она ищет файлы с *.M* в имени, которое вам пришлось бы изменить, если бы вы делали файлы .AVI), и это немного более минималистично, он просто использует libx264 с настройками по умолчанию в качестве выходного кодека и не указывает шрифт и т. д. Тайм-код в этом случае записывается в левом верхнем углу кадра.

person stib    schedule 03.09.2012
comment
Хорошая идея, к сожалению, она не работает с дробями типа 12.34 fps. - person Lekensteyn; 01.12.2013
comment
На самом деле похоже, что это работает только для стандартного frame_rate, например, 25, пришлось перекодировать, да и то, время было почему-то неправильное для меня. - person ntg; 05.12.2014
comment
в пакетном скрипте была опечатка, которая заставляла его использовать 25 кадров в секунду, теперь это исправлено. Посмотрите, как это происходит. - person stib; 17.02.2015
comment
Также @ntg, вам придется перекодировать. Вы не можете изменить содержимое видео растра без перекодирования. - person stib; 17.02.2015
comment
Я не уверен, как бы вы сделали это с ffprobe, но параметр rate работает, если вы укажете его как рациональное, поэтому, если вы скажете 24000/1001, это сработает для меня. - person iluvcapra; 15.06.2021

Фильтр drawtext, упомянутый в ответ @stib является ключом для вставки времени. Однако использование опции timecode не соответствует времени настенных часов. Если вы ошибетесь с параметром r (timecode_rate), ваше время не будет соответствовать времени воспроизведения.

Существуют и другие параметры, например, параметр text='%{prt}' позволяет отображать прошедшее время с точностью до микросекунды. Команда:

ffmpeg -i video.mp4 -vf "drawtext=text='%{prt}'" output.mp4

Чтобы вместо этого получить часы, мне пришлось использовать устаревшую опцию strftime. У него есть недокументированная опция basetime, которую можно использовать для установки времени начала в микросекундах. Пример, в котором я установил время начала на 12:00 1 декабря 2013 года (часть $(...) — это расширение оболочки, выполненное оболочкой) и отображаю только время (см. die.net/man/3/strftime" rel="noreferrer">руководство strftime по возможным форматам):

ffmpeg -i video.mp4 -vf "drawtext=expansion=strftime: \
    basetime=$(date +%s -d'2013-12-01 12:00:00')000000: \
    text='%H\\:%S\\:%S'" output.mp4

\\: используется для экранирования :, которое в противном случае имело бы значение разделителя опций.

Другой пример: команда для вставки даты и времени в черный ящик, на несколько пикселей от верхнего левого угла и «некоторое дополнение» (фактически, два пробела и новые строки по краям):

newline=$'\r'
ffmpeg -i video.mp4 -vf "drawtext=x=8:y=8:box=1:fontcolor=white:boxcolor=black: \
    expansion=strftime:basetime=$(date +%s -d'2013-12-01 12:00:00')000000: \
    text='$newline %Y-%m-%d %H\\:%M\\:%S $newline'" output.mp4

Другой пример, чтобы получить микросекунды ниже часов:

newline=$'\r'
ffmpeg -i video.mp4 -vf "drawtext=expansion=strftime: \
    basetime=$(date +%s -d'2013-12-01 12:00:00')000000: \
    text='$newline %H\\:%M\\:%S $newline':fontcolor=white:box=1:boxcolor=black, \
    drawtext=text='$newline %{pts} $newline': \
    y=2*th/3:box=1:fontcolor=white:boxcolor=black:" output.mp4

При этом используется тот факт, что текст на самом деле состоит из трех строк и что оба текста имеют новую строку (возврат каретки, ^M) в начале и в конце. (Без этой новой строки пробел удаляется)

Другие подсказки:

  • -vf и -filter:v равны.
  • Вы не можете указать фильтры несколько раз, например. -vf drawtext=text=1 -vf drawtext=text=2 будет рисовать только второй текст. Вы можете комбинировать фильтры с запятой, как я показал выше.
person Lekensteyn    schedule 01.12.2013
comment
вариант местного времени помогает здесь? ffmpeg.org/pipermail/ffmpeg-user/2014-July/022355. html - person rogerdpack; 10.07.2014
comment
localtime не помогает, оно основывается на местном времени, а не на фиксированном моменте. Команда, которую я пробовал: ffplay -i video.mp4 -vf drawtext='expansion=normal:text=%{localtime\\:%a %b %d %Y}' - person Lekensteyn; 10.07.2014
comment
этот работал newline=$'\r' ffmpeg -i video.mp4 -vf drawtext=expansion=strftime: \ basetime=$(date +%s -d'2013-12-01 12:00:00')000000: \ text='$newline %H\\:%M\\:%S $newline':fontcolor=white:box=1:boxcolor=black, \ drawtext=text='$newline %{pts} $newline': \ y=2*th/3:box=1:fontcolor=white:boxcolor=black: output.mp4 - person Rick2047; 30.05.2017

в более поздних сборках можно использовать фильтр drawtext ("t" в его примерах есть, я полагаю, временная метка кадра) для вставки текста. Он также работает для srtftime с «текущим» системным временем.

person rogerdpack    schedule 11.08.2012
comment
В документации есть ошибка, нет опции t. Это имя basetime. Во всяком случае, я не мог заставить это работать должным образом. - person Lekensteyn; 01.12.2013
comment
да, видимо, это устарело и удалено. Несколько других вещей, которые могут быть полезны: вы можете использовать все, что поддерживает eval, и иметь frame_num и localtime, доступные для материала strftime... - person rogerdpack; 03.12.2013
comment
См. мой ответ на этот вопрос, вчера я обнаружил несколько других способов узнать время. t кажется ошибкой документации, должно быть basetime (что относится только к expansion=strftime). - person Lekensteyn; 03.12.2013
comment
На самом деле t находится в FFMPEG 4.1, вы можете использовать ffmpeg -i input.mp4 -vf drawtext="fontsize=60:fontcolor=yellow:text='%{e\:t*1000}':x=(w-text_w):y=(h-text_h)" output.mp4. - person bk138; 30.12.2020

Самое простое решение, которое я нашел, чтобы показать часы, когда файл был захвачен, а не его продолжительность, и оно работает /на основе этого поста, спасибо!/

D:\Temp\2>ffmpeg.exe -i test.avi -vf "drawtext=fontfile=C\\:/Windows/Fonts/arial.ttf:timecode='00\:20\:10\:00':rate=25:text='TCR\:':fontsize=46:fontcolor=white:x=500:y=50: box=1: boxcolor=0x00000000@1"  -f mp4 textts.mp4

Так просто в таймкоде - ставь свое время начала, тогда отсчет идет нормально! Пример для Windows

person Ddd    schedule 09.08.2015
comment
это работает, удивительно, кстати, что здесь означает TCR - person http8086; 13.06.2020

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

ffmpeg -i test.mp4 -vf \
    "drawtext=fontfile=arialbd.ttf:text='%{pts\:gmtime\:0\:%H\\\:%M\\\:%S}'" test.avi

Это создает штамп в формате ЧЧ:ММ:СС; вы можете изменить его на любое другое, используя strftime.

Может показаться, что он поставит метку времени с gmtime, но это не так. Он фактически передает текущее время видео в секундах в gmtime, производя дату 01.01.1970 и время через много секунд после полуночи. Таким образом, вы просто отбрасываете часть даты и используете часть времени.

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

person felwithe    schedule 12.08.2017

FFMPEG сможет выполнить большую часть работы, но не все будет готово. Используя FFMPEG, вы можете последовательно декодировать все кадры и давать вам «Временную метку презентации» (в некоторых форматах могут быть доступны дополнительные метаданные, связанные со временем, но PTS — это то, что вам нужно искать, чтобы начать работу. .) Затем вы сами можете нарисовать текст на декодированном кадре. Я использую Qt для подобных вещей, используя QPainter для QImage с данными кадра, но может быть какой-то другой API для рисования изображения, которое вы считаете более очевидным. Затем используйте API FFMPEG, чтобы создать сжатое видео, в котором есть только что нарисованные кадры. Это будет немного сложнее, если вы также хотите звук. Моя собственная работа не очень заботится о звуке, поэтому я не удосужился изучить звуковые аспекты API. По сути, когда вы выполняете цикл чтения, извлекая пакеты из файла, некоторые из них будут аудио. Вместо того, чтобы отбрасывать их, как это делаю я, вам нужно сохранить их и записать в выходной файл, как вы их получили.

Я использовал только C API, а не C #, поэтому я не знаю, есть ли какие-то особые проблемы, о которых нужно беспокоиться.

person wrosecrans    schedule 13.07.2010