[FFmpeg-devel] [PATCH]Add little-endian G726 decoder and use it for Sun AU files
Carl Eugen Hoyos
cehoyos at ag.or.at
Thu Jul 11 14:06:20 CEST 2013
Hi!
Attached patch fixes ticket #1955 as suggested by Roman.
Please comment, Carl Eugen
-------------- next part --------------
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 5cdf778..90d8ec9 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -430,6 +430,7 @@ void avcodec_register_all(void)
REGISTER_DECODER(ADPCM_EA_XAS, adpcm_ea_xas);
REGISTER_ENCDEC (ADPCM_G722, adpcm_g722);
REGISTER_ENCDEC (ADPCM_G726, adpcm_g726);
+ REGISTER_DECODER(ADPCM_G726LE, adpcm_g726le);
REGISTER_DECODER(ADPCM_IMA_AMV, adpcm_ima_amv);
REGISTER_DECODER(ADPCM_IMA_APC, adpcm_ima_apc);
REGISTER_DECODER(ADPCM_IMA_DK3, adpcm_ima_dk3);
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index f0ccfee..d069345 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -370,6 +370,7 @@ enum AVCodecID {
AV_CODEC_ID_ADPCM_IMA_OKI = MKBETAG('O','K','I',' '),
AV_CODEC_ID_ADPCM_DTK = MKBETAG('D','T','K',' '),
AV_CODEC_ID_ADPCM_IMA_RAD = MKBETAG('R','A','D',' '),
+ AV_CODEC_ID_ADPCM_G726LE = MKBETAG('6','2','7','G'),
/* AMR */
AV_CODEC_ID_AMR_NB = 0x12000,
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index adc4772..cf1888e 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -1845,6 +1845,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
.long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Radical"),
.props = AV_CODEC_PROP_LOSSY,
},
+ {
+ .id = AV_CODEC_ID_ADPCM_G726LE,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "adpcm_g726le",
+ .long_name = NULL_IF_CONFIG_SMALL("G.726 ADPCM little-endian"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
/* AMR */
{
diff --git a/libavcodec/g726.c b/libavcodec/g726.c
index 7884f36..7db89ef 100644
--- a/libavcodec/g726.c
+++ b/libavcodec/g726.c
@@ -96,6 +96,7 @@ typedef struct G726Context {
int sez; /**< estimated second order prediction */
int y; /**< quantizer scaling factor for the next iteration */
int code_size;
+ int little_endian; /**< little-endian bitstream as used in aiff and Sun AU */
} G726Context;
static const int quant_tbl16[] = /**< 16kbit/s 2bits per sample */
@@ -396,7 +397,7 @@ AVCodec ff_adpcm_g726_encoder = {
};
#endif
-#if CONFIG_ADPCM_G726_DECODER
+#if CONFIG_ADPCM_G726_DECODER || CONFIG_ADPCM_G726LE_DECODER
static av_cold int g726_decode_init(AVCodecContext *avctx)
{
G726Context* c = avctx->priv_data;
@@ -404,6 +405,8 @@ static av_cold int g726_decode_init(AVCodecContext *avctx)
avctx->channels = 1;
avctx->channel_layout = AV_CH_LAYOUT_MONO;
+ c->little_endian = !strcmp(avctx->codec->name, "g726le");
+
c->code_size = avctx->bits_per_coded_sample;
if (c->code_size < 2 || c->code_size > 5) {
av_log(avctx, AV_LOG_ERROR, "Invalid number of bits %d\n", c->code_size);
@@ -438,7 +441,9 @@ static int g726_decode_frame(AVCodecContext *avctx, void *data,
init_get_bits(&gb, buf, buf_size * 8);
while (out_samples--)
- *samples++ = g726_decode(c, get_bits(&gb, c->code_size));
+ *samples++ = g726_decode(c, c->little_endian ?
+ get_bits_le(&gb, c->code_size) :
+ get_bits(&gb, c->code_size));
if (get_bits_left(&gb) > 0)
av_log(avctx, AV_LOG_ERROR, "Frame invalidly split, missing parser?\n");
@@ -453,7 +458,9 @@ static void g726_decode_flush(AVCodecContext *avctx)
G726Context *c = avctx->priv_data;
g726_reset(c);
}
+#endif
+#if CONFIG_ADPCM_G726_DECODER
AVCodec ff_adpcm_g726_decoder = {
.name = "g726",
.type = AVMEDIA_TYPE_AUDIO,
@@ -466,3 +473,17 @@ AVCodec ff_adpcm_g726_decoder = {
.long_name = NULL_IF_CONFIG_SMALL("G.726 ADPCM"),
};
#endif
+
+#if CONFIG_ADPCM_G726LE_DECODER
+AVCodec ff_adpcm_g726le_decoder = {
+ .name = "g726le",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_ADPCM_G726LE,
+ .priv_data_size = sizeof(G726Context),
+ .init = g726_decode_init,
+ .decode = g726_decode_frame,
+ .flush = g726_decode_flush,
+ .capabilities = CODEC_CAP_DR1,
+ .long_name = NULL_IF_CONFIG_SMALL("G.726 ADPCM little-endian"),
+};
+#endif
diff --git a/libavformat/au.c b/libavformat/au.c
index 22004d0..5546c7f 100644
--- a/libavformat/au.c
+++ b/libavformat/au.c
@@ -45,8 +45,12 @@ static const AVCodecTag codec_au_tags[] = {
{ AV_CODEC_ID_PCM_S32BE, 5 },
{ AV_CODEC_ID_PCM_F32BE, 6 },
{ AV_CODEC_ID_PCM_F64BE, 7 },
+ { AV_CODEC_ID_ADPCM_G726LE, 23 },
{ AV_CODEC_ID_ADPCM_G722,24 },
+ { AV_CODEC_ID_ADPCM_G726LE, 25 },
+ { AV_CODEC_ID_ADPCM_G726LE, 26 },
{ AV_CODEC_ID_PCM_ALAW, 27 },
+ { AV_CODEC_ID_ADPCM_G726LE, MKBETAG('7','2','6','2') },
{ AV_CODEC_ID_NONE, 0 },
};
@@ -101,7 +105,14 @@ static int au_read_header(AVFormatContext *s)
}
bps = av_get_bits_per_sample(codec);
- if (!bps) {
+ if (codec == AV_CODEC_ID_ADPCM_G726LE) {
+ if (id == MKBETAG('7','2','6','2')) {
+ bps = 2;
+ } else {
+ const uint8_t bpcss[] = {4, 0, 3, 5};
+ bps = bpcss[id - 23];
+ }
+ } else if (!bps) {
avpriv_request_sample(s, "Unknown bits per sample");
return AVERROR_PATCHWELCOME;
}
@@ -124,6 +135,7 @@ static int au_read_header(AVFormatContext *s)
st->codec->codec_id = codec;
st->codec->channels = channels;
st->codec->sample_rate = rate;
+ st->codec->bits_per_coded_sample = bps;
st->codec->bit_rate = channels * rate * bps;
st->codec->block_align = FFMAX(bps * st->codec->channels / 8, 1);
if (data_size != AU_UNKNOWN_SIZE)
More information about the ffmpeg-devel
mailing list