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
pull/2100/head
Richard Fuchs 2 weeks ago
parent 2c6b9a5dc1
commit b0738107ec

@ -4493,7 +4493,7 @@ static struct ssrc_entry *__ssrc_handler_transcode_new(void *p) {
if (!__ssrc_handler_decode_common(ch, h, &ch->encoder_format)) if (!__ssrc_handler_decode_common(ch, h, &ch->encoder_format))
goto err; 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; * h->dest_pt.codec_def->bits_per_sample / 8;
ilogs(codec, LOG_DEBUG, "Encoder created with clockrate %i, %i channels, using sample format %i " 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) if (in_pkt)
ilogs(transcoding, LOG_DEBUG, "Adding %i bytes to packetizer", in_pkt->size); ilogs(transcoding, LOG_DEBUG, "Adding %i bytes to packetizer", in_pkt->size);
int64_t pts, duration; int64_t pts, duration;
int ret = pkt_f(in_pkt, int ret = pkt_f(in_pkt, ch->sample_buffer, &inout, ch->bytes_per_packet, pkt_f_data, &pts,
ch->sample_buffer, &inout, pkt_f_data, &pts, &duration); &duration);
if (G_UNLIKELY(ret == -1 || pts == AV_NOPTS_VALUE)) { if (G_UNLIKELY(ret == -1 || pts == AV_NOPTS_VALUE)) {
// nothing // nothing

@ -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) int64_t *__restrict pts, int64_t *__restrict duration)
{ {
if (!pkt) 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; // returns: -1 = not enough data, nothing returned; 0 = returned a packet;
// 1 = returned a packet and there's more // 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, size_t num_bytes,
int64_t *__restrict pts, int64_t *__restrict duration) encoder_t *enc, int64_t *__restrict pts, int64_t *__restrict duration)
{ {
// avoid moving buffers around if possible: // avoid moving buffers around if possible:
// most common case: new input packet has just enough (or more) data as what we need // 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; *pts = pkt->pts;
*duration = pkt->duration; *duration = pkt->duration;
memcpy(input_output->s, pkt->data, input_output->len); memcpy(input_output->s, pkt->data, num_bytes);
// any leftovers? // any leftovers?
if (pkt->size > input_output->len) { if (pkt->size > num_bytes) {
g_string_append_len(buf, (char *) pkt->data + input_output->len, g_string_append_len(buf, (char *) pkt->data + num_bytes,
pkt->size - input_output->len); pkt->size - num_bytes);
*duration = input_output->len *duration = fraction_mult(num_bytes * 8, &enc->clockrate_fact)
* (fraction_mult(enc->def->bits_per_sample, &enc->clockrate_fact) / 8); / enc->def->bits_per_sample;
enc->packet_pts = pkt->pts + *duration; 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 // we have to move data around. append input packet to buffer if we have one
if (pkt) if (pkt)
g_string_append_len(buf, (char *) pkt->data, pkt->size); g_string_append_len(buf, (char *) pkt->data, pkt->size);
// do we have enough? // do we have enough?
if (buf->len < input_output->len) if (buf->len < num_bytes)
return -1; return -1;
// copy requested data into provided output buffer and remove from interim buffer // copy requested data into provided output buffer and remove from interim buffer
memcpy(input_output->s, buf->str, input_output->len); memcpy(input_output->s, buf->str, num_bytes);
g_string_erase(buf, 0, input_output->len); input_output->len = num_bytes;
g_string_erase(buf, 0, num_bytes);
// adjust output pts // adjust output pts
*pts = enc->packet_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; 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); amr_encoder_mode_change(enc);
enc->avc.amr.pkt_seq++; 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) int64_t *__restrict pts, int64_t *__restrict duration)
{ {
assert(pkt->size >= 1); assert(pkt->size >= 1);
@ -3582,7 +3584,7 @@ static void bcg729_encoder_close(encoder_t *enc) {
enc->bcg729 = NULL; 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) int64_t *__restrict pts, int64_t *__restrict duration)
{ {
// how many frames do we want? // 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 // easiest case: we only want one frame. return what we got
if (want_frames == 1 && pkt) 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 // any other case, we go through our buffer
str output = *input_output; // remaining output buffer str output = *input_output; // remaining output buffer

@ -103,7 +103,7 @@ typedef struct encoder_callback_s encoder_callback_t;
typedef struct dtx_method_s dtx_method_t; typedef struct dtx_method_s dtx_method_t;
typedef struct codec_cc_s codec_cc_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); int64_t *__restrict pts, int64_t *__restrict dur);
typedef void format_init_f(struct rtp_payload_type *); typedef void format_init_f(struct rtp_payload_type *);
typedef void set_enc_options_f(encoder_t *, const str *); typedef void set_enc_options_f(encoder_t *, const str *);

@ -25,7 +25,7 @@ static int dec_cb(encoder_t *e, void *u1, void *u2) {
char payload[plen]; char payload[plen];
str inout = STR_LEN(payload, plen); str inout = STR_LEN(payload, plen);
int64_t pts, dur; 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 if (inout.len != *expect_len
|| memcmp(inout.s, *expect, *expect_len)) || memcmp(inout.s, *expect, *expect_len))

Loading…
Cancel
Save