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();
}