mirror of
https://github.com/Rafostar/clapper.git
synced 2025-08-29 15:22:11 +02:00
Compare commits
7 Commits
696b9a2d2e
...
b4922a5847
Author | SHA1 | Date | |
---|---|---|---|
|
b4922a5847 | ||
|
554548fbe0 | ||
|
e158fe9b5b | ||
|
c5da836bf1 | ||
|
aacf798c49 | ||
|
b717471d91 | ||
|
ea4a7d3761 |
@@ -642,18 +642,6 @@ clapper_app_application_command_line (GApplication *app, GApplicationCommandLine
|
|||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
_is_claps_file (GFile *file)
|
|
||||||
{
|
|
||||||
gchar *basename = g_file_get_basename (file);
|
|
||||||
gboolean is_claps;
|
|
||||||
|
|
||||||
is_claps = (basename && g_str_has_suffix (basename, ".claps"));
|
|
||||||
g_free (basename);
|
|
||||||
|
|
||||||
return is_claps;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
add_item_from_file (GFile *file, ClapperQueue *queue)
|
add_item_from_file (GFile *file, ClapperQueue *queue)
|
||||||
{
|
{
|
||||||
@@ -666,51 +654,6 @@ add_item_from_file (GFile *file, ClapperQueue *queue)
|
|||||||
gst_object_unref (item);
|
gst_object_unref (item);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
add_items_from_claps_file (GFile *file, ClapperQueue *queue)
|
|
||||||
{
|
|
||||||
GDataInputStream *dstream = NULL;
|
|
||||||
GFileInputStream *stream;
|
|
||||||
GError *error = NULL;
|
|
||||||
gchar *line;
|
|
||||||
|
|
||||||
if (!(stream = g_file_read (file, NULL, &error)))
|
|
||||||
goto finish;
|
|
||||||
|
|
||||||
dstream = g_data_input_stream_new (G_INPUT_STREAM (stream));
|
|
||||||
|
|
||||||
while ((line = g_data_input_stream_read_line (
|
|
||||||
dstream, NULL, NULL, &error))) {
|
|
||||||
g_strstrip (line);
|
|
||||||
|
|
||||||
if (strlen (line) > 0) {
|
|
||||||
GFile *tmp_file = gst_uri_is_valid (line)
|
|
||||||
? g_file_new_for_uri (line)
|
|
||||||
: g_file_new_for_path (line);
|
|
||||||
|
|
||||||
if (_is_claps_file (tmp_file))
|
|
||||||
add_items_from_claps_file (tmp_file, queue);
|
|
||||||
else
|
|
||||||
add_item_from_file (tmp_file, queue);
|
|
||||||
|
|
||||||
g_object_unref (tmp_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_free (line);
|
|
||||||
}
|
|
||||||
|
|
||||||
finish:
|
|
||||||
if (error) {
|
|
||||||
GST_ERROR ("Could not read \".claps\" file, reason: %s", error->message);
|
|
||||||
g_error_free (error);
|
|
||||||
}
|
|
||||||
if (stream) {
|
|
||||||
g_input_stream_close (G_INPUT_STREAM (stream), NULL, NULL);
|
|
||||||
g_object_unref (stream);
|
|
||||||
}
|
|
||||||
g_clear_object (&dstream);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
add_item_with_subtitles (GFile *media_file,
|
add_item_with_subtitles (GFile *media_file,
|
||||||
GFile *subs_file, ClapperQueue *queue)
|
GFile *subs_file, ClapperQueue *queue)
|
||||||
@@ -779,12 +722,8 @@ clapper_app_application_open (GApplication *app,
|
|||||||
if (!handled) {
|
if (!handled) {
|
||||||
gint i;
|
gint i;
|
||||||
|
|
||||||
for (i = 0; i < n_files; ++i) {
|
for (i = 0; i < n_files; ++i)
|
||||||
if (_is_claps_file (files[i]))
|
add_item_from_file (files[i], queue);
|
||||||
add_items_from_claps_file (files[i], queue);
|
|
||||||
else
|
|
||||||
add_item_from_file (files[i], queue);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
add_only = (g_strcmp0 (hint, "add-only") == 0);
|
add_only = (g_strcmp0 (hint, "add-only") == 0);
|
||||||
|
@@ -44,6 +44,8 @@ void clapper_app_bus_post_refresh_streams (ClapperAppBus *app_bus, GstObject *sr
|
|||||||
|
|
||||||
void clapper_app_bus_post_refresh_timeline (ClapperAppBus *app_bus, GstObject *src);
|
void clapper_app_bus_post_refresh_timeline (ClapperAppBus *app_bus, GstObject *src);
|
||||||
|
|
||||||
|
void clapper_app_bus_post_insert_playlist (ClapperAppBus *app_bus, GstObject *src, GstObject *playlist_item, GObject *playlist);
|
||||||
|
|
||||||
void clapper_app_bus_post_simple_signal (ClapperAppBus *app_bus, GstObject *src, guint signal_id);
|
void clapper_app_bus_post_simple_signal (ClapperAppBus *app_bus, GstObject *src, guint signal_id);
|
||||||
|
|
||||||
void clapper_app_bus_post_object_desc_signal (ClapperAppBus *app_bus, GstObject *src, guint signal_id, GstObject *object, const gchar *desc);
|
void clapper_app_bus_post_object_desc_signal (ClapperAppBus *app_bus, GstObject *src, guint signal_id, GstObject *object, const gchar *desc);
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
#include "clapper-bus-private.h"
|
#include "clapper-bus-private.h"
|
||||||
#include "clapper-app-bus-private.h"
|
#include "clapper-app-bus-private.h"
|
||||||
#include "clapper-player-private.h"
|
#include "clapper-player-private.h"
|
||||||
|
#include "clapper-queue-private.h"
|
||||||
#include "clapper-media-item-private.h"
|
#include "clapper-media-item-private.h"
|
||||||
#include "clapper-timeline-private.h"
|
#include "clapper-timeline-private.h"
|
||||||
|
|
||||||
@@ -41,6 +42,7 @@ enum
|
|||||||
CLAPPER_APP_BUS_STRUCTURE_PROP_NOTIFY,
|
CLAPPER_APP_BUS_STRUCTURE_PROP_NOTIFY,
|
||||||
CLAPPER_APP_BUS_STRUCTURE_REFRESH_STREAMS,
|
CLAPPER_APP_BUS_STRUCTURE_REFRESH_STREAMS,
|
||||||
CLAPPER_APP_BUS_STRUCTURE_REFRESH_TIMELINE,
|
CLAPPER_APP_BUS_STRUCTURE_REFRESH_TIMELINE,
|
||||||
|
CLAPPER_APP_BUS_STRUCTURE_INSERT_PLAYLIST,
|
||||||
CLAPPER_APP_BUS_STRUCTURE_SIMPLE_SIGNAL,
|
CLAPPER_APP_BUS_STRUCTURE_SIMPLE_SIGNAL,
|
||||||
CLAPPER_APP_BUS_STRUCTURE_OBJECT_DESC_SIGNAL,
|
CLAPPER_APP_BUS_STRUCTURE_OBJECT_DESC_SIGNAL,
|
||||||
CLAPPER_APP_BUS_STRUCTURE_DESC_WITH_DETAILS_SIGNAL,
|
CLAPPER_APP_BUS_STRUCTURE_DESC_WITH_DETAILS_SIGNAL,
|
||||||
@@ -52,6 +54,7 @@ static ClapperBusQuark _structure_quarks[] = {
|
|||||||
{"prop-notify", 0},
|
{"prop-notify", 0},
|
||||||
{"refresh-streams", 0},
|
{"refresh-streams", 0},
|
||||||
{"refresh-timeline", 0},
|
{"refresh-timeline", 0},
|
||||||
|
{"insert-playlist", 0},
|
||||||
{"simple-signal", 0},
|
{"simple-signal", 0},
|
||||||
{"object-desc-signal", 0},
|
{"object-desc-signal", 0},
|
||||||
{"desc-with-details-signal", 0},
|
{"desc-with-details-signal", 0},
|
||||||
@@ -65,6 +68,7 @@ enum
|
|||||||
CLAPPER_APP_BUS_FIELD_PSPEC,
|
CLAPPER_APP_BUS_FIELD_PSPEC,
|
||||||
CLAPPER_APP_BUS_FIELD_SIGNAL_ID,
|
CLAPPER_APP_BUS_FIELD_SIGNAL_ID,
|
||||||
CLAPPER_APP_BUS_FIELD_OBJECT,
|
CLAPPER_APP_BUS_FIELD_OBJECT,
|
||||||
|
CLAPPER_APP_BUS_FIELD_OTHER_OBJECT,
|
||||||
CLAPPER_APP_BUS_FIELD_DESC,
|
CLAPPER_APP_BUS_FIELD_DESC,
|
||||||
CLAPPER_APP_BUS_FIELD_DETAILS,
|
CLAPPER_APP_BUS_FIELD_DETAILS,
|
||||||
CLAPPER_APP_BUS_FIELD_ERROR,
|
CLAPPER_APP_BUS_FIELD_ERROR,
|
||||||
@@ -76,6 +80,7 @@ static ClapperBusQuark _field_quarks[] = {
|
|||||||
{"pspec", 0},
|
{"pspec", 0},
|
||||||
{"signal-id", 0},
|
{"signal-id", 0},
|
||||||
{"object", 0},
|
{"object", 0},
|
||||||
|
{"other-object", 0},
|
||||||
{"desc", 0},
|
{"desc", 0},
|
||||||
{"details", 0},
|
{"details", 0},
|
||||||
{"error", 0},
|
{"error", 0},
|
||||||
@@ -160,6 +165,36 @@ _handle_refresh_timeline_msg (GstMessage *msg, const GstStructure *structure)
|
|||||||
clapper_timeline_refresh (timeline);
|
clapper_timeline_refresh (timeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
clapper_app_bus_post_insert_playlist (ClapperAppBus *self, GstObject *src,
|
||||||
|
GstObject *playlist_item, GObject *playlist)
|
||||||
|
{
|
||||||
|
GstStructure *structure = gst_structure_new_id (_STRUCTURE_QUARK (INSERT_PLAYLIST),
|
||||||
|
_FIELD_QUARK (OBJECT), GST_TYPE_OBJECT, playlist_item,
|
||||||
|
_FIELD_QUARK (OTHER_OBJECT), G_TYPE_OBJECT, playlist,
|
||||||
|
NULL);
|
||||||
|
gst_bus_post (GST_BUS_CAST (self), gst_message_new_application (src, structure));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
_handle_insert_playlist_msg (GstMessage *msg, const GstStructure *structure)
|
||||||
|
{
|
||||||
|
ClapperPlayer *player = CLAPPER_PLAYER_CAST (GST_MESSAGE_SRC (msg));
|
||||||
|
ClapperQueue *queue = clapper_player_get_queue (player);
|
||||||
|
GstObject *playlist_item;
|
||||||
|
GObject *playlist;
|
||||||
|
|
||||||
|
gst_structure_id_get (structure,
|
||||||
|
_FIELD_QUARK (OBJECT), GST_TYPE_OBJECT, &playlist_item,
|
||||||
|
_FIELD_QUARK (OTHER_OBJECT), G_TYPE_OBJECT, &playlist,
|
||||||
|
NULL);
|
||||||
|
clapper_queue_handle_playlist (queue,
|
||||||
|
CLAPPER_MEDIA_ITEM (playlist_item), G_LIST_STORE (playlist));
|
||||||
|
|
||||||
|
gst_object_unref (playlist_item);
|
||||||
|
g_object_unref (playlist);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
clapper_app_bus_post_simple_signal (ClapperAppBus *self, GstObject *src, guint signal_id)
|
clapper_app_bus_post_simple_signal (ClapperAppBus *self, GstObject *src, guint signal_id)
|
||||||
{
|
{
|
||||||
@@ -285,6 +320,8 @@ clapper_app_bus_message_func (GstBus *bus, GstMessage *msg, gpointer user_data G
|
|||||||
_handle_refresh_streams_msg (msg, structure);
|
_handle_refresh_streams_msg (msg, structure);
|
||||||
else if (quark == _STRUCTURE_QUARK (REFRESH_TIMELINE))
|
else if (quark == _STRUCTURE_QUARK (REFRESH_TIMELINE))
|
||||||
_handle_refresh_timeline_msg (msg, structure);
|
_handle_refresh_timeline_msg (msg, structure);
|
||||||
|
else if (quark == _STRUCTURE_QUARK (INSERT_PLAYLIST))
|
||||||
|
_handle_insert_playlist_msg (msg, structure);
|
||||||
else if (quark == _STRUCTURE_QUARK (SIMPLE_SIGNAL))
|
else if (quark == _STRUCTURE_QUARK (SIMPLE_SIGNAL))
|
||||||
_handle_simple_signal_msg (msg, structure);
|
_handle_simple_signal_msg (msg, structure);
|
||||||
else if (quark == _STRUCTURE_QUARK (OBJECT_DESC_SIGNAL))
|
else if (quark == _STRUCTURE_QUARK (OBJECT_DESC_SIGNAL))
|
||||||
|
@@ -29,6 +29,9 @@ G_BEGIN_DECLS
|
|||||||
G_GNUC_INTERNAL
|
G_GNUC_INTERNAL
|
||||||
ClapperHarvest * clapper_harvest_new (void);
|
ClapperHarvest * clapper_harvest_new (void);
|
||||||
|
|
||||||
|
G_GNUC_INTERNAL
|
||||||
|
void clapper_harvest_set_enhancer_in_caps (ClapperHarvest *harvest, ClapperEnhancerProxy *proxy);
|
||||||
|
|
||||||
G_GNUC_INTERNAL
|
G_GNUC_INTERNAL
|
||||||
gboolean clapper_harvest_unpack (ClapperHarvest *harvest, GstBuffer **buffer, gsize *buf_size, GstCaps **caps, GstTagList **tags, GstToc **toc, GstStructure **headers);
|
gboolean clapper_harvest_unpack (ClapperHarvest *harvest, GstBuffer **buffer, gsize *buf_size, GstCaps **caps, GstTagList **tags, GstToc **toc, GstStructure **headers);
|
||||||
|
|
||||||
|
@@ -94,6 +94,13 @@ clapper_harvest_new (void)
|
|||||||
return harvest;
|
return harvest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
clapper_harvest_set_enhancer_in_caps (ClapperHarvest *self, ClapperEnhancerProxy *proxy)
|
||||||
|
{
|
||||||
|
gst_caps_set_simple (self->caps, "enhancer", G_TYPE_STRING,
|
||||||
|
clapper_enhancer_proxy_get_module_name (proxy), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
clapper_harvest_unpack (ClapperHarvest *self,
|
clapper_harvest_unpack (ClapperHarvest *self,
|
||||||
GstBuffer **buffer, gsize *buf_size, GstCaps **caps,
|
GstBuffer **buffer, gsize *buf_size, GstCaps **caps,
|
||||||
@@ -221,7 +228,6 @@ clapper_harvest_fill_from_cache (ClapperHarvest *self, ClapperEnhancerProxy *pro
|
|||||||
gchar *filename;
|
gchar *filename;
|
||||||
const gchar *data, *read_str;
|
const gchar *data, *read_str;
|
||||||
const guint8 *buf_data;
|
const guint8 *buf_data;
|
||||||
guint8 *buf_copy;
|
|
||||||
gsize buf_size;
|
gsize buf_size;
|
||||||
gint64 epoch_cached, epoch_now = 0;
|
gint64 epoch_cached, epoch_now = 0;
|
||||||
gdouble exp_seconds;
|
gdouble exp_seconds;
|
||||||
@@ -281,10 +287,10 @@ clapper_harvest_fill_from_cache (ClapperHarvest *self, ClapperEnhancerProxy *pro
|
|||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read media type */
|
/* Read caps */
|
||||||
read_str = clapper_cache_read_string (&data);
|
read_str = clapper_cache_read_string (&data);
|
||||||
if (G_UNLIKELY (read_str == NULL)) {
|
if (G_UNLIKELY (read_str == NULL)) {
|
||||||
GST_ERROR_OBJECT (self, "Could not read media type from cache file");
|
GST_ERROR_OBJECT (self, "Could not read caps from cache file");
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,9 +302,12 @@ clapper_harvest_fill_from_cache (ClapperHarvest *self, ClapperEnhancerProxy *pro
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Fill harvest */
|
/* Fill harvest */
|
||||||
buf_copy = g_memdup2 (buf_data, buf_size);
|
if (!(self->caps = gst_caps_from_string (read_str))) {
|
||||||
if (!clapper_harvest_fill (self, read_str, buf_copy, buf_size))
|
GST_ERROR_OBJECT (self, "Could not construct caps from cache");
|
||||||
goto finish;
|
goto finish;
|
||||||
|
}
|
||||||
|
self->buffer = gst_buffer_new_memdup (buf_data, buf_size);
|
||||||
|
self->buf_size = buf_size;
|
||||||
|
|
||||||
/* Read tags */
|
/* Read tags */
|
||||||
read_str = clapper_cache_read_string (&data);
|
read_str = clapper_cache_read_string (&data);
|
||||||
@@ -332,7 +341,6 @@ clapper_harvest_export_to_cache (ClapperHarvest *self, ClapperEnhancerProxy *pro
|
|||||||
const GstStructure *config, GUri *uri)
|
const GstStructure *config, GUri *uri)
|
||||||
{
|
{
|
||||||
GByteArray *bytes;
|
GByteArray *bytes;
|
||||||
const GstStructure *caps_structure;
|
|
||||||
gchar *filename, *temp_str = NULL;
|
gchar *filename, *temp_str = NULL;
|
||||||
gboolean data_ok = TRUE;
|
gboolean data_ok = TRUE;
|
||||||
|
|
||||||
@@ -366,12 +374,13 @@ clapper_harvest_export_to_cache (ClapperHarvest *self, ClapperEnhancerProxy *pro
|
|||||||
clapper_cache_store_string (bytes, temp_str); // NULL when no config
|
clapper_cache_store_string (bytes, temp_str); // NULL when no config
|
||||||
g_clear_pointer (&temp_str, g_free);
|
g_clear_pointer (&temp_str, g_free);
|
||||||
|
|
||||||
/* Store media type */
|
/* Store caps */
|
||||||
caps_structure = gst_caps_get_structure (self->caps, 0);
|
temp_str = gst_caps_to_string (self->caps);
|
||||||
if (G_LIKELY (caps_structure != NULL)) {
|
if (G_LIKELY (temp_str != NULL)) {
|
||||||
clapper_cache_store_string (bytes, gst_structure_get_name (caps_structure));
|
clapper_cache_store_string (bytes, temp_str);
|
||||||
|
g_clear_pointer (&temp_str, g_free);
|
||||||
} else {
|
} else {
|
||||||
GST_ERROR_OBJECT (self, "Cannot cache empty caps");
|
GST_ERROR_OBJECT (self, "Cannot cache caps");
|
||||||
data_ok = FALSE;
|
data_ok = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,11 +443,15 @@ clapper_harvest_export_to_cache (ClapperHarvest *self, ClapperEnhancerProxy *pro
|
|||||||
*
|
*
|
||||||
* Commonly used media types are:
|
* Commonly used media types are:
|
||||||
*
|
*
|
||||||
* * `application/dash+xml`
|
* * `application/dash+xml` - DASH manifest
|
||||||
*
|
*
|
||||||
* * `application/x-hls`
|
* * `application/x-hls` - HLS manifest
|
||||||
*
|
*
|
||||||
* * `text/uri-list`
|
* * `text/x-uri` - direct media URI
|
||||||
|
*
|
||||||
|
* * `text/uri-list` - playlist of URIs
|
||||||
|
*
|
||||||
|
* * `application/clapper-playlist` - custom playlist format
|
||||||
*
|
*
|
||||||
* Returns: %TRUE when filled successfully, %FALSE if taken data was empty.
|
* Returns: %TRUE when filled successfully, %FALSE if taken data was empty.
|
||||||
*
|
*
|
||||||
@@ -459,6 +472,7 @@ clapper_harvest_fill (ClapperHarvest *self, const gchar *media_type, gpointer da
|
|||||||
if (gst_debug_category_get_threshold (GST_CAT_DEFAULT) >= GST_LEVEL_LOG) {
|
if (gst_debug_category_get_threshold (GST_CAT_DEFAULT) >= GST_LEVEL_LOG) {
|
||||||
gboolean is_printable = (strcmp (media_type, "application/dash+xml") == 0)
|
gboolean is_printable = (strcmp (media_type, "application/dash+xml") == 0)
|
||||||
|| (strcmp (media_type, "application/x-hls") == 0)
|
|| (strcmp (media_type, "application/x-hls") == 0)
|
||||||
|
|| (strcmp (media_type, "text/x-uri") == 0)
|
||||||
|| (strcmp (media_type, "text/uri-list") == 0);
|
|| (strcmp (media_type, "text/uri-list") == 0);
|
||||||
|
|
||||||
if (is_printable) {
|
if (is_printable) {
|
||||||
|
@@ -33,6 +33,9 @@ void clapper_media_item_update_from_tag_list (ClapperMediaItem *item, const GstT
|
|||||||
G_GNUC_INTERNAL
|
G_GNUC_INTERNAL
|
||||||
void clapper_media_item_update_from_discoverer_info (ClapperMediaItem *self, GstDiscovererInfo *info);
|
void clapper_media_item_update_from_discoverer_info (ClapperMediaItem *self, GstDiscovererInfo *info);
|
||||||
|
|
||||||
|
G_GNUC_INTERNAL
|
||||||
|
gboolean clapper_media_item_update_from_item (ClapperMediaItem *item, ClapperMediaItem *other_item, ClapperPlayer *player);
|
||||||
|
|
||||||
G_GNUC_INTERNAL
|
G_GNUC_INTERNAL
|
||||||
gboolean clapper_media_item_set_duration (ClapperMediaItem *item, gdouble duration, ClapperAppBus *app_bus);
|
gboolean clapper_media_item_set_duration (ClapperMediaItem *item, gdouble duration, ClapperAppBus *app_bus);
|
||||||
|
|
||||||
|
@@ -51,6 +51,10 @@ struct _ClapperMediaItem
|
|||||||
gchar *container_format;
|
gchar *container_format;
|
||||||
gdouble duration;
|
gdouble duration;
|
||||||
|
|
||||||
|
/* Whether using title from URI */
|
||||||
|
gboolean title_is_parsed;
|
||||||
|
|
||||||
|
GSList *redirects;
|
||||||
gchar *cache_uri;
|
gchar *cache_uri;
|
||||||
|
|
||||||
/* For shuffle */
|
/* For shuffle */
|
||||||
@@ -198,6 +202,12 @@ clapper_media_item_get_id (ClapperMediaItem *self)
|
|||||||
return self->id;
|
return self->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* FIXME: 1.0:
|
||||||
|
* Consider change to be transfer-full and just return latest data from redirects
|
||||||
|
* list (alternatively expose redirect URI). This should make it possible to work
|
||||||
|
* with enhancers that would benefit from knowledge about URI changes
|
||||||
|
* (e.g "Recall" could read actual media instead of playlist file).
|
||||||
|
*/
|
||||||
/**
|
/**
|
||||||
* clapper_media_item_get_uri:
|
* clapper_media_item_get_uri:
|
||||||
* @item: a #ClapperMediaItem
|
* @item: a #ClapperMediaItem
|
||||||
@@ -295,11 +305,11 @@ clapper_media_item_get_title (ClapperMediaItem *self)
|
|||||||
|
|
||||||
static inline gboolean
|
static inline gboolean
|
||||||
_refresh_tag_prop_unlocked (ClapperMediaItem *self, const gchar *tag,
|
_refresh_tag_prop_unlocked (ClapperMediaItem *self, const gchar *tag,
|
||||||
gboolean from_user, gchar **tag_ptr)
|
gboolean allow_overwrite, gchar **tag_ptr)
|
||||||
{
|
{
|
||||||
const gchar *string;
|
const gchar *string;
|
||||||
|
|
||||||
if ((*tag_ptr && from_user) // if already set, user cannot modify it
|
if ((*tag_ptr && !allow_overwrite)
|
||||||
|| !gst_tag_list_peek_string_index (self->tags, tag, 0, &string) // guarantees non-empty string
|
|| !gst_tag_list_peek_string_index (self->tags, tag, 0, &string) // guarantees non-empty string
|
||||||
|| (g_strcmp0 (*tag_ptr, string) == 0))
|
|| (g_strcmp0 (*tag_ptr, string) == 0))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@@ -488,11 +498,12 @@ clapper_media_item_insert_tags_internal (ClapperMediaItem *self, const GstTagLis
|
|||||||
*flags |= CLAPPER_REACTABLE_ITEM_UPDATED_TAGS;
|
*flags |= CLAPPER_REACTABLE_ITEM_UPDATED_TAGS;
|
||||||
|
|
||||||
if ((title_changed = _refresh_tag_prop_unlocked (self, GST_TAG_TITLE,
|
if ((title_changed = _refresh_tag_prop_unlocked (self, GST_TAG_TITLE,
|
||||||
from_user, &self->title))) {
|
(!from_user || self->title_is_parsed), &self->title))) {
|
||||||
|
self->title_is_parsed = FALSE;
|
||||||
*flags |= CLAPPER_REACTABLE_ITEM_UPDATED_TITLE;
|
*flags |= CLAPPER_REACTABLE_ITEM_UPDATED_TITLE;
|
||||||
}
|
}
|
||||||
cont_changed = _refresh_tag_prop_unlocked (self, GST_TAG_CONTAINER_FORMAT,
|
cont_changed = _refresh_tag_prop_unlocked (self, GST_TAG_CONTAINER_FORMAT,
|
||||||
from_user, &self->container_format);
|
!from_user, &self->container_format);
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_OBJECT_UNLOCK (self);
|
GST_OBJECT_UNLOCK (self);
|
||||||
@@ -668,6 +679,61 @@ clapper_media_item_update_from_discoverer_info (ClapperMediaItem *self, GstDisco
|
|||||||
gst_object_unref (player);
|
gst_object_unref (player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* XXX: Must be set from player thread */
|
||||||
|
static inline gboolean
|
||||||
|
clapper_media_item_set_redirect_uri (ClapperMediaItem *self, const gchar *redirect_uri)
|
||||||
|
{
|
||||||
|
/* Check if we did not already redirect into that URI (prevent endless loop) */
|
||||||
|
if (!redirect_uri || g_slist_find_custom (self->redirects, redirect_uri, (GCompareFunc) strcmp))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
self->redirects = g_slist_prepend (self->redirects, g_strdup (redirect_uri));
|
||||||
|
GST_DEBUG_OBJECT (self, "Set redirect URI: \"%s\"", (gchar *) self->redirects->data);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
clapper_media_item_update_from_item (ClapperMediaItem *self, ClapperMediaItem *other_item,
|
||||||
|
ClapperPlayer *player)
|
||||||
|
{
|
||||||
|
gboolean title_changed = FALSE;
|
||||||
|
|
||||||
|
if (!clapper_media_item_set_redirect_uri (self, clapper_media_item_get_uri (other_item)))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
GST_OBJECT_LOCK (other_item);
|
||||||
|
|
||||||
|
if (other_item->tags)
|
||||||
|
clapper_media_item_update_from_tag_list (self, other_item->tags, 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
|
||||||
|
* did not contain it, thus we have to manually update it and notify. */
|
||||||
|
if (other_item->title_is_parsed) {
|
||||||
|
GST_OBJECT_LOCK (self);
|
||||||
|
title_changed = g_set_str (&self->title, other_item->title);
|
||||||
|
self->title_is_parsed = TRUE;
|
||||||
|
GST_OBJECT_UNLOCK (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_OBJECT_UNLOCK (other_item);
|
||||||
|
|
||||||
|
if (title_changed) {
|
||||||
|
ClapperReactableItemUpdatedFlags flags = CLAPPER_REACTABLE_ITEM_UPDATED_TITLE;
|
||||||
|
ClapperFeaturesManager *features_manager;
|
||||||
|
|
||||||
|
clapper_app_bus_post_prop_notify (player->app_bus, GST_OBJECT_CAST (self), param_specs[PROP_TITLE]);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* XXX: Must be set from player thread or upon construction */
|
/* XXX: Must be set from player thread or upon construction */
|
||||||
void
|
void
|
||||||
clapper_media_item_set_cache_location (ClapperMediaItem *self, const gchar *location)
|
clapper_media_item_set_cache_location (ClapperMediaItem *self, const gchar *location)
|
||||||
@@ -682,7 +748,7 @@ clapper_media_item_set_cache_location (ClapperMediaItem *self, const gchar *loca
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* XXX: Can only be read from player thread.
|
/* XXX: Can only be read from player thread.
|
||||||
* Returns cache URI if available, item URI otherwise. */
|
* Returns cache URI if available, otherwise redirect or item URI. */
|
||||||
inline const gchar *
|
inline const gchar *
|
||||||
clapper_media_item_get_playback_uri (ClapperMediaItem *self)
|
clapper_media_item_get_playback_uri (ClapperMediaItem *self)
|
||||||
{
|
{
|
||||||
@@ -702,6 +768,9 @@ clapper_media_item_get_playback_uri (ClapperMediaItem *self)
|
|||||||
clapper_media_item_set_cache_location (self, NULL);
|
clapper_media_item_set_cache_location (self, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (self->redirects)
|
||||||
|
return self->redirects->data;
|
||||||
|
|
||||||
return self->uri;
|
return self->uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -745,6 +814,7 @@ clapper_media_item_constructed (GObject *object)
|
|||||||
self->uri = g_strdup ("file://");
|
self->uri = g_strdup ("file://");
|
||||||
|
|
||||||
self->title = clapper_utils_title_from_uri (self->uri);
|
self->title = clapper_utils_title_from_uri (self->uri);
|
||||||
|
self->title_is_parsed = (self->title != NULL);
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->constructed (object);
|
G_OBJECT_CLASS (parent_class)->constructed (object);
|
||||||
}
|
}
|
||||||
@@ -765,6 +835,7 @@ clapper_media_item_finalize (GObject *object)
|
|||||||
gst_object_unparent (GST_OBJECT_CAST (self->timeline));
|
gst_object_unparent (GST_OBJECT_CAST (self->timeline));
|
||||||
gst_object_unref (self->timeline);
|
gst_object_unref (self->timeline);
|
||||||
|
|
||||||
|
g_slist_free_full (self->redirects, g_free);
|
||||||
g_free (self->cache_uri);
|
g_free (self->cache_uri);
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
@@ -892,7 +963,8 @@ clapper_media_item_class_init (ClapperMediaItemClass *klass)
|
|||||||
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||||
|
|
||||||
/* FIXME: 1.0: Consider rename to e.g. "(menu/display)-title"
|
/* FIXME: 1.0: Consider rename to e.g. "(menu/display)-title"
|
||||||
* and also make it non-nullable (return URI as final fallback) */
|
* and also make it non-nullable (return URI as final fallback).
|
||||||
|
* NOTE: It would probably need to work with redirect URI */
|
||||||
/**
|
/**
|
||||||
* ClapperMediaItem:title:
|
* ClapperMediaItem:title:
|
||||||
*
|
*
|
||||||
|
@@ -831,6 +831,71 @@ _handle_element_msg (GstMessage *msg, ClapperPlayer *player)
|
|||||||
|
|
||||||
g_free (name);
|
g_free (name);
|
||||||
g_free (details);
|
g_free (details);
|
||||||
|
} else if (gst_message_has_name (msg, "ClapperPlaylistParsed")) {
|
||||||
|
ClapperMediaItem *playlist_item = NULL;
|
||||||
|
GListStore *playlist = NULL;
|
||||||
|
const GstStructure *structure = gst_message_get_structure (msg);
|
||||||
|
guint n_items;
|
||||||
|
|
||||||
|
/* If message contains item, use that.
|
||||||
|
* Otherwise assume pending item was parsed. */
|
||||||
|
if (gst_structure_has_field (structure, "item")) {
|
||||||
|
gst_structure_get (structure,
|
||||||
|
"item", CLAPPER_TYPE_MEDIA_ITEM, &playlist_item, NULL);
|
||||||
|
} else {
|
||||||
|
GST_OBJECT_LOCK (player);
|
||||||
|
|
||||||
|
/* Playlist is always parsed before playback starts */
|
||||||
|
if (player->pending_item)
|
||||||
|
playlist_item = gst_object_ref (player->pending_item);
|
||||||
|
|
||||||
|
GST_OBJECT_UNLOCK (player);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (G_UNLIKELY (playlist_item == NULL)) {
|
||||||
|
GST_WARNING_OBJECT (player, "Playlist parsed without media item set");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_INFO_OBJECT (player, "Received parsed playlist of %" GST_PTR_FORMAT
|
||||||
|
"(%s)", playlist_item, clapper_media_item_get_uri (playlist_item));
|
||||||
|
|
||||||
|
gst_structure_get (structure,
|
||||||
|
"playlist", G_TYPE_LIST_STORE, &playlist, NULL);
|
||||||
|
|
||||||
|
n_items = g_list_model_get_n_items (G_LIST_MODEL (playlist));
|
||||||
|
|
||||||
|
if (G_LIKELY (n_items > 0)) {
|
||||||
|
ClapperMediaItem *active_item = g_list_model_get_item (G_LIST_MODEL (playlist), 0);
|
||||||
|
gboolean updated;
|
||||||
|
|
||||||
|
/* Update redirect URI (must be done from player thread) */
|
||||||
|
updated = clapper_media_item_update_from_item (playlist_item, active_item, player);
|
||||||
|
gst_object_unref (active_item);
|
||||||
|
|
||||||
|
if (!updated) {
|
||||||
|
GstMessage *msg;
|
||||||
|
GError *error;
|
||||||
|
|
||||||
|
error = g_error_new (GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
|
||||||
|
"Detected infinite redirection in playlist");
|
||||||
|
msg = gst_message_new_error (GST_OBJECT (player), error, NULL);
|
||||||
|
|
||||||
|
_handle_error_msg (msg, player);
|
||||||
|
|
||||||
|
g_error_free (error);
|
||||||
|
gst_message_unref (msg);
|
||||||
|
} else if (n_items > 1) {
|
||||||
|
/* Forward to append remaining items (must be done from main thread) */
|
||||||
|
clapper_app_bus_post_insert_playlist (player->app_bus,
|
||||||
|
GST_OBJECT_CAST (player),
|
||||||
|
GST_OBJECT_CAST (playlist_item),
|
||||||
|
G_OBJECT (playlist));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_object_unref (playlist_item);
|
||||||
|
g_object_unref (playlist);
|
||||||
} else if (gst_message_has_name (msg, "GstCacheDownloadComplete")) {
|
} else if (gst_message_has_name (msg, "GstCacheDownloadComplete")) {
|
||||||
ClapperMediaItem *downloaded_item = NULL;
|
ClapperMediaItem *downloaded_item = NULL;
|
||||||
const GstStructure *structure;
|
const GstStructure *structure;
|
||||||
|
@@ -826,7 +826,8 @@ _element_setup_cb (GstElement *playbin, GstElement *element, ClapperPlayer *self
|
|||||||
factory_name = g_intern_static_string (GST_OBJECT_NAME (factory));
|
factory_name = g_intern_static_string (GST_OBJECT_NAME (factory));
|
||||||
GST_INFO_OBJECT (self, "Element setup: %s", factory_name);
|
GST_INFO_OBJECT (self, "Element setup: %s", factory_name);
|
||||||
|
|
||||||
if (factory_name == g_intern_static_string ("clapperextractablesrc")) {
|
if (factory_name == g_intern_static_string ("clapperextractablesrc")
|
||||||
|
|| factory_name == g_intern_static_string ("clapperplaylistdemux")) {
|
||||||
g_object_set (element,
|
g_object_set (element,
|
||||||
"enhancer-proxies", self->enhancer_proxies,
|
"enhancer-proxies", self->enhancer_proxies,
|
||||||
NULL);
|
NULL);
|
||||||
|
@@ -19,6 +19,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
#include <gio/gio.h>
|
||||||
|
|
||||||
#include "clapper-queue.h"
|
#include "clapper-queue.h"
|
||||||
#include "clapper-media-item.h"
|
#include "clapper-media-item.h"
|
||||||
@@ -31,6 +32,8 @@ ClapperQueue * clapper_queue_new (void);
|
|||||||
|
|
||||||
void clapper_queue_handle_played_item_changed (ClapperQueue *queue, ClapperMediaItem *played_item, ClapperAppBus *app_bus);
|
void clapper_queue_handle_played_item_changed (ClapperQueue *queue, ClapperMediaItem *played_item, ClapperAppBus *app_bus);
|
||||||
|
|
||||||
|
void clapper_queue_handle_playlist (ClapperQueue *queue, ClapperMediaItem *playlist_item, GListStore *playlist);
|
||||||
|
|
||||||
void clapper_queue_handle_about_to_finish (ClapperQueue *queue, ClapperPlayer *player);
|
void clapper_queue_handle_about_to_finish (ClapperQueue *queue, ClapperPlayer *player);
|
||||||
|
|
||||||
gboolean clapper_queue_handle_eos (ClapperQueue *queue, ClapperPlayer *player);
|
gboolean clapper_queue_handle_eos (ClapperQueue *queue, ClapperPlayer *player);
|
||||||
|
@@ -337,6 +337,42 @@ _get_next_item_unlocked (ClapperQueue *self, ClapperQueueProgressionMode mode)
|
|||||||
return next_item;
|
return next_item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_take_item_unlocked (ClapperQueue *self, ClapperMediaItem *item, gint index)
|
||||||
|
{
|
||||||
|
guint prev_length = self->items->len;
|
||||||
|
|
||||||
|
g_ptr_array_insert (self->items, index, item);
|
||||||
|
gst_object_set_parent (GST_OBJECT_CAST (item), GST_OBJECT_CAST (self));
|
||||||
|
|
||||||
|
/* In append we inserted at array length */
|
||||||
|
if (index < 0)
|
||||||
|
index = prev_length;
|
||||||
|
|
||||||
|
_announce_model_update (self, index, 0, 1, item);
|
||||||
|
|
||||||
|
/* If has selection and inserting before it */
|
||||||
|
if (self->current_index != CLAPPER_QUEUE_INVALID_POSITION
|
||||||
|
&& (guint) index <= self->current_index) {
|
||||||
|
self->current_index++;
|
||||||
|
_announce_current_index_change (self);
|
||||||
|
} else if (prev_length == 0 && _replace_current_item_unlocked (self, item, 0)) {
|
||||||
|
/* If queue was empty, auto select first item and announce it */
|
||||||
|
_announce_current_item_and_index_change (self);
|
||||||
|
} else if (self->current_index == prev_length - 1
|
||||||
|
&& clapper_queue_get_progression_mode (self) == CLAPPER_QUEUE_PROGRESSION_CONSECUTIVE) {
|
||||||
|
ClapperPlayer *player = clapper_player_get_from_ancestor (GST_OBJECT_CAST (self));
|
||||||
|
gboolean after_eos = (gboolean) g_atomic_int_get (&player->eos);
|
||||||
|
|
||||||
|
/* In consecutive progression automatically select next item
|
||||||
|
* if we were after EOS of last queue item */
|
||||||
|
if (after_eos && _replace_current_item_unlocked (self, item, index))
|
||||||
|
_announce_current_item_and_index_change (self);
|
||||||
|
|
||||||
|
gst_object_unref (player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For gapless we need to manually replace current item in queue when it starts
|
* For gapless we need to manually replace current item in queue when it starts
|
||||||
* playing and emit notify about change, this function will do that if necessary
|
* playing and emit notify about change, this function will do that if necessary
|
||||||
@@ -366,6 +402,31 @@ clapper_queue_handle_played_item_changed (ClapperQueue *self, ClapperMediaItem *
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Must be called from main thread */
|
||||||
|
void
|
||||||
|
clapper_queue_handle_playlist (ClapperQueue *self, ClapperMediaItem *playlist_item,
|
||||||
|
GListStore *playlist)
|
||||||
|
{
|
||||||
|
GListModel *playlist_model = G_LIST_MODEL (playlist);
|
||||||
|
guint i, index, n_items = g_list_model_get_n_items (playlist_model);
|
||||||
|
|
||||||
|
CLAPPER_QUEUE_REC_LOCK (self);
|
||||||
|
|
||||||
|
/* If playlist item is still in the queue, insert
|
||||||
|
* remaining items after it, otherwise append */
|
||||||
|
if (G_LIKELY (g_ptr_array_find (self->items, playlist_item, &index)))
|
||||||
|
index++;
|
||||||
|
else
|
||||||
|
index = self->items->len;
|
||||||
|
|
||||||
|
for (i = 1; i < n_items; ++i) {
|
||||||
|
ClapperMediaItem *item = g_list_model_get_item (playlist_model, i);
|
||||||
|
_take_item_unlocked (self, item, index++);
|
||||||
|
}
|
||||||
|
|
||||||
|
CLAPPER_QUEUE_REC_UNLOCK (self);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
clapper_queue_handle_about_to_finish (ClapperQueue *self, ClapperPlayer *player)
|
clapper_queue_handle_about_to_finish (ClapperQueue *self, ClapperPlayer *player)
|
||||||
{
|
{
|
||||||
@@ -481,39 +542,8 @@ clapper_queue_insert_item (ClapperQueue *self, ClapperMediaItem *item, gint inde
|
|||||||
|
|
||||||
CLAPPER_QUEUE_REC_LOCK (self);
|
CLAPPER_QUEUE_REC_LOCK (self);
|
||||||
|
|
||||||
if (!g_ptr_array_find (self->items, item, NULL)) {
|
if (!g_ptr_array_find (self->items, item, NULL))
|
||||||
guint prev_length = self->items->len;
|
_take_item_unlocked (self, gst_object_ref (item), index);
|
||||||
|
|
||||||
g_ptr_array_insert (self->items, index, gst_object_ref (item));
|
|
||||||
gst_object_set_parent (GST_OBJECT_CAST (item), GST_OBJECT_CAST (self));
|
|
||||||
|
|
||||||
/* In append we inserted at array length */
|
|
||||||
if (index < 0)
|
|
||||||
index = prev_length;
|
|
||||||
|
|
||||||
_announce_model_update (self, index, 0, 1, item);
|
|
||||||
|
|
||||||
/* If has selection and inserting before it */
|
|
||||||
if (self->current_index != CLAPPER_QUEUE_INVALID_POSITION
|
|
||||||
&& (guint) index <= self->current_index) {
|
|
||||||
self->current_index++;
|
|
||||||
_announce_current_index_change (self);
|
|
||||||
} else if (prev_length == 0 && _replace_current_item_unlocked (self, item, 0)) {
|
|
||||||
/* If queue was empty, auto select first item and announce it */
|
|
||||||
_announce_current_item_and_index_change (self);
|
|
||||||
} else if (self->current_index == prev_length - 1
|
|
||||||
&& clapper_queue_get_progression_mode (self) == CLAPPER_QUEUE_PROGRESSION_CONSECUTIVE) {
|
|
||||||
ClapperPlayer *player = clapper_player_get_from_ancestor (GST_OBJECT_CAST (self));
|
|
||||||
gboolean after_eos = (gboolean) g_atomic_int_get (&player->eos);
|
|
||||||
|
|
||||||
/* In consecutive progression automatically select next item
|
|
||||||
* if we were after EOS of last queue item */
|
|
||||||
if (after_eos && _replace_current_item_unlocked (self, item, index))
|
|
||||||
_announce_current_item_and_index_change (self);
|
|
||||||
|
|
||||||
gst_object_unref (player);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CLAPPER_QUEUE_REC_UNLOCK (self);
|
CLAPPER_QUEUE_REC_UNLOCK (self);
|
||||||
}
|
}
|
||||||
|
@@ -39,6 +39,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
#include <gst/tag/tag.h>
|
||||||
#include <gst/pbutils/pbutils.h>
|
#include <gst/pbutils/pbutils.h>
|
||||||
|
|
||||||
#include "clapper-discoverer.h"
|
#include "clapper-discoverer.h"
|
||||||
@@ -128,8 +129,9 @@ _run_discovery (ClapperDiscoverer *self)
|
|||||||
ClapperMediaItem *item;
|
ClapperMediaItem *item;
|
||||||
ClapperQueue *queue;
|
ClapperQueue *queue;
|
||||||
ClapperDiscovererDiscoveryMode discovery_mode;
|
ClapperDiscovererDiscoveryMode discovery_mode;
|
||||||
|
GstTagList *tags;
|
||||||
const gchar *uri;
|
const gchar *uri;
|
||||||
gboolean success = FALSE;
|
gboolean had_tags, success = FALSE;
|
||||||
|
|
||||||
if (self->pending_items->len == 0) {
|
if (self->pending_items->len == 0) {
|
||||||
GST_DEBUG_OBJECT (self, "No more pending items");
|
GST_DEBUG_OBJECT (self, "No more pending items");
|
||||||
@@ -157,6 +159,16 @@ _run_discovery (ClapperDiscoverer *self)
|
|||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tags = clapper_media_item_get_tags (item);
|
||||||
|
had_tags = !gst_tag_list_is_empty (tags);
|
||||||
|
gst_tag_list_unref (tags);
|
||||||
|
|
||||||
|
if (had_tags) {
|
||||||
|
GST_DEBUG_OBJECT (self, "Queued %" GST_PTR_FORMAT
|
||||||
|
" already has tags, ignoring discovery", item);
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
uri = clapper_media_item_get_uri (item);
|
uri = clapper_media_item_get_uri (item);
|
||||||
GST_DEBUG_OBJECT (self, "Starting discovery of %"
|
GST_DEBUG_OBJECT (self, "Starting discovery of %"
|
||||||
GST_PTR_FORMAT "(%s)", item, uri);
|
GST_PTR_FORMAT "(%s)", item, uri);
|
||||||
|
@@ -106,9 +106,10 @@ clapper_enhancer_director_extract_in_thread (ClapperEnhancerDirectorData *data)
|
|||||||
|
|
||||||
/* We are done with extractable, but keep harvest and try to cache it */
|
/* We are done with extractable, but keep harvest and try to cache it */
|
||||||
if (success) {
|
if (success) {
|
||||||
if (!g_cancellable_is_cancelled (data->cancellable))
|
if (!g_cancellable_is_cancelled (data->cancellable)) {
|
||||||
|
clapper_harvest_set_enhancer_in_caps (harvest, proxy);
|
||||||
clapper_harvest_export_to_cache (harvest, proxy, config, data->uri);
|
clapper_harvest_export_to_cache (harvest, proxy, config, data->uri);
|
||||||
|
}
|
||||||
gst_clear_structure (&config);
|
gst_clear_structure (&config);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -163,7 +164,8 @@ clapper_enhancer_director_parse_in_thread (ClapperEnhancerDirectorData *data)
|
|||||||
|
|
||||||
mem = gst_buffer_peek_memory (data->buffer, 0);
|
mem = gst_buffer_peek_memory (data->buffer, 0);
|
||||||
if (!mem || !gst_memory_map (mem, &info, GST_MAP_READ)) {
|
if (!mem || !gst_memory_map (mem, &info, GST_MAP_READ)) {
|
||||||
GST_ERROR_OBJECT (self, "Could not read playlist buffer data");
|
g_set_error (data->error, GST_RESOURCE_ERROR,
|
||||||
|
GST_RESOURCE_ERROR_FAILED, "Could not read playlist buffer data");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/* Clapper Playback Library
|
/* Clapper Playback Library
|
||||||
* Copyright (C) 2024 Rafał Dzięgiel <rafostar.github@gmail.com>
|
* Copyright (C) 2025 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
@@ -26,12 +26,12 @@
|
|||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
#define CLAPPER_TYPE_URI_LIST_DEMUX (clapper_uri_list_demux_get_type())
|
#define CLAPPER_TYPE_HARVEST_URI_DEMUX (clapper_harvest_uri_demux_get_type())
|
||||||
#define CLAPPER_URI_LIST_DEMUX_CAST(obj) ((ClapperUriListDemux *)(obj))
|
#define CLAPPER_HARVEST_URI_DEMUX_CAST(obj) ((ClapperHarvestUriDemux *)(obj))
|
||||||
|
|
||||||
G_GNUC_INTERNAL
|
G_GNUC_INTERNAL
|
||||||
G_DECLARE_FINAL_TYPE (ClapperUriListDemux, clapper_uri_list_demux, CLAPPER, URI_LIST_DEMUX, ClapperUriBaseDemux)
|
G_DECLARE_FINAL_TYPE (ClapperHarvestUriDemux, clapper_harvest_uri_demux, CLAPPER, HARVEST_URI_DEMUX, ClapperUriBaseDemux)
|
||||||
|
|
||||||
GST_ELEMENT_REGISTER_DECLARE (clapperurilistdemux)
|
GST_ELEMENT_REGISTER_DECLARE (clapperharvesturidemux)
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
@@ -1,5 +1,5 @@
|
|||||||
/* Clapper Playback Library
|
/* Clapper Playback Library
|
||||||
* Copyright (C) 2024 Rafał Dzięgiel <rafostar.github@gmail.com>
|
* Copyright (C) 2025 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
@@ -16,12 +16,12 @@
|
|||||||
* <https://www.gnu.org/licenses/>.
|
* <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "clapper-uri-list-demux-private.h"
|
#include "clapper-harvest-uri-demux-private.h"
|
||||||
|
|
||||||
#define GST_CAT_DEFAULT clapper_uri_list_demux_debug
|
#define GST_CAT_DEFAULT clapper_harvest_uri_demux_debug
|
||||||
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
||||||
|
|
||||||
struct _ClapperUriListDemux
|
struct _ClapperHarvestUriDemux
|
||||||
{
|
{
|
||||||
ClapperUriBaseDemux parent;
|
ClapperUriBaseDemux parent;
|
||||||
|
|
||||||
@@ -32,12 +32,12 @@ struct _ClapperUriListDemux
|
|||||||
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
|
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS ("text/uri-list, source=(string)clapper-harvest"));
|
GST_STATIC_CAPS ("text/x-uri, source=(string)clapper-harvest"));
|
||||||
|
|
||||||
#define parent_class clapper_uri_list_demux_parent_class
|
#define parent_class clapper_harvest_uri_demux_parent_class
|
||||||
G_DEFINE_TYPE (ClapperUriListDemux, clapper_uri_list_demux, CLAPPER_TYPE_URI_BASE_DEMUX);
|
G_DEFINE_TYPE (ClapperHarvestUriDemux, clapper_harvest_uri_demux, CLAPPER_TYPE_URI_BASE_DEMUX);
|
||||||
GST_ELEMENT_REGISTER_DEFINE (clapperurilistdemux, "clapperurilistdemux",
|
GST_ELEMENT_REGISTER_DEFINE (clapperharvesturidemux, "clapperharvesturidemux",
|
||||||
512, CLAPPER_TYPE_URI_LIST_DEMUX);
|
512, CLAPPER_TYPE_HARVEST_URI_DEMUX);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_set_property (GstObject *obj, const gchar *prop_name, gpointer value)
|
_set_property (GstObject *obj, const gchar *prop_name, gpointer value)
|
||||||
@@ -93,10 +93,10 @@ configure_deep_element (GQuark field_id, const GValue *value, GstElement *child)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clapper_uri_list_demux_deep_element_added (GstBin *bin, GstBin *sub_bin, GstElement *child)
|
clapper_harvest_uri_demux_deep_element_added (GstBin *bin, GstBin *sub_bin, GstElement *child)
|
||||||
{
|
{
|
||||||
if (GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_FLAG_SOURCE)) {
|
if (GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_FLAG_SOURCE)) {
|
||||||
ClapperUriListDemux *self = CLAPPER_URI_LIST_DEMUX_CAST (bin);
|
ClapperHarvestUriDemux *self = CLAPPER_HARVEST_URI_DEMUX_CAST (bin);
|
||||||
|
|
||||||
g_mutex_lock (&self->lock);
|
g_mutex_lock (&self->lock);
|
||||||
|
|
||||||
@@ -110,7 +110,7 @@ clapper_uri_list_demux_deep_element_added (GstBin *bin, GstBin *sub_bin, GstElem
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
clapper_uri_list_demux_process_buffer (ClapperUriBaseDemux *uri_bd,
|
clapper_harvest_uri_demux_process_buffer (ClapperUriBaseDemux *uri_bd,
|
||||||
GstBuffer *buffer, GCancellable *cancellable)
|
GstBuffer *buffer, GCancellable *cancellable)
|
||||||
{
|
{
|
||||||
GstMemory *mem = gst_buffer_peek_memory (buffer, 0);
|
GstMemory *mem = gst_buffer_peek_memory (buffer, 0);
|
||||||
@@ -127,12 +127,12 @@ clapper_uri_list_demux_process_buffer (ClapperUriBaseDemux *uri_bd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clapper_uri_list_demux_handle_custom_event (ClapperUriBaseDemux *uri_bd, GstEvent *event)
|
clapper_harvest_uri_demux_handle_custom_event (ClapperUriBaseDemux *uri_bd, GstEvent *event)
|
||||||
{
|
{
|
||||||
const GstStructure *structure = gst_event_get_structure (event);
|
const GstStructure *structure = gst_event_get_structure (event);
|
||||||
|
|
||||||
if (structure && gst_structure_has_name (structure, "http-headers")) {
|
if (structure && gst_structure_has_name (structure, "http-headers")) {
|
||||||
ClapperUriListDemux *self = CLAPPER_URI_LIST_DEMUX_CAST (uri_bd);
|
ClapperHarvestUriDemux *self = CLAPPER_HARVEST_URI_DEMUX_CAST (uri_bd);
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (self, "Received \"http-headers\" custom event");
|
GST_DEBUG_OBJECT (self, "Received \"http-headers\" custom event");
|
||||||
|
|
||||||
@@ -146,15 +146,15 @@ clapper_uri_list_demux_handle_custom_event (ClapperUriBaseDemux *uri_bd, GstEven
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clapper_uri_list_demux_init (ClapperUriListDemux *self)
|
clapper_harvest_uri_demux_init (ClapperHarvestUriDemux *self)
|
||||||
{
|
{
|
||||||
g_mutex_init (&self->lock);
|
g_mutex_init (&self->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clapper_uri_list_demux_finalize (GObject *object)
|
clapper_harvest_uri_demux_finalize (GObject *object)
|
||||||
{
|
{
|
||||||
ClapperUriListDemux *self = CLAPPER_URI_LIST_DEMUX_CAST (object);
|
ClapperHarvestUriDemux *self = CLAPPER_HARVEST_URI_DEMUX_CAST (object);
|
||||||
|
|
||||||
GST_TRACE_OBJECT (self, "Finalize");
|
GST_TRACE_OBJECT (self, "Finalize");
|
||||||
|
|
||||||
@@ -165,26 +165,26 @@ clapper_uri_list_demux_finalize (GObject *object)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clapper_uri_list_demux_class_init (ClapperUriListDemuxClass *klass)
|
clapper_harvest_uri_demux_class_init (ClapperHarvestUriDemuxClass *klass)
|
||||||
{
|
{
|
||||||
GObjectClass *gobject_class = (GObjectClass *) klass;
|
GObjectClass *gobject_class = (GObjectClass *) klass;
|
||||||
GstElementClass *gstelement_class = (GstElementClass *) klass;
|
GstElementClass *gstelement_class = (GstElementClass *) klass;
|
||||||
GstBinClass *gstbin_class = (GstBinClass *) klass;
|
GstBinClass *gstbin_class = (GstBinClass *) klass;
|
||||||
ClapperUriBaseDemuxClass *clapperuribd_class = (ClapperUriBaseDemuxClass *) klass;
|
ClapperUriBaseDemuxClass *clapperuribd_class = (ClapperUriBaseDemuxClass *) klass;
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "clapperurilistdemux", 0,
|
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "clapperharvesturidemux", 0,
|
||||||
"Clapper URI List Demux");
|
"Clapper Harvest URI Demux");
|
||||||
|
|
||||||
gobject_class->finalize = clapper_uri_list_demux_finalize;
|
gobject_class->finalize = clapper_harvest_uri_demux_finalize;
|
||||||
|
|
||||||
gstbin_class->deep_element_added = clapper_uri_list_demux_deep_element_added;
|
gstbin_class->deep_element_added = clapper_harvest_uri_demux_deep_element_added;
|
||||||
|
|
||||||
clapperuribd_class->process_buffer = clapper_uri_list_demux_process_buffer;
|
clapperuribd_class->process_buffer = clapper_harvest_uri_demux_process_buffer;
|
||||||
clapperuribd_class->handle_custom_event = clapper_uri_list_demux_handle_custom_event;
|
clapperuribd_class->handle_custom_event = clapper_harvest_uri_demux_handle_custom_event;
|
||||||
|
|
||||||
gst_element_class_add_static_pad_template (gstelement_class, &sink_template);
|
gst_element_class_add_static_pad_template (gstelement_class, &sink_template);
|
||||||
|
|
||||||
gst_element_class_set_static_metadata (gstelement_class, "Clapper URI List Demux",
|
gst_element_class_set_static_metadata (gstelement_class, "Clapper Harvest URI Demux",
|
||||||
"Demuxer", "A custom demuxer for URI lists",
|
"Demuxer", "A custom demuxer for harvested URI",
|
||||||
"Rafał Dzięgiel <rafostar.github@gmail.com>");
|
"Rafał Dzięgiel <rafostar.github@gmail.com>");
|
||||||
}
|
}
|
@@ -25,7 +25,9 @@
|
|||||||
#include "../clapper-media-item.h"
|
#include "../clapper-media-item.h"
|
||||||
#include "../clapper-playlistable.h"
|
#include "../clapper-playlistable.h"
|
||||||
|
|
||||||
#define CLAPPER_PLAYLIST_MEDIA_TYPE "text/clapper-playlist"
|
#define CLAPPER_PLAYLIST_MEDIA_TYPE "application/clapper-playlist"
|
||||||
|
#define CLAPPER_CLAPS_MEDIA_TYPE "text/clapper-claps"
|
||||||
|
#define URI_LIST_MEDIA_TYPE "text/uri-list"
|
||||||
#define DATA_CHUNK_SIZE 4096
|
#define DATA_CHUNK_SIZE 4096
|
||||||
|
|
||||||
#define GST_CAT_DEFAULT clapper_playlist_demux_debug
|
#define GST_CAT_DEFAULT clapper_playlist_demux_debug
|
||||||
@@ -53,9 +55,10 @@ static GParamSpec *param_specs[PROP_LAST] = { NULL, };
|
|||||||
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
|
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS (CLAPPER_PLAYLIST_MEDIA_TYPE));
|
GST_STATIC_CAPS (CLAPPER_PLAYLIST_MEDIA_TYPE ";" CLAPPER_CLAPS_MEDIA_TYPE ";" URI_LIST_MEDIA_TYPE));
|
||||||
|
|
||||||
static GstStaticCaps type_find_caps = GST_STATIC_CAPS (CLAPPER_PLAYLIST_MEDIA_TYPE);
|
static GstStaticCaps clapper_playlist_caps = GST_STATIC_CAPS (CLAPPER_PLAYLIST_MEDIA_TYPE);
|
||||||
|
static GstStaticCaps clapper_claps_caps = GST_STATIC_CAPS (CLAPPER_CLAPS_MEDIA_TYPE);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clapper_playlist_type_find (GstTypeFind *tf, ClapperEnhancerProxy *proxy)
|
clapper_playlist_type_find (GstTypeFind *tf, ClapperEnhancerProxy *proxy)
|
||||||
@@ -134,20 +137,60 @@ clapper_playlist_type_find (GstTypeFind *tf, ClapperEnhancerProxy *proxy)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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. */
|
||||||
|
static void
|
||||||
|
clapper_claps_type_find (GstTypeFind *tf, gpointer user_data G_GNUC_UNUSED)
|
||||||
|
{
|
||||||
|
const guint8 *data;
|
||||||
|
|
||||||
|
if ((data = gst_type_find_peek (tf, 0, 3))) {
|
||||||
|
gboolean possible;
|
||||||
|
|
||||||
|
/* Linux file path */
|
||||||
|
possible = (data[0] == '/' && g_ascii_isalnum (data[1]));
|
||||||
|
|
||||||
|
#ifdef G_OS_WIN32
|
||||||
|
/* Windows file path ("C:\..." or "D:/...") */
|
||||||
|
if (!possible)
|
||||||
|
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
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
type_find_register (GstPlugin *plugin)
|
type_find_register (GstPlugin *plugin)
|
||||||
{
|
{
|
||||||
ClapperEnhancerProxyList *global_proxies = clapper_get_global_enhancer_proxies ();
|
ClapperEnhancerProxyList *global_proxies = clapper_get_global_enhancer_proxies ();
|
||||||
GstCaps *reg_caps = NULL;
|
GstCaps *reg_caps;
|
||||||
guint i, n_proxies = clapper_enhancer_proxy_list_get_n_proxies (global_proxies);
|
guint i, n_proxies = clapper_enhancer_proxy_list_get_n_proxies (global_proxies);
|
||||||
gboolean res = FALSE;
|
gboolean res;
|
||||||
|
|
||||||
|
reg_caps = gst_static_caps_get (&clapper_claps_caps);
|
||||||
|
res = gst_type_find_register (plugin, "clapper-claps",
|
||||||
|
GST_RANK_MARGINAL + 1, (GstTypeFindFunction) clapper_claps_type_find,
|
||||||
|
"claps", reg_caps, NULL, NULL);
|
||||||
|
gst_clear_caps (®_caps);
|
||||||
|
|
||||||
for (i = 0; i < n_proxies; ++i) {
|
for (i = 0; i < n_proxies; ++i) {
|
||||||
ClapperEnhancerProxy *proxy = clapper_enhancer_proxy_list_peek_proxy (global_proxies, i);
|
ClapperEnhancerProxy *proxy = clapper_enhancer_proxy_list_peek_proxy (global_proxies, i);
|
||||||
|
|
||||||
if (clapper_enhancer_proxy_target_has_interface (proxy, CLAPPER_TYPE_PLAYLISTABLE)) {
|
if (clapper_enhancer_proxy_target_has_interface (proxy, CLAPPER_TYPE_PLAYLISTABLE)
|
||||||
|
&& (clapper_enhancer_proxy_get_extra_data (proxy, "X-Data-Prefix")
|
||||||
|
|| clapper_enhancer_proxy_get_extra_data (proxy, "X-Data-Contains")
|
||||||
|
|| clapper_enhancer_proxy_get_extra_data (proxy, "X-Data-Regex"))) {
|
||||||
if (!reg_caps)
|
if (!reg_caps)
|
||||||
reg_caps = gst_static_caps_get (&type_find_caps);
|
reg_caps = gst_static_caps_get (&clapper_playlist_caps);
|
||||||
|
|
||||||
res |= gst_type_find_register (plugin, clapper_enhancer_proxy_get_module_name (proxy),
|
res |= gst_type_find_register (plugin, clapper_enhancer_proxy_get_module_name (proxy),
|
||||||
GST_RANK_MARGINAL + 1, (GstTypeFindFunction) clapper_playlist_type_find,
|
GST_RANK_MARGINAL + 1, (GstTypeFindFunction) clapper_playlist_type_find,
|
||||||
@@ -166,6 +209,86 @@ GST_TYPE_FIND_REGISTER_DEFINE_CUSTOM (clapperplaylistdemux, type_find_register);
|
|||||||
GST_ELEMENT_REGISTER_DEFINE (clapperplaylistdemux, "clapperplaylistdemux",
|
GST_ELEMENT_REGISTER_DEFINE (clapperplaylistdemux, "clapperplaylistdemux",
|
||||||
512, CLAPPER_TYPE_PLAYLIST_DEMUX);
|
512, CLAPPER_TYPE_PLAYLIST_DEMUX);
|
||||||
|
|
||||||
|
static GListStore *
|
||||||
|
_parse_uri_list (ClapperPlaylistDemux *self, GUri *uri, GstBuffer *buffer,
|
||||||
|
GCancellable *cancellable, GError **error)
|
||||||
|
{
|
||||||
|
GListStore *playlist;
|
||||||
|
GstMemory *mem;
|
||||||
|
GstMapInfo info;
|
||||||
|
const gchar *ptr, *end;
|
||||||
|
|
||||||
|
mem = gst_buffer_peek_memory (buffer, 0);
|
||||||
|
if (!mem || !gst_memory_map (mem, &info, GST_MAP_READ)) {
|
||||||
|
g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
|
||||||
|
"Could not read URI list buffer data");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
playlist = g_list_store_new (CLAPPER_TYPE_MEDIA_ITEM);
|
||||||
|
ptr = (gchar *) info.data;
|
||||||
|
end = ptr + info.size;
|
||||||
|
|
||||||
|
while (ptr < end) {
|
||||||
|
ClapperMediaItem *item = NULL;
|
||||||
|
const gchar *nl = memchr (ptr, '\n', end - ptr);
|
||||||
|
gsize len = nl ? nl - ptr : end - ptr;
|
||||||
|
gchar *line;
|
||||||
|
|
||||||
|
if (g_cancellable_is_cancelled (cancellable))
|
||||||
|
break;
|
||||||
|
|
||||||
|
line = g_strndup (ptr, len);
|
||||||
|
GST_DEBUG_OBJECT (self, "Parsing line: %s", line);
|
||||||
|
|
||||||
|
if (gst_uri_is_valid (line)) {
|
||||||
|
GST_DEBUG_OBJECT (self, "Found URI: %s", line);
|
||||||
|
item = clapper_media_item_new (line);
|
||||||
|
} else {
|
||||||
|
gchar *base_uri, *res_uri;
|
||||||
|
|
||||||
|
base_uri = g_uri_to_string (uri);
|
||||||
|
res_uri = g_uri_resolve_relative (base_uri, line, G_URI_FLAGS_ENCODED, error);
|
||||||
|
g_free (base_uri);
|
||||||
|
|
||||||
|
if (res_uri) {
|
||||||
|
GST_DEBUG_OBJECT (self, "Resolved URI: %s", res_uri);
|
||||||
|
item = clapper_media_item_new (res_uri);
|
||||||
|
g_free (res_uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (line);
|
||||||
|
|
||||||
|
if (G_UNLIKELY (*error != NULL)) {
|
||||||
|
g_clear_object (&playlist);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (G_LIKELY (item != NULL))
|
||||||
|
g_list_store_append (playlist, G_OBJECT (item));
|
||||||
|
|
||||||
|
/* Advance to the next line */
|
||||||
|
ptr = nl ? (nl + 1) : end;
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_memory_unmap (mem, &info);
|
||||||
|
|
||||||
|
return playlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_caps_have_media_type (GstCaps *caps, const gchar *media_type)
|
||||||
|
{
|
||||||
|
GstStructure *structure;
|
||||||
|
gboolean is_media_type = FALSE;
|
||||||
|
|
||||||
|
if (caps && (structure = gst_caps_get_structure (caps, 0)))
|
||||||
|
is_media_type = gst_structure_has_name (structure, media_type);
|
||||||
|
|
||||||
|
return is_media_type;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clapper_playlist_demux_handle_caps (ClapperUriBaseDemux *uri_bd, GstCaps *caps)
|
clapper_playlist_demux_handle_caps (ClapperUriBaseDemux *uri_bd, GstCaps *caps)
|
||||||
{
|
{
|
||||||
@@ -231,9 +354,6 @@ clapper_playlist_demux_process_buffer (ClapperUriBaseDemux *uri_bd,
|
|||||||
GstBuffer *buffer, GCancellable *cancellable)
|
GstBuffer *buffer, GCancellable *cancellable)
|
||||||
{
|
{
|
||||||
ClapperPlaylistDemux *self = CLAPPER_PLAYLIST_DEMUX_CAST (uri_bd);
|
ClapperPlaylistDemux *self = CLAPPER_PLAYLIST_DEMUX_CAST (uri_bd);
|
||||||
ClapperEnhancerProxyList *proxies;
|
|
||||||
GList *filtered_proxies;
|
|
||||||
GstCaps *caps = NULL;
|
|
||||||
GstQuery *query = gst_query_new_uri ();
|
GstQuery *query = gst_query_new_uri ();
|
||||||
GUri *uri = NULL;
|
GUri *uri = NULL;
|
||||||
GListStore *playlist;
|
GListStore *playlist;
|
||||||
@@ -257,33 +377,42 @@ clapper_playlist_demux_process_buffer (ClapperUriBaseDemux *uri_bd,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!self->director)
|
if (_caps_have_media_type (self->caps, CLAPPER_PLAYLIST_MEDIA_TYPE)) {
|
||||||
self->director = clapper_enhancer_director_new ();
|
ClapperEnhancerProxyList *proxies;
|
||||||
|
GList *filtered_proxies;
|
||||||
|
|
||||||
GST_OBJECT_LOCK (self);
|
GST_OBJECT_LOCK (self);
|
||||||
|
|
||||||
if (G_LIKELY (self->enhancer_proxies != NULL)) {
|
if (G_LIKELY (self->enhancer_proxies != NULL)) {
|
||||||
GST_INFO_OBJECT (self, "Using enhancer proxies: %" GST_PTR_FORMAT, self->enhancer_proxies);
|
GST_INFO_OBJECT (self, "Using enhancer proxies: %" GST_PTR_FORMAT, self->enhancer_proxies);
|
||||||
proxies = gst_object_ref (self->enhancer_proxies);
|
proxies = gst_object_ref (self->enhancer_proxies);
|
||||||
} else {
|
} else {
|
||||||
/* Compat for old ClapperDiscoverer feature that does not set this property */
|
/* Compat for old ClapperDiscoverer feature that does not set this property */
|
||||||
GST_WARNING_OBJECT (self, "Falling back to using global enhancer proxy list!");
|
GST_WARNING_OBJECT (self, "Falling back to using global enhancer proxy list!");
|
||||||
proxies = gst_object_ref (clapper_get_global_enhancer_proxies ());
|
proxies = gst_object_ref (clapper_get_global_enhancer_proxies ());
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_OBJECT_UNLOCK (self);
|
||||||
|
|
||||||
|
if (!self->director)
|
||||||
|
self->director = clapper_enhancer_director_new ();
|
||||||
|
|
||||||
|
filtered_proxies = _filter_playlistables (self, self->caps, proxies);
|
||||||
|
gst_object_unref (proxies);
|
||||||
|
|
||||||
|
playlist = clapper_enhancer_director_parse (self->director,
|
||||||
|
filtered_proxies, uri, buffer, cancellable, &error);
|
||||||
|
|
||||||
|
g_clear_list (&filtered_proxies, gst_object_unref);
|
||||||
|
} else if (_caps_have_media_type (self->caps, URI_LIST_MEDIA_TYPE)
|
||||||
|
|| _caps_have_media_type (self->caps, CLAPPER_CLAPS_MEDIA_TYPE)) {
|
||||||
|
playlist = _parse_uri_list (self, uri, buffer, cancellable, &error);
|
||||||
|
} else { // Should never happen
|
||||||
|
playlist = NULL;
|
||||||
|
error = g_error_new (GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
|
||||||
|
"Unsupported media type in caps");
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_caps_replace (&caps, self->caps);
|
|
||||||
|
|
||||||
GST_OBJECT_UNLOCK (self);
|
|
||||||
|
|
||||||
filtered_proxies = _filter_playlistables (self, caps, proxies);
|
|
||||||
gst_clear_caps (&caps);
|
|
||||||
gst_object_unref (proxies);
|
|
||||||
|
|
||||||
playlist = clapper_enhancer_director_parse (self->director,
|
|
||||||
filtered_proxies, uri, buffer, cancellable, &error);
|
|
||||||
|
|
||||||
g_clear_list (&filtered_proxies, gst_object_unref);
|
|
||||||
|
|
||||||
if (!playlist) {
|
if (!playlist) {
|
||||||
GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ,
|
GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ,
|
||||||
("%s", error->message), (NULL));
|
("%s", error->message), (NULL));
|
||||||
|
@@ -28,8 +28,8 @@
|
|||||||
|
|
||||||
#include "clapper-plugin-private.h"
|
#include "clapper-plugin-private.h"
|
||||||
#include "clapper-extractable-src-private.h"
|
#include "clapper-extractable-src-private.h"
|
||||||
|
#include "clapper-harvest-uri-demux-private.h"
|
||||||
#include "clapper-playlist-demux-private.h"
|
#include "clapper-playlist-demux-private.h"
|
||||||
#include "clapper-uri-list-demux-private.h"
|
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
clapper_gst_plugin_init (GstPlugin *plugin)
|
clapper_gst_plugin_init (GstPlugin *plugin)
|
||||||
@@ -46,7 +46,7 @@ clapper_gst_plugin_init (GstPlugin *plugin)
|
|||||||
/* Avoid registering an URI handler without schemes */
|
/* Avoid registering an URI handler without schemes */
|
||||||
if (clapper_enhancer_proxy_list_has_proxy_with_interface (global_proxies, CLAPPER_TYPE_EXTRACTABLE)) {
|
if (clapper_enhancer_proxy_list_has_proxy_with_interface (global_proxies, CLAPPER_TYPE_EXTRACTABLE)) {
|
||||||
res &= (GST_ELEMENT_REGISTER (clapperextractablesrc, plugin)
|
res &= (GST_ELEMENT_REGISTER (clapperextractablesrc, plugin)
|
||||||
&& GST_ELEMENT_REGISTER (clapperurilistdemux, plugin));
|
&& GST_ELEMENT_REGISTER (clapperharvesturidemux, plugin));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Type find will only register if there are playlistable enhancers */
|
/* Type find will only register if there are playlistable enhancers */
|
||||||
|
@@ -163,7 +163,7 @@ clapper_sources = [
|
|||||||
'gst/clapper-extractable-src.c',
|
'gst/clapper-extractable-src.c',
|
||||||
'gst/clapper-enhancer-director.c',
|
'gst/clapper-enhancer-director.c',
|
||||||
'gst/clapper-uri-base-demux.c',
|
'gst/clapper-uri-base-demux.c',
|
||||||
'gst/clapper-uri-list-demux.c',
|
'gst/clapper-harvest-uri-demux.c',
|
||||||
'gst/clapper-playlist-demux.c',
|
'gst/clapper-playlist-demux.c',
|
||||||
'../shared/clapper-shared-utils.c',
|
'../shared/clapper-shared-utils.c',
|
||||||
]
|
]
|
||||||
|
Reference in New Issue
Block a user