Bug 859199 - Load GStreamer libraries at runtime r=doublec
authorEdwin Flores <eflores@mozilla.com>
Tue, 11 Jun 2013 14:13:09 +1200
changeset 134604 7881391b201fc8bc581a3d7fc1d156a8246ffbad
parent 134603 928d5b1c632fa5deb62f8dbb493400fc0c4c77cb
child 134605 63e57ae2f15c950662dd7f84284ce29e1983c6e2
push id24805
push useremorley@mozilla.com
push dateTue, 11 Jun 2013 08:32:39 +0000
treeherdermozilla-central@81b227f1a522 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdoublec
bugs859199
milestone24.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 859199 - Load GStreamer libraries at runtime r=doublec
content/media/gstreamer/GStreamerFormatHelper.cpp
content/media/gstreamer/GStreamerFormatHelper.h
content/media/gstreamer/GStreamerFunctionList.h
content/media/gstreamer/GStreamerLoader.cpp
content/media/gstreamer/GStreamerLoader.h
content/media/gstreamer/GStreamerMozVideoBuffer.h
content/media/gstreamer/GStreamerReader.cpp
content/media/gstreamer/moz.build
layout/build/Makefile.in
toolkit/library/Makefile.in
--- a/content/media/gstreamer/GStreamerFormatHelper.cpp
+++ b/content/media/gstreamer/GStreamerFormatHelper.cpp
@@ -2,25 +2,32 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "GStreamerFormatHelper.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsXPCOMStrings.h"
+#include "GStreamerLoader.h"
 
 #define ENTRY_FORMAT(entry) entry[0]
 #define ENTRY_CAPS(entry) entry[1]
 
+namespace mozilla {
+
 GStreamerFormatHelper* GStreamerFormatHelper::gInstance = nullptr;
+bool GStreamerFormatHelper::sLoadOK = false;
 
 GStreamerFormatHelper* GStreamerFormatHelper::Instance() {
   if (!gInstance) {
-    gst_init(nullptr, nullptr);
+    if ((sLoadOK = load_gstreamer())) {
+      gst_init(nullptr, nullptr);
+    }
+
     gInstance = new GStreamerFormatHelper();
   }
 
   return gInstance;
 }
 
 void GStreamerFormatHelper::Shutdown() {
   if (gInstance) {
@@ -49,57 +56,71 @@ char const *const GStreamerFormatHelper:
   {"mp4a.40.2", "audio/mpeg, mpegversion=(int)4"},
   {"mp3", "audio/mpeg, mpegversion=(int)1"},
 };
 
 GStreamerFormatHelper::GStreamerFormatHelper()
   : mFactories(nullptr),
     mCookie(static_cast<uint32_t>(-1))
 {
+  if (!sLoadOK) {
+    return;
+  }
+
   mSupportedContainerCaps = gst_caps_new_empty();
   for (unsigned int i = 0; i < G_N_ELEMENTS(mContainers); i++) {
     const char* capsString = mContainers[i][1];
     GstCaps* caps = gst_caps_from_string(capsString);
     gst_caps_append(mSupportedContainerCaps, caps);
   }
 
   mSupportedCodecCaps = gst_caps_new_empty();
   for (unsigned int i = 0; i < G_N_ELEMENTS(mCodecs); i++) {
     const char* capsString = mCodecs[i][1];
     GstCaps* caps = gst_caps_from_string(capsString);
     gst_caps_append(mSupportedCodecCaps, caps);
   }
 }
 
 GStreamerFormatHelper::~GStreamerFormatHelper() {
+  if (!sLoadOK) {
+    return;
+  }
+
   gst_caps_unref(mSupportedContainerCaps);
   gst_caps_unref(mSupportedCodecCaps);
 
   if (mFactories)
     g_list_free(mFactories);
 }
 
 bool GStreamerFormatHelper::CanHandleMediaType(const nsACString& aMIMEType,
                                                const nsAString* aCodecs) {
+  if (!sLoadOK) {
+    return false;
+  }
+
   const char *type;
   NS_CStringGetData(aMIMEType, &type, NULL);
 
   GstCaps* caps = ConvertFormatsToCaps(type, aCodecs);
   if (!caps) {
     return false;
   }
 
   bool ret = HaveElementsToProcessCaps(caps);
   gst_caps_unref(caps);
 
   return ret;
 }
 
 GstCaps* GStreamerFormatHelper::ConvertFormatsToCaps(const char* aMIMEType,
                                                      const nsAString* aCodecs) {
+  NS_ASSERTION(sLoadOK, "GStreamer library not linked");
+
   unsigned int i;
 
   /* convert aMIMEType to gst container caps */
   const char* capsString = nullptr;
   for (i = 0; i < G_N_ELEMENTS(mContainers); i++) {
     if (!strcmp(ENTRY_FORMAT(mContainers[i]), aMIMEType)) {
       capsString = ENTRY_CAPS(mContainers[i]);
       break;
@@ -138,16 +159,17 @@ GstCaps* GStreamerFormatHelper::ConvertF
     /* appends and frees tmp */
     gst_caps_append(caps, tmp);
   }
 
   return caps;
 }
 
 bool GStreamerFormatHelper::HaveElementsToProcessCaps(GstCaps* aCaps) {
+  NS_ASSERTION(sLoadOK, "GStreamer library not linked");
 
   GList* factories = GetFactories();
 
   GList* list;
   /* here aCaps contains [containerCaps, [codecCaps1, [codecCaps2, ...]]] so process
    * caps structures individually as we want one element for _each_
    * structure */
   for (unsigned int i = 0; i < gst_caps_get_size(aCaps); i++) {
@@ -161,28 +183,36 @@ bool GStreamerFormatHelper::HaveElements
     g_list_free(list);
   }
 
   return true;
 }
 
 bool GStreamerFormatHelper::CanHandleContainerCaps(GstCaps* aCaps)
 {
+  NS_ASSERTION(sLoadOK, "GStreamer library not linked");
+
   return gst_caps_can_intersect(aCaps, mSupportedContainerCaps);
 }
 
 bool GStreamerFormatHelper::CanHandleCodecCaps(GstCaps* aCaps)
 {
+  NS_ASSERTION(sLoadOK, "GStreamer library not linked");
+
   return gst_caps_can_intersect(aCaps, mSupportedCodecCaps);
 }
 
 GList* GStreamerFormatHelper::GetFactories() {
+  NS_ASSERTION(sLoadOK, "GStreamer library not linked");
+
   uint32_t cookie = gst_default_registry_get_feature_list_cookie ();
   if (cookie != mCookie) {
     g_list_free(mFactories);
     mFactories = gst_element_factory_list_get_elements
         (GST_ELEMENT_FACTORY_TYPE_DEMUXER | GST_ELEMENT_FACTORY_TYPE_DECODER,
          GST_RANK_MARGINAL);
     mCookie = cookie;
   }
 
   return mFactories;
 }
+
+} // namespace mozilla
--- a/content/media/gstreamer/GStreamerFormatHelper.h
+++ b/content/media/gstreamer/GStreamerFormatHelper.h
@@ -6,16 +6,18 @@
 
 #if !defined(GStreamerFormatHelper_h_)
 #define GStreamerFormatHelper_h_
 
 #include <gst/gst.h>
 #include <mozilla/Types.h>
 #include "nsXPCOMStrings.h"
 
+namespace mozilla {
+
 class GStreamerFormatHelper {
   /* This class can be used to query the GStreamer registry for the required
    * demuxers/decoders from nsHTMLMediaElement::CanPlayType.
    * It implements looking at the GstRegistry to check if elements to
    * demux/decode the formats passed to CanPlayType() are actually installed.
    */
   public:
     static GStreamerFormatHelper* Instance();
@@ -40,16 +42,22 @@ class GStreamerFormatHelper {
     static GStreamerFormatHelper* gInstance;
 
     /* table to convert from container MIME types to GStreamer caps */
     static char const *const mContainers[6][2];
 
     /* table to convert from codec MIME types to GStreamer caps */
     static char const *const mCodecs[9][2];
 
+    /*
+     * True iff we were able to find the proper GStreamer libs and the functions
+     * we need.
+     */
+    static bool sLoadOK;
+
     /* whitelist of supported container/codec gst caps */
     GstCaps* mSupportedContainerCaps;
     GstCaps* mSupportedCodecCaps;
 
     /* list of GStreamer element factories
      * Element factories are the basic types retrieved from the GStreamer
      * registry, they describe all plugins and elements that GStreamer can
      * create.
@@ -59,9 +67,11 @@ class GStreamerFormatHelper {
     GList* mFactories;
 
     /* Storage for the default registrys feature list cookie.
      * It changes every time a feature is added to or removed from the
      * GStreamer registry. */
     uint32_t mCookie;
 };
 
+} //namespace mozilla
+
 #endif
new file mode 100644
--- /dev/null
+++ b/content/media/gstreamer/GStreamerFunctionList.h
@@ -0,0 +1,101 @@
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef __APPLE__
+
+/*
+ * List of symbol names we need to dlsym from the gstreamer library.
+ */
+GST_FUNC(LIBGSTAPP, gst_app_sink_get_type)
+GST_FUNC(LIBGSTAPP, gst_app_sink_pull_buffer)
+GST_FUNC(LIBGSTAPP, gst_app_sink_set_callbacks)
+GST_FUNC(LIBGSTAPP, gst_app_src_end_of_stream)
+GST_FUNC(LIBGSTAPP, gst_app_src_get_size)
+GST_FUNC(LIBGSTAPP, gst_app_src_get_type)
+GST_FUNC(LIBGSTAPP, gst_app_src_push_buffer)
+GST_FUNC(LIBGSTAPP, gst_app_src_set_callbacks)
+GST_FUNC(LIBGSTAPP, gst_app_src_set_size)
+GST_FUNC(LIBGSTAPP, gst_app_src_set_stream_type)
+GST_FUNC(LIBGSTREAMER, gst_bin_get_by_name)
+GST_FUNC(LIBGSTREAMER, gst_bin_get_type)
+GST_FUNC(LIBGSTREAMER, gst_bin_iterate_recurse)
+GST_FUNC(LIBGSTREAMER, gst_buffer_copy_metadata)
+GST_FUNC(LIBGSTREAMER, gst_buffer_get_qdata)
+GST_FUNC(LIBGSTREAMER, gst_buffer_get_type)
+GST_FUNC(LIBGSTREAMER, gst_buffer_new)
+GST_FUNC(LIBGSTREAMER, gst_buffer_new_and_alloc)
+GST_FUNC(LIBGSTREAMER, gst_buffer_set_qdata)
+GST_FUNC(LIBGSTREAMER, gst_bus_timed_pop_filtered)
+GST_FUNC(LIBGSTREAMER, gst_caps_append)
+GST_FUNC(LIBGSTREAMER, gst_caps_can_intersect)
+GST_FUNC(LIBGSTREAMER, gst_caps_from_string)
+GST_FUNC(LIBGSTREAMER, gst_caps_get_size)
+GST_FUNC(LIBGSTREAMER, gst_caps_get_structure)
+GST_FUNC(LIBGSTREAMER, gst_caps_new_any)
+GST_FUNC(LIBGSTREAMER, gst_caps_new_empty)
+GST_FUNC(LIBGSTREAMER, gst_caps_new_full)
+GST_FUNC(LIBGSTREAMER, gst_caps_new_simple)
+GST_FUNC(LIBGSTREAMER, gst_caps_unref)
+GST_FUNC(LIBGSTREAMER, gst_element_factory_get_klass)
+GST_FUNC(LIBGSTREAMER, gst_element_factory_list_filter)
+GST_FUNC(LIBGSTREAMER, gst_element_factory_list_get_elements)
+GST_FUNC(LIBGSTREAMER, gst_element_factory_make)
+GST_FUNC(LIBGSTREAMER, gst_element_get_factory)
+GST_FUNC(LIBGSTREAMER, gst_element_get_pad)
+GST_FUNC(LIBGSTREAMER, gst_element_get_type)
+GST_FUNC(LIBGSTREAMER, gst_element_query_convert)
+GST_FUNC(LIBGSTREAMER, gst_element_query_duration)
+GST_FUNC(LIBGSTREAMER, gst_element_seek_simple)
+GST_FUNC(LIBGSTREAMER, gst_element_set_state)
+GST_FUNC(LIBGSTREAMER, gst_event_parse_new_segment)
+GST_FUNC(LIBGSTREAMER, gst_flow_get_name)
+GST_FUNC(LIBGSTREAMER, gst_init)
+GST_FUNC(LIBGSTREAMER, gst_init_check)
+GST_FUNC(LIBGSTREAMER, gst_iterator_next)
+GST_FUNC(LIBGSTREAMER, gst_message_parse_error)
+GST_FUNC(LIBGSTREAMER, gst_mini_object_get_type)
+GST_FUNC(LIBGSTREAMER, gst_mini_object_new)
+GST_FUNC(LIBGSTREAMER, gst_mini_object_ref)
+GST_FUNC(LIBGSTREAMER, gst_mini_object_unref)
+GST_FUNC(LIBGSTREAMER, gst_object_get_parent)
+GST_FUNC(LIBGSTREAMER, gst_object_unref)
+GST_FUNC(LIBGSTREAMER, gst_pad_add_event_probe)
+GST_FUNC(LIBGSTREAMER, gst_pad_alloc_buffer)
+GST_FUNC(LIBGSTREAMER, gst_pad_get_element_private)
+GST_FUNC(LIBGSTREAMER, gst_pad_get_negotiated_caps)
+GST_FUNC(LIBGSTREAMER, gst_pad_set_bufferalloc_function)
+GST_FUNC(LIBGSTREAMER, gst_pad_set_element_private)
+GST_FUNC(LIBGSTREAMER, gst_parse_bin_from_description)
+GST_FUNC(LIBGSTREAMER, gst_pipeline_get_bus)
+GST_FUNC(LIBGSTREAMER, gst_pipeline_get_type)
+GST_FUNC(LIBGSTREAMER, gst_registry_get_default)
+GST_FUNC(LIBGSTREAMER, gst_registry_get_feature_list_cookie)
+GST_FUNC(LIBGSTREAMER, gst_segment_init)
+GST_FUNC(LIBGSTREAMER, gst_segment_set_newsegment)
+GST_FUNC(LIBGSTREAMER, gst_segment_to_stream_time)
+GST_FUNC(LIBGSTREAMER, gst_structure_copy)
+GST_FUNC(LIBGSTREAMER, gst_structure_get_fraction)
+GST_FUNC(LIBGSTREAMER, gst_structure_get_int)
+GST_FUNC(LIBGSTREAMER, gst_structure_get_value)
+GST_FUNC(LIBGSTREAMER, gst_structure_new)
+GST_FUNC(LIBGSTREAMER, gst_structure_take_value)
+GST_FUNC(LIBGSTREAMER, gst_util_uint64_scale)
+GST_FUNC(LIBGSTVIDEO, gst_video_format_get_component_height)
+GST_FUNC(LIBGSTVIDEO, gst_video_format_get_component_offset)
+GST_FUNC(LIBGSTVIDEO, gst_video_format_get_component_width)
+GST_FUNC(LIBGSTVIDEO, gst_video_format_get_row_stride)
+GST_FUNC(LIBGSTVIDEO, gst_video_format_parse_caps)
+
+/*
+ * Functions that have been defined in the header file. We replace them so that
+ * they don't try to use the global gstreamer functions.
+ */
+#ifdef REPLACE_FUNC
+REPLACE_FUNC(gst_buffer_ref);
+REPLACE_FUNC(gst_buffer_unref);
+REPLACE_FUNC(gst_message_unref);
+#endif
+
+#endif // !defined(__APPLE__)
new file mode 100644
--- /dev/null
+++ b/content/media/gstreamer/GStreamerLoader.cpp
@@ -0,0 +1,116 @@
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <dlfcn.h>
+#include <stdio.h>
+
+#include "GStreamerLoader.h"
+
+#define LIBGSTREAMER 0
+#define LIBGSTAPP 1
+#define LIBGSTVIDEO 2
+
+namespace mozilla {
+
+/*
+ * Declare our function pointers using the types from the global gstreamer
+ * definitions.
+ */
+#define GST_FUNC(_, func) typeof(::func)* func;
+#define REPLACE_FUNC(func) GST_FUNC(-1, func)
+#include "GStreamerFunctionList.h"
+#undef GST_FUNC
+#undef REPLACE_FUNC
+
+/*
+ * Redefinitions of functions that have been defined in the gstreamer headers to
+ * stop them calling the gstreamer functions in global scope.
+ */
+GstBuffer * gst_buffer_ref_impl(GstBuffer *buf);
+void gst_buffer_unref_impl(GstBuffer *buf);
+void gst_message_unref_impl(GstMessage *msg);
+
+bool
+load_gstreamer()
+{
+#ifdef __APPLE__
+  return true;
+#endif
+  static bool loaded = false;
+
+  if (loaded) {
+    return true;
+  }
+
+  void *gstreamerLib = nullptr;
+  guint major = 0;
+  guint minor = 0;
+  guint micro, nano;
+
+  typedef typeof(::gst_version) VersionFuncType;
+  if (VersionFuncType *versionFunc = (VersionFuncType*)dlsym(RTLD_DEFAULT, "gst_version")) {
+    versionFunc(&major, &minor, &micro, &nano);
+  }
+
+  if (major == GST_VERSION_MAJOR && minor == GST_VERSION_MINOR) {
+    gstreamerLib = RTLD_DEFAULT;
+  } else {
+    gstreamerLib = dlopen("libgstreamer-0.10.so.0", RTLD_NOW | RTLD_LOCAL);
+  }
+
+  void *handles[] = {
+    gstreamerLib,
+    dlopen("libgstapp-0.10.so.0", RTLD_NOW | RTLD_LOCAL),
+    dlopen("libgstvideo-0.10.so.0", RTLD_NOW | RTLD_LOCAL)
+  };
+
+  for (size_t i = 0; i < sizeof(handles) / sizeof(handles[0]); i++) {
+    if (!handles[i]) {
+      goto fail;
+    }
+  }
+
+#define GST_FUNC(lib, symbol) \
+  if (!(symbol = (typeof(symbol))dlsym(handles[lib], #symbol))) { \
+    goto fail; \
+  }
+#define REPLACE_FUNC(symbol) symbol = symbol##_impl;
+#include "GStreamerFunctionList.h"
+#undef GST_FUNC
+#undef REPLACE_FUNC
+
+  loaded = true;
+  return true;
+
+fail:
+
+  for (size_t i = 0; i < sizeof(handles) / sizeof(handles[0]); i++) {
+    if (handles[i] && handles[i] != RTLD_DEFAULT) {
+      dlclose(handles[i]);
+    }
+  }
+
+  return false;
+}
+
+GstBuffer *
+gst_buffer_ref_impl(GstBuffer *buf)
+{
+  return (GstBuffer *)gst_mini_object_ref(GST_MINI_OBJECT_CAST(buf));
+}
+
+void
+gst_buffer_unref_impl(GstBuffer *buf)
+{
+  gst_mini_object_unref(GST_MINI_OBJECT_CAST(buf));
+}
+
+void
+gst_message_unref_impl(GstMessage *msg)
+{
+  gst_mini_object_unref(GST_MINI_OBJECT_CAST(msg));
+}
+
+}
new file mode 100644
--- /dev/null
+++ b/content/media/gstreamer/GStreamerLoader.h
@@ -0,0 +1,37 @@
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GStreamerLoader_h_
+#define GStreamerLoader_h_
+
+#include <gst/gst.h>
+#include <gst/gstbuffer.h>
+#include <gst/gstelementfactory.h>
+#include <gst/gststructure.h>
+#include <gst/app/gstappsrc.h>
+#include <gst/app/gstappsink.h>
+#include <gst/video/video.h>
+
+namespace mozilla {
+
+/*
+ * dlopens the required libraries and dlsyms the functions we need.
+ * Returns true on success, false otherwise.
+ */
+bool load_gstreamer();
+
+/*
+ * Declare our extern function pointers using the types from the global
+ * gstreamer definitions.
+ */
+#define GST_FUNC(_, func) extern typeof(::func)* func;
+#define REPLACE_FUNC(func) GST_FUNC(-1, func)
+#include "GStreamerFunctionList.h"
+#undef GST_FUNC
+#undef REPLACE_FUNC
+
+}
+
+#endif // GStreamerLoader_h_
--- a/content/media/gstreamer/GStreamerMozVideoBuffer.h
+++ b/content/media/gstreamer/GStreamerMozVideoBuffer.h
@@ -1,16 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef __GST_MOZ_VIDEO_BUFFER_H__
 #define __GST_MOZ_VIDEO_BUFFER_H__
 
 #include <gst/gst.h>
+#include "GStreamerLoader.h"
 #include "MediaDecoderReader.h"
 
 namespace mozilla {
 
 #define GST_TYPE_MOZ_VIDEO_BUFFER_DATA            (gst_moz_video_buffer_data_get_type())
 #define GST_IS_MOZ_VIDEO_BUFFER_DATA(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MOZ_VIDEO_BUFFER_DATA))
 
 #define GST_TYPE_MOZ_VIDEO_BUFFER            (gst_moz_video_buffer_get_type())
--- a/content/media/gstreamer/GStreamerReader.cpp
+++ b/content/media/gstreamer/GStreamerReader.cpp
@@ -9,16 +9,17 @@
 #include "AbstractMediaDecoder.h"
 #include "MediaResource.h"
 #include "GStreamerReader.h"
 #include "GStreamerFormatHelper.h"
 #include "GStreamerMozVideoBuffer.h"
 #include "VideoUtils.h"
 #include "mozilla/dom/TimeRanges.h"
 #include "mozilla/Preferences.h"
+#include "GStreamerLoader.h"
 
 namespace mozilla {
 
 using namespace layers;
 
 // Un-comment to enable logging of seek bisections.
 //#define SEEK_LOGGING
 
@@ -29,17 +30,17 @@ extern PRLogModuleInfo* gMediaDecoderLog
 #define LOG(type, msg)
 #endif
 
 extern bool
 IsYV12Format(const VideoData::YCbCrBuffer::Plane& aYPlane,
              const VideoData::YCbCrBuffer::Plane& aCbPlane,
              const VideoData::YCbCrBuffer::Plane& aCrPlane);
 
-static const int MAX_CHANNELS = 4;
+static const unsigned int MAX_CHANNELS = 4;
 // Let the demuxer work in pull mode for short files
 static const int SHORT_FILE_SIZE = 1024 * 1024;
 // The default resource->Read() size when working in push mode
 static const int DEFAULT_SOURCE_READ_SIZE = 50 * 1024;
 
 typedef enum {
   GST_PLAY_FLAG_VIDEO         = (1 << 0),
   GST_PLAY_FLAG_AUDIO         = (1 << 1),
--- a/content/media/gstreamer/moz.build
+++ b/content/media/gstreamer/moz.build
@@ -4,18 +4,20 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 MODULE = 'content'
 
 EXPORTS += [
     'GStreamerDecoder.h',
     'GStreamerFormatHelper.h',
+    'GStreamerLoader.h',
     'GStreamerReader.h',
 ]
 
 CPP_SOURCES += [
     'GStreamerDecoder.cpp',
     'GStreamerFormatHelper.cpp',
     'GStreamerReader.cpp',
     'GStreamerMozVideoBuffer.cpp',
+    'GStreamerLoader.cpp',
 ]
 
--- a/layout/build/Makefile.in
+++ b/layout/build/Makefile.in
@@ -244,19 +244,21 @@ SHARED_LIBRARY_LIBS += \
 
 ifdef ENABLE_EDITOR_API_LOG
 DEFINES += -DENABLE_EDITOR_API_LOG
 endif
 
 SHARED_LIBRARY_LIBS += \
 	$(DEPTH)/js/xpconnect/src/$(LIB_PREFIX)xpconnect_s.$(LIB_SUFFIX)
 
+ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 ifdef MOZ_GSTREAMER
 EXTRA_DSO_LDOPTS += $(GSTREAMER_LIBS)
 endif
+endif
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES	+= -I$(srcdir)/../base \
 		   -I$(srcdir)/../generic \
--- a/toolkit/library/Makefile.in
+++ b/toolkit/library/Makefile.in
@@ -630,19 +630,21 @@ endif # WINNT
 ifdef MOZ_JPROF
 EXTRA_DSO_LDOPTS += -ljprof
 endif
 
 ifdef MOZ_ENABLE_QT
 EXTRA_DSO_LDOPTS += $(MOZ_QT_LDFLAGS) $(XEXT_LIBS)
 endif
 
+ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 ifdef MOZ_GSTREAMER
 EXTRA_DSO_LDOPTS += $(GSTREAMER_LIBS)
 endif
+endif
 
 # Generate GDB pretty printer-autoload files only on Linux. OSX's GDB is
 # too old to support Python pretty-printers; if this changes, we could make
 # this 'ifdef GNU_CC'.
 ifeq (Linux,$(OS_ARCH))
 # Create a GDB Python auto-load file alongside the libxul shared library in
 # the build directory.
 PP_TARGETS += LIBXUL_AUTOLOAD