xref: /third_party/ffmpeg/libavcodec/cngenc.c (revision cabdff1a)
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