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 "codec_internal.h" 27#include "encode.h" 28#include "lpc.h" 29 30typedef struct CNGContext { 31 LPCContext lpc; 32 int order; 33 int32_t *samples32; 34 double *ref_coef; 35} CNGContext; 36 37static av_cold int cng_encode_close(AVCodecContext *avctx) 38{ 39 CNGContext *p = avctx->priv_data; 40 ff_lpc_end(&p->lpc); 41 av_freep(&p->samples32); 42 av_freep(&p->ref_coef); 43 return 0; 44} 45 46static av_cold int cng_encode_init(AVCodecContext *avctx) 47{ 48 CNGContext *p = avctx->priv_data; 49 int ret; 50 51 avctx->frame_size = 640; 52 p->order = 10; 53 if ((ret = ff_lpc_init(&p->lpc, avctx->frame_size, p->order, FF_LPC_TYPE_LEVINSON)) < 0) 54 return ret; 55 p->samples32 = av_malloc_array(avctx->frame_size, sizeof(*p->samples32)); 56 p->ref_coef = av_malloc_array(p->order, sizeof(*p->ref_coef)); 57 if (!p->samples32 || !p->ref_coef) 58 return AVERROR(ENOMEM); 59 60 return 0; 61} 62 63static int cng_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, 64 const AVFrame *frame, int *got_packet_ptr) 65{ 66 CNGContext *p = avctx->priv_data; 67 int ret, i; 68 double energy = 0; 69 int qdbov; 70 int16_t *samples = (int16_t*) frame->data[0]; 71 72 if ((ret = ff_get_encode_buffer(avctx, avpkt, 1 + p->order, 0))) { 73 av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n"); 74 return ret; 75 } 76 77 for (i = 0; i < frame->nb_samples; i++) { 78 p->samples32[i] = samples[i]; 79 energy += samples[i] * samples[i]; 80 } 81 energy /= frame->nb_samples; 82 if (energy > 0) { 83 double dbov = 10 * log10(energy / 1081109975); 84 qdbov = av_clip_uintp2(-floor(dbov), 7); 85 } else { 86 qdbov = 127; 87 } 88 ff_lpc_calc_ref_coefs(&p->lpc, p->samples32, p->order, p->ref_coef); 89 avpkt->data[0] = qdbov; 90 for (i = 0; i < p->order; i++) 91 avpkt->data[1 + i] = p->ref_coef[i] * 127 + 127; 92 93 *got_packet_ptr = 1; 94 av_assert1(avpkt->size == 1 + p->order); 95 96 return 0; 97} 98 99const FFCodec ff_comfortnoise_encoder = { 100 .p.name = "comfortnoise", 101 .p.long_name = NULL_IF_CONFIG_SMALL("RFC 3389 comfort noise generator"), 102 .p.type = AVMEDIA_TYPE_AUDIO, 103 .p.id = AV_CODEC_ID_COMFORT_NOISE, 104 .p.capabilities = AV_CODEC_CAP_DR1, 105 .priv_data_size = sizeof(CNGContext), 106 .init = cng_encode_init, 107 FF_CODEC_ENCODE_CB(cng_encode_frame), 108 .close = cng_encode_close, 109 .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, 110 AV_SAMPLE_FMT_NONE }, 111 .p.ch_layouts = (const AVChannelLayout[]){ AV_CHANNEL_LAYOUT_MONO, { 0 } }, 112 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, 113}; 114