[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