[FFmpeg-devel] [RFC]Support G.726 in Sun AU

Carl Eugen Hoyos cehoyos at ag.or.at
Sat Nov 24 01:47:05 CET 2012


Hi!

Attached path was intended to fix ticket #1955.
Unfortunately, ffmpeg decodes the sample with distortions with the patch, 
while sox decodes it fine. ffmpeg decodes samples made with the patch and its 
own encoder fine, sox encodes code_size 4 with distortions, 3 and 5 as white 
noise.

Please comment, Carl Eugen
-------------- next part --------------
diff --git a/libavformat/au.c b/libavformat/au.c
index 788e261..58628a1 100644
--- a/libavformat/au.c
+++ b/libavformat/au.c
@@ -36,6 +36,10 @@
 /* if we don't know the size in advance */
 #define AU_UNKNOWN_SIZE ((uint32_t)(~0))
 
+typedef struct {
+    int bps;
+} AUContext;
+
 /* The libavcodec codecs we support, and the IDs they have in the file */
 static const AVCodecTag codec_au_tags[] = {
     { AV_CODEC_ID_PCM_MULAW, 1 },
@@ -45,6 +49,9 @@ 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_G726, 23 },
+    { AV_CODEC_ID_ADPCM_G726, 25 },
+    { AV_CODEC_ID_ADPCM_G726, 26 },
     { AV_CODEC_ID_PCM_ALAW, 27 },
     { AV_CODEC_ID_NONE, 0 },
 };
@@ -55,6 +62,15 @@ static int put_au_header(AVIOContext *pb, AVCodecContext *enc)
 {
     if(!enc->codec_tag)
         return -1;
+    if (enc->codec_id == AV_CODEC_ID_ADPCM_G726) {
+        if (enc->bits_per_coded_sample < 3 || enc->bits_per_coded_sample > 5) {
+            av_log(pb, AV_LOG_ERROR,
+                   "bits_per_coded_sample '%d' not supported for G.726 in Sun AU\n",
+                   enc->bits_per_coded_sample);
+            return AVERROR_INVALIDDATA;
+        }
+        enc->codec_tag = (uint8_t []){23, 26, 0, 25}[enc->bits_per_coded_sample & 3];
+    }
     ffio_wfourcc(pb, ".snd");    /* magic number */
     avio_wb32(pb, 24);           /* header size */
     avio_wb32(pb, AU_UNKNOWN_SIZE); /* data size */
@@ -120,7 +136,8 @@ static int au_probe(AVProbeData *p)
 /* au input */
 static int au_read_header(AVFormatContext *s)
 {
-    int size, bps, data_size = 0;
+    AUContext *au = s->priv_data;
+    int size, data_size = 0;
     unsigned int tag;
     AVIOContext *pb = s->pb;
     unsigned int id, channels, rate;
@@ -145,7 +162,9 @@ static int au_read_header(AVFormatContext *s)
 
     codec = ff_codec_get_id(codec_au_tags, id);
 
-    if (!(bps = av_get_bits_per_sample(codec))) {
+    if (codec == AV_CODEC_ID_ADPCM_G726) {
+        au->bps = (uint8_t []){4, 0, 3, 5}[id - 23];
+    } else if (!(au->bps = av_get_bits_per_sample(codec))) {
         av_log_ask_for_sample(s, "could not determine bits per sample\n");
         return AVERROR_INVALIDDATA;
     }
@@ -169,8 +188,9 @@ 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 = au->bps;
     if (data_size != AU_UNKNOWN_SIZE)
-    st->duration = (((int64_t)data_size)<<3) / (st->codec->channels * (int64_t)bps);
+        st->duration = (((int64_t)data_size)<<3) / (st->codec->channels * (int64_t)au->bps);
     avpriv_set_pts_info(st, 64, 1, rate);
     return 0;
 }
@@ -180,14 +200,14 @@ static int au_read_header(AVFormatContext *s)
 static int au_read_packet(AVFormatContext *s,
                           AVPacket *pkt)
 {
+    AUContext *au = s->priv_data;
     int ret;
-    int bpcs = av_get_bits_per_sample(s->streams[0]->codec->codec_id);
 
-    if (!bpcs)
+    if (!au->bps)
         return AVERROR(EINVAL);
     ret= av_get_packet(s->pb, pkt, BLOCK_SIZE *
                        s->streams[0]->codec->channels *
-                       bpcs >> 3);
+                       au->bps >> 3);
     if (ret < 0)
         return ret;
     pkt->flags &= ~AV_PKT_FLAG_CORRUPT;
@@ -199,6 +219,7 @@ static int au_read_packet(AVFormatContext *s,
 AVInputFormat ff_au_demuxer = {
     .name           = "au",
     .long_name      = NULL_IF_CONFIG_SMALL("Sun AU"),
+    .priv_data_size = sizeof(AUContext),
     .read_probe     = au_probe,
     .read_header    = au_read_header,
     .read_packet    = au_read_packet,


More information about the ffmpeg-devel mailing list