static int dpcm_decode_frame(AVCodecContext *avctx,

                             void *data, int *data_size,

                             uint8_t *buf, int buf_size)

{

    DPCMContext *s = avctx->priv_data;

    int in, out = 0;

    int predictor[2];

    int channel_number = 0;

    short *output_samples = data;

    int shift[2];

    unsigned char byte;

    short diff;



    if (!buf_size)

        return 0;



    // almost every DPCM variant expands one byte of data into two

    if(*data_size/2 < buf_size)




    switch(avctx->codec->id) {



    case CODEC_ID_ROQ_DPCM:

        if (s->channels == 1)

            predictor[0] = AV_RL16(&buf[6]);

        else {

            predictor[0] = buf[7] << 8;

            predictor[1] = buf[6] << 8;

        }

        SE_16BIT(predictor[0]);

        SE_16BIT(predictor[1]);



        /* decode the samples */

        for (in = 8, out = 0; in < buf_size; in++, out++) {

            predictor[channel_number] += s->roq_square_array[buf[in]];

            predictor[channel_number] = av_clip_int16(predictor[channel_number]);

            output_samples[out] = predictor[channel_number];



            /* toggle channel */

            channel_number ^= s->channels - 1;

        }

        break;



    case CODEC_ID_INTERPLAY_DPCM:

        in = 6;  /* skip over the stream mask and stream length */

        predictor[0] = AV_RL16(&buf[in]);

        in += 2;

        SE_16BIT(predictor[0])

        output_samples[out++] = predictor[0];

        if (s->channels == 2) {

            predictor[1] = AV_RL16(&buf[in]);

            in += 2;

            SE_16BIT(predictor[1])

            output_samples[out++] = predictor[1];

        }



        while (in < buf_size) {

            predictor[channel_number] += interplay_delta_table[buf[in++]];

            predictor[channel_number] = av_clip_int16(predictor[channel_number]);

            output_samples[out++] = predictor[channel_number];



            /* toggle channel */

            channel_number ^= s->channels - 1;

        }



        break;



    case CODEC_ID_XAN_DPCM:

        in = 0;

        shift[0] = shift[1] = 4;

        predictor[0] = AV_RL16(&buf[in]);

        in += 2;

        SE_16BIT(predictor[0]);

        if (s->channels == 2) {

            predictor[1] = AV_RL16(&buf[in]);

            in += 2;

            SE_16BIT(predictor[1]);

        }



        while (in < buf_size) {

            byte = buf[in++];

            diff = (byte & 0xFC) << 8;

            if ((byte & 0x03) == 3)

                shift[channel_number]++;

            else

                shift[channel_number] -= (2 * (byte & 3));

            /* saturate the shifter to a lower limit of 0 */

            if (shift[channel_number] < 0)

                shift[channel_number] = 0;



            diff >>= shift[channel_number];

            predictor[channel_number] += diff;



            predictor[channel_number] = av_clip_int16(predictor[channel_number]);

            output_samples[out++] = predictor[channel_number];



            /* toggle channel */

            channel_number ^= s->channels - 1;

        }

        break;

    case CODEC_ID_SOL_DPCM:

        in = 0;

        if (avctx->codec_tag != 3) {



            while (in < buf_size) {

                int n1, n2;

                n1 = (buf[in] >> 4) & 0xF;

                n2 = buf[in++] & 0xF;

                s->sample[0] += s->sol_table[n1];

                 if (s->sample[0] < 0) s->sample[0] = 0;

                if (s->sample[0] > 255) s->sample[0] = 255;

                output_samples[out++] = (s->sample[0] - 128) << 8;

                s->sample[s->channels - 1] += s->sol_table[n2];

                if (s->sample[s->channels - 1] < 0) s->sample[s->channels - 1] = 0;

                if (s->sample[s->channels - 1] > 255) s->sample[s->channels - 1] = 255;

                output_samples[out++] = (s->sample[s->channels - 1] - 128) << 8;

            }

        } else {

            while (in < buf_size) {

                int n;

                n = buf[in++];

                if (n & 0x80) s->sample[channel_number] -= s->sol_table[n & 0x7F];

                else s->sample[channel_number] += s->sol_table[n & 0x7F];

                s->sample[channel_number] = av_clip_int16(s->sample[channel_number]);

                output_samples[out++] = s->sample[channel_number];

                /* toggle channel */

                channel_number ^= s->channels - 1;

            }

        }

        break;

    }



    *data_size = out * sizeof(short);

    return buf_size;

}