mirror of
https://gitee.com/openharmony/third_party_ffmpeg
synced 2024-11-23 11:19:55 +00:00
XMA1 and XMA2 stereo decoders
Signed-off-by: Paul B Mahol <onemda@gmail.com>
This commit is contained in:
parent
c8780822ba
commit
b456ece557
@ -30,6 +30,7 @@ version <next>:
|
||||
- innoHeim/Rsupport Screen Capture Codec decoder
|
||||
- ADPCM AICA decoder
|
||||
- Interplay ACM demuxer and audio decoder
|
||||
- XMA1 & XMA2 decoder
|
||||
|
||||
|
||||
version 2.8:
|
||||
|
@ -1076,6 +1076,8 @@ following image formats are supported:
|
||||
@item Windows Media Audio Lossless @tab @tab X
|
||||
@item Windows Media Audio Pro @tab @tab X
|
||||
@item Windows Media Audio Voice @tab @tab X
|
||||
@item Xbox Media Audio 1 @tab @tab X
|
||||
@item Xbox Media Audio 2 @tab @tab X
|
||||
@end multitable
|
||||
|
||||
@code{X} means that encoding (resp. decoding) is supported.
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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 */
|
||||
{
|
||||
|
@ -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, \
|
||||
|
@ -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 */
|
||||
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 */
|
||||
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;
|
||||
}
|
||||
|
||||
/** 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;
|
||||
}
|
||||
|
||||
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);
|
||||
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 },
|
||||
};
|
||||
|
@ -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 },
|
||||
|
@ -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);
|
||||
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,21 @@ 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;
|
||||
if (size < 8 + nb_streams * 20)
|
||||
return AVERROR_INVALIDDATA;
|
||||
for (i = 0; i < nb_streams; i++)
|
||||
codec->channels += codec->extradata[8 + i * 20 + 17];
|
||||
}
|
||||
|
||||
if (bitrate > INT_MAX) {
|
||||
|
Loading…
Reference in New Issue
Block a user