- Вопрос или проблема
- В результирующем выходном видео не содержится последний кадр, временная метка которого указана параметром -to!
- Ответ или решение
- Команда FFmpeg для извлечения сегмента видео
- Описание параметров:
- Решение проблем с отсутствующими кадрами:
- Частота кадров и битрейт:
- Копирование всех потоков:
- Рекомендации по таймстампам:
- Заключение
Вопрос или проблема
Попытка извлечь часть видео осуществляется с помощью команды ffmpeg с опциями -ss и -to следующим образом:
ffmpeg -ss "1.0" -i "<input>.mp4" -fps_mode passthrough -ss "1.208" -to "3.125" -map 0 -vcodec h264 -profile:v high -b:v 409628 -crf 20 -enc_time_base 1:24 -avoid_negative_ts make_zero -fflags +genpts -video_track_timescale 24 -copy_unknown -map_metadata 0 <output>.mp4
Значения для -ss
(первая инстанция выбрана на 1 секунду меньше, чем значение второй инстанции -ss, чтобы использовать комбинированный поиск сначала по грубому ключевому кадру на 1 секунду, а затем использовать точный поиск на 1.208 секунды. (Таким образом, 1 + 1.208 = 2.208 секунды — это временная метка начальной точки кадра). Временные значения берутся из вывода команды ffprobe, чтобы соответствовать временным меткам pts. Это может не быть временем ключевого кадра, поэтому -c copy нельзя использовать для этого видеопотока.
В результирующем выходном видео не содержится последний кадр, временная метка которого указана параметром -to
!
Количество кадров также на 1 меньше, чем представлено кадрами в диапазоне параметров -ss
и -to
.
Поскольку входное видео имеет пронумерованные кадры (например, 0, 1, 2 ..), визуально проверено выходное видео, и подтверждено, что последний кадр отсутствует в выводе!
-
Может кто-то помочь, поделившись оптимальным набором точных опций для передачи в команду ffmpeg
-ss
-to
, чтобы извлечь видеосегмент в диапазоне временных меток, сохраняя все параметры такими же, как во входном? (fps, кодек, разрешение, time_base и т. д.). (а также другие потоки, включая аудио, субтитры, также нужны в этом диапазоне временных меток)Я собрал параметры, проводя поиск в интернете, и добавил параметры в команду ffmpeg выше, значения параметров кодека,
time_base
, битрейта получены из вывода команды ffprobe, как и значения временных меток начальной и конечной точек (-ss
-to
). -
Обе параметры
-enc_time_base 1:24, -video_track_timescale 24
используются в вышеуказанной команде, чтобы установить fps таким же, как во входном (из вывода команды ffprobe значение fps былоr_frame_rate=24/1
), есть ли другая опция или правильная опция для команды, чтобы обеспечить выходной fps таким же, как во входном видео, без явного указания числового fps как входного параметра к команде?- обеспечивает ли опция
-fps_mode passthrough
, заданная команде ffmpeg, что fps выхода установлен таким же, как и входное видео?
- обеспечивает ли опция
-
Должен ли параметр
-b:v <битрейт>
обязательно указываться в этой команде, чтобы обеспечить такой же битрейт, как во входном? Есть ли другие опционные параметры, доступные для команды, чтобы сохранить битрейт таким же, как во входном?Цель этого извлечения: некоторые извлеченные сегменты позже будут конкатенированы вместе, поэтому предприняты попытки выше сохранить fps, разрешение, базу времени и другие параметры одинаковыми во всех извлеченных сегментах.
-
помогут ли опции в команде
-avoid_negative_ts make_zero -fflags +genpts
сбросить временные метки в каждом извлеченном видеофайле? (и сделать конкатенацию позже более безопасной) -
помогают ли параметры
-map 0 и -map_metadata 0
успешно скопировать все другие потоки в этом диапазоне времени? или необходимо явно указывать значения кодека звука, скорости, кодека потока в этой команде ffmpeg? -
временные метки кадра (секунды.миллисекунды) берутся из вывода команды ffprobe (pts_time).
Некоторые из ответов в интернете предлагали скорректировать значения pts_time в значении -ss на 1 миллисекунду, нужно ли это смещение?
- Если да, должен ли параметр
-ss
быть на 1 миллисекунду больше, чем значение временной метки кадра pts_time, предоставленной выводом ffprobe? - Если такое добавление необходимо из-за округления ceil/floor или приближений в алгоритме ffmpeg, то чтобы предотвратить несовпадение позиций кадров, следует ли добавлять <50% времени кадра, а не 1 мс? (то есть, для файла 120fps, 1000мс/120 = 8.333 миллисекунд длительности, следует ли добавить 4 мс к pts_time, чтобы получить более безопасное значение времени начального параметра -ss?)
- должно ли конечное время также рассчитываться аналогично.
- без получения из вывода ffprobe, есть ли точный расчет для получения временной метки (секунды.миллисекунды) N-го кадра? (расчет вроде N/fps, например: для 20-го кадра видео 30 fps, является ли вычисление 20/30fps = 0.666 секунд достаточным для представления pts_time 20-го кадра как входного в команду ffmpeg, не рискуя несовпадением позиции кадра на 1 по сравнению с внутренними алгоритмами ffmpeg? (например, 19-й кадр выше имел бы время до 0.665 секунд, так что очень близко к 0.666 секундам, что вызывает беспокойство по поводу риска проблемы вычисления позиции 1 кадра))
Вывод ffprobe входного видеофайла (сокращенный):
"codec_name": "h264",
"codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10",
"profile": "High",
"codec_type": "video",
"codec_tag_string": "avc1",
"codec_tag": "0x31637661",
"width": 640,
"height": 480,
..
"r_frame_rate": "24/1",
"avg_frame_rate": "24/1",
"time_base": "1/24",
"start_pts": 0,
"start_time": "0.000000",
"duration_ts": 240,
"duration": "10.000000",
"bit_rate": "409628",
а кадр на начальном времени диапазона, используемого в команде ffmpeg для извлечения:
pts=53
pts_time=2.208333
..
pts=98
pts_time=4.083333
pts=99
pts_time=4.125000
Как мы видим временные метки выше, pts=99 (время 4.125) является значением конечной точки -to, однако этот 99-й кадр не виден в выходном файле!
Тогда как вывод команды ffprobe результирующего выходного файла:
"codec_name": "h264",
"codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10",
"profile": "High",
"codec_type": "video",
"codec_tag_string": "avc1",
"codec_tag": "0x31637661",
"width": 640,
"height": 480,
…
"r_frame_rate": "24/1",
"avg_frame_rate": "24/1",
"time_base": "1/24",
"start_pts": 0,
"start_time": "0.000000",
"duration_ts": 46,
"duration": "1.916667",
"bit_rate": "406401",
"bits_per_raw_sample": "8",
"nb_frames": "46",
"extradata_size": 38,
.
Ответ или решение
Для извлечения сегмента видео с помощью FFmpeg между временными метками с сохранением всех параметров (кодек, разрешение, частота кадров и т.д.) можно использовать следующие рекомендации и команды.
Команда FFmpeg для извлечения сегмента видео
Для извлечения видео между заданными временными метками (в формате секунд.миллисекунд) с сохранением всех важных параметров оригинала, рекомендуется использовать следующую команду:
ffmpeg -ss 1.208 -to 4.125 -i "<input>.mp4" -map 0 -c:v copy -c:a copy -c:s copy -avoid_negative_ts make_zero -fflags +genpts "<output>.mp4"
Описание параметров:
-ss 1.208
– задает начальную точку извлечения.-to 4.125
– задает конечную точку извлечения.-i "<input>.mp4"
– указывает входной файл.-map 0
– копирует все потоки (видео, аудио, субтитры) из входного файла.-c:v copy
,-c:a copy
,-c:s copy
– используют копирование потока без перекодировки, что помогает сохранить оригинальное качество.-avoid_negative_ts make_zero
– обнуляет временные метки для упрощения конкатенации видео.-fflags +genpts
– генерирует временные метки.
Решение проблем с отсутствующими кадрами:
Если в вашем первом результате выходное видео не содержит последнего кадра, это может быть связано с тем, как FFmpeg обрабатывает временные метки. В этом случае стоит выставить параметр -to
на 0.001 секунды больше, чем желаемая конечная точка, чтобы захватить последний кадр. Пример команды:
ffmpeg -ss 1.208 -to 4.126 -i "<input>.mp4" -map 0 -c:v copy -c:a copy -c:s copy -avoid_negative_ts make_zero -fflags +genpts "<output>.mp4"
Частота кадров и битрейт:
- Установка
-c:v copy
позволяет сохранить оригинальную частоту кадров и битрейт. Если нужно гарантированно сохранить эти значения, можно использовать-b:v
с тем же значением, что и в исходном файле:-b:v 409628
Однако это обычно не требуется, если данные потоки копируются.
Копирование всех потоков:
-map 0
и -c:* copy
обеспечивают сохранение всех потоков без необходимости указывать их конкретные типы и параметры.
Рекомендации по таймстампам:
Коррекция значений времени не всегда необходима, но если ваш проект содержит много сопоставлений кадров, вы можете усреднить задержку по 1/2 частоты кадров (например, для 24fps, добавить примерно 10 мс). Для расчета N
-го кадра можно использовать:
timestamp = N / fps
Например, для 20-го кадра 24fps:
timestamp = 20 / 24 = 0.8333 секунд
Заключение
Используйте указанные выше рекомендации для извлечения сегментов из видео с максимальным сохранением оригинального качества и параметров. Убедитесь, что используете подходящие опции, чтобы избежать потери данных и кадров. Если у вас возникнут дополнительные вопросы, не стесняйтесь задавать их или обращаться за помощью.