|
|
|
@ -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 }, |
|
|
|
|
}; |
|
|
|
|