From 2e43b47305ff231ed81e726625d7f6f559e3c13f Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Fri, 2 Feb 2018 09:00:14 -0500 Subject: [PATCH] TT#31409 check codec support only once during startup Change-Id: I8eacd1f62cc1273707b4c4d1046918225e1b6957 --- daemon/codec.c | 18 ++++- lib/codeclib.c | 165 +++++++++++++++++--------------------- lib/codeclib.h | 16 ++-- recording-daemon/output.c | 14 +++- 4 files changed, 109 insertions(+), 104 deletions(-) diff --git a/daemon/codec.c b/daemon/codec.c index 506730f2c..8a8498dd1 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -110,8 +110,14 @@ reset: } static void __ensure_codec_def(struct rtp_payload_type *pt) { + if (pt->codec_def) + return; + + pt->codec_def = codec_find(&pt->encoding); if (!pt->codec_def) - pt->codec_def = codec_find(&pt->encoding); + return; + if (!pt->codec_def->encoder || !pt->codec_def->decoder) + pt->codec_def = NULL; } static GList *__delete_receiver_codec(struct call_media *receiver, GList *link) { struct rtp_payload_type *pt = link->data; @@ -405,9 +411,9 @@ static struct ssrc_entry *__ssrc_handler_new(void *p) { if (!ch->encoder) goto err; // XXX make bitrate configurable - if (encoder_config(ch->encoder, h->dest_pt.codec_def->avcodec_id, + if (encoder_config(ch->encoder, h->dest_pt.codec_def, h->dest_pt.codec_def->default_bitrate, - ch->ptime / h->dest_pt.codec_def->clockrate_mult, + ch->ptime, &enc_format, &ch->encoder_format)) goto err; @@ -622,6 +628,12 @@ static struct rtp_payload_type *codec_make_payload_type(const str *codec, struct const codec_def_t *dec = codec_find(codec); if (!dec) return NULL; + // we must support both encoding and decoding + if (!dec->encoder) + return NULL; + if (!dec->decoder) + return NULL; + if (dec->rfc_payload_type >= 0) { const struct rtp_payload_type *rfc_pt = rtp_get_rfc_payload_type(dec->rfc_payload_type); if (rfc_pt) { diff --git a/lib/codeclib.c b/lib/codeclib.c index 99b261321..cd8b439ad 100644 --- a/lib/codeclib.c +++ b/lib/codeclib.c @@ -37,10 +37,8 @@ static codec_def_t __codec_defs[] = { .rtpname = "PCMA", .avcodec_id = AV_CODEC_ID_PCM_ALAW, .clockrate_mult = 1, - .avcodec_name = NULL, .default_clockrate = 8000, .default_channels = 1, - .default_bitrate = 0, .default_ptime = 20, .packetizer = packetizer_samplestream, .bits_per_sample = 8, @@ -49,10 +47,8 @@ static codec_def_t __codec_defs[] = { .rtpname = "PCMU", .avcodec_id = AV_CODEC_ID_PCM_MULAW, .clockrate_mult = 1, - .avcodec_name = NULL, .default_clockrate = 8000, .default_channels = 1, - .default_bitrate = 0, .default_ptime = 20, .packetizer = packetizer_samplestream, .bits_per_sample = 8, @@ -61,22 +57,17 @@ static codec_def_t __codec_defs[] = { .rtpname = "G723", .avcodec_id = AV_CODEC_ID_G723_1, .clockrate_mult = 1, - .avcodec_name = NULL, .default_clockrate = 8000, .default_channels = 1, - .default_bitrate = 0, .default_ptime = 30, .packetizer = packetizer_passthrough, - .bits_per_sample = 0, }, { .rtpname = "G722", .avcodec_id = AV_CODEC_ID_ADPCM_G722, .clockrate_mult = 2, - .avcodec_name = NULL, .default_clockrate = 8000, .default_channels = 1, - .default_bitrate = 0, .default_ptime = 20, .packetizer = packetizer_samplestream, .bits_per_sample = 8, @@ -85,207 +76,152 @@ static codec_def_t __codec_defs[] = { .rtpname = "QCELP", .avcodec_id = AV_CODEC_ID_QCELP, .clockrate_mult = 1, - .avcodec_name = NULL, - .default_clockrate = -1, - .default_channels = -1, - .default_bitrate = 0, .default_ptime = 20, .packetizer = packetizer_passthrough, - .bits_per_sample = 0, + .decode_only_ok = 1, }, { .rtpname = "G729", .avcodec_id = AV_CODEC_ID_G729, .clockrate_mult = 1, - .avcodec_name = NULL, .default_clockrate = 8000, .default_channels = 1, - .default_bitrate = 0, .default_ptime = 20, .packetizer = packetizer_passthrough, - .bits_per_sample = 0, }, { .rtpname = "speex", .avcodec_id = AV_CODEC_ID_SPEEX, - .clockrate_mult = 1, - .avcodec_name = NULL, .default_clockrate = 16000, .default_channels = 1, .default_bitrate = 11000, .default_ptime = 20, .packetizer = packetizer_passthrough, - .bits_per_sample = 0, }, { .rtpname = "GSM", .avcodec_id = AV_CODEC_ID_GSM, - .clockrate_mult = 1, - .avcodec_name = NULL, .default_clockrate = 8000, .default_channels = 1, - .default_bitrate = 0, .default_ptime = 20, .packetizer = packetizer_passthrough, - .bits_per_sample = 0, }, { .rtpname = "iLBC", .avcodec_id = AV_CODEC_ID_ILBC, - .clockrate_mult = 1, - .avcodec_name = NULL, - .default_clockrate = -1, - .default_channels = -1, - .default_bitrate = 0, .default_ptime = 20, .packetizer = packetizer_passthrough, - .bits_per_sample = 0, }, { .rtpname = "opus", .avcodec_id = AV_CODEC_ID_OPUS, - .clockrate_mult = 1, .avcodec_name = "libopus", .default_clockrate = 48000, .default_channels = 2, .default_bitrate = 32000, .default_ptime = 20, .packetizer = packetizer_passthrough, - .bits_per_sample = 0, }, { .rtpname = "vorbis", .avcodec_id = AV_CODEC_ID_VORBIS, - .clockrate_mult = 1, .avcodec_name = "libvorbis", - .default_clockrate = -1, - .default_channels = -1, - .default_bitrate = 0, .default_ptime = 20, .packetizer = packetizer_passthrough, - .bits_per_sample = 0, }, { .rtpname = "ac3", .avcodec_id = AV_CODEC_ID_AC3, - .clockrate_mult = 1, - .avcodec_name = NULL, - .default_clockrate = -1, - .default_channels = -1, - .default_bitrate = 0, .default_ptime = 20, .packetizer = packetizer_passthrough, - .bits_per_sample = 0, }, { .rtpname = "eac3", .avcodec_id = AV_CODEC_ID_EAC3, - .clockrate_mult = 1, - .avcodec_name = NULL, - .default_clockrate = -1, - .default_channels = -1, - .default_bitrate = 0, .default_ptime = 20, .packetizer = packetizer_passthrough, - .bits_per_sample = 0, }, { .rtpname = "ATRAC3", .avcodec_id = AV_CODEC_ID_ATRAC3, - .clockrate_mult = 1, - .avcodec_name = NULL, - .default_clockrate = -1, - .default_channels = -1, - .default_bitrate = 0, .default_ptime = 20, .packetizer = packetizer_passthrough, - .bits_per_sample = 0, + .decode_only_ok = 1, }, { .rtpname = "ATRAC-X", .avcodec_id = AV_CODEC_ID_ATRAC3P, - .clockrate_mult = 1, - .avcodec_name = NULL, - .default_clockrate = -1, - .default_channels = -1, - .default_bitrate = 0, .default_ptime = 20, .packetizer = packetizer_passthrough, - .bits_per_sample = 0, + .decode_only_ok = 1, }, #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 0, 0) { .rtpname = "EVRC", .avcodec_id = AV_CODEC_ID_EVRC, - .clockrate_mult = 1, .avcodec_name = NULL, - .default_clockrate = -1, - .default_channels = -1, - .default_bitrate = 0, .default_ptime = 20, .packetizer = packetizer_passthrough, - .bits_per_sample = 0, + .decode_only_ok = 1, }, { .rtpname = "EVRC0", .avcodec_id = AV_CODEC_ID_EVRC, - .clockrate_mult = 1, .avcodec_name = NULL, .default_clockrate = 8000, - .default_channels = -1, - .default_bitrate = -1, .default_ptime = 20, .packetizer = packetizer_passthrough, - .bits_per_sample = 0, + .decode_only_ok = 1, }, { .rtpname = "EVRC1", .avcodec_id = AV_CODEC_ID_EVRC, - .clockrate_mult = 1, .avcodec_name = NULL, .default_clockrate = 8000, - .default_channels = -1, - .default_bitrate = -1, .default_ptime = 20, .packetizer = packetizer_passthrough, - .bits_per_sample = 0, + .decode_only_ok = 1, }, #endif { .rtpname = "AMR", .avcodec_id = AV_CODEC_ID_AMR_NB, - .clockrate_mult = 1, .avcodec_name = NULL, .default_clockrate = 8000, .default_channels = 1, .default_bitrate = 6600, .default_ptime = 20, .packetizer = packetizer_passthrough, - .bits_per_sample = 0, }, { .rtpname = "AMR-WB", .avcodec_id = AV_CODEC_ID_AMR_NB, - .clockrate_mult = 1, .avcodec_name = NULL, .default_clockrate = 16000, .default_channels = 1, .default_bitrate = 14250, .default_ptime = 20, .packetizer = packetizer_passthrough, - .bits_per_sample = 0, }, + // pseudo-codecs { .rtpname = "telephone-event", .avcodec_id = -1, - .clockrate_mult = 1, .avcodec_name = NULL, - .default_clockrate = -1, - .default_channels = -1, - .default_bitrate = -1, - .default_ptime = -1, .packetizer = packetizer_passthrough, - .bits_per_sample = 0, + }, + // for file writing + { + .rtpname = "PCM-S16LE", + .avcodec_id = AV_CODEC_ID_PCM_S16LE, + .avcodec_name = NULL, + .packetizer = packetizer_passthrough, + }, + { + .rtpname = "MP3", + .avcodec_id = AV_CODEC_ID_MP3, + .avcodec_name = NULL, + .packetizer = packetizer_passthrough, }, }; @@ -321,11 +257,14 @@ decoder_t *decoder_new_fmt(const codec_def_t *def, int clockrate, int channels, ret->out_format = *resample_fmt; // sample format to be determined later when decoded frames arrive - AVCodec *codec = NULL; - if (def->avcodec_name) - codec = avcodec_find_decoder_by_name(def->avcodec_name); - if (!codec) - codec = avcodec_find_decoder(def->avcodec_id); + AVCodec *codec = def->decoder; +// AVCodec *codec = NULL; +// if (def->decoder) +// codec = def->decoder; +// if (!codec && def->avcodec_name) +// codec = avcodec_find_decoder_by_name(def->avcodec_name); +// if (!codec && def->avcodec_id >= 0) +// codec = avcodec_find_decoder(def->avcodec_id); if (!codec) { ilog(LOG_WARN, "Codec '%s' not supported", def->rtpname); goto err; @@ -553,16 +492,53 @@ void codeclib_init() { codecs_ht = g_hash_table_new(str_hash, str_equal); for (int i = 0; i < G_N_ELEMENTS(__codec_defs); i++) { + // add to hash table codec_def_t *def = &__codec_defs[i]; str_init(&def->rtpname_str, (char *) def->rtpname); assert(g_hash_table_lookup(codecs_ht, &def->rtpname_str) == NULL); g_hash_table_insert(codecs_ht, &def->rtpname_str, def); + // init undefined member vars + if (!def->clockrate_mult) + def->clockrate_mult = 1; + if (!def->default_ptime) + def->default_ptime = -1; + if (!def->default_clockrate) + def->default_clockrate = -1; + if (!def->default_channels) + def->default_channels = -1; + + // init RFC-related info const struct rtp_payload_type *pt = rtp_get_rfc_codec(&def->rtpname_str); if (pt) def->rfc_payload_type = pt->payload_type; else def->rfc_payload_type = -1; + + // look up AVCodec structs + if (def->avcodec_name) { + def->encoder = avcodec_find_encoder_by_name(def->avcodec_name); + def->decoder = avcodec_find_decoder_by_name(def->avcodec_name); + } + if (def->avcodec_id >= 0) { + if (!def->encoder) + def->encoder = avcodec_find_encoder(def->avcodec_id); + if (!def->decoder) + def->decoder = avcodec_find_decoder(def->avcodec_id); + } + // check if we have support if we are supposed to + if (def->avcodec_name || def->avcodec_id >= 0) { + if (!def->encoder && !def->decoder) + ilog(LOG_INFO, "Codec %s is not supported by codec library", def->rtpname); + else if (!def->encoder) { + if (!def->decode_only_ok) + ilog(LOG_INFO, "Codec %s is only supported for decoding by codec library", + def->rtpname); + } + else if (!def->decoder) + ilog(LOG_INFO, "Codec %s is only supported for encoding by codec library", + def->rtpname); + } } } @@ -707,7 +683,7 @@ encoder_t *encoder_new() { return ret; } -int encoder_config(encoder_t *enc, int codec_id, int bitrate, int ptime, +int encoder_config(encoder_t *enc, const codec_def_t *def, int bitrate, int ptime, const format_t *requested_format, format_t *actual_format) { const char *err; @@ -721,10 +697,16 @@ int encoder_config(encoder_t *enc, int codec_id, int bitrate, int ptime, enc->requested_format = *requested_format; err = "output codec not found"; - enc->codec = avcodec_find_encoder(codec_id); + enc->codec = def->encoder; +// if (codec_name) +// enc->codec = avcodec_find_encoder_by_name(codec_name); +// if (!enc->codec) +// enc->codec = avcodec_find_encoder(codec_id); if (!enc->codec) goto err; + ptime /= def->clockrate_mult; + err = "failed to alloc codec context"; enc->avcctx = avcodec_alloc_context3(enc->codec); if (!enc->avcctx) @@ -793,6 +775,7 @@ void encoder_close(encoder_t *enc) { avcodec_free_context(&enc->avcctx); } enc->avcctx = NULL; + enc->codec = NULL; format_init(&enc->requested_format); format_init(&enc->actual_format); av_audio_fifo_free(enc->fifo); diff --git a/lib/codeclib.h b/lib/codeclib.h index 336053653..5ed247922 100644 --- a/lib/codeclib.h +++ b/lib/codeclib.h @@ -31,18 +31,22 @@ typedef int packetizer_f(AVPacket *, GString *, str *); struct codec_def_s { const char * const rtpname; - const int clockrate_mult; + int clockrate_mult; const int avcodec_id; - const char *avcodec_name; - const int default_clockrate; - const int default_channels; + const char * const avcodec_name; + int default_clockrate; + int default_channels; const int default_bitrate; - const int default_ptime; + int default_ptime; packetizer_f * const packetizer; const int bits_per_sample; + const int decode_only_ok; + // filled in by codeclib_init() str rtpname_str; int rfc_payload_type; + AVCodec *encoder; + AVCodec *decoder; }; struct format_s { @@ -107,7 +111,7 @@ int decoder_input_data(decoder_t *dec, const str *data, unsigned long ts, encoder_t *encoder_new(); -int encoder_config(encoder_t *enc, int codec_id, int bitrate, int ptime, +int encoder_config(encoder_t *enc, const codec_def_t *def, int bitrate, int ptime, const format_t *requested_format, format_t *actual_format); void encoder_close(encoder_t *); void encoder_free(encoder_t *); diff --git a/recording-daemon/output.c b/recording-daemon/output.c index d25338975..f11d0ebb2 100644 --- a/recording-daemon/output.c +++ b/recording-daemon/output.c @@ -8,7 +8,8 @@ #include "db.h" -static int output_codec_id; +//static int output_codec_id; +static const codec_def_t *output_codec; static const char *output_file_format; int mp3_bitrate; @@ -73,7 +74,7 @@ int output_config(output_t *output, const format_t *requested_format, format_t * if (!output->fmtctx->oformat) goto err; - if (encoder_config(output->encoder, output_codec_id, mp3_bitrate, 0, requested_format, actual_format)) + if (encoder_config(output->encoder, output_codec, mp3_bitrate, 0, requested_format, actual_format)) goto err; // err = "output codec not found"; @@ -215,14 +216,19 @@ void output_close(output_t *output) { void output_init(const char *format) { + str codec; + if (!strcmp(format, "wav")) { - output_codec_id = AV_CODEC_ID_PCM_S16LE; + str_init(&codec, "PCM-S16LE"); output_file_format = "wav"; } else if (!strcmp(format, "mp3")) { - output_codec_id = AV_CODEC_ID_MP3; + str_init(&codec, "MP3"); output_file_format = "mp3"; } else die("Unknown output format '%s'", format); + + output_codec = codec_find(&codec); + assert(output_codec != NULL); }