Как точно обрезать видео с помощью FFmpeg

задняя часть FFmpeg
Как точно обрезать видео с помощью FFmpeg

1. Описание проблемы

1.1 Предыстория

ранее на основеffmpegВыполняйте вторичную разработку, выполняйте общие функции обработки видео и используйтеffmpegКомандная строка делает свое дело. На этой основе также строится система доступа и планирования транскодирования для предоставления внешних услуг. Есть функция, которая должна быть такой: быстро обрезать суб-видео определенного временного диапазона из указанного видео, два требования: 1. Чтобы было быстро, не так долго, как перекодирование 2. Если быть точным, вы можно указать при редактировании, с какой секунды начинать и с какой секунды заканчивать.

1.2 Трудности

использоватьffmpegЛегко отредактировать небольшое видео из длинного видео. например, командаffmpeg -i input.mp4 -ss 00:10:03 -t 00:03:00 -vcodec copy -acodec copy output.mp4изinput.mp4На 10-й минуте и 3-й секунде 3-минутное видео редактируется и сохраняется какoutput.mp4документ. параметр-vcodec copy -acodec copyЭто прямое копирование аудио- и видеопотока исходного видео без кодирования и декодирования. Хотя описанный выше метод удобен, у него есть фатальный недостаток:Экран сначала зависает (но звук всегда нормальный), а через несколько секунд экран нормально прокручивается. Видео ниже является примером.

2. Анализ причин

Причина этого в том, что время начала клипа попадает в видеоGOPсреднее положение вместо первогоIРамка. Студенты, которые немного разбираются в кодировании видео, должны были это слышать.I,B,PРамка. Проще говоря,IКадр – это законченное изображение,Pкадр в соответствии сI帧делать дифференциальное кодирование,Bкаркас по переду и спинкеI,P,BКадры кодируются по-разному. то естьIкадр имеет полное содержимое, в то время какPа такжеBрамки нет, так что если отсутствуетIкадр, тоPа такжеBКадры не могут нормально декодироваться. Вообще говоря,GOPПервый кадр внутриIкадр, а затем несколькоPа такжеBРамка. ОдинGOPВозможно до 10 секунд. На фото ниже реальное видеоI,B,PИнфографика кадра, красное представлениеIкадр, вы можете видеть дваIКадры далеко друг от друга (на самом деле 10 секунд).

Из вышеприведенного анализа видно, что время начала клипа, скорее всего, не совпадает сIрамка из-за отсутствияIкадр сделает следующееPа такжеBКадры не могут быть декодированы, что приводит к зависанию изображения. Приведенный выше анализ основан на прямом копировании видеоконтента без кодирования и декодирования.Если вы рассмотрите декодирование изображений одно за другим, а затем кодируете изображения, соответствующие требованиям времени, время редактирования может быть очень точным. Но это слишком трудоемко: для выполнения операций кодирования и декодирования требуется много ресурсов процессора.

3. Решения

Решение все же есть: к первому, соответствующему требованиям времениGOPкодек и послеGOPКонтент копируется непосредственно в целевое видео. Давай, первыйGOPкадров перераспределяются из-за перекодированияIкадр, чтобы его можно было воспроизвести, во-вторых, после этогоGOPКонтент копируется напрямую, поэтому он в основном не потребляет ЦП, а производительность увеличивается. Как показано ниже:

Конечно, в нем еще есть какие-то ямы, и ямы будут засыпаны ниже.

3.1 Сращивание

Исходное видео может удивить: я закодировал код своими способностями, почему вы можете декодировать его напрямую, скопировав? В общем декодирование зависит отSPSа такжеPPS, в то время как исходное видео и целевое видеоSPSа такжеPPSбудет другим, поэтому прямая копия не будет правильно декодирована. заmp4документ,SPSа такжеPPSОбычно ставится в заголовке файла. Файл может иметь только один заголовок, поэтому он не может хранить два разных заголовка.SPSа такжеPPS. Чтобы правильно декодировать целевое видео, исходное видео должно бытьSPSа такжеPPS. Если вы не можете поместить заголовок файла, куда вы можете его поместить? Можно ли его разместить перед копируемой рамкой? Как это сказать? Я был беспомощен и мне не с чего было начать, пока однажды я вдруг не вспомнил, что для того, чтобы заполнить дыру, я выследилh264_mp4toannexbреализации, его роль заключается вSPSа такжеPPSСкопируйте в кадр (точнее, он должен бытьAVPacket) перед ним. Приходить! Просмотрите конкретную реализацию h264_mp4toannexb: во всехAVPacketувеличение спереди0x000001или0x00000001,существуетIВставить перед рамкойSPSа такжеPPS. то есть черезh264_mp4toexannbдля расшифровки нужногоSPSа такжеPPSВставить правильно в видео.h264_mp4toannexbОн также относительно прост в использовании, код выглядит следующим образом:

AVBSFContext* initBSF(const std::string &filter_name, const AVCodecParameters *codec_par, AVRational tb)
{
    const AVBitStreamFilter *filter = av_bsf_get_by_name(m_filter_name.c_str());
​
    AVBSFContext *bsf_ctx = nullptr;
    av_bsf_alloc(filter, &bsf_ctx);
​
    avcodec_parameters_copy(bsf_ctx->par_in, codec_par);
    bsf_ctx->time_base_in = tb;
​
    av_bsf_init(bsf_ctx);
    return bsf_ctx;
}
​
AVPacket* feedPacket(AVBSFContext *bsf_ctx, AVPacket &packet)
{
    av_bsf_send_packet(bsf_ctx, packet);
​
    AVPacket *dst_packet = av_packet_alloc();
    av_bsf_receive_packet(bsf_ctx, dst_packet);
​
    return dst_packet;
}
​
void test()
{
    AVBSFContext *bsf_ctx = initBSF("h264_mp4toannexb", video_stream->codecpar, video_stream->time_base);
    AVPacket *packet = readVideoPacket();
    AVPacket *dst_packet = feedPacket(bsf_ctx, packet);
}

Примечание: сначала кодекGOPи оригинальное продолжение видеоGOPСледует внимательно обращаться с временными метками во время сращивания, иначе при воспроизведении видео может возникнуть дрожание.

3.2 Хуапин

Думаете, все кончено? нет! ! Вы обнаружите, что некоторые видео будут выглядеть размытыми в последнюю секунду. . . .

Нетрудно догадаться, в чем причина Хуапина: последний кадрBРамка. Так как не во всех клипах есть последний кадр видеоBкадр, так что Huaping не нужно. знаю даBвызывается кадр, решение очевидно: убедитесь, что последний кадрPРамка. Даже если это немного с течением времени (аудиопоток должен немного следовать за видеопотоком). Однако, поскольку невозможно напрямуюAVPacketОпределить, является ли кадрPкадр, так что последнийGOPтакже должен быть декодирован (кодирование не требуется). Запишите первый после превышения диапазона времениPобрамленныйpts, скопируй позжеGOP, скопируйте сюдаptsможет остановиться.

4. Резюме

Сначала я думал, что проблема трудно решить, в конце концовffmpegЕсть проблема с обрезанием командной строки. Тем не менее, это всегда одно и то же, начиная с причины проблемы, шаг за шагом ища решение и разбивая проблемы, встречающиеся на пути, одну за другой. Помните, что вам нужно понять принцип, чтобы решить проблему.