From fa8123e1c273a1c8ef9f944f1a5b217f5a3de5e8 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Mon, 7 Jul 2025 11:44:43 -0400 Subject: [PATCH] MT#55283 explicitly return PTS/duration ... from packetizer function instead of putting it into the AVPacket. Remove AVPacket from callback function arguments. Fix up PTS/duration adjustments where they were missing. Closes #1963 Change-Id: Ib36b36bb6648b0579dd83155c7217317dda29cc3 --- daemon/codec.c | 28 ++++++++++++++++------------ daemon/media_player.c | 17 +++++++++-------- include/codec.h | 5 +++-- lib/codeclib.c | 42 +++++++++++++++++++++++++++++++++--------- lib/codeclib.h | 3 ++- t/test-amr-encode.c | 3 ++- 6 files changed, 65 insertions(+), 33 deletions(-) diff --git a/daemon/codec.c b/daemon/codec.c index 8508e7818..ed03617e0 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -285,8 +285,9 @@ static transcode_job_q transcode_jobs = TYPED_GQUEUE_INIT; static tc_code (*__rtp_decode)(struct codec_ssrc_handler *ch, struct codec_ssrc_handler *input_ch, struct transcode_packet *packet, struct media_packet *mp); static void transcode_job_free(struct transcode_job *j); -static void packet_encoded_tx(AVPacket *pkt, struct codec_ssrc_handler *ch, struct media_packet *mp, - str *inout, char *buf, unsigned int pkt_len, const struct fraction *cr_fact); +static void packet_encoded_tx(struct codec_ssrc_handler *ch, struct media_packet *mp, + str *inout, char *buf, unsigned int pkt_len, int64_t pts, int64_t duration, + const struct fraction *cr_fact); static void codec_output_rtp_seq_passthrough(struct media_packet *mp, struct codec_scheduler *csch, struct codec_handler *handler, @@ -4519,8 +4520,9 @@ static void __free_ssrc_handler(struct codec_ssrc_handler *ch) { void packet_encoded_packetize(AVPacket *pkt, struct codec_ssrc_handler *ch, struct media_packet *mp, packetizer_f pkt_f, void *pkt_f_data, const struct fraction *cr_fact, - void (*tx_f)(AVPacket *, struct codec_ssrc_handler *, struct media_packet *, str *, - char *, unsigned int, const struct fraction *cr_fact)) + void (*tx_f)(struct codec_ssrc_handler *, struct media_packet *, str *, + char *, unsigned int, int64_t pts, int64_t duration, + const struct fraction *cr_fact)) { // run this through our packetizer AVPacket *in_pkt = pkt; @@ -4538,10 +4540,11 @@ void packet_encoded_packetize(AVPacket *pkt, struct codec_ssrc_handler *ch, stru // and request a packet 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); + ch->sample_buffer, &inout, pkt_f_data, &pts, &duration); - if (G_UNLIKELY(ret == -1 || pkt->pts == AV_NOPTS_VALUE)) { + if (G_UNLIKELY(ret == -1 || pts == AV_NOPTS_VALUE)) { // nothing bufferpool_unref(buf); break; @@ -4549,7 +4552,7 @@ void packet_encoded_packetize(AVPacket *pkt, struct codec_ssrc_handler *ch, stru ilogs(transcoding, LOG_DEBUG, "Received packet of %zu bytes from packetizer", inout.len); - tx_f(pkt, ch, mp, &inout, buf, pkt_len, cr_fact); + tx_f(ch, mp, &inout, buf, pkt_len, pts, duration, cr_fact); if (ret == 0) { // no more to go @@ -4598,8 +4601,9 @@ static void codec_output_rtp_seq_own(struct media_packet *mp, struct codec_sched 0, payload_type, ts_delay); } -static void packet_encoded_tx(AVPacket *pkt, struct codec_ssrc_handler *ch, struct media_packet *mp, - str *inout, char *buf, unsigned int pkt_len, const struct fraction *cr_fact) +static void packet_encoded_tx(struct codec_ssrc_handler *ch, struct media_packet *mp, + str *inout, char *buf, unsigned int pkt_len, int64_t pts, int64_t duration, + const struct fraction *cr_fact) { // check special payloads @@ -4612,7 +4616,7 @@ static void packet_encoded_tx(AVPacket *pkt, struct codec_ssrc_handler *ch, stru int is_dtmf = 0; if (dtmf_pt != -1) - is_dtmf = dtmf_event_payload(inout, (uint64_t *) &pkt->pts, pkt->duration, + is_dtmf = dtmf_event_payload(inout, (uint64_t *) &pts, duration, &ch->dtmf_event, &ch->dtmf_events); if (is_dtmf) { payload_type = dtmf_pt; @@ -4628,7 +4632,7 @@ static void packet_encoded_tx(AVPacket *pkt, struct codec_ssrc_handler *ch, stru ts_delay = ntohs(ev_pt->duration) - (ch->handler->dest_pt.ptime * ch->handler->dest_pt.clock_rate / 1000); } else { - if (is_silence_event(inout, &ch->silence_events, pkt->pts, pkt->duration)) + if (is_silence_event(inout, &ch->silence_events, pts, duration)) payload_type = ch->handler->cn_payload_type; } @@ -4642,7 +4646,7 @@ static void packet_encoded_tx(AVPacket *pkt, struct codec_ssrc_handler *ch, stru memcpy(send_buf, buf, pkt_len); } ch->codec_output_rtp_seq(mp, &ch->csch, ch->handler, send_buf, inout->len, ch->csch.first_ts - + fraction_divl(pkt->pts, cr_fact), + + fraction_divl(pts, cr_fact), ch->rtp_mark ? 1 : 0, payload_type, ts_delay); mp->ssrc_out->seq_diff++; diff --git a/daemon/media_player.c b/daemon/media_player.c index 476cff696..179276c7a 100644 --- a/daemon/media_player.c +++ b/daemon/media_player.c @@ -816,20 +816,21 @@ static void media_player_cache_entry_decoder_thread(void *p) { obj_release(entry); } -static void packet_encoded_cache(AVPacket *pkt, struct codec_ssrc_handler *ch, struct media_packet *mp, - str *s, char *buf, unsigned int pkt_len, const struct fraction *cr_fact) +static void packet_encoded_cache(struct codec_ssrc_handler *ch, struct media_packet *mp, + str *s, char *buf, unsigned int pkt_len, + int64_t pts, int64_t dur, const struct fraction *cr_fact) { struct media_player_cache_entry *entry = mp->cache_entry; struct media_player_cache_packet *ep = g_new0(__typeof(*ep), 1); - long duration = fraction_divl(pkt->duration, cr_fact); + long duration = fraction_divl(dur, cr_fact); *ep = (__typeof__(*ep)) { .buf = buf, .s = *s, - .pts = pkt->pts, + .pts = pts, .duration_ts = duration, - .duration = (long long) duration * 1000000LL + .duration = duration * 1000000LL / entry->coder.handler->dest_pt.clock_rate, }; @@ -838,9 +839,9 @@ static void packet_encoded_cache(AVPacket *pkt, struct codec_ssrc_handler *ch, s if (entry->kernel_idx != -1) { ilog(LOG_DEBUG, "Adding media packet (length %zu, TS %" PRIu64 ", delay %lu ms) to kernel packet stream %i", - s->len, pkt->pts, entry->duration, entry->kernel_idx); - if (!kernel_add_stream_packet(entry->kernel_idx, s->s, s->len, entry->duration, pkt->pts, - pkt->duration)) + s->len, pts, entry->duration, entry->kernel_idx); + if (!kernel_add_stream_packet(entry->kernel_idx, s->s, s->len, entry->duration, pts, + dur)) ilog(LOG_ERR | LOG_FLAG_LIMIT, "Failed to add packet to kernel player (%s)", strerror(errno)); } diff --git a/include/codec.h b/include/codec.h index ecbc30464..7b0a762c4 100644 --- a/include/codec.h +++ b/include/codec.h @@ -254,8 +254,9 @@ void codec_handlers_stop(codec_handlers_q *, struct call_media *sink, bool clear void packet_encoded_packetize(AVPacket *pkt, struct codec_ssrc_handler *ch, struct media_packet *mp, packetizer_f pkt_f, void *pkt_f_data, const struct fraction *cr_fact, - void (*tx_f)(AVPacket *, struct codec_ssrc_handler *, struct media_packet *, str *, - char *, unsigned int, const struct fraction *cr_fact)); + void (*tx_f)(struct codec_ssrc_handler *, struct media_packet *, str *, + char *, unsigned int, int64_t pts, int64_t duration, + const struct fraction *cr_fact)); void codec_output_rtp(struct media_packet *mp, struct codec_scheduler *, struct codec_handler *handler, // normally == ch->handler except for DTMF char *buf, // malloc'd, room for rtp_header + filled-in payload diff --git a/lib/codeclib.c b/lib/codeclib.c index 3d47b5d71..ea43025ba 100644 --- a/lib/codeclib.c +++ b/lib/codeclib.c @@ -2159,7 +2159,9 @@ 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, encoder_t *enc, + int64_t *__restrict pts, int64_t *__restrict duration) +{ if (!pkt) return -1; if (output->len < pkt->size) { @@ -2169,22 +2171,29 @@ int packetizer_passthrough(AVPacket *pkt, GString *buf, str *output, encoder_t * } output->len = pkt->size; memcpy(output->s, pkt->data, pkt->size); + *pts = pkt->pts; + *duration = pkt->duration; return 0; } // 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) { +static int packetizer_samplestream(AVPacket *pkt, GString *buf, str *input_output, 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)) { + *pts = pkt->pts; + *duration = pkt->duration; memcpy(input_output->s, pkt->data, input_output->len); // any leftovers? if (pkt->size > input_output->len) { g_string_append_len(buf, (char *) pkt->data + input_output->len, pkt->size - input_output->len); - enc->packet_pts = pkt->pts + input_output->len + *duration = input_output->len * (fraction_mult(enc->def->bits_per_sample, &enc->clockrate_fact) / 8); + enc->packet_pts = pkt->pts + *duration; } return buf->len >= input_output->len ? 1 : 0; } @@ -2198,9 +2207,9 @@ static int packetizer_samplestream(AVPacket *pkt, GString *buf, str *input_outpu memcpy(input_output->s, buf->str, input_output->len); g_string_erase(buf, 0, input_output->len); // adjust output pts - enc->avpkt->pts = enc->packet_pts; - enc->packet_pts += input_output->len - * fraction_mult(enc->def->bits_per_sample, &enc->clockrate_fact) / 8; + *pts = enc->packet_pts; + *duration = input_output->len * (fraction_mult(enc->def->bits_per_sample, &enc->clockrate_fact) / 8); + enc->packet_pts += *duration; return buf->len >= input_output->len ? 1 : 0; } @@ -3313,7 +3322,9 @@ 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, encoder_t *enc, + int64_t *__restrict pts, int64_t *__restrict duration) +{ assert(pkt->size >= 1); // CMR + TOC byte (already included) + optional ILL/ILP + optional CRC + payload @@ -3342,6 +3353,9 @@ static int packetizer_amr(AVPacket *pkt, GString *buf, str *output, encoder_t *e unsigned char *s = (unsigned char *) output->s; // for safe bit shifting + *pts = pkt->pts; + *duration = enc->actual_format.clockrate * 20 / 1000; // 160 or 320 + s[0] = '\xf0'; // no CMR req (4 bits) // or do we have a CMR? @@ -3565,13 +3579,15 @@ 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, encoder_t *enc, + int64_t *__restrict pts, int64_t *__restrict duration) +{ // how many frames do we want? int want_frames = input_output->len / 10; // easiest case: we only want one frame. return what we got if (want_frames == 1 && pkt) - return packetizer_passthrough(pkt, buf, input_output, enc); + return packetizer_passthrough(pkt, buf, input_output, enc, pts, duration); // any other case, we go through our buffer str output = *input_output; // remaining output buffer @@ -3588,12 +3604,15 @@ static int packetizer_g729(AVPacket *pkt, GString *buf, str *input_output, encod && have_noise_frames != 4) return -1; + int64_t dur = 0; + // return non-silence/noise frames while we can while (buf->len >= 10 && want_frames && output.len >= 10) { memcpy(output.s, buf->str, 10); g_string_erase(buf, 0, 10); want_frames--; str_shift(&output, 10); + dur += 80; } // append silence/noise frames if we can @@ -3602,8 +3621,13 @@ static int packetizer_g729(AVPacket *pkt, GString *buf, str *input_output, encod g_string_erase(buf, 0, 2); want_frames--; str_shift(&output, 2); + dur += 80; } + *pts = enc->packet_pts; + *duration = dur; + enc->packet_pts += dur; + if (output.len == input_output->len) return -1; // got nothing input_output->len = output.s - input_output->s; diff --git a/lib/codeclib.h b/lib/codeclib.h index 8b2382f9a..5d1b4ae77 100644 --- a/lib/codeclib.h +++ b/lib/codeclib.h @@ -103,7 +103,8 @@ 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 *, 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 *); typedef void set_dec_options_f(decoder_t *, const str *); diff --git a/t/test-amr-encode.c b/t/test-amr-encode.c index 4653e688b..82bd14808 100644 --- a/t/test-amr-encode.c +++ b/t/test-amr-encode.c @@ -24,7 +24,8 @@ static int dec_cb(encoder_t *e, void *u1, void *u2) { int plen = 256; char payload[plen]; str inout = STR_LEN(payload, plen); - e->def->packetizer(e->avpkt, buf, &inout, e); + int64_t pts, dur; + e->def->packetizer(e->avpkt, buf, &inout, e, &pts, &dur); if (inout.len != *expect_len || memcmp(inout.s, *expect, *expect_len))