1 /* GStreamer
2 *
3 * Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library 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 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 /**
22 * SECTION:gstplay-videooverlayvideorenderer
23 * @title: GstPlayVideoOverlayVideoRenderer
24 * @short_description: Play Video Overlay Video Renderer
25 *
26 */
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include "gstplay-video-overlay-video-renderer.h"
33 #include "gstplay.h"
34
35 #include <gst/video/video.h>
36
37 struct _GstPlayVideoOverlayVideoRenderer
38 {
39 GObject parent;
40
41 GstVideoOverlay *video_overlay;
42 gpointer window_handle;
43 gint x, y, width, height;
44
45 GstElement *video_sink; /* configured video sink, or NULL */
46 };
47
48 struct _GstPlayVideoOverlayVideoRendererClass
49 {
50 GObjectClass parent_class;
51 };
52
53 static void
54 gst_play_video_overlay_video_renderer_interface_init
55 (GstPlayVideoRendererInterface * iface);
56
57 enum
58 {
59 VIDEO_OVERLAY_VIDEO_RENDERER_PROP_0,
60 VIDEO_OVERLAY_VIDEO_RENDERER_PROP_WINDOW_HANDLE,
61 VIDEO_OVERLAY_VIDEO_RENDERER_PROP_VIDEO_SINK,
62 VIDEO_OVERLAY_VIDEO_RENDERER_PROP_LAST
63 };
64
65 G_DEFINE_TYPE_WITH_CODE (GstPlayVideoOverlayVideoRenderer,
66 gst_play_video_overlay_video_renderer, G_TYPE_OBJECT,
67 G_IMPLEMENT_INTERFACE (GST_TYPE_PLAY_VIDEO_RENDERER,
68 gst_play_video_overlay_video_renderer_interface_init));
69
70 static GParamSpec
71 * video_overlay_video_renderer_param_specs
72 [VIDEO_OVERLAY_VIDEO_RENDERER_PROP_LAST] = { NULL, };
73
74 static void
gst_play_video_overlay_video_renderer_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)75 gst_play_video_overlay_video_renderer_set_property (GObject * object,
76 guint prop_id, const GValue * value, GParamSpec * pspec)
77 {
78 GstPlayVideoOverlayVideoRenderer *self =
79 GST_PLAY_VIDEO_OVERLAY_VIDEO_RENDERER (object);
80
81 switch (prop_id) {
82 case VIDEO_OVERLAY_VIDEO_RENDERER_PROP_WINDOW_HANDLE:
83 self->window_handle = g_value_get_pointer (value);
84 if (self->video_overlay)
85 gst_video_overlay_set_window_handle (self->video_overlay,
86 (guintptr) self->window_handle);
87 break;
88 case VIDEO_OVERLAY_VIDEO_RENDERER_PROP_VIDEO_SINK:
89 self->video_sink = gst_object_ref_sink (g_value_get_object (value));
90 break;
91 default:
92 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
93 break;
94 }
95 }
96
97 static void
gst_play_video_overlay_video_renderer_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)98 gst_play_video_overlay_video_renderer_get_property (GObject * object,
99 guint prop_id, GValue * value, GParamSpec * pspec)
100 {
101 GstPlayVideoOverlayVideoRenderer *self =
102 GST_PLAY_VIDEO_OVERLAY_VIDEO_RENDERER (object);
103
104 switch (prop_id) {
105 case VIDEO_OVERLAY_VIDEO_RENDERER_PROP_WINDOW_HANDLE:
106 g_value_set_pointer (value, self->window_handle);
107 break;
108 case VIDEO_OVERLAY_VIDEO_RENDERER_PROP_VIDEO_SINK:
109 g_value_set_object (value, self->video_sink);
110 break;
111 default:
112 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
113 break;
114 }
115 }
116
117 static void
gst_play_video_overlay_video_renderer_finalize(GObject * object)118 gst_play_video_overlay_video_renderer_finalize (GObject * object)
119 {
120 GstPlayVideoOverlayVideoRenderer *self =
121 GST_PLAY_VIDEO_OVERLAY_VIDEO_RENDERER (object);
122
123 if (self->video_overlay)
124 gst_object_unref (self->video_overlay);
125
126 if (self->video_sink)
127 gst_object_unref (self->video_sink);
128
129 G_OBJECT_CLASS
130 (gst_play_video_overlay_video_renderer_parent_class)->finalize (object);
131 }
132
133 static void
gst_play_video_overlay_video_renderer_class_init(GstPlayVideoOverlayVideoRendererClass * klass)134 gst_play_video_overlay_video_renderer_class_init
135 (GstPlayVideoOverlayVideoRendererClass * klass)
136 {
137 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
138
139 gobject_class->set_property =
140 gst_play_video_overlay_video_renderer_set_property;
141 gobject_class->get_property =
142 gst_play_video_overlay_video_renderer_get_property;
143 gobject_class->finalize = gst_play_video_overlay_video_renderer_finalize;
144
145 video_overlay_video_renderer_param_specs
146 [VIDEO_OVERLAY_VIDEO_RENDERER_PROP_WINDOW_HANDLE] =
147 g_param_spec_pointer ("window-handle", "Window Handle",
148 "Window handle to embed the video into",
149 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
150
151 video_overlay_video_renderer_param_specs
152 [VIDEO_OVERLAY_VIDEO_RENDERER_PROP_VIDEO_SINK] =
153 g_param_spec_object ("video-sink", "Video Sink",
154 "the video output element to use (NULL = default sink)",
155 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
156
157 g_object_class_install_properties (gobject_class,
158 VIDEO_OVERLAY_VIDEO_RENDERER_PROP_LAST,
159 video_overlay_video_renderer_param_specs);
160 }
161
162 static void
gst_play_video_overlay_video_renderer_init(GstPlayVideoOverlayVideoRenderer * self)163 gst_play_video_overlay_video_renderer_init
164 (GstPlayVideoOverlayVideoRenderer * self)
165 {
166 self->x = self->y = self->width = self->height = -1;
167 self->video_sink = NULL;
168 }
169
gst_play_video_overlay_video_renderer_create_video_sink(GstPlayVideoRenderer * iface,GstPlay * play)170 static GstElement *gst_play_video_overlay_video_renderer_create_video_sink
171 (GstPlayVideoRenderer * iface, GstPlay * play)
172 {
173 GstElement *video_overlay;
174 GstPlayVideoOverlayVideoRenderer *self =
175 GST_PLAY_VIDEO_OVERLAY_VIDEO_RENDERER (iface);
176
177 if (self->video_overlay)
178 gst_object_unref (self->video_overlay);
179
180 video_overlay = gst_play_get_pipeline (play);
181 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY (video_overlay), NULL);
182
183 self->video_overlay = GST_VIDEO_OVERLAY (video_overlay);
184
185 gst_video_overlay_set_window_handle (self->video_overlay,
186 (guintptr) self->window_handle);
187 if (self->width != -1 || self->height != -1)
188 gst_video_overlay_set_render_rectangle (self->video_overlay, self->x,
189 self->y, self->width, self->height);
190
191 return self->video_sink;
192 }
193
194 static void
gst_play_video_overlay_video_renderer_interface_init(GstPlayVideoRendererInterface * iface)195 gst_play_video_overlay_video_renderer_interface_init
196 (GstPlayVideoRendererInterface * iface)
197 {
198 iface->create_video_sink =
199 gst_play_video_overlay_video_renderer_create_video_sink;
200 }
201
202 /**
203 * gst_play_video_overlay_video_renderer_new:
204 * @window_handle: (allow-none): Window handle to use or %NULL
205 *
206 * Returns: (transfer full):
207 * Since: 1.20
208 */
209 GstPlayVideoRenderer *
gst_play_video_overlay_video_renderer_new(gpointer window_handle)210 gst_play_video_overlay_video_renderer_new (gpointer window_handle)
211 {
212 return g_object_new (GST_TYPE_PLAY_VIDEO_OVERLAY_VIDEO_RENDERER,
213 "window-handle", window_handle, NULL);
214 }
215
216 /**
217 * gst_play_video_overlay_video_renderer_new_with_sink:
218 * @window_handle: (allow-none): Window handle to use or %NULL
219 * @video_sink: (transfer floating): the custom video_sink element to be set for the video renderer
220 *
221 * Returns: (transfer full):
222 *
223 * Since: 1.20
224 */
225 GstPlayVideoRenderer *
gst_play_video_overlay_video_renderer_new_with_sink(gpointer window_handle,GstElement * video_sink)226 gst_play_video_overlay_video_renderer_new_with_sink (gpointer window_handle,
227 GstElement * video_sink)
228 {
229 return g_object_new (GST_TYPE_PLAY_VIDEO_OVERLAY_VIDEO_RENDERER,
230 "window-handle", window_handle, "video-sink", video_sink, NULL);
231 }
232
233 /**
234 * gst_play_video_overlay_video_renderer_set_window_handle:
235 * @self: #GstPlayVideoRenderer instance
236 * @window_handle: handle referencing to the platform specific window
237 *
238 * Sets the platform specific window handle into which the video
239 * should be rendered
240 * Since: 1.20
241 **/
gst_play_video_overlay_video_renderer_set_window_handle(GstPlayVideoOverlayVideoRenderer * self,gpointer window_handle)242 void gst_play_video_overlay_video_renderer_set_window_handle
243 (GstPlayVideoOverlayVideoRenderer * self, gpointer window_handle)
244 {
245 g_return_if_fail (GST_IS_PLAY_VIDEO_OVERLAY_VIDEO_RENDERER (self));
246
247 g_object_set (self, "window-handle", window_handle, NULL);
248 }
249
250 /**
251 * gst_play_video_overlay_video_renderer_get_window_handle:
252 * @self: #GstPlayVideoRenderer instance
253 *
254 * Returns: (transfer none): The currently set, platform specific window
255 * handle
256 * Since: 1.20
257 */
258 gpointer
gst_play_video_overlay_video_renderer_get_window_handle(GstPlayVideoOverlayVideoRenderer * self)259 gst_play_video_overlay_video_renderer_get_window_handle
260 (GstPlayVideoOverlayVideoRenderer * self) {
261 gpointer window_handle;
262
263 g_return_val_if_fail (GST_IS_PLAY_VIDEO_OVERLAY_VIDEO_RENDERER (self), NULL);
264
265 g_object_get (self, "window-handle", &window_handle, NULL);
266
267 return window_handle;
268 }
269
270 /**
271 * gst_play_video_overlay_video_renderer_expose:
272 * @self: a #GstPlayVideoOverlayVideoRenderer instance.
273 *
274 * Tell an overlay that it has been exposed. This will redraw the current frame
275 * in the drawable even if the pipeline is PAUSED.
276 * Since: 1.20
277 */
gst_play_video_overlay_video_renderer_expose(GstPlayVideoOverlayVideoRenderer * self)278 void gst_play_video_overlay_video_renderer_expose
279 (GstPlayVideoOverlayVideoRenderer * self)
280 {
281 g_return_if_fail (GST_IS_PLAY_VIDEO_OVERLAY_VIDEO_RENDERER (self));
282
283 if (self->video_overlay)
284 gst_video_overlay_expose (self->video_overlay);
285 }
286
287 /**
288 * gst_play_video_overlay_video_renderer_set_render_rectangle:
289 * @self: a #GstPlayVideoOverlayVideoRenderer instance
290 * @x: the horizontal offset of the render area inside the window
291 * @y: the vertical offset of the render area inside the window
292 * @width: the width of the render area inside the window
293 * @height: the height of the render area inside the window
294 *
295 * Configure a subregion as a video target within the window set by
296 * gst_play_video_overlay_video_renderer_set_window_handle(). If this is not
297 * used or not supported the video will fill the area of the window set as the
298 * overlay to 100%. By specifying the rectangle, the video can be overlaid to
299 * a specific region of that window only. After setting the new rectangle one
300 * should call gst_play_video_overlay_video_renderer_expose() to force a
301 * redraw. To unset the region pass -1 for the @width and @height parameters.
302 *
303 * This method is needed for non fullscreen video overlay in UI toolkits that
304 * do not support subwindows.
305 *
306 * Since: 1.20
307 */
gst_play_video_overlay_video_renderer_set_render_rectangle(GstPlayVideoOverlayVideoRenderer * self,gint x,gint y,gint width,gint height)308 void gst_play_video_overlay_video_renderer_set_render_rectangle
309 (GstPlayVideoOverlayVideoRenderer * self, gint x, gint y, gint width,
310 gint height)
311 {
312 g_return_if_fail (GST_IS_PLAY_VIDEO_OVERLAY_VIDEO_RENDERER (self));
313
314 self->x = x;
315 self->y = y;
316 self->width = width;
317 self->height = height;
318
319 if (self->video_overlay)
320 gst_video_overlay_set_render_rectangle (self->video_overlay,
321 x, y, width, height);
322 }
323
324 /**
325 * gst_play_video_overlay_video_renderer_get_render_rectangle:
326 * @self: a #GstPlayVideoOverlayVideoRenderer instance
327 * @x: (out) (allow-none): the horizontal offset of the render area inside the window
328 * @y: (out) (allow-none): the vertical offset of the render area inside the window
329 * @width: (out) (allow-none): the width of the render area inside the window
330 * @height: (out) (allow-none): the height of the render area inside the window
331 *
332 * Return the currently configured render rectangle. See gst_play_video_overlay_video_renderer_set_render_rectangle()
333 * for details.
334 *
335 * Since: 1.20
336 */
gst_play_video_overlay_video_renderer_get_render_rectangle(GstPlayVideoOverlayVideoRenderer * self,gint * x,gint * y,gint * width,gint * height)337 void gst_play_video_overlay_video_renderer_get_render_rectangle
338 (GstPlayVideoOverlayVideoRenderer * self, gint * x, gint * y,
339 gint * width, gint * height)
340 {
341 g_return_if_fail (GST_IS_PLAY_VIDEO_OVERLAY_VIDEO_RENDERER (self));
342
343 if (x)
344 *x = self->x;
345 if (y)
346 *y = self->y;
347 if (width)
348 *width = self->width;
349 if (height)
350 *height = self->height;
351 }
352