mozillasink.cpp
Go to the documentation of this file.
1 /* GStreamer
2  * Copyright (C) <2010> Pioneers of the Inevitable <songbird@songbirdnest.com>
3  *
4  * Authors: Steve Lloyd <slloyd@songbirdnest.com>
5  * Michael Smith <msmith@songbirdnest.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Library General Public License for more
16  */
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20 
21 /* Must be before any other mozilla headers */
22 #include "mozilla-config.h"
23 
24 #include <gst/gst.h>
25 #include <gst/base/gstbasesink.h>
26 
27 #include <nsComponentManagerUtils.h>
28 #include <nsServiceManagerUtils.h>
29 #include <nsCOMPtr.h>
30 #include <nsIOutputStream.h>
31 #include <nsIProxyObjectManager.h>
32 
33 #include "mozillaplugin.h"
34 
37 
39  GstBaseSink parent;
40 
41  /* The Mozilla output stream, whose methods will always be called on the main
42  * thread using a proxy */
43  nsCOMPtr<nsIOutputStream> output_stream;
44  nsCOMPtr<nsIOutputStream> proxied_output_stream;
45 
46  /* If true, the stream is seekable.
47  * TODO: Implement ability to seek. Right now this is just set to false. */
48  gboolean is_seekable;
49 };
50 
52  GstBaseSinkClass parent_class;
53 };
54 
55 GST_DEBUG_CATEGORY_STATIC (mozilla_sink_debug);
56 #define GST_CAT_DEFAULT mozilla_sink_debug
57 
58 static const GstElementDetails gst_mozilla_sink_details =
59 GST_ELEMENT_DETAILS ((gchar *)"Mozilla nsIOutputStream sink",
60  (gchar *)"Sink",
61  (gchar *)"Write data to a hosting mozilla "
62  "application's output stream API",
63  (gchar *)"Pioneers of the Inevitable <songbird@songbirdnest.com");
64 
65 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
66  GST_PAD_SINK,
67  GST_PAD_ALWAYS,
68  GST_STATIC_CAPS_ANY);
69 
70 enum
71 {
74 };
75 
76 static void gst_mozilla_sink_set_property (GObject * object, guint prop_id,
77  const GValue * value, GParamSpec * pspec);
78 static void gst_mozilla_sink_get_property (GObject * object, guint prop_id,
79  GValue * value, GParamSpec * pspec);
80 
81 static GstFlowReturn gst_mozilla_sink_render (GstBaseSink * bsink,
82  GstBuffer * buf);
83 static gboolean gst_mozilla_sink_start (GstBaseSink * bsink);
84 static gboolean gst_mozilla_sink_stop (GstBaseSink * bsink);
85 static gboolean gst_mozilla_sink_event (GstBaseSink * bsink, GstEvent * event);
86 
89 
90 GST_BOILERPLATE (GstMozillaSink, gst_mozilla_sink, GstBaseSink,
91  GST_TYPE_BASE_SINK);
92 
93 static void
94 gst_mozilla_sink_base_init (gpointer g_class)
95 {
96  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
97 
98  gst_element_class_add_pad_template (element_class,
99  gst_static_pad_template_get (&sink_template));
100 
101  gst_element_class_set_details (element_class, &gst_mozilla_sink_details);
102 }
103 
104 static void
106 {
107  GObjectClass *gobject_class;
108  GstBaseSinkClass *gstbasesink_class;
109 
110  gobject_class = (GObjectClass *) klass;
111  gstbasesink_class = (GstBaseSinkClass *) klass;
112 
113  gobject_class->set_property = gst_mozilla_sink_set_property;
114  gobject_class->get_property = gst_mozilla_sink_get_property;
115 
116  g_object_class_install_property
117  (gobject_class, PROP_STREAM,
118  g_param_spec_pointer ("stream", "Stream",
119  "Mozilla output stream", (GParamFlags) G_PARAM_READWRITE));
120 
121  gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_mozilla_sink_render);
122  gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_mozilla_sink_start);
123  gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_mozilla_sink_stop);
124  gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_mozilla_sink_event);
125 
126  GST_DEBUG_CATEGORY_INIT (mozilla_sink_debug, "mozillasink", 0,
127  "Mozilla Sink");
128 }
129 
130 
131 static void
133 {
134  sink->output_stream = nsnull;
135  sink->proxied_output_stream = nsnull;
136 
137  sink->is_seekable = FALSE;
138 
139  /* Don't sync to clock by default */
140  gst_base_sink_set_sync (GST_BASE_SINK (sink), FALSE);
141 }
142 
143 static void
144 gst_mozilla_sink_set_property (GObject * object, guint prop_id,
145  const GValue * value, GParamSpec * pspec)
146 {
147  GstMozillaSink *sink = GST_MOZILLA_SINK (object);
148 
149  switch (prop_id) {
150  case PROP_STREAM:
151  {
152  nsresult rv;
153 
154  nsCOMPtr<nsIProxyObjectManager> proxyObjectManager =
155  do_GetService("@mozilla.org/xpcomproxy;1", &rv);
156  if (NS_FAILED (rv)) {
157  GST_WARNING_OBJECT (sink, "Failed to get Mozilla proxy object manager");
158  return;
159  }
160 
161  sink->output_stream =
162  do_QueryInterface((nsIOutputStream *) g_value_get_pointer(value));
163  if (!sink->output_stream) {
164  GST_WARNING_OBJECT (sink, "Failed to set output stream");
165  return;
166  }
167 
168  /* Get main thread proxy for the output stream. All output stream methods
169  * will be called using the proxy. */
170  rv = proxyObjectManager->GetProxyForObject(
171  NS_PROXY_TO_MAIN_THREAD,
172  NS_GET_IID (nsIOutputStream),
173  sink->output_stream,
174  NS_PROXY_SYNC | NS_PROXY_ALWAYS,
175  getter_AddRefs(sink->proxied_output_stream));
176  if (NS_FAILED (rv)) {
177  GST_WARNING_OBJECT (sink, "Failed to get proxy for output stream");
178  return;
179  }
180 
181  break;
182  }
183  default:
184  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
185  break;
186  }
187 }
188 
189 static void
190 gst_mozilla_sink_get_property (GObject * object, guint prop_id,
191  GValue * value, GParamSpec * pspec)
192 {
193  GstMozillaSink *sink = GST_MOZILLA_SINK (object);
194 
195  switch (prop_id) {
196  case PROP_STREAM:
197  {
198  nsIOutputStream* rawStreamPtr = sink->output_stream.get();
199  NS_IF_ADDREF (rawStreamPtr);
200  g_value_set_pointer (value, rawStreamPtr);
201  break;
202  }
203  default:
204  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
205  break;
206  }
207 }
208 
209 static GstFlowReturn
210 gst_mozilla_sink_render (GstBaseSink * bsink, GstBuffer * buf)
211 {
212  GstMozillaSink *sink = GST_MOZILLA_SINK (bsink);
213  nsresult rv;
214 
215  if (!sink->proxied_output_stream) {
216  GST_WARNING_OBJECT (sink, "Tried to render without a proxied stream");
217  return GST_FLOW_UNEXPECTED;
218  }
219 
220  PRUint32 bytesWritten;
221  PRUint32 offset = 0;
222  PRUint32 count = GST_BUFFER_SIZE (buf);
223  char * data = (char *) GST_BUFFER_DATA (buf);
224  GST_DEBUG_OBJECT (sink, "Writing %u byte buffer", count);
225 
226  while (offset < count) {
227  rv = sink->proxied_output_stream->Write(data + offset, count - offset,
228  &bytesWritten);
229  if (NS_FAILED (rv)) {
230  GST_WARNING_OBJECT (sink, "Failed to write buffer to output stream");
231  return GST_FLOW_UNEXPECTED;
232  }
233 
234  GST_DEBUG_OBJECT (sink, "Wrote %u bytes to output stream", bytesWritten);
235  offset += bytesWritten;
236  }
237 
238  return GST_FLOW_OK;
239 }
240 
241 static gboolean
242 gst_mozilla_sink_start (GstBaseSink * bsink)
243 {
244  GstMozillaSink *sink = GST_MOZILLA_SINK (bsink);
245 
246  if (!sink->output_stream || !sink->proxied_output_stream) {
247  GST_WARNING_OBJECT (sink, "Tried to start with invalid output stream");
248  return FALSE;
249  }
250 
251  return TRUE;
252 }
253 
254 static gboolean
255 gst_mozilla_sink_stop (GstBaseSink * bsink)
256 {
257  GstMozillaSink *sink = GST_MOZILLA_SINK (bsink);
258 
260 
261  return TRUE;
262 }
263 
264 static gboolean
265 gst_mozilla_sink_event (GstBaseSink * bsink, GstEvent * event)
266 {
267  GstEventType type;
268  GstMozillaSink *sink = GST_MOZILLA_SINK (bsink);
269 
270  type = GST_EVENT_TYPE (event);
271 
272  switch (type) {
273  case GST_EVENT_EOS:
274  {
275  GST_DEBUG_OBJECT (sink, "Handling EOS event");
277  break;
278  }
279  case GST_EVENT_FLUSH_STOP:
280  {
281  GST_DEBUG_OBJECT (sink, "Handling flush start event");
283  break;
284  }
285  default:
286  break;
287  }
288 
289  return TRUE;
290 }
291 
292 static void
294 {
295  GST_DEBUG_OBJECT (sink, "Closing output stream");
296  nsresult rv;
297 
298  rv = sink->proxied_output_stream->Close();
299  if (NS_FAILED (rv)) {
300  GST_WARNING_OBJECT (sink, "Failed to close output stream");
301  }
302 }
303 
304 static void
306 {
307  GST_DEBUG_OBJECT (sink, "Flushing output stream");
308 
309  nsresult rv = sink->proxied_output_stream->Flush();
310  if (NS_FAILED (rv)) {
311  GST_WARNING_OBJECT (sink, "Failed to flush output stream");
312  }
313 }
static const GstElementDetails gst_mozilla_sink_details
Definition: mozillasink.cpp:58
nsCOMPtr< nsIOutputStream > proxied_output_stream
Definition: mozillasink.cpp:44
var event
GstBaseSink parent
Definition: mozillasink.cpp:39
static void gst_mozilla_sink_class_init(GstMozillaSinkClass *klass)
static gboolean gst_mozilla_sink_stop(GstBaseSink *bsink)
static void gst_mozilla_sink_base_init(gpointer g_class)
Definition: mozillasink.cpp:94
PRUint32 & offset
nsCOMPtr< nsIOutputStream > output_stream
Definition: mozillasink.cpp:43
var count
Definition: test_bug7406.js:32
static gboolean gst_mozilla_sink_start(GstBaseSink *bsink)
#define GST_MOZILLA_SINK(obj)
Definition: mozillaplugin.h:45
static void gst_mozilla_sink_flush_stream(GstMozillaSink *sink)
GstBaseSinkClass parent_class
Definition: mozillasink.cpp:52
static GstFlowReturn gst_mozilla_sink_render(GstBaseSink *bsink, GstBuffer *buf)
countRef value
Definition: FeedWriter.js:1423
GST_BOILERPLATE(GstMozillaSink, gst_mozilla_sink, GstBaseSink, GST_TYPE_BASE_SINK)
GST_DEBUG_CATEGORY_STATIC(mozilla_sink_debug)
static void gst_mozilla_sink_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
static void gst_mozilla_sink_close_stream(GstMozillaSink *sink)
static void gst_mozilla_sink_init(GstMozillaSink *sink, GstMozillaSinkClass *g_class)
static void gst_mozilla_sink_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
static GstStaticPadTemplate sink_template
Definition: mozillasink.cpp:65
observe data
Definition: FeedWriter.js:1329
static gboolean gst_mozilla_sink_event(GstBaseSink *bsink, GstEvent *event)
gboolean is_seekable
Definition: mozillasink.cpp:48