Команда 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 ..), визуально проверено выходное видео, и подтверждено, что последний кадр отсутствует в выводе!


  1. Может кто-то помочь, поделившись оптимальным набором точных опций для передачи в команду ffmpeg -ss -to, чтобы извлечь видеосегмент в диапазоне временных меток, сохраняя все параметры такими же, как во входном? (fps, кодек, разрешение, time_base и т. д.). (а также другие потоки, включая аудио, субтитры, также нужны в этом диапазоне временных меток)

    Я собрал параметры, проводя поиск в интернете, и добавил параметры в команду ffmpeg выше, значения параметров кодека, time_base, битрейта получены из вывода команды ffprobe, как и значения временных меток начальной и конечной точек (-ss -to).

  2. Обе параметры -enc_time_base 1:24, -video_track_timescale 24 используются в вышеуказанной команде, чтобы установить fps таким же, как во входном (из вывода команды ffprobe значение fps было r_frame_rate=24/1), есть ли другая опция или правильная опция для команды, чтобы обеспечить выходной fps таким же, как во входном видео, без явного указания числового fps как входного параметра к команде?

    • обеспечивает ли опция -fps_mode passthrough, заданная команде ffmpeg, что fps выхода установлен таким же, как и входное видео?
  3. Должен ли параметр -b:v <битрейт> обязательно указываться в этой команде, чтобы обеспечить такой же битрейт, как во входном? Есть ли другие опционные параметры, доступные для команды, чтобы сохранить битрейт таким же, как во входном?

    Цель этого извлечения: некоторые извлеченные сегменты позже будут конкатенированы вместе, поэтому предприняты попытки выше сохранить fps, разрешение, базу времени и другие параметры одинаковыми во всех извлеченных сегментах.

  4. помогут ли опции в команде -avoid_negative_ts make_zero -fflags +genpts сбросить временные метки в каждом извлеченном видеофайле? (и сделать конкатенацию позже более безопасной)

  5. помогают ли параметры -map 0 и -map_metadata 0 успешно скопировать все другие потоки в этом диапазоне времени? или необходимо явно указывать значения кодека звука, скорости, кодека потока в этой команде ffmpeg?

  6. временные метки кадра (секунды.миллисекунды) берутся из вывода команды 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 секунд

Заключение

Используйте указанные выше рекомендации для извлечения сегментов из видео с максимальным сохранением оригинального качества и параметров. Убедитесь, что используете подходящие опции, чтобы избежать потери данных и кадров. Если у вас возникнут дополнительные вопросы, не стесняйтесь задавать их или обращаться за помощью.

Оцените материал
Добавить комментарий

Капча загружается...