diff --git a/daemon/codec.c b/daemon/codec.c index fdc42c4de..31b72dd14 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -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); diff --git a/include/codec.h b/include/codec.h index add8949e3..49f06f65b 100644 --- a/include/codec.h +++ b/include/codec.h @@ -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;