static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, const uint8_t *buf, int buf_size)

{

    SmackVContext * const smk = avctx->priv_data;

    uint8_t *out;

    uint32_t *pal;

    GetBitContext gb;

    int blocks, blk, bw, bh;

    int i;

    int stride;



    if(buf_size == 769)

        return 0;

    if(smk->pic.data[0])

            avctx->release_buffer(avctx, &smk->pic);



    smk->pic.reference = 1;

    smk->pic.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;

    if(avctx->reget_buffer(avctx, &smk->pic) < 0){

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

        return -1;

    }



    /* make the palette available on the way out */

    pal = (uint32_t*)smk->pic.data[1];

    smk->pic.palette_has_changed = buf[0] & 1;

    smk->pic.key_frame = !!(buf[0] & 2);

    if(smk->pic.key_frame)

        smk->pic.pict_type = FF_I_TYPE;

    else

        smk->pic.pict_type = FF_P_TYPE;



    buf++;

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

        *pal++ = bytestream_get_be24(&buf);

    buf_size -= 769;



    last_reset(smk->mmap_tbl, smk->mmap_last);

    last_reset(smk->mclr_tbl, smk->mclr_last);

    last_reset(smk->full_tbl, smk->full_last);

    last_reset(smk->type_tbl, smk->type_last);

    init_get_bits(&gb, buf, buf_size * 8);



    blk = 0;

    bw = avctx->width >> 2;

    bh = avctx->height >> 2;

    blocks = bw * bh;

    out = smk->pic.data[0];

    stride = smk->pic.linesize[0];

    while(blk < blocks) {

        int type, run, mode;

        uint16_t pix;



        type = smk_get_code(&gb, smk->type_tbl, smk->type_last);

        run = block_runs[(type >> 2) & 0x3F];

        switch(type & 3){

        case SMK_BLK_MONO:

            while(run-- && blk < blocks){

                int clr, map;

                int hi, lo;

                clr = smk_get_code(&gb, smk->mclr_tbl, smk->mclr_last);

                map = smk_get_code(&gb, smk->mmap_tbl, smk->mmap_last);

                out = smk->pic.data[0] + (blk / bw) * (stride * 4) + (blk % bw) * 4;

                hi = clr >> 8;

                lo = clr & 0xFF;

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

                    if(map & 1) out[0] = hi; else out[0] = lo;

                    if(map & 2) out[1] = hi; else out[1] = lo;

                    if(map & 4) out[2] = hi; else out[2] = lo;

                    if(map & 8) out[3] = hi; else out[3] = lo;

                    map >>= 4;

                    out += stride;

                }

                blk++;

            }

            break;

        case SMK_BLK_FULL:

            mode = 0;

            if(avctx->codec_tag == MKTAG('S', 'M', 'K', '4')) { // In case of Smacker v4 we have three modes

                if(get_bits1(&gb)) mode = 1;

                else if(get_bits1(&gb)) mode = 2;

            }

            while(run-- && blk < blocks){

                out = smk->pic.data[0] + (blk / bw) * (stride * 4) + (blk % bw) * 4;

                switch(mode){

                case 0:

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

                        pix = smk_get_code(&gb, smk->full_tbl, smk->full_last);

                        AV_WL16(out+2,pix);

                        pix = smk_get_code(&gb, smk->full_tbl, smk->full_last);

                        AV_WL16(out,pix);

                        out += stride;

                    }

                    break;

                case 1:

                    pix = smk_get_code(&gb, smk->full_tbl, smk->full_last);

                    out[0] = out[1] = pix & 0xFF;

                    out[2] = out[3] = pix >> 8;

                    out += stride;

                    out[0] = out[1] = pix & 0xFF;

                    out[2] = out[3] = pix >> 8;

                    out += stride;

                    pix = smk_get_code(&gb, smk->full_tbl, smk->full_last);

                    out[0] = out[1] = pix & 0xFF;

                    out[2] = out[3] = pix >> 8;

                    out += stride;

                    out[0] = out[1] = pix & 0xFF;

                    out[2] = out[3] = pix >> 8;

                    out += stride;

                    break;

                case 2:

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

                        uint16_t pix1, pix2;

                        pix1 = smk_get_code(&gb, smk->full_tbl, smk->full_last);

                        pix2 = smk_get_code(&gb, smk->full_tbl, smk->full_last);

                        AV_WL16(out,pix1);

                        AV_WL16(out+2,pix2);

                        out += stride;

                        AV_WL16(out,pix1);

                        AV_WL16(out+2,pix2);

                        out += stride;

                    }

                    break;

                }

                blk++;

            }

            break;

        case SMK_BLK_SKIP:

            while(run-- && blk < blocks)

                blk++;

            break;

        case SMK_BLK_FILL:

            mode = type >> 8;

            while(run-- && blk < blocks){

                uint32_t col;

                out = smk->pic.data[0] + (blk / bw) * (stride * 4) + (blk % bw) * 4;

                col = mode * 0x01010101;

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

                    *((uint32_t*)out) = col;

                    out += stride;

                }

                blk++;

            }

            break;

        }



    }



    *data_size = sizeof(AVFrame);

    *(AVFrame*)data = smk->pic;



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

    return buf_size;

}
