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