00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <math.h>
00023
00024 #include "libavutil/common.h"
00025 #include "avcodec.h"
00026 #include "internal.h"
00027 #include "lpc.h"
00028
00029 typedef struct CNGContext {
00030 LPCContext lpc;
00031 int order;
00032 int32_t *samples32;
00033 double *ref_coef;
00034 } CNGContext;
00035
00036 static av_cold int cng_encode_close(AVCodecContext *avctx)
00037 {
00038 CNGContext *p = avctx->priv_data;
00039 ff_lpc_end(&p->lpc);
00040 av_free(p->samples32);
00041 av_free(p->ref_coef);
00042 return 0;
00043 }
00044
00045 static av_cold int cng_encode_init(AVCodecContext *avctx)
00046 {
00047 CNGContext *p = avctx->priv_data;
00048 int ret;
00049
00050 if (avctx->channels != 1) {
00051 av_log(avctx, AV_LOG_ERROR, "Only mono supported\n");
00052 return AVERROR(EINVAL);
00053 }
00054
00055 avctx->frame_size = 640;
00056 p->order = 10;
00057 if ((ret = ff_lpc_init(&p->lpc, avctx->frame_size, p->order, FF_LPC_TYPE_LEVINSON)) < 0)
00058 return ret;
00059 p->samples32 = av_malloc(avctx->frame_size * sizeof(*p->samples32));
00060 p->ref_coef = av_malloc(p->order * sizeof(*p->ref_coef));
00061 if (!p->samples32 || !p->ref_coef) {
00062 cng_encode_close(avctx);
00063 return AVERROR(ENOMEM);
00064 }
00065
00066 return 0;
00067 }
00068
00069 static int cng_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
00070 const AVFrame *frame, int *got_packet_ptr)
00071 {
00072 CNGContext *p = avctx->priv_data;
00073 int ret, i;
00074 double energy = 0;
00075 int qdbov;
00076 int16_t *samples = (int16_t*) frame->data[0];
00077
00078 if ((ret = ff_alloc_packet(avpkt, 1 + p->order))) {
00079 av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
00080 return ret;
00081 }
00082
00083 for (i = 0; i < frame->nb_samples; i++) {
00084 p->samples32[i] = samples[i];
00085 energy += samples[i] * samples[i];
00086 }
00087 energy /= frame->nb_samples;
00088 if (energy > 0) {
00089 double dbov = 10 * log10(energy / 1081109975);
00090 qdbov = av_clip(-floor(dbov), 0, 127);
00091 } else {
00092 qdbov = 127;
00093 }
00094 ret = ff_lpc_calc_ref_coefs(&p->lpc, p->samples32, p->order, p->ref_coef);
00095 avpkt->data[0] = qdbov;
00096 for (i = 0; i < p->order; i++)
00097 avpkt->data[1 + i] = p->ref_coef[i] * 127 + 127;
00098
00099 *got_packet_ptr = 1;
00100 avpkt->size = 1 + p->order;
00101
00102 return 0;
00103 }
00104
00105 AVCodec ff_comfortnoise_encoder = {
00106 .name = "comfortnoise",
00107 .type = AVMEDIA_TYPE_AUDIO,
00108 .id = AV_CODEC_ID_COMFORT_NOISE,
00109 .priv_data_size = sizeof(CNGContext),
00110 .init = cng_encode_init,
00111 .encode2 = cng_encode_frame,
00112 .close = cng_encode_close,
00113 .long_name = NULL_IF_CONFIG_SMALL("RFC 3389 comfort noise generator"),
00114 .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
00115 AV_SAMPLE_FMT_NONE },
00116 };