+ AVFrame *frame = data;
+ int ret;
+
+ /* get output buffer */
+ frame->nb_samples = s->samples_per_frame;
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
+ s->packet_loss = 1;
+ return 0;
+ }
+
+ return decode_packet(avctx, s, data, got_frame_ptr, avpkt);
+}
+
+static int xma_decode_packet(AVCodecContext *avctx, void *data,
+ int *got_frame_ptr, AVPacket *avpkt)
+{
+ XMADecodeCtx *s = avctx->priv_data;
+ int got_stream_frame_ptr = 0;
+ AVFrame *frame = data;
+ int i, ret, offset = INT_MAX;
+
+ ret = decode_packet(avctx, &s->xma[s->current_stream], s->frames[s->current_stream],
+ &got_stream_frame_ptr, avpkt);
+
+ if (got_stream_frame_ptr) {
+ memcpy(&s->samples[s->current_stream * 2 + 0][s->offset[s->current_stream] * 512],
+ s->frames[s->current_stream]->extended_data[0], 512 * 4);
+ if (avctx->channels > 1)
+ memcpy(&s->samples[s->current_stream * 2 + 1][s->offset[s->current_stream] * 512],
+ s->frames[s->current_stream]->extended_data[1], 512 * 4);
+ s->offset[s->current_stream]++;
+ }
+
+ if (s->xma[s->current_stream].packet_done ||
+ s->xma[s->current_stream].packet_loss) {
+ int bret;
+
+ if (s->xma[s->current_stream].skip_packets == 0) {
+ ;
+ } else if (s->xma[0].skip_packets == 0 && avctx->channels >= 2) {
+ s->current_stream = 0;
+ } else if (s->xma[1].skip_packets == 0 && avctx->channels >= 4) {
+ s->current_stream = 1;
+ } else if (s->xma[2].skip_packets == 0 && avctx->channels >= 6) {
+ s->current_stream = 2;
+ } else if (s->xma[3].skip_packets == 0 && avctx->channels == 8) {
+ s->current_stream = 3;
+ } else {
+ int min[2];
+
+ min[0] = s->xma[0].skip_packets;
+ min[1] = i = 0;
+
+ for (i = 1; i < avctx->channels / 2; i++) {
+ if (s->xma[i].skip_packets < min[0]) {
+ min[1] = i;
+ min[0] = s->xma[i].skip_packets;
+ }
+ }
+
+ s->current_stream = min[1];
+ }
+
+ for (i = 0; i < avctx->channels / 2; i++) {
+ s->xma[i].skip_packets = FFMAX(0, s->xma[i].skip_packets - 1);
+ }
+
+ for (i = 0; i < (avctx->channels + 1) / 2; i++) {
+ offset = FFMIN(offset, s->offset[i]);
+ }
+
+ if (offset > 0) {
+ frame->nb_samples = 512 * offset;
+ if ((bret = ff_get_buffer(avctx, frame, 0)) < 0)
+ return bret;
+
+ for (i = 0; i < (avctx->channels + 1) / 2; i++) {
+ memcpy(frame->extended_data[i * 2 + 0], s->samples[i * 2 + 0], frame->nb_samples * 4);
+ if (avctx->channels > 1)
+ memcpy(frame->extended_data[i * 2 + 1], s->samples[i * 2 + 1], frame->nb_samples * 4);
+ s->offset[i] -= offset;
+ if (s->offset[i]) {
+ memmove(s->samples[i * 2 + 0], s->samples[i * 2 + 0] + frame->nb_samples, s->offset[i] * 4 * 512);
+ if (avctx->channels > 1)
+ memmove(s->samples[i * 2 + 1], s->samples[i * 2 + 1] + frame->nb_samples, s->offset[i] * 4 * 512);
+ }
+ }
+
+ *got_frame_ptr = 1;
+ }
+ }
+
+ return ret;
+}
+
+static av_cold int xma_decode_init(AVCodecContext *avctx)
+{
+ XMADecodeCtx *s = avctx->priv_data;
+ int i, ret;
+
+ if (avctx->channels <= 0 || avctx->channels > 8)
+ return AVERROR_INVALIDDATA;
+
+ for (i = 0; i < (avctx->channels + 1) / 2; i++) {
+ ret = decode_init(&s->xma[i], avctx);
+ if (ret < 0)
+ return ret;
+ s->frames[i] = av_frame_alloc();
+ if (!s->frames[i])
+ return AVERROR(ENOMEM);
+ s->frames[i]->nb_samples = 512;
+ if ((ret = ff_get_buffer(avctx, s->frames[i], 0)) < 0) {
+ return AVERROR(ENOMEM);
+ }
+
+ }
+
+ return ret;
+}
+
+static av_cold int xma_decode_end(AVCodecContext *avctx)
+{
+ XMADecodeCtx *s = avctx->priv_data;
+ int i;
+
+ for (i = 0; i < avctx->channels / 2; i++) {
+ decode_end(&s->xma[i]);
+ av_frame_free(&s->frames[i]);
+ }
+
+ return 0;
+}
+
+static void flush(WMAProDecodeCtx *s)
+{