mirror of
https://github.com/Rafostar/clapper.git
synced 2025-08-29 15:22:11 +02:00
Compare commits
13 Commits
harvest-ca
...
tagged
Author | SHA1 | Date | |
---|---|---|---|
|
72ab32d4ef | ||
|
e9d0d8f345 | ||
|
0b8d359844 | ||
|
4a93bea203 | ||
|
5e2c1a8e30 | ||
|
72c8e4ab84 | ||
|
db61b9c773 | ||
|
682ad6c3c8 | ||
|
749796a12f | ||
|
c557c11e86 | ||
|
a2f67a9bc0 | ||
|
ddc0a4d8f9 | ||
|
92e3e686db |
Submodule pkgs/flatpak/flathub updated: f58477c356...b7c25acba8
@@ -213,7 +213,7 @@ clapper_enhancer_proxy_copy (ClapperEnhancerProxy *src_proxy, const gchar *copy_
|
||||
copy->pspecs = g_new (GParamSpec *, copy->n_pspecs);
|
||||
|
||||
for (i = 0; i < src_proxy->n_pspecs; ++i)
|
||||
copy->pspecs[i] = src_proxy->pspecs[i];
|
||||
copy->pspecs[i] = g_param_spec_ref (src_proxy->pspecs[i]);
|
||||
|
||||
copy->scope = CLAPPER_ENHANCER_PARAM_LOCAL;
|
||||
|
||||
@@ -706,7 +706,7 @@ clapper_enhancer_proxy_get_version (ClapperEnhancerProxy *self)
|
||||
*
|
||||
* Get extra data from enhancer plugin info file specified by @key.
|
||||
*
|
||||
* External data in the plugin info file is prefixed with `X-`.
|
||||
* Extra data in the plugin info file is prefixed with `X-`.
|
||||
* For example `X-Schemes=https`.
|
||||
*
|
||||
* Returns: (nullable): extra data value of the proxied enhancer.
|
||||
@@ -740,6 +740,10 @@ clapper_enhancer_proxy_get_extra_data (ClapperEnhancerProxy *self, const gchar *
|
||||
* calling this function with "X-Schemes" as key and "http" as value will
|
||||
* return %TRUE.
|
||||
*
|
||||
* It is also safe to call this function when there is no such @key
|
||||
* in plugin info file. Use [method@Clapper.EnhancerProxy.get_extra_data]
|
||||
* if you need to know whether key exists.
|
||||
*
|
||||
* Returns: whether list named with @key existed and contained @value.
|
||||
*
|
||||
* Since: 0.10
|
||||
|
@@ -43,6 +43,7 @@ struct _ClapperMediaItem
|
||||
gchar *uri;
|
||||
gchar *suburi;
|
||||
|
||||
GstTagList *tags;
|
||||
ClapperTimeline *timeline;
|
||||
|
||||
guint id;
|
||||
@@ -56,6 +57,13 @@ struct _ClapperMediaItem
|
||||
gboolean used;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ClapperMediaItem *item;
|
||||
gboolean changed;
|
||||
gboolean from_user;
|
||||
} ClapperMediaItemTagIterData;
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
@@ -63,6 +71,7 @@ enum
|
||||
PROP_URI,
|
||||
PROP_SUBURI,
|
||||
PROP_CACHE_LOCATION,
|
||||
PROP_TAGS,
|
||||
PROP_TITLE,
|
||||
PROP_CONTAINER_FORMAT,
|
||||
PROP_DURATION,
|
||||
@@ -111,8 +120,8 @@ clapper_media_item_new (const gchar *uri)
|
||||
|
||||
/* FIXME: Set initial container format from file extension parsing */
|
||||
|
||||
GST_TRACE_OBJECT (item, "New media item, ID: %u, URI: %s, title: %s",
|
||||
item->id, item->uri, item->title);
|
||||
GST_TRACE_OBJECT (item, "New media item, ID: %u, URI: \"%s\", title: \"%s\"",
|
||||
item->id, item->uri, GST_STR_NULL (item->title));
|
||||
|
||||
return item;
|
||||
}
|
||||
@@ -258,27 +267,6 @@ clapper_media_item_get_suburi (ClapperMediaItem *self)
|
||||
return suburi;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clapper_media_item_take_title (ClapperMediaItem *self, gchar *title,
|
||||
ClapperAppBus *app_bus)
|
||||
{
|
||||
gboolean changed;
|
||||
|
||||
GST_OBJECT_LOCK (self);
|
||||
if ((changed = g_strcmp0 (self->title, title) != 0)) {
|
||||
g_free (self->title);
|
||||
self->title = title;
|
||||
}
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
if (changed)
|
||||
clapper_app_bus_post_prop_notify (app_bus, GST_OBJECT_CAST (self), param_specs[PROP_TITLE]);
|
||||
else
|
||||
g_free (title);
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* clapper_media_item_get_title:
|
||||
* @item: a #ClapperMediaItem
|
||||
@@ -305,25 +293,24 @@ clapper_media_item_get_title (ClapperMediaItem *self)
|
||||
return title;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clapper_media_item_take_container_format (ClapperMediaItem *self, gchar *container_format,
|
||||
ClapperAppBus *app_bus)
|
||||
static inline gboolean
|
||||
_refresh_tag_prop_unlocked (ClapperMediaItem *self, const gchar *tag,
|
||||
gboolean from_user, gchar **tag_ptr)
|
||||
{
|
||||
gboolean changed;
|
||||
const gchar *string;
|
||||
|
||||
GST_OBJECT_LOCK (self);
|
||||
if ((changed = g_strcmp0 (self->container_format, container_format) != 0)) {
|
||||
g_free (self->container_format);
|
||||
self->container_format = container_format;
|
||||
}
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
if ((*tag_ptr && from_user) // if already set, user cannot modify it
|
||||
|| !gst_tag_list_peek_string_index (self->tags, tag, 0, &string) // guarantees non-empty string
|
||||
|| (g_strcmp0 (*tag_ptr, string) == 0))
|
||||
return FALSE;
|
||||
|
||||
if (changed)
|
||||
clapper_app_bus_post_prop_notify (app_bus, GST_OBJECT_CAST (self), param_specs[PROP_CONTAINER_FORMAT]);
|
||||
else
|
||||
g_free (container_format);
|
||||
GST_LOG_OBJECT (self, "Tag prop \"%s\" update: \"%s\" -> \"%s\"",
|
||||
tag, GST_STR_NULL (*tag_ptr), string);
|
||||
|
||||
return changed;
|
||||
g_free (*tag_ptr);
|
||||
*tag_ptr = g_strdup (string);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -333,6 +320,8 @@ clapper_media_item_take_container_format (ClapperMediaItem *self, gchar *contain
|
||||
* Get media item container format.
|
||||
*
|
||||
* Returns: (transfer full) (nullable): media container format.
|
||||
*
|
||||
* Deprecated: 0.10: Get `container-format` from [property@Clapper.MediaItem:tags] instead.
|
||||
*/
|
||||
gchar *
|
||||
clapper_media_item_get_container_format (ClapperMediaItem *self)
|
||||
@@ -389,11 +378,207 @@ clapper_media_item_get_duration (ClapperMediaItem *self)
|
||||
return duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* clapper_media_item_get_tags:
|
||||
* @item: a #ClapperMediaItem
|
||||
*
|
||||
* Get readable list of tags stored in media item.
|
||||
*
|
||||
* Returns: (transfer full): a #GstTagList.
|
||||
*
|
||||
* Since: 0.10
|
||||
*/
|
||||
GstTagList *
|
||||
clapper_media_item_get_tags (ClapperMediaItem *self)
|
||||
{
|
||||
GstTagList *tags = NULL;
|
||||
|
||||
g_return_val_if_fail (CLAPPER_IS_MEDIA_ITEM (self), NULL);
|
||||
|
||||
GST_OBJECT_LOCK (self);
|
||||
tags = gst_tag_list_ref (self->tags);
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
return tags;
|
||||
}
|
||||
|
||||
static void
|
||||
_tags_replace_func (const GstTagList *tags, const gchar *tag, ClapperMediaItemTagIterData *data)
|
||||
{
|
||||
ClapperMediaItem *self = data->item;
|
||||
guint index = 0;
|
||||
gboolean replace = FALSE;
|
||||
|
||||
while (TRUE) {
|
||||
const GValue *old_value = gst_tag_list_get_value_index (self->tags, tag, index);
|
||||
const GValue *new_value = gst_tag_list_get_value_index (tags, tag, index);
|
||||
|
||||
/* Number of old values is the same or greater and
|
||||
* all values until this iteration were the same */
|
||||
if (!new_value)
|
||||
break;
|
||||
|
||||
/* A wild new tag appeared */
|
||||
if (!old_value) {
|
||||
replace = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Users can only set non-existing tags */
|
||||
if (data->from_user)
|
||||
break;
|
||||
|
||||
/* Check with tolerance for doubles */
|
||||
if (G_VALUE_TYPE (old_value) == G_TYPE_DOUBLE
|
||||
&& G_VALUE_TYPE (new_value) == G_TYPE_DOUBLE) {
|
||||
gdouble old_dbl, new_dbl;
|
||||
|
||||
old_dbl = g_value_get_double (old_value);
|
||||
new_dbl = g_value_get_double (new_value);
|
||||
|
||||
if ((replace = !G_APPROX_VALUE (old_dbl, new_dbl, FLT_EPSILON)))
|
||||
break;
|
||||
} else if (gst_value_compare (old_value, new_value) != GST_VALUE_EQUAL) {
|
||||
replace = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
++index;
|
||||
}
|
||||
|
||||
if (replace) {
|
||||
const GValue *value;
|
||||
index = 0;
|
||||
|
||||
GST_LOG_OBJECT (self, "Replacing \"%s\" tag value", tag);
|
||||
|
||||
/* Ensure writable, but only when replacing something */
|
||||
if (!data->changed) {
|
||||
self->tags = gst_tag_list_make_writable (self->tags);
|
||||
data->changed = TRUE;
|
||||
}
|
||||
|
||||
/* Replace first tag value (so it becomes sole member) */
|
||||
value = gst_tag_list_get_value_index (tags, tag, index);
|
||||
gst_tag_list_add_value (self->tags, GST_TAG_MERGE_REPLACE, tag, value);
|
||||
|
||||
/* Append any remaining tags (so next time we iterate indexes will match) */
|
||||
while ((value = gst_tag_list_get_value_index (tags, tag, ++index)))
|
||||
gst_tag_list_add_value (self->tags, GST_TAG_MERGE_APPEND, tag, value);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clapper_media_item_insert_tags_internal (ClapperMediaItem *self, const GstTagList *tags,
|
||||
ClapperAppBus *app_bus, gboolean from_user)
|
||||
{
|
||||
ClapperMediaItemTagIterData data;
|
||||
gboolean title_changed = FALSE, cont_changed = FALSE;
|
||||
|
||||
GST_OBJECT_LOCK (self);
|
||||
|
||||
data.item = self;
|
||||
data.changed = FALSE;
|
||||
data.from_user = from_user;
|
||||
|
||||
if (G_LIKELY (tags != self->tags))
|
||||
gst_tag_list_foreach (tags, (GstTagForeachFunc) _tags_replace_func, &data);
|
||||
|
||||
if (data.changed) {
|
||||
title_changed = _refresh_tag_prop_unlocked (self, GST_TAG_TITLE,
|
||||
from_user, &self->title);
|
||||
cont_changed = _refresh_tag_prop_unlocked (self, GST_TAG_CONTAINER_FORMAT,
|
||||
from_user, &self->container_format);
|
||||
}
|
||||
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
if (!data.changed)
|
||||
return FALSE;
|
||||
|
||||
if (app_bus) {
|
||||
GstObject *src = GST_OBJECT_CAST (self);
|
||||
|
||||
clapper_app_bus_post_prop_notify (app_bus, src, param_specs[PROP_TAGS]);
|
||||
|
||||
if (title_changed)
|
||||
clapper_app_bus_post_prop_notify (app_bus, src, param_specs[PROP_TITLE]);
|
||||
if (cont_changed)
|
||||
clapper_app_bus_post_prop_notify (app_bus, src, param_specs[PROP_CONTAINER_FORMAT]);
|
||||
} else {
|
||||
GObject *src = G_OBJECT (self);
|
||||
|
||||
clapper_utils_prop_notify_on_main_sync (src, param_specs[PROP_TAGS]);
|
||||
|
||||
if (title_changed)
|
||||
clapper_utils_prop_notify_on_main_sync (src, param_specs[PROP_TITLE]);
|
||||
if (cont_changed)
|
||||
clapper_utils_prop_notify_on_main_sync (src, param_specs[PROP_CONTAINER_FORMAT]);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* clapper_media_item_populate_tags:
|
||||
* @item: a #ClapperMediaItem
|
||||
* @tags: a #GstTagList of GLOBAL scope
|
||||
*
|
||||
* Populate non-existing tags in @item tag list.
|
||||
*
|
||||
* Passed @tags must use [enum@Gst.TagScope.GLOBAL] scope.
|
||||
*
|
||||
* Note that tags are automatically determined during media playback
|
||||
* and those take precedence. This function can be useful if an app can
|
||||
* determine some tags that are not in media metadata or for filling
|
||||
* item with some initial/cached tags to display in UI before playback.
|
||||
*
|
||||
* When a tag already exists in the tag list (was populated) this
|
||||
* function will not overwrite it. If you really need to permanently
|
||||
* override some tags in media, you can use `taginject` element as
|
||||
* player video/audio filter instead.
|
||||
*
|
||||
* Returns: whether at least one tag got updated.
|
||||
*
|
||||
* Since: 0.10
|
||||
*/
|
||||
gboolean
|
||||
clapper_media_item_populate_tags (ClapperMediaItem *self, const GstTagList *tags)
|
||||
{
|
||||
ClapperPlayer *player;
|
||||
ClapperAppBus *app_bus = NULL;
|
||||
gboolean changed;
|
||||
|
||||
g_return_val_if_fail (CLAPPER_IS_MEDIA_ITEM (self), FALSE);
|
||||
g_return_val_if_fail (tags != NULL, FALSE);
|
||||
|
||||
if (G_UNLIKELY (gst_tag_list_get_scope (tags) != GST_TAG_SCOPE_GLOBAL)) {
|
||||
g_warning ("Cannot populate media item tags using a list with non-global tag scope");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ((player = clapper_player_get_from_ancestor (GST_OBJECT_CAST (self))))
|
||||
app_bus = player->app_bus;
|
||||
|
||||
changed = clapper_media_item_insert_tags_internal (self, tags, app_bus, TRUE);
|
||||
|
||||
if (changed && player) {
|
||||
ClapperFeaturesManager *features_manager;
|
||||
|
||||
if ((features_manager = clapper_player_get_features_manager (player)))
|
||||
clapper_features_manager_trigger_item_updated (features_manager, self);
|
||||
}
|
||||
|
||||
gst_clear_object (&player);
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* clapper_media_item_get_timeline:
|
||||
* @item: a #ClapperMediaItem
|
||||
*
|
||||
* Get the [class@Clapper.Timeline] assosiated with @item.
|
||||
* Get the [class@Clapper.Timeline] associated with @item.
|
||||
*
|
||||
* Returns: (transfer none): a #ClapperTimeline of item.
|
||||
*/
|
||||
@@ -405,21 +590,6 @@ clapper_media_item_get_timeline (ClapperMediaItem *self)
|
||||
return self->timeline;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clapper_media_item_update_from_container_tags (ClapperMediaItem *self, const GstTagList *tags,
|
||||
ClapperAppBus *app_bus)
|
||||
{
|
||||
gchar *string = NULL;
|
||||
gboolean changed = FALSE;
|
||||
|
||||
if (gst_tag_list_get_string (tags, GST_TAG_CONTAINER_FORMAT, &string))
|
||||
changed |= clapper_media_item_take_container_format (self, string, app_bus);
|
||||
if (gst_tag_list_get_string (tags, GST_TAG_TITLE, &string))
|
||||
changed |= clapper_media_item_take_title (self, string, app_bus);
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
void
|
||||
clapper_media_item_update_from_tag_list (ClapperMediaItem *self, const GstTagList *tags,
|
||||
ClapperPlayer *player)
|
||||
@@ -427,7 +597,7 @@ clapper_media_item_update_from_tag_list (ClapperMediaItem *self, const GstTagLis
|
||||
GstTagScope scope = gst_tag_list_get_scope (tags);
|
||||
|
||||
if (scope == GST_TAG_SCOPE_GLOBAL) {
|
||||
gboolean changed = clapper_media_item_update_from_container_tags (self, tags, player->app_bus);
|
||||
gboolean changed = clapper_media_item_insert_tags_internal (self, tags, player->app_bus, FALSE);
|
||||
|
||||
if (changed) {
|
||||
ClapperFeaturesManager *features_manager;
|
||||
@@ -459,7 +629,7 @@ clapper_media_item_update_from_discoverer_info (ClapperMediaItem *self, GstDisco
|
||||
GstDiscovererContainerInfo *cinfo = (GstDiscovererContainerInfo *) sinfo;
|
||||
|
||||
if ((tags = gst_discoverer_container_info_get_tags (cinfo)))
|
||||
changed |= clapper_media_item_update_from_container_tags (self, tags, player->app_bus);
|
||||
changed |= clapper_media_item_insert_tags_internal (self, tags, player->app_bus, FALSE);
|
||||
}
|
||||
gst_discoverer_stream_info_unref (sinfo);
|
||||
}
|
||||
@@ -542,6 +712,9 @@ clapper_media_item_get_used (ClapperMediaItem *self)
|
||||
static void
|
||||
clapper_media_item_init (ClapperMediaItem *self)
|
||||
{
|
||||
self->tags = gst_tag_list_new_empty ();
|
||||
gst_tag_list_set_scope (self->tags, GST_TAG_SCOPE_GLOBAL);
|
||||
|
||||
self->timeline = clapper_timeline_new ();
|
||||
gst_object_set_parent (GST_OBJECT_CAST (self->timeline), GST_OBJECT_CAST (self));
|
||||
}
|
||||
@@ -571,6 +744,8 @@ clapper_media_item_finalize (GObject *object)
|
||||
g_free (self->title);
|
||||
g_free (self->container_format);
|
||||
|
||||
gst_tag_list_unref (self->tags);
|
||||
|
||||
gst_object_unparent (GST_OBJECT_CAST (self->timeline));
|
||||
gst_object_unref (self->timeline);
|
||||
|
||||
@@ -617,6 +792,9 @@ clapper_media_item_get_property (GObject *object, guint prop_id,
|
||||
case PROP_SUBURI:
|
||||
g_value_take_string (value, clapper_media_item_get_suburi (self));
|
||||
break;
|
||||
case PROP_TAGS:
|
||||
g_value_take_boxed (value, clapper_media_item_get_tags (self));
|
||||
break;
|
||||
case PROP_TITLE:
|
||||
g_value_take_string (value, clapper_media_item_get_title (self));
|
||||
break;
|
||||
@@ -686,10 +864,27 @@ clapper_media_item_class_init (ClapperMediaItemClass *klass)
|
||||
NULL, NULL, NULL,
|
||||
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* ClapperMediaItem:tags:
|
||||
*
|
||||
* A readable list of tags stored in media item.
|
||||
*
|
||||
* Since: 0.10
|
||||
*/
|
||||
param_specs[PROP_TAGS] = g_param_spec_boxed ("tags",
|
||||
NULL, NULL, GST_TYPE_TAG_LIST,
|
||||
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/* FIXME: 1.0: Consider rename to e.g. "(menu/display)-title"
|
||||
* and also make it non-nullable (return URI as final fallback) */
|
||||
/**
|
||||
* ClapperMediaItem:title:
|
||||
*
|
||||
* Media title.
|
||||
*
|
||||
* This might be a different string compared to `title` from
|
||||
* [property@Clapper.MediaItem:tags], as this gives parsed
|
||||
* title from file name/URI as fallback when no `title` tag.
|
||||
*/
|
||||
param_specs[PROP_TITLE] = g_param_spec_string ("title",
|
||||
NULL, NULL, NULL,
|
||||
@@ -699,15 +894,21 @@ clapper_media_item_class_init (ClapperMediaItemClass *klass)
|
||||
* ClapperMediaItem:container-format:
|
||||
*
|
||||
* Media container format.
|
||||
*
|
||||
* Deprecated: 0.10: Get `container-format` from [property@Clapper.MediaItem:tags] instead.
|
||||
*/
|
||||
param_specs[PROP_CONTAINER_FORMAT] = g_param_spec_string ("container-format",
|
||||
NULL, NULL, NULL,
|
||||
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED);
|
||||
|
||||
/**
|
||||
* ClapperMediaItem:duration:
|
||||
*
|
||||
* Media duration as a decimal number in seconds.
|
||||
*
|
||||
* This might be a different value compared to `duration` from
|
||||
* [property@Clapper.MediaItem:tags], as this value is updated
|
||||
* during decoding instead of being a fixed value from metadata.
|
||||
*/
|
||||
param_specs[PROP_DURATION] = g_param_spec_double ("duration",
|
||||
NULL, NULL, 0, G_MAXDOUBLE, 0,
|
||||
|
@@ -27,6 +27,7 @@
|
||||
#include <glib-object.h>
|
||||
#include <gio/gio.h>
|
||||
#include <gst/gst.h>
|
||||
#include <gst/tag/tag.h>
|
||||
|
||||
#include <clapper/clapper-visibility.h>
|
||||
#include <clapper/clapper-timeline.h>
|
||||
@@ -63,12 +64,18 @@ gchar * clapper_media_item_get_suburi (ClapperMediaItem *item);
|
||||
CLAPPER_API
|
||||
gchar * clapper_media_item_get_title (ClapperMediaItem *item);
|
||||
|
||||
CLAPPER_API
|
||||
CLAPPER_DEPRECATED_FOR(clapper_media_item_get_tags)
|
||||
gchar * clapper_media_item_get_container_format (ClapperMediaItem *item);
|
||||
|
||||
CLAPPER_API
|
||||
gdouble clapper_media_item_get_duration (ClapperMediaItem *item);
|
||||
|
||||
CLAPPER_API
|
||||
GstTagList * clapper_media_item_get_tags (ClapperMediaItem *item);
|
||||
|
||||
CLAPPER_API
|
||||
gboolean clapper_media_item_populate_tags (ClapperMediaItem *item, const GstTagList *tags);
|
||||
|
||||
CLAPPER_API
|
||||
ClapperTimeline * clapper_media_item_get_timeline (ClapperMediaItem *item);
|
||||
|
||||
|
@@ -2833,7 +2833,7 @@ clapper_player_class_init (ClapperPlayerClass *klass)
|
||||
* An initial bitrate (bits/s) to select during
|
||||
* starting adaptive streaming such as DASH or HLS.
|
||||
*
|
||||
* If value is higher than lowest available bitrate in streaming
|
||||
* If value is lower than the lowest available bitrate in streaming
|
||||
* manifest, then lowest possible bitrate will be selected.
|
||||
*
|
||||
* Since: 0.8
|
||||
|
@@ -52,7 +52,7 @@ G_DEFINE_TYPE_WITH_PRIVATE (ClapperThreadedObject, clapper_threaded_object, GST_
|
||||
* Useful when you want to invoke object thread to do some
|
||||
* action in it from a different thread.
|
||||
*
|
||||
* Returns: a #GMainContext of the object used thread.
|
||||
* Returns: (transfer none): a #GMainContext of the object used thread.
|
||||
*/
|
||||
GMainContext *
|
||||
clapper_threaded_object_get_context (ClapperThreadedObject *self)
|
||||
|
@@ -45,6 +45,9 @@ void clapper_utils_queue_remove_on_main_sync (ClapperQueue *queue, ClapperMediaI
|
||||
G_GNUC_INTERNAL
|
||||
void clapper_utils_queue_clear_on_main_sync (ClapperQueue *queue);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void clapper_utils_prop_notify_on_main_sync (GObject *object, GParamSpec *pspec);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
gchar * clapper_utils_uri_from_file (GFile *file);
|
||||
|
||||
|
@@ -39,6 +39,12 @@ typedef struct
|
||||
ClapperUtilsQueueAlterMethod method;
|
||||
} ClapperUtilsQueueAlterData;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GObject *object;
|
||||
GParamSpec *pspec;
|
||||
} ClapperUtilsPropNotifyData;
|
||||
|
||||
void
|
||||
clapper_utils_initialize (void)
|
||||
{
|
||||
@@ -71,6 +77,27 @@ clapper_utils_queue_alter_data_free (ClapperUtilsQueueAlterData *data)
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
static ClapperUtilsPropNotifyData *
|
||||
clapper_utils_prop_notify_data_new (GObject *object, GParamSpec *pspec)
|
||||
{
|
||||
ClapperUtilsPropNotifyData *data = g_new (ClapperUtilsPropNotifyData, 1);
|
||||
|
||||
data->object = object;
|
||||
data->pspec = pspec;
|
||||
|
||||
GST_TRACE ("Created prop notify data: %p", data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static void
|
||||
clapper_utils_prop_notify_data_free (ClapperUtilsPropNotifyData *data)
|
||||
{
|
||||
GST_TRACE ("Freeing prop notify data: %p", data);
|
||||
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
clapper_utils_queue_alter_on_main (ClapperUtilsQueueAlterData *data)
|
||||
{
|
||||
@@ -110,6 +137,15 @@ clapper_utils_queue_alter_on_main (ClapperUtilsQueueAlterData *data)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
clapper_utils_prop_notify_on_main (ClapperUtilsPropNotifyData *data)
|
||||
{
|
||||
GST_DEBUG ("Prop notify invoked");
|
||||
g_object_notify_by_pspec (data->object, data->pspec);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void
|
||||
clapper_utils_queue_alter_invoke_on_main_sync_take (ClapperUtilsQueueAlterData *data)
|
||||
{
|
||||
@@ -155,6 +191,27 @@ clapper_utils_queue_clear_on_main_sync (ClapperQueue *queue)
|
||||
clapper_utils_queue_alter_invoke_on_main_sync_take (data);
|
||||
}
|
||||
|
||||
void
|
||||
clapper_utils_prop_notify_on_main_sync (GObject *object, GParamSpec *pspec)
|
||||
{
|
||||
ClapperUtilsPropNotifyData *data;
|
||||
|
||||
if (g_main_context_is_owner (g_main_context_default ())) { // already in main thread
|
||||
g_object_notify_by_pspec (object, pspec);
|
||||
return;
|
||||
}
|
||||
|
||||
data = clapper_utils_prop_notify_data_new (object, pspec);
|
||||
|
||||
GST_DEBUG ("Invoking prop notify on main...");
|
||||
|
||||
clapper_shared_utils_context_invoke_sync_full (g_main_context_default (),
|
||||
(GThreadFunc) clapper_utils_prop_notify_on_main, data,
|
||||
(GDestroyNotify) clapper_utils_prop_notify_data_free);
|
||||
|
||||
GST_DEBUG ("Prop notify invoke finished");
|
||||
}
|
||||
|
||||
gchar *
|
||||
clapper_utils_uri_from_file (GFile *file)
|
||||
{
|
||||
|
@@ -95,7 +95,8 @@ clapper_enhancer_director_extract_in_thread (ClapperEnhancerDirectorData *data)
|
||||
#endif
|
||||
|
||||
if (G_LIKELY (extractable != NULL)) {
|
||||
clapper_enhancer_proxy_apply_config_to_enhancer (proxy, config, (GObject *) extractable);
|
||||
if (config)
|
||||
clapper_enhancer_proxy_apply_config_to_enhancer (proxy, config, (GObject *) extractable);
|
||||
|
||||
success = clapper_extractable_extract (extractable, data->uri,
|
||||
harvest, data->cancellable, data->error);
|
||||
|
@@ -235,6 +235,7 @@ if build_gir
|
||||
clapper_enums,
|
||||
],
|
||||
extra_args: [
|
||||
gir_init_section,
|
||||
'--quiet',
|
||||
'--warn-all',
|
||||
'-DCLAPPER_COMPILATION',
|
||||
|
@@ -1,6 +1,6 @@
|
||||
// Skipped by GI, but Vala can handle it fine
|
||||
//init_get_option_group skip=false
|
||||
*_FORMAT skip=false
|
||||
*.peek_* skip=false
|
||||
|
||||
// Init func compatibility
|
||||
init.argv unowned
|
||||
|
@@ -594,11 +594,14 @@ static gboolean
|
||||
gst_clapper_sink_start (GstBaseSink *bsink)
|
||||
{
|
||||
GstClapperSink *self = GST_CLAPPER_SINK_CAST (bsink);
|
||||
gboolean with_clapper_gtk;
|
||||
|
||||
GST_INFO_OBJECT (self, "Start");
|
||||
|
||||
if (G_UNLIKELY (!(! !gst_gtk_invoke_on_main ((GThreadFunc) (GCallback)
|
||||
gst_clapper_sink_start_on_main, self)))) {
|
||||
with_clapper_gtk = g_type_from_name ("ClapperGtkVideo");
|
||||
|
||||
if (G_UNLIKELY (!with_clapper_gtk && !(! !gst_gtk_invoke_on_main (
|
||||
(GThreadFunc) (GCallback) gst_clapper_sink_start_on_main, self)))) {
|
||||
GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
|
||||
("GtkWidget could not be created"), (NULL));
|
||||
|
||||
|
@@ -4,6 +4,13 @@ build_gir = (gir.found() and not get_option('introspection').disabled())
|
||||
vapigen = find_program('vapigen', required: get_option('vapi'))
|
||||
build_vapi = (vapigen.found() and not get_option('vapi').disabled())
|
||||
|
||||
gir_init_section = '--add-init-section=extern void gst_init(gint*,gchar**);' + \
|
||||
'g_setenv("GST_REGISTRY_DISABLE", "yes", TRUE);' + \
|
||||
'g_setenv("GST_REGISTRY_1_0", "@0@", TRUE);'.format(meson.current_build_dir() + '/gir_empty_registry.reg') + \
|
||||
'g_setenv("GST_PLUGIN_PATH_1_0", "", TRUE);' + \
|
||||
'g_setenv("GST_PLUGIN_SYSTEM_PATH_1_0", "", TRUE);' + \
|
||||
'gst_init(NULL,NULL);'
|
||||
|
||||
subdir('gst')
|
||||
subdir('clapper')
|
||||
subdir('clapper-gtk')
|
||||
|
@@ -41,5 +41,11 @@
|
||||
#endif
|
||||
|
||||
#define @CLAPPER_API@_API _@CLAPPER_API@_VISIBILITY
|
||||
|
||||
#if !defined(@CLAPPER_API@_COMPILATION)
|
||||
#define @CLAPPER_API@_DEPRECATED G_DEPRECATED _@CLAPPER_API@_VISIBILITY
|
||||
#define @CLAPPER_API@_DEPRECATED_FOR(f) G_DEPRECATED_FOR(f) _@CLAPPER_API@_VISIBILITY
|
||||
#else
|
||||
#define @CLAPPER_API@_DEPRECATED _@CLAPPER_API@_VISIBILITY
|
||||
#define @CLAPPER_API@_DEPRECATED_FOR(f) _@CLAPPER_API@_VISIBILITY
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user