[FFmpeg-devel] [PATCH] QCELP decoder

Kenan Gillet kenan.gillet
Fri Nov 21 05:53:37 CET 2008


On Thu, Nov 20, 2008 at 5:08 PM, Michael Niedermayer <michaelni at gmx.at> wrote:
> On Thu, Nov 20, 2008 at 10:46:49AM -0800, Kenan Gillet wrote:
>> On Sat, Nov 15, 2008 at 3:10 PM, Michael Niedermayer <michaelni at gmx.at> wrote:
>> > On Fri, Nov 14, 2008 at 03:32:51PM -0800, Kenan Gillet wrote:
>> >> Hi,
>> >> On Fri, Nov 14, 2008 at 2:27 PM, Michael Niedermayer <michaelni at gmx.at> wrote:
>> >> > On Fri, Nov 14, 2008 at 12:17:50PM -0800, Kenan Gillet wrote:
>> >> >>
>> >> >> On Nov 14, 2008, at 2:14 AM, Michael Niedermayer wrote:

[...]
>> >> +
>> >> +/// @defgroup qcelp_unpacked_data_frame QCELP unpacked data frame
>> >> +/// @{
>> >> +    uint8_t           cbsign[16];
>> >
>> >> +    uint8_t           cbgain[16];
>> >> +    uint8_t           cindex[16];
>> >> +    uint8_t           plag[4];
>> >> +    uint8_t           pfrac[4];
>> >> +    uint8_t           pgain[4];
>> >> +    uint8_t           lspv[10];               /*!< LSP for RATE_OCTAVE, LSPV for other rates */
>> >> +    uint8_t           reserved;               /*!< on all but rate 1/2 packets */
>> >> +/// @}
>> >> +
>> >> +    uint8_t           erasure_count;
>> >> +    uint8_t           octave_count;           /*!< count the consecutive RATE_OCTAVE frames */
>> >> +    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];
>> >> +    int               prev_framerate;
>> >> +    float             prev_pitch_gain[4];
>> >> +    uint8_t           prev_pitch_lag[4];
>> >> +    uint16_t          first16bits;
>> >> +} QCELPContext;
>> >
>> > i somehow think this struct does not belong in qcelpdata.h
>> > but rather qcelpdec.c
>> >
>>
>> I agree, but it is needed by the unpacking table.
>> should I just put the struct in qcelpdec.c and include qcelpdata.h after ?
>
> ok (maybe diego will want it to be renamed to .c though ...)

ok to keep it the way it is?

or to move the QCELPContext in qcelpdec.c ?

>
>
> [...]
>> >
>> > [...]
>> >
>> >
>> >>  static void warn_insufficient_frame_quality(AVCodecContext *avctx,
>> >>                                              const char *message) {
>> >>      av_log(avctx, AV_LOG_WARNING, "Frame #%d, IFQ: %s\n", avctx->frame_number, message);
>> >>  }
>> >>
>> >> +static int qcelp_decode_frame(AVCodecContext *avctx,
>> >> +                              void *data,
>> >> +                              int *data_size,
>> >> +                              uint8_t *buf,
>> >> +                              const int buf_size) {
>> >> +    QCELPContext      *q = avctx->priv_data;
>> >> +    float             *outbuffer = data;
>> >> +    int               i;
>> >> +    float             quantized_lspf[10], lpc[10];
>> >> +    float             gain[16];
>> >> +    float             *formant_mem;
>> >> +
>> >> +    if ((q->framerate = determine_framerate(avctx, buf_size, &buf)) == I_F_Q) {
>> >> +        warn_insufficient_frame_quality(avctx, "Framerate cannot be determined.");
>> >> +        goto erasure;
>> >> +    }
>> >> +
>> >> +    if (q->framerate == RATE_OCTAVE &&
>> >> +       (q->first16bits = AV_RB16(buf)) == 0xFFFF) {
>> >> +        warn_insufficient_frame_quality(avctx, "Framerate is 1/8 and first 16 bits are on.");
>> >> +        goto erasure;
>> >> +    }
>> >> +
>> >> +    if (q->framerate > SILENCE) {
>> >> +        const QCELPBitmap *bitmaps     = qcelp_unpacking_bitmaps_per_rate[q->framerate];
>> >> +        const QCELPBitmap *bitmaps_end = qcelp_unpacking_bitmaps_per_rate[q->framerate]
>> >> +                                       + qcelp_bits_per_rate[q->framerate];
>> >> +        uint8_t           *unpacked_data = (uint8_t *)q;
>> >> +
>> >
>> >> +        init_get_bits(&q->gb, buf, qcelp_bits_per_rate[q->framerate]);
>> >
>> > qcelp_bits_per_rate does not seem correct here nor does its name seem
>> > to match what it contains
>>
>>
>> yes changed back to buf_size.
>>
>> what about changing qcelp_bits_per_rate  to qcelp_unpacking_bitmaps_per_rate_len
>> because it really is the len of the unpacking bitmaps, or do you have
>> a better suggestion ?
>
> the suggested name is too long IMHO

qcelp_unpacking_bitmaps_lengths ?


[...]


>> @@ -490,4 +537,20 @@
>>    -9.918777e-2, 3.749518e-2,  8.985137e-1
>>  };
>>
>> +/**
>> + * This spread factor is used, for bitrate 1/8 and I_F_Q,
>> + * to force the LSP frequencies to be at least 80 Hz apart.
>> + *
>> + * TIA/EIA/IS-733 2.4.3.3.2
>> + */
>> +#define QCELP_LSP_SPREAD_FACTOR 0.02
>> +
>> +/**
>> + * predictor coefficient for the conversion of LSP codes
>> + * to LSP frequencies for 1/8 and I_F_Q
>> + *
>> + * TIA/EIA/IS-733 2.4.3.2.7-2
>> + */
>> +#define QCELP_LSP_OCTAVE_PREDICTOR 29.0/32
>> +
>>  #endif /* AVCODEC_QCELPDATA_H */
>> Index: libavcodec/qcelpdec.c
>> ===================================================================
>> --- libavcodec/qcelpdec.c     (revision 15885)
>> +++ libavcodec/qcelpdec.c     (working copy)

[...]
>
>> +
>> +/**
>> + * Converts codebook transmission codes to GAIN and INDEX.
>> + *
>> + * @param q the context
>> + * @param gain array holding the decoded gain
>> + *
>> + * TIA/EIA/IS-733 2.4.6.2
>> + */
>> +static void decode_gain_and_index(QCELPContext  *q,
>> +                                  float *gain) {
>> +    int   i, subframes_count, g1[16];
>> +    float gain_memory, smooth_coef;
>> +
>> +    if (q->bitrate >= RATE_QUARTER) {
>
>> +        switch (q->bitrate) {
>> +            case RATE_FULL:
>> +                subframes_count = 16;
>> +                break;
>> +            case RATE_HALF:
>> +                subframes_count = 4;
>> +                break;
>> +            default:
>> +                subframes_count = 5;
>> +        }
>
> switch (q->bitrate) {
>    case RATE_FULL: subframes_count = 16; break;
>    case RATE_HALF: subframes_count = 4 ; break;
>    default       : subframes_count = 5 ;
> }

done


>
>
>> +        for (i = 0; i < subframes_count; i++) {
>> +            g1[i] = 4 * q->cbgain[i];
>> +            if (q->bitrate == RATE_FULL && !((i+1) & 3)) {
>> +                g1[i] += av_clip((g1[i-1] + g1[i-2] + g1[i-3]) / 3 - 6, 0, 32);
>> +            }
>> +
>> +            gain[i] = qcelp_g12ga[g1[i]];
>> +
>> +            if (q->cbsign[i]) {
>> +                gain[i] = -gain[i];
>> +                q->cindex[i] = (q->cindex[i]-89) & 127;
>> +            }
>> +        }
>> +
>> +        q->prev_g1[0] = g1[i-2];
>> +        q->prev_g1[1] = g1[i-1];
>> +        q->last_codebook_gain = qcelp_g12ga[g1[i-1]];
>> +
>> +        if (q->bitrate == RATE_QUARTER) {
>> +            // Provide smoothing of the unvoiced excitation energy.
>> +            gain[7] =     gain[4];
>> +            gain[6] = 0.4*gain[3] + 0.6*gain[4];
>> +            gain[5] =     gain[3];
>> +            gain[4] = 0.8*gain[2] + 0.2*gain[3];
>> +            gain[3] = 0.2*gain[1] + 0.8*gain[2];
>> +            gain[2] =     gain[1];
>> +            gain[1] = 0.6*gain[0] + 0.4*gain[1];
>> +        }
>> +    } else {
>> +        if (q->bitrate == RATE_OCTAVE) {
>> +            g1[0] = 2 * q->cbgain[0] + av_clip((q->prev_g1[0] + q->prev_g1[1]) / 2 - 5, 0, 54);
>> +            smooth_coef = 0.125;
>> +            i = 7;
>> +        } else {
>> +            assert(q->bitrate == I_F_Q);
>> +
>> +            g1[0] = q->prev_g1[1];
>> +            switch (q->erasure_count) {
>> +            case 1 : break;
>> +            case 2 : g1[0] -= 1; break;
>> +            case 3 : g1[0] -= 2; break;
>> +            default: g1[0] -= 6;
>> +            }
>> +            if (g1[0] < 0)
>> +                g1[0] = 0;
>> +            smooth_coef = 0.25;
>> +            i = 3;
>> +        }
>
>> +        gain_memory = q->last_codebook_gain;
>> +
>> +        q->last_codebook_gain =
>> +                      gain[i] = 0.5 * (gain_memory + qcelp_g12ga[g1[0]]);
>> +
>> +        smooth_coef *= (gain[i] - gain_memory);
>> +        // This interpolation is done to produce smoother background noise.
>> +        for (; i > 0; i--)
>> +            gain[i-1] = gain_memory + smooth_coef * i;
>
> something like:
>
> N= 8 or 4
> slope= 0.5*(qcelp_g12ga[g1[0]] - q->last_codebook_gain)/N;
> for (i=1; i<= N; i++)
>    gain[i-1] = q->last_codebook_gain + i*slope;
> q->last_codebook_gain = gain[i-1];
>
> appears simpler

done

[...]


>
>> @@ -96,7 +293,7 @@
>
> [...]
>> @@ -298,6 +553,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 && **buf >= 0) {
>
> **buf being unsigned so i dont think the >= 0 check makes sense

no sense at all, fixed


>
>
> [...]
>> @@ -305,6 +600,107 @@
>>             message);
>>  }
>>
>> +static int qcelp_decode_frame(AVCodecContext *avctx,
>> +                              void *data,
>> +                              int *data_size,
>> +                              uint8_t *buf,
>> +                              const int buf_size) {
>> +    QCELPContext      *q = avctx->priv_data;
>> +    float             *outbuffer = data;
>> +    int               i;
>> +    float             quantized_lspf[10], lpc[10];
>> +    float             gain[16];
>> +    float             *formant_mem;
>> +
>> +    if ((q->bitrate = determine_bitrate(avctx, buf_size, &buf)) == I_F_Q) {
>> +        warn_insufficient_frame_quality(avctx, "bitrate cannot be determined.");
>> +        goto erasure;
>> +    }
>> +
>> +    if (q->bitrate == RATE_OCTAVE &&
>> +       (q->first16bits = AV_RB16(buf)) == 0xFFFF) {
>> +        warn_insufficient_frame_quality(avctx, "Bitrate is 1/8 and first 16 bits are on.");
>> +        goto erasure;
>> +    }
>> +
>> +    if (q->bitrate > SILENCE) {
>> +        const QCELPBitmap *bitmaps     = qcelp_unpacking_bitmaps_per_rate[q->bitrate];
>> +        const QCELPBitmap *bitmaps_end = qcelp_unpacking_bitmaps_per_rate[q->bitrate]
>> +                                       + qcelp_bits_per_rate[q->bitrate];
>> +        uint8_t           *unpacked_data = (uint8_t *)q;
>> +
>
>> +        init_get_bits(&q->gb, buf, buf_size);
>
> i think this is mixing size in bits and size in bytes

fixed




More information about the ffmpeg-devel mailing list