From 48d4dc3f7b4e4342df4028564e3f9b83a95ff169 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Tue, 1 Sep 2020 13:01:55 -0400 Subject: [PATCH] TT#91003 support passing extra codec options Change-Id: I8e994f69d4ffc21ab5ab6e8c269e266cb1635b79 --- README.md | 3 ++- daemon/codec.c | 24 ++++++++++++++------- lib/codeclib.c | 57 +++++++++++++++++++++++++++----------------------- lib/codeclib.h | 18 +++++++++------- lib/rtplib.h | 1 + 5 files changed, 60 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 75d2e38dd..c00d9aaee 100644 --- a/README.md +++ b/README.md @@ -1127,7 +1127,8 @@ Optionally included keys are: channels) must also be specified. Additional options that can be appended to the codec string with additional slashes - are ptime and the `fmtp` string, for example `iLBC/8000/1///mode=30`. + are ptime, the `fmtp` string, and additional codec-specific options, for example + `iLBC/8000/1///mode=30` to use as `fmtp`. If a literal `=` cannot be used due to parsing constraints (i.e. being wrongly interpreted as a key-value pair), it can be escaped by using two dashes instead, diff --git a/daemon/codec.c b/daemon/codec.c index ed1b14195..f6fceae07 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -1558,7 +1558,7 @@ void codec_packet_free(void *pp) { struct rtp_payload_type *codec_make_payload_type(const str *codec_str, struct call_media *media) { str codec_fmt = *codec_str; - str codec, parms, chans, opts, extra_opts, fmt_params; + str codec, parms, chans, opts, extra_opts, fmt_params, codec_opts; if (str_token_sep(&codec, &codec_fmt, '/')) return NULL; str_token_sep(&parms, &codec_fmt, '/'); @@ -1566,6 +1566,7 @@ struct rtp_payload_type *codec_make_payload_type(const str *codec_str, struct ca str_token_sep(&opts, &codec_fmt, '/'); str_token_sep(&extra_opts, &codec_fmt, '/'); str_token_sep(&fmt_params, &codec_fmt, '/'); + str_token_sep(&codec_opts, &codec_fmt, '/'); int clockrate = str_to_i(&parms, 0); int channels = str_to_i(&chans, 0); @@ -1583,6 +1584,7 @@ struct rtp_payload_type *codec_make_payload_type(const str *codec_str, struct ca ret->bitrate = bitrate; ret->ptime = ptime; ret->format_parameters = fmt_params; + ret->codec_opts = codec_opts; const codec_def_t *def = codec_find(&ret->encoding, 0); ret->codec_def = def; @@ -1773,7 +1775,8 @@ static struct ssrc_entry *__ssrc_handler_transcode_new(void *p) { if (encoder_config_fmtp(ch->encoder, h->dest_pt.codec_def, ch->bitrate, ch->ptime, - &enc_format, &ch->encoder_format, &h->dest_pt.format_parameters)) + &enc_format, &ch->encoder_format, &h->dest_pt.format_parameters, + &h->dest_pt.codec_opts)) goto err; if (h->pcm_dtmf_detect) { @@ -1788,7 +1791,7 @@ static struct ssrc_entry *__ssrc_handler_transcode_new(void *p) { ch->decoder = decoder_new_fmtp(h->source_pt.codec_def, h->source_pt.clock_rate, h->source_pt.channels, h->source_pt.ptime, - &ch->encoder_format, &h->source_pt.format_parameters); + &ch->encoder_format, &h->source_pt.format_parameters, &h->source_pt.codec_opts); if (!ch->decoder) goto err; @@ -2189,6 +2192,7 @@ static void __rtp_payload_type_dup(struct call *call, struct rtp_payload_type *p call_str_cpy(call, &pt->encoding, &pt->encoding); call_str_cpy(call, &pt->encoding_parameters, &pt->encoding_parameters); call_str_cpy(call, &pt->format_parameters, &pt->format_parameters); + call_str_cpy(call, &pt->codec_opts, &pt->codec_opts); } static struct rtp_payload_type *__rtp_payload_type_copy(const struct rtp_payload_type *pt) { struct rtp_payload_type *pt_copy = g_slice_alloc(sizeof(*pt)); @@ -2273,7 +2277,9 @@ static int __revert_codec_strip(GHashTable *removed, const str *codec, g_queue_free(q); return 1; } -static int __codec_options_set1(struct rtp_payload_type *pt, const str *enc, GHashTable *codec_set) { +static int __codec_options_set1(struct call *call, struct rtp_payload_type *pt, const str *enc, + GHashTable *codec_set) +{ str *pt_str = g_hash_table_lookup(codec_set, enc); if (!pt_str) return 0; @@ -2288,15 +2294,17 @@ static int __codec_options_set1(struct rtp_payload_type *pt, const str *enc, GHa // match - apply options if (!pt->bitrate) pt->bitrate = pt_parsed->bitrate; + if (!pt->codec_opts.len && pt_parsed->codec_opts.len) + call_str_cpy(call, &pt->codec_opts, &pt_parsed->codec_opts); payload_type_free(pt_parsed); return 1; } -static void __codec_options_set(struct rtp_payload_type *pt, GHashTable *codec_set) { +static void __codec_options_set(struct call *call, struct rtp_payload_type *pt, GHashTable *codec_set) { if (!codec_set) return; - if (__codec_options_set1(pt, &pt->encoding_with_params, codec_set)) + if (__codec_options_set1(call, pt, &pt->encoding_with_params, codec_set)) return; - if (__codec_options_set1(pt, &pt->encoding, codec_set)) + if (__codec_options_set1(call, pt, &pt->encoding, codec_set)) return; } void codec_rtp_payload_types(struct call_media *media, struct call_media *other_media, @@ -2354,7 +2362,7 @@ void codec_rtp_payload_types(struct call_media *media, struct call_media *other_ continue; } } - __codec_options_set(pt, flags->codec_set); + __codec_options_set(call, pt, flags->codec_set); if (!mask_all && (!flags->codec_mask || !g_hash_table_lookup(flags->codec_mask, &pt->encoding)) && (!flags->codec_mask || !g_hash_table_lookup(flags->codec_mask, &pt->encoding_with_params))) __rtp_payload_type_add(media, other_media, pt); diff --git a/lib/codeclib.c b/lib/codeclib.c index 0a2f57732..a6f7034df 100644 --- a/lib/codeclib.c +++ b/lib/codeclib.c @@ -49,10 +49,10 @@ static set_enc_options_f amr_set_enc_options; static set_dec_options_f amr_set_dec_options; static void avc_def_init(codec_def_t *); -static const char *avc_decoder_init(decoder_t *, const str *); +static const char *avc_decoder_init(decoder_t *, const str *, const str *); static int avc_decoder_input(decoder_t *dec, const str *data, GQueue *out); static void avc_decoder_close(decoder_t *); -static const char *avc_encoder_init(encoder_t *enc, const str *); +static const char *avc_encoder_init(encoder_t *enc, const str *, const str *); static int avc_encoder_input(encoder_t *enc, AVFrame **frame); static void avc_encoder_close(encoder_t *enc); @@ -60,7 +60,7 @@ static int amr_decoder_input(decoder_t *dec, const str *data, GQueue *out); static void amr_encoder_got_packet(encoder_t *enc); static int ilbc_decoder_input(decoder_t *dec, const str *data, GQueue *out); -static const char *dtmf_decoder_init(decoder_t *, const str *); +static const char *dtmf_decoder_init(decoder_t *, const str *, const str *); static int dtmf_decoder_input(decoder_t *dec, const str *data, GQueue *out); @@ -103,10 +103,10 @@ static const codec_type_t codec_type_dtmf = { static packetizer_f packetizer_g729; // aggregate some frames into packets static void bcg729_def_init(codec_def_t *); -static const char *bcg729_decoder_init(decoder_t *, const str *); +static const char *bcg729_decoder_init(decoder_t *, const str *, 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 const char *bcg729_encoder_init(encoder_t *enc, const str *, const str *); static int bcg729_encoder_input(encoder_t *enc, AVFrame **frame); static void bcg729_encoder_close(encoder_t *enc); @@ -447,7 +447,7 @@ const codec_def_t *codec_find_by_av(enum AVCodecID id) { -static const char *avc_decoder_init(decoder_t *dec, const str *fmtp) { +static const char *avc_decoder_init(decoder_t *dec, const str *fmtp, const str *extra_opts) { AVCodec *codec = dec->def->decoder; if (!codec) return "codec not supported"; @@ -459,7 +459,7 @@ static const char *avc_decoder_init(decoder_t *dec, const str *fmtp) { dec->u.avc.avcctx->sample_rate = dec->in_format.clockrate; if (dec->def->set_dec_options) - dec->def->set_dec_options(dec, fmtp); + dec->def->set_dec_options(dec, fmtp, extra_opts); int i = avcodec_open2(dec->u.avc.avcctx, codec, NULL); if (i) { @@ -476,12 +476,16 @@ static const char *avc_decoder_init(decoder_t *dec, const str *fmtp) { -decoder_t *decoder_new_fmt(const codec_def_t *def, int clockrate, int channels, int ptime, const format_t *resample_fmt) { - return decoder_new_fmtp(def, clockrate, channels, ptime, resample_fmt, NULL); +decoder_t *decoder_new_fmt(const codec_def_t *def, int clockrate, int channels, int ptime, + const format_t *resample_fmt) +{ + return decoder_new_fmtp(def, clockrate, channels, ptime, resample_fmt, NULL, NULL); } -decoder_t *decoder_new_fmtp(const codec_def_t *def, int clockrate, int channels, int ptime, const format_t *resample_fmt, - const str *fmtp) +decoder_t *decoder_new_fmtp(const codec_def_t *def, int clockrate, int channels, int ptime, + const format_t *resample_fmt, + const str *fmtp, + const str *extra_opts) { const char *err; decoder_t *ret = NULL; @@ -507,7 +511,7 @@ decoder_t *decoder_new_fmtp(const codec_def_t *def, int clockrate, int channels, else ret->ptime = def->default_ptime; - err = def->codec_type->decoder_init(ret, fmtp); + err = def->codec_type->decoder_init(ret, fmtp, extra_opts); if (err) goto err; @@ -1008,7 +1012,7 @@ encoder_t *encoder_new(void) { return ret; } -static const char *avc_encoder_init(encoder_t *enc, const str *fmtp) { +static const char *avc_encoder_init(encoder_t *enc, const str *fmtp, const str *extra_opts) { enc->u.avc.codec = enc->def->encoder; if (!enc->u.avc.codec) return "output codec not found"; @@ -1044,7 +1048,7 @@ static const char *avc_encoder_init(encoder_t *enc, const str *fmtp) { enc->samples_per_packet = enc->samples_per_frame; if (enc->def->set_enc_options) - enc->def->set_enc_options(enc, fmtp); + enc->def->set_enc_options(enc, fmtp, extra_opts); int i = avcodec_open2(enc->u.avc.avcctx, enc->u.avc.codec, NULL); if (i) { @@ -1058,11 +1062,12 @@ static const char *avc_encoder_init(encoder_t *enc, const str *fmtp) { int encoder_config(encoder_t *enc, const codec_def_t *def, int bitrate, int ptime, const format_t *requested_format, format_t *actual_format) { - return encoder_config_fmtp(enc, def, bitrate, ptime, requested_format, actual_format, NULL); + return encoder_config_fmtp(enc, def, bitrate, ptime, requested_format, actual_format, NULL, NULL); } int encoder_config_fmtp(encoder_t *enc, const codec_def_t *def, int bitrate, int ptime, - const format_t *requested_format, format_t *actual_format, const str *fmtp) + const format_t *requested_format, format_t *actual_format, const str *fmtp, + const str *extra_opts) { const char *err; @@ -1081,7 +1086,7 @@ int encoder_config_fmtp(encoder_t *enc, const codec_def_t *def, int bitrate, int enc->ptime = ptime / def->clockrate_mult; enc->bitrate = bitrate; - err = def->codec_type->encoder_init ? def->codec_type->encoder_init(enc, fmtp) : 0; + err = def->codec_type->encoder_init ? def->codec_type->encoder_init(enc, fmtp, extra_opts) : 0; if (err) goto err; @@ -1370,7 +1375,7 @@ static void opus_init(struct rtp_payload_type *pt) { ilog(LOG_DEBUG, "Using default bitrate of %i bps for %i-channel Opus", pt->bitrate, pt->channels); } -static void opus_set_enc_options(encoder_t *enc, const str *fmtp) { +static void opus_set_enc_options(encoder_t *enc, const str *fmtp, const str *codec_opts) { int ret; if (enc->ptime) if ((ret = av_opt_set_int(enc->u.avc.avcctx, "frame_duration", enc->ptime, @@ -1423,7 +1428,7 @@ static int ilbc_mode(int ptime, const str *fmtp, const char *direction) { return mode; } -static void ilbc_set_enc_options(encoder_t *enc, const str *fmtp) { +static void ilbc_set_enc_options(encoder_t *enc, const str *fmtp, const str *codec_opts) { int ret; int mode = ilbc_mode(enc->ptime, fmtp, "encoder"); @@ -1433,7 +1438,7 @@ static void ilbc_set_enc_options(encoder_t *enc, const str *fmtp) { mode, av_error(ret)); } -static void ilbc_set_dec_options(decoder_t *dec, const str *fmtp) { +static void ilbc_set_dec_options(decoder_t *dec, const str *fmtp, const str *codec_opts) { int mode = ilbc_mode(dec->ptime, fmtp, "decoder"); if (mode == 20) dec->u.avc.avcctx->block_align = 38; @@ -1469,7 +1474,7 @@ static int ilbc_decoder_input(decoder_t *dec, const str *data, GQueue *out) { "block mode (%i ms mode)", (int) dec->u.avc.avcctx->block_align, (int) data->len, block_align, mode); avc_decoder_close(dec); - avc_decoder_init(dec, fmtp); + avc_decoder_init(dec, fmtp, NULL); } return avc_decoder_input(dec, data, out); @@ -1598,7 +1603,7 @@ static void amr_set_encdec_options(codec_options_t *opts, const str *fmtp, const // XXX other options } } -static void amr_set_enc_options(encoder_t *enc, const str *fmtp) { +static void amr_set_enc_options(encoder_t *enc, const str *fmtp, const str *codec_opts) { amr_set_encdec_options(&enc->codec_options, fmtp, enc->def); // if a mode-set was given, pick the highest supported bitrate @@ -1627,7 +1632,7 @@ static void amr_set_enc_options(encoder_t *enc, const str *fmtp) { } } } -static void amr_set_dec_options(decoder_t *dec, const str *fmtp) { +static void amr_set_dec_options(decoder_t *dec, const str *fmtp, const str *codec_opts) { amr_set_encdec_options(&dec->codec_options, fmtp, dec->def); } @@ -1833,7 +1838,7 @@ static void bcg729_def_init(codec_def_t *def) { } } -static const char *bcg729_decoder_init(decoder_t *dec, const str *fmtp) { +static const char *bcg729_decoder_init(decoder_t *dec, const str *fmtp, const str *extra_opts) { dec->u.bcg729 = initBcg729DecoderChannel(); if (!dec->u.bcg729) return "failed to initialize bcg729"; @@ -1877,7 +1882,7 @@ static void bcg729_decoder_close(decoder_t *dec) { dec->u.bcg729 = NULL; } -static const char *bcg729_encoder_init(encoder_t *enc, const str *fmtp) { +static const char *bcg729_encoder_init(encoder_t *enc, const str *fmtp, const str *extra_opts) { enc->u.bcg729 = initBcg729EncoderChannel(0); // no VAD if (!enc->u.bcg729) return "failed to initialize bcg729"; @@ -1968,7 +1973,7 @@ static int packetizer_g729(AVPacket *pkt, GString *buf, str *input_output, encod #endif -static const char *dtmf_decoder_init(decoder_t *dec, const str *fmtp) { +static const char *dtmf_decoder_init(decoder_t *dec, const str *fmtp, const str *extra_opts) { dec->u.dtmf.event = -1; return NULL; } diff --git a/lib/codeclib.h b/lib/codeclib.h index fa8479319..2583c901f 100644 --- a/lib/codeclib.h +++ b/lib/codeclib.h @@ -67,19 +67,19 @@ typedef union codec_options_u codec_options_t; typedef int packetizer_f(AVPacket *, GString *, str *, encoder_t *); typedef void format_init_f(struct rtp_payload_type *); -typedef void set_enc_options_f(encoder_t *, const str *); -typedef void set_dec_options_f(decoder_t *, 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 *); struct codec_type_s { void (*def_init)(codec_def_t *); - const char *(*decoder_init)(decoder_t *, const str *); + const char *(*decoder_init)(decoder_t *, const str *, const str *); int (*decoder_input)(decoder_t *, const str *data, GQueue *); void (*decoder_close)(decoder_t *); - const char *(*encoder_init)(encoder_t *, const str *); + const char *(*encoder_init)(encoder_t *, const str *, const str *); int (*encoder_input)(encoder_t *, AVFrame **); void (*encoder_got_packet)(encoder_t *); void (*encoder_close)(encoder_t *); @@ -242,9 +242,11 @@ const codec_def_t *codec_find(const str *name, enum media_type); const codec_def_t *codec_find_by_av(enum AVCodecID); -decoder_t *decoder_new_fmt(const codec_def_t *def, int clockrate, int channels, int ptime, const format_t *resample_fmt); -decoder_t *decoder_new_fmtp(const codec_def_t *def, int clockrate, int channels, int ptime, const format_t *resample_fmt, - const str *fmtp); +decoder_t *decoder_new_fmt(const codec_def_t *def, int clockrate, int channels, int ptime, + const format_t *resample_fmt); +decoder_t *decoder_new_fmtp(const codec_def_t *def, int clockrate, int channels, int ptime, + const format_t *resample_fmt, + const str *fmtp, const str *codec_opts); void decoder_close(decoder_t *dec); 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); @@ -254,7 +256,7 @@ encoder_t *encoder_new(void); int encoder_config(encoder_t *enc, const codec_def_t *def, int bitrate, int ptime, const format_t *requested_format, format_t *actual_format); int encoder_config_fmtp(encoder_t *enc, const codec_def_t *def, int bitrate, int ptime, - const format_t *requested_format, format_t *actual_format, const str *fmtp); + const format_t *requested_format, format_t *actual_format, const str *fmtp, const str *codec_opts); void encoder_close(encoder_t *); void encoder_free(encoder_t *); int encoder_input_data(encoder_t *enc, AVFrame *frame, diff --git a/lib/rtplib.h b/lib/rtplib.h index 370c24ab6..7cb73f8ae 100644 --- a/lib/rtplib.h +++ b/lib/rtplib.h @@ -24,6 +24,7 @@ struct rtp_payload_type { str encoding_parameters; // "2" int channels; // 2 str format_parameters; // value of a=fmtp + str codec_opts; // extra codec-specific options int ptime; // default from RFC int bitrate;