`EBUR128Analysis`: place a `queue` before `appsink`

This improves the performance of the analysis (by 2x!),
by offloading non-`libebur128`-computations (i.e. decode-convert)
to a separate thread, thus reducing walltime.
This commit is contained in:
Roman Lebedev 2023-06-30 00:24:40 +03:00 committed by Jonas Kvinge
parent bda2b91c92
commit 40ef3191fc
1 changed files with 17 additions and 2 deletions

View File

@ -282,9 +282,10 @@ std::optional<EBUR128Measures> EBUR128AnalysisImpl::Compute(const Song &song) {
GstElement *src = CreateElement("filesrc", pipeline);
GstElement *decode = CreateElement("decodebin", pipeline);
GstElement *convert = CreateElement("audioconvert", pipeline);
GstElement *queue = CreateElement("queue2", pipeline);
GstElement *sink = CreateElement("appsink", pipeline);
if (!src || !decode || !convert || !sink) {
if (!src || !decode || !convert || !queue || !sink) {
gst_object_unref(pipeline);
return std::nullopt;
}
@ -300,16 +301,30 @@ std::optional<EBUR128Measures> EBUR128AnalysisImpl::Compute(const Song &song) {
"layout = (string) interleaved");
GstCaps *caps = gst_static_caps_get(&static_caps);
gst_element_link_filtered(convert, sink, caps);
// Place a queue before the sink. It really does matter for performance.
gst_element_link_filtered(convert, queue, caps);
gst_element_link_many(queue, sink, nullptr);
gst_caps_unref(caps);
// Allow the queue to contain up to 60s of audio. It is a magical number,
// going higher does not appear to be beneficial for performance,
// and while it can be lower, that generally restricts decoding parallelizm.
g_object_set(G_OBJECT(queue), "max-size-time", 60 * GST_SECOND, nullptr);
// And disable the default buffer and byte limits.
g_object_set(G_OBJECT(queue), "max-size-buffers", 0, nullptr);
g_object_set(G_OBJECT(queue), "max-size-bytes", 0, nullptr);
GstAppSinkCallbacks callbacks;
memset(&callbacks, 0, sizeof(callbacks));
callbacks.new_sample = NewBufferCallback;
gst_app_sink_set_callbacks(reinterpret_cast<GstAppSink*>(sink), &callbacks, &impl, nullptr);
g_object_set(G_OBJECT(sink), "buffer-list", FALSE, nullptr);
g_object_set(G_OBJECT(sink), "sync", FALSE, nullptr);
g_object_set(G_OBJECT(sink), "emit-signals", TRUE, nullptr);
// Disable in-appsink buffering, since we place a proper queue before it.
g_object_set(G_OBJECT(sink), "max-buffers", 1, nullptr);
// Set the filename
g_object_set(src, "location", song.url().toLocalFile().toUtf8().constData(), nullptr);