static int xan_decode_frame(AVCodecContext *avctx,

                            void *data, int *data_size,

                            AVPacket *avpkt)

{

    const uint8_t *buf = avpkt->data;

    int ret, buf_size = avpkt->size;

    XanContext *s = avctx->priv_data;



    if (avctx->codec->id == CODEC_ID_XAN_WC3) {

        const uint8_t *buf_end = buf + buf_size;

        int tag = 0;

        while (buf_end - buf > 8 && tag != VGA__TAG) {

            unsigned *tmpptr;

            uint32_t new_pal;

            int size;

            int i;

            tag  = bytestream_get_le32(&buf);

            size = bytestream_get_be32(&buf);

            size = FFMIN(size, buf_end - buf);

            switch (tag) {

            case PALT_TAG:

                if (size < PALETTE_SIZE)

                    return AVERROR_INVALIDDATA;

                if (s->palettes_count >= PALETTES_MAX)

                    return AVERROR_INVALIDDATA;

                tmpptr = av_realloc(s->palettes, (s->palettes_count + 1) * AVPALETTE_SIZE);

                if (!tmpptr)

                    return AVERROR(ENOMEM);

                s->palettes = tmpptr;

                tmpptr += s->palettes_count * AVPALETTE_COUNT;

                for (i = 0; i < PALETTE_COUNT; i++) {

#if RUNTIME_GAMMA

                    int r = gamma_corr(*buf++);

                    int g = gamma_corr(*buf++);

                    int b = gamma_corr(*buf++);

#else

                    int r = gamma_lookup[*buf++];

                    int g = gamma_lookup[*buf++];

                    int b = gamma_lookup[*buf++];

#endif

                    *tmpptr++ = (r << 16) | (g << 8) | b;

                }

                s->palettes_count++;

                break;

            case SHOT_TAG:

                if (size < 4)

                    return AVERROR_INVALIDDATA;

                new_pal = bytestream_get_le32(&buf);

                if (new_pal < s->palettes_count) {

                    s->cur_palette = new_pal;

                } else

                    av_log(avctx, AV_LOG_ERROR, "Invalid palette selected\n");

                break;

            case VGA__TAG:

                break;

            default:

                buf += size;

                break;

            }

        }

        buf_size = buf_end - buf;

    }

    if ((ret = avctx->get_buffer(avctx, &s->current_frame))) {

        av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n");

        return ret;

    }

    s->current_frame.reference = 3;



    if (!s->frame_size)

        s->frame_size = s->current_frame.linesize[0] * s->avctx->height;



    memcpy(s->current_frame.data[1], s->palettes + s->cur_palette * AVPALETTE_COUNT, AVPALETTE_SIZE);



    s->buf = buf;

    s->size = buf_size;



    xan_wc3_decode_frame(s);



    /* release the last frame if it is allocated */

    if (s->last_frame.data[0])

        avctx->release_buffer(avctx, &s->last_frame);



    *data_size = sizeof(AVFrame);

    *(AVFrame*)data = s->current_frame;



    /* shuffle frames */

    FFSWAP(AVFrame, s->current_frame, s->last_frame);



    /* always report that the buffer was completely consumed */

    return buf_size;

}
