mirror of
https://github.com/Rafostar/clapper.git
synced 2025-12-24 05:56:41 +01:00
@@ -89,7 +89,7 @@ drag_item_prepare_cb (GtkDragSource *drag_source, gdouble x, gdouble y, ClapperA
|
||||
|
||||
paintable = gtk_widget_paintable_new (list_widget);
|
||||
|
||||
drag_data = g_new0 (ClapperAppQueueListDragData, 1);
|
||||
drag_data = g_new (ClapperAppQueueListDragData, 1);
|
||||
drag_data->item = gst_object_ref (item);
|
||||
drag_data->widget = g_object_ref_sink (pickup);
|
||||
drag_data->paintable = gdk_paintable_get_current_image (paintable);
|
||||
@@ -150,8 +150,12 @@ queue_drop_value_notify_cb (GtkDropTarget *drop_target,
|
||||
{
|
||||
const GValue *value = gtk_drop_target_get_value (drop_target);
|
||||
|
||||
if (value && !clapper_app_utils_value_for_item_is_valid (value))
|
||||
gtk_drop_target_reject (drop_target);
|
||||
if (value) {
|
||||
if (!clapper_app_utils_value_for_item_is_valid (value))
|
||||
gtk_drop_target_reject (drop_target);
|
||||
} else {
|
||||
self->list_target = NULL; // Reset when value is lost
|
||||
}
|
||||
}
|
||||
|
||||
static GdkDragAction
|
||||
@@ -223,6 +227,7 @@ queue_drop_leave_cb (GtkDropTarget *drop_target, ClapperAppQueueList *self)
|
||||
if (self->list_target) {
|
||||
gtk_widget_set_margin_top (self->list_target, 0);
|
||||
gtk_widget_set_margin_bottom (self->list_target, 0);
|
||||
self->list_target = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,55 +235,75 @@ static gboolean
|
||||
queue_drop_cb (GtkDropTarget *drop_target, const GValue *value,
|
||||
gdouble x, gdouble y, ClapperAppQueueList *self)
|
||||
{
|
||||
ClapperQueue *queue;
|
||||
ClapperMediaItem *item;
|
||||
GtkWidget *pickup;
|
||||
ClapperPlayer *player = clapper_gtk_get_player_from_ancestor (GTK_WIDGET (self));
|
||||
ClapperQueue *queue = clapper_player_get_queue (player);
|
||||
ClapperMediaItem *item = NULL;
|
||||
guint drop_index = 0;
|
||||
gboolean success = FALSE;
|
||||
|
||||
if (G_UNLIKELY (self->list_target == NULL))
|
||||
return FALSE;
|
||||
if (self->list_target) {
|
||||
GtkWidget *pickup = gtk_widget_get_first_child (self->list_target);
|
||||
|
||||
pickup = gtk_widget_get_first_child (self->list_target);
|
||||
/* Reset margins on drop */
|
||||
gtk_widget_set_margin_top (self->list_target, 0);
|
||||
gtk_widget_set_margin_bottom (self->list_target, 0);
|
||||
self->list_target = NULL;
|
||||
|
||||
/* Reset margins on drop */
|
||||
gtk_widget_set_margin_top (self->list_target, 0);
|
||||
gtk_widget_set_margin_bottom (self->list_target, 0);
|
||||
self->list_target = NULL;
|
||||
if (G_UNLIKELY (pickup == NULL) || !CLAPPER_APP_IS_MEDIA_ITEM_BOX (pickup))
|
||||
return FALSE;
|
||||
|
||||
if (G_UNLIKELY (pickup == NULL) || !CLAPPER_APP_IS_MEDIA_ITEM_BOX (pickup))
|
||||
return FALSE;
|
||||
item = clapper_app_media_item_box_get_media_item (CLAPPER_APP_MEDIA_ITEM_BOX_CAST (pickup));
|
||||
|
||||
item = clapper_app_media_item_box_get_media_item (CLAPPER_APP_MEDIA_ITEM_BOX_CAST (pickup));
|
||||
queue = CLAPPER_QUEUE (gst_object_get_parent (GST_OBJECT (item)));
|
||||
if (!clapper_queue_find_item (queue, item, &drop_index))
|
||||
return FALSE;
|
||||
|
||||
if (G_UNLIKELY (queue == NULL))
|
||||
return FALSE;
|
||||
|
||||
if (!clapper_queue_find_item (queue, item, &drop_index)) {
|
||||
gst_object_unref (queue);
|
||||
return FALSE;
|
||||
if (self->drop_after)
|
||||
drop_index++;
|
||||
} else {
|
||||
drop_index = clapper_queue_get_n_items (queue); // Append
|
||||
}
|
||||
|
||||
if (self->drop_after)
|
||||
drop_index++;
|
||||
|
||||
/* Moving item with widget */
|
||||
if (G_VALUE_HOLDS (value, GTK_TYPE_WIDGET)) {
|
||||
ClapperAppQueueListDragData *drag_data;
|
||||
|
||||
drag_data = (ClapperAppQueueListDragData *) g_object_get_data (G_OBJECT (self), "drag-data");
|
||||
|
||||
/* Insert at different place */
|
||||
if (item != drag_data->item) {
|
||||
guint index = 0;
|
||||
/* When user drops a widget and drag data is present, it means
|
||||
* that it is an item drop within the same window */
|
||||
if (drag_data) {
|
||||
/* Insert at different place */
|
||||
if (item != drag_data->item) {
|
||||
guint index = 0;
|
||||
|
||||
if (clapper_queue_find_item (queue, drag_data->item, &index)) {
|
||||
if (drop_index > index)
|
||||
drop_index--;
|
||||
if (clapper_queue_find_item (queue, drag_data->item, &index)) {
|
||||
if (drop_index > index)
|
||||
drop_index--;
|
||||
|
||||
clapper_queue_reposition_item (queue, drag_data->item, drop_index);
|
||||
success = TRUE;
|
||||
clapper_queue_reposition_item (queue, drag_data->item, drop_index);
|
||||
success = TRUE;
|
||||
}
|
||||
}
|
||||
} else { // Drop from another window
|
||||
GtkWidget *drop_widget = GTK_WIDGET (g_value_get_object (value));
|
||||
|
||||
if (G_LIKELY (CLAPPER_APP_IS_MEDIA_ITEM_BOX (drop_widget))) {
|
||||
ClapperMediaItem *drop_item;
|
||||
ClapperQueue *src_queue;
|
||||
|
||||
drop_item = clapper_app_media_item_box_get_media_item (
|
||||
CLAPPER_APP_MEDIA_ITEM_BOX_CAST (drop_widget));
|
||||
|
||||
if ((src_queue = CLAPPER_QUEUE (gst_object_get_parent (GST_OBJECT (drop_item))))) {
|
||||
gst_object_ref (drop_item); // Ref so it survives queue removal
|
||||
|
||||
clapper_queue_remove_item (src_queue, drop_item);
|
||||
clapper_queue_insert_item (queue, drop_item, drop_index);
|
||||
success = TRUE;
|
||||
|
||||
gst_object_unref (drop_item); // Unref after placed in new queue
|
||||
gst_object_unref (src_queue);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -300,8 +325,6 @@ queue_drop_cb (GtkDropTarget *drop_target, const GValue *value,
|
||||
}
|
||||
}
|
||||
|
||||
gst_object_unref (queue);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
@@ -335,37 +335,36 @@ _resize_tick (GtkWidget *widget, GdkFrameClock *frame_clock,
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static gint
|
||||
_get_gcd (gint width, gint height)
|
||||
{
|
||||
return (height > 0)
|
||||
? _get_gcd (height, width % height)
|
||||
: width;
|
||||
}
|
||||
|
||||
static void
|
||||
_calculate_win_resize (gint win_w, gint win_h,
|
||||
gint vid_w, gint vid_h, gint *dest_w, gint *dest_h)
|
||||
{
|
||||
gdouble win_aspect = (gdouble) win_w / win_h;
|
||||
gdouble vid_aspect = (gdouble) vid_w / vid_h;
|
||||
/* Get the smallest integer ratio (e.g. 1920x1080 becomes 16x9) */
|
||||
gint gcd = _get_gcd (vid_w, vid_h);
|
||||
gint min_w = vid_w / gcd;
|
||||
gint min_h = vid_h / gcd;
|
||||
|
||||
if (win_aspect < vid_aspect) {
|
||||
while (!G_APPROX_VALUE (fmod (win_w, vid_aspect), 0, FLT_EPSILON))
|
||||
win_w++;
|
||||
/* Find the scale multiplier that best fits video */
|
||||
gint scale_fit = MIN (win_w / min_w, win_h / min_h);
|
||||
|
||||
win_h = round ((gdouble) win_w / vid_aspect);
|
||||
/* Calculate minimal allowed scale for video (-1 for ceil) */
|
||||
gint scale_min = MAX (
|
||||
(MIN_WINDOW_WIDTH + min_w - 1) / min_w,
|
||||
(MIN_WINDOW_HEIGHT + min_h - 1) / min_h);
|
||||
|
||||
if (win_h < MIN_WINDOW_HEIGHT) {
|
||||
_calculate_win_resize (G_MAXINT, MIN_WINDOW_HEIGHT, vid_w, vid_h, dest_w, dest_h);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
while (!G_APPROX_VALUE (fmod (win_h * vid_aspect, 1.0), 0, FLT_EPSILON))
|
||||
win_h++;
|
||||
/* Select best allowed scale multiplier */
|
||||
gint scale = MAX (scale_fit, scale_min);
|
||||
|
||||
win_w = round ((gdouble) win_h * vid_aspect);
|
||||
|
||||
if (win_w < MIN_WINDOW_WIDTH) {
|
||||
_calculate_win_resize (MIN_WINDOW_WIDTH, G_MAXINT, vid_w, vid_h, dest_w, dest_h);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
*dest_w = win_w;
|
||||
*dest_h = win_h;
|
||||
*dest_w = min_w * scale;
|
||||
*dest_h = min_h * scale;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1283,6 +1282,7 @@ clapper_app_window_constructed (GObject *object)
|
||||
|
||||
if ((proxy = clapper_enhancer_proxy_list_get_proxy_by_module (proxies, "clapper-mpris"))) {
|
||||
clapper_enhancer_proxy_set_locally (proxy,
|
||||
"app-id", CLAPPER_APP_ID,
|
||||
"own-name", mpris_name,
|
||||
"identity", CLAPPER_APP_NAME,
|
||||
"desktop-entry", CLAPPER_APP_ID,
|
||||
|
||||
@@ -91,6 +91,7 @@ clapperapp_sources = [
|
||||
clapperapp_c_args = [
|
||||
'-DG_LOG_DOMAIN="ClapperApp"',
|
||||
'-DCLAPPER_APP_INTERNAL_COMPILATION',
|
||||
'-DCLAPPER_DISABLE_DEPRECATION_WARNINGS',
|
||||
'-DGST_USE_UNSTABLE_API',
|
||||
]
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<property name="close-response">cancel</property>
|
||||
<property name="default-response">add</property>
|
||||
<property name="follows-content-size">false</property>
|
||||
<property name="content-width">420</property>
|
||||
<property name="content-width">460</property>
|
||||
<property name="extra-child">
|
||||
<object class="GtkListBox">
|
||||
<property name="selection-mode">none</property>
|
||||
|
||||
@@ -139,6 +139,7 @@ clappergtk_sources = [
|
||||
clappergtk_c_args = [
|
||||
'-DG_LOG_DOMAIN="ClapperGtk"',
|
||||
'-DCLAPPER_GTK_COMPILATION',
|
||||
'-DCLAPPER_DISABLE_DEPRECATION_WARNINGS',
|
||||
'-DGST_USE_UNSTABLE_API',
|
||||
]
|
||||
|
||||
|
||||
@@ -239,7 +239,6 @@ clapper_harvest_fill_from_cache (ClapperHarvest *self, ClapperEnhancerProxy *pro
|
||||
g_free (filename);
|
||||
|
||||
if (!mapped_file) {
|
||||
/* No error if cache disabled or version mismatch */
|
||||
if (error) {
|
||||
if (error->domain == G_FILE_ERROR && error->code == G_FILE_ERROR_NOENT)
|
||||
GST_DEBUG_OBJECT (self, "No cached harvest found");
|
||||
@@ -247,6 +246,9 @@ clapper_harvest_fill_from_cache (ClapperHarvest *self, ClapperEnhancerProxy *pro
|
||||
GST_ERROR_OBJECT (self, "Could not use cached harvest, reason: %s", error->message);
|
||||
|
||||
g_error_free (error);
|
||||
} else {
|
||||
/* No error if cache disabled or version mismatch */
|
||||
GST_DEBUG_OBJECT (self, "Import skipped");
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
G_BEGIN_DECLS
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void clapper_media_item_update_from_tag_list (ClapperMediaItem *item, const GstTagList *tags, ClapperPlayer *player);
|
||||
void clapper_media_item_update_from_tag_list (ClapperMediaItem *item, const GstTagList *tags, gboolean allow_overwrite, ClapperPlayer *player);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void clapper_media_item_update_from_discoverer_info (ClapperMediaItem *self, GstDiscovererInfo *info);
|
||||
|
||||
@@ -66,7 +66,7 @@ typedef struct
|
||||
{
|
||||
ClapperMediaItem *item;
|
||||
gboolean changed;
|
||||
gboolean from_user;
|
||||
gboolean allow_overwrite;
|
||||
} ClapperMediaItemTagIterData;
|
||||
|
||||
enum
|
||||
@@ -476,8 +476,8 @@ _tags_replace_func (const GstTagList *tags, const gchar *tag, ClapperMediaItemTa
|
||||
break;
|
||||
}
|
||||
|
||||
/* Users can only set non-existing tags */
|
||||
if (data->from_user)
|
||||
/* No overwrites allowed (e.g. user tags) */
|
||||
if (!data->allow_overwrite)
|
||||
break;
|
||||
|
||||
/* Check with tolerance for doubles */
|
||||
@@ -522,7 +522,7 @@ _tags_replace_func (const GstTagList *tags, const gchar *tag, ClapperMediaItemTa
|
||||
|
||||
static gboolean
|
||||
clapper_media_item_insert_tags_internal (ClapperMediaItem *self, const GstTagList *tags,
|
||||
ClapperAppBus *app_bus, gboolean from_user, ClapperReactableItemUpdatedFlags *flags)
|
||||
ClapperAppBus *app_bus, gboolean allow_overwrite, ClapperReactableItemUpdatedFlags *flags)
|
||||
{
|
||||
ClapperMediaItemTagIterData data;
|
||||
gboolean title_changed = FALSE, cont_changed = FALSE;
|
||||
@@ -531,7 +531,7 @@ clapper_media_item_insert_tags_internal (ClapperMediaItem *self, const GstTagLis
|
||||
|
||||
data.item = self;
|
||||
data.changed = FALSE;
|
||||
data.from_user = from_user;
|
||||
data.allow_overwrite = allow_overwrite;
|
||||
|
||||
if (G_LIKELY (tags != self->tags))
|
||||
gst_tag_list_foreach (tags, (GstTagForeachFunc) _tags_replace_func, &data);
|
||||
@@ -540,12 +540,12 @@ clapper_media_item_insert_tags_internal (ClapperMediaItem *self, const GstTagLis
|
||||
*flags |= CLAPPER_REACTABLE_ITEM_UPDATED_TAGS;
|
||||
|
||||
if ((title_changed = _refresh_tag_prop_unlocked (self, GST_TAG_TITLE,
|
||||
(!from_user || self->title_is_parsed), &self->title))) {
|
||||
(allow_overwrite || self->title_is_parsed), &self->title))) {
|
||||
self->title_is_parsed = FALSE;
|
||||
*flags |= CLAPPER_REACTABLE_ITEM_UPDATED_TITLE;
|
||||
}
|
||||
cont_changed = _refresh_tag_prop_unlocked (self, GST_TAG_CONTAINER_FORMAT,
|
||||
!from_user, &self->container_format);
|
||||
allow_overwrite, &self->container_format);
|
||||
}
|
||||
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
@@ -618,7 +618,7 @@ clapper_media_item_populate_tags (ClapperMediaItem *self, const GstTagList *tags
|
||||
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, &flags);
|
||||
changed = clapper_media_item_insert_tags_internal (self, tags, app_bus, FALSE, &flags);
|
||||
|
||||
if (changed && player) {
|
||||
ClapperFeaturesManager *features_manager;
|
||||
@@ -652,22 +652,18 @@ clapper_media_item_get_timeline (ClapperMediaItem *self)
|
||||
|
||||
void
|
||||
clapper_media_item_update_from_tag_list (ClapperMediaItem *self, const GstTagList *tags,
|
||||
ClapperPlayer *player)
|
||||
gboolean allow_overwrite, ClapperPlayer *player)
|
||||
{
|
||||
GstTagScope scope = gst_tag_list_get_scope (tags);
|
||||
ClapperReactableItemUpdatedFlags flags = 0;
|
||||
gboolean changed = clapper_media_item_insert_tags_internal (self, tags, player->app_bus, allow_overwrite, &flags);
|
||||
|
||||
if (scope == GST_TAG_SCOPE_GLOBAL) {
|
||||
ClapperReactableItemUpdatedFlags flags = 0;
|
||||
gboolean changed = clapper_media_item_insert_tags_internal (self, tags, player->app_bus, FALSE, &flags);
|
||||
if (changed) {
|
||||
ClapperFeaturesManager *features_manager;
|
||||
|
||||
if (changed) {
|
||||
ClapperFeaturesManager *features_manager;
|
||||
|
||||
if (player->reactables_manager)
|
||||
clapper_reactables_manager_trigger_item_updated (player->reactables_manager, self, flags);
|
||||
if ((features_manager = clapper_player_get_features_manager (player)))
|
||||
clapper_features_manager_trigger_item_updated (features_manager, self);
|
||||
}
|
||||
if (player->reactables_manager)
|
||||
clapper_reactables_manager_trigger_item_updated (player->reactables_manager, self, flags);
|
||||
if ((features_manager = clapper_player_get_features_manager (player)))
|
||||
clapper_features_manager_trigger_item_updated (features_manager, self);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -693,7 +689,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_insert_tags_internal (self, tags, player->app_bus, FALSE, &flags);
|
||||
changed |= clapper_media_item_insert_tags_internal (self, tags, player->app_bus, TRUE, &flags);
|
||||
}
|
||||
gst_discoverer_stream_info_unref (sinfo);
|
||||
}
|
||||
@@ -783,8 +779,8 @@ clapper_media_item_update_from_parsed_playlist (ClapperMediaItem *self, GListSto
|
||||
|
||||
GST_OBJECT_LOCK (other_item);
|
||||
|
||||
if (other_item->tags)
|
||||
clapper_media_item_update_from_tag_list (self, other_item->tags, player);
|
||||
if (other_item->tags) // Tags are always GLOBAL here
|
||||
clapper_media_item_update_from_tag_list (self, other_item->tags, TRUE, player);
|
||||
|
||||
/* Since its redirect now, we have to update title to describe new file instead of
|
||||
* being a playlist title. If other item had parsed title, it also means that tags
|
||||
|
||||
@@ -1038,7 +1038,9 @@ _handle_tag_msg (GstMessage *msg, ClapperPlayer *player)
|
||||
}
|
||||
player->pending_tags = gst_tag_list_ref (tags);
|
||||
} else if (G_LIKELY (player->played_item != NULL)) {
|
||||
clapper_media_item_update_from_tag_list (player->played_item, tags, player);
|
||||
gboolean is_global = (gst_tag_list_get_scope (tags) == GST_TAG_SCOPE_GLOBAL);
|
||||
if (is_global || player->stream_tags_allowed)
|
||||
clapper_media_item_update_from_tag_list (player->played_item, tags, is_global, player);
|
||||
}
|
||||
|
||||
gst_tag_list_unref (tags);
|
||||
@@ -1116,10 +1118,28 @@ static inline void
|
||||
_handle_stream_collection_msg (GstMessage *msg, ClapperPlayer *player)
|
||||
{
|
||||
GstStreamCollection *collection = NULL;
|
||||
guint i, n_streams, n_video = 0, n_audio = 0, n_text = 0;
|
||||
|
||||
GST_INFO_OBJECT (player, "Stream collection");
|
||||
|
||||
gst_message_parse_stream_collection (msg, &collection);
|
||||
n_streams = gst_stream_collection_get_size (collection);
|
||||
|
||||
for (i = 0; i < n_streams; ++i) {
|
||||
GstStream *stream = gst_stream_collection_get_stream (collection, i);
|
||||
GstStreamType stream_type = gst_stream_get_stream_type (stream);
|
||||
|
||||
if ((stream_type & GST_STREAM_TYPE_VIDEO) == GST_STREAM_TYPE_VIDEO)
|
||||
n_video++;
|
||||
else if ((stream_type & GST_STREAM_TYPE_AUDIO) == GST_STREAM_TYPE_AUDIO)
|
||||
n_audio++;
|
||||
else if ((stream_type & GST_STREAM_TYPE_TEXT) == GST_STREAM_TYPE_TEXT)
|
||||
n_text++;
|
||||
}
|
||||
|
||||
player->stream_tags_allowed = (n_video + n_audio + n_text == 1);
|
||||
GST_DEBUG_OBJECT (player, "Stream tags allowed: %s", (player->stream_tags_allowed) ? "yes" : "no");
|
||||
|
||||
clapper_player_take_stream_collection (player, collection);
|
||||
}
|
||||
|
||||
@@ -1214,9 +1234,10 @@ _handle_stream_start_msg (GstMessage *msg, ClapperPlayer *player)
|
||||
clapper_player_playbin_update_current_decoders (player);
|
||||
|
||||
if (player->pending_tags) {
|
||||
if (G_LIKELY (player->played_item != NULL))
|
||||
clapper_media_item_update_from_tag_list (player->played_item, player->pending_tags, player);
|
||||
|
||||
if (G_LIKELY (player->played_item != NULL)) {
|
||||
/* Pending tags come from "extractablesrc" and are always GLOBAL (preferred) */
|
||||
clapper_media_item_update_from_tag_list (player->played_item, player->pending_tags, TRUE, player);
|
||||
}
|
||||
gst_clear_tag_list (&player->pending_tags);
|
||||
}
|
||||
if (player->pending_toc) {
|
||||
|
||||
@@ -61,6 +61,7 @@ struct _ClapperPlayer
|
||||
|
||||
/* Pending tags/toc that arrive before stream start.
|
||||
* To be applied to "played_item", thus no lock needed. */
|
||||
gboolean stream_tags_allowed;
|
||||
GstTagList *pending_tags;
|
||||
GstToc *pending_toc;
|
||||
|
||||
|
||||
@@ -780,6 +780,7 @@ clapper_player_reset (ClapperPlayer *self, gboolean pending_dispose)
|
||||
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
self->stream_tags_allowed = FALSE;
|
||||
gst_clear_tag_list (&self->pending_tags);
|
||||
|
||||
if (self->pending_toc) {
|
||||
|
||||
@@ -134,6 +134,40 @@ clapper_playlist_type_find (GstTypeFind *tf, ClapperEnhancerProxy *proxy)
|
||||
CLAPPER_PLAYLIST_MEDIA_TYPE, "enhancer", G_TYPE_STRING, module_name, NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_is_claps_possible (const guint8 *data, gsize len)
|
||||
{
|
||||
gboolean possible = FALSE;
|
||||
|
||||
/* Linux file path */
|
||||
if (len >= 2)
|
||||
possible = (data[0] == '/' && g_ascii_isalnum (data[1]));
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
/* Windows file path ("C:\..." or "D:/...") */
|
||||
if (!possible && len >= 3) {
|
||||
possible = (g_ascii_isalpha (data[0]) && data[1] == ':' && (data[2] == '\\' || data[2] == '/'));
|
||||
|
||||
/* Windows UNC path */
|
||||
if (!possible)
|
||||
possible = (data[0] == '\\' && data[1] == '\\' && g_ascii_isalnum (data[2]));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check for URI (at least 3 characters before colon) */
|
||||
if (!possible && len > 3) {
|
||||
guint i = 0, end = MIN (len, 16);
|
||||
|
||||
while (i < end && g_ascii_isalpha (data[i]))
|
||||
++i;
|
||||
|
||||
if (i >= 3 && i < end)
|
||||
possible = (data[i] == ':');
|
||||
}
|
||||
|
||||
return possible;
|
||||
}
|
||||
|
||||
/* Finds text file of full file paths. Claps file might also use URIs,
|
||||
* but in that case lets GStreamer built-in type finders find that as
|
||||
* "text/uri-list" and we will handle it with this element too. */
|
||||
@@ -141,26 +175,54 @@ static void
|
||||
clapper_claps_type_find (GstTypeFind *tf, gpointer user_data G_GNUC_UNUSED)
|
||||
{
|
||||
const guint8 *data;
|
||||
guint64 data_size = 16;
|
||||
|
||||
if ((data = gst_type_find_peek (tf, 0, 3))) {
|
||||
gboolean possible;
|
||||
if (!(data = gst_type_find_peek (tf, 0, data_size))) {
|
||||
if ((data_size = gst_type_find_get_length (tf)) > 0)
|
||||
data = gst_type_find_peek (tf, 0, data_size);
|
||||
|
||||
/* Linux file path */
|
||||
possible = (data[0] == '/' && g_ascii_isalnum (data[1]));
|
||||
if (!data)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
/* Windows file path ("C:\..." or "D:/...") */
|
||||
if (!possible)
|
||||
possible = (g_ascii_isalpha (data[0]) && data[1] == ':' && (data[2] == '\\' || data[2] == '/'));
|
||||
/* Continue parsing only if start looks like
|
||||
* file path, otherwise reject data early */
|
||||
if (_is_claps_possible (data, data_size)) {
|
||||
guint probability = GST_TYPE_FIND_POSSIBLE;
|
||||
data_size = 1024;
|
||||
|
||||
/* Windows UNC Path */
|
||||
if (!possible)
|
||||
possible = (data[0] == '\\' && data[1] == '\\' && g_ascii_isalnum (data[2]));
|
||||
#endif
|
||||
if (!(data = gst_type_find_peek (tf, 0, data_size)))
|
||||
if ((data_size = gst_type_find_get_length (tf)) > 0)
|
||||
data = gst_type_find_peek (tf, 0, data_size);
|
||||
|
||||
if (possible) {
|
||||
GST_INFO ("Suggesting possible type: " CLAPPER_CLAPS_MEDIA_TYPE);
|
||||
gst_type_find_suggest_empty_simple (tf, GST_TYPE_FIND_POSSIBLE, CLAPPER_CLAPS_MEDIA_TYPE);
|
||||
if (data) {
|
||||
const guint8 *line_start = data;
|
||||
const guint8 *end = data + data_size;
|
||||
guint pathlike = 0, total = 0;
|
||||
|
||||
while (line_start < end) {
|
||||
const guint8 *newline = memchr (line_start, '\n', end - line_start);
|
||||
gsize len = newline ? (newline - line_start) : (end - line_start);
|
||||
|
||||
if (len > 0) {
|
||||
++total;
|
||||
if (_is_claps_possible (line_start, len))
|
||||
++pathlike;
|
||||
}
|
||||
|
||||
if (!newline)
|
||||
break;
|
||||
|
||||
line_start = newline + 1;
|
||||
}
|
||||
|
||||
/* Multiple lines and most of them looks like a file path */
|
||||
if (total > 1 && pathlike >= MAX (2, total * 3 / 4))
|
||||
probability = GST_TYPE_FIND_LIKELY;
|
||||
|
||||
GST_INFO ("Suggesting %s type: " CLAPPER_CLAPS_MEDIA_TYPE,
|
||||
(probability >= GST_TYPE_FIND_LIKELY) ? "likely" : "possible");
|
||||
gst_type_find_suggest_empty_simple (tf, probability, CLAPPER_CLAPS_MEDIA_TYPE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,6 +171,7 @@ clapper_sources = [
|
||||
clapper_c_args = [
|
||||
'-DG_LOG_DOMAIN="Clapper"',
|
||||
'-DCLAPPER_COMPILATION',
|
||||
'-DCLAPPER_DISABLE_DEPRECATION_WARNINGS',
|
||||
'-DGST_USE_UNSTABLE_API',
|
||||
'-DG_SETTINGS_ENABLE_BACKEND',
|
||||
]
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
#define @CLAPPER_API@_API _@CLAPPER_API@_VISIBILITY
|
||||
|
||||
#if !defined(@CLAPPER_API@_COMPILATION)
|
||||
#if !defined(CLAPPER_DISABLE_DEPRECATION_WARNINGS)
|
||||
#define @CLAPPER_API@_DEPRECATED G_DEPRECATED _@CLAPPER_API@_VISIBILITY
|
||||
#define @CLAPPER_API@_DEPRECATED_FOR(f) G_DEPRECATED_FOR(f) _@CLAPPER_API@_VISIBILITY
|
||||
#else
|
||||
|
||||
Reference in New Issue
Block a user