Browse Source

TT#122401 support multiple DTX method per codec

Change-Id: I775d56e675255b3dca4227779d1146d8c8806f06
rfuchs/1283
Richard Fuchs 5 years ago
parent
commit
dc38a0e88e
3 changed files with 137 additions and 27 deletions
  1. +1
    -1
      daemon/codec.c
  2. +117
    -24
      lib/codeclib.c
  3. +19
    -2
      lib/codeclib.h

+ 1
- 1
daemon/codec.c View File

@ -2642,7 +2642,7 @@ static void __dtx_free(void *p) {
mutex_destroy(&dtxb->lock); mutex_destroy(&dtxb->lock);
} }
static void __dtx_setup(struct codec_ssrc_handler *ch) { static void __dtx_setup(struct codec_ssrc_handler *ch) {
if (!ch->handler->source_pt.codec_def->dtx || ch->dtx_buffer)
if (!decoder_has_dtx(ch->decoder) || ch->dtx_buffer)
return; return;
if (!rtpe_config.dtx_delay) if (!rtpe_config.dtx_delay)


+ 117
- 24
lib/codeclib.c View File

@ -106,6 +106,13 @@ static const codec_type_t codec_type_cn = {
.decoder_close = avc_decoder_close, .decoder_close = avc_decoder_close,
}; };
static const dtx_method_t dtx_method_silence = {
.do_dtx = generic_silence_dtx,
};
static const dtx_method_t dtx_method_amr = {
.do_dtx = amr_dtx,
};
#ifdef HAVE_BCG729 #ifdef HAVE_BCG729
static packetizer_f packetizer_g729; // aggregate some frames into packets static packetizer_f packetizer_g729; // aggregate some frames into packets
@ -142,7 +149,9 @@ static codec_def_t __codec_defs[] = {
.bits_per_sample = 8, .bits_per_sample = 8,
.media_type = MT_AUDIO, .media_type = MT_AUDIO,
.codec_type = &codec_type_avcodec, .codec_type = &codec_type_avcodec,
.dtx = generic_silence_dtx,
.dtx_methods = {
[DTX_SILENCE] = &dtx_method_silence,
},
}, },
{ {
.rtpname = "PCMU", .rtpname = "PCMU",
@ -155,7 +164,9 @@ static codec_def_t __codec_defs[] = {
.bits_per_sample = 8, .bits_per_sample = 8,
.media_type = MT_AUDIO, .media_type = MT_AUDIO,
.codec_type = &codec_type_avcodec, .codec_type = &codec_type_avcodec,
.dtx = generic_silence_dtx,
.dtx_methods = {
[DTX_SILENCE] = &dtx_method_silence,
},
}, },
{ {
.rtpname = "G723", .rtpname = "G723",
@ -168,7 +179,9 @@ static codec_def_t __codec_defs[] = {
.packetizer = packetizer_passthrough, .packetizer = packetizer_passthrough,
.media_type = MT_AUDIO, .media_type = MT_AUDIO,
.codec_type = &codec_type_avcodec, .codec_type = &codec_type_avcodec,
.dtx = generic_silence_dtx,
.dtx_methods = {
[DTX_SILENCE] = &dtx_method_silence,
},
}, },
{ {
.rtpname = "G722", .rtpname = "G722",
@ -181,7 +194,9 @@ static codec_def_t __codec_defs[] = {
.bits_per_sample = 8, .bits_per_sample = 8,
.media_type = MT_AUDIO, .media_type = MT_AUDIO,
.codec_type = &codec_type_avcodec, .codec_type = &codec_type_avcodec,
.dtx = generic_silence_dtx,
.dtx_methods = {
[DTX_SILENCE] = &dtx_method_silence,
},
}, },
{ {
.rtpname = "QCELP", .rtpname = "QCELP",
@ -191,7 +206,9 @@ static codec_def_t __codec_defs[] = {
.packetizer = packetizer_passthrough, .packetizer = packetizer_passthrough,
.media_type = MT_AUDIO, .media_type = MT_AUDIO,
.codec_type = &codec_type_avcodec, .codec_type = &codec_type_avcodec,
.dtx = generic_silence_dtx,
.dtx_methods = {
[DTX_SILENCE] = &dtx_method_silence,
},
}, },
#ifndef HAVE_BCG729 #ifndef HAVE_BCG729
{ {
@ -204,7 +221,9 @@ static codec_def_t __codec_defs[] = {
.packetizer = packetizer_passthrough, .packetizer = packetizer_passthrough,
.media_type = MT_AUDIO, .media_type = MT_AUDIO,
.codec_type = &codec_type_avcodec, .codec_type = &codec_type_avcodec,
.dtx = generic_silence_dtx,
.dtx_methods = {
[DTX_SILENCE] = &dtx_method_silence,
},
}, },
{ {
.rtpname = "G729a", .rtpname = "G729a",
@ -216,7 +235,9 @@ static codec_def_t __codec_defs[] = {
.packetizer = packetizer_passthrough, .packetizer = packetizer_passthrough,
.media_type = MT_AUDIO, .media_type = MT_AUDIO,
.codec_type = &codec_type_avcodec, .codec_type = &codec_type_avcodec,
.dtx = generic_silence_dtx,
.dtx_methods = {
[DTX_SILENCE] = &dtx_method_silence,
},
}, },
#else #else
{ {
@ -231,7 +252,9 @@ static codec_def_t __codec_defs[] = {
.bits_per_sample = 1, // 10 ms frame has 80 samples and encodes as (max) 10 bytes = 80 bits .bits_per_sample = 1, // 10 ms frame has 80 samples and encodes as (max) 10 bytes = 80 bits
.media_type = MT_AUDIO, .media_type = MT_AUDIO,
.codec_type = &codec_type_bcg729, .codec_type = &codec_type_bcg729,
.dtx = generic_silence_dtx,
.dtx_methods = {
[DTX_SILENCE] = &dtx_method_silence,
},
}, },
{ {
.rtpname = "G729a", .rtpname = "G729a",
@ -244,7 +267,9 @@ static codec_def_t __codec_defs[] = {
.bits_per_sample = 1, // 10 ms frame has 80 samples and encodes as (max) 10 bytes = 80 bits .bits_per_sample = 1, // 10 ms frame has 80 samples and encodes as (max) 10 bytes = 80 bits
.media_type = MT_AUDIO, .media_type = MT_AUDIO,
.codec_type = &codec_type_bcg729, .codec_type = &codec_type_bcg729,
.dtx = generic_silence_dtx,
.dtx_methods = {
[DTX_SILENCE] = &dtx_method_silence,
},
}, },
#endif #endif
{ {
@ -257,7 +282,9 @@ static codec_def_t __codec_defs[] = {
.packetizer = packetizer_passthrough, .packetizer = packetizer_passthrough,
.media_type = MT_AUDIO, .media_type = MT_AUDIO,
.codec_type = &codec_type_avcodec, .codec_type = &codec_type_avcodec,
.dtx = generic_silence_dtx,
.dtx_methods = {
[DTX_SILENCE] = &dtx_method_silence,
},
}, },
{ {
.rtpname = "GSM", .rtpname = "GSM",
@ -269,7 +296,9 @@ static codec_def_t __codec_defs[] = {
.packetizer = packetizer_passthrough, .packetizer = packetizer_passthrough,
.media_type = MT_AUDIO, .media_type = MT_AUDIO,
.codec_type = &codec_type_avcodec, .codec_type = &codec_type_avcodec,
.dtx = generic_silence_dtx,
.dtx_methods = {
[DTX_SILENCE] = &dtx_method_silence,
},
}, },
{ {
.rtpname = "iLBC", .rtpname = "iLBC",
@ -299,7 +328,9 @@ static codec_def_t __codec_defs[] = {
.codec_type = &codec_type_avcodec, .codec_type = &codec_type_avcodec,
.init = opus_init, .init = opus_init,
.set_enc_options = opus_set_enc_options, .set_enc_options = opus_set_enc_options,
.dtx = generic_silence_dtx,
.dtx_methods = {
[DTX_SILENCE] = &dtx_method_silence,
},
}, },
{ {
.rtpname = "vorbis", .rtpname = "vorbis",
@ -310,7 +341,9 @@ static codec_def_t __codec_defs[] = {
.packetizer = packetizer_passthrough, .packetizer = packetizer_passthrough,
.media_type = MT_AUDIO, .media_type = MT_AUDIO,
.codec_type = &codec_type_avcodec, .codec_type = &codec_type_avcodec,
.dtx = generic_silence_dtx,
.dtx_methods = {
[DTX_SILENCE] = &dtx_method_silence,
},
}, },
{ {
.rtpname = "ac3", .rtpname = "ac3",
@ -319,7 +352,9 @@ static codec_def_t __codec_defs[] = {
.packetizer = packetizer_passthrough, .packetizer = packetizer_passthrough,
.media_type = MT_AUDIO, .media_type = MT_AUDIO,
.codec_type = &codec_type_avcodec, .codec_type = &codec_type_avcodec,
.dtx = generic_silence_dtx,
.dtx_methods = {
[DTX_SILENCE] = &dtx_method_silence,
},
}, },
{ {
.rtpname = "eac3", .rtpname = "eac3",
@ -328,7 +363,9 @@ static codec_def_t __codec_defs[] = {
.packetizer = packetizer_passthrough, .packetizer = packetizer_passthrough,
.media_type = MT_AUDIO, .media_type = MT_AUDIO,
.codec_type = &codec_type_avcodec, .codec_type = &codec_type_avcodec,
.dtx = generic_silence_dtx,
.dtx_methods = {
[DTX_SILENCE] = &dtx_method_silence,
},
}, },
{ {
.rtpname = "ATRAC3", .rtpname = "ATRAC3",
@ -337,7 +374,9 @@ static codec_def_t __codec_defs[] = {
.packetizer = packetizer_passthrough, .packetizer = packetizer_passthrough,
.media_type = MT_AUDIO, .media_type = MT_AUDIO,
.codec_type = &codec_type_avcodec, .codec_type = &codec_type_avcodec,
.dtx = generic_silence_dtx,
.dtx_methods = {
[DTX_SILENCE] = &dtx_method_silence,
},
}, },
{ {
.rtpname = "ATRAC-X", .rtpname = "ATRAC-X",
@ -346,7 +385,9 @@ static codec_def_t __codec_defs[] = {
.packetizer = packetizer_passthrough, .packetizer = packetizer_passthrough,
.media_type = MT_AUDIO, .media_type = MT_AUDIO,
.codec_type = &codec_type_avcodec, .codec_type = &codec_type_avcodec,
.dtx = generic_silence_dtx,
.dtx_methods = {
[DTX_SILENCE] = &dtx_method_silence,
},
}, },
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 0, 0) #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 0, 0)
{ {
@ -356,7 +397,9 @@ static codec_def_t __codec_defs[] = {
.packetizer = packetizer_passthrough, .packetizer = packetizer_passthrough,
.media_type = MT_AUDIO, .media_type = MT_AUDIO,
.codec_type = &codec_type_avcodec, .codec_type = &codec_type_avcodec,
.dtx = generic_silence_dtx,
.dtx_methods = {
[DTX_SILENCE] = &dtx_method_silence,
},
}, },
{ {
.rtpname = "EVRC0", .rtpname = "EVRC0",
@ -366,7 +409,9 @@ static codec_def_t __codec_defs[] = {
.packetizer = packetizer_passthrough, .packetizer = packetizer_passthrough,
.media_type = MT_AUDIO, .media_type = MT_AUDIO,
.codec_type = &codec_type_avcodec, .codec_type = &codec_type_avcodec,
.dtx = generic_silence_dtx,
.dtx_methods = {
[DTX_SILENCE] = &dtx_method_silence,
},
}, },
{ {
.rtpname = "EVRC1", .rtpname = "EVRC1",
@ -376,7 +421,9 @@ static codec_def_t __codec_defs[] = {
.packetizer = packetizer_passthrough, .packetizer = packetizer_passthrough,
.media_type = MT_AUDIO, .media_type = MT_AUDIO,
.codec_type = &codec_type_avcodec, .codec_type = &codec_type_avcodec,
.dtx = generic_silence_dtx,
.dtx_methods = {
[DTX_SILENCE] = &dtx_method_silence,
},
}, },
#endif #endif
{ {
@ -395,7 +442,10 @@ static codec_def_t __codec_defs[] = {
.codec_type = &codec_type_amr, .codec_type = &codec_type_amr,
.set_enc_options = amr_set_enc_options, .set_enc_options = amr_set_enc_options,
.set_dec_options = amr_set_dec_options, .set_dec_options = amr_set_dec_options,
.dtx = amr_dtx,
.dtx_methods = {
[DTX_NATIVE] = &dtx_method_amr,
[DTX_SILENCE] = &dtx_method_silence,
},
}, },
{ {
.rtpname = "AMR-WB", .rtpname = "AMR-WB",
@ -413,7 +463,10 @@ static codec_def_t __codec_defs[] = {
.codec_type = &codec_type_amr, .codec_type = &codec_type_amr,
.set_enc_options = amr_set_enc_options, .set_enc_options = amr_set_enc_options,
.set_dec_options = amr_set_dec_options, .set_dec_options = amr_set_dec_options,
.dtx = amr_dtx,
.dtx_methods = {
[DTX_NATIVE] = &dtx_method_amr,
[DTX_SILENCE] = &dtx_method_silence,
},
}, },
{ {
.rtpname = "telephone-event", .rtpname = "telephone-event",
@ -559,6 +612,15 @@ decoder_t *decoder_new_fmtp(const codec_def_t *def, int clockrate, int channels,
else else
ret->ptime = def->default_ptime; ret->ptime = def->default_ptime;
// init with first supported DTX method
enum dtx_method dm = -1;
for (int i = 0; i < NUM_DTX_METHODS; i++) {
if (def->dtx_methods[i]) {
dm = i;
break;
}
}
err = def->codec_type->decoder_init(ret, fmtp, extra_opts); err = def->codec_type->decoder_init(ret, fmtp, extra_opts);
if (err) if (err)
goto err; goto err;
@ -568,6 +630,8 @@ decoder_t *decoder_new_fmtp(const codec_def_t *def, int clockrate, int channels,
ret->pts = (uint64_t) -1LL; ret->pts = (uint64_t) -1LL;
ret->rtp_ts = (unsigned long) -1L; ret->rtp_ts = (unsigned long) -1L;
decoder_switch_dtx(ret, dm);
return ret; return ret;
err: err:
@ -579,6 +643,33 @@ err:
} }
int decoder_switch_dtx(decoder_t *dec, enum dtx_method dm) {
if (dec->dtx.cleanup)
dec->dtx.cleanup(dec);
ZERO(dec->dtx);
unsigned int i = dm;
if (i >= NUM_DTX_METHODS)
return -1;
const dtx_method_t *dmp = dec->def->dtx_methods[i];
if (!dmp)
return -1;
dec->dtx = *dmp;
if (dmp->init) {
if (dmp->init(dec)) {
ilog(LOG_ERR, "Failed to initialise DTX (%u)", i);
decoder_switch_dtx(dec, -1);
return -1;
}
}
return 0;
}
gboolean decoder_has_dtx(decoder_t *dec) {
return dec->dtx.do_dtx == NULL ? FALSE : TRUE;
}
static void avc_decoder_close(decoder_t *dec) { static void avc_decoder_close(decoder_t *dec) {
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(56, 1, 0) #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(56, 1, 0)
avcodec_free_context(&dec->u.avc.avcctx); avcodec_free_context(&dec->u.avc.avcctx);
@ -597,6 +688,8 @@ void decoder_close(decoder_t *dec) {
if (dec->def && dec->def->codec_type && dec->def->codec_type->decoder_close) if (dec->def && dec->def->codec_type && dec->def->codec_type->decoder_close)
dec->def->codec_type->decoder_close(dec); dec->def->codec_type->decoder_close(dec);
decoder_switch_dtx(dec, -1);
resample_shutdown(&dec->resampler); resample_shutdown(&dec->resampler);
g_slice_free1(sizeof(*dec), dec); g_slice_free1(sizeof(*dec), dec);
} }
@ -712,7 +805,7 @@ static int __decoder_input_data(decoder_t *dec, const str *data, unsigned long t
if (G_UNLIKELY(!dec)) if (G_UNLIKELY(!dec))
return -1; return -1;
if (!data && !dec->def->dtx)
if (!data && !dec->dtx.do_dtx)
return 0; return 0;
ts *= dec->def->clockrate_mult; ts *= dec->def->clockrate_mult;
@ -741,7 +834,7 @@ static int __decoder_input_data(decoder_t *dec, const str *data, unsigned long t
if (data) if (data)
dec->def->codec_type->decoder_input(dec, data, &frames); dec->def->codec_type->decoder_input(dec, data, &frames);
else else
dec->def->dtx(dec, &frames, ptime);
dec->dtx.do_dtx(dec, &frames, ptime);
AVFrame *frame; AVFrame *frame;
int ret = 0; int ret = 0;


+ 19
- 2
lib/codeclib.h View File

@ -58,6 +58,7 @@ struct resample_s;
struct seq_packet_s; struct seq_packet_s;
struct rtp_payload_type; struct rtp_payload_type;
union codec_options_u; union codec_options_u;
struct dtx_method_s;
typedef struct codec_type_s codec_type_t; typedef struct codec_type_s codec_type_t;
typedef struct decoder_s decoder_t; typedef struct decoder_s decoder_t;
@ -66,13 +67,13 @@ typedef struct format_s format_t;
typedef struct resample_s resample_t; typedef struct resample_s resample_t;
typedef struct seq_packet_s seq_packet_t; typedef struct seq_packet_s seq_packet_t;
typedef union codec_options_u codec_options_t; typedef union codec_options_u codec_options_t;
typedef struct dtx_method_s dtx_method_t;
typedef int packetizer_f(AVPacket *, GString *, str *, encoder_t *); typedef int packetizer_f(AVPacket *, GString *, str *, encoder_t *);
typedef void format_init_f(struct rtp_payload_type *); typedef void format_init_f(struct rtp_payload_type *);
typedef void set_enc_options_f(encoder_t *, const str *, const str *); typedef void set_enc_options_f(encoder_t *, const str *, const str *);
typedef void set_dec_options_f(decoder_t *, const str *, const str *); typedef void set_dec_options_f(decoder_t *, const str *, const str *);
typedef int format_cmp_f(const struct rtp_payload_type *, const struct rtp_payload_type *); typedef int format_cmp_f(const struct rtp_payload_type *, const struct rtp_payload_type *);
typedef int decoder_dtx_f(decoder_t *, GQueue *, int);
@ -117,6 +118,13 @@ union codec_options_u {
} amr; } amr;
}; };
enum dtx_method {
DTX_NATIVE = 0,
DTX_SILENCE,
NUM_DTX_METHODS
};
struct codec_def_s { struct codec_def_s {
const char * const rtpname; const char * const rtpname;
int clockrate_mult; int clockrate_mult;
@ -137,7 +145,7 @@ struct codec_def_s {
format_init_f *init; format_init_f *init;
set_enc_options_f *set_enc_options; set_enc_options_f *set_enc_options;
set_dec_options_f *set_dec_options; set_dec_options_f *set_dec_options;
decoder_dtx_f *dtx;
const dtx_method_t * const dtx_methods[NUM_DTX_METHODS];
// filled in by codeclib_init() // filled in by codeclib_init()
str rtpname_str; str rtpname_str;
@ -171,9 +179,16 @@ enum codec_event {
CE_AMR_SEND_CMR, CE_AMR_SEND_CMR,
}; };
struct dtx_method_s {
int (*init)(decoder_t *);
void (*cleanup)(decoder_t *);
int (*do_dtx)(decoder_t *, GQueue *, int);
};
struct decoder_s { struct decoder_s {
const codec_def_t *def; const codec_def_t *def;
codec_options_t codec_options; codec_options_t codec_options;
dtx_method_t dtx;
format_t in_format, format_t in_format,
dec_out_format, dec_out_format,
@ -281,6 +296,8 @@ decoder_t *decoder_new_fmtp(const codec_def_t *def, int clockrate, int channels,
void decoder_close(decoder_t *dec); void decoder_close(decoder_t *dec);
int decoder_input_data(decoder_t *dec, const str *data, unsigned long ts, int decoder_input_data(decoder_t *dec, const str *data, unsigned long ts,
int (*callback)(decoder_t *, AVFrame *, void *u1, void *u2), void *u1, void *u2); int (*callback)(decoder_t *, AVFrame *, void *u1, void *u2), void *u1, void *u2);
gboolean decoder_has_dtx(decoder_t *);
int decoder_switch_dtx(decoder_t *dec, enum dtx_method);
int decoder_dtx(decoder_t *dec, unsigned long ts, int ptime, int decoder_dtx(decoder_t *dec, unsigned long ts, int ptime,
int (*callback)(decoder_t *, AVFrame *, void *u1, void *u2), void *u1, void *u2); int (*callback)(decoder_t *, AVFrame *, void *u1, void *u2), void *u1, void *u2);


Loading…
Cancel
Save