sbGStreamerMediaContainer.cpp
Go to the documentation of this file.
1 /*
2  *
3  *=BEGIN SONGBIRD LICENSE
4  *
5  * Copyright(c) 2005-2011 POTI, Inc.
6  * http://www.songbirdnest.com
7  *
8  * For information about the licensing and copyright of this Add-On please
9  * contact POTI, Inc. at customer@songbirdnest.com.
10  *
11  *=END SONGBIRD LICENSE
12  *
13  */
14 
17 #include "sbIGStreamerService.h"
19 
20 #include "nsThreadUtils.h"
21 
22 
23 
25 
26 
27 
28 NS_IMETHODIMP
29 sbGStreamerMediaContainer::GetMimeType(nsACString & aMimeType)
30 {
31  nsresult rv;
32 
33  // If no caps, then the MIME type is not yet acquired.
34  if (!mCaps) {
35  rv = AcquireMimeType_Priv();
36  NS_ENSURE_SUCCESS(rv, rv);
37  }
38 
39  NS_ENSURE_TRUE(!mMimeType.IsEmpty(), NS_ERROR_NOT_AVAILABLE);
40  aMimeType.Assign(mMimeType);
41 
42  return NS_OK;
43 }
44 
45 
46 
47 NS_IMETHODIMP
48 sbGStreamerMediaContainer::GetPath(nsACString & aPath)
49 {
50  aPath.Assign(mPath);
51  return NS_OK;
52 }
53 
54 
55 
56 NS_IMETHODIMP
57 sbGStreamerMediaContainer::SetPath(const nsACString & aPath)
58 {
59  // Do nothing if the path is the same:
60  if (mPath.Equals(aPath)) {
61  return NS_OK;
62  }
63 
64  // Clear the MIME type of the old file:
65  mMimeType.Truncate();
66 
67  // Clear any caps of the old file:
68  if (mCaps) {
69  gst_caps_unref(mCaps);
70  mCaps = NULL;
71  }
72 
73  // Set the new path:
74  mPath.Assign(aPath);
75 
76  return NS_OK;
77 }
78 
79 
80 
82 {
83  // Dispose of any caps:
84  if (mCaps)
85  {
86  gst_caps_unref(mCaps);
87  mCaps = NULL;
88  }
89 
90  // Dispose of the pipeline. This unrefs all the pipeline elements:
91  if (mPipeline) {
92  gst_object_unref (mPipeline);
93  mPipeline = NULL;
94  mFilesrc = NULL;
95  mTypefind = NULL;
96  mSink = NULL;
97  }
98 
99  // Dispose of the main loop:
100  if (mLoop) {
101  g_main_loop_unref (mLoop);
102  mLoop = NULL;
103  }
104 }
105 
106 
107 
109  mLoop(NULL),
110  mPipeline(NULL),
111  mFilesrc(NULL),
112  mTypefind(NULL),
113  mSink(NULL),
114  mCaps(NULL)
115 {
116 }
117 
118 
119 
120 nsresult
122 {
123  // Initialize GStreamer. Adapted from sbGStreamerPipeline.cpp
124  // http://src.songbirdnest.com/xref/trunk/components/mediacore/gstreamer/src/sbGStreamerPipeline.cpp#87
125 
126  // We need to make sure the gstreamer service component has been loaded
127  // since it calls gst_init for us.
128  nsresult rv;
129  nsCOMPtr<sbIGStreamerService> gstreamer;
130  if (!NS_IsMainThread()) {
132  }
133  else {
134  gstreamer = do_GetService(SBGSTREAMERSERVICE_CONTRACTID, &rv);
135  }
136  NS_ENSURE_SUCCESS(rv, rv);
137  (void)gstreamer;
138 
139  // Create the loop in which the typefind pipeline will run:
140  mLoop = g_main_loop_new (NULL, FALSE);
141  NS_ENSURE_TRUE(mLoop, NS_ERROR_FAILURE);
142 
143  /* create a new pipeline to hold the elements */
144  mPipeline = GST_PIPELINE (gst_pipeline_new ("pipe"));
145  NS_ENSURE_TRUE(mPipeline, NS_ERROR_FAILURE);
146 
147  /* create file source and typefind element */
148  mFilesrc = gst_element_factory_make ("filesrc", "source");
149  NS_ENSURE_TRUE(mFilesrc, NS_ERROR_FAILURE);
150 
151  mTypefind = gst_element_factory_make ("typefind", "decoder");
152  NS_ENSURE_TRUE(mTypefind, NS_ERROR_FAILURE);
153 
154  mSink = gst_element_factory_make ("fakesink", "sink");
155  NS_ENSURE_TRUE(mSink, NS_ERROR_FAILURE);
156 
157  g_signal_connect (mTypefind, "have-type", G_CALLBACK(OnHaveType_Priv), this);
158 
159  /* setup */
160  gst_bin_add_many (
161  GST_BIN (mPipeline),
162  mFilesrc,
163  mTypefind,
164  mSink,
165  NULL);
166  gst_element_link_many (
167  mFilesrc,
168  mTypefind,
169  mSink,
170  NULL);
171 
172  return NS_OK;
173 }
174 
175 
176 
177 nsresult
178 sbGStreamerMediaContainer::AcquireMimeType_Priv()
179 {
180  NS_ENSURE_TRUE(!mPath.IsEmpty(), NS_ERROR_NOT_INITIALIZED);
181 
182  if (mCaps) {
183  // Already acquired
184  return NS_OK;
185  }
186 
187  // Set the bus message callback:
188  NS_ENSURE_STATE(mPipeline);
189  GstBus * bus = gst_pipeline_get_bus (GST_PIPELINE (mPipeline));
190  gst_bus_add_watch_full (
191  bus,
192  G_PRIORITY_DEFAULT,
193  OnBusMessage_Priv,
194  this,
195  OnPrerollDone_Priv);
196 
197  // Set the filesrc target:
198  NS_ENSURE_STATE(mFilesrc);
199  g_object_set (G_OBJECT (mFilesrc), "location", mPath.get(), NULL);
200 
201  // Preroll the pipeline:
202  NS_ENSURE_STATE(mLoop);
203  gst_element_set_state (GST_ELEMENT (mPipeline), GST_STATE_PAUSED);
204  g_main_loop_run (mLoop);
205 
206  // Get the MIME type if typefind got caps:
207  if (mCaps) {
208  nsresult rv = GetMimeTypeForCaps(mCaps, mMimeType);
209  NS_ENSURE_SUCCESS(rv,rv);
210  }
211 
212  // Set the bus message callback for pipeline shutdown:
213  gst_bus_add_watch_full (
214  bus,
215  G_PRIORITY_DEFAULT,
216  OnBusMessage_Priv,
217  this,
218  OnPrerollDone_Priv);
219  gst_object_unref (bus);
220 
221  // Shut down the pipeline:
222  GstStateChangeReturn mode =
223  gst_element_set_state (GST_ELEMENT (mPipeline), GST_STATE_NULL);
224  if (mode == GST_STATE_CHANGE_ASYNC) {
225  g_main_loop_run (mLoop);
226  }
227 
228  // Return the proper result:
229  NS_ENSURE_TRUE(!mMimeType.IsEmpty(), NS_ERROR_NOT_AVAILABLE);
230 
231  return NS_OK;
232 }
233 
234 
235 
236 void
237 sbGStreamerMediaContainer::OnHaveType_Priv (
238  GstElement * typefind,
239  guint probability,
240  GstCaps * caps,
241  gpointer user_data)
242 {
243  NS_ENSURE_TRUE(user_data,);
245  static_cast<sbGStreamerMediaContainer *>(user_data);
246 
247  // Save the found caps:
248  self->mCaps = gst_caps_ref(caps);
249 }
250 
251 
252 
253 gboolean
254 sbGStreamerMediaContainer::OnBusMessage_Priv (
255  GstBus * bus,
256  GstMessage * message,
257  gpointer data)
258 {
259  NS_ENSURE_TRUE(data, FALSE);
261  static_cast<sbGStreamerMediaContainer *>(data);
262 
263  switch (GST_MESSAGE_TYPE (message))
264  {
265  case GST_MESSAGE_STATE_CHANGED:
266  {
267  GstState from;
268  GstState to;
269  GstState goal;
270  gst_message_parse_state_changed (message, &from, &to, &goal);
271 
272  GstObject * who = GST_MESSAGE_SRC (message);
273  if (who == GST_OBJECT (self->mPipeline))
274  {
275  gboolean done = (goal == GST_STATE_VOID_PENDING || to == GST_STATE_NULL);
276  return !done;
277  }
278  }
279  break;
280 
281  case GST_MESSAGE_ERROR:
282  {
283  GError * err;
284  gchar * debug;
285 
286  gst_message_parse_error(message, &err, &debug);
287 
288  g_error_free (err);
289  g_free (debug);
290 
291  return FALSE;
292  }
293  break;
294 
295  case GST_MESSAGE_EOS:
296  {
297  return FALSE;
298  }
299  break;
300 
301  default:
302  /* unhandled message */
303  break;
304  }
305 
306 
307  return TRUE;
308 }
309 
310 
311 gboolean
312 sbGStreamerMediaContainer::OnMainLoopDone_Priv (
313  gpointer user_data)
314 {
315  NS_ENSURE_TRUE(user_data, FALSE);
317  static_cast<sbGStreamerMediaContainer *>(user_data);
318  g_main_loop_quit (self->mLoop);
319  return FALSE;
320 }
321 
322 
323 
324 void
325 sbGStreamerMediaContainer::OnPrerollDone_Priv (
326  gpointer user_data)
327 {
328  g_idle_add (OnMainLoopDone_Priv, user_data);
329 }
330 
331 
332 
335 {
336  static sbGStreamerMediaContainer ssbGStreamerMediaContainer;
337 
338  return ssbGStreamerMediaContainer;
339 }
return NS_OK
_updateCookies aPath
#define SBGSTREAMERSERVICE_CONTRACTID
const sbCreateProxiedComponent do_ProxiedGetService(const nsCID &aCID, nsresult *error=0)
unique done
NS_DECL_ISUPPORTS NS_DECL_SBIMEDIACONTAINER ~sbGStreamerMediaContainer()
GstMessage * message
function debug(aMsg)
nsresult GetMimeTypeForCaps(GstCaps *aCaps, nsACString &aMimeType)
sbGStreamerMediaContainer & GetsbGStreamerMediaContainer()
var self
observe data
Definition: FeedWriter.js:1329
NS_IMPL_ISUPPORTS1(sbGStreamerMediaContainer, sbIMediaContainer)