diff options
author | Vladimir Voroshilov <voroshil@gmail.com> | 2008-09-03 23:47:58 +0700 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2011-09-24 21:11:00 +0200 |
commit | e610c5f383f31e55a672961f1e671d83328c36b1 (patch) | |
tree | 064a96c6d93afe64266fb868025e32688dabcc79 /libavcodec/g729dec.c | |
parent | b7c7fc335900eb4bfd403115eecfafff23be684d (diff) | |
download | ffmpeg-e610c5f383f31e55a672961f1e671d83328c36b1.tar.gz |
Add G.729D decoder
Diffstat (limited to 'libavcodec/g729dec.c')
-rw-r--r-- | libavcodec/g729dec.c | 110 |
1 files changed, 109 insertions, 1 deletions
diff --git a/libavcodec/g729dec.c b/libavcodec/g729dec.c index c1d0905a0d..5fc2167277 100644 --- a/libavcodec/g729dec.c +++ b/libavcodec/g729dec.c @@ -81,6 +81,10 @@ */ #define MR_ENERGY 1018156 +#define DECISION_NOISE 0 +#define DECISION_INTERMEDIATE 1 +#define DECISION_VOICE 2 + typedef enum { FORMAT_G729_8K = 0, FORMAT_G729D_6K4, @@ -124,6 +128,10 @@ typedef struct { /// (14.1) gain code from current and previous subframe int16_t past_gain_code[2]; + /// voice decision on previous subframe (0-noise, 1-intermediate, 2-voice), G.729D + int16_t voice_decision; + + int16_t onset; ///< detected onset level (0-2) int16_t was_periodic; ///< whether previous frame was declared as periodic or not (4.4) uint16_t rand_value; ///< random number generator value (4.4.4) int ma_predictor_prev; ///< switched MA predictor of LSP quantizer from last good frame @@ -230,6 +238,85 @@ static void lsf_restore_from_previous(int16_t* lsfq, } } +/** + * Constructs new excitation signal and applies phase filter to it + * @param out[out] constructed speech signal + * @param in original excitation signal + * @param fc_cur (2.13) original fixed-codebook vector + * @param gain_code (14.1) gain code + * @param subframe_size length of the subframe + */ +void g729d_get_new_exc( + int16_t* out, + const int16_t* in, + const int16_t* fc_cur, + int dstate, + int gain_code, + int subframe_size) +{ + int i; + int16_t fc_new[SUBFRAME_SIZE]; + + ff_celp_convolve_circ(fc_new, fc_cur, phase_filter[dstate], subframe_size); + + for(i=0; i<subframe_size; i++) + { + out[i] = in[i]; + out[i] -= (gain_code * fc_cur[i] + 0x2000) >> 14; + out[i] += (gain_code * fc_new[i] + 0x2000) >> 14; + } +} + +/** + * Makes decision about onset in current subframe + * @param past_onset decision result of previous subframe + * @param past_gain_code gain code of current and previous subframe + * + * @return onset decision result for current subframe + */ +int g729d_onset_decision(int past_onset, const int16_t* past_gain_code) +{ + if((past_gain_code[0] >> 1) > past_gain_code[1]) + return 2; + else + return FFMAX(past_onset-1, 0); +} + +/** + * Makes decision about voice presence in current subframe + * @param onset onset level + * @param prev_voice_decision voice decision result from previous subframe + * @param past_gain_pitch pitch gain of current and previous subframes + * + * @return voice decision result for current subframe + */ +static int16_t g729d_voice_decision(int onset, int prev_voice_decision, const int16_t* past_gain_pitch) +{ + int i, low_gain_pitch_cnt, voice_decision; + + if(past_gain_pitch[0] >= 14745) // 0.9 + voice_decision = DECISION_VOICE; + else if (past_gain_pitch[0] <= 9830) // 0.6 + voice_decision = DECISION_NOISE; + else + voice_decision = DECISION_INTERMEDIATE; + + for(i=0, low_gain_pitch_cnt=0; i<6; i++) + if(past_gain_pitch[i] < 9830) + low_gain_pitch_cnt++; + + if(low_gain_pitch_cnt > 2 && !onset) + voice_decision = DECISION_NOISE; + + if(!onset && voice_decision > prev_voice_decision + 1) + voice_decision--; + + if(onset && voice_decision < DECISION_VOICE) + voice_decision++; + + return voice_decision; +} + static av_cold int decoder_init(AVCodecContext * avctx) { G729Context* ctx = avctx->priv_data; @@ -302,6 +389,9 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, if (buf_size == 10) { packet_type = FORMAT_G729_8K; format = format_g729_8k; + //Reset voice decision + ctx->onset = 0; + ctx->voice_decision = DECISION_VOICE; av_log(avctx, AV_LOG_DEBUG, "Packet type: %s\n", "G.729 @ 8kbit/s"); } else if (buf_size == 8) { packet_type = FORMAT_G729D_6K4; @@ -497,11 +587,29 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, SUBFRAME_SIZE, 10, 1, - 0x800)) { + 0x800)) /* Overflow occured, downscale excitation signal... */ for (j = 0; j < 2 * SUBFRAME_SIZE + PITCH_DELAY_MAX + INTERPOL_LEN; j++) ctx->exc_base[j] >>= 2; + /* ... and make synthesis again. */ + if (packet_type == FORMAT_G729D_6K4) { + int16_t exc_new[SUBFRAME_SIZE]; + + ctx->onset = g729d_onset_decision(ctx->onset, ctx->past_gain_code); + ctx->voice_decision = g729d_voice_decision(ctx->onset, ctx->voice_decision, ctx->past_gain_pitch); + + g729d_get_new_exc(exc_new, ctx->exc + i * SUBFRAME_SIZE, fc, ctx->voice_decision, ctx->past_gain_code[0], SUBFRAME_SIZE); + + ff_celp_lp_synthesis_filter( + synth+10, + &lp[i][1], + exc_new, + SUBFRAME_SIZE, + 10, + 0, + 0x800); + } else { ff_celp_lp_synthesis_filter( synth+10, &lp[i][1], |