[FFmpeg-devel] [PATCH] QCELP decoder

Kenan Gillet kenan.gillet
Mon Dec 1 02:04:07 CET 2008


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:
>> Hi all,
>>
>> sorry for the delay. I was waiting to resolve the parsing/decoding of
>> the bitrate/packet type issue.
>> Reynaldo and I agreed on IRC to live the parsing/decoding as it is  
>> for now.
>>
>> So here is round 13 of the qcelp decoder.
>> - QCELPContext was split so that it can be moved into qcelpdec.c and
>> only keep the unpacked data structure (QCELPFrame) in qcelpdata.h
>> - add doxy comments on QCELPFrame field
>> - simplify decode_gain_and_index for RATE_OCTAVE and IFQ
>> - rename qcelp_bits_per_rate into qcelp_unpacking_bitmaps_lengths
>> - use double in qcelp_lsp.c
>>
>> have a great day
>>
>> Kenan
>
>> Index: libavcodec/qcelp.h
>> ===================================================================
>> --- libavcodec/qcelp.h	(revision 0)
>> +++ libavcodec/qcelp.h	(revision 0)
>> @@ -0,0 +1,48 @@
>> +/*
>> + * QCELP decoder
>> + * Copyright (c) 2007 Reynaldo H. Verdejo Pinochet
>> + *
>> + * This file is part of FFmpeg.
>> + *
>> + * FFmpeg is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU Lesser General Public
>> + * License as published by the Free Software Foundation; either
>> + * version 2.1 of the License, or (at your option) any later  
>> version.
>> + *
>> + * FFmpeg is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + * Lesser General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU Lesser General Public
>> + * License along with FFmpeg; if not, write to the Free Software
>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  
>> 02110-1301 USA
>> + */
>> +
>> +#ifndef AVCODEC_QCELP_H
>> +#define AVCODEC_QCELP_H
>> +
>> +/**
>> + * @file qcelp.h
>> + * QCELP decoder
>> + * @author Reynaldo H. Verdejo Pinochet
>> + */
>> +
>
>> +typedef enum
>> +{
>> +    I_F_Q = -1,           /*!< insufficient frame quality */
>> +    SILENCE,
>> +    RATE_OCTAVE,
>> +    RATE_QUARTER,
>> +    RATE_HALF,
>> +    RATE_FULL
>> +} qcelp_packet_rate;
>
> i think this could be in qcelpdec.c ?

done,

I think we should also get rid of qcelp.h since it only contains
the declaration of qcelp_lspf2lpc, which beg the question of
what file should the qcelp_lsp.c code be in ?


>> +
>> +/**
>> + * 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);
>> +
>> +#endif /* AVCODEC_QCELP_H */
>
>
>> Index: libavcodec/qcelpdata.h
>> ===================================================================
>> --- libavcodec/qcelpdata.h	(revision 15955)
>> +++ libavcodec/qcelpdata.h	(working copy)
>> @@ -34,6 +34,37 @@
>> #include "libavutil/common.h"
>>
>> /**
>> + * QCELP unpacked data frame
>> + */
>> +typedef struct {
>> +/// @defgroup qcelp_codebook_parameters QCELP excitation codebook  
>> parameters
>> +/// @{
>> +    uint8_t cbsign[16]; ///!< sign of the codebook gain for each  
>> codebook subframe
>> +    uint8_t cbgain[16]; ///!< unsigned codebook gain for each  
>> codebook subframe
>> +    uint8_t cindex[16]; ///!< codebook index for each codebook  
>> subframe
>> +/// @}
>> +
>> +/// @defgroup qcelp_pitch_parameters QCELP pitch prediction  
>> parameters
>> +/// @{
>> +    uint8_t plag[4];    ///!< pitch lag for each pitch subframe
>> +    uint8_t pfrac[4];   ///!< fractional pitch lag for each pitch  
>> subframe
>> +    uint8_t pgain[4];   ///!< pitch gain for each pitch subframe
>> +/// @}
>> +
>> +    /**
>> +     * line spectral pair frequencies (LSP) for RATE_OCTAVE,
>> +     * line spectral pair frequencies grouped into five vectors
>> +     * of dimension two (LSPV) for other rates
>> +     */
>> +    uint8_t lspv[10];
>> +
>
> ok
>
>
>> +    /**
>> +     * 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 ?

[...]


>> Index: libavcodec/qcelpdec.c
>> ===================================================================
>> --- libavcodec/qcelpdec.c	(revision 15955)
>> +++ libavcodec/qcelpdec.c	(working copy)
>> @@ -40,6 +40,27 @@
>> #undef NDEBUG
>> #include <assert.h>
>>
>> +typedef struct {
>> +    GetBitContext     gb;
>> +    qcelp_packet_rate bitrate;
>> +    QCELPFrame        frame;                  /*!< unpacked data  
>> frame */
>> +    uint8_t           erasure_count;
>> +    uint8_t           octave_count;           /*!< count the  
>> consecutive RATE_OCTAVE frames */
>> +    float             prev_lspf[10];
>> +    float             predictor_lspf[10];     /*!< LSP predictor,
>
> ok
>
>
>> +                                                  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];
>
> is it correct to use the random values from the last frame? I  
> faintly remember
> seeing that this wasnt done in previous patches ... just asking to  
> make sure
> no bug slipt in ...

it was not up to specs.

 From TIA 733 2.4.8.1.2
rnd(n) is band-pass filtered before being scaled by the appropriate  
codebook gain.
The filter states are saved from the last Rate 1/4 frame that used the  
filter.  The sequence,
rnd_bpf(n), is generated by band-pass filtering rnd(n) with the FIR  
filter described in
Table 2.4.8.1.2-1.

[...]


>> @@ -381,6 +479,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));
>> +        }
>> +
>> +        // 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));
>> +
>> +    } 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.
>>  *
>
>
>> @@ -432,6 +588,46 @@
>>     return -1;
>> }
>>
>
>> +/*
>> + * Determine the bitrate from the frame size and/or the first byte  
>> of the frame.
>
> /**

done


>
>> + *
>> + * @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_WARNING, "Buffer is too small for  
>> the claimed bitrate.\n");
>
> i think tis should be AV_LOG_ERROR

done


>> +            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)
>> {
>

[...]

thanks for all the reviewing :)

Kenan





More information about the ffmpeg-devel mailing list