static int decode_frame(AVCodecContext *avctx, void *data,

                        int *got_frame_ptr, AVPacket *pkt)

{

    SANMVideoContext *ctx = avctx->priv_data;

    int i, ret;



    bytestream2_init(&ctx->gb, pkt->data, pkt->size);

    if (ctx->output->data[0])

        avctx->release_buffer(avctx, ctx->output);



    if (!ctx->version) {

        int to_store = 0;



        while (bytestream2_get_bytes_left(&ctx->gb) >= 8) {

            uint32_t sig, size;

            int pos;



            sig  = bytestream2_get_be32u(&ctx->gb);

            size = bytestream2_get_be32u(&ctx->gb);

            pos  = bytestream2_tell(&ctx->gb);



            if (bytestream2_get_bytes_left(&ctx->gb) < size) {

                av_log(avctx, AV_LOG_ERROR, "incorrect chunk size %d\n", size);

                break;

            }

            switch (sig) {

            case MKBETAG('N', 'P', 'A', 'L'):

                if (size != 256 * 3) {

                    av_log(avctx, AV_LOG_ERROR, "incorrect palette block size %d\n",

                           size);

                    return AVERROR_INVALIDDATA;

                }

                for (i = 0; i < 256; i++)

                    ctx->pal[i] = 0xFF << 24 | bytestream2_get_be24u(&ctx->gb);

                break;

            case MKBETAG('F', 'O', 'B', 'J'):

                if (size < 16)

                    return AVERROR_INVALIDDATA;

                if (ret = process_frame_obj(ctx))

                    return ret;

                break;

            case MKBETAG('X', 'P', 'A', 'L'):

                if (size == 6 || size == 4) {

                    uint8_t tmp[3];

                    int j;



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

                        for (j = 0; j < 3; j++) {

                            int t = (ctx->pal[i] >> (16 - j * 8)) & 0xFF;

                            tmp[j] = av_clip_uint8((t * 129 + ctx->delta_pal[i * 3 + j]) >> 7);

                        }

                        ctx->pal[i] = 0xFF << 24 | AV_RB24(tmp);

                    }

                } else {

                    if (size < 768 * 2 + 4) {

                        av_log(avctx, AV_LOG_ERROR, "incorrect palette change block size %d\n",

                               size);

                        return AVERROR_INVALIDDATA;

                    }

                    bytestream2_skipu(&ctx->gb, 4);

                    for (i = 0; i < 768; i++)

                        ctx->delta_pal[i] = bytestream2_get_le16u(&ctx->gb);

                    if (size >= 768 * 5 + 4) {

                        for (i = 0; i < 256; i++)

                            ctx->pal[i] = 0xFF << 24 | bytestream2_get_be24u(&ctx->gb);

                    } else {

                        memset(ctx->pal, 0, sizeof(ctx->pal));

                    }

                }

                break;

            case MKBETAG('S', 'T', 'O', 'R'):

                to_store = 1;

                break;

            case MKBETAG('F', 'T', 'C', 'H'):

                memcpy(ctx->frm0, ctx->stored_frame, ctx->buf_size);

                break;

            default:

                bytestream2_skip(&ctx->gb, size);

                av_log(avctx, AV_LOG_DEBUG, "unknown/unsupported chunk %x\n", sig);

                break;

            }



            bytestream2_seek(&ctx->gb, pos + size, SEEK_SET);

            if (size & 1)

                bytestream2_skip(&ctx->gb, 1);

        }

        if (to_store)

            memcpy(ctx->stored_frame, ctx->frm0, ctx->buf_size);

        if ((ret = copy_output(ctx, NULL)))

            return ret;

        memcpy(ctx->output->data[1], ctx->pal, 1024);

    } else {

        SANMFrameHeader header;



        if ((ret = read_frame_header(ctx, &header)))

            return ret;



        ctx->rotate_code = header.rotate_code;

        if ((ctx->output->key_frame = !header.seq_num)) {

            ctx->output->pict_type = AV_PICTURE_TYPE_I;

            fill_frame(ctx->frm1, ctx->npixels, header.bg_color);

            fill_frame(ctx->frm2, ctx->npixels, header.bg_color);

        } else {

            ctx->output->pict_type = AV_PICTURE_TYPE_P;

        }



        if (header.codec < FF_ARRAY_ELEMS(v1_decoders)) {

            if ((ret = v1_decoders[header.codec](ctx))) {

                av_log(avctx, AV_LOG_ERROR,

                       "subcodec %d: error decoding frame\n", header.codec);

                return ret;

            }

        } else {

            av_log_ask_for_sample(avctx, "subcodec %d is not implemented\n",

                   header.codec);

            return AVERROR_PATCHWELCOME;

        }



        if ((ret = copy_output(ctx, &header)))

            return ret;

    }

    if (ctx->rotate_code)

        rotate_bufs(ctx, ctx->rotate_code);



    *got_frame_ptr  = 1;

    *(AVFrame*)data = *ctx->output;



    return pkt->size;

}
