4

最近、ffmpeg を 0.9 から 1.0 にアップグレードしました (Win7x64 および iOS でテスト済み) avcodec_decode_video2。簡単に言うと、ビデオのサイズが変更されるたびにクラッシュが発生します (例: 320x240 から 160x120 に、またはその逆)。

独自のソースから mpeg4 ビデオ ストリームを受信し、次のようにデコードします。

// once, during initialization:
AVCodec *codec_ = avcodec_find_decoder(CODEC_ID_MPEG4);
AVCodecContext ctx_ = avcodec_alloc_context3(codec_);
avcodec_open2(ctx_, codec_, 0);
AVPacket packet_;
av_init_packet(&packet_);
AVFrame picture_ = avcodec_alloc_frame();

// on every frame:
int got_picture;
packet_.size = size;
packet_.data = (uint8_t *)buffer;
avcodec_decode_video2(ctx_, picture_, &got_picture, &packet_);

繰り返しますが、上記のすべては、1.0 にアップグレードするまで問題なく機能していました。フレームの寸法が変わるたびに -avcodec_decode_video2クラッシュします。AVCodecContext で幅/高さを割り当てていないことに注意してください-最初もストリームが変更されたときも-それが理由でしょうか?

アイデアをいただければ幸いです。

更新: ctx_.width と ctx_.height を設定しても役に立ちません。

Update2:クラッシュの直前に、次のログ メッセージが表示されます。

mpeg4、レベル 24: "未解放のバッファが 2 つ見つかりました!". レベル 8: 「アサーション i < avci->buffer_count が libavcodec/utils.c:603 で失敗しました」

Update3を 1.1.2 にアップグレードすると、このクラッシュが修正されました。デコーダは、オンザフライで次元の変更に再び対処できます。

4

2 に答える 2

3

を埋めてみることができますAVPacket::side_data。フレームサイズを変更すると、コーデックはフレームサイズから情報を受け取ります(を参照libavcodec/utils.c apply_param_change function) 。

この構造は次のように埋めることができます。

int my_ff_add_param_change(AVPacket *pkt, int32_t width, int32_t height)
{
    uint32_t flags = 0;
    int size = 4 * 3;
    uint8_t *data;
    if (!pkt)
        return AVERROR(EINVAL);

    flags = AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS;
    data = av_packet_new_side_data(pkt, AV_PKT_DATA_PARAM_CHANGE, size);

    if (!data)
        return AVERROR(ENOMEM);

    ((uint32_t*)data)[0] = flags;
    ((uint32_t*)data)[1] = width;
    ((uint32_t*)data)[2] = height;
    return 0;
}

サイズが変わるたびにこの関数を呼び出す必要があります。

この機能は最近登場したと思います。新しいffmpegソースを探すまで、私はそれについて知りませんでした。

UPD

あなたが書いているように、問題を解決する最も簡単な方法はコーデックの再起動を実行することです。avcodec_close/に電話するだけavcodec_open2

于 2012-12-03T20:48:03.573 に答える
0

フレームのサイズがその場で変更されたときに、同じ問題に遭遇しました。ただし、avcodec_close/avcodec_open2 の呼び出しは不要です。よりクリーンな方法は、avcodec_decode_video2 を呼び出す前に、AVPacket データ構造をリセットすることです。ここにコードがあります:

av_init_packet(&packet_)

ここで重要なのは、このメソッドが AVPacket のすべての値をデフォルトにリセットすることです。詳細については、ドキュメントを確認してください。

于 2014-05-05T17:28:47.253 に答える