Как я могу найти кадр № X с помощью ffmpeg?

Я пишу видеоредактор, и мне нужно найти точный кадр, зная номер кадра.

В других сообщениях на stackoverflow мне говорилось, что ffmpeg может дать мне несколько битых кадров после поиска, что не является проблемой для воспроизведения, но является большой проблемой для видеоредакторов.

И мне нужно искать по номеру кадра, не по времени, которое станет неточным при преобразовании в номер кадра.

Я прочитал tuts Дрейнджера (который сейчас устарел) и получил:

av_seek_frame(fmt_ctx, video_stream_id, frame, AVSEEK_FLAG_ANY);

Он всегда стремится к No. 0 и всегда return 0, что означает успех. Затем я попытался прочитать исходный код Blender и обнаружил, что он действительно сложный (может, мне стоит реализовать буфер изображений?).

Итак, есть ли простой способ перейти к кадру с помощью простого вызова, такого как seek(context, frame_number) (при получении полного кадра, а не сломанного)? Или есть какая-нибудь легкая библиотека, которая упрощает это?

РЕДАКТИРОВАТЬ: Благодаря praks411 , я нашел решение:

void AV_seek(AV * av, size_t frame)
{
    int frame_delta = frame - av->frame_id;
    if (frame_delta < 0 || frame_delta > 5)
        av_seek_frame(av->fmt_ctx, av->video_stream_id,
                frame, AVSEEK_FLAG_BACKWARD);
    while (av->frame_id != frame)
        AV_read_frame(av);
}

void AV_read_frame(AV * av)
{
    AVPacket packet;
    int frame_done;

    while (av_read_frame(av->fmt_ctx, &packet) >= 0) {
        if (packet.stream_index == av->video_stream_id) {
            avcodec_decode_video2(av->codec_ctx, av->frame, &frame_done, &packet);
            if (frame_done) {
                ...
                av->frame_id = packet.dts;
                av_free_packet(&packet);
                return;
            }
        }
        av_free_packet(&packet);
    }
}

EDIT2: Оказывается, для этого есть библиотека: FFMS2. Это «исходная библиотека [...] на основе FFmpeg для легкого доступа с точностью до кадра» и переносимая (по крайней мере, в Windows и Linux).


person Giumo    schedule 09.07.2013    source источник
comment
Вам гарантирован фиксированный стабильный fps? Тогда вы сможете искать по времени. См. Также обсуждение ключевого кадра   -  person rogerdpack    schedule 13.02.2014
comment
знает только пользователь. это может быть видео с переменной частотой кадров.   -  person Giumo    schedule 13.02.2014


Ответы (1)


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

Однако, если вы имеете дело с фиксированным значением FPS, вы можете легко сопоставить временную метку с индексом кадра.

Перед поиском вам нужно будет преобразовать ваше время в AVStream.time_base единиц, если вы указали поток. Прочтите документацию ffmpeg для av_seek_frame в avformat.h.

Например, если вы хотите найти 1.23 секунд клипа:

 double m_out_start_time = 1.23;
 int flgs = AVSEEK_FLAG_ANY;
 int seek_ts = (m_out_start_time*(m_in_vid_strm->time_base.den))/(m_in_vid_strm->time_base.num);
 if(av_seek_frame(m_informat, m_in_vid_strm_idx,seek_ts, flgs) < 0)
 {
     PRINT_MSG("Failed to seek Video ")
 }
person praks411    schedule 09.07.2013
comment
О, и я наконец знаю, что документация находится в файлах заголовков, неудивительно, что я не могу найти ее в Интернете. - person Giumo; 10.07.2013
comment
Тогда как я могу узнать, где находится ближайший ключевой кадр? - person Giumo; 10.07.2013
comment
Разве time_base.den / time_base.num - это не fps? Разве seek_ts = time * fps не номер кадра? - person Giumo; 10.07.2013
comment
Вы говорите о временной базе контекста кодека, я взял другое время потока. Для поиска ключевого кадра ближайшего времени. Я думаю, вы должны сохранять некоторую терпимость в поиске, то есть пытаться искать, скажем, за 3 кадра до вашего желаемого кадра, чтобы вы не пропустили свой кадр, если он не является ключевым кадром. Затем оттуда прочтите кадр за кадром. - person praks411; 10.07.2013
comment
После некоторых попыток я обнаружил, что мне нужно установить флаги на AVSEEK_FLAG_BACKWARD для поиска ключевого кадра. И seek_ts - номер кадра. Я также обнаружил, что в видеофайле, который я пробовал раньше, всего 4 ключевых кадра (WebM, всего 360 кадров, 30 кадров в секунду, не знаю почему), что действительно мешало моим экспериментам по поиску. - person Giumo; 11.07.2013
comment
Не следует ли вам также добавить m_in_vid_strm->start_time в seek_ts? - person Sam; 08.09.2015