]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/wmaprodec.c
Merge commit '99f40fd02f1870c2dee70977b672da9cb198f0be'
[ffmpeg] / libavcodec / wmaprodec.c
index 19dc335b3295b5395ed030130cc3d4dd96cdfb57..422478542d212a1ae74e46caf678376eaaf3511d 100644 (file)
@@ -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_XMA2) {
+            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_XMA2 && !s->packet_loss &&
             ((s->packet_sequence_number + 1) & 0xF) != packet_sequence_number) {
             s->packet_loss = 1;
             av_log(avctx, AV_LOG_ERROR,
@@ -1623,6 +1694,11 @@ static int decode_packet(AVCodecContext *avctx, void *data,
             s->packet_done = 1;
     }
 
+    if (remaining_bits(s, gb) < 0) {
+        av_log(avctx, AV_LOG_ERROR, "Overread %d\n", -remaining_bits(s, gb));
+        s->packet_loss = 1;
+    }
+
     if (s->packet_done && !s->packet_loss &&
         remaining_bits(s, gb) > 0) {
         /** save the rest of the data so that it can be decoded
@@ -1671,3 +1747,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 },
+};