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