4
int64_t timeBase;
timeBase = (int64_t(pavStrm-> time_base.num) * AV_TIME_BASE) / int64_t(pavStrm->time_base.den);
int64_t seekTarget = int64_t(iFrameNumber) * timeBase;
av_seek_frame(fmt_ctx, -1, seekTarget, AVSEEK_FLAG_FRAME);

ここでは、iFrameNumebr の後の次の 5 フレームを読み取りたい

for(int iCnt = 0; iCnt <= 4; iCnt++)
{
    iRet = av_read_frame(fmt_ctx, &pkt);
        do 
        {
            ret = decode_packet(&got_frame, 0);
            if (ret < 0)
                break;
            pkt.data += ret;
            pkt.size -= ret;

        }while (pkt.size > 0);
    av_free_packet(&pkt);
}

static int decode_packet(int *got_frame, int cached)
{
int ret = 0;
int decoded = pkt.size;
*got_frame = 0;

if (pkt.stream_index == video_stream_idx)
{
    /* decode video frame */
    ret = avcodec_decode_video2(video_dec_ctx, frame, got_frame, &pkt);
}

AVSEEK_FLAG_BACKWARD を使用している場合、5 パケットと 5 フレームの最初の 2 つは空白ですが正しいです。

AVSEEK_FLAG_FRAME を使用している場合、最初の 3 フレームではない 5 パケットと 3 フレームがビデオから返されます。

任意の iFrameNumber

フレーム番号を取得しながらフレームを取得する方法と、av_seek_frame() の seektarget 3 番目のパラメータの正確な値を教えてください。

フレームをrgb24形式に変換する際にも問題があります

4

3 に答える 3

19

最も一般的ですが、理解するのが難しい機能の 1 つだと思いますav_seek_frame()。また、十分にコメントされていません。

フラグAVSEEK_FLAG_FRAMEが設定されている場合、3 番目のパラメーターはシークするフレーム番号である必要があります。

をよりよく理解するための例を見てみましょうav_seek_frame():

fps=10 の 10 フレームのビデオがあるとします。1 番目と 5 番目のフレームがキー フレーム (I Frameまたはintra frame) です。その他は、何らかの形式の P フレームまたは B フレームです。

0 1 2 3 4 5 6 7 8 9 (フレーム番号)

0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 (タイムベース)

av_seek_frame(fmt_ctx, -1, 2, AVSEEK_FLAG_FRAME);
av_seek_frame(fmt_ctx, -1, 0.15, 0);
// These will seek to the fifth frame. Cause `AVSEEK_FLAG_ANY` is not given. Seeking to the next key frame after third parameter.

av_seek_frame(fmt_ctx, -1, 2, AVSEEK_FLAG_FRAME | AVSEEK_FLAG_ANY);
// This will seek to exactly the third parameter specified. But probably only a frame with no actual meaning. (We can't get a meaningful image if no related I/P/B frames given.)

av_seek_frame(fmt_ctx, -1, 0.15, AVSEEK_FLAG_ANY);
// Seek to 0.2. Nothing interesting as above.

av_seek_frame(fmt_ctx, -1, 0.15, AVSEEK_FLAG_ANY | AVSEEK_FLAG_BACKWARD);
// Seek to 0.1. Also nothing interesting.

av_seek_frame(fmt_ctx, -1, 2, AVSEEK_FLAG_FRAME | AVSEEK_FLAG_BACKWARD);
// Got the first frame. Seeking to the nearest key frame before the third parameter.

したがって、任意のフレームを取得したい場合は、通常はAVSEEK_FLAG_BACKWARD最初にシークし、通常どおりデコードします。次に、最初のいくつかのパケットのポイントと期間を確認し、それらをドロップする必要があるかどうかを確認します。

于 2016-10-12T04:16:06.280 に答える
1
timeBase = (int64_t(video_stream-> time_base.num) * AV_TIME_BASE) / int64_t(video_stream->time_base.den);
int64_t seekTarget = int64_t(iFrameNumber) * timeBase * (video_stream->time_base.den / video_stream->avg_frame_rate.num);


int iiiret = av_seek_frame(fmt_ctx, -1, seekTarget, AVSEEK_FLAG_FRAME);
于 2016-10-29T06:35:57.520 に答える