+static int atrac3p_decode_frame(AVCodecContext *avctx, void *data,
+ int *got_frame_ptr, AVPacket *avpkt)
+{
+ ATRAC3PContext *ctx = avctx->priv_data;
+ AVFrame *frame = data;
+ int i, ret, ch_unit_id, ch_block = 0, out_ch_index = 0,
channels_to_process;
+ float **samples_p = (float **)frame->extended_data;
+
+ frame->nb_samples = ATRAC3P_FRAME_SAMPLES;
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ return ret;
+ }
+
+ if ((ret = init_get_bits8(&ctx->gb, avpkt->data, avpkt->size)) < 0)
+ return ret;
+
+ if (get_bits1(&ctx->gb)) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid start bit!\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ while (get_bits_left(&ctx->gb) >= 2 &&
+ (ch_unit_id = get_bits(&ctx->gb, 2)) !=
CH_UNIT_TERMINATOR) {
+ if (ch_unit_id == CH_UNIT_EXTENSION) {
+ avpriv_report_missing_feature(avctx, "Channel unit
extension");
+ return AVERROR_PATCHWELCOME;
+ }
+ if (ch_block >= ctx->num_channel_blocks ||
+ ctx->channel_blocks[ch_block] != ch_unit_id) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Frame data doesn't match channel
configuration!\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ ctx->ch_units[ch_block].unit_type = ch_unit_id;
+ channels_to_process = ch_unit_id + 1;
+
+ if ((ret = ff_atrac3p_decode_channel_unit(&ctx->gb,
+ &ctx->ch_units[ch_block],
+ channels_to_process,
+ avctx)) < 0)
+ return ret;
+
+ decode_residual_spectrum(&ctx->ch_units[ch_block], ctx->samples,
+ channels_to_process, avctx);
+ reconstruct_frame(ctx, &ctx->ch_units[ch_block],
+ channels_to_process, avctx);
+
+ for (i = 0; i < channels_to_process; i++)
+ memcpy(samples_p[out_ch_index + i], ctx->outp_buf[i],
+ ATRAC3P_FRAME_SAMPLES * sizeof(**samples_p));
+
+ ch_block++;
+ out_ch_index += channels_to_process;
+ }
+
+ *got_frame_ptr = 1;
+
+ return avctx->block_align;
+}