summaryrefslogtreecommitdiff
path: root/libavcodec
diff options
context:
space:
mode:
authorPaul B Mahol <onemda@gmail.com>2015-11-01 13:15:36 +0100
committerPaul B Mahol <onemda@gmail.com>2015-11-06 13:45:50 +0100
commitb456ece55731c545d0bf62641fee2da437861987 (patch)
treec022717fc064f9c7b3b7f5dd3f13e51085b2e7a3 /libavcodec
parentc8780822bacc38a8d84c882d564b07dd152366ed (diff)
XMA1 and XMA2 stereo decoders
Signed-off-by: Paul B Mahol <onemda@gmail.com>
Diffstat (limited to 'libavcodec')
-rw-r--r--libavcodec/Makefile2
-rw-r--r--libavcodec/allcodecs.c2
-rw-r--r--libavcodec/avcodec.h2
-rw-r--r--libavcodec/codec_desc.c14
-rw-r--r--libavcodec/version.h2
-rw-r--r--libavcodec/wmaprodec.c131
6 files changed, 137 insertions, 16 deletions
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 67fb72ad9d..06d3ddd918 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 095f8128e2..4a21fe7b4b 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 91cd6a829f..95cdf5a823 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 c6117400a8..9cad3e6e47 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/version.h b/libavcodec/version.h
index cc4e2367b6..1e21f155fc 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -29,7 +29,7 @@
#include "libavutil/version.h"
#define LIBAVCODEC_VERSION_MAJOR 57
-#define LIBAVCODEC_VERSION_MINOR 14
+#define LIBAVCODEC_VERSION_MINOR 15
#define LIBAVCODEC_VERSION_MICRO 100
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
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 },
+};