root/trunk/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp

Revision 36123, 9.2 KB (checked in by alp@webkit.org, 3 months ago)

2008-09-05 Gustavo Noronha Silva <gns@gnome.org>

Reviewed by Alp Toker.

https://bugs.webkit.org/show_bug.cgi?id=18346
[GTK] Remove build warnings

Applied some casts, and removed an unused typedef to make the
compiler happy, printing less warnings when building.

  • Property svn:eol-style set to native
Line 
1/*
2 *  Copyright (C) 2007 OpenedHand
3 *  Copyright (C) 2007 Alp Toker <alp@atoker.com>
4 *
5 *  This library is free software; you can redistribute it and/or
6 *  modify it under the terms of the GNU Lesser General Public
7 *  License as published by the Free Software Foundation; either
8 *  version 2 of the License, or (at your option) any later version.
9 *
10 *  This library is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 *  Lesser General Public License for more details.
14 *
15 *  You should have received a copy of the GNU Lesser General Public
16 *  License along with this library; if not, write to the Free Software
17 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20/**
21 * SECTION:webkit-video-sink
22 * @short_description: GStreamer video sink
23 *
24 * #WebKitVideoSink is a GStreamer sink element that sends
25 * data to a #cairo_surface_t.
26 */
27
28#include "config.h"
29#include "VideoSinkGStreamer.h"
30
31#include <glib.h>
32#include <gst/gst.h>
33#include <gst/video/video.h>
34
35static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE("sink",
36        GST_PAD_SINK, GST_PAD_ALWAYS,
37        GST_STATIC_CAPS(GST_VIDEO_CAPS_RGBx ";" GST_VIDEO_CAPS_BGRx));
38
39GST_DEBUG_CATEGORY_STATIC(webkit_video_sink_debug);
40#define GST_CAT_DEFAULT webkit_video_sink_debug
41
42static GstElementDetails webkit_video_sink_details =
43  GST_ELEMENT_DETAILS((gchar*) "WebKit video sink",
44                      (gchar*) "Sink/Video",
45                      (gchar*) "Sends video data from a GStreamer pipeline to a Cairo surface",
46                      (gchar*) "Alp Toker <alp@atoker.com>");
47
48enum {
49    PROP_0,
50    PROP_SURFACE
51};
52
53struct _WebKitVideoSinkPrivate {
54    cairo_surface_t* surface;
55    GAsyncQueue* async_queue;
56    gboolean rgb_ordering;
57    int width;
58    int height;
59    int fps_n;
60    int fps_d;
61    int par_n;
62    int par_d;
63};
64
65#define _do_init(bla) \
66    GST_DEBUG_CATEGORY_INIT (webkit_video_sink_debug, \
67                             "webkitsink", \
68                             0, \
69                             "webkit video sink")
70
71GST_BOILERPLATE_FULL(WebKitVideoSink,
72                     webkit_video_sink,
73                     GstBaseSink,
74                     GST_TYPE_BASE_SINK,
75                     _do_init);
76
77static void
78webkit_video_sink_base_init(gpointer g_class)
79{
80    GstElementClass* element_class = GST_ELEMENT_CLASS(g_class);
81
82    gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&sinktemplate));
83    gst_element_class_set_details(element_class, &webkit_video_sink_details);
84}
85
86static void
87webkit_video_sink_init(WebKitVideoSink* sink, WebKitVideoSinkClass* klass)
88{
89    WebKitVideoSinkPrivate* priv;
90
91    sink->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE(sink, WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkPrivate);
92    priv->async_queue = g_async_queue_new();
93}
94
95static gboolean
96webkit_video_sink_idle_func(gpointer data)
97{
98    WebKitVideoSinkPrivate* priv;
99    GstBuffer* buffer;
100
101    priv = (WebKitVideoSinkPrivate*)data;
102
103    if (!priv->async_queue)
104        return FALSE;
105
106    buffer = (GstBuffer*)g_async_queue_try_pop(priv->async_queue);
107    if (buffer == NULL || G_UNLIKELY(!GST_IS_BUFFER(buffer)))
108        return FALSE;
109
110    // TODO: consider priv->rgb_ordering?
111    cairo_surface_t* src = cairo_image_surface_create_for_data(GST_BUFFER_DATA(buffer), CAIRO_FORMAT_RGB24, priv->width, priv->height, (4 * priv->width + 3) & ~ 3);
112
113    // TODO: We copy the data twice right now. This could be easily improved.
114    cairo_t* cr = cairo_create(priv->surface);
115    cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
116    cairo_set_source_surface(cr, src, 0, 0);
117    cairo_surface_destroy(src);
118    cairo_rectangle(cr, 0, 0, priv->width, priv->height);
119    cairo_fill(cr);
120    cairo_destroy(cr);
121
122    gst_buffer_unref(buffer);
123
124    return FALSE;
125}
126
127static GstFlowReturn
128webkit_video_sink_render(GstBaseSink* bsink, GstBuffer* buffer)
129{
130    WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(bsink);
131    WebKitVideoSinkPrivate* priv = sink->priv;
132
133    g_async_queue_push(priv->async_queue, gst_buffer_ref(buffer));
134    g_idle_add_full(G_PRIORITY_HIGH_IDLE, webkit_video_sink_idle_func, priv, NULL);
135
136    return GST_FLOW_OK;
137}
138
139static gboolean
140webkit_video_sink_set_caps(GstBaseSink* bsink, GstCaps* caps)
141{
142    WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(bsink);
143    WebKitVideoSinkPrivate* priv = sink->priv;
144    GstStructure* structure;
145    gboolean ret;
146    const GValue* fps;
147    const GValue* par;
148    gint width, height;
149    int red_mask;
150
151    GstCaps* intersection = gst_caps_intersect(gst_static_pad_template_get_caps(&sinktemplate), caps);
152
153    if (gst_caps_is_empty(intersection))
154        return FALSE;
155
156    gst_caps_unref(intersection);
157
158    structure = gst_caps_get_structure(caps, 0);
159
160    ret = gst_structure_get_int(structure, "width", &width);
161    ret &= gst_structure_get_int(structure, "height", &height);
162    fps = gst_structure_get_value(structure, "framerate");
163    ret &= (fps != NULL);
164
165    par = gst_structure_get_value(structure, "pixel-aspect-ratio");
166
167    if (!ret)
168        return FALSE;
169
170    priv->width = width;
171    priv->height = height;
172
173    /* We dont yet use fps or pixel aspect into but handy to have */
174    priv->fps_n = gst_value_get_fraction_numerator(fps);
175    priv->fps_d = gst_value_get_fraction_denominator(fps);
176
177    if (par) {
178        priv->par_n = gst_value_get_fraction_numerator(par);
179        priv->par_d = gst_value_get_fraction_denominator(par);
180    } else
181        priv->par_n = priv->par_d = 1;
182
183    gst_structure_get_int(structure, "red_mask", &red_mask);
184    priv->rgb_ordering = (red_mask == static_cast<int>(0xff000000));
185
186    return TRUE;
187}
188
189static void
190webkit_video_sink_dispose(GObject* object)
191{
192    WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object);
193    WebKitVideoSinkPrivate* priv = sink->priv;
194
195    if (priv->surface) {
196        cairo_surface_destroy(priv->surface);
197        priv->surface = NULL;
198    }
199
200    if (priv->async_queue) {
201        g_async_queue_unref(priv->async_queue);
202        priv->async_queue = NULL;
203    }
204
205    G_OBJECT_CLASS(parent_class)->dispose(object);
206}
207
208static void
209webkit_video_sink_finalize(GObject* object)
210{
211    G_OBJECT_CLASS(parent_class)->finalize(object);
212}
213
214static void
215webkit_video_sink_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec)
216{
217    WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object);
218    WebKitVideoSinkPrivate* priv = sink->priv;
219
220    switch (prop_id) {
221    case PROP_SURFACE:
222        if (priv->surface)
223            cairo_surface_destroy(priv->surface);
224        priv->surface = cairo_surface_reference((cairo_surface_t*)g_value_get_pointer(value));
225        break;
226    default:
227        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
228        break;
229    }
230}
231
232static void
233webkit_video_sink_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec* pspec)
234{
235    WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object);
236
237    switch (prop_id) {
238    case PROP_SURFACE:
239        g_value_set_pointer(value, sink->priv->surface);
240        break;
241    default:
242        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
243        break;
244    }
245}
246
247static gboolean
248webkit_video_sink_stop(GstBaseSink* base_sink)
249{
250    WebKitVideoSinkPrivate* priv = WEBKIT_VIDEO_SINK(base_sink)->priv;
251
252    g_async_queue_lock(priv->async_queue);
253
254    /* Remove all remaining objects from the queue */
255    while(GstBuffer* buffer = (GstBuffer*)g_async_queue_try_pop_unlocked(priv->async_queue))
256        gst_buffer_unref(buffer);
257
258    g_async_queue_unlock(priv->async_queue);
259
260    return TRUE;
261}
262
263static void
264webkit_video_sink_class_init(WebKitVideoSinkClass* klass)
265{
266    GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
267    GstBaseSinkClass* gstbase_sink_class = GST_BASE_SINK_CLASS(klass);
268
269    g_type_class_add_private(klass, sizeof(WebKitVideoSinkPrivate));
270
271    gobject_class->set_property = webkit_video_sink_set_property;
272    gobject_class->get_property = webkit_video_sink_get_property;
273
274    gobject_class->dispose = webkit_video_sink_dispose;
275    gobject_class->finalize = webkit_video_sink_finalize;
276
277    gstbase_sink_class->render = webkit_video_sink_render;
278    gstbase_sink_class->preroll = webkit_video_sink_render;
279    gstbase_sink_class->stop = webkit_video_sink_stop;
280    gstbase_sink_class->set_caps = webkit_video_sink_set_caps;
281
282    g_object_class_install_property(
283        gobject_class, PROP_SURFACE,
284        g_param_spec_pointer("surface", "surface", "Target cairo_surface_t*",
285                             (GParamFlags)(G_PARAM_READWRITE)));
286}
287
288/**
289 * webkit_video_sink_new:
290 * @surface: a #cairo_surface_t
291 *
292 * Creates a new GStreamer video sink which uses @surface as the target
293 * for sinking a video stream from GStreamer.
294 *
295 * Return value: a #GstElement for the newly created video sink
296 */
297GstElement*
298webkit_video_sink_new(cairo_surface_t* surface)
299{
300    return (GstElement*)g_object_new(WEBKIT_TYPE_VIDEO_SINK, "surface", surface, NULL);
301}
302
303void
304webkit_video_sink_set_surface(WebKitVideoSink* sink, cairo_surface_t* surface)
305{
306    WebKitVideoSinkPrivate* priv;
307
308    sink->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE(sink, WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkPrivate);
309    if (priv->surface)
310        cairo_surface_destroy(priv->surface);
311    priv->surface = cairo_surface_reference(surface);
312}
Note: See TracBrowser for help on using the browser.