From 25d3fca079a19ee4905c5581c6e5c26ddd744ea7 Mon Sep 17 00:00:00 2001 From: Jim Broadus Date: Tue, 5 Jan 2021 15:38:08 -0800 Subject: [PATCH] gstengine: Fix output audio depth When the decoder bin's src pad becomes available, check its caps for a format. If the format is not S16LE, then apply F32LE caps before the tee. This prevents the pipeline from negotiating S16LE when the decoder produces other formats. --- src/engines/gstenginepipeline.cpp | 48 +++++++++++++++++++++++++++++-- src/engines/gstenginepipeline.h | 3 ++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/engines/gstenginepipeline.cpp b/src/engines/gstenginepipeline.cpp index 811e170c0..aac5dcc1a 100644 --- a/src/engines/gstenginepipeline.cpp +++ b/src/engines/gstenginepipeline.cpp @@ -850,20 +850,59 @@ void GstEnginePipeline::BufferingMessageReceived(GstMessage* msg) { } } +QString GstEnginePipeline::GetAudioFormat(GstCaps* caps) { + const guint sz = gst_caps_get_size(caps); + for (int i = 0; i < sz; i++) { + GstStructure* s = gst_caps_get_structure(caps, i); + if (strcmp(gst_structure_get_name(s), "audio/x-raw") == 0) { + const gchar* fmt = gst_structure_get_string(s, "format"); + if (fmt != nullptr) { + return QString::fromUtf8(fmt); + } + } + } + return ""; +} + void GstEnginePipeline::NewPadCallback(GstElement*, GstPad* pad, gpointer self) { GstEnginePipeline* instance = reinterpret_cast(self); GstPad* const audiopad = gst_element_get_static_pad(instance->audiobin_, "sink"); - // Link decodebin's sink pad to audiobin's src pad. + qLog(Debug) << "Decoder bin pad added:" << GST_PAD_NAME(pad); + + // Make sure the audio bin isn't already linked to something. if (GST_PAD_IS_LINKED(audiopad)) { qLog(Warning) << instance->id() << "audiopad is already linked, unlinking old pad"; gst_pad_unlink(audiopad, GST_PAD_PEER(audiopad)); } - gst_pad_link(pad, audiopad); + // See what the decoder bin wants to output. + GstCaps* caps = gst_pad_get_current_caps(pad); + if (caps) { + gchar* caps_str = gst_caps_to_string(caps); + qLog(Debug) << "Current caps:" << caps_str; + g_free(caps_str); + + QString fmt = GetAudioFormat(caps); + + // The output branch only handles F32LE and S16LE. If the source is S16LE, + // then use that throughout the pipeline. Otherwise, use F32LE. + if (fmt != "S16LE") { + GstCaps* new_caps = gst_caps_new_simple("audio/x-raw", "format", + G_TYPE_STRING, "F32LE", nullptr); + g_object_set(instance->capsfilter_, "caps", new_caps, nullptr); + gst_caps_unref(new_caps); + } + gst_caps_unref(caps); + } + + // Link decodebin's sink pad to audiobin's src pad. + if (gst_pad_link(pad, audiopad) != GST_PAD_LINK_OK) { + qLog(Error) << "Failed to link decoder to audio bin."; + } gst_object_unref(audiopad); // Offset the timestamps on all the buffers coming out of the decodebin so @@ -1100,6 +1139,11 @@ void GstEnginePipeline::TransitionToNext() { ignore_tags_ = true; + // Reset the caps filter + GstCaps* new_caps = gst_caps_new_any(); + g_object_set(capsfilter_, "caps", new_caps, nullptr); + gst_caps_unref(new_caps); + if (!ReplaceDecodeBin(next_.url_)) { qLog(Error) << "ReplaceDecodeBin failed with " << next_.url_; return; diff --git a/src/engines/gstenginepipeline.h b/src/engines/gstenginepipeline.h index 6a56764e2..039d54b03 100644 --- a/src/engines/gstenginepipeline.h +++ b/src/engines/gstenginepipeline.h @@ -168,6 +168,9 @@ class GstEnginePipeline : public QObject { // a src pad immediately and we can link it after everything's created. void MaybeLinkDecodeToAudio(); + // Helper method to retrieve the audio format from a GstCaps object. + static QString GetAudioFormat(GstCaps* caps); + private slots: void FaderTimelineFinished();