static int dpcm_decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPacket *avpkt) { const uint8_t *buf = avpkt->data; int buf_size = avpkt->size; DPCMContext *s = avctx->priv_data; int in, out = 0; int predictor[2]; int ch = 0; int stereo = s->channels - 1; 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) return -1; switch(avctx->codec->id) { case CODEC_ID_ROQ_DPCM: if (stereo) { predictor[0] = buf[7] << 8; predictor[1] = buf[6] << 8; } else { predictor[0] = AV_RL16(&buf[6]); } SE_16BIT(predictor[0]); SE_16BIT(predictor[1]); /* decode the samples */ for (in = 8, out = 0; in < buf_size; in++, out++) { predictor[ch] += s->roq_square_array[buf[in]]; predictor[ch] = av_clip_int16(predictor[ch]); output_samples[out] = predictor[ch]; /* toggle channel */ ch ^= stereo; } 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 (stereo) { predictor[1] = AV_RL16(&buf[in]); in += 2; SE_16BIT(predictor[1]) output_samples[out++] = predictor[1]; } while (in < buf_size) { predictor[ch] += interplay_delta_table[buf[in++]]; predictor[ch] = av_clip_int16(predictor[ch]); output_samples[out++] = predictor[ch]; /* toggle channel */ ch ^= stereo; } 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 (stereo) { 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[ch]++; else shift[ch] -= (2 * (byte & 3)); /* saturate the shifter to a lower limit of 0 */ if (shift[ch] < 0) shift[ch] = 0; diff >>= shift[ch]; predictor[ch] += diff; predictor[ch] = av_clip_int16(predictor[ch]); output_samples[out++] = predictor[ch]; /* toggle channel */ ch ^= stereo; } break; case CODEC_ID_SOL_DPCM: in = 0; if (avctx->codec_tag != 3) { if(*data_size/4 < buf_size) return -1; 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[stereo] += s->sol_table[n2]; if (s->sample[stereo] < 0) s->sample[stereo] = 0; if (s->sample[stereo] > 255) s->sample[stereo] = 255; output_samples[out++] = (s->sample[stereo] - 128) << 8; } } else { while (in < buf_size) { int n; n = buf[in++]; if (n & 0x80) s->sample[ch] -= s->sol_table[n & 0x7F]; else s->sample[ch] += s->sol_table[n & 0x7F]; s->sample[ch] = av_clip_int16(s->sample[ch]); output_samples[out++] = s->sample[ch]; /* toggle channel */ ch ^= stereo; } } break; } *data_size = out * sizeof(short); return buf_size; }