mirror of https://github.com/sipwise/rtpengine.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
276 lines
7.2 KiB
276 lines
7.2 KiB
#include "codecmod.h"
|
|
|
|
#ifndef HAVE_BCG729
|
|
|
|
static const codec_def_t g729 = {
|
|
.rtpname = "G729",
|
|
.avcodec_id = AV_CODEC_ID_G729,
|
|
.default_clockrate = 8000,
|
|
.default_channels = 1,
|
|
.default_ptime = 20,
|
|
.minimum_ptime = 20,
|
|
.packetizer = packetizer_passthrough,
|
|
.media_type = MT_AUDIO,
|
|
.codec_type = &codec_type_avcodec,
|
|
.dtx_methods = {
|
|
[DTX_SILENCE] = &dtx_method_silence,
|
|
[DTX_CN] = &dtx_method_cn,
|
|
},
|
|
.fixed_sizes = 1,
|
|
};
|
|
|
|
static const codec_def_t g729a = {
|
|
.rtpname = "G729a",
|
|
.avcodec_id = AV_CODEC_ID_G729,
|
|
.default_clockrate = 8000,
|
|
.default_channels = 1,
|
|
.default_ptime = 20,
|
|
.minimum_ptime = 20,
|
|
.packetizer = packetizer_passthrough,
|
|
.media_type = MT_AUDIO,
|
|
.codec_type = &codec_type_avcodec,
|
|
.dtx_methods = {
|
|
[DTX_SILENCE] = &dtx_method_silence,
|
|
[DTX_CN] = &dtx_method_cn,
|
|
},
|
|
.fixed_sizes = 1,
|
|
};
|
|
|
|
#else
|
|
|
|
#include <bcg729/encoder.h>
|
|
#include <bcg729/decoder.h>
|
|
#include "fix_frame_channel_layout.compat"
|
|
#include "loglib.h"
|
|
|
|
|
|
static packetizer_f packetizer_g729; // aggregate some frames into packets
|
|
|
|
static void bcg729_def_init(struct codec_def_s *);
|
|
static const char *bcg729_decoder_init(decoder_t *, const str *);
|
|
static int bcg729_decoder_input(decoder_t *dec, const str *data, GQueue *out);
|
|
static void bcg729_decoder_close(decoder_t *);
|
|
static const char *bcg729_encoder_init(encoder_t *enc, const str *);
|
|
static int bcg729_encoder_input(encoder_t *enc, AVFrame **frame);
|
|
static void bcg729_encoder_close(encoder_t *enc);
|
|
|
|
static const codec_type_t codec_type_bcg729 = {
|
|
.def_init = bcg729_def_init,
|
|
.decoder_init = bcg729_decoder_init,
|
|
.decoder_input = bcg729_decoder_input,
|
|
.decoder_close = bcg729_decoder_close,
|
|
.encoder_init = bcg729_encoder_init,
|
|
.encoder_input = bcg729_encoder_input,
|
|
.encoder_close = bcg729_encoder_close,
|
|
};
|
|
|
|
static const codec_def_t g729 = {
|
|
.rtpname = "G729",
|
|
.avcodec_id = -1,
|
|
.default_clockrate = 8000,
|
|
.default_channels = 1,
|
|
.default_ptime = 20,
|
|
.minimum_ptime = 20,
|
|
.default_fmtp = "annexb=yes",
|
|
.format_cmp = format_cmp_ignore,
|
|
.packetizer = packetizer_g729,
|
|
.bits_per_sample = 1, // 10 ms frame has 80 samples and encodes as (max) 10 bytes = 80 bits
|
|
.media_type = MT_AUDIO,
|
|
.codec_type = &codec_type_bcg729,
|
|
.dtx_methods = {
|
|
[DTX_SILENCE] = &dtx_method_silence,
|
|
[DTX_CN] = &dtx_method_cn,
|
|
},
|
|
.fixed_sizes = 1,
|
|
};
|
|
|
|
static const codec_def_t g729a = {
|
|
.rtpname = "G729a",
|
|
.avcodec_id = -1,
|
|
.default_clockrate = 8000,
|
|
.default_channels = 1,
|
|
.default_ptime = 20,
|
|
.minimum_ptime = 20,
|
|
.default_fmtp = "annexb=no",
|
|
.format_cmp = format_cmp_ignore,
|
|
.packetizer = packetizer_g729,
|
|
.bits_per_sample = 1, // 10 ms frame has 80 samples and encodes as (max) 10 bytes = 80 bits
|
|
.media_type = MT_AUDIO,
|
|
.codec_type = &codec_type_bcg729,
|
|
.dtx_methods = {
|
|
[DTX_SILENCE] = &dtx_method_silence,
|
|
[DTX_CN] = &dtx_method_cn,
|
|
},
|
|
.fixed_sizes = 1,
|
|
};
|
|
|
|
|
|
|
|
static void bcg729_def_init(struct codec_def_s *def) {
|
|
// test init
|
|
bcg729EncoderChannelContextStruct *e = initBcg729EncoderChannel(0);
|
|
bcg729DecoderChannelContextStruct *d = initBcg729DecoderChannel();
|
|
if (e) {
|
|
def->support_encoding = 1;
|
|
closeBcg729EncoderChannel(e);
|
|
}
|
|
if (d) {
|
|
def->support_decoding = 1;
|
|
closeBcg729DecoderChannel(d);
|
|
}
|
|
}
|
|
|
|
static const char *bcg729_decoder_init(decoder_t *dec, const str *extra_opts) {
|
|
dec->bcg729 = initBcg729DecoderChannel();
|
|
if (!dec->bcg729)
|
|
return "failed to initialize bcg729";
|
|
return NULL;
|
|
}
|
|
|
|
static int bcg729_decoder_input(decoder_t *dec, const str *data, GQueue *out) {
|
|
str input = *data;
|
|
uint64_t pts = dec->pts;
|
|
|
|
while (input.len >= 2) {
|
|
int frame_len = input.len >= 10 ? 10 : 2;
|
|
str inp_frame = input;
|
|
inp_frame.len = frame_len;
|
|
str_shift(&input, frame_len);
|
|
|
|
AVFrame *frame = av_frame_alloc();
|
|
frame->nb_samples = 80;
|
|
frame->format = AV_SAMPLE_FMT_S16;
|
|
frame->sample_rate = dec->in_format.clockrate; // 8000
|
|
DEF_CH_LAYOUT(&frame->CH_LAYOUT, dec->in_format.channels);
|
|
frame->pts = pts;
|
|
if (av_frame_get_buffer(frame, 0) < 0)
|
|
abort();
|
|
|
|
pts += frame->nb_samples;
|
|
|
|
// XXX handle lost packets and comfort noise
|
|
bcg729Decoder(dec->bcg729, (void *) inp_frame.s, inp_frame.len, 0, 0, 0,
|
|
(void *) frame->extended_data[0]);
|
|
|
|
g_queue_push_tail(out, frame);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void bcg729_decoder_close(decoder_t *dec) {
|
|
if (dec->bcg729)
|
|
closeBcg729DecoderChannel(dec->bcg729);
|
|
dec->bcg729 = NULL;
|
|
}
|
|
|
|
static const char *bcg729_encoder_init(encoder_t *enc, const str *extra_opts) {
|
|
enc->bcg729 = initBcg729EncoderChannel(0); // no VAD
|
|
if (!enc->bcg729)
|
|
return "failed to initialize bcg729";
|
|
|
|
enc->actual_format.format = AV_SAMPLE_FMT_S16;
|
|
enc->actual_format.channels = 1;
|
|
enc->actual_format.clockrate = 8000;
|
|
enc->samples_per_frame = 80;
|
|
enc->samples_per_packet = enc->actual_format.clockrate * enc->ptime / 1000;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static int bcg729_encoder_input(encoder_t *enc, AVFrame **frame) {
|
|
if (!*frame)
|
|
return 0;
|
|
|
|
if ((*frame)->nb_samples != 80) {
|
|
ilog(LOG_ERR | LOG_FLAG_LIMIT, "bcg729: input %u samples instead of 80", (*frame)->nb_samples);
|
|
return -1;
|
|
}
|
|
|
|
av_new_packet(enc->avpkt, 10);
|
|
unsigned char len = 0;
|
|
|
|
bcg729Encoder(enc->bcg729, (void *) (*frame)->extended_data[0], enc->avpkt->data, &len);
|
|
if (!len) {
|
|
av_packet_unref(enc->avpkt);
|
|
return 0;
|
|
}
|
|
|
|
enc->avpkt->size = len;
|
|
enc->avpkt->pts = (*frame)->pts;
|
|
enc->avpkt->duration = len * 8; // Duration is used by encoder_input_data for pts calculation
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void bcg729_encoder_close(encoder_t *enc) {
|
|
if (enc->bcg729)
|
|
closeBcg729EncoderChannel(enc->bcg729);
|
|
enc->bcg729 = NULL;
|
|
}
|
|
|
|
static int packetizer_g729(AVPacket *pkt, GString *buf, str *input_output, size_t num_bytes, encoder_t *enc,
|
|
int64_t *__restrict pts, int64_t *__restrict duration)
|
|
{
|
|
// how many frames do we want?
|
|
int want_frames = input_output->len / 10;
|
|
|
|
// easiest case: we only want one frame. return what we got
|
|
if (want_frames == 1 && pkt)
|
|
return packetizer_passthrough(pkt, buf, input_output, num_bytes, enc, pts, duration);
|
|
|
|
// any other case, we go through our buffer
|
|
str output = *input_output; // remaining output buffer
|
|
if (pkt)
|
|
g_string_append_len(buf, (char *) pkt->data, pkt->size);
|
|
|
|
// how many frames do we have?
|
|
int have_audio_frames = buf->len / 10;
|
|
int have_noise_frames = (buf->len % 10) / 2;
|
|
// we have enough?
|
|
// special case: 4 noise frames (8 bytes) must be returned now, as otherwise
|
|
// (5 noise frames) they might become indistinguishable from an audio frame
|
|
if (have_audio_frames + have_noise_frames < want_frames
|
|
&& have_noise_frames != 4)
|
|
return -1;
|
|
|
|
int64_t dur = 0;
|
|
|
|
// return non-silence/noise frames while we can
|
|
while (buf->len >= 10 && want_frames && output.len >= 10) {
|
|
memcpy(output.s, buf->str, 10);
|
|
g_string_erase(buf, 0, 10);
|
|
want_frames--;
|
|
str_shift(&output, 10);
|
|
dur += 80;
|
|
}
|
|
|
|
// append silence/noise frames if we can
|
|
while (buf->len >= 2 && want_frames && output.len >= 2) {
|
|
memcpy(output.s, buf->str, 2);
|
|
g_string_erase(buf, 0, 2);
|
|
want_frames--;
|
|
str_shift(&output, 2);
|
|
dur += 80;
|
|
}
|
|
|
|
*pts = enc->packet_pts;
|
|
*duration = dur;
|
|
enc->packet_pts += dur;
|
|
|
|
if (output.len == input_output->len)
|
|
return -1; // got nothing
|
|
input_output->len = output.s - input_output->s;
|
|
return buf->len >= 2 ? 1 : 0;
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
__attribute__((constructor))
|
|
static void init(void) {
|
|
codeclib_register_codec(&g729);
|
|
codeclib_register_codec(&g729a);
|
|
}
|