Title: [111119] trunk/Source/WebCore
Revision
111119
Author
[email protected]
Date
2012-03-17 04:30:21 -0700 (Sat, 17 Mar 2012)

Log Message

[GStreamer] run AudioFileReader in a nested loop
https://bugs.webkit.org/show_bug.cgi?id=80823

Reviewed by Martin Robinson.

Use a separate main loop for the file reader, this approach is
much cleaner than polling the default GLib main context.

* platform/audio/gstreamer/AudioFileReaderGStreamer.cpp:
(AudioFileReader):
(WebCore::enteredMainLoopCallback):
(WebCore):
(WebCore::AudioFileReader::AudioFileReader):
(WebCore::AudioFileReader::handleMessage):
(WebCore::AudioFileReader::start):
(WebCore::AudioFileReader::createBus):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (111118 => 111119)


--- trunk/Source/WebCore/ChangeLog	2012-03-17 10:48:41 UTC (rev 111118)
+++ trunk/Source/WebCore/ChangeLog	2012-03-17 11:30:21 UTC (rev 111119)
@@ -1,3 +1,22 @@
+2012-03-12  Philippe Normand  <[email protected]>
+
+        [GStreamer] run AudioFileReader in a nested loop
+        https://bugs.webkit.org/show_bug.cgi?id=80823
+
+        Reviewed by Martin Robinson.
+
+        Use a separate main loop for the file reader, this approach is
+        much cleaner than polling the default GLib main context.
+
+        * platform/audio/gstreamer/AudioFileReaderGStreamer.cpp:
+        (AudioFileReader):
+        (WebCore::enteredMainLoopCallback):
+        (WebCore):
+        (WebCore::AudioFileReader::AudioFileReader):
+        (WebCore::AudioFileReader::handleMessage):
+        (WebCore::AudioFileReader::start):
+        (WebCore::AudioFileReader::createBus):
+
 2012-02-07  Robert Hogan  <[email protected]>
 
         CSS 2.1 failure: fixed-table-layout-013 and fixed-table-layout-015 fail

Modified: trunk/Source/WebCore/platform/audio/gstreamer/AudioFileReaderGStreamer.cpp (111118 => 111119)


--- trunk/Source/WebCore/platform/audio/gstreamer/AudioFileReaderGStreamer.cpp	2012-03-17 10:48:41 UTC (rev 111118)
+++ trunk/Source/WebCore/platform/audio/gstreamer/AudioFileReaderGStreamer.cpp	2012-03-17 11:30:21 UTC (rev 111119)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (C) 2011 Igalia S.L
+ *  Copyright (C) 2011, 2012 Igalia S.L
  *  Copyright (C) 2011 Zan Dobersek  <[email protected]>
  *
  *  This library is free software; you can redistribute it and/or
@@ -24,8 +24,6 @@
 #include "AudioFileReader.h"
 
 #include "AudioBus.h"
-#include "GOwnPtr.h"
-#include "GRefPtr.h"
 #include <gio/gio.h>
 #include <gst/app/gstappsink.h>
 #include <gst/audio/multichannel.h>
@@ -33,6 +31,8 @@
 #include <gst/pbutils/pbutils.h>
 #include <wtf/Noncopyable.h>
 #include <wtf/PassOwnPtr.h>
+#include <wtf/gobject/GOwnPtr.h>
+#include <wtf/gobject/GRefPtr.h>
 
 namespace WebCore {
 
@@ -50,6 +50,7 @@
     void handleNewDeinterleavePad(GstPad*);
     void deinterleavePadsConfigured();
     void plugDeinterleave(GstPad*);
+    void decodeAudioForBusCreation();
 
 private:
     const void* m_data;
@@ -62,11 +63,10 @@
     GstBufferList* m_frontRightBuffers;
     GstBufferListIterator* m_frontRightBuffersIterator;
     GstElement* m_pipeline;
-    bool m_eos;
     unsigned m_channelSize;
-
-    gulong m_deinterleavePadAddedSignalHandlerId;
-    gulong m_deinterleaveNoMorePadSignalHandlerId;
+    GRefPtr<GstElement> m_decodebin;
+    GRefPtr<GstElement> m_deInterleave;
+    GRefPtr<GMainLoop> m_loop;
 };
 
 static GstCaps* getGStreamerAudioCaps(int channels, float sampleRate)
@@ -112,11 +112,18 @@
     reader->plugDeinterleave(pad);
 }
 
+gboolean enteredMainLoopCallback(gpointer userData)
+{
+    AudioFileReader* reader = reinterpret_cast<AudioFileReader*>(userData);
+    reader->decodeAudioForBusCreation();
+    return FALSE;
+}
+
 AudioFileReader::AudioFileReader(const char* filePath)
     : m_data(0)
     , m_dataSize(0)
     , m_filePath(filePath)
-    , m_eos(false)
+    , m_channelSize(0)
 {
 }
 
@@ -124,7 +131,7 @@
     : m_data(data)
     , m_dataSize(dataSize)
     , m_filePath(0)
-    , m_eos(false)
+    , m_channelSize(0)
 {
 }
 
@@ -176,7 +183,7 @@
 
     switch (GST_MESSAGE_TYPE(message)) {
     case GST_MESSAGE_EOS:
-        m_eos = true;
+        g_main_loop_quit(m_loop.get());
         break;
     case GST_MESSAGE_WARNING:
         gst_message_parse_warning(message, &error.outPtr(), &debug.outPtr());
@@ -241,17 +248,17 @@
     GstElement* audioConvert  = gst_element_factory_make("audioconvert", 0);
     GstElement* audioResample = gst_element_factory_make("audioresample", 0);
     GstElement* capsFilter = gst_element_factory_make("capsfilter", 0);
-    GstElement* deInterleave = gst_element_factory_make("deinterleave", "deinterleave");
+    m_deInterleave = gst_element_factory_make("deinterleave", "deinterleave");
 
-    g_object_set(deInterleave, "keep-positions", TRUE, NULL);
-    m_deinterleavePadAddedSignalHandlerId = g_signal_connect(deInterleave, "pad-added", G_CALLBACK(onGStreamerDeinterleavePadAddedCallback), this);
-    m_deinterleaveNoMorePadSignalHandlerId = g_signal_connect(deInterleave, "no-more-pads", G_CALLBACK(onGStreamerDeinterleaveReadyCallback), this);
+    g_object_set(m_deInterleave.get(), "keep-positions", TRUE, NULL);
+    g_signal_connect(m_deInterleave.get(), "pad-added", G_CALLBACK(onGStreamerDeinterleavePadAddedCallback), this);
+    g_signal_connect(m_deInterleave.get(), "no-more-pads", G_CALLBACK(onGStreamerDeinterleaveReadyCallback), this);
 
     GstCaps* caps = getGStreamerAudioCaps(2, m_sampleRate);
     g_object_set(capsFilter, "caps", caps, NULL);
     gst_caps_unref(caps);
 
-    gst_bin_add_many(GST_BIN(m_pipeline), audioConvert, audioResample, capsFilter, deInterleave, NULL);
+    gst_bin_add_many(GST_BIN(m_pipeline), audioConvert, audioResample, capsFilter, m_deInterleave.get(), NULL);
 
     GstPad* sinkPad = gst_element_get_static_pad(audioConvert, "sink");
     gst_pad_link(pad, sinkPad);
@@ -259,15 +266,43 @@
 
     gst_element_link_pads_full(audioConvert, "src", audioResample, "sink", GST_PAD_LINK_CHECK_NOTHING);
     gst_element_link_pads_full(audioResample, "src", capsFilter, "sink", GST_PAD_LINK_CHECK_NOTHING);
-    gst_element_link_pads_full(capsFilter, "src", deInterleave, "sink", GST_PAD_LINK_CHECK_NOTHING);
+    gst_element_link_pads_full(capsFilter, "src", m_deInterleave.get(), "sink", GST_PAD_LINK_CHECK_NOTHING);
 
     gst_element_sync_state_with_parent(audioConvert);
     gst_element_sync_state_with_parent(audioResample);
     gst_element_sync_state_with_parent(capsFilter);
-    gst_element_sync_state_with_parent(deInterleave);
+    gst_element_sync_state_with_parent(m_deInterleave.get());
 }
 
+void AudioFileReader::decodeAudioForBusCreation()
+{
+    // Build the pipeline (giostreamsrc | filesrc) ! decodebin2
+    // A deinterleave element is added once a src pad becomes available in decodebin.
+    m_pipeline = gst_pipeline_new(0);
 
+    GRefPtr<GstBus> bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(m_pipeline)));
+    gst_bus_add_signal_watch(bus.get());
+    g_signal_connect(bus.get(), "message", G_CALLBACK(messageCallback), this);
+
+    GstElement* source;
+    if (m_data) {
+        ASSERT(m_dataSize);
+        source = gst_element_factory_make("giostreamsrc", 0);
+        GRefPtr<GInputStream> memoryStream = g_memory_input_stream_new_from_data(m_data, m_dataSize, 0);
+        g_object_set(source, "stream", memoryStream.get(), NULL);
+    } else {
+        source = gst_element_factory_make("filesrc", 0);
+        g_object_set(source, "location", m_filePath, NULL);
+    }
+
+    m_decodebin = gst_element_factory_make("decodebin2", "decodebin");
+    g_signal_connect(m_decodebin.get(), "pad-added", G_CALLBACK(onGStreamerDecodebinPadAddedCallback), this);
+
+    gst_bin_add_many(GST_BIN(m_pipeline), source, m_decodebin.get(), NULL);
+    gst_element_link_pads_full(source, "src", m_decodebin.get(), "sink", GST_PAD_LINK_CHECK_NOTHING);
+    gst_element_set_state(m_pipeline, GST_STATE_PAUSED);
+}
+
 PassOwnPtr<AudioBus> AudioFileReader::createBus(float sampleRate, bool mixToMono)
 {
     m_sampleRate = sampleRate;
@@ -287,50 +322,25 @@
     m_frontRightBuffersIterator = gst_buffer_list_iterate(m_frontRightBuffers);
     gst_buffer_list_iterator_add_group(m_frontRightBuffersIterator);
 
-    // Build the pipeline (giostreamsrc | filesrc) ! decodebin2
-    // A deinterleave element is added once a src pad becomes available in decodebin.
-    m_pipeline = gst_pipeline_new(0);
+    GRefPtr<GMainContext> context = g_main_context_new();
+    g_main_context_push_thread_default(context.get());
+    m_loop = adoptGRef(g_main_loop_new(context.get(), FALSE));
 
-    GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(m_pipeline));
-    gst_bus_add_signal_watch(bus);
-    gulong busSignalHandlerId = g_signal_connect(bus, "message", G_CALLBACK(messageCallback), this);
+    // Start the pipeline processing just after the loop is started.
+    GSource* timeoutSource = g_timeout_source_new(0);
+    g_source_attach(timeoutSource, context.get());
+    g_source_set_callback(timeoutSource, reinterpret_cast<GSourceFunc>(enteredMainLoopCallback), this, 0);
 
-    GstElement* source;
-    if (m_data) {
-        ASSERT(m_dataSize);
-        source = gst_element_factory_make("giostreamsrc", 0);
-        GRefPtr<GInputStream> memoryStream = g_memory_input_stream_new_from_data(m_data, m_dataSize, 0);
-        g_object_set(source, "stream", memoryStream.get(), NULL);
-    } else {
-        source = gst_element_factory_make("filesrc", 0);
-        g_object_set(source, "location", m_filePath, NULL);
-    }
+    g_main_loop_run(m_loop.get());
+    g_main_context_pop_thread_default(context.get());
 
-    GstElement* decodebin = gst_element_factory_make("decodebin2", "decodebin");
-    gulong decodebinPadAddedSignalHandlerId = g_signal_connect(decodebin, "pad-added", G_CALLBACK(onGStreamerDecodebinPadAddedCallback), this);
+    GRefPtr<GstBus> bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(m_pipeline)));
+    g_signal_handlers_disconnect_by_func(bus.get(), reinterpret_cast<gpointer>(messageCallback), this);
 
-    gst_bin_add_many(GST_BIN(m_pipeline), source, decodebin, NULL);
-    gst_element_link_pads_full(source, "src", decodebin, "sink", GST_PAD_LINK_CHECK_NOTHING);
+    g_signal_handlers_disconnect_by_func(m_decodebin.get(), reinterpret_cast<gpointer>(onGStreamerDecodebinPadAddedCallback), this);
+    g_signal_handlers_disconnect_by_func(m_deInterleave.get(), reinterpret_cast<gpointer>(onGStreamerDeinterleavePadAddedCallback), this);
+    g_signal_handlers_disconnect_by_func(m_deInterleave.get(), reinterpret_cast<gpointer>(onGStreamerDeinterleaveReadyCallback), this);
 
-    m_eos = false;
-    m_channelSize = 0;
-    gst_element_set_state(m_pipeline, GST_STATE_PAUSED);
-    while (!m_eos)
-        g_main_context_iteration(0, FALSE);
-
-    g_signal_handler_disconnect(bus, busSignalHandlerId);
-    gst_object_unref(bus);
-
-    g_signal_handler_disconnect(decodebin, decodebinPadAddedSignalHandlerId);
-
-    if (GstElement* deinterleave = gst_bin_get_by_name(GST_BIN(m_pipeline), "deinterleave")) {
-        if (g_signal_handler_is_connected(deinterleave, m_deinterleavePadAddedSignalHandlerId))
-            g_signal_handler_disconnect(deinterleave, m_deinterleavePadAddedSignalHandlerId);
-        if (g_signal_handler_is_connected(deinterleave, m_deinterleaveNoMorePadSignalHandlerId))
-            g_signal_handler_disconnect(deinterleave, m_deinterleaveNoMorePadSignalHandlerId);
-        gst_object_unref(deinterleave);
-    }
-
     unsigned channels = mixToMono ? 1 : 2;
     OwnPtr<AudioBus> audioBus = adoptPtr(new AudioBus(channels, m_channelSize, true));
     audioBus->setSampleRate(m_sampleRate);
@@ -347,6 +357,8 @@
     gst_element_set_state(m_pipeline, GST_STATE_NULL);
     gst_object_unref(GST_OBJECT(m_pipeline));
 
+    m_decodebin.clear();
+    m_deInterleave.clear();
     return audioBus.release();
 }
 

Modified: trunk/Source/WebCore/platform/graphics/gstreamer/GRefPtrGStreamer.cpp (111118 => 111119)


--- trunk/Source/WebCore/platform/graphics/gstreamer/GRefPtrGStreamer.cpp	2012-03-17 10:48:41 UTC (rev 111118)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/GRefPtrGStreamer.cpp	2012-03-17 11:30:21 UTC (rev 111119)
@@ -120,5 +120,25 @@
         gst_object_unref(ptr);
 }
 
+template <> GRefPtr<GstBus> adoptGRef(GstBus* ptr)
+{
+    ASSERT(!GST_OBJECT_IS_FLOATING(GST_OBJECT(ptr)));
+    return GRefPtr<GstBus>(ptr, GRefPtrAdopt);
 }
+
+template <> GstBus* refGPtr<GstBus>(GstBus* ptr)
+{
+    if (ptr)
+        webkitGstObjectRefSink(GST_OBJECT(ptr));
+
+    return ptr;
+}
+
+template <> void derefGPtr<GstBus>(GstBus* ptr)
+{
+    if (ptr)
+        gst_object_unref(ptr);
+}
+
+}
 #endif // USE(GSTREAMER)

Modified: trunk/Source/WebCore/platform/graphics/gstreamer/GRefPtrGStreamer.h (111118 => 111119)


--- trunk/Source/WebCore/platform/graphics/gstreamer/GRefPtrGStreamer.h	2012-03-17 10:48:41 UTC (rev 111118)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/GRefPtrGStreamer.h	2012-03-17 11:30:21 UTC (rev 111119)
@@ -28,6 +28,7 @@
 typedef struct _GstPadTemplate GstPadTemplate;
 typedef struct _GstCaps GstCaps;
 typedef struct _GstTask GstTask;
+typedef struct _GstBus GstBus;
 
 namespace WTF {
 
@@ -50,6 +51,10 @@
 template<> GstTask* refGPtr<GstTask>(GstTask* ptr);
 template<> void derefGPtr<GstTask>(GstTask* ptr);
 
+template<> GRefPtr<GstBus> adoptGRef(GstBus* ptr);
+template<> GstBus* refGPtr<GstBus>(GstBus* ptr);
+template<> void derefGPtr<GstBus>(GstBus* ptr);
+
 }
 
 #endif // USE(GSTREAMER)
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to