From b0738107ec55aa3760b46d55477765633425f0d4 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Fri, 1 May 2026 13:26:19 -0400 Subject: [PATCH] MT#55283 extend packetizer input In case of bitstream style codecs which still use an encoder which operates on fixed frame sizes (e.g. G.726), passing the maximum allowed frame/packet size to the packetizer is not enough. Instead it needs to know separately how much data it is expected to return. Add another argument to pass this information. This also fixes the incorrect math to adjust the frame duration in case of chunked output. Change-Id: I1d57c684ecea055059481de0220f6b6001088605 --- daemon/codec.c | 6 +++--- lib/codeclib.c | 40 +++++++++++++++++++++------------------- lib/codeclib.h | 2 +- t/test-amr-encode.c | 2 +- 4 files changed, 26 insertions(+), 24 deletions(-) diff --git a/daemon/codec.c b/daemon/codec.c index 710387960..ac2151409 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -4493,7 +4493,7 @@ static struct ssrc_entry *__ssrc_handler_transcode_new(void *p) { if (!__ssrc_handler_decode_common(ch, h, &ch->encoder_format)) goto err; - ch->bytes_per_packet = (ch->encoder->samples_per_packet ? : ch->encoder->samples_per_frame) + ch->bytes_per_packet = (ch->encoder->samples_per_packet ?: ch->encoder->samples_per_frame) * h->dest_pt.codec_def->bits_per_sample / 8; ilogs(codec, LOG_DEBUG, "Encoder created with clockrate %i, %i channels, using sample format %i " @@ -4589,8 +4589,8 @@ void packet_encoded_packetize(AVPacket *pkt, struct codec_ssrc_handler *ch, stru if (in_pkt) ilogs(transcoding, LOG_DEBUG, "Adding %i bytes to packetizer", in_pkt->size); int64_t pts, duration; - int ret = pkt_f(in_pkt, - ch->sample_buffer, &inout, pkt_f_data, &pts, &duration); + int ret = pkt_f(in_pkt, ch->sample_buffer, &inout, ch->bytes_per_packet, pkt_f_data, &pts, + &duration); if (G_UNLIKELY(ret == -1 || pts == AV_NOPTS_VALUE)) { // nothing diff --git a/lib/codeclib.c b/lib/codeclib.c index b97033e59..034e420a4 100644 --- a/lib/codeclib.c +++ b/lib/codeclib.c @@ -2163,7 +2163,7 @@ int encoder_input_fifo(encoder_t *enc, AVFrame *frame, } -int packetizer_passthrough(AVPacket *pkt, GString *buf, str *output, encoder_t *enc, +int packetizer_passthrough(AVPacket *pkt, GString *buf, str *output, size_t num_bytes, encoder_t *enc, int64_t *__restrict pts, int64_t *__restrict duration) { if (!pkt) @@ -2182,39 +2182,41 @@ int packetizer_passthrough(AVPacket *pkt, GString *buf, str *output, encoder_t * // returns: -1 = not enough data, nothing returned; 0 = returned a packet; // 1 = returned a packet and there's more -static int packetizer_samplestream(AVPacket *pkt, GString *buf, str *input_output, encoder_t *enc, - int64_t *__restrict pts, int64_t *__restrict duration) +static int packetizer_samplestream(AVPacket *pkt, GString *buf, str *input_output, size_t num_bytes, + encoder_t *enc, int64_t *__restrict pts, int64_t *__restrict duration) { // avoid moving buffers around if possible: // most common case: new input packet has just enough (or more) data as what we need - if (G_LIKELY(pkt && buf->len == 0 && pkt->size >= input_output->len)) { + if (G_LIKELY(pkt && buf->len == 0 && pkt->size >= num_bytes)) { *pts = pkt->pts; *duration = pkt->duration; - memcpy(input_output->s, pkt->data, input_output->len); + memcpy(input_output->s, pkt->data, num_bytes); // any leftovers? - if (pkt->size > input_output->len) { - g_string_append_len(buf, (char *) pkt->data + input_output->len, - pkt->size - input_output->len); - *duration = input_output->len - * (fraction_mult(enc->def->bits_per_sample, &enc->clockrate_fact) / 8); + if (pkt->size > num_bytes) { + g_string_append_len(buf, (char *) pkt->data + num_bytes, + pkt->size - num_bytes); + *duration = fraction_mult(num_bytes * 8, &enc->clockrate_fact) + / enc->def->bits_per_sample; enc->packet_pts = pkt->pts + *duration; } - return buf->len >= input_output->len ? 1 : 0; + input_output->len = num_bytes; + return buf->len >= num_bytes ? 1 : 0; } // we have to move data around. append input packet to buffer if we have one if (pkt) g_string_append_len(buf, (char *) pkt->data, pkt->size); // do we have enough? - if (buf->len < input_output->len) + if (buf->len < num_bytes) return -1; // copy requested data into provided output buffer and remove from interim buffer - memcpy(input_output->s, buf->str, input_output->len); - g_string_erase(buf, 0, input_output->len); + memcpy(input_output->s, buf->str, num_bytes); + input_output->len = num_bytes; + g_string_erase(buf, 0, num_bytes); // adjust output pts *pts = enc->packet_pts; - *duration = input_output->len * (fraction_mult(enc->def->bits_per_sample, &enc->clockrate_fact) / 8); + *duration = fraction_mult(num_bytes * 8, &enc->clockrate_fact) / enc->def->bits_per_sample; enc->packet_pts += *duration; - return buf->len >= input_output->len ? 1 : 0; + return buf->len >= num_bytes ? 1 : 0; } @@ -3325,7 +3327,7 @@ static void amr_encoder_got_packet(encoder_t *enc) { amr_encoder_mode_change(enc); enc->avc.amr.pkt_seq++; } -static int packetizer_amr(AVPacket *pkt, GString *buf, str *output, encoder_t *enc, +static int packetizer_amr(AVPacket *pkt, GString *buf, str *output, size_t num_bytes, encoder_t *enc, int64_t *__restrict pts, int64_t *__restrict duration) { assert(pkt->size >= 1); @@ -3582,7 +3584,7 @@ static void bcg729_encoder_close(encoder_t *enc) { enc->bcg729 = NULL; } -static int packetizer_g729(AVPacket *pkt, GString *buf, str *input_output, encoder_t *enc, +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? @@ -3590,7 +3592,7 @@ static int packetizer_g729(AVPacket *pkt, GString *buf, str *input_output, encod // easiest case: we only want one frame. return what we got if (want_frames == 1 && pkt) - return packetizer_passthrough(pkt, buf, input_output, enc, pts, duration); + 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 diff --git a/lib/codeclib.h b/lib/codeclib.h index bd33bcd6a..e4ca14c6c 100644 --- a/lib/codeclib.h +++ b/lib/codeclib.h @@ -103,7 +103,7 @@ typedef struct encoder_callback_s encoder_callback_t; typedef struct dtx_method_s dtx_method_t; typedef struct codec_cc_s codec_cc_t; -typedef int packetizer_f(AVPacket *, GString *, str *, encoder_t *, +typedef int packetizer_f(AVPacket *, GString *, str *, size_t, encoder_t *, int64_t *__restrict pts, int64_t *__restrict dur); typedef void format_init_f(struct rtp_payload_type *); typedef void set_enc_options_f(encoder_t *, const str *); diff --git a/t/test-amr-encode.c b/t/test-amr-encode.c index 82bd14808..65deea688 100644 --- a/t/test-amr-encode.c +++ b/t/test-amr-encode.c @@ -25,7 +25,7 @@ static int dec_cb(encoder_t *e, void *u1, void *u2) { char payload[plen]; str inout = STR_LEN(payload, plen); int64_t pts, dur; - e->def->packetizer(e->avpkt, buf, &inout, e, &pts, &dur); + e->def->packetizer(e->avpkt, buf, &inout, plen, e, &pts, &dur); if (inout.len != *expect_len || memcmp(inout.s, *expect, *expect_len))