• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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