1 /*
2 * Clutter-GStreamer.
3 *
4 * GStreamer integration library for Clutter.
5 *
6 * clutter-gst-video-texture.c - ClutterTexture using GStreamer to display a
7 * video stream.
8 *
9 * Authored By Matthew Allum <mallum@openedhand.com>
10 * Damien Lespiau <damien.lespiau@intel.com>
11 * Lionel Landwerlin <lionel.g.landwerlin@linux.intel.com>
12 *
13 * Copyright (C) 2006 OpenedHand
14 * Copyright (C) 2010, 2011 Intel Corporation
15 *
16 * This library is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU Lesser General Public
18 * License as published by the Free Software Foundation; either
19 * version 2 of the License, or (at your option) any later version.
20 *
21 * This library is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 * Lesser General Public License for more details.
25 *
26 * You should have received a copy of the GNU Lesser General Public
27 * License along with this library; if not, write to the
28 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
29 * Boston, MA 02111-1307, USA.
30 */
31
32 /**
33 * SECTION:clutter-gst-video-texture
34 * @short_description: Actor for playback of video files.
35 *
36 * #ClutterGstVideoTexture is a #ClutterTexture that plays video files.
37 */
38
39 #ifdef HAVE_CONFIG_H
40 #include "config.h"
41 #endif
42
43 #include <string.h>
44
45 #include <glib.h>
46 #include <gio/gio.h>
47 #include <gst/base/gstbasesink.h>
48 #include <gst/video/video.h>
49
50 #include "clutter-gst-debug.h"
51 #include "clutter-gst-enum-types.h"
52 #include "clutter-gst-marshal.h"
53 #include "clutter-gst-player.h"
54 #include "clutter-gst-private.h"
55 #include "clutter-gst-video-texture.h"
56
57 struct _ClutterGstVideoTexturePrivate
58 {
59 /* width / height (in pixels) of the frame data before applying the pixel
60 * aspect ratio */
61 gint buffer_width;
62 gint buffer_height;
63
64 /* Pixel aspect ration is par_n / par_d. this is set by the sink */
65 guint par_n, par_d;
66
67 /* natural width / height (in pixels) of the texture (after par applied) */
68 guint texture_width;
69 guint texture_height;
70
71 CoglHandle idle_material;
72 CoglColor idle_color_unpre;
73 };
74
75 enum {
76 PROP_0 = 32, /* Avoid overlap with player properties */
77
78 PROP_IDLE_MATERIAL,
79 PROP_PAR
80 };
81
82 static void clutter_gst_video_texture_media_init (ClutterMediaIface *iface);
83 static void clutter_gst_video_texture_player_init (ClutterGstPlayerIface *iface);
84
85 G_DEFINE_TYPE_WITH_CODE (ClutterGstVideoTexture,
86 clutter_gst_video_texture,
87 CLUTTER_TYPE_TEXTURE,
88 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_MEDIA,
89 clutter_gst_video_texture_media_init)
90 G_IMPLEMENT_INTERFACE (CLUTTER_GST_TYPE_PLAYER,
91 clutter_gst_video_texture_player_init));
92
93 /* Clutter 1.4 has this symbol, we don't want to depend on 1.4 just for that
94 * just yet */
95 static void
_cogl_color_unpremultiply(CoglColor * color)96 _cogl_color_unpremultiply (CoglColor *color)
97 {
98 gfloat alpha;
99
100 alpha = cogl_color_get_alpha (color);
101
102 if (alpha != 0)
103 {
104 gfloat red, green, blue;
105
106 red = cogl_color_get_red (color);
107 green = cogl_color_get_green (color);
108 blue = cogl_color_get_blue (color);
109
110 red = red / alpha;
111 green = green / alpha;
112 blue = blue / alpha;
113
114 cogl_color_set_from_4f (color, red, green, blue, alpha);
115 }
116 }
117
118 /* Clutter 1.4 has this symbol, we don't want to depend on 1.4 just for that
119 * just yet */
120 static void
_cogl_color_set_alpha_byte(CoglColor * color,unsigned char alpha)121 _cogl_color_set_alpha_byte (CoglColor *color,
122 unsigned char alpha)
123 {
124 unsigned char red, green, blue;
125
126 red = cogl_color_get_red_byte (color);
127 green = cogl_color_get_green_byte (color);
128 blue = cogl_color_get_blue_byte (color);
129
130 cogl_color_set_from_4ub (color, red, green, blue, alpha);
131 }
132
133 static void
gen_texcoords_and_draw_cogl_rectangle(ClutterActor * self)134 gen_texcoords_and_draw_cogl_rectangle (ClutterActor *self)
135 {
136 ClutterActorBox box;
137
138 clutter_actor_get_allocation_box (self, &box);
139
140 cogl_rectangle_with_texture_coords (0, 0,
141 box.x2 - box.x1,
142 box.y2 - box.y1,
143 0, 0, 1.0, 1.0);
144 }
145
146 static void
create_black_idle_material(ClutterGstVideoTexture * video_texture)147 create_black_idle_material (ClutterGstVideoTexture *video_texture)
148 {
149 ClutterGstVideoTexturePrivate *priv = video_texture->priv;
150
151 priv->idle_material = cogl_material_new ();
152 cogl_color_set_from_4ub (&priv->idle_color_unpre, 0, 0, 0, 0xff);
153 cogl_material_set_color (priv->idle_material, &priv->idle_color_unpre);
154 }
155
156 static void
clutter_gst_video_texture_media_init(ClutterMediaIface * iface)157 clutter_gst_video_texture_media_init (ClutterMediaIface *iface)
158 {
159 }
160
161 static void
clutter_gst_video_texture_player_init(ClutterGstPlayerIface * iface)162 clutter_gst_video_texture_player_init (ClutterGstPlayerIface *iface)
163 {
164 }
165
166 static void
clutter_gst_video_texture_size_change(ClutterTexture * texture,gint width,gint height)167 clutter_gst_video_texture_size_change (ClutterTexture *texture,
168 gint width,
169 gint height)
170 {
171 ClutterGstVideoTexture *video_texture = CLUTTER_GST_VIDEO_TEXTURE (texture);
172 ClutterGstVideoTexturePrivate *priv = video_texture->priv;
173 gboolean changed;
174
175 /* we are being told the actual (as in number of pixels in the buffers)
176 * frame size. Store the values to be used in preferred_width/height() */
177 changed = (priv->buffer_width != width) || (priv->buffer_height != height);
178 priv->buffer_width = width;
179 priv->buffer_height = height;
180
181 if (changed)
182 {
183 /* reset the computed texture dimensions if the underlying frames have
184 * changed size */
185 CLUTTER_GST_NOTE (ASPECT_RATIO, "frame size has been updated to %dx%d",
186 width, height);
187
188 priv->texture_width = priv->texture_height = 0;
189
190 /* queue a relayout to ask containers/layout manager to ask for
191 * the preferred size again */
192 clutter_actor_queue_relayout (CLUTTER_ACTOR (texture));
193 }
194 }
195
196 /*
197 * Clutter actor implementation
198 */
199
200 static void
clutter_gst_video_texture_get_natural_size(ClutterGstVideoTexture * texture,gfloat * width,gfloat * height)201 clutter_gst_video_texture_get_natural_size (ClutterGstVideoTexture *texture,
202 gfloat *width,
203 gfloat *height)
204 {
205 ClutterGstVideoTexturePrivate *priv = texture->priv;
206 guint dar_n, dar_d;
207 gboolean ret;
208
209 /* we cache texture_width and texture_height */
210
211 if (G_UNLIKELY (priv->buffer_width == 0 || priv->buffer_height == 0))
212 {
213 /* we don't know the size of the frames yet default to 0,0 */
214 priv->texture_width = 0;
215 priv->texture_height = 0;
216 }
217 else if (G_UNLIKELY (priv->texture_width == 0 || priv->texture_height == 0))
218 {
219 CLUTTER_GST_NOTE (ASPECT_RATIO, "frame is %dx%d with par %d/%d",
220 priv->buffer_width, priv->buffer_height,
221 priv->par_n, priv->par_d);
222
223 ret = gst_video_calculate_display_ratio (&dar_n, &dar_d,
224 priv->buffer_width,
225 priv->buffer_height,
226 priv->par_n, priv->par_d,
227 1, 1);
228 if (ret == FALSE)
229 dar_n = dar_d = 1;
230
231 if (priv->buffer_height % dar_d == 0)
232 {
233 priv->texture_width = gst_util_uint64_scale (priv->buffer_height,
234 dar_n, dar_d);
235 priv->texture_height = priv->buffer_height;
236 }
237 else if (priv->buffer_width % dar_n == 0)
238 {
239 priv->texture_width = priv->buffer_width;
240 priv->texture_height = gst_util_uint64_scale (priv->buffer_width,
241 dar_d, dar_n);
242
243 }
244 else
245 {
246 priv->texture_width = gst_util_uint64_scale (priv->buffer_height,
247 dar_n, dar_d);
248 priv->texture_height = priv->buffer_height;
249 }
250
251 CLUTTER_GST_NOTE (ASPECT_RATIO,
252 "final size is %dx%d (calculated par is %d/%d)",
253 priv->texture_width, priv->texture_height,
254 dar_n, dar_d);
255 }
256
257 if (width)
258 *width = (gfloat)priv->texture_width;
259
260 if (height)
261 *height = (gfloat)priv->texture_height;
262 }
263
264 static void
clutter_gst_video_texture_get_preferred_width(ClutterActor * self,gfloat for_height,gfloat * min_width_p,gfloat * natural_width_p)265 clutter_gst_video_texture_get_preferred_width (ClutterActor *self,
266 gfloat for_height,
267 gfloat *min_width_p,
268 gfloat *natural_width_p)
269 {
270 ClutterGstVideoTexture *texture = CLUTTER_GST_VIDEO_TEXTURE (self);
271 ClutterGstVideoTexturePrivate *priv = texture->priv;
272 gboolean sync_size, keep_aspect_ratio;
273 gfloat natural_width, natural_height;
274
275 /* Min request is always 0 since we can scale down or clip */
276 if (min_width_p)
277 *min_width_p = 0;
278
279 sync_size = clutter_texture_get_sync_size (CLUTTER_TEXTURE (self));
280 keep_aspect_ratio =
281 clutter_texture_get_keep_aspect_ratio (CLUTTER_TEXTURE (self));
282
283 clutter_gst_video_texture_get_natural_size (texture,
284 &natural_width,
285 &natural_height);
286
287 if (sync_size)
288 {
289 if (natural_width_p)
290 {
291 if (!keep_aspect_ratio ||
292 for_height < 0 ||
293 priv->buffer_height <= 0)
294 {
295 *natural_width_p = natural_width;
296 }
297 else
298 {
299 /* Set the natural width so as to preserve the aspect ratio */
300 gfloat ratio = natural_width / natural_height;
301
302 *natural_width_p = ratio * for_height;
303 }
304 }
305 }
306 else
307 {
308 if (natural_width_p)
309 *natural_width_p = 0;
310 }
311 }
312
313 static void
clutter_gst_video_texture_get_preferred_height(ClutterActor * self,gfloat for_width,gfloat * min_height_p,gfloat * natural_height_p)314 clutter_gst_video_texture_get_preferred_height (ClutterActor *self,
315 gfloat for_width,
316 gfloat *min_height_p,
317 gfloat *natural_height_p)
318 {
319 ClutterGstVideoTexture *texture = CLUTTER_GST_VIDEO_TEXTURE (self);
320 ClutterGstVideoTexturePrivate *priv = texture->priv;
321 gboolean sync_size, keep_aspect_ratio;
322 gfloat natural_width, natural_height;
323
324 /* Min request is always 0 since we can scale down or clip */
325 if (min_height_p)
326 *min_height_p = 0;
327
328 sync_size = clutter_texture_get_sync_size (CLUTTER_TEXTURE (self));
329 keep_aspect_ratio =
330 clutter_texture_get_keep_aspect_ratio (CLUTTER_TEXTURE (self));
331
332 clutter_gst_video_texture_get_natural_size (texture,
333 &natural_width,
334 &natural_height);
335
336 if (sync_size)
337 {
338 if (natural_height_p)
339 {
340 if (!keep_aspect_ratio ||
341 for_width < 0 ||
342 priv->buffer_width <= 0)
343 {
344 *natural_height_p = natural_height;
345 }
346 else
347 {
348 /* Set the natural height so as to preserve the aspect ratio */
349 gfloat ratio = natural_height / natural_width;
350
351 *natural_height_p = ratio * for_width;
352 }
353 }
354 }
355 else
356 {
357 if (natural_height_p)
358 *natural_height_p = 0;
359 }
360 }
361
362 /*
363 * ClutterTexture unconditionnaly sets the material color to:
364 * (opacity,opacity,opacity,opacity)
365 * so we can't set a black material to the texture. Let's override paint()
366 * for now.
367 */
368 static void
clutter_gst_video_texture_paint(ClutterActor * actor)369 clutter_gst_video_texture_paint (ClutterActor *actor)
370 {
371 ClutterGstVideoTexture *video_texture = (ClutterGstVideoTexture *) actor;
372 ClutterGstVideoTexturePrivate *priv = video_texture->priv;
373 ClutterActorClass *actor_class;
374 gboolean is_idle;
375
376 is_idle = clutter_gst_player_get_idle (CLUTTER_GST_PLAYER (video_texture));
377 if (G_UNLIKELY (is_idle))
378 {
379 CoglColor *color;
380 gfloat alpha;
381
382 /* blend the alpha of the idle material with the actor's opacity */
383 color = cogl_color_copy (&priv->idle_color_unpre);
384 alpha = clutter_actor_get_paint_opacity (actor) *
385 cogl_color_get_alpha_byte (color) / 0xff;
386 _cogl_color_set_alpha_byte (color, alpha);
387 cogl_color_premultiply (color);
388 cogl_material_set_color (priv->idle_material, color);
389
390 cogl_set_source (priv->idle_material);
391
392 /* draw */
393 gen_texcoords_and_draw_cogl_rectangle (actor);
394 }
395 else
396 {
397 /* when not idle, just chain up to ClutterTexture::paint() */
398 actor_class =
399 CLUTTER_ACTOR_CLASS (clutter_gst_video_texture_parent_class);
400 actor_class->paint (actor);
401 }
402
403 }
404
405 /*
406 * GObject implementation
407 */
408
409 static void
clutter_gst_video_texture_dispose(GObject * object)410 clutter_gst_video_texture_dispose (GObject *object)
411 {
412 ClutterGstVideoTexture *self = CLUTTER_GST_VIDEO_TEXTURE (object);
413
414 clutter_gst_player_deinit (CLUTTER_GST_PLAYER (self));
415
416 G_OBJECT_CLASS (clutter_gst_video_texture_parent_class)->dispose (object);
417 }
418
419 static void
clutter_gst_video_texture_finalize(GObject * object)420 clutter_gst_video_texture_finalize (GObject *object)
421 {
422 ClutterGstVideoTexture *self;
423 ClutterGstVideoTexturePrivate *priv;
424
425 self = CLUTTER_GST_VIDEO_TEXTURE (object);
426 priv = self->priv;
427
428 if (priv->idle_material != COGL_INVALID_HANDLE)
429 cogl_handle_unref (priv->idle_material);
430
431 G_OBJECT_CLASS (clutter_gst_video_texture_parent_class)->finalize (object);
432 }
433
434 static void
clutter_gst_video_texture_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)435 clutter_gst_video_texture_set_property (GObject *object,
436 guint property_id,
437 const GValue *value,
438 GParamSpec *pspec)
439 {
440 ClutterGstVideoTexture *video_texture = CLUTTER_GST_VIDEO_TEXTURE (object);
441 ClutterGstVideoTexturePrivate *priv = video_texture->priv;
442
443 switch (property_id)
444 {
445 case PROP_IDLE_MATERIAL:
446 clutter_gst_video_texture_set_idle_material (video_texture,
447 g_value_get_boxed (value));
448 break;
449 case PROP_PAR:
450 priv->par_n = gst_value_get_fraction_numerator (value);
451 priv->par_d = gst_value_get_fraction_denominator (value);
452 break;
453
454 default:
455 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
456 }
457 }
458
459 static void
clutter_gst_video_texture_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)460 clutter_gst_video_texture_get_property (GObject *object,
461 guint property_id,
462 GValue *value,
463 GParamSpec *pspec)
464 {
465 ClutterGstVideoTexture *video_texture;
466 ClutterGstVideoTexturePrivate *priv;
467
468 video_texture = CLUTTER_GST_VIDEO_TEXTURE (object);
469 priv = video_texture->priv;
470
471 switch (property_id)
472 {
473 case PROP_IDLE_MATERIAL:
474 g_value_set_boxed (value, priv->idle_material);
475 break;
476 case PROP_PAR:
477 gst_value_set_fraction (value, priv->par_n, priv->par_d);
478 break;
479
480 default:
481 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
482 }
483 }
484
485 static void
clutter_gst_video_texture_class_init(ClutterGstVideoTextureClass * klass)486 clutter_gst_video_texture_class_init (ClutterGstVideoTextureClass *klass)
487 {
488 GObjectClass *object_class = G_OBJECT_CLASS (klass);
489 ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
490 ClutterTextureClass *texture_class = CLUTTER_TEXTURE_CLASS (klass);
491 GParamSpec *pspec;
492
493 g_type_class_add_private (klass, sizeof (ClutterGstVideoTexturePrivate));
494
495 object_class->dispose = clutter_gst_video_texture_dispose;
496 object_class->finalize = clutter_gst_video_texture_finalize;
497 object_class->set_property = clutter_gst_video_texture_set_property;
498 object_class->get_property = clutter_gst_video_texture_get_property;
499
500 actor_class->paint = clutter_gst_video_texture_paint;
501 actor_class->get_preferred_width =
502 clutter_gst_video_texture_get_preferred_width;
503 actor_class->get_preferred_height =
504 clutter_gst_video_texture_get_preferred_height;
505
506 texture_class->size_change = clutter_gst_video_texture_size_change;
507
508 pspec = g_param_spec_boxed ("idle-material",
509 "Idle material",
510 "Material to use for drawing when not playing",
511 COGL_TYPE_HANDLE,
512 CLUTTER_GST_PARAM_READWRITE);
513 g_object_class_install_property (object_class, PROP_IDLE_MATERIAL, pspec);
514
515 pspec = gst_param_spec_fraction ("pixel-aspect-ratio",
516 "Pixel Aspect Ratio",
517 "Pixel aspect ratio of incoming frames",
518 1, 100, 100, 1, 1, 1,
519 CLUTTER_GST_PARAM_READWRITE);
520 g_object_class_install_property (object_class, PROP_PAR, pspec);
521
522
523 clutter_gst_player_class_init (object_class);
524 }
525
526 static void
idle_cb(ClutterGstVideoTexture * video_texture,GParamSpec * pspec,gpointer data)527 idle_cb (ClutterGstVideoTexture *video_texture,
528 GParamSpec *pspec,
529 gpointer data)
530 {
531 /* restore the idle material so we don't just display the last frame */
532 clutter_actor_queue_redraw (CLUTTER_ACTOR (video_texture));
533 }
534
535 static void
on_autocluttersink_element_added(GstBin * bin,GstElement * element,ClutterGstVideoTexture * data)536 on_autocluttersink_element_added (GstBin *bin,
537 GstElement *element,
538 ClutterGstVideoTexture *data)
539 {
540 if (GST_IS_BASE_SINK (element))
541 g_object_set (G_OBJECT (element), "qos", TRUE, NULL);
542 }
543
544 static gboolean
setup_pipeline(ClutterGstVideoTexture * video_texture)545 setup_pipeline (ClutterGstVideoTexture *video_texture)
546 {
547 GstElement *pipeline, *video_sink;
548
549 pipeline =
550 clutter_gst_player_get_pipeline (CLUTTER_GST_PLAYER (video_texture));
551 if (!pipeline)
552 {
553 g_critical ("Unable to get playbin2 element");
554 return FALSE;
555 }
556
557 video_sink = gst_element_factory_make ("cluttersink", NULL);
558
559 g_object_set (G_OBJECT (video_sink),
560 "texture", CLUTTER_TEXTURE (video_texture),
561 NULL);
562 g_object_set (G_OBJECT (pipeline),
563 "video-sink", video_sink,
564 "subtitle-font-desc", "Sans 16",
565 NULL);
566
567 return TRUE;
568 }
569
570 static void
clutter_gst_video_texture_init(ClutterGstVideoTexture * video_texture)571 clutter_gst_video_texture_init (ClutterGstVideoTexture *video_texture)
572 {
573 ClutterGstVideoTexturePrivate *priv;
574
575 video_texture->priv = priv =
576 G_TYPE_INSTANCE_GET_PRIVATE (video_texture,
577 CLUTTER_GST_TYPE_VIDEO_TEXTURE,
578 ClutterGstVideoTexturePrivate);
579
580 if (!clutter_gst_player_init (CLUTTER_GST_PLAYER (video_texture)))
581 {
582 g_warning ("Failed to initiate suitable playback pipeline.");
583 return;
584 }
585
586 if (!setup_pipeline (video_texture))
587 {
588 g_warning ("Failed to initiate suitable sinks for pipeline.");
589 return;
590 }
591
592 create_black_idle_material (video_texture);
593
594 priv->par_n = priv->par_d = 1;
595
596 g_signal_connect (video_texture, "notify::idle",
597 G_CALLBACK (idle_cb),
598 NULL);
599 }
600
601 /*
602 * Private symbols
603 */
604
605 /**
606 * clutter_gst_video_texture_new:
607 *
608 * Creates a video texture.
609 *
610 * <note>This function has to be called from Clutter's main thread. While
611 * GStreamer will spawn threads to do its work, we want all the GL calls to
612 * happen in the same thread. Clutter-gst knows which thread it is by
613 * assuming this constructor is called from the Clutter thread.</note>
614 *
615 * Return value: the newly created video texture actor
616 */
617 ClutterActor*
clutter_gst_video_texture_new(void)618 clutter_gst_video_texture_new (void)
619 {
620 return g_object_new (CLUTTER_GST_TYPE_VIDEO_TEXTURE,
621 "disable-slicing", TRUE,
622 NULL);
623 }
624
625 /**
626 * clutter_gst_video_texture_get_pipeline:
627 * @texture: a #ClutterGstVideoTexture
628 *
629 * Retrieves the #GstPipeline used by the @texture, for direct use with
630 * GStreamer API.
631 *
632 * Return value: (transfer none): the pipeline element used by the video texture
633 */
634 GstElement *
clutter_gst_video_texture_get_pipeline(ClutterGstVideoTexture * texture)635 clutter_gst_video_texture_get_pipeline (ClutterGstVideoTexture *texture)
636 {
637 return clutter_gst_player_get_pipeline (CLUTTER_GST_PLAYER (texture));
638 }
639
640 /**
641 * clutter_gst_video_texture_get_idle_material:
642 * @texture: a #ClutterGstVideoTexture
643 *
644 * Retrieves the material used to draw when no media is being played.
645 *
646 * Return value: (transfer none): the #CoglHandle of the idle material
647 *
648 * Since: 1.2
649 */
650 CoglHandle
clutter_gst_video_texture_get_idle_material(ClutterGstVideoTexture * texture)651 clutter_gst_video_texture_get_idle_material (ClutterGstVideoTexture *texture)
652 {
653 g_return_val_if_fail (CLUTTER_GST_IS_VIDEO_TEXTURE (texture),
654 COGL_INVALID_HANDLE);
655
656 return texture->priv->idle_material;
657 }
658 /**
659 * clutter_gst_video_texture_set_idle_material:
660 * @texture: a #ClutterGstVideoTexture
661 * @material: the handle of a Cogl material
662 *
663 * Sets a material to use to draw when no media is being played. The
664 * #ClutterGstVideoTexture holds a reference of the @material.
665 *
666 * The default idle material will paint the #ClutterGstVideoTexture in black.
667 * If %COGL_INVALID_HANDLE is given as @material to this function, this
668 * default idle material will be used.
669 *
670 * Since: 1.2
671 */
672 void
clutter_gst_video_texture_set_idle_material(ClutterGstVideoTexture * texture,CoglHandle material)673 clutter_gst_video_texture_set_idle_material (ClutterGstVideoTexture *texture,
674 CoglHandle material)
675 {
676 ClutterGstVideoTexturePrivate *priv;
677
678 g_return_if_fail (CLUTTER_GST_IS_VIDEO_TEXTURE (texture));
679
680 priv = texture->priv;
681 /* priv->idle_material always has a valid material */
682 cogl_handle_unref (priv->idle_material);
683
684 if (material != COGL_INVALID_HANDLE)
685 {
686 priv->idle_material = cogl_handle_ref (material);
687 cogl_material_get_color (material, &priv->idle_color_unpre);
688 _cogl_color_unpremultiply (&priv->idle_color_unpre);
689 }
690 else
691 {
692 create_black_idle_material (texture);
693 }
694
695 g_object_notify (G_OBJECT (texture), "idle-material");
696 }
697
698 /**
699 * clutter_gst_video_texture_get_user_agent:
700 * @texture: a #ClutterGstVideoTexture
701 *
702 * Retrieves the user agent used when streaming.
703 *
704 * Return value: the user agent used. The returned string has to be freed with
705 * g_free()
706 *
707 * Since: 1.2
708 */
709 gchar *
clutter_gst_video_texture_get_user_agent(ClutterGstVideoTexture * texture)710 clutter_gst_video_texture_get_user_agent (ClutterGstVideoTexture *texture)
711 {
712 return clutter_gst_player_get_user_agent (CLUTTER_GST_PLAYER (texture));
713 }
714
715 /**
716 * clutter_gst_video_texture_set_user_agent:
717 * @texture: a #ClutterGstVideoTexture
718 * @user_agent: the user agent
719 *
720 * Sets the user agent to use when streaming.
721 *
722 * When streaming content, you might want to set a custom user agent, eg. to
723 * promote your software, make it appear in statistics or because the server
724 * requires a special user agent you want to impersonate.
725 *
726 * Since: 1.2
727 */
728 void
clutter_gst_video_texture_set_user_agent(ClutterGstVideoTexture * texture,const gchar * user_agent)729 clutter_gst_video_texture_set_user_agent (ClutterGstVideoTexture *texture,
730 const gchar * user_agent)
731 {
732 clutter_gst_player_set_user_agent (CLUTTER_GST_PLAYER (texture),
733 user_agent);
734 }
735
736 /**
737 * clutter_gst_video_texture_get_seek_flags:
738 * @texture: a #ClutterGstVideoTexture
739 *
740 * Get the current value of the seek-flags property.
741 *
742 * Return value: a combination of #ClutterGstSeekFlags
743 *
744 * Since: 1.4
745 */
746 ClutterGstSeekFlags
clutter_gst_video_texture_get_seek_flags(ClutterGstVideoTexture * texture)747 clutter_gst_video_texture_get_seek_flags (ClutterGstVideoTexture *texture)
748 {
749 return clutter_gst_player_get_seek_flags (CLUTTER_GST_PLAYER (texture));
750 }
751
752 /**
753 * clutter_gst_video_texture_set_seek_flags:
754 * @texture: a #ClutterGstVideoTexture
755 * @flags: a combination of #ClutterGstSeekFlags
756 *
757 * Seeking can be done with several trade-offs. Clutter-gst defaults
758 * to %CLUTTER_GST_SEEK_FLAG_NONE.
759 *
760 * Since: 1.4
761 */
762 void
clutter_gst_video_texture_set_seek_flags(ClutterGstVideoTexture * texture,ClutterGstSeekFlags flags)763 clutter_gst_video_texture_set_seek_flags (ClutterGstVideoTexture *texture,
764 ClutterGstSeekFlags flags)
765 {
766 clutter_gst_player_set_seek_flags (CLUTTER_GST_PLAYER (texture), flags);
767 }
768
769 /**
770 * clutter_gst_video_texture_get_buffering_mode:
771 * @texture: a #ClutterGstVideoTexture
772 *
773 * Return value: a #ClutterGstBufferingMode
774 *
775 * Since: 1.4
776 */
777 ClutterGstBufferingMode
clutter_gst_video_texture_get_buffering_mode(ClutterGstVideoTexture * texture)778 clutter_gst_video_texture_get_buffering_mode (ClutterGstVideoTexture *texture)
779 {
780 return clutter_gst_player_get_buffering_mode (CLUTTER_GST_PLAYER (texture));
781 }
782
783 /**
784 * clutter_gst_video_texture_set_buffering_mode:
785 * @texture: a #ClutterGstVideoTexture
786 * @mode: a #ClutterGstBufferingMode
787 *
788 * Since: 1.4
789 */
790 void
clutter_gst_video_texture_set_buffering_mode(ClutterGstVideoTexture * texture,ClutterGstBufferingMode mode)791 clutter_gst_video_texture_set_buffering_mode (ClutterGstVideoTexture *texture,
792 ClutterGstBufferingMode mode)
793 {
794 clutter_gst_player_set_buffering_mode (CLUTTER_GST_PLAYER (texture), mode);
795 }
796
797 /**
798 * clutter_gst_video_texture_get_audio_streams:
799 * @texture: a #ClutterGstVideoTexture
800 *
801 * Get the list of audio streams of the current media.
802 *
803 * Return value: (transfer none) (element-type Gst.TagList): a list of
804 * #GstTagList describing the available audio streams
805 *
806 * Since: 1.4
807 */
808 GList *
clutter_gst_video_texture_get_audio_streams(ClutterGstVideoTexture * texture)809 clutter_gst_video_texture_get_audio_streams (ClutterGstVideoTexture *texture)
810 {
811 return clutter_gst_player_get_audio_streams (CLUTTER_GST_PLAYER (texture));
812 }
813
814 /**
815 * clutter_gst_video_texture_get_audio_stream:
816 * @texture: a #ClutterGstVideoTexture
817 *
818 * Get the current audio stream. The number returned in the index of the
819 * audio stream playing in the list returned by
820 * clutter_gst_video_texture_get_audio_streams().
821 *
822 * Return value: the index of the current audio stream, -1 if the media has no
823 * audio stream
824 *
825 * Since: 1.4
826 */
827 gint
clutter_gst_video_texture_get_audio_stream(ClutterGstVideoTexture * texture)828 clutter_gst_video_texture_get_audio_stream (ClutterGstVideoTexture *texture)
829 {
830 return clutter_gst_player_get_audio_stream (CLUTTER_GST_PLAYER (texture));
831 }
832
833 /**
834 * clutter_gst_video_texture_set_audio_stream:
835 * @texture: a #ClutterGstVideoTexture
836 * @index_: the index of the audio stream
837 *
838 * Set the audio stream to play. @index_ is the index of the stream
839 * in the list returned by clutter_gst_video_texture_get_audio_streams().
840 *
841 * Since: 1.4
842 */
843 void
clutter_gst_video_texture_set_audio_stream(ClutterGstVideoTexture * texture,gint index_)844 clutter_gst_video_texture_set_audio_stream (ClutterGstVideoTexture *texture,
845 gint index_)
846 {
847 clutter_gst_player_set_audio_stream (CLUTTER_GST_PLAYER (texture), index_);
848 }
849
850 /**
851 * clutter_gst_video_texture_get_subtitle_tracks:
852 * @texture: a #ClutterGstVideoTexture
853 *
854 * Get the list of subtitles tracks of the current media.
855 *
856 * Return value: (transfer none) (element-type Gst.TagList): a list
857 * of #GstTagList describing the available subtitles tracks
858 *
859 * Since: 1.4
860 */
861 GList *
clutter_gst_video_texture_get_subtitle_tracks(ClutterGstVideoTexture * texture)862 clutter_gst_video_texture_get_subtitle_tracks (ClutterGstVideoTexture *texture)
863 {
864 return clutter_gst_player_get_subtitle_tracks (CLUTTER_GST_PLAYER (texture));
865 }
866
867 /**
868 * clutter_gst_video_texture_get_subtitle_track:
869 * @texture: a #ClutterGstVideoTexture
870 *
871 * Get the current subtitles track. The number returned is the index of the
872 * subitles track in the list returned by
873 * clutter_gst_video_texture_get_subtitle_tracks().
874 *
875 * Return value: the index of the current subtitlest track, -1 if the media has
876 * no subtitles track or if the subtitles have been turned off
877 *
878 * Since: 1.4
879 */
880 gint
clutter_gst_video_texture_get_subtitle_track(ClutterGstVideoTexture * texture)881 clutter_gst_video_texture_get_subtitle_track (ClutterGstVideoTexture *texture)
882 {
883 return clutter_gst_player_get_subtitle_track (CLUTTER_GST_PLAYER (texture));
884 }
885
886 /**
887 * clutter_gst_video_texture_set_subtitle_track:
888 * @texture: a #ClutterGstVideoTexture
889 * @index_: the index of the subtitles track
890 *
891 * Set the subtitles track to play. @index_ is the index of the stream
892 * in the list returned by clutter_gst_video_texture_get_subtitle_tracks().
893 *
894 * If @index_ is -1, the subtitles are turned off.
895 *
896 * Since: 1.4
897 */
898 void
clutter_gst_video_texture_set_subtitle_track(ClutterGstVideoTexture * texture,gint index_)899 clutter_gst_video_texture_set_subtitle_track (ClutterGstVideoTexture *texture,
900 gint index_)
901 {
902 clutter_gst_player_set_subtitle_track (CLUTTER_GST_PLAYER (texture), index_);
903 }
904