From b456ece55731c545d0bf62641fee2da437861987 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Sun, 1 Nov 2015 13:15:36 +0100 Subject: XMA1 and XMA2 stereo decoders Signed-off-by: Paul B Mahol --- libavcodec/wmaprodec.c | 131 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 116 insertions(+), 15 deletions(-) (limited to 'libavcodec/wmaprodec.c') diff --git a/libavcodec/wmaprodec.c b/libavcodec/wmaprodec.c index 19dc335b32..3b759f6158 100644 --- a/libavcodec/wmaprodec.c +++ b/libavcodec/wmaprodec.c @@ -206,9 +206,11 @@ typedef struct WMAProDecodeCtx { int subframe_offset; ///< subframe offset in the bit reservoir uint8_t packet_loss; ///< set in case of bitstream error uint8_t packet_done; ///< set when a packet is fully decoded + uint8_t skip_packets; /* frame decode state */ uint32_t frame_num; ///< current frame number (not used for decoding) + int num_frames; GetBitContext gb; ///< bitstream reader context int buf_bit_size; ///< buffer size in bits uint8_t drc_gain; ///< gain for the DRC tool @@ -268,6 +270,21 @@ static av_cold int decode_end(AVCodecContext *avctx) return 0; } +static av_cold int get_rate(AVCodecContext *avctx) +{ + if (avctx->codec_id != AV_CODEC_ID_WMAPRO) { // XXX: is this really only for XMA? + if (avctx->sample_rate > 44100) + return 48000; + else if (avctx->sample_rate > 32000) + return 44100; + else if (avctx->sample_rate > 24000) + return 32000; + return 24000; + } + + return avctx->sample_rate; +} + /** *@brief Initialize the decoder. *@param avctx codec context @@ -282,6 +299,9 @@ static av_cold int decode_init(AVCodecContext *avctx) int log2_max_num_subframes; int num_possible_block_sizes; + if (avctx->codec_id == AV_CODEC_ID_XMA1 || avctx->codec_id == AV_CODEC_ID_XMA2) + avctx->block_align = 2048; + if (!avctx->block_align) { av_log(avctx, AV_LOG_ERROR, "block_align is not set\n"); return AVERROR(EINVAL); @@ -296,7 +316,25 @@ static av_cold int decode_init(AVCodecContext *avctx) avctx->sample_fmt = AV_SAMPLE_FMT_FLTP; - if (avctx->extradata_size >= 18) { + if (avctx->codec_id == AV_CODEC_ID_XMA2 && avctx->extradata_size >= 34) { + s->decode_flags = 0x10d6; + channel_mask = AV_RL32(edata_ptr+2); + s->bits_per_sample = 16; + /** dump the extradata */ + for (i = 0; i < avctx->extradata_size; i++) + ff_dlog(avctx, "[%x] ", avctx->extradata[i]); + ff_dlog(avctx, "\n"); + + } else if (avctx->codec_id == AV_CODEC_ID_XMA1 && avctx->extradata_size >= 28) { + s->decode_flags = 0x10d6; + s->bits_per_sample = 16; + channel_mask = 0; + /** dump the extradata */ + for (i = 0; i < avctx->extradata_size; i++) + ff_dlog(avctx, "[%x] ", avctx->extradata[i]); + ff_dlog(avctx, "\n"); + + } else if (avctx->extradata_size >= 18) { s->decode_flags = AV_RL16(edata_ptr+14); channel_mask = AV_RL32(edata_ptr+2); s->bits_per_sample = AV_RL16(edata_ptr); @@ -310,6 +348,11 @@ static av_cold int decode_init(AVCodecContext *avctx) return AVERROR_PATCHWELCOME; } + if (avctx->codec_id != AV_CODEC_ID_WMAPRO && avctx->channels > 2) { + avpriv_report_missing_feature(avctx, ">2 channels support"); + return AVERROR_PATCHWELCOME; + } + /** generic init */ s->log2_frame_size = av_log2(avctx->block_align) + 4; if (s->log2_frame_size > 25) { @@ -318,17 +361,25 @@ static av_cold int decode_init(AVCodecContext *avctx) } /** frame info */ - s->skip_frame = 1; /* skip first frame */ + if (avctx->codec_id != AV_CODEC_ID_WMAPRO) + s->skip_frame = 0; + else + s->skip_frame = 1; /* skip first frame */ + s->packet_loss = 1; s->len_prefix = (s->decode_flags & 0x40); /** get frame len */ - bits = ff_wma_get_frame_len_bits(avctx->sample_rate, 3, s->decode_flags); - if (bits > WMAPRO_BLOCK_MAX_BITS) { - avpriv_request_sample(avctx, "14-bit block sizes"); - return AVERROR_PATCHWELCOME; + if (avctx->codec_id == AV_CODEC_ID_WMAPRO) { + bits = ff_wma_get_frame_len_bits(avctx->sample_rate, 3, s->decode_flags); + if (bits > WMAPRO_BLOCK_MAX_BITS) { + avpriv_request_sample(avctx, "14-bit block sizes"); + return AVERROR_PATCHWELCOME; + } + s->samples_per_frame = 1 << bits; + } else { + s->samples_per_frame = 512; } - s->samples_per_frame = 1 << bits; /** subframe info */ log2_max_num_subframes = ((s->decode_flags & 0x38) >> 3); @@ -417,12 +468,12 @@ static av_cold int decode_init(AVCodecContext *avctx) int subframe_len = s->samples_per_frame >> i; int x; int band = 1; + int rate = get_rate(avctx); s->sfb_offsets[i][0] = 0; for (x = 0; x < MAX_BANDS-1 && s->sfb_offsets[i][band - 1] < subframe_len; x++) { - int offset = (subframe_len * 2 * critical_freq[x]) - / s->avctx->sample_rate + 2; + int offset = (subframe_len * 2 * critical_freq[x]) / rate + 2; offset &= ~3; if (offset > s->sfb_offsets[i][band - 1]) s->sfb_offsets[i][band++] = offset; @@ -1535,32 +1586,52 @@ static int decode_packet(AVCodecContext *avctx, void *data, *got_frame_ptr = 0; + if (s->skip_packets > 0) { + s->skip_packets--; + return FFMIN(avpkt->size, avctx->block_align); + } + if (s->packet_done || s->packet_loss) { s->packet_done = 0; /** sanity check for the buffer length */ - if (buf_size < avctx->block_align) { + if (avctx->codec_id == AV_CODEC_ID_WMAPRO && buf_size < avctx->block_align) { av_log(avctx, AV_LOG_ERROR, "Input packet too small (%d < %d)\n", buf_size, avctx->block_align); return AVERROR_INVALIDDATA; } - s->next_packet_start = buf_size - avctx->block_align; - buf_size = avctx->block_align; + if (avctx->codec_id == AV_CODEC_ID_WMAPRO) { + s->next_packet_start = buf_size - avctx->block_align; + buf_size = avctx->block_align; + } else { + s->next_packet_start = buf_size - FFMIN(buf_size, avctx->block_align); + buf_size = FFMIN(buf_size, avctx->block_align); + } s->buf_bit_size = buf_size << 3; /** parse packet header */ init_get_bits(gb, buf, s->buf_bit_size); - packet_sequence_number = get_bits(gb, 4); - skip_bits(gb, 2); + if (avctx->codec_id == AV_CODEC_ID_WMAPRO) { + packet_sequence_number = get_bits(gb, 4); + skip_bits(gb, 2); + } else { + s->num_frames = get_bits(gb, 6); + packet_sequence_number = 0; + } /** get number of bits that need to be added to the previous frame */ num_bits_prev_frame = get_bits(gb, s->log2_frame_size); + if (avctx->codec_id != AV_CODEC_ID_WMAPRO) { + skip_bits(gb, 3); + s->skip_packets = get_bits(gb, 8); + } + ff_dlog(avctx, "packet[%d]: nbpf %x\n", avctx->frame_number, num_bits_prev_frame); /** check for packet loss */ - if (!s->packet_loss && + if (avctx->codec_id == AV_CODEC_ID_WMAPRO && !s->packet_loss && ((s->packet_sequence_number + 1) & 0xF) != packet_sequence_number) { s->packet_loss = 1; av_log(avctx, AV_LOG_ERROR, @@ -1671,3 +1742,33 @@ AVCodec ff_wmapro_decoder = { .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }, }; + +AVCodec ff_xma1_decoder = { + .name = "xma1", + .long_name = NULL_IF_CONFIG_SMALL("Xbox Media Audio 1"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_XMA1, + .priv_data_size = sizeof(WMAProDecodeCtx), + .init = decode_init, + .close = decode_end, + .decode = decode_packet, + .capabilities = AV_CODEC_CAP_SUBFRAMES | AV_CODEC_CAP_DR1, + .flush = flush, + .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, + AV_SAMPLE_FMT_NONE }, +}; + +AVCodec ff_xma2_decoder = { + .name = "xma2", + .long_name = NULL_IF_CONFIG_SMALL("Xbox Media Audio 2"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_XMA2, + .priv_data_size = sizeof(WMAProDecodeCtx), + .init = decode_init, + .close = decode_end, + .decode = decode_packet, + .capabilities = AV_CODEC_CAP_SUBFRAMES | AV_CODEC_CAP_DR1, + .flush = flush, + .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, + AV_SAMPLE_FMT_NONE }, +}; -- cgit v1.2.3