[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