gstreamer/subprojects/gst-plugins-bad/gst-libs/gst/player/gstplayer.c
Sebastian Dröge 6b22f53fa9 player: Without dispatcher emit signals directly instead of via the default main context
This is how it was documented and how it worked before the port to GstPlay.

Without this, applications expecting signals to be emitted directly
without anything running the main context will simply not receive any
signals.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5672>
2023-11-15 17:16:36 +00:00

1768 lines
46 KiB
C

/* GStreamer
*
* Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
* Copyright (C) 2015 Brijesh Singh <brijesh.ksingh@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:gstplayer
* @title: GstPlayer
* @short_description: Player
* @symbols:
* - GstPlayer
*
* Starting from GStreamer 1.20, application developers are strongly advised to migrate to #GstPlay.
* #GstPlayer will be deprecated in 1.20 and most likely removed by 1.24.
*/
/* TODO:
*
* - Equalizer
* - Gapless playback
* - Frame stepping
* - Subtitle font, connection speed
* - Deinterlacing
* - Buffering control (-> progressive downloading)
* - Playlist/queue object
* - Custom video sink (e.g. embed in GL scene)
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstplayer.h"
#include "gstplayer-signal-dispatcher-private.h"
#include "gstplayer-video-renderer-private.h"
#include "gstplayer-media-info-private.h"
#include "gstplayer-wrapped-video-renderer-private.h"
#include <gst/gst.h>
#include <gst/play/play.h>
#include <gst/video/video.h>
#include <gst/video/colorbalance.h>
#include <gst/tag/tag.h>
#include <gst/pbutils/descriptions.h>
#include <string.h>
GST_DEBUG_CATEGORY_STATIC (gst_player_debug);
#define GST_CAT_DEFAULT gst_player_debug
#define DEFAULT_URI NULL
#define DEFAULT_POSITION GST_CLOCK_TIME_NONE
#define DEFAULT_DURATION GST_CLOCK_TIME_NONE
#define DEFAULT_VOLUME 1.0
#define DEFAULT_MUTE FALSE
#define DEFAULT_RATE 1.0
#define DEFAULT_POSITION_UPDATE_INTERVAL_MS 100
#define DEFAULT_AUDIO_VIDEO_OFFSET 0
#define DEFAULT_SUBTITLE_VIDEO_OFFSET 0
/**
* gst_player_error_quark:
*/
GQuark
gst_player_error_quark (void)
{
return g_quark_from_static_string ("gst-player-error-quark");
}
static GQuark QUARK_CONFIG;
/* Keep ConfigQuarkId and _config_quark_strings ordered and synced */
typedef enum
{
CONFIG_QUARK_USER_AGENT = 0,
CONFIG_QUARK_POSITION_INTERVAL_UPDATE,
CONFIG_QUARK_ACCURATE_SEEK,
CONFIG_QUARK_MAX
} ConfigQuarkId;
static const gchar *_config_quark_strings[] = {
"user-agent",
"position-interval-update",
"accurate-seek",
};
static GQuark _config_quark_table[CONFIG_QUARK_MAX];
#define CONFIG_QUARK(q) _config_quark_table[CONFIG_QUARK_##q]
enum
{
PROP_0,
PROP_VIDEO_RENDERER,
PROP_SIGNAL_DISPATCHER,
PROP_URI,
PROP_SUBURI,
PROP_POSITION,
PROP_DURATION,
PROP_MEDIA_INFO,
PROP_CURRENT_AUDIO_TRACK,
PROP_CURRENT_VIDEO_TRACK,
PROP_CURRENT_SUBTITLE_TRACK,
PROP_VOLUME,
PROP_MUTE,
PROP_RATE,
PROP_PIPELINE,
PROP_VIDEO_MULTIVIEW_MODE,
PROP_VIDEO_MULTIVIEW_FLAGS,
PROP_AUDIO_VIDEO_OFFSET,
PROP_SUBTITLE_VIDEO_OFFSET,
PROP_LAST
};
enum
{
SIGNAL_URI_LOADED,
SIGNAL_POSITION_UPDATED,
SIGNAL_DURATION_CHANGED,
SIGNAL_STATE_CHANGED,
SIGNAL_BUFFERING,
SIGNAL_END_OF_STREAM,
SIGNAL_ERROR,
SIGNAL_WARNING,
SIGNAL_VIDEO_DIMENSIONS_CHANGED,
SIGNAL_MEDIA_INFO_UPDATED,
SIGNAL_VOLUME_CHANGED,
SIGNAL_MUTE_CHANGED,
SIGNAL_SEEK_DONE,
SIGNAL_LAST
};
struct _GstPlayer
{
GstObject parent;
GstPlay *play;
GstPlaySignalAdapter *signal_adapter;
/* legacy */
GstPlayerSignalDispatcher *signal_dispatcher;
GstPlayerVideoRenderer *video_renderer;
};
struct _GstPlayerClass
{
GstObjectClass parent_class;
};
#define parent_class gst_player_parent_class
G_DEFINE_TYPE (GstPlayer, gst_player, GST_TYPE_OBJECT);
static guint signals[SIGNAL_LAST] = { 0, };
static GParamSpec *param_specs[PROP_LAST] = { NULL, };
static void gst_player_finalize (GObject * object);
static void gst_player_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_player_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_player_constructed (GObject * object);
static void
gst_player_init (GstPlayer * self)
{
self->play = gst_play_new (NULL);
}
static void
config_quark_initialize (void)
{
gint i;
QUARK_CONFIG = g_quark_from_static_string ("player-config");
if (G_N_ELEMENTS (_config_quark_strings) != CONFIG_QUARK_MAX)
g_warning ("the quark table is not consistent! %d != %d",
(int) G_N_ELEMENTS (_config_quark_strings), CONFIG_QUARK_MAX);
for (i = 0; i < CONFIG_QUARK_MAX; i++) {
_config_quark_table[i] =
g_quark_from_static_string (_config_quark_strings[i]);
}
}
static void
gst_player_class_init (GstPlayerClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
gobject_class->set_property = gst_player_set_property;
gobject_class->get_property = gst_player_get_property;
gobject_class->finalize = gst_player_finalize;
gobject_class->constructed = gst_player_constructed;
param_specs[PROP_VIDEO_RENDERER] =
g_param_spec_object ("video-renderer",
"Video Renderer", "Video renderer to use for rendering videos",
GST_TYPE_PLAYER_VIDEO_RENDERER,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
param_specs[PROP_SIGNAL_DISPATCHER] =
g_param_spec_object ("signal-dispatcher",
"Signal Dispatcher", "Dispatcher for the signals to e.g. event loops",
GST_TYPE_PLAYER_SIGNAL_DISPATCHER,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
param_specs[PROP_URI] = g_param_spec_string ("uri", "URI", "Current URI",
DEFAULT_URI, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
param_specs[PROP_SUBURI] = g_param_spec_string ("suburi", "Subtitle URI",
"Current Subtitle URI", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
param_specs[PROP_POSITION] =
g_param_spec_uint64 ("position", "Position", "Current Position",
0, G_MAXUINT64, DEFAULT_POSITION,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
param_specs[PROP_MEDIA_INFO] =
g_param_spec_object ("media-info", "Media Info",
"Current media information", GST_TYPE_PLAYER_MEDIA_INFO,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
param_specs[PROP_CURRENT_AUDIO_TRACK] =
g_param_spec_object ("current-audio-track", "Current Audio Track",
"Current audio track information", GST_TYPE_PLAYER_AUDIO_INFO,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
param_specs[PROP_CURRENT_VIDEO_TRACK] =
g_param_spec_object ("current-video-track", "Current Video Track",
"Current video track information", GST_TYPE_PLAYER_VIDEO_INFO,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
param_specs[PROP_CURRENT_SUBTITLE_TRACK] =
g_param_spec_object ("current-subtitle-track", "Current Subtitle Track",
"Current audio subtitle information", GST_TYPE_PLAYER_SUBTITLE_INFO,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
param_specs[PROP_DURATION] =
g_param_spec_uint64 ("duration", "Duration", "Duration",
0, G_MAXUINT64, DEFAULT_DURATION,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
param_specs[PROP_VOLUME] =
g_param_spec_double ("volume", "Volume", "Volume",
0, 10.0, DEFAULT_VOLUME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
param_specs[PROP_MUTE] =
g_param_spec_boolean ("mute", "Mute", "Mute",
DEFAULT_MUTE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
param_specs[PROP_PIPELINE] =
g_param_spec_object ("pipeline", "Pipeline",
"GStreamer pipeline that is used",
GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
param_specs[PROP_RATE] =
g_param_spec_double ("rate", "rate", "Playback rate",
-64.0, 64.0, DEFAULT_RATE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
param_specs[PROP_VIDEO_MULTIVIEW_MODE] =
g_param_spec_enum ("video-multiview-mode",
"Multiview Mode Override",
"Re-interpret a video stream as one of several frame-packed stereoscopic modes.",
GST_TYPE_VIDEO_MULTIVIEW_FRAME_PACKING,
GST_VIDEO_MULTIVIEW_FRAME_PACKING_NONE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
param_specs[PROP_VIDEO_MULTIVIEW_FLAGS] =
g_param_spec_flags ("video-multiview-flags",
"Multiview Flags Override",
"Override details of the multiview frame layout",
GST_TYPE_VIDEO_MULTIVIEW_FLAGS, GST_VIDEO_MULTIVIEW_FLAGS_NONE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
param_specs[PROP_AUDIO_VIDEO_OFFSET] =
g_param_spec_int64 ("audio-video-offset", "Audio Video Offset",
"The synchronisation offset between audio and video in nanoseconds",
G_MININT64, G_MAXINT64, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
param_specs[PROP_SUBTITLE_VIDEO_OFFSET] =
g_param_spec_int64 ("subtitle-video-offset", "Text Video Offset",
"The synchronisation offset between text and video in nanoseconds",
G_MININT64, G_MAXINT64, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, PROP_LAST, param_specs);
signals[SIGNAL_URI_LOADED] =
g_signal_new ("uri-loaded", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
NULL, NULL, G_TYPE_NONE, 1, G_TYPE_STRING);
signals[SIGNAL_POSITION_UPDATED] =
g_signal_new ("position-updated", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_CLOCK_TIME);
signals[SIGNAL_DURATION_CHANGED] =
g_signal_new ("duration-changed", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_CLOCK_TIME);
signals[SIGNAL_STATE_CHANGED] =
g_signal_new ("state-changed", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_PLAYER_STATE);
signals[SIGNAL_BUFFERING] =
g_signal_new ("buffering", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
NULL, NULL, G_TYPE_NONE, 1, G_TYPE_INT);
signals[SIGNAL_END_OF_STREAM] =
g_signal_new ("end-of-stream", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
NULL, NULL, G_TYPE_NONE, 0, G_TYPE_INVALID);
signals[SIGNAL_ERROR] =
g_signal_new ("error", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
NULL, NULL, G_TYPE_NONE, 1, G_TYPE_ERROR);
signals[SIGNAL_VIDEO_DIMENSIONS_CHANGED] =
g_signal_new ("video-dimensions-changed", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
NULL, NULL, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
signals[SIGNAL_MEDIA_INFO_UPDATED] =
g_signal_new ("media-info-updated", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_PLAYER_MEDIA_INFO);
signals[SIGNAL_VOLUME_CHANGED] =
g_signal_new ("volume-changed", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
NULL, NULL, G_TYPE_NONE, 0, G_TYPE_INVALID);
signals[SIGNAL_MUTE_CHANGED] =
g_signal_new ("mute-changed", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
NULL, NULL, G_TYPE_NONE, 0, G_TYPE_INVALID);
signals[SIGNAL_WARNING] =
g_signal_new ("warning", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
NULL, NULL, G_TYPE_NONE, 1, G_TYPE_ERROR);
signals[SIGNAL_SEEK_DONE] =
g_signal_new ("seek-done", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_CLOCK_TIME);
config_quark_initialize ();
}
static void
gst_player_finalize (GObject * object)
{
GstPlayer *self = GST_PLAYER (object);
GST_TRACE_OBJECT (self, "Finalizing");
if (self->signal_dispatcher)
g_object_unref (self->signal_dispatcher);
if (self->video_renderer)
g_object_unref (self->video_renderer);
if (self->signal_adapter)
g_object_unref (self->signal_adapter);
if (self->play)
gst_object_unref (self->play);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gst_player_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstPlayer *self = GST_PLAYER (object);
switch (prop_id) {
case PROP_SIGNAL_DISPATCHER:
self->signal_dispatcher = g_value_dup_object (value);
break;
case PROP_VIDEO_RENDERER:
self->video_renderer = g_value_dup_object (value);
break;
default:
g_object_set_property (G_OBJECT (self->play),
g_param_spec_get_name (pspec), value);
break;
}
}
static void
gst_player_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstPlayer *self = GST_PLAYER (object);
switch (prop_id) {
case PROP_VIDEO_RENDERER:
g_value_set_object (value, self->video_renderer);
break;
case PROP_MEDIA_INFO:
g_value_take_object (value, gst_player_get_media_info (self));
break;
case PROP_CURRENT_AUDIO_TRACK:
g_value_take_object (value, gst_player_get_current_audio_track (self));
break;
case PROP_CURRENT_VIDEO_TRACK:
g_value_take_object (value, gst_player_get_current_video_track (self));
break;
case PROP_CURRENT_SUBTITLE_TRACK:
g_value_take_object (value, gst_player_get_current_subtitle_track (self));
break;
default:
g_object_get_property (G_OBJECT (self->play),
g_param_spec_get_name (pspec), value);
break;
}
}
static gpointer
gst_player_init_once (G_GNUC_UNUSED gpointer user_data)
{
gst_init (NULL, NULL);
GST_DEBUG_CATEGORY_INIT (gst_player_debug, "gst-player", 0, "GstPlayer");
gst_player_error_quark ();
return NULL;
}
static void
uri_loaded_cb (GstPlaySignalAdapter * adapter, const gchar * uri,
GstPlayer * self)
{
g_signal_emit (self, signals[SIGNAL_URI_LOADED], 0, uri);
}
static void
position_updated_cb (GstPlaySignalAdapter * adapter, GstClockTime position,
GstPlayer * self)
{
g_signal_emit (self, signals[SIGNAL_POSITION_UPDATED], 0, position);
}
static void
duration_changed_cb (GstPlaySignalAdapter * adapter, GstClockTime duraton,
GstPlayer * self)
{
g_signal_emit (self, signals[SIGNAL_DURATION_CHANGED], 0, duraton);
}
static void
state_changed_cb (GstPlaySignalAdapter * adapter, GstPlayState state,
GstPlayer * self)
{
GstPlayerState s = GST_PLAYER_STATE_BUFFERING;
switch (state) {
case GST_PLAY_STATE_BUFFERING:
s = GST_PLAYER_STATE_BUFFERING;
break;
case GST_PLAY_STATE_PAUSED:
s = GST_PLAYER_STATE_PAUSED;
break;
case GST_PLAY_STATE_PLAYING:
s = GST_PLAYER_STATE_PLAYING;
break;
case GST_PLAY_STATE_STOPPED:
s = GST_PLAYER_STATE_STOPPED;
break;
}
g_signal_emit (self, signals[SIGNAL_STATE_CHANGED], 0, s);
}
static void
buffering_cb (GstPlaySignalAdapter * adapter, gint buffering_percent,
GstPlayer * self)
{
g_signal_emit (self, signals[SIGNAL_BUFFERING], 0, buffering_percent);
}
static void
end_of_stream_cb (GstPlaySignalAdapter * adapter, GstPlayer * self)
{
g_signal_emit (self, signals[SIGNAL_END_OF_STREAM], 0, NULL);
}
static void
error_cb (GstPlaySignalAdapter * adapter, GError * error,
GstStructure * details, GstPlayer * self)
{
g_signal_emit (self, signals[SIGNAL_ERROR], 0, error);
}
static void
dimensions_changed_cb (GstPlaySignalAdapter * adapter, guint width,
guint height, GstPlayer * self)
{
g_signal_emit (self, signals[SIGNAL_VIDEO_DIMENSIONS_CHANGED], 0, width,
height);
}
static void
media_info_cb (GstPlaySignalAdapter * adapter, GstPlayMediaInfo * info,
GstPlayer * self)
{
GstPlayerMediaInfo *i = gst_player_media_info_wrapped (info);
g_signal_emit (self, signals[SIGNAL_MEDIA_INFO_UPDATED], 0, i);
g_object_unref (i);
}
static void
volume_cb (GstPlaySignalAdapter * adapter, gdouble volume, GstPlayer * self)
{
g_signal_emit (self, signals[SIGNAL_VOLUME_CHANGED], 0, NULL);
}
static void
mute_cb (GstPlaySignalAdapter * adapter, gboolean muted, GstPlayer * self)
{
g_signal_emit (self, signals[SIGNAL_MUTE_CHANGED], 0, NULL);
}
static void
warning_cb (GstPlaySignalAdapter * adapter, GError * warning,
GstStructure * details, GstPlayer * self)
{
g_signal_emit (self, signals[SIGNAL_WARNING], 0, warning);
}
static void
seek_done_cb (GstPlaySignalAdapter * adapter, GstClockTime time,
GstPlayer * self)
{
g_signal_emit (self, signals[SIGNAL_SEEK_DONE], 0, time);
}
static void
gst_player_constructed (GObject * object)
{
GstPlayer *self = GST_PLAYER (object);
GstPlayerVideoRenderer *renderer = NULL;
G_OBJECT_CLASS (parent_class)->constructed (object);
if (self->video_renderer != NULL) {
renderer =
gst_player_wrapped_video_renderer_new (self->video_renderer, self);
g_object_set (self->play, "video-renderer",
GST_PLAY_VIDEO_RENDERER (renderer), NULL);
g_object_unref (renderer);
}
if (self->signal_dispatcher != NULL) {
GMainContext *context = NULL;
g_object_get (self->signal_dispatcher, "application-context", &context,
NULL);
self->signal_adapter =
gst_play_signal_adapter_new_with_main_context (self->play, context);
g_main_context_unref (context);
} else {
self->signal_adapter = gst_play_signal_adapter_new_sync_emit (self->play);
}
g_signal_connect (self->signal_adapter, "uri-loaded",
G_CALLBACK (uri_loaded_cb), self);
g_signal_connect (self->signal_adapter, "position-updated",
G_CALLBACK (position_updated_cb), self);
g_signal_connect (self->signal_adapter, "duration-changed",
G_CALLBACK (duration_changed_cb), self);
g_signal_connect (self->signal_adapter, "state-changed",
G_CALLBACK (state_changed_cb), self);
g_signal_connect (self->signal_adapter, "buffering",
G_CALLBACK (buffering_cb), self);
g_signal_connect (self->signal_adapter, "end-of-stream",
G_CALLBACK (end_of_stream_cb), self);
g_signal_connect (self->signal_adapter, "error", G_CALLBACK (error_cb), self);
g_signal_connect (self->signal_adapter, "video-dimensions-changed",
G_CALLBACK (dimensions_changed_cb), self);
g_signal_connect (self->signal_adapter, "media-info-updated",
G_CALLBACK (media_info_cb), self);
g_signal_connect (self->signal_adapter, "volume-changed",
G_CALLBACK (volume_cb), self);
g_signal_connect (self->signal_adapter, "mute-changed", G_CALLBACK (mute_cb),
self);
g_signal_connect (self->signal_adapter, "warning", G_CALLBACK (warning_cb),
self);
g_signal_connect (self->signal_adapter, "seek-done",
G_CALLBACK (seek_done_cb), self);
}
/**
* gst_player_new:
* @video_renderer: (transfer full) (allow-none): GstPlayerVideoRenderer to use
* @signal_dispatcher: (transfer full) (allow-none): GstPlayerSignalDispatcher to use
*
* Creates a new #GstPlayer instance that uses @signal_dispatcher to dispatch
* signals to some event loop system, or emits signals directly if NULL is
* passed. See gst_player_g_main_context_signal_dispatcher_new().
*
* Video is going to be rendered by @video_renderer, or if %NULL is provided
* no special video set up will be done and some default handling will be
* performed.
*
* Returns: (transfer full): a new #GstPlayer instance
*/
GstPlayer *
gst_player_new (GstPlayerVideoRenderer * video_renderer,
GstPlayerSignalDispatcher * signal_dispatcher)
{
static GOnce once = G_ONCE_INIT;
GstPlayer *self;
g_once (&once, gst_player_init_once, NULL);
self =
g_object_new (GST_TYPE_PLAYER, "signal-dispatcher", signal_dispatcher,
"video-renderer", video_renderer, NULL);
gst_object_ref_sink (self);
if (video_renderer)
g_object_unref (video_renderer);
if (signal_dispatcher)
g_object_unref (signal_dispatcher);
return self;
}
/**
* gst_player_play:
* @player: #GstPlayer instance
*
* Request to play the loaded stream.
*/
void
gst_player_play (GstPlayer * self)
{
g_return_if_fail (GST_IS_PLAYER (self));
gst_play_play (self->play);
}
/**
* gst_player_pause:
* @player: #GstPlayer instance
*
* Pauses the current stream.
*/
void
gst_player_pause (GstPlayer * self)
{
g_return_if_fail (GST_IS_PLAYER (self));
gst_play_pause (self->play);
}
/**
* gst_player_stop:
* @player: #GstPlayer instance
*
* Stops playing the current stream and resets to the first position
* in the stream.
*/
void
gst_player_stop (GstPlayer * self)
{
g_return_if_fail (GST_IS_PLAYER (self));
gst_play_stop (self->play);
}
/**
* gst_player_set_rate:
* @player: #GstPlayer instance
* @rate: playback rate
*
* Playback at specified rate
*/
void
gst_player_set_rate (GstPlayer * self, gdouble rate)
{
g_return_if_fail (GST_IS_PLAYER (self));
g_return_if_fail (rate != 0.0);
g_object_set (self, "rate", rate, NULL);
}
/**
* gst_player_get_rate:
* @player: #GstPlayer instance
*
* Returns: current playback rate
*/
gdouble
gst_player_get_rate (GstPlayer * self)
{
gdouble val;
g_return_val_if_fail (GST_IS_PLAYER (self), DEFAULT_RATE);
g_object_get (self, "rate", &val, NULL);
return val;
}
/**
* gst_player_seek:
* @player: #GstPlayer instance
* @position: position to seek in nanoseconds
*
* Seeks the currently-playing stream to the absolute @position time
* in nanoseconds.
*/
void
gst_player_seek (GstPlayer * self, GstClockTime position)
{
g_return_if_fail (GST_IS_PLAYER (self));
g_return_if_fail (GST_CLOCK_TIME_IS_VALID (position));
gst_play_seek (self->play, position);
}
/**
* gst_player_get_uri:
* @player: #GstPlayer instance
*
* Gets the URI of the currently-playing stream.
*
* Returns: (transfer full) (nullable): a string containing the URI of the
* currently-playing stream. g_free() after usage.
*/
gchar *
gst_player_get_uri (GstPlayer * self)
{
gchar *val;
g_return_val_if_fail (GST_IS_PLAYER (self), DEFAULT_URI);
g_object_get (self, "uri", &val, NULL);
return val;
}
/**
* gst_player_set_uri:
* @player: #GstPlayer instance
* @uri: (nullable): next URI to play.
*
* Sets the next URI to play.
*/
void
gst_player_set_uri (GstPlayer * self, const gchar * val)
{
g_return_if_fail (GST_IS_PLAYER (self));
g_object_set (self, "uri", val, NULL);
}
/**
* gst_player_set_subtitle_uri:
* @player: #GstPlayer instance
* @uri: (nullable): subtitle URI
*
* Sets the external subtitle URI. This should be combined with a call to
* gst_player_set_subtitle_track_enabled(@player, TRUE) so the subtitles are actually
* rendered.
*/
void
gst_player_set_subtitle_uri (GstPlayer * self, const gchar * suburi)
{
g_return_if_fail (GST_IS_PLAYER (self));
g_object_set (self, "suburi", suburi, NULL);
}
/**
* gst_player_get_subtitle_uri:
* @player: #GstPlayer instance
*
* current subtitle URI
*
* Returns: (transfer full) (nullable): URI of the current external subtitle.
* g_free() after usage.
*/
gchar *
gst_player_get_subtitle_uri (GstPlayer * self)
{
gchar *val = NULL;
g_return_val_if_fail (GST_IS_PLAYER (self), NULL);
g_object_get (self, "suburi", &val, NULL);
return val;
}
/**
* gst_player_get_position:
* @player: #GstPlayer instance
*
* Returns: the absolute position time, in nanoseconds, of the
* currently-playing stream.
*/
GstClockTime
gst_player_get_position (GstPlayer * self)
{
GstClockTime val;
g_return_val_if_fail (GST_IS_PLAYER (self), DEFAULT_POSITION);
g_object_get (self, "position", &val, NULL);
return val;
}
/**
* gst_player_get_duration:
* @player: #GstPlayer instance
*
* Retrieves the duration of the media stream that self represents.
*
* Returns: the duration of the currently-playing media stream, in
* nanoseconds.
*/
GstClockTime
gst_player_get_duration (GstPlayer * self)
{
GstClockTime val;
g_return_val_if_fail (GST_IS_PLAYER (self), DEFAULT_DURATION);
g_object_get (self, "duration", &val, NULL);
return val;
}
/**
* gst_player_get_volume:
* @player: #GstPlayer instance
*
* Returns the current volume level, as a percentage between 0 and 1.
*
* Returns: the volume as percentage between 0 and 1.
*/
gdouble
gst_player_get_volume (GstPlayer * self)
{
gdouble val;
g_return_val_if_fail (GST_IS_PLAYER (self), DEFAULT_VOLUME);
g_object_get (self, "volume", &val, NULL);
return val;
}
/**
* gst_player_set_volume:
* @player: #GstPlayer instance
* @val: the new volume level, as a percentage between 0 and 1
*
* Sets the volume level of the stream as a percentage between 0 and 1.
*
* This volume is a linear factor. For showing the volume in a GUI it
* might make sense to first convert from a different format. Volume sliders
* should usually use a cubic volume. See gst_stream_volume_convert_volume().
*/
void
gst_player_set_volume (GstPlayer * self, gdouble val)
{
g_return_if_fail (GST_IS_PLAYER (self));
g_object_set (self, "volume", val, NULL);
}
/**
* gst_player_get_mute:
* @player: #GstPlayer instance
*
* Returns: %TRUE if the currently-playing stream is muted.
*/
gboolean
gst_player_get_mute (GstPlayer * self)
{
gboolean val;
g_return_val_if_fail (GST_IS_PLAYER (self), DEFAULT_MUTE);
g_object_get (self, "mute", &val, NULL);
return val;
}
/**
* gst_player_set_mute:
* @player: #GstPlayer instance
* @val: Mute state the should be set
*
* %TRUE if the currently-playing stream should be muted.
*/
void
gst_player_set_mute (GstPlayer * self, gboolean val)
{
g_return_if_fail (GST_IS_PLAYER (self));
g_object_set (self, "mute", val, NULL);
}
/**
* gst_player_get_pipeline:
* @player: #GstPlayer instance
*
* Returns: (transfer full): The internal playbin instance.
*
* The caller should free it with g_object_unref()
*/
GstElement *
gst_player_get_pipeline (GstPlayer * self)
{
GstElement *val;
g_return_val_if_fail (GST_IS_PLAYER (self), NULL);
g_object_get (self, "pipeline", &val, NULL);
return val;
}
/**
* gst_player_get_media_info:
* @player: #GstPlayer instance
*
* A Function to get the current media info #GstPlayerMediaInfo instance.
*
* Returns: (transfer full) (nullable): media info instance.
*
* The caller should free it with g_object_unref()
*/
GstPlayerMediaInfo *
gst_player_get_media_info (GstPlayer * self)
{
GstPlayMediaInfo *info;
GstPlayerMediaInfo *ret;
g_return_val_if_fail (GST_IS_PLAYER (self), NULL);
info = gst_play_get_media_info (self->play);
if (!info)
return NULL;
ret = gst_player_media_info_wrapped (info);
g_object_unref (info);
return ret;
}
/**
* gst_player_get_current_audio_track:
* @player: #GstPlayer instance
*
* A Function to get current audio #GstPlayerAudioInfo instance.
*
* Returns: (transfer full) (nullable): current audio track.
*
* The caller should free it with g_object_unref()
*/
GstPlayerAudioInfo *
gst_player_get_current_audio_track (GstPlayer * self)
{
GstPlayAudioInfo *info;
GstPlayerAudioInfo *ret = NULL;
g_return_val_if_fail (GST_IS_PLAYER (self), NULL);
info = gst_play_get_current_audio_track (self->play);
if (info != NULL) {
ret = gst_player_audio_info_wrapped (info);
g_object_unref (info);
}
return ret;
}
/**
* gst_player_get_current_video_track:
* @player: #GstPlayer instance
*
* A Function to get current video #GstPlayerVideoInfo instance.
*
* Returns: (transfer full) (nullable): current video track.
*
* The caller should free it with g_object_unref()
*/
GstPlayerVideoInfo *
gst_player_get_current_video_track (GstPlayer * self)
{
GstPlayVideoInfo *info;
GstPlayerVideoInfo *ret = NULL;
g_return_val_if_fail (GST_IS_PLAYER (self), NULL);
info = gst_play_get_current_video_track (self->play);
if (info != NULL) {
ret = gst_player_video_info_wrapped (info);
g_object_unref (info);
}
return ret;
}
/**
* gst_player_get_current_subtitle_track:
* @player: #GstPlayer instance
*
* A Function to get current subtitle #GstPlayerSubtitleInfo instance.
*
* Returns: (transfer full) (nullable): current subtitle track.
*
* The caller should free it with g_object_unref()
*/
GstPlayerSubtitleInfo *
gst_player_get_current_subtitle_track (GstPlayer * self)
{
GstPlaySubtitleInfo *info;
GstPlayerSubtitleInfo *ret = NULL;
g_return_val_if_fail (GST_IS_PLAYER (self), NULL);
info = gst_play_get_current_subtitle_track (self->play);
if (info != NULL) {
ret = gst_player_subtitle_info_wrapped (info);
g_object_unref (info);
}
return ret;
}
/**
* gst_player_set_audio_track:
* @player: #GstPlayer instance
* @stream_index: stream index
*
* Returns: %TRUE or %FALSE
*
* Sets the audio track @stream_idex.
*/
gboolean
gst_player_set_audio_track (GstPlayer * self, gint stream_index)
{
g_return_val_if_fail (GST_IS_PLAYER (self), 0);
return gst_play_set_audio_track (self->play, stream_index);
}
/**
* gst_player_set_video_track:
* @player: #GstPlayer instance
* @stream_index: stream index
*
* Returns: %TRUE or %FALSE
*
* Sets the video track @stream_index.
*/
gboolean
gst_player_set_video_track (GstPlayer * self, gint stream_index)
{
g_return_val_if_fail (GST_IS_PLAYER (self), 0);
return gst_play_set_video_track (self->play, stream_index);
}
/**
* gst_player_set_subtitle_track:
* @player: #GstPlayer instance
* @stream_index: stream index
*
* Returns: %TRUE or %FALSE
*
* Sets the subtitle stack @stream_index.
*/
gboolean
gst_player_set_subtitle_track (GstPlayer * self, gint stream_index)
{
g_return_val_if_fail (GST_IS_PLAYER (self), 0);
return gst_play_set_subtitle_track (self->play, stream_index);
}
/**
* gst_player_set_audio_track_enabled:
* @player: #GstPlayer instance
* @enabled: TRUE or FALSE
*
* Enable or disable the current audio track.
*/
void
gst_player_set_audio_track_enabled (GstPlayer * self, gboolean enabled)
{
g_return_if_fail (GST_IS_PLAYER (self));
gst_play_set_audio_track_enabled (self->play, enabled);
}
/**
* gst_player_set_video_track_enabled:
* @player: #GstPlayer instance
* @enabled: TRUE or FALSE
*
* Enable or disable the current video track.
*/
void
gst_player_set_video_track_enabled (GstPlayer * self, gboolean enabled)
{
g_return_if_fail (GST_IS_PLAYER (self));
gst_play_set_video_track_enabled (self->play, enabled);
}
/**
* gst_player_set_subtitle_track_enabled:
* @player: #GstPlayer instance
* @enabled: TRUE or FALSE
*
* Enable or disable the current subtitle track.
*/
void
gst_player_set_subtitle_track_enabled (GstPlayer * self, gboolean enabled)
{
g_return_if_fail (GST_IS_PLAYER (self));
gst_play_set_subtitle_track_enabled (self->play, enabled);
}
/**
* gst_player_set_visualization:
* @player: #GstPlayer instance
* @name: (nullable): visualization element obtained from
* #gst_player_visualizations_get()
*
* Returns: %TRUE if the visualizations was set correctly. Otherwise,
* %FALSE.
*/
gboolean
gst_player_set_visualization (GstPlayer * self, const gchar * name)
{
g_return_val_if_fail (GST_IS_PLAYER (self), FALSE);
return gst_play_set_visualization (self->play, name);
}
/**
* gst_player_get_current_visualization:
* @player: #GstPlayer instance
*
* Returns: (transfer full) (nullable): Name of the currently enabled
* visualization.
* g_free() after usage.
*/
gchar *
gst_player_get_current_visualization (GstPlayer * self)
{
g_return_val_if_fail (GST_IS_PLAYER (self), NULL);
return gst_play_get_current_visualization (self->play);
}
/**
* gst_player_set_visualization_enabled:
* @player: #GstPlayer instance
* @enabled: TRUE or FALSE
*
* Enable or disable the visualization.
*/
void
gst_player_set_visualization_enabled (GstPlayer * self, gboolean enabled)
{
g_return_if_fail (GST_IS_PLAYER (self));
gst_play_set_visualization_enabled (self->play, enabled);
}
struct CBChannelMap
{
const gchar *label; /* channel label name */
const gchar *name; /* get_name () */
};
static const struct CBChannelMap cb_channel_map[] = {
/* GST_PLAYER_COLOR_BALANCE_BRIGHTNESS */ {"BRIGHTNESS", "brightness"},
/* GST_PLAYER_COLOR_BALANCE_CONTRAST */ {"CONTRAST", "contrast"},
/* GST_PLAYER_COLOR_BALANCE_SATURATION */ {"SATURATION", "saturation"},
/* GST_PLAYER_COLOR_BALANCE_HUE */ {"HUE", "hue"},
};
/**
* gst_player_has_color_balance:
* @player:#GstPlayer instance
*
* Checks whether the @player has color balance support available.
*
* Returns: %TRUE if @player has color balance support. Otherwise,
* %FALSE.
*/
gboolean
gst_player_has_color_balance (GstPlayer * self)
{
g_return_val_if_fail (GST_IS_PLAYER (self), FALSE);
return gst_play_has_color_balance (self->play);
}
/**
* gst_player_set_color_balance:
* @player: #GstPlayer instance
* @type: #GstPlayerColorBalanceType
* @value: The new value for the @type, ranged [0,1]
*
* Sets the current value of the indicated channel @type to the passed
* value.
*/
void
gst_player_set_color_balance (GstPlayer * self, GstPlayerColorBalanceType type,
gdouble value)
{
g_return_if_fail (GST_IS_PLAYER (self));
g_return_if_fail (value >= 0.0 && value <= 1.0);
gst_play_set_color_balance (self->play, (GstPlayColorBalanceType) type,
value);
}
/**
* gst_player_get_color_balance:
* @player: #GstPlayer instance
* @type: #GstPlayerColorBalanceType
*
* Retrieve the current value of the indicated @type.
*
* Returns: The current value of @type, between [0,1]. In case of
* error -1 is returned.
*/
gdouble
gst_player_get_color_balance (GstPlayer * self, GstPlayerColorBalanceType type)
{
g_return_val_if_fail (GST_IS_PLAYER (self), -1);
return gst_play_get_color_balance (self->play,
(GstPlayColorBalanceType) type);
}
/**
* gst_player_get_multiview_mode:
* @player: #GstPlayer instance
*
* Retrieve the current value of the indicated @type.
*
* Returns: The current value of @type, Default: -1 "none"
*
* Since: 1.10
*/
GstVideoMultiviewFramePacking
gst_player_get_multiview_mode (GstPlayer * self)
{
GstVideoMultiviewFramePacking val = GST_VIDEO_MULTIVIEW_FRAME_PACKING_NONE;
g_return_val_if_fail (GST_IS_PLAYER (self),
GST_VIDEO_MULTIVIEW_FRAME_PACKING_NONE);
g_object_get (self, "video-multiview-mode", &val, NULL);
return val;
}
/**
* gst_player_set_multiview_mode:
* @player: #GstPlayer instance
* @mode: The new value for the @type
*
* Sets the current value of the indicated mode @type to the passed
* value.
*
* Since: 1.10
*/
void
gst_player_set_multiview_mode (GstPlayer * self,
GstVideoMultiviewFramePacking mode)
{
g_return_if_fail (GST_IS_PLAYER (self));
g_object_set (self, "video-multiview-mode", mode, NULL);
}
/**
* gst_player_get_multiview_flags:
* @player: #GstPlayer instance
*
* Retrieve the current value of the indicated @type.
*
* Returns: The current value of @type, Default: 0x00000000 "none
*
* Since: 1.10
*/
GstVideoMultiviewFlags
gst_player_get_multiview_flags (GstPlayer * self)
{
GstVideoMultiviewFlags val = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
g_return_val_if_fail (GST_IS_PLAYER (self), val);
g_object_get (self, "video-multiview-flags", &val, NULL);
return val;
}
/**
* gst_player_set_multiview_flags:
* @player: #GstPlayer instance
* @flags: The new value for the @type
*
* Sets the current value of the indicated mode @type to the passed
* value.
*
* Since: 1.10
*/
void
gst_player_set_multiview_flags (GstPlayer * self, GstVideoMultiviewFlags flags)
{
g_return_if_fail (GST_IS_PLAYER (self));
g_object_set (self, "video-multiview-flags", flags, NULL);
}
/**
* gst_player_get_audio_video_offset:
* @player: #GstPlayer instance
*
* Retrieve the current value of audio-video-offset property
*
* Returns: The current value of audio-video-offset in nanoseconds
*
* Since: 1.10
*/
gint64
gst_player_get_audio_video_offset (GstPlayer * self)
{
gint64 val = 0;
g_return_val_if_fail (GST_IS_PLAYER (self), DEFAULT_AUDIO_VIDEO_OFFSET);
g_object_get (self, "audio-video-offset", &val, NULL);
return val;
}
/**
* gst_player_set_audio_video_offset:
* @player: #GstPlayer instance
* @offset: #gint64 in nanoseconds
*
* Sets audio-video-offset property by value of @offset
*
* Since: 1.10
*/
void
gst_player_set_audio_video_offset (GstPlayer * self, gint64 offset)
{
g_return_if_fail (GST_IS_PLAYER (self));
g_object_set (self, "audio-video-offset", offset, NULL);
}
/**
* gst_player_get_subtitle_video_offset:
* @player: #GstPlayer instance
*
* Retrieve the current value of subtitle-video-offset property
*
* Returns: The current value of subtitle-video-offset in nanoseconds
*
* Since: 1.16
*/
gint64
gst_player_get_subtitle_video_offset (GstPlayer * self)
{
gint64 val = 0;
g_return_val_if_fail (GST_IS_PLAYER (self), DEFAULT_SUBTITLE_VIDEO_OFFSET);
g_object_get (self, "subtitle-video-offset", &val, NULL);
return val;
}
/**
* gst_player_set_subtitle_video_offset:
* @player: #GstPlayer instance
* @offset: #gint64 in nanoseconds
*
* Sets subtitle-video-offset property by value of @offset
*
* Since: 1.16
*/
void
gst_player_set_subtitle_video_offset (GstPlayer * self, gint64 offset)
{
g_return_if_fail (GST_IS_PLAYER (self));
g_object_set (self, "subtitle-video-offset", offset, NULL);
}
#define C_ENUM(v) ((gint) v)
#define C_FLAGS(v) ((guint) v)
GType
gst_player_color_balance_type_get_type (void)
{
static gsize id = 0;
static const GEnumValue values[] = {
{C_ENUM (GST_PLAYER_COLOR_BALANCE_HUE), "GST_PLAYER_COLOR_BALANCE_HUE",
"hue"},
{C_ENUM (GST_PLAYER_COLOR_BALANCE_BRIGHTNESS),
"GST_PLAYER_COLOR_BALANCE_BRIGHTNESS", "brightness"},
{C_ENUM (GST_PLAYER_COLOR_BALANCE_SATURATION),
"GST_PLAYER_COLOR_BALANCE_SATURATION", "saturation"},
{C_ENUM (GST_PLAYER_COLOR_BALANCE_CONTRAST),
"GST_PLAYER_COLOR_BALANCE_CONTRAST", "contrast"},
{0, NULL, NULL}
};
if (g_once_init_enter (&id)) {
GType tmp = g_enum_register_static ("GstPlayerColorBalanceType", values);
g_once_init_leave (&id, tmp);
}
return (GType) id;
}
/**
* gst_player_color_balance_type_get_name:
* @type: a #GstPlayerColorBalanceType
*
* Gets a string representing the given color balance type.
*
* Returns: (transfer none): a string with the name of the color
* balance type.
*/
const gchar *
gst_player_color_balance_type_get_name (GstPlayerColorBalanceType type)
{
g_return_val_if_fail (type >= GST_PLAYER_COLOR_BALANCE_BRIGHTNESS &&
type <= GST_PLAYER_COLOR_BALANCE_HUE, NULL);
return cb_channel_map[type].name;
}
GType
gst_player_state_get_type (void)
{
static gsize id = 0;
static const GEnumValue values[] = {
{C_ENUM (GST_PLAYER_STATE_STOPPED), "GST_PLAYER_STATE_STOPPED", "stopped"},
{C_ENUM (GST_PLAYER_STATE_BUFFERING), "GST_PLAYER_STATE_BUFFERING",
"buffering"},
{C_ENUM (GST_PLAYER_STATE_PAUSED), "GST_PLAYER_STATE_PAUSED", "paused"},
{C_ENUM (GST_PLAYER_STATE_PLAYING), "GST_PLAYER_STATE_PLAYING", "playing"},
{0, NULL, NULL}
};
if (g_once_init_enter (&id)) {
GType tmp = g_enum_register_static ("GstPlayerState", values);
g_once_init_leave (&id, tmp);
}
return (GType) id;
}
/**
* gst_player_state_get_name:
* @state: a #GstPlayerState
*
* Gets a string representing the given state.
*
* Returns: (transfer none): a string with the name of the state.
*/
const gchar *
gst_player_state_get_name (GstPlayerState state)
{
switch (state) {
case GST_PLAYER_STATE_STOPPED:
return "stopped";
case GST_PLAYER_STATE_BUFFERING:
return "buffering";
case GST_PLAYER_STATE_PAUSED:
return "paused";
case GST_PLAYER_STATE_PLAYING:
return "playing";
}
g_assert_not_reached ();
return NULL;
}
GType
gst_player_error_get_type (void)
{
static gsize id = 0;
static const GEnumValue values[] = {
{C_ENUM (GST_PLAYER_ERROR_FAILED), "GST_PLAYER_ERROR_FAILED", "failed"},
{0, NULL, NULL}
};
if (g_once_init_enter (&id)) {
GType tmp = g_enum_register_static ("GstPlayerError", values);
g_once_init_leave (&id, tmp);
}
return (GType) id;
}
/**
* gst_player_error_get_name:
* @error: a #GstPlayerError
*
* Gets a string representing the given error.
*
* Returns: (transfer none): a string with the given error.
*/
const gchar *
gst_player_error_get_name (GstPlayerError error)
{
switch (error) {
case GST_PLAYER_ERROR_FAILED:
return "failed";
}
g_assert_not_reached ();
return NULL;
}
/**
* gst_player_set_config:
* @player: #GstPlayer instance
* @config: (transfer full): a #GstStructure
*
* Set the configuration of the player. If the player is already configured, and
* the configuration haven't change, this function will return %TRUE. If the
* player is not in the GST_PLAYER_STATE_STOPPED, this method will return %FALSE
* and active configuration will remain.
*
* @config is a #GstStructure that contains the configuration parameters for
* the player.
*
* This function takes ownership of @config.
*
* Returns: %TRUE when the configuration could be set.
* Since: 1.10
*/
gboolean
gst_player_set_config (GstPlayer * self, GstStructure * config)
{
g_return_val_if_fail (GST_IS_PLAYER (self), FALSE);
g_return_val_if_fail (config != NULL, FALSE);
return gst_play_set_config (self->play, config);
}
/**
* gst_player_get_config:
* @player: #GstPlayer instance
*
* Get a copy of the current configuration of the player. This configuration
* can either be modified and used for the gst_player_set_config() call
* or it must be freed after usage.
*
* Returns: (transfer full): a copy of the current configuration of @player. Use
* gst_structure_free() after usage or gst_player_set_config().
*
* Since: 1.10
*/
GstStructure *
gst_player_get_config (GstPlayer * self)
{
g_return_val_if_fail (GST_IS_PLAYER (self), NULL);
return gst_play_get_config (self->play);
}
/**
* gst_player_config_set_user_agent:
* @config: a #GstPlayer configuration
* @agent: (nullable): the string to use as user agent
*
* Set the user agent to pass to the server if @player needs to connect
* to a server during playback. This is typically used when playing HTTP
* or RTSP streams.
*
* Since: 1.10
*/
void
gst_player_config_set_user_agent (GstStructure * config, const gchar * agent)
{
g_return_if_fail (config != NULL);
g_return_if_fail (agent != NULL);
gst_structure_id_set (config,
CONFIG_QUARK (USER_AGENT), G_TYPE_STRING, agent, NULL);
}
/**
* gst_player_config_get_user_agent:
* @config: a #GstPlayer configuration
*
* Return the user agent which has been configured using
* gst_player_config_set_user_agent() if any.
*
* Returns: (transfer full) (nullable): the configured agent, or %NULL
*
* Since: 1.10
*/
gchar *
gst_player_config_get_user_agent (const GstStructure * config)
{
gchar *agent = NULL;
g_return_val_if_fail (config != NULL, NULL);
gst_structure_id_get (config,
CONFIG_QUARK (USER_AGENT), G_TYPE_STRING, &agent, NULL);
return agent;
}
/**
* gst_player_config_set_position_update_interval:
* @config: a #GstPlayer configuration
* @interval: interval in ms
*
* set interval in milliseconds between two position-updated signals.
* pass 0 to stop updating the position.
*
* Since: 1.10
*/
void
gst_player_config_set_position_update_interval (GstStructure * config,
guint interval)
{
g_return_if_fail (config != NULL);
g_return_if_fail (interval <= 10000);
gst_structure_id_set (config,
CONFIG_QUARK (POSITION_INTERVAL_UPDATE), G_TYPE_UINT, interval, NULL);
}
/**
* gst_player_config_get_position_update_interval:
* @config: a #GstPlayer configuration
*
* Returns: current position update interval in milliseconds
*
* Since: 1.10
*/
guint
gst_player_config_get_position_update_interval (const GstStructure * config)
{
guint interval = DEFAULT_POSITION_UPDATE_INTERVAL_MS;
g_return_val_if_fail (config != NULL, DEFAULT_POSITION_UPDATE_INTERVAL_MS);
gst_structure_id_get (config,
CONFIG_QUARK (POSITION_INTERVAL_UPDATE), G_TYPE_UINT, &interval, NULL);
return interval;
}
/**
* gst_player_config_set_seek_accurate:
* @config: a #GstPlayer configuration
* @accurate: accurate seek or not
*
* Enable or disable accurate seeking. When enabled, elements will try harder
* to seek as accurately as possible to the requested seek position. Generally
* it will be slower especially for formats that don't have any indexes or
* timestamp markers in the stream.
*
* If accurate seeking is disabled, elements will seek as close as the request
* position without slowing down seeking too much.
*
* Accurate seeking is disabled by default.
*
* Since: 1.12
*/
void
gst_player_config_set_seek_accurate (GstStructure * config, gboolean accurate)
{
g_return_if_fail (config != NULL);
gst_structure_id_set (config,
CONFIG_QUARK (ACCURATE_SEEK), G_TYPE_BOOLEAN, accurate, NULL);
}
/**
* gst_player_config_get_seek_accurate:
* @config: a #GstPlayer configuration
*
* Returns: %TRUE if accurate seeking is enabled
*
* Since: 1.12
*/
gboolean
gst_player_config_get_seek_accurate (const GstStructure * config)
{
gboolean accurate = FALSE;
g_return_val_if_fail (config != NULL, FALSE);
gst_structure_id_get (config,
CONFIG_QUARK (ACCURATE_SEEK), G_TYPE_BOOLEAN, &accurate, NULL);
return accurate;
}
/**
* gst_player_get_video_snapshot:
* @player: #GstPlayer instance
* @format: output format of the video snapshot
* @config: (allow-none): Additional configuration
*
* Get a snapshot of the currently selected video stream, if any. The format can be
* selected with @format and optional configuration is possible with @config
* Currently supported settings are:
* - width, height of type G_TYPE_INT
* - pixel-aspect-ratio of type GST_TYPE_FRACTION
* Except for GST_PLAYER_THUMBNAIL_RAW_NATIVE format, if no config is set, pixel-aspect-ratio would be 1/1
*
* Returns: (transfer full) (nullable): Current video snapshot sample or %NULL on failure
*
* Since: 1.12
*/
GstSample *
gst_player_get_video_snapshot (GstPlayer * self,
GstPlayerSnapshotFormat format, const GstStructure * config)
{
g_return_val_if_fail (GST_IS_PLAYER (self), NULL);
return gst_play_get_video_snapshot (self->play,
(GstPlaySnapshotFormat) format, config);
}