Может ли 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
Все еще работаем над тем, как расположить и наложить визуализированные субтитры на видео и перекодировать в том же формате. Я буду обновлять этот пост, как я знаю больше.
Фильтр отрисовки текста 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 и немного оболочки fu:
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.
Edit Так как я перешел на темную сторону, я теперь делаю это в среде 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'))}
Это создает mp4s для данной папки, содержащей файлы.MOV, .MP4 и.MTS (используя -filter
Команда ищет файлы с *.M* в имени, которые вы должны изменить, если бы вы работали с файлами.AVI), и она немного более минимальна, она просто использует libx264 с настройками по умолчанию в качестве выходного кодека и не указать шрифт и т. д. В этом случае временной код записывается в верхнем левом углу кадра.
Фильтр drawtext, упомянутый в ответе @stib, является ключом для вставки времени. С использованием timecode
Опция, однако, не соответствует настенным часам. Если вы получите r
(timecode_rate) параметр неверный, тогда ваше время не будет соответствовать вашему времени воспроизведения.
Существуют и другие варианты, например, text='%{prt}'
Опция позволяет отображать прошедшее время с точностью до микросекунды. Команда:
ffmpeg -i video.mp4 -vf "drawtext=text='%{prt}'" output.mp4
Чтобы получить часы вместо этого, я должен был использовать устаревший strftime
вариант. Это имеет недокументированное basetime
опция, которую можно использовать для установки времени начала в микросекундах. Пример, в котором я установил время начала 12:00 1 декабря 2013 года ($(...)
часть - это расширение оболочки, выполняемое оболочкой), и отображается только время ( возможные форматы см. в руководстве 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
будет рисовать только второй текст. Вы можете комбинировать фильтры с запятой, как я показал выше.
Вот мое решение, и я считаю, что оно правильное, поскольку оно позволяет избежать необходимости вручную устанавливать скорость и позволяет форматировать выходные данные.
ffmpeg -i test.mp4 -vf \
"drawtext=fontfile=arialbd.ttf:text='%{pts\:gmtime\:0\:%H\\\:%M\\\:%S}'" test.avi
Это производит штамп в формате ЧЧ: ММ: СС; вы можете изменить его на что угодно, используя strftime.
Может показаться, что он собирается поставить отметку времени с gmtime
, но это не то, что происходит. Фактически, оно передает текущее время видео в секундах в gmtime, производя дату 1/1/1970 и время, которое, однако, составляет много секунд после полуночи. Таким образом, вы просто отбрасываете часть даты и используете часть времени.
Обратите внимание на тройные экранированные двоеточия в функции pts, которые вы должны будете сделать, если введете его, как я делал выше. Также вы можете видеть, что я скопировал файл шрифта для Arial Bold и поместил его прямо в рабочий каталог для простоты.
В более поздних сборках вы можете использовать фильтр drawtext ("t" в его примерах, я считаю, метку времени фрейма) для вставки текста. Он также работает для srtftime в "текущее" системное время.
Самое простое решение, которое я нашел, чтобы показать часы, когда файл был захвачен, а не его продолжительность, и он работает / на основе этого поста, спасибо!/ Is
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 сможет выполнить большую часть работы, но она не будет полностью упакована. Используя FFMPEG, вы можете сделать так, чтобы он декодировал все кадры в последовательности, и предоставил вам "метку времени презентации" (в некоторых форматах могут быть доступны дополнительные метаданные, относящиеся ко времени, но PTS - это то, что вам нужно для начала работы).) Затем вы сами можете нарисовать текст на декодированной рамке самостоятельно. Я использую Qt для подобных вещей, используя QPainter для QImage с данными фрейма, но может быть какой-то другой API для рисования на изображении, которое вы находите более очевидным. Затем используйте API FFMPEG для создания сжатого видео, в котором будут только что нарисованные кадры. Это будет немного сложнее, если вы также хотите аудио. Моя собственная работа не заботится об аудио, поэтому я не потрудился изучить аудио аспекты API. По сути, когда вы выполняете цикл чтения, получая пакеты из файла, некоторые из них будут аудио. Вместо того, чтобы отбрасывать их, как я, вам нужно сохранить их и записать в выходной файл, как вы их получили.
Я использовал только C API, а не C#, поэтому я не знаю, есть ли какие-то особые проблемы, о которых стоит беспокоиться.