1/* 2 * RFC 3389 comfort noise generator 3 * Copyright (c) 2012 Martin Storsjo 4 * 5 * This file is part of FFmpeg. 6 * 7 * FFmpeg is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * FFmpeg is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with FFmpeg; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22#include <math.h> 23 24#include "libavutil/common.h" 25#include "avcodec.h" 26#include "internal.h" 27#include "lpc.h" 28 29typedef struct CNGContext { 30 LPCContext lpc; 31 int order; 32 int32_t *samples32; 33 double *ref_coef; 34} CNGContext; 35 36static av_cold int cng_encode_close(AVCodecContext *avctx) 37{ 38 CNGContext *p = avctx->priv_data; 39 ff_lpc_end(&p->lpc); 40 av_free(p->samples32); 41 av_free(p->ref_coef); 42 return 0; 43} 44 45static av_cold int cng_encode_init(AVCodecContext *avctx) 46{ 47 CNGContext *p = avctx->priv_data; 48 int ret; 49 50 if (avctx->channels != 1) { 51 av_log(avctx, AV_LOG_ERROR, "Only mono supported\n"); 52 return AVERROR(EINVAL); 53 } 54 55 avctx->frame_size = 640; 56 p->order = 10; 57 if ((ret = ff_lpc_init(&p->lpc, avctx->frame_size, p->order, FF_LPC_TYPE_LEVINSON)) < 0) 58 return ret; 59 p->samples32 = av_malloc_array(avctx->frame_size, sizeof(*p->samples32)); 60 p->ref_coef = av_malloc_array(p->order, sizeof(*p->ref_coef)); 61 if (!p->samples32 || !p->ref_coef) { 62 cng_encode_close(avctx); 63 return AVERROR(ENOMEM); 64 } 65 66 return 0; 67} 68 69static int cng_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, 70 const AVFrame *frame, int *got_packet_ptr) 71{ 72 CNGContext *p = avctx->priv_data; 73 int ret, i; 74 double energy = 0; 75 int qdbov; 76 int16_t *samples = (int16_t*) frame->data[0]; 77 78 if ((ret = ff_alloc_packet(avpkt, 1 + p->order))) { 79 av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n"); 80 return ret; 81 } 82 83 for (i = 0; i < frame->nb_samples; i++) { 84 p->samples32[i] = samples[i]; 85 energy += samples[i] * samples[i]; 86 } 87 energy /= frame->nb_samples; 88 if (energy > 0) { 89 double dbov = 10 * log10(energy / 1081109975); 90 qdbov = av_clip(-floor(dbov), 0, 127); 91 } else { 92 qdbov = 127; 93 } 94 ret = ff_lpc_calc_ref_coefs(&p->lpc, p->samples32, p->order, p->ref_coef); 95 avpkt->data[0] = qdbov; 96 for (i = 0; i < p->order; i++) 97 avpkt->data[1 + i] = p->ref_coef[i] * 127 + 127; 98 99 *got_packet_ptr = 1; 100 avpkt->size = 1 + p->order; 101 102 return 0; 103} 104 105AVCodec ff_comfortnoise_encoder = { 106 .name = "comfortnoise", 107 .long_name = NULL_IF_CONFIG_SMALL("RFC 3389 comfort noise generator"), 108 .type = AVMEDIA_TYPE_AUDIO, 109 .id = AV_CODEC_ID_COMFORT_NOISE, 110 .priv_data_size = sizeof(CNGContext), 111 .init = cng_encode_init, 112 .encode2 = cng_encode_frame, 113 .close = cng_encode_close, 114 .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, 115 AV_SAMPLE_FMT_NONE }, 116}; 117