Мне нужно записать временной код в видео, и мне интересно, на что способен ffmpeg?
Может ли ffmpeg записать тайм-код?
Ответы (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
Все еще работаю над тем, как расположить и наложить отрендеренные субтитры на видео и перекодировать в том же формате. Я обновлю этот пост, когда узнаю больше.
У меня работает фильтр 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 с настройками по умолчанию в качестве выходного кодека и не указывает шрифт и т. д. Тайм-код в этом случае записывается в левом верхнем углу кадра.
12.34 fps
.
- person Lekensteyn; 01.12.2013
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
будет рисовать только второй текст. Вы можете комбинировать фильтры с запятой, как я показал выше.
ffplay -i video.mp4 -vf drawtext='expansion=normal:text=%{localtime\\:%a %b %d %Y}'
- person Lekensteyn; 10.07.2014
в более поздних сборках можно использовать фильтр drawtext ("t" в его примерах есть, я полагаю, временная метка кадра) для вставки текста. Он также работает для srtftime с «текущим» системным временем.
t
. Это имя basetime
. Во всяком случае, я не мог заставить это работать должным образом.
- person Lekensteyn; 01.12.2013
t
кажется ошибкой документации, должно быть basetime
(что относится только к expansion=strftime
).
- person Lekensteyn; 03.12.2013
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
Вот мое решение, и я считаю, что оно правильное, потому что оно позволяет избежать необходимости вручную устанавливать скорость и позволяет форматировать вывод.
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 и для простоты поместил его прямо в рабочий каталог.
FFMPEG сможет выполнить большую часть работы, но не все будет готово. Используя FFMPEG, вы можете последовательно декодировать все кадры и давать вам «Временную метку презентации» (в некоторых форматах могут быть доступны дополнительные метаданные, связанные со временем, но PTS — это то, что вам нужно искать, чтобы начать работу. .) Затем вы сами можете нарисовать текст на декодированном кадре. Я использую Qt для подобных вещей, используя QPainter для QImage с данными кадра, но может быть какой-то другой API для рисования изображения, которое вы считаете более очевидным. Затем используйте API FFMPEG, чтобы создать сжатое видео, в котором есть только что нарисованные кадры. Это будет немного сложнее, если вы также хотите звук. Моя собственная работа не очень заботится о звуке, поэтому я не удосужился изучить звуковые аспекты API. По сути, когда вы выполняете цикл чтения, извлекая пакеты из файла, некоторые из них будут аудио. Вместо того, чтобы отбрасывать их, как это делаю я, вам нужно сохранить их и записать в выходной файл, как вы их получили.
Я использовал только C API, а не C #, поэтому я не знаю, есть ли какие-то особые проблемы, о которых нужно беспокоиться.