yading@10: /* yading@10: * RFC 3389 comfort noise generator yading@10: * Copyright (c) 2012 Martin Storsjo yading@10: * yading@10: * This file is part of FFmpeg. yading@10: * yading@10: * FFmpeg is free software; you can redistribute it and/or yading@10: * modify it under the terms of the GNU Lesser General Public yading@10: * License as published by the Free Software Foundation; either yading@10: * version 2.1 of the License, or (at your option) any later version. yading@10: * yading@10: * FFmpeg is distributed in the hope that it will be useful, yading@10: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@10: * Lesser General Public License for more details. yading@10: * yading@10: * You should have received a copy of the GNU Lesser General Public yading@10: * License along with FFmpeg; if not, write to the Free Software yading@10: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@10: */ yading@10: yading@10: #include yading@10: yading@10: #include "libavutil/common.h" yading@10: #include "avcodec.h" yading@10: #include "celp_filters.h" yading@10: #include "internal.h" yading@10: #include "libavutil/lfg.h" yading@10: yading@10: typedef struct CNGContext { yading@10: float *refl_coef, *target_refl_coef; yading@10: float *lpc_coef; yading@10: int order; yading@10: int energy, target_energy; yading@10: int inited; yading@10: float *filter_out; yading@10: float *excitation; yading@10: AVLFG lfg; yading@10: } CNGContext; yading@10: yading@10: static av_cold int cng_decode_close(AVCodecContext *avctx) yading@10: { yading@10: CNGContext *p = avctx->priv_data; yading@10: av_free(p->refl_coef); yading@10: av_free(p->target_refl_coef); yading@10: av_free(p->lpc_coef); yading@10: av_free(p->filter_out); yading@10: av_free(p->excitation); yading@10: return 0; yading@10: } yading@10: yading@10: static av_cold int cng_decode_init(AVCodecContext *avctx) yading@10: { yading@10: CNGContext *p = avctx->priv_data; yading@10: yading@10: avctx->sample_fmt = AV_SAMPLE_FMT_S16; yading@10: avctx->channels = 1; yading@10: avctx->sample_rate = 8000; yading@10: yading@10: p->order = 12; yading@10: avctx->frame_size = 640; yading@10: p->refl_coef = av_mallocz(p->order * sizeof(*p->refl_coef)); yading@10: p->target_refl_coef = av_mallocz(p->order * sizeof(*p->target_refl_coef)); yading@10: p->lpc_coef = av_mallocz(p->order * sizeof(*p->lpc_coef)); yading@10: p->filter_out = av_mallocz((avctx->frame_size + p->order) * yading@10: sizeof(*p->filter_out)); yading@10: p->excitation = av_mallocz(avctx->frame_size * sizeof(*p->excitation)); yading@10: if (!p->refl_coef || !p->target_refl_coef || !p->lpc_coef || yading@10: !p->filter_out || !p->excitation) { yading@10: cng_decode_close(avctx); yading@10: return AVERROR(ENOMEM); yading@10: } yading@10: yading@10: av_lfg_init(&p->lfg, 0); yading@10: yading@10: return 0; yading@10: } yading@10: yading@10: static void make_lpc_coefs(float *lpc, const float *refl, int order) yading@10: { yading@10: float buf[100]; yading@10: float *next, *cur; yading@10: int m, i; yading@10: next = buf; yading@10: cur = lpc; yading@10: for (m = 0; m < order; m++) { yading@10: next[m] = refl[m]; yading@10: for (i = 0; i < m; i++) yading@10: next[i] = cur[i] + refl[m] * cur[m - i - 1]; yading@10: FFSWAP(float*, next, cur); yading@10: } yading@10: if (cur != lpc) yading@10: memcpy(lpc, cur, sizeof(*lpc) * order); yading@10: } yading@10: yading@10: static void cng_decode_flush(AVCodecContext *avctx) yading@10: { yading@10: CNGContext *p = avctx->priv_data; yading@10: p->inited = 0; yading@10: } yading@10: yading@10: static int cng_decode_frame(AVCodecContext *avctx, void *data, yading@10: int *got_frame_ptr, AVPacket *avpkt) yading@10: { yading@10: AVFrame *frame = data; yading@10: CNGContext *p = avctx->priv_data; yading@10: int buf_size = avpkt->size; yading@10: int ret, i; yading@10: int16_t *buf_out; yading@10: float e = 1.0; yading@10: float scaling; yading@10: yading@10: if (avpkt->size) { yading@10: int dbov = -avpkt->data[0]; yading@10: p->target_energy = 1081109975 * pow(10, dbov / 10.0) * 0.75; yading@10: memset(p->target_refl_coef, 0, p->order * sizeof(*p->target_refl_coef)); yading@10: for (i = 0; i < FFMIN(avpkt->size - 1, p->order); i++) { yading@10: p->target_refl_coef[i] = (avpkt->data[1 + i] - 127) / 128.0; yading@10: } yading@10: } yading@10: yading@10: if (p->inited) { yading@10: p->energy = p->energy / 2 + p->target_energy / 2; yading@10: for (i = 0; i < p->order; i++) yading@10: p->refl_coef[i] = 0.6 *p->refl_coef[i] + 0.4 * p->target_refl_coef[i]; yading@10: } else { yading@10: p->energy = p->target_energy; yading@10: memcpy(p->refl_coef, p->target_refl_coef, p->order * sizeof(*p->refl_coef)); yading@10: p->inited = 1; yading@10: } yading@10: make_lpc_coefs(p->lpc_coef, p->refl_coef, p->order); yading@10: yading@10: for (i = 0; i < p->order; i++) yading@10: e *= 1.0 - p->refl_coef[i]*p->refl_coef[i]; yading@10: yading@10: scaling = sqrt(e * p->energy / 1081109975); yading@10: for (i = 0; i < avctx->frame_size; i++) { yading@10: int r = (av_lfg_get(&p->lfg) & 0xffff) - 0x8000; yading@10: p->excitation[i] = scaling * r; yading@10: } yading@10: ff_celp_lp_synthesis_filterf(p->filter_out + p->order, p->lpc_coef, yading@10: p->excitation, avctx->frame_size, p->order); yading@10: yading@10: frame->nb_samples = avctx->frame_size; yading@10: if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) yading@10: return ret; yading@10: buf_out = (int16_t *)frame->data[0]; yading@10: for (i = 0; i < avctx->frame_size; i++) yading@10: buf_out[i] = p->filter_out[i + p->order]; yading@10: memcpy(p->filter_out, p->filter_out + avctx->frame_size, yading@10: p->order * sizeof(*p->filter_out)); yading@10: yading@10: *got_frame_ptr = 1; yading@10: yading@10: return buf_size; yading@10: } yading@10: yading@10: AVCodec ff_comfortnoise_decoder = { yading@10: .name = "comfortnoise", yading@10: .type = AVMEDIA_TYPE_AUDIO, yading@10: .id = AV_CODEC_ID_COMFORT_NOISE, yading@10: .priv_data_size = sizeof(CNGContext), yading@10: .init = cng_decode_init, yading@10: .decode = cng_decode_frame, yading@10: .flush = cng_decode_flush, yading@10: .close = cng_decode_close, yading@10: .long_name = NULL_IF_CONFIG_SMALL("RFC 3389 comfort noise generator"), yading@10: .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, yading@10: AV_SAMPLE_FMT_NONE }, yading@10: .capabilities = CODEC_CAP_DELAY | CODEC_CAP_DR1, yading@10: };