Signed-off-by: Paul B Mahol <one...@gmail.com> --- libavcodec/Makefile | 2 ++ libavcodec/allcodecs.c | 2 ++ libavcodec/avcodec.h | 2 ++ libavcodec/codec_desc.c | 14 ++++++++ libavcodec/wmaprodec.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++--- libavformat/riff.c | 2 ++ libavformat/riffdec.c | 25 ++++++++++--- 7 files changed, 131 insertions(+), 10 deletions(-)
diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 67fb72a..06d3ddd 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -586,6 +586,8 @@ OBJS-$(CONFIG_XBM_ENCODER) += xbmenc.o OBJS-$(CONFIG_XFACE_DECODER) += xfacedec.o xface.o OBJS-$(CONFIG_XFACE_ENCODER) += xfaceenc.o xface.o OBJS-$(CONFIG_XL_DECODER) += xl.o +OBJS-$(CONFIG_XMA1_DECODER) += wmaprodec.o wma.o wma_common.o +OBJS-$(CONFIG_XMA2_DECODER) += wmaprodec.o wma.o wma_common.o OBJS-$(CONFIG_XSUB_DECODER) += xsubdec.o OBJS-$(CONFIG_XSUB_ENCODER) += xsubenc.o OBJS-$(CONFIG_XWD_DECODER) += xwddec.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 095f812..4a21fe7 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -445,6 +445,8 @@ void avcodec_register_all(void) REGISTER_ENCDEC (WMAV2, wmav2); REGISTER_DECODER(WMAVOICE, wmavoice); REGISTER_DECODER(WS_SND1, ws_snd1); + REGISTER_DECODER(XMA1, xma1); + REGISTER_DECODER(XMA2, xma2); /* PCM codecs */ REGISTER_ENCDEC (PCM_ALAW, pcm_alaw); diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 91cd6a8..95cdf5a 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -497,6 +497,8 @@ enum AVCodecID { AV_CODEC_ID_DSD_MSBF_PLANAR, AV_CODEC_ID_4GV, AV_CODEC_ID_INTERPLAY_ACM, + AV_CODEC_ID_XMA1, + AV_CODEC_ID_XMA2, /* subtitle codecs */ AV_CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs. diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index c611740..9cad3e6 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -2629,6 +2629,20 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Interplay ACM"), .props = AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_XMA1, + .type = AVMEDIA_TYPE_AUDIO, + .name = "xma1", + .long_name = NULL_IF_CONFIG_SMALL("Xbox Media Audio 1"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_XMA2, + .type = AVMEDIA_TYPE_AUDIO, + .name = "xma2", + .long_name = NULL_IF_CONFIG_SMALL("Xbox Media Audio 2"), + .props = AV_CODEC_PROP_LOSSY, + }, /* subtitle codecs */ { diff --git a/libavcodec/wmaprodec.c b/libavcodec/wmaprodec.c index 19dc335..7471961 100644 --- a/libavcodec/wmaprodec.c +++ b/libavcodec/wmaprodec.c @@ -86,6 +86,8 @@ * subframe in order to reconstruct the output samples. */ +#define DEBUG 1 + #include <inttypes.h> #include "libavutil/float_dsp.h" @@ -206,9 +208,12 @@ 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; + int8_t packet_metadata; /* 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 @@ -282,6 +287,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 +304,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 +336,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,7 +349,14 @@ 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 */ + if (avctx->codec_id == AV_CODEC_ID_XMA1) + s->packet_metadata = 0; + else + s->packet_metadata = 1; s->packet_loss = 1; s->len_prefix = (s->decode_flags & 0x40); @@ -1535,6 +1573,11 @@ 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; @@ -1551,16 +1594,27 @@ static int decode_packet(AVCodecContext *avctx, void *data, /** 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) { + if (get_bits(gb, 3) != s->packet_metadata) + return AVERROR_INVALIDDATA; + 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 +1725,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 }, +}; diff --git a/libavformat/riff.c b/libavformat/riff.c index 3eec611..f297dd4 100644 --- a/libavformat/riff.c +++ b/libavformat/riff.c @@ -424,6 +424,8 @@ const AVCodecTag ff_codec_wav_tags[] = { { AV_CODEC_ID_WMAV2, 0x0161 }, { AV_CODEC_ID_WMAPRO, 0x0162 }, { AV_CODEC_ID_WMALOSSLESS, 0x0163 }, + { AV_CODEC_ID_XMA1, 0x0165 }, + { AV_CODEC_ID_XMA2, 0x0166 }, { AV_CODEC_ID_ADPCM_CT, 0x0200 }, { AV_CODEC_ID_ATRAC3, 0x0270 }, { AV_CODEC_ID_ADPCM_G722, 0x028F }, diff --git a/libavformat/riffdec.c b/libavformat/riffdec.c index 26779e1..5022312 100644 --- a/libavformat/riffdec.c +++ b/libavformat/riffdec.c @@ -99,10 +99,12 @@ int ff_get_wav_header(AVFormatContext *s, AVIOContext *pb, codec->codec_type = AVMEDIA_TYPE_AUDIO; if (!big_endian) { id = avio_rl16(pb); - codec->channels = avio_rl16(pb); - codec->sample_rate = avio_rl32(pb); - bitrate = avio_rl32(pb) * 8LL; - codec->block_align = avio_rl16(pb); + if (id != 0x0165) { + codec->channels = avio_rl16(pb); + codec->sample_rate = avio_rl32(pb); + bitrate = avio_rl32(pb) * 8LL; + codec->block_align = avio_rl16(pb); + } } else { id = avio_rb16(pb); codec->channels = avio_rb16(pb); @@ -126,7 +128,7 @@ int ff_get_wav_header(AVFormatContext *s, AVIOContext *pb, codec->codec_id = ff_wav_codec_get_id(id, codec->bits_per_coded_sample); } - if (size >= 18) { /* We're obviously dealing with WAVEFORMATEX */ + if (size >= 18 && id != 0x0165) { /* We're obviously dealing with WAVEFORMATEX */ int cbSize = avio_rl16(pb); /* cbSize */ if (big_endian) { avpriv_report_missing_feature(codec, "WAVEFORMATEX support for RIFX files\n"); @@ -149,6 +151,19 @@ int ff_get_wav_header(AVFormatContext *s, AVIOContext *pb, /* It is possible for the chunk to contain garbage at the end */ if (size > 0) avio_skip(pb, size); + } else if (id == 0x0165 && size >= 32) { + int nb_streams, i; + + size -= 4; + av_freep(&codec->extradata); + if (ff_get_extradata(codec, pb, size) < 0) + return AVERROR(ENOMEM); + nb_streams = AV_RL16(codec->extradata + 4); + codec->sample_rate = AV_RL32(codec->extradata + 12); + codec->channels = 0; + bitrate = 0; + for (i = 0; i < nb_streams; i++) + codec->channels += codec->extradata[8 + i * 20 + 17]; } if (bitrate > INT_MAX) { -- 1.9.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel