static void rpza_decode_stream(RpzaContext *s)

{

    int width = s->avctx->width;

    int stride = s->frame.linesize[0] / 2;

    int row_inc = stride - 4;

    int stream_ptr = 0;

    int chunk_size;

    unsigned char opcode;

    int n_blocks;

    unsigned short colorA = 0, colorB;

    unsigned short color4[4];

    unsigned char index, idx;

    unsigned short ta, tb;

    unsigned short *pixels = (unsigned short *)s->frame.data[0];



    int row_ptr = 0;

    int pixel_ptr = 0;

    int block_ptr;

    int pixel_x, pixel_y;

    int total_blocks;



    

    if (s->buf[stream_ptr] != 0xe1)

        av_log(s->avctx, AV_LOG_ERROR, "First chunk byte is 0x%02x instead of 0xe1\n",

            s->buf[stream_ptr]);



    

    chunk_size = AV_RB32(&s->buf[stream_ptr]) & 0x00FFFFFF;

    stream_ptr += 4;



    

    if (chunk_size != s->size)

        av_log(s->avctx, AV_LOG_ERROR, "MOV chunk size != encoded chunk size; using MOV chunk size\n");



    chunk_size = s->size;



    

    total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4);



    

    while (stream_ptr < chunk_size) {

        opcode = s->buf[stream_ptr++]; 



        n_blocks = (opcode & 0x1f) + 1; 



        

        if ((opcode & 0x80) == 0) {

            colorA = (opcode << 8) | (s->buf[stream_ptr++]);

            opcode = 0;

            if ((s->buf[stream_ptr] & 0x80) != 0) {

                





                opcode = 0x20;

                n_blocks = 1;

            }

        }



        switch (opcode & 0xe0) {



        

        case 0x80:

            while (n_blocks--) {

              ADVANCE_BLOCK();

            }

            break;



        

        case 0xa0:

            colorA = AV_RB16 (&s->buf[stream_ptr]);

            stream_ptr += 2;

            while (n_blocks--) {

                block_ptr = row_ptr + pixel_ptr;

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

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

                        pixels[block_ptr] = colorA;

                        block_ptr++;

                    }

                    block_ptr += row_inc;

                }

                ADVANCE_BLOCK();

            }

            break;



        

        case 0xc0:

            colorA = AV_RB16 (&s->buf[stream_ptr]);

            stream_ptr += 2;

        case 0x20:

            colorB = AV_RB16 (&s->buf[stream_ptr]);

            stream_ptr += 2;



            

            color4[0] = colorB;

            color4[1] = 0;

            color4[2] = 0;

            color4[3] = colorA;



            

            ta = (colorA >> 10) & 0x1F;

            tb = (colorB >> 10) & 0x1F;

            color4[1] |= ((11 * ta + 21 * tb) >> 5) << 10;

            color4[2] |= ((21 * ta + 11 * tb) >> 5) << 10;



            

            ta = (colorA >> 5) & 0x1F;

            tb = (colorB >> 5) & 0x1F;

            color4[1] |= ((11 * ta + 21 * tb) >> 5) << 5;

            color4[2] |= ((21 * ta + 11 * tb) >> 5) << 5;



            

            ta = colorA & 0x1F;

            tb = colorB & 0x1F;

            color4[1] |= ((11 * ta + 21 * tb) >> 5);

            color4[2] |= ((21 * ta + 11 * tb) >> 5);





            while (n_blocks--) {

                block_ptr = row_ptr + pixel_ptr;

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

                    index = s->buf[stream_ptr++];

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

                        idx = (index >> (2 * (3 - pixel_x))) & 0x03;

                        pixels[block_ptr] = color4[idx];

                        block_ptr++;

                    }

                    block_ptr += row_inc;

                }

                ADVANCE_BLOCK();

            }

            break;



        

        case 0x00:

            if (s->size - stream_ptr < 16)


            block_ptr = row_ptr + pixel_ptr;

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

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

                    

                    if ((pixel_y != 0) || (pixel_x !=0)) {

                        colorA = AV_RB16 (&s->buf[stream_ptr]);

                        stream_ptr += 2;

                    }

                    pixels[block_ptr] = colorA;

                    block_ptr++;

                }

                block_ptr += row_inc;

            }

            ADVANCE_BLOCK();

            break;



        

        default:

            av_log(s->avctx, AV_LOG_ERROR, "Unknown opcode %d in rpza chunk."

                 " Skip remaining %d bytes of chunk data.\n", opcode,

                 chunk_size - stream_ptr);


        } 

    }

}