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

Carl Eugen Hoyos cehoyos at ag.or.at
Sat Nov 24 16:29:32 CET 2012


Hi!

On Saturday 24 November 2012 01:47:05 am Carl Eugen Hoyos wrote:
> 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.

Updated patch attached that contains a bitrate calculation that is needed for 
remuxing to wav.
I was unable to find a file that can be decoded (without distortions) with 
this patch applied but remuxing to au works fine and the distortions are not 
a regression afaict (I tested r2759), so I suspect this is problem with the 
G.726 implementation (or all other G.726 implementations).

I will push if nobody objects, Carl Eugen
-------------- next part --------------
diff --git a/libavformat/au.c b/libavformat/au.c
index d4d4ff3..cbcf34f 100644
--- a/libavformat/au.c
+++ b/libavformat/au.c
@@ -38,6 +38,10 @@
 /* the specification requires an annotation field of at least eight bytes */
 #define AU_HEADER_SIZE (24+8)
 
+typedef struct {
+    int bits_per_coded_sample;
+} 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 },
@@ -47,7 +51,10 @@ 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_G722, 24 },
+    { AV_CODEC_ID_ADPCM_G726, 25 },
+    { AV_CODEC_ID_ADPCM_G726, 26 },
     { AV_CODEC_ID_PCM_ALAW, 27 },
     { AV_CODEC_ID_NONE, 0 },
 };
@@ -58,6 +65,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, AU_HEADER_SIZE);  /* header size */
     avio_wb32(pb, AU_UNKNOWN_SIZE); /* data size */
@@ -124,7 +140,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;
@@ -149,7 +166,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->bits_per_coded_sample = (uint8_t []){4, 0, 3, 5}[id - 23];
+    } else if (!(au->bits_per_coded_sample = av_get_bits_per_sample(codec))) {
         av_log_ask_for_sample(s, "could not determine bits per sample\n");
         return AVERROR_INVALIDDATA;
     }
@@ -173,8 +192,11 @@ 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->bits_per_coded_sample;
+    st->codec->bit_rate = rate * au->bits_per_coded_sample;
     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->bits_per_coded_sample);
     avpriv_set_pts_info(st, 64, 1, rate);
     return 0;
 }
@@ -184,8 +206,9 @@ 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);
+    int bpcs = au->bits_per_coded_sample;
 
     if (!bpcs)
         return AVERROR(EINVAL);
@@ -203,6 +226,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