43376179c68c2c2a947c42ea693f15f58aa50230
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / gst-libs / gst / player / gstplayer.c
1 /* GStreamer
2  *
3  * Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
4  * Copyright (C) 2015 Brijesh Singh <brijesh.ksingh@gmail.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 /**
23  * SECTION:gstplayer
24  * @title: GstPlayer
25  * @short_description: Player
26  * @symbols:
27  * - GstPlayer
28  *
29  * Starting from GStreamer 1.20, application developers are strongly advised to migrate to #GstPlay.
30  * #GstPlayer will be deprecated in 1.20 and most likely removed by 1.24.
31  */
32
33 /* TODO:
34  *
35  * - Equalizer
36  * - Gapless playback
37  * - Frame stepping
38  * - Subtitle font, connection speed
39  * - Deinterlacing
40  * - Buffering control (-> progressive downloading)
41  * - Playlist/queue object
42  * - Custom video sink (e.g. embed in GL scene)
43  *
44  */
45
46 #ifdef HAVE_CONFIG_H
47 #include "config.h"
48 #endif
49
50 #include "gstplayer.h"
51 #include "gstplayer-signal-dispatcher-private.h"
52 #include "gstplayer-video-renderer-private.h"
53 #include "gstplayer-media-info-private.h"
54 #include "gstplayer-wrapped-video-renderer-private.h"
55
56 #include <gst/gst.h>
57 #include <gst/play/play.h>
58 #include <gst/video/video.h>
59 #include <gst/video/colorbalance.h>
60 #include <gst/tag/tag.h>
61 #include <gst/pbutils/descriptions.h>
62
63 #include <string.h>
64
65 GST_DEBUG_CATEGORY_STATIC (gst_player_debug);
66 #define GST_CAT_DEFAULT gst_player_debug
67
68 #define DEFAULT_URI NULL
69 #define DEFAULT_POSITION GST_CLOCK_TIME_NONE
70 #define DEFAULT_DURATION GST_CLOCK_TIME_NONE
71 #define DEFAULT_VOLUME 1.0
72 #define DEFAULT_MUTE FALSE
73 #define DEFAULT_RATE 1.0
74 #define DEFAULT_POSITION_UPDATE_INTERVAL_MS 100
75 #define DEFAULT_AUDIO_VIDEO_OFFSET 0
76 #define DEFAULT_SUBTITLE_VIDEO_OFFSET 0
77
78 /**
79  * gst_player_error_quark:
80  */
81 GQuark
82 gst_player_error_quark (void)
83 {
84   return g_quark_from_static_string ("gst-player-error-quark");
85 }
86
87 static GQuark QUARK_CONFIG;
88
89 /* Keep ConfigQuarkId and _config_quark_strings ordered and synced */
90 typedef enum
91 {
92   CONFIG_QUARK_USER_AGENT = 0,
93   CONFIG_QUARK_POSITION_INTERVAL_UPDATE,
94   CONFIG_QUARK_ACCURATE_SEEK,
95
96   CONFIG_QUARK_MAX
97 } ConfigQuarkId;
98
99 static const gchar *_config_quark_strings[] = {
100   "user-agent",
101   "position-interval-update",
102   "accurate-seek",
103 };
104
105 static GQuark _config_quark_table[CONFIG_QUARK_MAX];
106
107 #define CONFIG_QUARK(q) _config_quark_table[CONFIG_QUARK_##q]
108
109 enum
110 {
111   PROP_0,
112   PROP_VIDEO_RENDERER,
113   PROP_SIGNAL_DISPATCHER,
114   PROP_URI,
115   PROP_SUBURI,
116   PROP_POSITION,
117   PROP_DURATION,
118   PROP_MEDIA_INFO,
119   PROP_CURRENT_AUDIO_TRACK,
120   PROP_CURRENT_VIDEO_TRACK,
121   PROP_CURRENT_SUBTITLE_TRACK,
122   PROP_VOLUME,
123   PROP_MUTE,
124   PROP_RATE,
125   PROP_PIPELINE,
126   PROP_VIDEO_MULTIVIEW_MODE,
127   PROP_VIDEO_MULTIVIEW_FLAGS,
128   PROP_AUDIO_VIDEO_OFFSET,
129   PROP_SUBTITLE_VIDEO_OFFSET,
130   PROP_LAST
131 };
132
133 enum
134 {
135   SIGNAL_URI_LOADED,
136   SIGNAL_POSITION_UPDATED,
137   SIGNAL_DURATION_CHANGED,
138   SIGNAL_STATE_CHANGED,
139   SIGNAL_BUFFERING,
140   SIGNAL_END_OF_STREAM,
141   SIGNAL_ERROR,
142   SIGNAL_WARNING,
143   SIGNAL_VIDEO_DIMENSIONS_CHANGED,
144   SIGNAL_MEDIA_INFO_UPDATED,
145   SIGNAL_VOLUME_CHANGED,
146   SIGNAL_MUTE_CHANGED,
147   SIGNAL_SEEK_DONE,
148   SIGNAL_LAST
149 };
150
151 struct _GstPlayer
152 {
153   GstObject parent;
154
155   GstPlay *play;
156   GstPlaySignalAdapter *signal_adapter;
157
158   /* legacy */
159   GstPlayerSignalDispatcher *signal_dispatcher;
160 };
161
162 struct _GstPlayerClass
163 {
164   GstObjectClass parent_class;
165 };
166
167 #define parent_class gst_player_parent_class
168 G_DEFINE_TYPE (GstPlayer, gst_player, GST_TYPE_OBJECT);
169
170 static guint signals[SIGNAL_LAST] = { 0, };
171 static GParamSpec *param_specs[PROP_LAST] = { NULL, };
172
173 static void gst_player_finalize (GObject * object);
174 static void gst_player_set_property (GObject * object, guint prop_id,
175     const GValue * value, GParamSpec * pspec);
176 static void gst_player_get_property (GObject * object, guint prop_id,
177     GValue * value, GParamSpec * pspec);
178
179 static void
180 gst_player_init (G_GNUC_UNUSED GstPlayer * self)
181 {
182
183 }
184
185 static void
186 config_quark_initialize (void)
187 {
188   gint i;
189
190   QUARK_CONFIG = g_quark_from_static_string ("player-config");
191
192   if (G_N_ELEMENTS (_config_quark_strings) != CONFIG_QUARK_MAX)
193     g_warning ("the quark table is not consistent! %d != %d",
194         (int) G_N_ELEMENTS (_config_quark_strings), CONFIG_QUARK_MAX);
195
196   for (i = 0; i < CONFIG_QUARK_MAX; i++) {
197     _config_quark_table[i] =
198         g_quark_from_static_string (_config_quark_strings[i]);
199   }
200 }
201
202 static void
203 gst_player_class_init (GstPlayerClass * klass)
204 {
205   GObjectClass *gobject_class = (GObjectClass *) klass;
206
207   gobject_class->set_property = gst_player_set_property;
208   gobject_class->get_property = gst_player_get_property;
209   gobject_class->finalize = gst_player_finalize;
210
211   param_specs[PROP_VIDEO_RENDERER] =
212       g_param_spec_object ("video-renderer",
213       "Video Renderer", "Video renderer to use for rendering videos",
214       GST_TYPE_PLAYER_VIDEO_RENDERER,
215       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
216
217   param_specs[PROP_SIGNAL_DISPATCHER] =
218       g_param_spec_object ("signal-dispatcher",
219       "Signal Dispatcher", "Dispatcher for the signals to e.g. event loops",
220       GST_TYPE_PLAYER_SIGNAL_DISPATCHER,
221       G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
222
223   param_specs[PROP_URI] = g_param_spec_string ("uri", "URI", "Current URI",
224       DEFAULT_URI, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
225
226   param_specs[PROP_SUBURI] = g_param_spec_string ("suburi", "Subtitle URI",
227       "Current Subtitle URI", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
228
229   param_specs[PROP_POSITION] =
230       g_param_spec_uint64 ("position", "Position", "Current Position",
231       0, G_MAXUINT64, DEFAULT_POSITION,
232       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
233
234   param_specs[PROP_MEDIA_INFO] =
235       g_param_spec_object ("media-info", "Media Info",
236       "Current media information", GST_TYPE_PLAYER_MEDIA_INFO,
237       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
238
239   param_specs[PROP_CURRENT_AUDIO_TRACK] =
240       g_param_spec_object ("current-audio-track", "Current Audio Track",
241       "Current audio track information", GST_TYPE_PLAYER_AUDIO_INFO,
242       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
243
244   param_specs[PROP_CURRENT_VIDEO_TRACK] =
245       g_param_spec_object ("current-video-track", "Current Video Track",
246       "Current video track information", GST_TYPE_PLAYER_VIDEO_INFO,
247       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
248
249   param_specs[PROP_CURRENT_SUBTITLE_TRACK] =
250       g_param_spec_object ("current-subtitle-track", "Current Subtitle Track",
251       "Current audio subtitle information", GST_TYPE_PLAYER_SUBTITLE_INFO,
252       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
253
254   param_specs[PROP_DURATION] =
255       g_param_spec_uint64 ("duration", "Duration", "Duration",
256       0, G_MAXUINT64, DEFAULT_DURATION,
257       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
258
259   param_specs[PROP_VOLUME] =
260       g_param_spec_double ("volume", "Volume", "Volume",
261       0, 10.0, DEFAULT_VOLUME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
262
263   param_specs[PROP_MUTE] =
264       g_param_spec_boolean ("mute", "Mute", "Mute",
265       DEFAULT_MUTE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
266
267   param_specs[PROP_PIPELINE] =
268       g_param_spec_object ("pipeline", "Pipeline",
269       "GStreamer pipeline that is used",
270       GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
271
272   param_specs[PROP_RATE] =
273       g_param_spec_double ("rate", "rate", "Playback rate",
274       -64.0, 64.0, DEFAULT_RATE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
275
276   param_specs[PROP_VIDEO_MULTIVIEW_MODE] =
277       g_param_spec_enum ("video-multiview-mode",
278       "Multiview Mode Override",
279       "Re-interpret a video stream as one of several frame-packed stereoscopic modes.",
280       GST_TYPE_VIDEO_MULTIVIEW_FRAME_PACKING,
281       GST_VIDEO_MULTIVIEW_FRAME_PACKING_NONE,
282       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
283
284   param_specs[PROP_VIDEO_MULTIVIEW_FLAGS] =
285       g_param_spec_flags ("video-multiview-flags",
286       "Multiview Flags Override",
287       "Override details of the multiview frame layout",
288       GST_TYPE_VIDEO_MULTIVIEW_FLAGS, GST_VIDEO_MULTIVIEW_FLAGS_NONE,
289       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
290
291   param_specs[PROP_AUDIO_VIDEO_OFFSET] =
292       g_param_spec_int64 ("audio-video-offset", "Audio Video Offset",
293       "The synchronisation offset between audio and video in nanoseconds",
294       G_MININT64, G_MAXINT64, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
295
296   param_specs[PROP_SUBTITLE_VIDEO_OFFSET] =
297       g_param_spec_int64 ("subtitle-video-offset", "Text Video Offset",
298       "The synchronisation offset between text and video in nanoseconds",
299       G_MININT64, G_MAXINT64, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
300
301   g_object_class_install_properties (gobject_class, PROP_LAST, param_specs);
302
303   signals[SIGNAL_URI_LOADED] =
304       g_signal_new ("uri-loaded", G_TYPE_FROM_CLASS (klass),
305       G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
306       NULL, NULL, G_TYPE_NONE, 1, G_TYPE_STRING);
307
308   signals[SIGNAL_POSITION_UPDATED] =
309       g_signal_new ("position-updated", G_TYPE_FROM_CLASS (klass),
310       G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
311       NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_CLOCK_TIME);
312
313   signals[SIGNAL_DURATION_CHANGED] =
314       g_signal_new ("duration-changed", G_TYPE_FROM_CLASS (klass),
315       G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
316       NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_CLOCK_TIME);
317
318   signals[SIGNAL_STATE_CHANGED] =
319       g_signal_new ("state-changed", G_TYPE_FROM_CLASS (klass),
320       G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
321       NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_PLAYER_STATE);
322
323   signals[SIGNAL_BUFFERING] =
324       g_signal_new ("buffering", G_TYPE_FROM_CLASS (klass),
325       G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
326       NULL, NULL, G_TYPE_NONE, 1, G_TYPE_INT);
327
328   signals[SIGNAL_END_OF_STREAM] =
329       g_signal_new ("end-of-stream", G_TYPE_FROM_CLASS (klass),
330       G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
331       NULL, NULL, G_TYPE_NONE, 0, G_TYPE_INVALID);
332
333   signals[SIGNAL_ERROR] =
334       g_signal_new ("error", G_TYPE_FROM_CLASS (klass),
335       G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
336       NULL, NULL, G_TYPE_NONE, 1, G_TYPE_ERROR);
337
338   signals[SIGNAL_VIDEO_DIMENSIONS_CHANGED] =
339       g_signal_new ("video-dimensions-changed", G_TYPE_FROM_CLASS (klass),
340       G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
341       NULL, NULL, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
342
343   signals[SIGNAL_MEDIA_INFO_UPDATED] =
344       g_signal_new ("media-info-updated", G_TYPE_FROM_CLASS (klass),
345       G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
346       NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_PLAYER_MEDIA_INFO);
347
348   signals[SIGNAL_VOLUME_CHANGED] =
349       g_signal_new ("volume-changed", G_TYPE_FROM_CLASS (klass),
350       G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
351       NULL, NULL, G_TYPE_NONE, 0, G_TYPE_INVALID);
352
353   signals[SIGNAL_MUTE_CHANGED] =
354       g_signal_new ("mute-changed", G_TYPE_FROM_CLASS (klass),
355       G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
356       NULL, NULL, G_TYPE_NONE, 0, G_TYPE_INVALID);
357
358   signals[SIGNAL_WARNING] =
359       g_signal_new ("warning", G_TYPE_FROM_CLASS (klass),
360       G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
361       NULL, NULL, G_TYPE_NONE, 1, G_TYPE_ERROR);
362
363   signals[SIGNAL_SEEK_DONE] =
364       g_signal_new ("seek-done", G_TYPE_FROM_CLASS (klass),
365       G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
366       NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_CLOCK_TIME);
367
368   config_quark_initialize ();
369 }
370
371 static void
372 gst_player_finalize (GObject * object)
373 {
374   GstPlayer *self = GST_PLAYER (object);
375
376   GST_TRACE_OBJECT (self, "Finalizing");
377
378   if (self->signal_dispatcher)
379     g_object_unref (self->signal_dispatcher);
380   if (self->signal_adapter)
381     g_object_unref (self->signal_adapter);
382   if (self->play)
383     gst_object_unref (self->play);
384
385   G_OBJECT_CLASS (parent_class)->finalize (object);
386 }
387
388 static void
389 gst_player_set_property (GObject * object, guint prop_id,
390     const GValue * value, GParamSpec * pspec)
391 {
392   GstPlayer *self = GST_PLAYER (object);
393
394   switch (prop_id) {
395     case PROP_SIGNAL_DISPATCHER:
396       self->signal_dispatcher = g_value_dup_object (value);
397       break;
398     default:
399       g_object_set_property (G_OBJECT (self->play),
400           g_param_spec_get_name (pspec), value);
401       break;
402   }
403 }
404
405 static void
406 gst_player_get_property (GObject * object, guint prop_id,
407     GValue * value, GParamSpec * pspec)
408 {
409   GstPlayer *self = GST_PLAYER (object);
410
411   switch (prop_id) {
412     case PROP_MEDIA_INFO:
413       g_value_take_object (value, gst_player_get_media_info (self));
414       break;
415     case PROP_CURRENT_AUDIO_TRACK:
416       g_value_take_object (value, gst_player_get_current_audio_track (self));
417       break;
418     case PROP_CURRENT_VIDEO_TRACK:
419       g_value_take_object (value, gst_player_get_current_video_track (self));
420       break;
421     case PROP_CURRENT_SUBTITLE_TRACK:
422       g_value_take_object (value, gst_player_get_current_subtitle_track (self));
423       break;
424     default:
425       g_object_get_property (G_OBJECT (self->play),
426           g_param_spec_get_name (pspec), value);
427       break;
428   }
429 }
430
431 static gpointer
432 gst_player_init_once (G_GNUC_UNUSED gpointer user_data)
433 {
434   gst_init (NULL, NULL);
435
436   GST_DEBUG_CATEGORY_INIT (gst_player_debug, "gst-player", 0, "GstPlayer");
437   gst_player_error_quark ();
438
439   return NULL;
440 }
441
442 static void
443 uri_loaded_cb (GstPlaySignalAdapter * adapter, const gchar * uri,
444     GstPlayer * self)
445 {
446   g_signal_emit (self, signals[SIGNAL_URI_LOADED], 0, uri);
447 }
448
449 static void
450 position_updated_cb (GstPlaySignalAdapter * adapter, GstClockTime position,
451     GstPlayer * self)
452 {
453   g_signal_emit (self, signals[SIGNAL_POSITION_UPDATED], 0, position);
454 }
455
456 static void
457 duration_changed_cb (GstPlaySignalAdapter * adapter, GstClockTime duraton,
458     GstPlayer * self)
459 {
460   g_signal_emit (self, signals[SIGNAL_DURATION_CHANGED], 0, duraton);
461 }
462
463 static void
464 state_changed_cb (GstPlaySignalAdapter * adapter, GstPlayState state,
465     GstPlayer * self)
466 {
467   GstPlayerState s = GST_PLAYER_STATE_BUFFERING;
468   switch (state) {
469     case GST_PLAY_STATE_BUFFERING:
470       s = GST_PLAYER_STATE_BUFFERING;
471       break;
472     case GST_PLAY_STATE_PAUSED:
473       s = GST_PLAYER_STATE_PAUSED;
474       break;
475     case GST_PLAY_STATE_PLAYING:
476       s = GST_PLAYER_STATE_PLAYING;
477       break;
478     case GST_PLAY_STATE_STOPPED:
479       s = GST_PLAYER_STATE_STOPPED;
480       break;
481   }
482   g_signal_emit (self, signals[SIGNAL_STATE_CHANGED], 0, s);
483 }
484
485 static void
486 buffering_cb (GstPlaySignalAdapter * adapter, gint buffering_percent,
487     GstPlayer * self)
488 {
489   g_signal_emit (self, signals[SIGNAL_BUFFERING], 0, buffering_percent);
490 }
491
492 static void
493 end_of_stream_cb (GstPlaySignalAdapter * adapter, GstPlayer * self)
494 {
495   g_signal_emit (self, signals[SIGNAL_END_OF_STREAM], 0, NULL);
496 }
497
498 static void
499 error_cb (GstPlaySignalAdapter * adapter, GError * error,
500     GstStructure * details, GstPlayer * self)
501 {
502   g_signal_emit (self, signals[SIGNAL_ERROR], 0, error);
503 }
504
505 static void
506 dimensions_changed_cb (GstPlaySignalAdapter * adapter, guint width,
507     guint height, GstPlayer * self)
508 {
509   g_signal_emit (self, signals[SIGNAL_VIDEO_DIMENSIONS_CHANGED], 0, width,
510       height);
511 }
512
513 static void
514 media_info_cb (GstPlaySignalAdapter * adapter, GstPlayMediaInfo * info,
515     GstPlayer * self)
516 {
517   GstPlayerMediaInfo *i = gst_player_media_info_wrapped (info);
518   g_signal_emit (self, signals[SIGNAL_MEDIA_INFO_UPDATED], 0, i);
519   g_object_unref (i);
520 }
521
522 static void
523 volume_cb (GstPlaySignalAdapter * adapter, gdouble volume, GstPlayer * self)
524 {
525   g_signal_emit (self, signals[SIGNAL_VOLUME_CHANGED], 0, NULL);
526 }
527
528
529 static void
530 mute_cb (GstPlaySignalAdapter * adapter, gboolean muted, GstPlayer * self)
531 {
532   g_signal_emit (self, signals[SIGNAL_MUTE_CHANGED], 0, NULL);
533 }
534
535 static void
536 warning_cb (GstPlaySignalAdapter * adapter, GError * warning,
537     GstStructure * details, GstPlayer * self)
538 {
539   g_signal_emit (self, signals[SIGNAL_WARNING], 0, warning);
540 }
541
542 static void
543 seek_done_cb (GstPlaySignalAdapter * adapter, GstClockTime time,
544     GstPlayer * self)
545 {
546   g_signal_emit (self, signals[SIGNAL_SEEK_DONE], 0, time);
547 }
548
549 /**
550  * gst_player_new:
551  * @video_renderer: (transfer full) (allow-none): GstPlayerVideoRenderer to use
552  * @signal_dispatcher: (transfer full) (allow-none): GstPlayerSignalDispatcher to use
553  *
554  * Creates a new #GstPlayer instance that uses @signal_dispatcher to dispatch
555  * signals to some event loop system, or emits signals directly if NULL is
556  * passed. See gst_player_g_main_context_signal_dispatcher_new().
557  *
558  * Video is going to be rendered by @video_renderer, or if %NULL is provided
559  * no special video set up will be done and some default handling will be
560  * performed.
561  *
562  * Returns: (transfer full): a new #GstPlayer instance
563  */
564 GstPlayer *
565 gst_player_new (GstPlayerVideoRenderer * video_renderer,
566     GstPlayerSignalDispatcher * signal_dispatcher)
567 {
568   static GOnce once = G_ONCE_INIT;
569   GstPlayer *self;
570
571   g_once (&once, gst_player_init_once, NULL);
572
573   self =
574       g_object_new (GST_TYPE_PLAYER, "signal-dispatcher", signal_dispatcher,
575       NULL);
576
577   self->play = gst_play_new (NULL);
578
579   if (video_renderer != NULL) {
580     GstPlayerVideoRenderer *renderer;
581     renderer = gst_player_wrapped_video_renderer_new (video_renderer, self);
582     g_object_set (self->play, "video-renderer",
583         GST_PLAY_VIDEO_RENDERER (renderer), NULL);
584     g_object_unref (renderer);
585   }
586
587   if (signal_dispatcher != NULL) {
588     GMainContext *context = NULL;
589
590     g_object_get (signal_dispatcher, "application-context", &context, NULL);
591     self->signal_adapter =
592         gst_play_signal_adapter_new_with_main_context (self->play, context);
593     g_main_context_unref (context);
594   } else {
595     self->signal_adapter = gst_play_signal_adapter_new (self->play);
596   }
597
598   gst_object_ref_sink (self);
599
600   g_signal_connect (self->signal_adapter, "uri-loaded",
601       G_CALLBACK (uri_loaded_cb), self);
602   g_signal_connect (self->signal_adapter, "position-updated",
603       G_CALLBACK (position_updated_cb), self);
604   g_signal_connect (self->signal_adapter, "duration-changed",
605       G_CALLBACK (duration_changed_cb), self);
606   g_signal_connect (self->signal_adapter, "state-changed",
607       G_CALLBACK (state_changed_cb), self);
608   g_signal_connect (self->signal_adapter, "buffering",
609       G_CALLBACK (buffering_cb), self);
610   g_signal_connect (self->signal_adapter, "end-of-stream",
611       G_CALLBACK (end_of_stream_cb), self);
612   g_signal_connect (self->signal_adapter, "error", G_CALLBACK (error_cb), self);
613   g_signal_connect (self->signal_adapter, "video-dimensions-changed",
614       G_CALLBACK (dimensions_changed_cb), self);
615   g_signal_connect (self->signal_adapter, "media-info-updated",
616       G_CALLBACK (media_info_cb), self);
617   g_signal_connect (self->signal_adapter, "volume-changed",
618       G_CALLBACK (volume_cb), self);
619   g_signal_connect (self->signal_adapter, "mute-changed", G_CALLBACK (mute_cb),
620       self);
621   g_signal_connect (self->signal_adapter, "warning", G_CALLBACK (warning_cb),
622       self);
623   g_signal_connect (self->signal_adapter, "seek-done",
624       G_CALLBACK (seek_done_cb), self);
625
626   if (video_renderer)
627     g_object_unref (video_renderer);
628   if (signal_dispatcher)
629     g_object_unref (signal_dispatcher);
630
631   return self;
632 }
633
634 /**
635  * gst_player_play:
636  * @player: #GstPlayer instance
637  *
638  * Request to play the loaded stream.
639  */
640 void
641 gst_player_play (GstPlayer * self)
642 {
643   g_return_if_fail (GST_IS_PLAYER (self));
644
645   gst_play_play (self->play);
646 }
647
648 /**
649  * gst_player_pause:
650  * @player: #GstPlayer instance
651  *
652  * Pauses the current stream.
653  */
654 void
655 gst_player_pause (GstPlayer * self)
656 {
657   g_return_if_fail (GST_IS_PLAYER (self));
658
659   gst_play_pause (self->play);
660 }
661
662 /**
663  * gst_player_stop:
664  * @player: #GstPlayer instance
665  *
666  * Stops playing the current stream and resets to the first position
667  * in the stream.
668  */
669 void
670 gst_player_stop (GstPlayer * self)
671 {
672   g_return_if_fail (GST_IS_PLAYER (self));
673
674   gst_play_stop (self->play);
675 }
676
677 /**
678  * gst_player_set_rate:
679  * @player: #GstPlayer instance
680  * @rate: playback rate
681  *
682  * Playback at specified rate
683  */
684 void
685 gst_player_set_rate (GstPlayer * self, gdouble rate)
686 {
687   g_return_if_fail (GST_IS_PLAYER (self));
688   g_return_if_fail (rate != 0.0);
689
690   g_object_set (self, "rate", rate, NULL);
691 }
692
693 /**
694  * gst_player_get_rate:
695  * @player: #GstPlayer instance
696  *
697  * Returns: current playback rate
698  */
699 gdouble
700 gst_player_get_rate (GstPlayer * self)
701 {
702   gdouble val;
703
704   g_return_val_if_fail (GST_IS_PLAYER (self), DEFAULT_RATE);
705
706   g_object_get (self, "rate", &val, NULL);
707
708   return val;
709 }
710
711 /**
712  * gst_player_seek:
713  * @player: #GstPlayer instance
714  * @position: position to seek in nanoseconds
715  *
716  * Seeks the currently-playing stream to the absolute @position time
717  * in nanoseconds.
718  */
719 void
720 gst_player_seek (GstPlayer * self, GstClockTime position)
721 {
722   g_return_if_fail (GST_IS_PLAYER (self));
723   g_return_if_fail (GST_CLOCK_TIME_IS_VALID (position));
724
725   gst_play_seek (self->play, position);
726 }
727
728 /**
729  * gst_player_get_uri:
730  * @player: #GstPlayer instance
731  *
732  * Gets the URI of the currently-playing stream.
733  *
734  * Returns: (transfer full) (nullable): a string containing the URI of the
735  * currently-playing stream. g_free() after usage.
736  */
737 gchar *
738 gst_player_get_uri (GstPlayer * self)
739 {
740   gchar *val;
741
742   g_return_val_if_fail (GST_IS_PLAYER (self), DEFAULT_URI);
743
744   g_object_get (self, "uri", &val, NULL);
745
746   return val;
747 }
748
749 /**
750  * gst_player_set_uri:
751  * @player: #GstPlayer instance
752  * @uri: (nullable): next URI to play.
753  *
754  * Sets the next URI to play.
755  */
756 void
757 gst_player_set_uri (GstPlayer * self, const gchar * val)
758 {
759   g_return_if_fail (GST_IS_PLAYER (self));
760
761   g_object_set (self, "uri", val, NULL);
762 }
763
764 /**
765  * gst_player_set_subtitle_uri:
766  * @player: #GstPlayer instance
767  * @uri: (nullable): subtitle URI
768  *
769  * Sets the external subtitle URI. This should be combined with a call to
770  * gst_player_set_subtitle_track_enabled(@player, TRUE) so the subtitles are actually
771  * rendered.
772  */
773 void
774 gst_player_set_subtitle_uri (GstPlayer * self, const gchar * suburi)
775 {
776   g_return_if_fail (GST_IS_PLAYER (self));
777
778   g_object_set (self, "suburi", suburi, NULL);
779 }
780
781 /**
782  * gst_player_get_subtitle_uri:
783  * @player: #GstPlayer instance
784  *
785  * current subtitle URI
786  *
787  * Returns: (transfer full) (nullable): URI of the current external subtitle.
788  *   g_free() after usage.
789  */
790 gchar *
791 gst_player_get_subtitle_uri (GstPlayer * self)
792 {
793   gchar *val = NULL;
794
795   g_return_val_if_fail (GST_IS_PLAYER (self), NULL);
796
797   g_object_get (self, "suburi", &val, NULL);
798
799   return val;
800 }
801
802 /**
803  * gst_player_get_position:
804  * @player: #GstPlayer instance
805  *
806  * Returns: the absolute position time, in nanoseconds, of the
807  * currently-playing stream.
808  */
809 GstClockTime
810 gst_player_get_position (GstPlayer * self)
811 {
812   GstClockTime val;
813
814   g_return_val_if_fail (GST_IS_PLAYER (self), DEFAULT_POSITION);
815
816   g_object_get (self, "position", &val, NULL);
817
818   return val;
819 }
820
821 /**
822  * gst_player_get_duration:
823  * @player: #GstPlayer instance
824  *
825  * Retrieves the duration of the media stream that self represents.
826  *
827  * Returns: the duration of the currently-playing media stream, in
828  * nanoseconds.
829  */
830 GstClockTime
831 gst_player_get_duration (GstPlayer * self)
832 {
833   GstClockTime val;
834
835   g_return_val_if_fail (GST_IS_PLAYER (self), DEFAULT_DURATION);
836
837   g_object_get (self, "duration", &val, NULL);
838
839   return val;
840 }
841
842 /**
843  * gst_player_get_volume:
844  * @player: #GstPlayer instance
845  *
846  * Returns the current volume level, as a percentage between 0 and 1.
847  *
848  * Returns: the volume as percentage between 0 and 1.
849  */
850 gdouble
851 gst_player_get_volume (GstPlayer * self)
852 {
853   gdouble val;
854
855   g_return_val_if_fail (GST_IS_PLAYER (self), DEFAULT_VOLUME);
856
857   g_object_get (self, "volume", &val, NULL);
858
859   return val;
860 }
861
862 /**
863  * gst_player_set_volume:
864  * @player: #GstPlayer instance
865  * @val: the new volume level, as a percentage between 0 and 1
866  *
867  * Sets the volume level of the stream as a percentage between 0 and 1.
868  *
869  * This volume is a linear factor. For showing the volume in a GUI it
870  * might make sense to first convert from a different format. Volume sliders
871  * should usually use a cubic volume. See gst_stream_volume_convert_volume().
872  */
873 void
874 gst_player_set_volume (GstPlayer * self, gdouble val)
875 {
876   g_return_if_fail (GST_IS_PLAYER (self));
877
878   g_object_set (self, "volume", val, NULL);
879 }
880
881 /**
882  * gst_player_get_mute:
883  * @player: #GstPlayer instance
884  *
885  * Returns: %TRUE if the currently-playing stream is muted.
886  */
887 gboolean
888 gst_player_get_mute (GstPlayer * self)
889 {
890   gboolean val;
891
892   g_return_val_if_fail (GST_IS_PLAYER (self), DEFAULT_MUTE);
893
894   g_object_get (self, "mute", &val, NULL);
895
896   return val;
897 }
898
899 /**
900  * gst_player_set_mute:
901  * @player: #GstPlayer instance
902  * @val: Mute state the should be set
903  *
904  * %TRUE if the currently-playing stream should be muted.
905  */
906 void
907 gst_player_set_mute (GstPlayer * self, gboolean val)
908 {
909   g_return_if_fail (GST_IS_PLAYER (self));
910
911   g_object_set (self, "mute", val, NULL);
912 }
913
914 /**
915  * gst_player_get_pipeline:
916  * @player: #GstPlayer instance
917  *
918  * Returns: (transfer full): The internal playbin instance.
919  *
920  * The caller should free it with g_object_unref()
921  */
922 GstElement *
923 gst_player_get_pipeline (GstPlayer * self)
924 {
925   GstElement *val;
926
927   g_return_val_if_fail (GST_IS_PLAYER (self), NULL);
928
929   g_object_get (self, "pipeline", &val, NULL);
930
931   return val;
932 }
933
934 /**
935  * gst_player_get_media_info:
936  * @player: #GstPlayer instance
937  *
938  * A Function to get the current media info #GstPlayerMediaInfo instance.
939  *
940  * Returns: (transfer full) (nullable): media info instance.
941  *
942  * The caller should free it with g_object_unref()
943  */
944 GstPlayerMediaInfo *
945 gst_player_get_media_info (GstPlayer * self)
946 {
947   GstPlayMediaInfo *info;
948   GstPlayerMediaInfo *ret;
949
950   g_return_val_if_fail (GST_IS_PLAYER (self), NULL);
951
952   info = gst_play_get_media_info (self->play);
953   if (!info)
954     return NULL;
955
956   ret = gst_player_media_info_wrapped (info);
957   g_object_unref (info);
958   return ret;
959 }
960
961 /**
962  * gst_player_get_current_audio_track:
963  * @player: #GstPlayer instance
964  *
965  * A Function to get current audio #GstPlayerAudioInfo instance.
966  *
967  * Returns: (transfer full) (nullable): current audio track.
968  *
969  * The caller should free it with g_object_unref()
970  */
971 GstPlayerAudioInfo *
972 gst_player_get_current_audio_track (GstPlayer * self)
973 {
974   GstPlayAudioInfo *info;
975   GstPlayerAudioInfo *ret = NULL;
976
977   g_return_val_if_fail (GST_IS_PLAYER (self), NULL);
978
979   info = gst_play_get_current_audio_track (self->play);
980   if (info != NULL) {
981     ret = gst_player_audio_info_wrapped (info);
982     g_object_unref (info);
983   }
984   return ret;
985 }
986
987 /**
988  * gst_player_get_current_video_track:
989  * @player: #GstPlayer instance
990  *
991  * A Function to get current video #GstPlayerVideoInfo instance.
992  *
993  * Returns: (transfer full) (nullable): current video track.
994  *
995  * The caller should free it with g_object_unref()
996  */
997 GstPlayerVideoInfo *
998 gst_player_get_current_video_track (GstPlayer * self)
999 {
1000   GstPlayVideoInfo *info;
1001   GstPlayerVideoInfo *ret = NULL;
1002
1003   g_return_val_if_fail (GST_IS_PLAYER (self), NULL);
1004
1005   info = gst_play_get_current_video_track (self->play);
1006   if (info != NULL) {
1007     ret = gst_player_video_info_wrapped (info);
1008     g_object_unref (info);
1009   }
1010   return ret;
1011 }
1012
1013 /**
1014  * gst_player_get_current_subtitle_track:
1015  * @player: #GstPlayer instance
1016  *
1017  * A Function to get current subtitle #GstPlayerSubtitleInfo instance.
1018  *
1019  * Returns: (transfer full) (nullable): current subtitle track.
1020  *
1021  * The caller should free it with g_object_unref()
1022  */
1023 GstPlayerSubtitleInfo *
1024 gst_player_get_current_subtitle_track (GstPlayer * self)
1025 {
1026   GstPlaySubtitleInfo *info;
1027   GstPlayerSubtitleInfo *ret = NULL;
1028
1029   g_return_val_if_fail (GST_IS_PLAYER (self), NULL);
1030
1031   info = gst_play_get_current_subtitle_track (self->play);
1032   if (info != NULL) {
1033     ret = gst_player_subtitle_info_wrapped (info);
1034     g_object_unref (info);
1035   }
1036   return ret;
1037 }
1038
1039 /**
1040  * gst_player_set_audio_track:
1041  * @player: #GstPlayer instance
1042  * @stream_index: stream index
1043  *
1044  * Returns: %TRUE or %FALSE
1045  *
1046  * Sets the audio track @stream_idex.
1047  */
1048 gboolean
1049 gst_player_set_audio_track (GstPlayer * self, gint stream_index)
1050 {
1051   g_return_val_if_fail (GST_IS_PLAYER (self), 0);
1052
1053   return gst_play_set_audio_track (self->play, stream_index);
1054 }
1055
1056 /**
1057  * gst_player_set_video_track:
1058  * @player: #GstPlayer instance
1059  * @stream_index: stream index
1060  *
1061  * Returns: %TRUE or %FALSE
1062  *
1063  * Sets the video track @stream_index.
1064  */
1065 gboolean
1066 gst_player_set_video_track (GstPlayer * self, gint stream_index)
1067 {
1068   g_return_val_if_fail (GST_IS_PLAYER (self), 0);
1069
1070   return gst_play_set_video_track (self->play, stream_index);
1071 }
1072
1073 /**
1074  * gst_player_set_subtitle_track:
1075  * @player: #GstPlayer instance
1076  * @stream_index: stream index
1077  *
1078  * Returns: %TRUE or %FALSE
1079  *
1080  * Sets the subtitle stack @stream_index.
1081  */
1082 gboolean
1083 gst_player_set_subtitle_track (GstPlayer * self, gint stream_index)
1084 {
1085   g_return_val_if_fail (GST_IS_PLAYER (self), 0);
1086
1087   return gst_play_set_subtitle_track (self->play, stream_index);
1088 }
1089
1090 /**
1091  * gst_player_set_audio_track_enabled:
1092  * @player: #GstPlayer instance
1093  * @enabled: TRUE or FALSE
1094  *
1095  * Enable or disable the current audio track.
1096  */
1097 void
1098 gst_player_set_audio_track_enabled (GstPlayer * self, gboolean enabled)
1099 {
1100   g_return_if_fail (GST_IS_PLAYER (self));
1101
1102   gst_play_set_audio_track_enabled (self->play, enabled);
1103 }
1104
1105 /**
1106  * gst_player_set_video_track_enabled:
1107  * @player: #GstPlayer instance
1108  * @enabled: TRUE or FALSE
1109  *
1110  * Enable or disable the current video track.
1111  */
1112 void
1113 gst_player_set_video_track_enabled (GstPlayer * self, gboolean enabled)
1114 {
1115   g_return_if_fail (GST_IS_PLAYER (self));
1116
1117   gst_play_set_video_track_enabled (self->play, enabled);
1118 }
1119
1120 /**
1121  * gst_player_set_subtitle_track_enabled:
1122  * @player: #GstPlayer instance
1123  * @enabled: TRUE or FALSE
1124  *
1125  * Enable or disable the current subtitle track.
1126  */
1127 void
1128 gst_player_set_subtitle_track_enabled (GstPlayer * self, gboolean enabled)
1129 {
1130   g_return_if_fail (GST_IS_PLAYER (self));
1131
1132   gst_play_set_subtitle_track_enabled (self->play, enabled);
1133 }
1134
1135 /**
1136  * gst_player_set_visualization:
1137  * @player: #GstPlayer instance
1138  * @name: (nullable): visualization element obtained from
1139  * #gst_player_visualizations_get()
1140  *
1141  * Returns: %TRUE if the visualizations was set correctly. Otherwise,
1142  * %FALSE.
1143  */
1144 gboolean
1145 gst_player_set_visualization (GstPlayer * self, const gchar * name)
1146 {
1147   g_return_val_if_fail (GST_IS_PLAYER (self), FALSE);
1148
1149   return gst_play_set_visualization (self->play, name);
1150 }
1151
1152 /**
1153  * gst_player_get_current_visualization:
1154  * @player: #GstPlayer instance
1155  *
1156  * Returns: (transfer full) (nullable): Name of the currently enabled
1157  *   visualization.
1158  *   g_free() after usage.
1159  */
1160 gchar *
1161 gst_player_get_current_visualization (GstPlayer * self)
1162 {
1163   g_return_val_if_fail (GST_IS_PLAYER (self), NULL);
1164
1165   return gst_play_get_current_visualization (self->play);
1166 }
1167
1168 /**
1169  * gst_player_set_visualization_enabled:
1170  * @player: #GstPlayer instance
1171  * @enabled: TRUE or FALSE
1172  *
1173  * Enable or disable the visualization.
1174  */
1175 void
1176 gst_player_set_visualization_enabled (GstPlayer * self, gboolean enabled)
1177 {
1178   g_return_if_fail (GST_IS_PLAYER (self));
1179
1180   gst_play_set_visualization_enabled (self->play, enabled);
1181 }
1182
1183 struct CBChannelMap
1184 {
1185   const gchar *label;           /* channel label name */
1186   const gchar *name;            /* get_name () */
1187 };
1188
1189 static const struct CBChannelMap cb_channel_map[] = {
1190   /* GST_PLAYER_COLOR_BALANCE_BRIGHTNESS */ {"BRIGHTNESS", "brightness"},
1191   /* GST_PLAYER_COLOR_BALANCE_CONTRAST   */ {"CONTRAST", "contrast"},
1192   /* GST_PLAYER_COLOR_BALANCE_SATURATION */ {"SATURATION", "saturation"},
1193   /* GST_PLAYER_COLOR_BALANCE_HUE        */ {"HUE", "hue"},
1194 };
1195
1196 /**
1197  * gst_player_has_color_balance:
1198  * @player:#GstPlayer instance
1199  *
1200  * Checks whether the @player has color balance support available.
1201  *
1202  * Returns: %TRUE if @player has color balance support. Otherwise,
1203  *   %FALSE.
1204  */
1205 gboolean
1206 gst_player_has_color_balance (GstPlayer * self)
1207 {
1208   g_return_val_if_fail (GST_IS_PLAYER (self), FALSE);
1209
1210   return gst_play_has_color_balance (self->play);
1211 }
1212
1213 /**
1214  * gst_player_set_color_balance:
1215  * @player: #GstPlayer instance
1216  * @type: #GstPlayerColorBalanceType
1217  * @value: The new value for the @type, ranged [0,1]
1218  *
1219  * Sets the current value of the indicated channel @type to the passed
1220  * value.
1221  */
1222 void
1223 gst_player_set_color_balance (GstPlayer * self, GstPlayerColorBalanceType type,
1224     gdouble value)
1225 {
1226   g_return_if_fail (GST_IS_PLAYER (self));
1227   g_return_if_fail (value >= 0.0 && value <= 1.0);
1228
1229   gst_play_set_color_balance (self->play, (GstPlayColorBalanceType) type,
1230       value);
1231 }
1232
1233 /**
1234  * gst_player_get_color_balance:
1235  * @player: #GstPlayer instance
1236  * @type: #GstPlayerColorBalanceType
1237  *
1238  * Retrieve the current value of the indicated @type.
1239  *
1240  * Returns: The current value of @type, between [0,1]. In case of
1241  *   error -1 is returned.
1242  */
1243 gdouble
1244 gst_player_get_color_balance (GstPlayer * self, GstPlayerColorBalanceType type)
1245 {
1246   g_return_val_if_fail (GST_IS_PLAYER (self), -1);
1247
1248   return gst_play_get_color_balance (self->play,
1249       (GstPlayColorBalanceType) type);
1250 }
1251
1252 /**
1253  * gst_player_get_multiview_mode:
1254  * @player: #GstPlayer instance
1255  *
1256  * Retrieve the current value of the indicated @type.
1257  *
1258  * Returns: The current value of @type, Default: -1 "none"
1259  *
1260  * Since: 1.10
1261  */
1262 GstVideoMultiviewFramePacking
1263 gst_player_get_multiview_mode (GstPlayer * self)
1264 {
1265   GstVideoMultiviewFramePacking val = GST_VIDEO_MULTIVIEW_FRAME_PACKING_NONE;
1266
1267   g_return_val_if_fail (GST_IS_PLAYER (self),
1268       GST_VIDEO_MULTIVIEW_FRAME_PACKING_NONE);
1269
1270   g_object_get (self, "video-multiview-mode", &val, NULL);
1271
1272   return val;
1273 }
1274
1275 /**
1276  * gst_player_set_multiview_mode:
1277  * @player: #GstPlayer instance
1278  * @mode: The new value for the @type
1279  *
1280  * Sets the current value of the indicated mode @type to the passed
1281  * value.
1282  *
1283  * Since: 1.10
1284  */
1285 void
1286 gst_player_set_multiview_mode (GstPlayer * self,
1287     GstVideoMultiviewFramePacking mode)
1288 {
1289   g_return_if_fail (GST_IS_PLAYER (self));
1290
1291   g_object_set (self, "video-multiview-mode", mode, NULL);
1292 }
1293
1294 /**
1295  * gst_player_get_multiview_flags:
1296  * @player: #GstPlayer instance
1297  *
1298  * Retrieve the current value of the indicated @type.
1299  *
1300  * Returns: The current value of @type, Default: 0x00000000 "none
1301  *
1302  * Since: 1.10
1303  */
1304 GstVideoMultiviewFlags
1305 gst_player_get_multiview_flags (GstPlayer * self)
1306 {
1307   GstVideoMultiviewFlags val = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1308
1309   g_return_val_if_fail (GST_IS_PLAYER (self), val);
1310
1311   g_object_get (self, "video-multiview-flags", &val, NULL);
1312
1313   return val;
1314 }
1315
1316 /**
1317  * gst_player_set_multiview_flags:
1318  * @player: #GstPlayer instance
1319  * @flags: The new value for the @type
1320  *
1321  * Sets the current value of the indicated mode @type to the passed
1322  * value.
1323  *
1324  * Since: 1.10
1325  */
1326 void
1327 gst_player_set_multiview_flags (GstPlayer * self, GstVideoMultiviewFlags flags)
1328 {
1329   g_return_if_fail (GST_IS_PLAYER (self));
1330
1331   g_object_set (self, "video-multiview-flags", flags, NULL);
1332 }
1333
1334 /**
1335  * gst_player_get_audio_video_offset:
1336  * @player: #GstPlayer instance
1337  *
1338  * Retrieve the current value of audio-video-offset property
1339  *
1340  * Returns: The current value of audio-video-offset in nanoseconds
1341  *
1342  * Since: 1.10
1343  */
1344 gint64
1345 gst_player_get_audio_video_offset (GstPlayer * self)
1346 {
1347   gint64 val = 0;
1348
1349   g_return_val_if_fail (GST_IS_PLAYER (self), DEFAULT_AUDIO_VIDEO_OFFSET);
1350
1351   g_object_get (self, "audio-video-offset", &val, NULL);
1352
1353   return val;
1354 }
1355
1356 /**
1357  * gst_player_set_audio_video_offset:
1358  * @player: #GstPlayer instance
1359  * @offset: #gint64 in nanoseconds
1360  *
1361  * Sets audio-video-offset property by value of @offset
1362  *
1363  * Since: 1.10
1364  */
1365 void
1366 gst_player_set_audio_video_offset (GstPlayer * self, gint64 offset)
1367 {
1368   g_return_if_fail (GST_IS_PLAYER (self));
1369
1370   g_object_set (self, "audio-video-offset", offset, NULL);
1371 }
1372
1373 /**
1374  * gst_player_get_subtitle_video_offset:
1375  * @player: #GstPlayer instance
1376  *
1377  * Retrieve the current value of subtitle-video-offset property
1378  *
1379  * Returns: The current value of subtitle-video-offset in nanoseconds
1380  *
1381  * Since: 1.16
1382  */
1383 gint64
1384 gst_player_get_subtitle_video_offset (GstPlayer * self)
1385 {
1386   gint64 val = 0;
1387
1388   g_return_val_if_fail (GST_IS_PLAYER (self), DEFAULT_SUBTITLE_VIDEO_OFFSET);
1389
1390   g_object_get (self, "subtitle-video-offset", &val, NULL);
1391
1392   return val;
1393 }
1394
1395 /**
1396  * gst_player_set_subtitle_video_offset:
1397  * @player: #GstPlayer instance
1398  * @offset: #gint64 in nanoseconds
1399  *
1400  * Sets subtitle-video-offset property by value of @offset
1401  *
1402  * Since: 1.16
1403  */
1404 void
1405 gst_player_set_subtitle_video_offset (GstPlayer * self, gint64 offset)
1406 {
1407   g_return_if_fail (GST_IS_PLAYER (self));
1408
1409   g_object_set (self, "subtitle-video-offset", offset, NULL);
1410 }
1411
1412
1413 #define C_ENUM(v) ((gint) v)
1414 #define C_FLAGS(v) ((guint) v)
1415
1416 GType
1417 gst_player_color_balance_type_get_type (void)
1418 {
1419   static gsize id = 0;
1420   static const GEnumValue values[] = {
1421     {C_ENUM (GST_PLAYER_COLOR_BALANCE_HUE), "GST_PLAYER_COLOR_BALANCE_HUE",
1422         "hue"},
1423     {C_ENUM (GST_PLAYER_COLOR_BALANCE_BRIGHTNESS),
1424         "GST_PLAYER_COLOR_BALANCE_BRIGHTNESS", "brightness"},
1425     {C_ENUM (GST_PLAYER_COLOR_BALANCE_SATURATION),
1426         "GST_PLAYER_COLOR_BALANCE_SATURATION", "saturation"},
1427     {C_ENUM (GST_PLAYER_COLOR_BALANCE_CONTRAST),
1428         "GST_PLAYER_COLOR_BALANCE_CONTRAST", "contrast"},
1429     {0, NULL, NULL}
1430   };
1431
1432   if (g_once_init_enter (&id)) {
1433     GType tmp = g_enum_register_static ("GstPlayerColorBalanceType", values);
1434     g_once_init_leave (&id, tmp);
1435   }
1436
1437   return (GType) id;
1438 }
1439
1440 /**
1441  * gst_player_color_balance_type_get_name:
1442  * @type: a #GstPlayerColorBalanceType
1443  *
1444  * Gets a string representing the given color balance type.
1445  *
1446  * Returns: (transfer none): a string with the name of the color
1447  *   balance type.
1448  */
1449 const gchar *
1450 gst_player_color_balance_type_get_name (GstPlayerColorBalanceType type)
1451 {
1452   g_return_val_if_fail (type >= GST_PLAYER_COLOR_BALANCE_BRIGHTNESS &&
1453       type <= GST_PLAYER_COLOR_BALANCE_HUE, NULL);
1454
1455   return cb_channel_map[type].name;
1456 }
1457
1458 GType
1459 gst_player_state_get_type (void)
1460 {
1461   static gsize id = 0;
1462   static const GEnumValue values[] = {
1463     {C_ENUM (GST_PLAYER_STATE_STOPPED), "GST_PLAYER_STATE_STOPPED", "stopped"},
1464     {C_ENUM (GST_PLAYER_STATE_BUFFERING), "GST_PLAYER_STATE_BUFFERING",
1465         "buffering"},
1466     {C_ENUM (GST_PLAYER_STATE_PAUSED), "GST_PLAYER_STATE_PAUSED", "paused"},
1467     {C_ENUM (GST_PLAYER_STATE_PLAYING), "GST_PLAYER_STATE_PLAYING", "playing"},
1468     {0, NULL, NULL}
1469   };
1470
1471   if (g_once_init_enter (&id)) {
1472     GType tmp = g_enum_register_static ("GstPlayerState", values);
1473     g_once_init_leave (&id, tmp);
1474   }
1475
1476   return (GType) id;
1477 }
1478
1479 /**
1480  * gst_player_state_get_name:
1481  * @state: a #GstPlayerState
1482  *
1483  * Gets a string representing the given state.
1484  *
1485  * Returns: (transfer none): a string with the name of the state.
1486  */
1487 const gchar *
1488 gst_player_state_get_name (GstPlayerState state)
1489 {
1490   switch (state) {
1491     case GST_PLAYER_STATE_STOPPED:
1492       return "stopped";
1493     case GST_PLAYER_STATE_BUFFERING:
1494       return "buffering";
1495     case GST_PLAYER_STATE_PAUSED:
1496       return "paused";
1497     case GST_PLAYER_STATE_PLAYING:
1498       return "playing";
1499   }
1500
1501   g_assert_not_reached ();
1502   return NULL;
1503 }
1504
1505 GType
1506 gst_player_error_get_type (void)
1507 {
1508   static gsize id = 0;
1509   static const GEnumValue values[] = {
1510     {C_ENUM (GST_PLAYER_ERROR_FAILED), "GST_PLAYER_ERROR_FAILED", "failed"},
1511     {0, NULL, NULL}
1512   };
1513
1514   if (g_once_init_enter (&id)) {
1515     GType tmp = g_enum_register_static ("GstPlayerError", values);
1516     g_once_init_leave (&id, tmp);
1517   }
1518
1519   return (GType) id;
1520 }
1521
1522 /**
1523  * gst_player_error_get_name:
1524  * @error: a #GstPlayerError
1525  *
1526  * Gets a string representing the given error.
1527  *
1528  * Returns: (transfer none): a string with the given error.
1529  */
1530 const gchar *
1531 gst_player_error_get_name (GstPlayerError error)
1532 {
1533   switch (error) {
1534     case GST_PLAYER_ERROR_FAILED:
1535       return "failed";
1536   }
1537
1538   g_assert_not_reached ();
1539   return NULL;
1540 }
1541
1542 /**
1543  * gst_player_set_config:
1544  * @player: #GstPlayer instance
1545  * @config: (transfer full): a #GstStructure
1546  *
1547  * Set the configuration of the player. If the player is already configured, and
1548  * the configuration haven't change, this function will return %TRUE. If the
1549  * player is not in the GST_PLAYER_STATE_STOPPED, this method will return %FALSE
1550  * and active configuration will remain.
1551  *
1552  * @config is a #GstStructure that contains the configuration parameters for
1553  * the player.
1554  *
1555  * This function takes ownership of @config.
1556  *
1557  * Returns: %TRUE when the configuration could be set.
1558  * Since: 1.10
1559  */
1560 gboolean
1561 gst_player_set_config (GstPlayer * self, GstStructure * config)
1562 {
1563   g_return_val_if_fail (GST_IS_PLAYER (self), FALSE);
1564   g_return_val_if_fail (config != NULL, FALSE);
1565
1566   return gst_play_set_config (self->play, config);
1567 }
1568
1569 /**
1570  * gst_player_get_config:
1571  * @player: #GstPlayer instance
1572  *
1573  * Get a copy of the current configuration of the player. This configuration
1574  * can either be modified and used for the gst_player_set_config() call
1575  * or it must be freed after usage.
1576  *
1577  * Returns: (transfer full): a copy of the current configuration of @player. Use
1578  * gst_structure_free() after usage or gst_player_set_config().
1579  *
1580  * Since: 1.10
1581  */
1582 GstStructure *
1583 gst_player_get_config (GstPlayer * self)
1584 {
1585   g_return_val_if_fail (GST_IS_PLAYER (self), NULL);
1586
1587   return gst_play_get_config (self->play);
1588 }
1589
1590 /**
1591  * gst_player_config_set_user_agent:
1592  * @config: a #GstPlayer configuration
1593  * @agent: (nullable): the string to use as user agent
1594  *
1595  * Set the user agent to pass to the server if @player needs to connect
1596  * to a server during playback. This is typically used when playing HTTP
1597  * or RTSP streams.
1598  *
1599  * Since: 1.10
1600  */
1601 void
1602 gst_player_config_set_user_agent (GstStructure * config, const gchar * agent)
1603 {
1604   g_return_if_fail (config != NULL);
1605   g_return_if_fail (agent != NULL);
1606
1607   gst_structure_id_set (config,
1608       CONFIG_QUARK (USER_AGENT), G_TYPE_STRING, agent, NULL);
1609 }
1610
1611 /**
1612  * gst_player_config_get_user_agent:
1613  * @config: a #GstPlayer configuration
1614  *
1615  * Return the user agent which has been configured using
1616  * gst_player_config_set_user_agent() if any.
1617  *
1618  * Returns: (transfer full) (nullable): the configured agent, or %NULL
1619  *
1620  * Since: 1.10
1621  */
1622 gchar *
1623 gst_player_config_get_user_agent (const GstStructure * config)
1624 {
1625   gchar *agent = NULL;
1626
1627   g_return_val_if_fail (config != NULL, NULL);
1628
1629   gst_structure_id_get (config,
1630       CONFIG_QUARK (USER_AGENT), G_TYPE_STRING, &agent, NULL);
1631
1632   return agent;
1633 }
1634
1635 /**
1636  * gst_player_config_set_position_update_interval:
1637  * @config: a #GstPlayer configuration
1638  * @interval: interval in ms
1639  *
1640  * set interval in milliseconds between two position-updated signals.
1641  * pass 0 to stop updating the position.
1642  *
1643  * Since: 1.10
1644  */
1645 void
1646 gst_player_config_set_position_update_interval (GstStructure * config,
1647     guint interval)
1648 {
1649   g_return_if_fail (config != NULL);
1650   g_return_if_fail (interval <= 10000);
1651
1652   gst_structure_id_set (config,
1653       CONFIG_QUARK (POSITION_INTERVAL_UPDATE), G_TYPE_UINT, interval, NULL);
1654 }
1655
1656 /**
1657  * gst_player_config_get_position_update_interval:
1658  * @config: a #GstPlayer configuration
1659  *
1660  * Returns: current position update interval in milliseconds
1661  *
1662  * Since: 1.10
1663  */
1664 guint
1665 gst_player_config_get_position_update_interval (const GstStructure * config)
1666 {
1667   guint interval = DEFAULT_POSITION_UPDATE_INTERVAL_MS;
1668
1669   g_return_val_if_fail (config != NULL, DEFAULT_POSITION_UPDATE_INTERVAL_MS);
1670
1671   gst_structure_id_get (config,
1672       CONFIG_QUARK (POSITION_INTERVAL_UPDATE), G_TYPE_UINT, &interval, NULL);
1673
1674   return interval;
1675 }
1676
1677 /**
1678  * gst_player_config_set_seek_accurate:
1679  * @config: a #GstPlayer configuration
1680  * @accurate: accurate seek or not
1681  *
1682  * Enable or disable accurate seeking. When enabled, elements will try harder
1683  * to seek as accurately as possible to the requested seek position. Generally
1684  * it will be slower especially for formats that don't have any indexes or
1685  * timestamp markers in the stream.
1686  *
1687  * If accurate seeking is disabled, elements will seek as close as the request
1688  * position without slowing down seeking too much.
1689  *
1690  * Accurate seeking is disabled by default.
1691  *
1692  * Since: 1.12
1693  */
1694 void
1695 gst_player_config_set_seek_accurate (GstStructure * config, gboolean accurate)
1696 {
1697   g_return_if_fail (config != NULL);
1698
1699   gst_structure_id_set (config,
1700       CONFIG_QUARK (ACCURATE_SEEK), G_TYPE_BOOLEAN, accurate, NULL);
1701 }
1702
1703 /**
1704  * gst_player_config_get_seek_accurate:
1705  * @config: a #GstPlayer configuration
1706  *
1707  * Returns: %TRUE if accurate seeking is enabled
1708  *
1709  * Since: 1.12
1710  */
1711 gboolean
1712 gst_player_config_get_seek_accurate (const GstStructure * config)
1713 {
1714   gboolean accurate = FALSE;
1715
1716   g_return_val_if_fail (config != NULL, FALSE);
1717
1718   gst_structure_id_get (config,
1719       CONFIG_QUARK (ACCURATE_SEEK), G_TYPE_BOOLEAN, &accurate, NULL);
1720
1721   return accurate;
1722 }
1723
1724 /**
1725  * gst_player_get_video_snapshot:
1726  * @player: #GstPlayer instance
1727  * @format: output format of the video snapshot
1728  * @config: (allow-none): Additional configuration
1729  *
1730  * Get a snapshot of the currently selected video stream, if any. The format can be
1731  * selected with @format and optional configuration is possible with @config
1732  * Currently supported settings are:
1733  * - width, height of type G_TYPE_INT
1734  * - pixel-aspect-ratio of type GST_TYPE_FRACTION
1735  *  Except for GST_PLAYER_THUMBNAIL_RAW_NATIVE format, if no config is set, pixel-aspect-ratio would be 1/1
1736  *
1737  * Returns: (transfer full) (nullable):  Current video snapshot sample or %NULL on failure
1738  *
1739  * Since: 1.12
1740  */
1741 GstSample *
1742 gst_player_get_video_snapshot (GstPlayer * self,
1743     GstPlayerSnapshotFormat format, const GstStructure * config)
1744 {
1745   g_return_val_if_fail (GST_IS_PLAYER (self), NULL);
1746
1747   return gst_play_get_video_snapshot (self->play,
1748       (GstPlaySnapshotFormat) format, config);
1749 }