From 0534e3d8edb585d4e48ac3e1e3006e28a5d6edff Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Fri, 4 Sep 2026 11:30:47 -0400 Subject: [PATCH] MT#65420 initial support for video transcoding Change-Id: I6fbf6dae7370860523abdb56ee3106e9fb3f0915 --- daemon/codec.c | 26 +++++++++-------- lib/auxlib.c | 6 ++++ lib/auxlib.h | 1 + lib/codeclib.c | 75 ++++++++++++++++++++++++++++++++++---------------- 4 files changed, 74 insertions(+), 34 deletions(-) diff --git a/daemon/codec.c b/daemon/codec.c index b8e13d8e6..04ca44e39 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -916,7 +916,7 @@ struct codec_handler *codec_handler_make_playback(const rtp_payload_type *src_pt handler->ssrc_handler->h.ssrc = ssrc; while (handler->ssrc_handler->csch.first_ts == 0) handler->ssrc_handler->csch.first_ts = ssl_random(); - handler->ssrc_handler->rtp_mark = true; + handler->ssrc_handler->rtp_mark = true; // relevant for audio ilogs(codec, LOG_DEBUG, "Created media playback context for " STR_FORMAT "/" STR_FORMAT " -> " STR_FORMAT "/" STR_FORMAT "/%d", @@ -4458,11 +4458,13 @@ static struct ssrc_entry *__ssrc_handler_transcode_new(void *p) { .time_base = h->dest_pt.time_base, }; - // see if there's a complete codec chain usable for this - if (!h->pcm_dtmf_detect) - ch->chain = codec_cc_new(h->source_pt.codec_def, &dec_format, - h->dest_pt.codec_def, &enc_format, - ch->bitrate, ch->ptime, async_chain_start, async_chain_finish); + if (h->dest_pt.codec_def->media_type == MT_AUDIO) { + // see if there's a complete codec chain usable for this + if (!h->pcm_dtmf_detect) + ch->chain = codec_cc_new(h->source_pt.codec_def, &dec_format, + h->dest_pt.codec_def, &enc_format, + ch->bitrate, ch->ptime, async_chain_start, async_chain_finish); + } if (ch->chain) { ilogs(codec, LOG_DEBUG, "Using codec chain to transcode from " STR_FORMAT "/" STR_FORMAT @@ -6434,12 +6436,14 @@ out: void codec_store_synthesise_basic(struct codec_store *dst, const char *reason) { if (!dst->codec_prefs.length) { // no codecs given: add defaults - static const str PCMU_str = STR_CONST("PCMU"); - static const str PCMA_str = STR_CONST("PCMA"); - codec_store_add_raw_order(dst, codec_make_payload_type(&PCMU_str, MT_AUDIO)); - codec_store_add_raw_order(dst, codec_make_payload_type(&PCMA_str, MT_AUDIO)); + if (dst->media->type_id == MT_AUDIO) { + static const str PCMU_str = STR_CONST("PCMU"); + static const str PCMA_str = STR_CONST("PCMA"); + codec_store_add_raw_order(dst, codec_make_payload_type(&PCMU_str, MT_AUDIO)); + codec_store_add_raw_order(dst, codec_make_payload_type(&PCMA_str, MT_AUDIO)); - ilogs(codec, LOG_DEBUG, "Using default codecs PCMU and PCMA for %s", reason); + ilogs(codec, LOG_DEBUG, "Using default codecs PCMU and PCMA for %s", reason); + } } else { // we already have a list of codecs - make sure they're all supported by us diff --git a/lib/auxlib.c b/lib/auxlib.c index 639cd27ec..d6b838b6b 100644 --- a/lib/auxlib.c +++ b/lib/auxlib.c @@ -263,7 +263,9 @@ void config_load_ext(int *argc, char ***argv, GOptionEntry *app_entries, const c { "io-uring", 0,0, G_OPTION_ARG_NONE, &rtpe_common_config_ptr->io_uring, "Use io_uring", NULL }, { "io-uring-buffers", 0,0, G_OPTION_ARG_INT, &rtpe_common_config_ptr->io_uring_buffers,"Number of io_uring entries per thread","INT" }, #endif +#ifdef WITH_TRANSCODING { "evs-lib-path", 0,0, G_OPTION_ARG_FILENAME, &rtpe_common_config_ptr->evs_lib_path, "Location of .so for 3GPP EVS codec", "FILE" }, + { "video-packet-size", 0,0, G_OPTION_ARG_INT, &rtpe_common_config_ptr->video_pkt_size,"Target maximum size of video RTP packets","INT" }, #ifdef HAVE_CODEC_CHAIN { "codec-chain-lib-path",0,0, G_OPTION_ARG_FILENAME, &rtpe_common_config_ptr->codec_chain_lib_path,"Location of libcodec-chain.so", "FILE" }, { "codec-chain-runners",0,0, G_OPTION_ARG_INT, &rtpe_common_config_ptr->codec_chain_runners,"Number of chain runners per codec","INT" }, @@ -273,6 +275,7 @@ void config_load_ext(int *argc, char ***argv, GOptionEntry *app_entries, const c { "codec-chain-interval",0,0, G_OPTION_ARG_INT, &rtpe_common_config_ptr->codec_chain_interval,"Microseconds between runs", "INT" }, { "codec-chain-opus-application",0,0,G_OPTION_ARG_STRING,&opus_application, "Opus application", "default|VoIP|audio|low-delay" }, { "codec-chain-opus-complexity",0,0,G_OPTION_ARG_INT, &rtpe_common_config_ptr->codec_chain_opus_complexity,"Opus encoding complexity (0..10)","INT" }, +#endif #endif }; @@ -525,6 +528,9 @@ out: die("Invalid value for --io-uring-buffers"); #endif + if (rtpe_common_config_ptr->video_pkt_size <= 0) + rtpe_common_config_ptr->video_pkt_size = 1300; + return; err: diff --git a/lib/auxlib.h b/lib/auxlib.h index 6d7c546c1..f83bacbe4 100644 --- a/lib/auxlib.h +++ b/lib/auxlib.h @@ -40,6 +40,7 @@ struct rtpengine_common_config { int max_log_line_length; int mos_type; // enum in codec_def_t char *evs_lib_path; + int video_pkt_size; char *codec_chain_lib_path; int codec_chain_runners; int codec_chain_concurrency; diff --git a/lib/codeclib.c b/lib/codeclib.c index 49eb22754..dfbe09d2a 100644 --- a/lib/codeclib.c +++ b/lib/codeclib.c @@ -283,28 +283,47 @@ static int __decoder_input_data(decoder_t *dec, const str *data, unsigned long t else dec->dtx.do_dtx(dec, &frames, *ptime); - AVFrame *frame; int ret = 0; - unsigned long samples = 0; - while ((frame = t_queue_pop_head(&frames))) { - samples += frame->nb_samples; - dec->dec_out_format.format = frame->format; - AVFrame *rsmp_frame = resample_frame(&dec->resampler, frame, &dec->dest_format); - if (!rsmp_frame) { - ilog(LOG_ERR | LOG_FLAG_LIMIT, "Resampling failed"); - ret = -1; + + if (dec->def->media_type == MT_AUDIO) { + AVFrame *frame; + unsigned long samples = 0; + while ((frame = t_queue_pop_head(&frames))) { + samples += frame->nb_samples; + dec->dec_out_format.format = frame->format; + AVFrame *rsmp_frame = resample_frame(&dec->resampler, frame, &dec->dest_format); + if (!rsmp_frame) { + ilog(LOG_ERR | LOG_FLAG_LIMIT, "Resampling failed"); + ret = -1; + } + else { + if (callback(dec, rsmp_frame, u1, u2)) + ret = -1; + } + if (rsmp_frame != frame) + av_frame_free(&frame); } - else { - if (callback(dec, rsmp_frame, u1, u2)) + + if (ptime) + *ptime = samples * 1000L / dec->in_format.clockrate; + } + else { // MT_VIDEO + AVFrame *frame; + while ((frame = t_queue_pop_head(&frames))) { + AVFrame *rsmp_frame = rescale_frame(&dec->rescaler, frame, &dec->dest_format); + if (!rsmp_frame) { + ilog(LOG_ERR | LOG_FLAG_LIMIT, "Rescaling failed"); ret = -1; + } + else { + if (callback(dec, rsmp_frame, u1, u2)) + ret = -1; + } + if (rsmp_frame != frame) + av_frame_free(&frame); } - if (rsmp_frame != frame) - av_frame_free(&frame); } - if (ptime) - *ptime = samples * 1000L / dec->in_format.clockrate; - return ret; } int decoder_input_data(decoder_t *dec, const str *data, unsigned long ts, @@ -416,10 +435,18 @@ void codeclib_init(int print) { def->default_clockrate_fact.div = 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; + if (!def->default_clockrate) { + if (def->media_type == MT_VIDEO) + def->default_clockrate = 90000; + else + def->default_clockrate = -1; + } + if (!def->default_channels) { + if (def->media_type == MT_VIDEO) + def->default_channels = 1; + else + def->default_channels = -1; + } if (!def->default_fps && def->media_type == MT_VIDEO) def->default_fps = 30; @@ -445,8 +472,10 @@ void codeclib_init(int print) { if (print) { if (def->support_encoding && def->support_decoding) { - if (def->default_channels > 0 && def->default_clockrate >= 0) - printf("%20s: fully supported\n", def->rtpname); + if (def->media_type == MT_AUDIO && def->default_channels > 0 && def->default_clockrate >= 0) + printf("%20s: fully supported (audio)\n", def->rtpname); + else if (def->media_type == MT_VIDEO && def->default_width > 0 && def->default_height >= 0) + printf("%20s: fully supported (video)\n", def->rtpname); else printf("%20s: codec supported but lacks RTP definition\n", def->rtpname); } @@ -711,7 +740,7 @@ int encoder_config_fmtp(encoder_t *enc, codec_def_t *def, int bitrate, int ptime enc->input_fn = encoder_input_direct; - if (enc->actual_format.format != -1 && enc->actual_format.clockrate > 0) { + if (def->media_type == MT_AUDIO && enc->actual_format.format != -1 && enc->actual_format.clockrate > 0) { enc->frame->nb_samples = enc->samples_per_frame ? : 256; enc->frame->format = enc->actual_format.format; enc->frame->sample_rate = enc->actual_format.clockrate;