TT#58659 add optional encoder detour

If multiple codecs are encoding to the same destination codec, make them
all use the same encoder context

Change-Id: Iaf9b248f9fd2016fef2b576d24d3fba557d7c1f5
changes/69/29869/5
Richard Fuchs 6 years ago
parent ca30ecaa3d
commit 194c9e482f

@ -107,6 +107,7 @@ static void __handler_shutdown(struct codec_handler *handler) {
handler->ssrc_handler = NULL;
handler->kernelize = 0;
handler->transcoder = 0;
handler->output_handler = handler; // reset to default
}
static void __codec_handler_free(void *pp) {
@ -121,6 +122,7 @@ void codec_handler_free(struct codec_handler *handler) {
static struct codec_handler *__handler_new(struct rtp_payload_type *pt) {
struct codec_handler *handler = g_slice_alloc0(sizeof(*handler));
handler->source_pt = *pt;
handler->output_handler = handler; // default
return handler;
}
@ -146,7 +148,8 @@ static void __make_dtmf(struct codec_handler *handler) {
handler->ssrc_hash = create_ssrc_hash_full(__ssrc_handler_new, handler);
}
static void __make_transcoder(struct codec_handler *handler, struct rtp_payload_type *dest)
static void __make_transcoder(struct codec_handler *handler, struct rtp_payload_type *dest,
GHashTable *output_transcoders)
{
assert(handler->source_pt.codec_def != NULL);
assert(dest->codec_def != NULL);
@ -164,7 +167,7 @@ static void __make_transcoder(struct codec_handler *handler, struct rtp_payload_
STR_FMT(&handler->source_pt.encoding_with_params),
STR_FMT(&dest->encoding_with_params));
return;
goto check_output;
reset:
__handler_shutdown(handler);
@ -178,6 +181,19 @@ reset:
ilog(LOG_DEBUG, "Created transcode context for " STR_FORMAT " -> " STR_FORMAT "",
STR_FMT(&handler->source_pt.encoding_with_params),
STR_FMT(&dest->encoding_with_params));
check_output:;
// check if we have multiple decoders transcoding to the same output PT
struct codec_handler *output_handler = g_hash_table_lookup(output_transcoders,
GINT_TO_POINTER(dest->payload_type));
if (output_handler) {
ilog(LOG_DEBUG, "Using existing encoder context");
handler->output_handler = output_handler;
}
else {
g_hash_table_insert(output_transcoders, GINT_TO_POINTER(dest->payload_type), handler);
handler->output_handler = handler; // make sure we don't have a stale pointer
}
}
struct codec_handler *codec_handler_make_playback(struct rtp_payload_type *src_pt,
@ -365,6 +381,11 @@ done:;
}
}
// if multiple input codecs transcode to the same output codec, we want to make sure
// that all the decoders output their media to the same encoder. we use the destination
// payload type to keep track of this.
GHashTable *output_transcoders = g_hash_table_new(g_direct_hash, g_direct_equal);
for (GList *l = receiver->codecs_prefs_recv.head; l; ) {
struct rtp_payload_type *pt = l->data;
@ -478,7 +499,7 @@ transcode:;
dest_pt->bitrate = reverse_pt->bitrate;
}
MEDIA_SET(receiver, TRANSCODE);
__make_transcoder(handler, dest_pt);
__make_transcoder(handler, dest_pt, output_transcoders);
next:
l = l->next;
@ -520,6 +541,8 @@ next:
while (passthrough_handlers) {
passthrough_handlers = g_slist_delete_link(passthrough_handlers, passthrough_handlers);
}
g_hash_table_destroy(output_transcoders);
}
@ -1105,6 +1128,24 @@ static int __packet_decoded(decoder_t *decoder, AVFrame *frame, void *u1, void *
ilog(LOG_DEBUG, "RTP media successfully decoded: TS %llu, samples %u",
(unsigned long long) frame->pts, frame->nb_samples);
// switch from input codec context to output context if necessary
struct codec_handler *handler = ch->handler;
if (handler->output_handler != handler) {
// our encoder is in a different codec handler
ilog(LOG_DEBUG, "Switching context from decoder to encoder");
handler = handler->output_handler;
struct codec_ssrc_handler *new_ch = get_ssrc(mp->ssrc_in->parent->h.ssrc, handler->ssrc_hash);
if (G_UNLIKELY(!new_ch)) {
ilog(LOG_ERR, "Switched from input to output codec context, but no codec handler present");
return -1;
}
// copy some essential parameters
if (!new_ch->first_ts)
new_ch->first_ts = ch->first_ts;
ch = new_ch;
}
encoder_input_fifo(ch->encoder, frame, __packet_encoded, ch, mp);
av_frame_free(&frame);

@ -30,6 +30,7 @@ struct codec_handler {
int transcoder:1;
struct ssrc_hash *ssrc_hash;
struct codec_handler *output_handler; // == self, or other PT handler
// for media playback
struct codec_ssrc_handler *ssrc_handler;

Loading…
Cancel
Save