Как извлечь точные по времени сегменты видео с помощью ffmpeg?

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

у меня есть кусок 15 секунд прямо с камеры.mov видео, из которого я хочу извлечь определенный кусок, который я могу идентифицировать по времени начала и времени остановки, в секундах. Я начал с попытки сделать то, что я назову "извлечением копии": получить секунды с 9 до 12,

ffmpeg -i test.mov -vcodec copy -acodec copy -ss 9 -to 12 test-copy.mov

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

ffmpeg -i test.mov -ss 00:00:09 -t 00:00:03 test-out.mov

это лучше, но не совсем: в начале клипа больше нет черных рамок, но они все еще там в конце.

после некоторого просмотра и чтения я тогда заподозрил, что проблема в том, что ffmpeg испытывает проблемы с поиском правильных точек из-за отсутствия ключевых кадров в оригинальном видео. Поэтому я перекодировал исходное видео (предположительно), чтобы добавить ключевые кадры, несколькими различными способами. Поскольку я хочу иметь возможность выбирать видео на границах секунды ("от 9 секунд до 12 секунд"), я попробовал, копируя различные предложения по всему интернету,

ffmpeg -i test.mov -force_key_frames "expr:gte(t, n_forced)" test-forced.mp4

и

ffmpeg -i test.mov -g 1 test-g-inserted.mp4

(Я построил их как mp4 на основе некоторых комментариев о контейнере mp4, необходимых для поддержки поиска ключевого кадра, но я честно просто взлом здесь.) Затем я попробовал извлечение, как и раньше, но на этих новых видео, которые предположительно теперь имеют ключевые кадры в них. Не повезло - оба кажутся примерно одинаковыми; начало в порядке, но в конце все еще есть черные рамки. (FWIW, оба теста принудительные.mp4 и тест-G-вставлен.mp4 также имеют трейлинг-черные рамки.)

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

4 ответов


Ok, прежде всего, предполагая, что вы знаете продолжительность начала и остановки; мы добавим ключевые кадры на этой продолжительности.

ffmpeg -i a.mp4 -force_key_frames 00:00:09,00:00:12 out.mp4

большую часть времени вы можете напрямую вырезать видео с совершенством, но в вашем случае это не поможет вам; поэтому мы позаботились об этом выше команды. Здесь будьте осторожны, чтобы не добавлять слишком много ключевых кадров, как это может быть проблемой при кодировании согласно Ffmpeg Docs.

теперь вы можете снова попытаться вырезать видео из конкретных время.

ffmpeg -ss 00:00:09 -i out.mp4 -t 00:00:03 -vcodec copy -acodec copy -y final.mp4

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

Ура.:)


я думаю, что проблема вопроса и других ответов состоит в том, что они через -ss в качестве опции в выходном файле, а не во входном файле. Большинство параметров ffmpeg не являются глобальными, а применяются только к файлу, которому они предшествуют. Часто не очевидно, куда должен идти вариант, поэтому иногда требуется проб и ошибок.

используется правильно, перед входным файлом, к которому они должны применяться,-ss и -t работал штрафа для меня. При включении аудио в выход, я должен был использовать -shortest в качестве опции для выходного файла, или я бы получил 2 минуты аудио с 2 секундами видео.

ffmpeg версия N-67413-g2a88c74 (в основном git источник от 14 дек 2014)

вот командная строка, которую я использовал, чтобы сделать клип недавно. (на самом деле, чтобы быть лучшим примером, так как я оставил звук для этого, и не замедлил его.)

ffmpeg -ss 120.2 -t 0.75 -i ../mcdeint.60p.lossless264.slow.mkv -c:a libopus -shortest -aspect 16:9 -preset veryslow -x264-params nr=250:ref=6 -crf 22 -movflags +faststart clip2.mkv

С -c:a copy (источник имеет AC3 audio), воспроизведение начинается с wonky mplayer. Вероятно, он захватывает аудио с начала аудиокадра, содержащего начало, а затем должен использовать смещение a/v в контейнере. При запуске аудио занимает долю секунды, чтобы опередить видео по этому смещению, а до тех пор видео воспроизводится с очень низким FPS. Поэтому я xcoded аудио. Ни opus, ни pcm_s16le не могут пойти в mp4, поэтому я использовал контейнер mkv для этого примера.

источником является кодирование без потерь x264 (-qp 0) С выхода a очень медленный yadif=3:1,mcdeint=3:1: 10 (на некоторых BFF-видео с NTSC DVD, возможно, с DV-камеры). Это еще не все!--7--> кадры, это P кадры с нормальным интервалом ключевого кадра.

настройка-ss на 0,2 секунды сделала именно то, что я надеялся, поэтому ffmpeg должен обрабатывать декодирование до требуемой точки. Это было не просто совпадение кадра I, где я хотел. Может быть!--9--> по умолчанию? Я также получаю тот же результат (байт за байтом идентичный выход gif), что и при использовании источник ffvhuff lossless как входной сигнал. (но он работает быстрее, так как ему не нужно декодировать до запрошенной точки.)

другой, возможно, релевантный вариант --seek2any, но он говорит: "Ищите неключевой кадр на уровне демуксера", что звучит так, как будто это позволит вам искать способы, которые будут производить искаженный вывод. (т. е. начать декодирование без фактического создания ссылок, которые требует текущий фрейм, просто использовать all-gray?)

я не пробовал использовать -c:v copy, так как я вырезание действительно короткого клипа для петли, поэтому я знаю, что не будет I кадры, где они мне нужны.

это командная строка, которую я фактически использовал, чтобы сделать короткий клип slo-mo без звука.

ffmpeg -ss 120.2 -t 0.75 -i ../vid.yadif3.1,mcdeint3.1.10.ffvhuff.mkv -an -shortest -aspect 16:9 -c:v libx264 -preset veryslow -x264-params nr=250:ref=6 -crf 22 -filter:v "setpts=3.0*PTS" -movflags +faststart -r 20 clip.mp4

отметим, что -r 20 было важно, потому что, в отличие от mkv, выход MP4 ffmpeg является постоянным-только частота кадров (edit: because -vsync vfr не является значением по умолчанию для mp4 muxer). Не говоря об этом, он установил бы выходной FPS = входной FPS, и дублировать кадры, когда это необходимо, чтобы это произошло. x264 и анимированный gif (с прозрачностью) могут очень эффективно кодировать дубликаты кадров, но это все равно глупо.

прежде чем готовить это в качестве примера, я сделал это в 2 шага, один вывод в mkv, затем ffmpeg -i clip.mkv -c:v copy -movflags +faststart -r 20 clip.mp4 в remux. Кстати, можно изменить fps видео при ремуксировании, без xcoding, просто не с ffmpeg. https://superuser.com/questions/740196/reducing-video-size-with-avconv-why-does-the-size-increase - ... Но в любом случае, ffmpeg отправил только 45 кадров в libx264 при создании mkv, хотя он думал, что делает 2,2-секундное видео на 60fps. Не используйте ffmpeg с mp4 для работы с переменными FPS.

edit: оказывается, ffmpeg по умолчанию -vsync vfr для выхода mkv, но не для mp4. С -vsync vfr, ffmpeg может написать VFR в выход mp4 как раз штраф.

и снова для вывода gif, в случае, если я решу не ставить его с HTML5 Видео (<video controls autoplay loop> <source src="clip.mp4" type="video/mp4"> </video>)

ffmpeg -ss 120.2 -t 0.75 -i ../vid.yadif3.1,mcdeint3.1.10.ffvhuff.mkv -an -shortest -aspect 16:9 -filter:v "setpts=3.0*PTS,scale=854x480" -r 20 clip.gif

мне пришлось использовать scale= потому что контейнер gif не хранит соотношение сторон, поэтому он не может автоматически масштабироваться при воспроизведении. (мое видео 720x480 pixel 16:9 масштабируется до 854x480 при воспроизведении. На самом деле должно быть 853.333, но это округляется, а затем ffmpeg хранит 853x480 в контейнере mkv, следовательно, используя-аспект 16: 9 все время, поэтому мой mp4 будет хранить правильное соотношение сторон [SAR 32:27 DAR 16:9], вместо [SAR 186:157 DAR 279:157])


нет необходимости добавлять ключевые кадры; как говорит Питер, это просто вопрос получения опций в правильном порядке. Однако см. https://trac.ffmpeg.org/wiki/Seeking для окончательного, официального руководства о том, как это сделать правильно.


Я хотел бы знать, как хорошо. До сих пор я конвертировал свои видео без потерь, извлекал сегмент и перекодировал их после редактирования:

ffmpeg -i input -ss 9.48 -t 3.52 -c:v libx264 -crf 0 -g 1 -c:a copy TempIframe.mp4

но это трудоемкий и процесс с потерями...

Я пробовал следующее без успеха:

ffmpeg -i source.mp4 -ss 1 -c:v copy -seek2any 1 -avoid_negative_ts 1 -safe 1 -c:a copy segment.mp4