Question

Recently I upgraded ffmpeg from 0.9 to 1.0 (tested on Win7x64 and on iOS), and now avcodec_decode_video2 seagfaults. Long story short: the crash occurs every time the video dimensions change (eg. from 320x240 to 160x120 or vice versa).

I receive mpeg4 video stream from some proprietary source and decode it like this:

// 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_);

Again, all the above had worked flawlessly until I upgraded to 1.0. Now every time the frame dimensions change - avcodec_decode_video2 crashes. Note that I don't assign width/height in AVCodecContext - neither in the beginning, nor when the stream changes - can it be the reason?

I'd appreciate any idea!

Update: setting ctx_.width and ctx_.height doesn't help.

Update2: just before the crash I get the following log messages:

mpeg4, level 24: "Found 2 unreleased buffers!". level 8: "Assertion i < avci->buffer_count failed at libavcodec/utils.c:603"

Update3 upgrading to 1.1.2 fixed this crash. The decoder is able again to cope with dimensions change on the fly.

Was it helpful?

Solution

You can try to fill the AVPacket::side_data. If you change the frame size, codec receives information from it (see libavcodec/utils.c apply_param_change function)

This structure can be filled as follows:

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;
}

You need to call this function every time the size changes.

I think this feature has appeared recently. I didn't know about it until I looked new ffmpeg sources.

UPD

As you write, the easiest method to solve the problem is to perform codec restart. Just call avcodec_close / avcodec_open2

OTHER TIPS

I just ran into same issue when my frames were changing size on the fly. However, calling avcodec_close/avcodec_open2 is superflous. A cleaner way is to just reset your AVPacket data structure before the call to avcodec_decode_video2. Here it is the code:

av_init_packet(&packet_)

The key here is that this method resets the all of the values of AVPacket to defaults. Check docs for more info.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top