[FFmpeg-devel] [RFC] SVX8 stereo files and AVCODEC_MAX_AUDIO_FRAME_SIZE

Stefano Sabatini stefano.sabatini-lala at poste.it
Tue May 17 01:07:33 CEST 2011


On date Monday 2011-05-16 18:50:08 +0200, Michael Niedermayer encoded:
> On Sun, May 15, 2011 at 09:23:11PM +0200, Stefano Sabatini wrote:
> > On date Sunday 2011-05-15 19:59:21 +0200, Stefano Sabatini encoded:
> > > On date Sunday 2011-05-15 16:42:03 +0200, Stefano Sabatini encoded:
> > > > On date Saturday 2011-05-14 22:19:02 +0200, Michael Niedermayer encoded:
> > > > > On Sat, May 14, 2011 at 11:07:24AM +0200, Stefano Sabatini wrote:
> > > > [...]
> > > > > the decoder can just copy the whole into a internal buffer and then
> > > > > return whatever fake partial reads it likes
> > > > > isnt pretty but its simple
> > > > 
> > > > I'm reading the whole audio chunk into the first packet, which is sent
> > > > to the decoder, and which decodes/interleaves the whole audio buffer
> > > > and returns it in little frames.
> > > > 
> > > > Check attached unfinished patches.
> > > > 
> > > > Now my problems is that for 8SVX files audio data format is signed
> > > > 8-bit, which I see is not directly supported as format (why?).
> > > > 
> > > > I could convert samples in the decoder signed->unsigned, but really
> > > > why signed 8-bit is not supported natively (and what would prevent
> > > > from adding it to resample/convert routines?).
> > > 
> > > Updated work in progress. int8 -> uint8 conversion is done in-codec,
> > > the clipping in delta_decode() looks necessary for avoiding overflow
> > > noise in 8svx_fib.iff (still can't understand why xine doesn't need
> > > it).
> > > 
> > 
> > > Not yet ready for commit (still some minor problems in the decode_frame
> > > codepath), please comment on the overall design.
> > 
> > Fixed.
> > 
> > Patch updated.
> > -- 
> > FFmpeg = Fundamental Funny Multipurpose Powered Encoding/decoding God
> 
> >  libavcodec/8svx.c      |  192 ++++++++++++++++++++++++++++++++++++++++---------
> >  libavcodec/allcodecs.c |    1 
> >  libavcodec/avcodec.h   |    1 
> >  libavformat/iff.c      |   40 +---------
> >  4 files changed, 163 insertions(+), 71 deletions(-)
> > 0ced7e8e1b767d93f03b902343c9db887daf7eea  0004-iff-8svx-re-desing-8SVX-demuxing-and-decoding-for-co.patch
> > From 3b19d249a0c1ead558f80b0e8e4454ef236130bb Mon Sep 17 00:00:00 2001
> > From: Stefano Sabatini <stefano.sabatini-lala at poste.it>
> > Date: Sun, 15 May 2011 13:24:46 +0200
> > Subject: [PATCH] iff/8svx: re-desing 8SVX demuxing and decoding for correctly handling stereo data
> > 
> > Make the iff demuxer send the whole audio chunk to the decoder, and by
> > moving interleaving from the iff demuxer to the decoder, and
> > introducing an 8svx_raw decoder which performs interleaving.
> > 
> > This is required for correctly handle stereo data, since samples is
> > stored like:
> > LLLLLL....RRRRRR
> > 
> > that is all left samples are at the beginning of the chunk, all right
> > samples at the end, so it is necessary to store and process the whole
> > buffer in order to decode each frame, so the decoder needs all the
> > data before starting to return interleaved data.
> > 
> > Fix decoding of files 8svx_exp.iff and 8svx_fib.iff, fix trac issue #169.
> > ---
> >  libavcodec/8svx.c      |  192 +++++++++++++++++++++++++++++++++++++++---------
> >  libavcodec/allcodecs.c |    1 +
> >  libavcodec/avcodec.h   |    1 +
> >  libavformat/iff.c      |   40 +---------
> >  4 files changed, 163 insertions(+), 71 deletions(-)
> > 
> > diff --git a/libavcodec/8svx.c b/libavcodec/8svx.c
> > index 4f95d90..1c5394f 100644
> > --- a/libavcodec/8svx.c
> > +++ b/libavcodec/8svx.c
> > @@ -1,5 +1,6 @@
> >  /*
> >   * Copyright (C) 2008 Jaikrishnan Menon
> > + * Copyright (C) 2011 Stefano Sabatini
> >   *
> >   * This file is part of FFmpeg.
> >   *
> > @@ -38,44 +39,137 @@
> >  
> >  /** decoder context */
> >  typedef struct EightSvxContext {
> > -    int16_t fib_acc;
> > -    const int16_t *table;
> > +    const int8_t *table;
> > +
> > +    /* buffer used to store the whole audio decoded/interleaved chunk,
> > +     * which is sent with the first packet */
> > +    uint8_t *samples;
> > +    size_t   samples_size;
> > +    int      samples_idx;
> >  } EightSvxContext;
> >  
> > -static const int16_t fibonacci[16]   = { -34<<8, -21<<8, -13<<8,  -8<<8, -5<<8, -3<<8, -2<<8, -1<<8,
> > -                                          0, 1<<8, 2<<8, 3<<8, 5<<8, 8<<8, 13<<8, 21<<8 };
> > -static const int16_t exponential[16] = { -128<<8, -64<<8, -32<<8, -16<<8, -8<<8, -4<<8, -2<<8, -1<<8,
> > -                                          0, 1<<8, 2<<8, 4<<8, 8<<8, 16<<8, 32<<8, 64<<8 };
> > +static const int8_t fibonacci[16]   = { -34,  -21, -13,  -8, -5, -3, -2, -1, 0, 1, 2, 3, 5, 8,  13, 21 };
> > +static const int8_t exponential[16] = { -128, -64, -32, -16, -8, -4, -2, -1, 0, 1, 2, 4, 8, 16, 32, 64 };
> > +
> > +#define MAX_FRAME_SIZE 2048
> > +
> > +/**
> > + * Interleave samples in buffer containing all left channel samples
> > + * at the beginning, and right channel samples at the end.
> > + * Each sample is assumed to be in signed 8-bit format.
> > + *
> > + * @param size the size in bytes of the dst and src buffer
> > + */
> > +static void interleave_stereo(uint8_t *dst, const uint8_t *src, int size)
> > +{
> > +    uint8_t *dst_end = dst + size;
> > +    size = size>>1;
> > +
> > +    while (dst < dst_end) {
> > +        *dst++ = *src;
> > +        *dst++ = *(src+size);
> > +        src++;
> > +    }
> > +}
> > +
> > +/**
> > + * Delta decode the compressed values in src, and put the resulting
> > + * decoded n samples in dst.
> > + *
> > + * @param val starting value assumed by the delta sequence
> > + * @param table delta sequence table
> > + * @return size in bytes of the decoded data, must be src_size*2
> > + */
> > +static int delta_decode(int8_t *dst, const uint8_t *src, int src_size,
> > +                        int8_t val, const int8_t *table)
> > +{
> > +    int n = src_size;
> > +    int8_t *dst0 = dst;
> > +
> > +    while (n--) {
> > +        uint8_t d = *src++;
> > +        val = av_clip(val + table[d & 0x0f], -127, 128);
> > +        *dst++ = val;
> > +        val = av_clip(val + table[d >> 4]  , -127, 128);
> > +        *dst++ = val;
> > +    }
> > +
> > +    return dst-dst0;
> > +}
> >  
> >  static int eightsvx_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
> >                                   AVPacket *avpkt)
> >  {
> >      EightSvxContext *esc = avctx->priv_data;
> > +    int out_data_size, n, consumed;
> > +    uint8_t *src, *dst;
> >  
> > +    /* decode and interleave the first packet */
> > +    if (!esc->samples && avpkt) {
> > +        uint8_t *samples, *interleaved_samples;
> >  
> > +        esc->samples_size = avctx->codec->id == CODEC_ID_8SVX_RAW ?
> > +            avpkt->size : avctx->channels + (avpkt->size-avctx->channels) * 2;
> > +
> > +        /* decompress */
> > +        if (avctx->codec->id == CODEC_ID_8SVX_FIB || avctx->codec->id == CODEC_ID_8SVX_EXP) {
> > +            const uint8_t *buf = avpkt->data;
> > +            int buf_size = avpkt->size;
> > +            int n = esc->samples_size;
> >  
> > +            if (!(samples = av_malloc(esc->samples_size)))
> > +                return AVERROR(ENOMEM);
> 
> malloc() is not a terribly fast operation, maybe the buffer could be
> reused.

This buffer is indeed reused when possible (e.g. because there was no
interleaving).

What do you suggest to use in place of av_malloc()?

> 
> 
> >  
> > +            /* the uncompressed starting value is contained in the first byte */
> > +            if (avctx->channels == 2) {
> > +                delta_decode(samples      , buf+1, buf_size/2-1, buf[0], esc->table);
> > +                buf += buf_size/2;
> > +                delta_decode(samples+n/2-1, buf+1, buf_size/2-1, buf[0], esc->table);
> > +            } else
> > +                delta_decode(samples      , buf+1, buf_size-1  , buf[0], esc->table);
> > +        } else
> > +            samples = avpkt->data;
> > +
> > +        /* interleave */
> > +        if (avctx->channels == 2) {
> > +            if (!(interleaved_samples = av_malloc(esc->samples_size)))
> > +                return AVERROR(ENOMEM);
> > +            interleave_stereo(interleaved_samples, samples, esc->samples_size);
> > +            if (samples != avpkt->data)
> > +                av_freep(&samples);
> > +        } else
> > +            interleaved_samples = samples;
> > +
> > +        /* copy data if necessary */
> > +        if (interleaved_samples == avpkt->data) {
> > +            if (!(interleaved_samples = av_malloc(esc->samples_size)))
> > +                return AVERROR(ENOMEM);
> > +            memcpy(interleaved_samples, samples, esc->samples_size);
> > +        }
> > +
> > +        esc->samples = interleaved_samples;
> >      }
> >  
> > +    /* return frames with fixed size */
> > +    out_data_size = FFMIN(MAX_FRAME_SIZE, esc->samples_size - esc->samples_idx);
> > +    if (*data_size < out_data_size) {
> > +        av_log(avctx, AV_LOG_ERROR, "Provided buffer with size %d is too small.\n", *data_size);
> > +        return AVERROR(EINVAL);
> > +    }
> > +
> > +    *data_size = out_data_size;
> > +    dst = data;
> > +    src = esc->samples + esc->samples_idx;
> 
> > +    for (n = out_data_size; n > 0; n--)
> > +        *dst++ = *src++ + 128;
> 
> a ^0x80808080 could be used to add 128 to 4 at once

Uhm, possible, but I agree it would be better to apply this
optimization as a separate patch.

> anyway, the patch is LGTM if tested, above can be done
> later / seperately

Patch applied (with FATE reg update and various build minor problems I
forgot to address in the patch).
-- 
FFmpeg = Fast & Furious Merciful Philosophical Enchanting Gospel


More information about the ffmpeg-devel mailing list