[FFmpeg-devel] [PATCH] QCELP decoder

Michael Niedermayer michaelni
Mon Dec 1 22:39:58 CET 2008


On Mon, Dec 01, 2008 at 12:45:09PM -0800, Kenan Gillet wrote:
> Hi,
> On Mon, Dec 1, 2008 at 8:24 AM, Michael Niedermayer <michaelni at gmx.at> wrote:
> > On Mon, Dec 01, 2008 at 08:17:52AM -0800, Kenan Gillet wrote:
> >>
> >> On Dec 1, 2008, at 4:52 AM, Michael Niedermayer wrote:
> >>
> >> > On Sun, Nov 30, 2008 at 05:04:07PM -0800, Kenan Gillet wrote:
> >> >> Hi,
> >> >> On Nov 30, 2008, at 7:50 AM, Michael Niedermayer wrote:
> >> >>
> >> >>> On Sat, Nov 29, 2008 at 10:39:58AM -0800, Kenan Gillet wrote:
> > [...]
> >> > [...]
> >> >>>> +    /**
> >> >>>> +     * reserved bits on all bitrate but bitrate 1/2 packets
> >> >>>
> >> >>> this is unclear, field that is on all but ... , vs. field that
> >> >>> exists always but
> >> >>> is reserved on all but .....
> >> >>>
> >> >>
> >> >> is "reserved bits only set for bitrate 1, 1/4 and 1/8" better ?
> >> >
> >> > no, because setting them means error IIRC
> >> > also IIRC there is no indication of the existence of other fields
> >> > for the
> >> > other rates ...
> >> >
> >>
> >> reserved bits only present in bitrate 1, 1/4 and 1/8 packets
> >>
> >> ?
> >
> > ok
> >
> > [...]
> 
> here is an updated round 14 of the patches,
> which is getting smaller and smaller :)
> 
> Kenan

[...]
> Index: libavcodec/qcelpdec.c
> ===================================================================
> --- libavcodec/qcelpdec.c	(revision 15972)
> +++ libavcodec/qcelpdec.c	(working copy)
> @@ -31,7 +31,6 @@
>  #include "avcodec.h"
>  #include "bitstream.h"
>  
> -#include "qcelp.h"
>  #include "qcelpdata.h"
>  
>  #include "celp_math.h"
> @@ -40,6 +39,16 @@
>  #undef NDEBUG
>  #include <assert.h>
>  
> +typedef enum
> +{
> +    I_F_Q = -1,    /*!< insufficient frame quality */
> +    SILENCE,
> +    RATE_OCTAVE,
> +    RATE_QUARTER,
> +    RATE_HALF,
> +    RATE_FULL
> +} qcelp_packet_rate;
> +
>  typedef struct {
>      GetBitContext     gb;
>      qcelp_packet_rate bitrate;
> @@ -49,6 +58,9 @@
>      float             prev_lspf[10];
>      float             predictor_lspf[10];     /*!< LSP predictor,
>                                                    only use for RATE_OCTAVE and I_F_Q */
> +    float             pitch_synthesis_filter_mem[303];
> +    float             pitch_pre_filter_mem[303];
> +    float             rnd_fir_filter_mem[180];
>      float             formant_mem[170];
>      float             last_codebook_gain;
>      int               prev_g1[2];
> @@ -58,6 +70,13 @@
>      uint16_t          first16bits;
>  } QCELPContext;
>  
> +/**
> + * Reconstructs LPC coefficients from the line spectral pair frequencies.
> + *
> + * TIA/EIA/IS-733 2.4.3.3.5
> + */
> +void qcelp_lspf2lpc(const float *lspf, float *lpc);
> +
>  static void weighted_vector_sumf(float *out, const float *in_a,
>                                   const float *in_b, float weight_coeff_a,
>                                   float weight_coeff_b, int length)

ok


> @@ -476,6 +495,64 @@
>  }
>  
>  /**
> + * Apply pitch synthesis filter and pitch prefilter to the scaled codebook vector.
> + * TIA/EIA/IS-733 2.4.5.2
> + *
> + * @param q the context
> + * @param cdn_vector the scaled codebook vector
> + */
> +static void apply_pitch_filters(QCELPContext *q,
> +                                float *cdn_vector) {
> +    int         i;
> +    float       gain[4];
> +    const float *v_synthesis_filtered, *v_pre_filtered;
> +
> +    if (q->bitrate >= RATE_HALF ||
> +       (q->bitrate == I_F_Q && (q->prev_bitrate >= RATE_HALF))) {
> +
> +        if (q->bitrate >= RATE_HALF) {
> +
> +            // Compute gain & lag for the whole frame.
> +            for (i = 0; i < 4; i++) {
> +                gain[i] = q->frame.plag[i] ? (q->frame.pgain[i] + 1) * 0.25 : 0.0;
> +
> +                q->frame.plag[i] += 16;
> +            }
> +            memcpy(q->prev_pitch_lag, q->frame.plag, sizeof(q->frame.plag));
> +        } else {
> +            gain[3] = q->erasure_count < 3 ? 0.9 - 0.3 * (q->erasure_count - 1)
> +                                           : 0.0;
> +            for (i = 0; i < 4; i++)
> +                gain[i] = FFMIN(q->prev_pitch_gain[i], gain[3]);
> +
> +            memset(q->frame.pfrac, 0, sizeof(q->frame.pfrac));

> +            memcpy(q->frame.plag, q->prev_pitch_lag, sizeof(q->frame.plag));

i think if prev_pitch_lag was used in the surrounding code then this memcpy
would be unneeded


> +        }
> +
> +        // pitch synthesis filter
> +        v_synthesis_filtered = do_pitchfilter(q->pitch_synthesis_filter_mem, cdn_vector,
> +                                              gain, q->frame.plag, q->frame.pfrac);
> +
> +        // pitch prefilter update
> +        for (i = 0; i < 4; i++)
> +            gain[i] = 0.5 * FFMIN(gain[i], 1.0);
> +
> +        v_pre_filtered = do_pitchfilter(q->pitch_pre_filter_mem, v_synthesis_filtered,
> +                                        gain, q->frame.plag, q->frame.pfrac);
> +
> +        apply_gain_ctrl(cdn_vector, v_synthesis_filtered, v_pre_filtered);
> +

> +        memcpy(q->prev_pitch_gain, gain, sizeof(q->prev_pitch_gain));

cant prev_pitch_gain be directly used instead of gain that then is copied
back?
(possibly with a better var name than prev_pitch_gain)


> +
> +    } else {
> +        memcpy(q->pitch_synthesis_filter_mem, cdn_vector + 17, 143 * sizeof(float));
> +        memcpy(q->pitch_pre_filter_mem,       cdn_vector + 17, 143 * sizeof(float));
> +        memset(q->prev_pitch_gain, 0, sizeof(q->prev_pitch_gain));
> +        memset(q->prev_pitch_lag,  0, sizeof(q->prev_pitch_lag));
> +    }
> +}
> +
> +/**
>   * Interpolates LSP frequencies and computes LPC coefficients
>   * for a given bitrate & pitch subframe.
>   *


> @@ -527,6 +604,46 @@
>      return -1;
>  }
>  
> +/**
> + * Determine the bitrate from the frame size and/or the first byte of the frame.
> + *
> + * @param avctx the AV codec context
> + * @param buf_size length of the buffer
> + * @param buf the bufffer
> + *
> + * @return the bitrate on success,
> + *         I_F_Q  if the bitrate cannot be satisfactorily determined
> + *
> + * TIA/EIA/IS-733 2.4.8.7.1
> + */
> +static int determine_bitrate(AVCodecContext *avctx,
> +                               const int buf_size,
> +                               uint8_t **buf) {
> +    qcelp_packet_rate bitrate;
> +
> +    if ((bitrate = buf_size2bitrate(buf_size)) >= 0) {
> +        if (bitrate > **buf) {
> +            av_log(avctx, AV_LOG_WARNING, "Claimed bitrate and buffer size mismatch.\n");
> +            bitrate = **buf;
> +        } else if (bitrate < **buf) {
> +            av_log(avctx, AV_LOG_ERROR, "Buffer is too small for the claimed bitrate.\n");
> +            return I_F_Q;
> +        }
> +        (*buf)++;
> +    } else if ((bitrate = buf_size2bitrate(buf_size + 1)) >= 0) {
> +        av_log(avctx, AV_LOG_WARNING,
> +               "Bitrate byte is missing, guessing the bitrate from packet size.\n");
> +    } else
> +        return I_F_Q;
> +
> +    if (bitrate == SILENCE) {
> +        // FIXME: the decoder should not handle SILENCE frames as I_F_Q frames
> +        av_log_missing_feature(avctx, "Blank frame", 1);
> +        bitrate = I_F_Q;
> +    }
> +    return bitrate;
> +}
> +
>  static void warn_insufficient_frame_quality(AVCodecContext *avctx,
>                                              const char *message)
>  {

ok


[...]
> Index: libavformat/mov.c
> ===================================================================
> --- libavformat/mov.c	(revision 15972)
> +++ libavformat/mov.c	(working copy)
> @@ -988,6 +988,10 @@
>  #endif
>      /* no ifdef since parameters are always those */
>      case CODEC_ID_QCELP:
> +        st->need_parsing = AVSTREAM_PARSE_FULL;
> +        st->codec->frame_size= 160;


> +        st->codec->channels= 1; /* really needed */

if this is really needed then its ok


> +        break;
>      case CODEC_ID_AMR_NB:
>      case CODEC_ID_AMR_WB:
>          st->codec->frame_size= sc->samples_per_frame;
[...]

-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

No snowflake in an avalanche ever feels responsible. -- Voltaire
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20081201/e1efb743/attachment.pgp>



More information about the ffmpeg-devel mailing list