У меня есть несколько видеозаписей с каналов Full HD IPTV, которые я сохранил с помощью VLC. Эти потоковые дампы хранятся в виде файлов MPEG-TS и содержат видео в кодировке AVC со звуком MPEG.
Я хотел бы извлечь определенные клипы из этих записей, основываясь на точных точках среза. Однако, у меня возникли трудности с определением точных миллисекундных временных меток, которые мне нужно передатьFFMPEG's -ss
и -to
параметры, чтобы точно попасть в нужные мне точки отсечения. Вот что я пробовал до сих пор:
Попытка 1
Моя первая попытка состояла в том, чтобы загрузить .ts
файлы вАвидемюкспоскольку он позволяет удобно покадровый поиск и отображает временную метку текущего кадра с необходимой точностью. Однако, если я помещу временную метку кадра, к которому я стремился (в формате HH:MM:SS.mmm
), вFFMPEGпараметры, разрез будет фактически смещен на несколько кадров, иногда более чем на секунду. Дрейф отличается для каждого файла и может быть положительным или отрицательным.
Затем я заметил, что для большинства этих записей, для первого кадраАвидемюксна самом деле показывает временную метку, которая не равна нулю (например, 00:00:00.280
или даже 00:00:00.216
). Я предположил, чтоВЛКначинает запись немедленно, ноАвидемюксигнорирует все до первого I-кадра. Я все еще удивляюсь временной метке вроде 00:00:00.216
, хотя, потому что эти видео на 25 кадров в секунду, а 216 даже не кратно 40 мс.
Попытка 2
Я попробовал двухпроходный процесс, в котором я бы кодировал видео один раз, начиная кодирование немного раньше, чем я хочу, и заканчивая его немного позже, чем я хочу. Затем я бы использовалАвидемюксподсчитать лишние кадры в начале и конце видео, а также переместить точки разреза nFrames * 40 ms
внутрь. Однако результаты быливсе ещенеточно, это приводило к тому, что иногда мне приходилось укорачивать видео на слишком мало кадров, иногда на слишком много.
Потеря доверия кАвидемюксточность временной метки или, по крайней мере, вывод о том, что он выполняет некоторые вычисления иначе, чемFFMPEGЯ подумал, что самым безопасным способом будет использовать тот же инструмент для определения точек обрезки, который я использую и для фактической обрезки видео.
Попытка 3
Я попытался извлечь отдельные кадры вокруг желаемых точек резки с помощью FFMPEG, используя те же самые -ss
и -to
параметры, которые я использую для резки видео, но выбрав только диапазон, близкий к желаемым точкам резки, и записав кадры в файлы изображений. Я бы также использовал фильтр, чтобы записать точную временную метку каждого кадра, как определеноFFMPEG, прямо в изображение. Таким образом, я мог бы просто считать нужные точки разрезания и использовать их для фактического кодирования. Моя командная строка будет выглядеть примерно так:
ffmpeg.exe -i input.ts -ss 00:00:29.000 -to 00:00:31.000 -vf drawtext=fontfile=roboto.ttf:fontsize=40:text='%{pts\:hms}':[email protected]:x=10:y=10 image%03d.png
Затем я нахожу точный файл PNG, который мне нужен для вырезания, смотрю на временную метку, и если там указано 00:00:30.160
, то это и есть временная метка, которую я буду использовать для -ss
фактического вырезания.
Однако, этовсе ещене сработало, и мои точки разрезания все еще на несколько кадров раньше или позже, чем извлеченные PNG. Поэтому изменениеFFMPEGПохоже, что вывод из видео в изображения влияет на расчет временных меток, поскольку они не совпадают!
До сих пор я не нашел способа избежать необходимости выполнять длительный процесс бинарного поиска, чтобы вручную подобрать точные временные метки, на которых должны располагаться разрезы, что особенно обременительно, поскольку я могу получить нужные мне временные метки, только выполняя «полный поиск декодирования» (т. е. используя параметр -ss
после входного параметра, а не до него), а поиск позиции, находящейся в записи несколько часов, может занять много времени.
Как мне найти временную метку, которая мне нужна, чтобы получить точную по кадру нарезку изFFMPEGв транспортном потоке MPEG, без необходимости декодировать, вырезать и сохранять видеофрагменты несколько раз, чтобы вручную продвигаться к ним?
ЗдесьМедиа информацияна одной из записей, на случай, если она содержит какие-либо подсказки о том, что с самими трансляциями происходит что-то странное:
General
ID : 1 (0x1)
Complete name : C:\Users\…\vlc-record-2021-03-09-00h23m11s.ts
Format : MPEG-TS
File size : 2.31 GiB
Overall bit rate mode : Variable
Video
ID : 256 (0x100)
Menu ID : 1 (0x1)
Format : AVC
Format/Info : Advanced Video Codec
Format profile : High@L4
Format settings : CABAC / 4 Ref Frames
Format settings, CABAC : Yes
Format settings, Reference frames : 4 frames
Codec ID : 27
Width : 1 920 pixels
Height : 1 080 pixels
Display aspect ratio : 16:9
Frame rate : 25.000 FPS
Standard : Component
Color space : YUV
Chroma subsampling : 4:2:0
Bit depth : 8 bits
Scan type : Interlaced
Scan type, store method : Separated fields
Scan order : Top Field First
Color range : Limited
Color primaries : BT.709
Transfer characteristics : BT.709
Matrix coefficients : BT.709
Audio
ID : 257 (0x101)
Menu ID : 1 (0x1)
Format : MPEG Audio
Format version : Version 1
Format profile : Layer 2
Codec ID : 3
Bit rate mode : Constant
Bit rate : 128 kb/s
Channel(s) : 2 channels
Sampling rate : 48.0 kHz
Compression mode : Lossy
Delay relative to video : -248 ms
Menu
ID : 4096 (0x1000)
Menu ID : 1 (0x1)
List : 256 (0x100) (AVC) / 257 (0x101) (MPEG Audio)
Service name : Service01
Service provider : FFmpeg
Service type : digital television
Дополнительная информация:Дрейф временной метки отличается для каждого файла, но постоянен в пределах каждого файла. То есть, если мне нужно сделать несколько разрезов в видео, и для одного разреза определить, что временная метка, указанная в изображениях, извлеченных с помощьюFFMPEGвсегда на 160 мс меньше, чем мне нужно -ss
, я могу использовать это же смещение для остальных разрезов в том же файле, и это будет точно.