[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