11 Commits

Author SHA1 Message Date
Rafał Dzięgiel
9fd87dbbb9 clapper: Rename enhancersrc -> extractablesrc
Since this element only uses enhancers of "extractable" type
2025-05-21 17:42:15 +02:00
Rafał Dzięgiel
ca15f4760a clapper: Cleanup cached harvests periodically 2025-05-21 17:42:08 +02:00
Rafał Dzięgiel
6ddb53252a clapper: Implement harvest caching
Using recently added local cache functionality, store harvests
that have expiration date. With this, next time the same URI is
selected for playback we can read it from cache, skipping loading
of any enhancer plugins and doing network requests.

This also works nicely with Clapper discoverer feature.
Making queued items be fetched and cached ahead of playback.
2025-05-20 18:56:28 +02:00
Rafał Dzięgiel
b30d53d8ce clapper: Add ability to set harvest expiration date 2025-05-20 17:18:20 +02:00
Rafał Dzięgiel
1527873bcc clapper: Fix missing unref of mapped file
In case where enhancer plugin version did not match
an unref was missing of read file.
2025-05-19 20:42:32 +02:00
Rafał Dzięgiel
e23f2acb3e meson: Remove unused "config.h" variable 2025-05-18 13:24:51 +02:00
Rafał Dzięgiel
1dfcb218ac meson: Bump min required libadwaita version
Since URI dialog was ported to use AdwAlertDialog,
a minimal Adw version has to be changed to 1.5.
2025-05-17 18:55:31 +02:00
Rafał Dzięgiel
b05f0f2b30 meson: Remove GIR init section
Clapper GStreamer plugin is not part of GObject Introspection,
so no need to init GStreamer when compiling bindings.
2025-05-17 18:20:33 +02:00
Rafał Dzięgiel
dad0d46196 Merge pull request #546 from Rafostar/configurable-enhancers
Make Clapper Enhancers configurable
2025-05-16 18:30:05 +02:00
Rafał Dzięgiel
147d94088c Merge pull request #548 from ximion/master
Use modern appstream, instead of appstream-util for validation
2025-05-03 15:42:28 +02:00
Matthias Klumpp
c7790d9f7b Use modern appstream, instead of appstream-util for validation 2025-05-03 01:56:53 +02:00
19 changed files with 763 additions and 162 deletions

View File

@@ -11,7 +11,7 @@ project('clapper', 'c',
glib_req = '>= 2.76.0'
gst_req = '>= 1.24.0'
gtk4_req = '>= 4.10.0'
adw_req = '>= 1.4.0'
adw_req = '>= 1.5.0'
clapper_version = meson.project_version().split('-')[0]
version_array = clapper_version.split('.')

View File

@@ -1,10 +1,11 @@
appstream_util = find_program('appstream-util', required: false)
if appstream_util.found()
appstream_cli = find_program('appstreamcli', required: false)
if appstream_cli.found()
test('Validate appstream file',
appstream_util,
appstream_cli,
args: [
'validate-relax',
'--nonet',
'validate',
'--no-net',
'--explain',
join_paths(meson.current_source_dir(), 'metainfo', 'com.github.rafostar.Clapper.metainfo.xml'),
]
)

View File

@@ -176,7 +176,6 @@ if build_gir
clappergtk_enums,
],
extra_args: [
gir_init_section,
'--quiet',
'--warn-all',
'-DCLAPPER_GTK_COMPILATION',

View File

@@ -27,6 +27,9 @@ G_BEGIN_DECLS
G_GNUC_INTERNAL
void clapper_cache_initialize (void);
G_GNUC_INTERNAL
gboolean clapper_cache_is_disabled (void);
G_GNUC_INTERNAL
GMappedFile * clapper_cache_open (const gchar *filename, const gchar **data, GError **error);
@@ -39,12 +42,18 @@ gint clapper_cache_read_int (const gchar **data);
G_GNUC_INTERNAL
guint clapper_cache_read_uint (const gchar **data);
G_GNUC_INTERNAL
gint64 clapper_cache_read_int64 (const gchar **data);
G_GNUC_INTERNAL
gdouble clapper_cache_read_double (const gchar **data);
G_GNUC_INTERNAL
const gchar * clapper_cache_read_string (const gchar **data);
G_GNUC_INTERNAL
const guint8 * clapper_cache_read_data (const gchar **data, gsize *size);
G_GNUC_INTERNAL
GType clapper_cache_read_enum (const gchar **data);
@@ -69,12 +78,18 @@ void clapper_cache_store_int (GByteArray *bytes, gint val);
G_GNUC_INTERNAL
void clapper_cache_store_uint (GByteArray *bytes, guint val);
G_GNUC_INTERNAL
void clapper_cache_store_int64 (GByteArray *bytes, gint64 val);
G_GNUC_INTERNAL
void clapper_cache_store_double (GByteArray *bytes, gdouble val);
G_GNUC_INTERNAL
void clapper_cache_store_string (GByteArray *bytes, const gchar *val);
G_GNUC_INTERNAL
void clapper_cache_store_data (GByteArray *bytes, const guint8 *val, gsize val_size);
G_GNUC_INTERNAL
void clapper_cache_store_enum (GByteArray *bytes, GType enum_type);

View File

@@ -45,6 +45,12 @@ clapper_cache_initialize (void)
}
}
gboolean
clapper_cache_is_disabled (void)
{
return cache_disabled;
}
GMappedFile *
clapper_cache_open (const gchar *filename, const gchar **data, GError **error)
{
@@ -111,6 +117,15 @@ clapper_cache_read_uint (const gchar **data)
return val;
}
inline gint64
clapper_cache_read_int64 (const gchar **data)
{
gint64 val = *(const gint64 *) *data;
*data += sizeof (gint64);
return val;
}
inline gdouble
clapper_cache_read_double (const gchar **data)
{
@@ -134,6 +149,22 @@ clapper_cache_read_string (const gchar **data)
return str;
}
inline const guint8 *
clapper_cache_read_data (const gchar **data, gsize *size)
{
const guint8 *val = NULL;
*size = *(const gsize *) *data;
*data += sizeof (gsize);
if (G_LIKELY (*size > 0)) {
val = (const guint8 *) *data;
*data += *size;
}
return val;
}
inline GType
clapper_cache_read_enum (const gchar **data)
{
@@ -332,6 +363,12 @@ clapper_cache_store_uint (GByteArray *bytes, guint val)
g_byte_array_append (bytes, (const guint8 *) &val, sizeof (guint));
}
inline void
clapper_cache_store_int64 (GByteArray *bytes, gint64 val)
{
g_byte_array_append (bytes, (const guint8 *) &val, sizeof (gint64));
}
inline void
clapper_cache_store_double (GByteArray *bytes, gdouble val)
{
@@ -349,6 +386,14 @@ clapper_cache_store_string (GByteArray *bytes, const gchar *val)
g_byte_array_append (bytes, (const guint8 *) val, strlen (val) + 1);
}
inline void
clapper_cache_store_data (GByteArray *bytes, const guint8 *val, gsize val_size)
{
g_byte_array_append (bytes, (const guint8 *) &val_size, sizeof (gsize));
if (G_LIKELY (val_size > 0))
g_byte_array_append (bytes, val, val_size);
}
inline void
clapper_cache_store_enum (GByteArray *bytes, GType enum_type)
{

View File

@@ -21,6 +21,7 @@
#include <glib.h>
#include <glib-object.h>
#include <gst/gst.h>
#include "clapper-enhancer-proxy.h"
@@ -45,6 +46,9 @@ G_GNUC_INTERNAL
GObject * clapper_enhancer_proxy_get_peas_info (ClapperEnhancerProxy *proxy);
G_GNUC_INTERNAL
void clapper_enhancer_proxy_apply_current_config_to_enhancer (ClapperEnhancerProxy *proxy, GObject *enhancer);
GstStructure * clapper_enhancer_proxy_make_current_config (ClapperEnhancerProxy *proxy);
G_GNUC_INTERNAL
void clapper_enhancer_proxy_apply_config_to_enhancer (ClapperEnhancerProxy *proxy, const GstStructure *config, GObject *enhancer);
G_END_DECLS

View File

@@ -345,8 +345,10 @@ clapper_enhancer_proxy_fill_from_cache (ClapperEnhancerProxy *self)
}
/* Plugin version check */
if (g_strcmp0 (clapper_cache_read_string (&data), self->version) != 0)
if (g_strcmp0 (clapper_cache_read_string (&data), self->version) != 0) {
g_mapped_file_unref (mapped_file);
return FALSE; // not an error
}
/* Restore Interfaces */
if ((self->n_ifaces = clapper_cache_read_uint (&data)) > 0) {
@@ -505,15 +507,18 @@ _apply_config_cb (GQuark field_id, const GValue *value, GObject *enhancer)
return TRUE;
}
void
clapper_enhancer_proxy_apply_current_config_to_enhancer (ClapperEnhancerProxy *self, GObject *enhancer)
/*
* clapper_enhancer_proxy_make_current_config:
*
* Returns: (transfer full) (nullable): Current merged global and local config as #GstStructure.
*/
GstStructure *
clapper_enhancer_proxy_make_current_config (ClapperEnhancerProxy *self)
{
GSettings *settings = clapper_enhancer_proxy_get_settings (self);
GstStructure *merged_config = NULL;
guint i;
GST_DEBUG_OBJECT (self, "Applying config to enhancer");
/* Lock here to ensure consistent local config */
GST_OBJECT_LOCK (self);
@@ -585,13 +590,14 @@ clapper_enhancer_proxy_apply_current_config_to_enhancer (ClapperEnhancerProxy *s
g_clear_object (&settings);
/* Nothing if no configurable properties
* or all have default values */
if (merged_config) {
gst_structure_foreach (merged_config, (GstStructureForeachFunc) _apply_config_cb, enhancer);
gst_structure_free (merged_config);
}
return merged_config;
}
void
clapper_enhancer_proxy_apply_config_to_enhancer (ClapperEnhancerProxy *self, const GstStructure *config, GObject *enhancer)
{
GST_DEBUG_OBJECT (self, "Applying config to enhancer");
gst_structure_foreach (config, (GstStructureForeachFunc) _apply_config_cb, enhancer);
GST_DEBUG_OBJECT (self, "Enhancer config applied");
}

View File

@@ -23,6 +23,7 @@
#include <gst/tag/tag.h>
#include "clapper-harvest.h"
#include "clapper-enhancer-proxy.h"
G_BEGIN_DECLS
@@ -32,4 +33,10 @@ ClapperHarvest * clapper_harvest_new (void);
G_GNUC_INTERNAL
gboolean clapper_harvest_unpack (ClapperHarvest *harvest, GstBuffer **buffer, gsize *buf_size, GstCaps **caps, GstTagList **tags, GstToc **toc, GstStructure **headers);
G_GNUC_INTERNAL
gboolean clapper_harvest_fill_from_cache (ClapperHarvest *harvest, ClapperEnhancerProxy *proxy, const GstStructure *config, GUri *uri);
G_GNUC_INTERNAL
void clapper_harvest_export_to_cache (ClapperHarvest *harvest, ClapperEnhancerProxy *proxy, const GstStructure *config, GUri *uri);
G_END_DECLS

View File

@@ -31,7 +31,11 @@
* https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/2867
*/
#include "config.h"
#include "clapper-harvest-private.h"
#include "clapper-cache-private.h"
#include "clapper-utils.h"
#define GST_CAT_DEFAULT clapper_harvest_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
@@ -50,6 +54,8 @@ struct _ClapperHarvest
guint16 n_chapters;
guint16 n_tracks;
gint64 exp_epoch;
};
#define parent_class clapper_harvest_parent_class
@@ -119,6 +125,302 @@ clapper_harvest_unpack (ClapperHarvest *self,
return TRUE;
}
/* Custom implementation due to the lack of TOC serialization in GStreamer */
static void
_harvest_fill_toc_from_cache (ClapperHarvest *self, const gchar **data)
{
guint i, n_entries;
n_entries = clapper_cache_read_uint (data);
for (i = 0; i < n_entries; ++i) {
guint j, n_subentries;
n_subentries = clapper_cache_read_uint (data);
for (j = 0; j < n_subentries; ++j) {
GstTocEntryType type;
const gchar *title;
gdouble start, end;
type = (GstTocEntryType) clapper_cache_read_int (data);
title = clapper_cache_read_string (data);
start = clapper_cache_read_double (data);
end = clapper_cache_read_double (data);
clapper_harvest_toc_add (self, type, title, start, end);
}
}
}
static void
_harvest_store_toc_to_cache (ClapperHarvest *self, GByteArray *bytes)
{
GList *list = NULL, *el;
guint n_entries = 0;
if (self->toc) {
list = gst_toc_get_entries (self->toc);
n_entries = g_list_length (list);
}
clapper_cache_store_uint (bytes, n_entries);
for (el = list; el; el = g_list_next (el)) {
const GstTocEntry *entry = (const GstTocEntry *) el->data;
GList *subentries, *sub_el;
guint n_subentries;
subentries = gst_toc_entry_get_sub_entries (entry);
n_subentries = g_list_length (subentries);
clapper_cache_store_uint (bytes, n_subentries);
for (sub_el = subentries; sub_el; sub_el = g_list_next (sub_el)) {
const GstTocEntry *subentry = (const GstTocEntry *) sub_el->data;
GstTagList *tags;
gint64 start = 0, end = 0;
gdouble start_dbl, end_dbl;
const gchar *title = NULL;
clapper_cache_store_int (bytes, (gint) gst_toc_entry_get_entry_type (subentry));
if ((tags = gst_toc_entry_get_tags (subentry)))
gst_tag_list_peek_string_index (tags, GST_TAG_TITLE, 0, &title);
clapper_cache_store_string (bytes, title);
gst_toc_entry_get_start_stop_times (subentry, &start, &end);
start_dbl = ((gdouble) start) / GST_SECOND;
end_dbl = (end >= 0) ? ((gdouble) end) / GST_SECOND : -1;
clapper_cache_store_double (bytes, start_dbl);
clapper_cache_store_double (bytes, end_dbl);
}
}
}
static inline gchar *
_build_cache_filename (ClapperEnhancerProxy *proxy, GUri *uri)
{
gchar *uri_str = g_uri_to_string (uri);
gchar name[15];
g_snprintf (name, sizeof (name), "%u.bin", g_str_hash (uri_str));
g_free (uri_str);
return g_build_filename (g_get_user_cache_dir (), CLAPPER_API_NAME,
"enhancers", clapper_enhancer_proxy_get_module_name (proxy),
"harvests", name, NULL);
}
/* NOTE: On failure, this function must not modify harvest! */
gboolean
clapper_harvest_fill_from_cache (ClapperHarvest *self, ClapperEnhancerProxy *proxy,
const GstStructure *config, GUri *uri)
{
GMappedFile *mapped_file;
GstStructure *config_cached = NULL;
GError *error = NULL;
gchar *filename;
const gchar *data, *read_str;
const guint8 *buf_data;
guint8 *buf_copy;
gsize buf_size;
gint64 epoch_cached, epoch_now = 0;
gdouble exp_seconds;
gboolean changed, read_ok = FALSE;
filename = _build_cache_filename (proxy, uri);
GST_DEBUG_OBJECT (self, "Importing harvest from cache file: \"%s\"", filename);
mapped_file = clapper_cache_open (filename, &data, &error);
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");
else
GST_ERROR_OBJECT (self, "Could not use cached harvest, reason: %s", error->message);
g_error_free (error);
}
return FALSE;
}
/* Plugin version check */
if (g_strcmp0 (clapper_cache_read_string (&data),
clapper_enhancer_proxy_get_version (proxy)) != 0)
goto finish; // no error printing here
if (G_LIKELY ((epoch_cached = clapper_cache_read_int64 (&data)) > 0)) {
GDateTime *date = g_date_time_new_now_utc ();
epoch_now = g_date_time_to_unix (date);
g_date_time_unref (date);
}
/* Check if expired */
if ((exp_seconds = (gdouble) (epoch_cached - epoch_now)) <= 0) {
GST_DEBUG_OBJECT (self, "Cached harvest expired"); // expiration is not an error
goto finish;
}
GST_DEBUG_OBJECT (self, "Cached harvest expiration in %" CLAPPER_TIME_FORMAT,
CLAPPER_TIME_ARGS (exp_seconds));
/* Read last used config to generate cache data */
if ((read_str = clapper_cache_read_string (&data)))
config_cached = gst_structure_from_string (read_str, NULL);
/* Compare used config when cache was generated to the current one */
changed = (config_cached && config)
? !gst_structure_is_equal (config_cached, config)
: (config_cached != config);
gst_clear_structure (&config_cached);
if (changed) {
GST_DEBUG_OBJECT (self, "Enhancer config differs from the last time");
goto finish;
}
/* Read media type */
read_str = clapper_cache_read_string (&data);
if (G_UNLIKELY (read_str == NULL)) {
GST_ERROR_OBJECT (self, "Could not read media type from cache file");
goto finish;
}
/* Read buffer data */
buf_data = clapper_cache_read_data (&data, &buf_size);
if (G_UNLIKELY (buf_data == NULL)) {
GST_ERROR_OBJECT (self, "Could not read buffer data from cache");
goto finish;
}
/* Fill harvest */
buf_copy = g_memdup2 (buf_data, buf_size);
if (!clapper_harvest_fill (self, read_str, buf_copy, buf_size))
goto finish;
/* Read tags */
read_str = clapper_cache_read_string (&data);
if (read_str && (self->tags = gst_tag_list_new_from_string (read_str))) {
GST_LOG_OBJECT (self, "Read %s", read_str);
gst_tag_list_set_scope (self->tags, GST_TAG_SCOPE_GLOBAL);
}
/* Read TOC */
_harvest_fill_toc_from_cache (self, &data);
/* Read headers */
read_str = clapper_cache_read_string (&data);
if (read_str && (self->headers = gst_structure_from_string (read_str, NULL)))
GST_LOG_OBJECT (self, "Read %s", read_str);
read_ok = TRUE;
finish:
g_mapped_file_unref (mapped_file);
if (!read_ok)
return FALSE;
GST_DEBUG_OBJECT (self, "Filled harvest from cache");
return TRUE;
}
void
clapper_harvest_export_to_cache (ClapperHarvest *self, ClapperEnhancerProxy *proxy,
const GstStructure *config, GUri *uri)
{
GByteArray *bytes;
const GstStructure *caps_structure;
gchar *filename, *temp_str = NULL;
gboolean data_ok = TRUE;
/* No caching if no expiration date set */
if (self->exp_epoch <= 0)
return;
/* Might happen if extractor extract function implementation
* returns %TRUE without filling harvest properly */
if (G_UNLIKELY (self->caps == NULL || self->buffer == NULL))
return; // no data to cache
bytes = clapper_cache_create ();
/* If cache disabled */
if (G_UNLIKELY (bytes == NULL))
return;
filename = _build_cache_filename (proxy, uri);
GST_DEBUG_OBJECT (self, "Exporting harvest to cache file: \"%s\"", filename);
/* Store enhancer version that generated harvest */
clapper_cache_store_string (bytes, clapper_enhancer_proxy_get_version (proxy));
/* Store expiration date */
clapper_cache_store_int64 (bytes, self->exp_epoch);
/* Store config used to generate harvest */
if (config)
temp_str = gst_structure_to_string (config);
clapper_cache_store_string (bytes, temp_str); // NULL when no config
g_clear_pointer (&temp_str, g_free);
/* Store media type */
caps_structure = gst_caps_get_structure (self->caps, 0);
if (G_LIKELY (caps_structure != NULL)) {
clapper_cache_store_string (bytes, gst_structure_get_name (caps_structure));
} else {
GST_ERROR_OBJECT (self, "Cannot cache empty caps");
data_ok = FALSE;
}
if (G_LIKELY (data_ok)) {
GstMemory *mem;
GstMapInfo map_info;
/* Store buffer data */
mem = gst_buffer_peek_memory (self->buffer, 0);
if (G_LIKELY (gst_memory_map (mem, &map_info, GST_MAP_READ))) {
clapper_cache_store_data (bytes, map_info.data, map_info.size);
gst_memory_unmap (mem, &map_info);
} else {
GST_ERROR_OBJECT (self, "Could not map harvest buffer for reading");
data_ok = FALSE;
}
}
if (G_LIKELY (data_ok)) {
GError *error = NULL;
/* Store tags */
if (self->tags)
temp_str = gst_tag_list_to_string (self->tags);
clapper_cache_store_string (bytes, temp_str);
g_clear_pointer (&temp_str, g_free);
/* Store TOC */
_harvest_store_toc_to_cache (self, bytes);
/* Store headers */
if (self->headers)
temp_str = gst_structure_to_string (self->headers);
clapper_cache_store_string (bytes, temp_str);
g_clear_pointer (&temp_str, g_free);
if (clapper_cache_write (filename, bytes, &error)) {
GST_DEBUG_OBJECT (self, "Successfully exported harvest to cache file");
} else if (error) {
GST_ERROR_OBJECT (self, "Could not cache harvest, reason: %s", error->message);
g_error_free (error);
}
}
g_free (filename);
g_byte_array_free (bytes, TRUE);
}
/**
* clapper_harvest_fill:
* @harvest: a #ClapperHarvest
@@ -155,7 +457,7 @@ clapper_harvest_fill (ClapperHarvest *self, const gchar *media_type, gpointer da
return FALSE;
}
if (gst_debug_category_get_threshold (GST_CAT_DEFAULT) >= GST_LEVEL_DEBUG) {
if (gst_debug_category_get_threshold (GST_CAT_DEFAULT) >= GST_LEVEL_LOG) {
gboolean is_printable = (strcmp (media_type, "application/dash+xml") == 0)
|| (strcmp (media_type, "application/x-hls") == 0)
|| (strcmp (media_type, "text/uri-list") == 0);
@@ -166,7 +468,7 @@ clapper_harvest_fill (ClapperHarvest *self, const gchar *media_type, gpointer da
data_str = g_new0 (gchar, size + 1);
memcpy (data_str, data, size);
GST_DEBUG_OBJECT (self, "Filled with data:\n%s", data_str);
GST_LOG_OBJECT (self, "Filled with data:\n%s", data_str);
g_free (data_str);
}
@@ -328,7 +630,7 @@ clapper_harvest_toc_add (ClapperHarvest *self, GstTocEntryType type,
g_snprintf (edition, sizeof (edition), "0%i", type);
g_snprintf (id, sizeof (id), "%s.%" G_GUINT16_FORMAT, id_prefix, nth_entry);
GST_DEBUG_OBJECT (self, "Inserting TOC %s: \"%s\""
GST_LOG_OBJECT (self, "Inserting TOC %s: \"%s\""
" (%" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT ")",
id, title, start_time, end_time);
@@ -380,7 +682,7 @@ clapper_harvest_headers_set (ClapperHarvest *self, const gchar *key, ...)
while (key != NULL) {
const gchar *val = va_arg (args, const gchar *);
GST_DEBUG_OBJECT (self, "Set header, \"%s\": \"%s\"", key, val);
GST_LOG_OBJECT (self, "Set header, \"%s\": \"%s\"", key, val);
gst_structure_set (self->headers, key, G_TYPE_STRING, val, NULL);
key = va_arg (args, const gchar *);
}
@@ -409,10 +711,70 @@ clapper_harvest_headers_set_value (ClapperHarvest *self, const gchar *key, const
_ensure_headers (self);
GST_DEBUG_OBJECT (self, "Set header, \"%s\": \"%s\"", key, g_value_get_string (value));
GST_LOG_OBJECT (self, "Set header, \"%s\": \"%s\"", key, g_value_get_string (value));
gst_structure_set_value (self->headers, key, value);
}
/**
* clapper_harvest_set_expiration_date_utc:
* @harvest: a #ClapperHarvest
* @date_utc: a #GDateTime in UTC time
*
* Set date in UTC time until harvested content is expected
* to stay alive.
*
* This is used for harvest caching, so next time user requests to
* play the same URI, recently harvested data can be reused without
* the need to run [vfunc@Clapper.Extractable.extract] again.
*
* Since: 0.10
*/
void
clapper_harvest_set_expiration_date_utc (ClapperHarvest *self, GDateTime *date_utc)
{
g_return_if_fail (CLAPPER_IS_HARVEST (self));
g_return_if_fail (date_utc != NULL);
self->exp_epoch = g_date_time_to_unix (date_utc);
GST_LOG_OBJECT (self, "Expiration epoch: %" G_GINT64_FORMAT, self->exp_epoch);
}
/**
* clapper_harvest_set_expiration_seconds:
* @harvest: a #ClapperHarvest
* @seconds: time in seconds until expiration
*
* Set amount of seconds for how long harvested content is
* expected to stay alive.
*
* Alternative function to [method@Clapper.Harvest.set_expiration_date_utc],
* but takes time as number in seconds from now.
*
* It is safe to pass zero or negative number to this function in
* case when calculating time manually and it already expired.
*
* Since: 0.10
*/
void
clapper_harvest_set_expiration_seconds (ClapperHarvest *self, gdouble seconds)
{
GDateTime *date, *date_epoch;
g_return_if_fail (CLAPPER_IS_HARVEST (self));
GST_LOG_OBJECT (self, "Set expiration in %" CLAPPER_TIME_FORMAT,
CLAPPER_TIME_ARGS (seconds));
date = g_date_time_new_now_utc ();
date_epoch = g_date_time_add_seconds (date, seconds);
g_date_time_unref (date);
self->exp_epoch = g_date_time_to_unix (date_epoch);
g_date_time_unref (date_epoch);
GST_LOG_OBJECT (self, "Expiration epoch: %" G_GINT64_FORMAT, self->exp_epoch);
}
static void
clapper_harvest_init (ClapperHarvest *self)
{

View File

@@ -61,4 +61,10 @@ void clapper_harvest_headers_set (ClapperHarvest *harvest, const gchar *key, ...
CLAPPER_API
void clapper_harvest_headers_set_value (ClapperHarvest *harvest, const gchar *key, const GValue *value);
CLAPPER_API
void clapper_harvest_set_expiration_date_utc (ClapperHarvest *harvest, GDateTime *date_utc);
CLAPPER_API
void clapper_harvest_set_expiration_seconds (ClapperHarvest *harvest, gdouble seconds);
G_END_DECLS

View File

@@ -29,12 +29,7 @@
#include "clapper-timeline-private.h"
#include "clapper-stream-private.h"
#include "clapper-stream-list-private.h"
#include "clapper-functionalities-availability.h"
#if CLAPPER_WITH_ENHANCERS_LOADER
#include "gst/clapper-enhancer-src-private.h"
#endif
#include "gst/clapper-extractable-src-private.h"
#define GST_CAT_DEFAULT clapper_playbin_bus_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
@@ -875,7 +870,6 @@ _handle_tag_msg (GstMessage *msg, ClapperPlayer *player)
{
GstObject *src = GST_MESSAGE_SRC (msg);
GstTagList *tags = NULL;
gboolean from_enhancer_src;
/* Tag messages should only be posted by sink elements */
if (G_UNLIKELY (!src))
@@ -886,14 +880,8 @@ _handle_tag_msg (GstMessage *msg, ClapperPlayer *player)
GST_LOG_OBJECT (player, "Got tags from element: %s: %" GST_PTR_FORMAT,
GST_OBJECT_NAME (src), tags);
#if CLAPPER_WITH_ENHANCERS_LOADER
from_enhancer_src = CLAPPER_IS_ENHANCER_SRC (src);
#else
from_enhancer_src = FALSE;
#endif
/* ClapperEnhancerSrc determines tags before stream start */
if (from_enhancer_src) {
/* ClapperExtractableSrc determines tags before stream start */
if (CLAPPER_IS_EXTRACTABLE_SRC (src)) {
if (player->pending_tags) {
gst_tag_list_unref (player->pending_tags);
}
@@ -910,7 +898,7 @@ _handle_toc_msg (GstMessage *msg, ClapperPlayer *player)
{
GstObject *src = GST_MESSAGE_SRC (msg);
GstToc *toc = NULL;
gboolean from_enhancer_src, updated = FALSE;
gboolean updated = FALSE;
/* TOC messages should only be posted by sink elements */
if (G_UNLIKELY (!src))
@@ -923,14 +911,8 @@ _handle_toc_msg (GstMessage *msg, ClapperPlayer *player)
" from element: %s, updated: %s",
toc, GST_OBJECT_NAME (src), (updated) ? "yes" : "no");
#if CLAPPER_WITH_ENHANCERS_LOADER
from_enhancer_src = CLAPPER_IS_ENHANCER_SRC (src);
#else
from_enhancer_src = FALSE;
#endif
/* ClapperEnhancerSrc determines TOC before stream start */
if (from_enhancer_src) {
/* ClapperExtractableSrc determines TOC before stream start */
if (CLAPPER_IS_EXTRACTABLE_SRC (src)) {
if (player->pending_toc) {
gst_toc_unref (player->pending_toc);
}

View File

@@ -816,7 +816,7 @@ _element_setup_cb (GstElement *playbin, GstElement *element, ClapperPlayer *self
factory_name = g_intern_static_string (GST_OBJECT_NAME (factory));
GST_INFO_OBJECT (self, "Element setup: %s", factory_name);
if (factory_name == g_intern_static_string ("clapperenhancersrc")) {
if (factory_name == g_intern_static_string ("clapperextractablesrc")) {
g_object_set (element,
"enhancer-proxies", self->enhancer_proxies,
NULL);

View File

@@ -17,12 +17,17 @@
* Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include <gst/gst.h>
#include "clapper-enhancer-director-private.h"
#include "../clapper-basic-functions.h"
#include "../clapper-cache-private.h"
#include "../clapper-enhancer-proxy-private.h"
#include "../clapper-extractable-private.h"
#include "../clapper-harvest-private.h"
#include "../clapper-utils.h"
#include "../../shared/clapper-shared-utils-private.h"
#include "../clapper-functionalities-availability.h"
@@ -31,6 +36,8 @@
#include "../clapper-enhancers-loader-private.h"
#endif
#define CLEANUP_INTERVAL 10800 // once every 3 hours
#define GST_CAT_DEFAULT clapper_enhancer_director_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
@@ -57,7 +64,7 @@ clapper_enhancer_director_extract_in_thread (ClapperEnhancerDirectorData *data)
ClapperEnhancerDirector *self = data->director;
GList *el;
ClapperHarvest *harvest = NULL;
gboolean success = FALSE, cached = FALSE;
gboolean success = FALSE;
GST_DEBUG_OBJECT (self, "Extraction start");
@@ -65,22 +72,22 @@ clapper_enhancer_director_extract_in_thread (ClapperEnhancerDirectorData *data)
if (g_cancellable_is_cancelled (data->cancellable))
return NULL;
/* TODO: Cache lookup */
if (cached) {
// if ((success = fill harvest from cache))
// return harvest;
}
GST_DEBUG_OBJECT (self, "Enhancer proxies for URI: %u",
g_list_length (data->filtered_proxies));
for (el = data->filtered_proxies; el; el = g_list_next (el)) {
ClapperEnhancerProxy *proxy = CLAPPER_ENHANCER_PROXY_CAST (el->data);
ClapperExtractable *extractable = NULL;
GstStructure *config;
/* Check just before extract */
if (g_cancellable_is_cancelled (data->cancellable))
harvest = clapper_harvest_new (); // fresh harvest for each iteration
config = clapper_enhancer_proxy_make_current_config (proxy);
if ((success = clapper_harvest_fill_from_cache (harvest, proxy, config, data->uri))
|| g_cancellable_is_cancelled (data->cancellable)) { // Check before extract
gst_clear_structure (&config);
break;
}
#if CLAPPER_WITH_ENHANCERS_LOADER
extractable = CLAPPER_EXTRACTABLE_CAST (
@@ -88,32 +95,32 @@ clapper_enhancer_director_extract_in_thread (ClapperEnhancerDirectorData *data)
#endif
if (G_LIKELY (extractable != NULL)) {
clapper_enhancer_proxy_apply_current_config_to_enhancer (proxy, (GObject *) extractable);
harvest = clapper_harvest_new (); // fresh harvest for each extractable
clapper_enhancer_proxy_apply_config_to_enhancer (proxy, config, (GObject *) extractable);
success = clapper_extractable_extract (extractable, data->uri,
harvest, data->cancellable, data->error);
gst_object_unref (extractable);
/* We are done with extractable, but keep its harvest */
if (success)
break;
/* We are done with extractable, but keep harvest and try to cache it */
if (success) {
if (!g_cancellable_is_cancelled (data->cancellable))
clapper_harvest_export_to_cache (harvest, proxy, config, data->uri);
/* Clear harvest and try again with next enhancer */
g_clear_object (&harvest);
gst_clear_structure (&config);
break;
}
}
/* Cleanup to try again with next enhancer */
g_clear_object (&harvest);
gst_clear_structure (&config);
}
/* Cancelled during extract */
/* Cancelled during extraction or exporting to cache */
if (g_cancellable_is_cancelled (data->cancellable))
success = FALSE;
if (success) {
if (!cached) {
/* TODO: Store in cache */
}
} else {
if (!success) {
gst_clear_object (&harvest);
/* Ensure we have some error set on failure */
@@ -131,6 +138,171 @@ clapper_enhancer_director_extract_in_thread (ClapperEnhancerDirectorData *data)
return harvest;
}
static inline void
_harvest_delete_if_expired (ClapperEnhancerDirector *self,
ClapperEnhancerProxy *proxy, GFile *file, const gint64 epoch_now)
{
GMappedFile *mapped_file;
const gchar *data;
gchar *filename;
GError *error = NULL;
gboolean delete = TRUE;
filename = g_file_get_path (file);
if ((mapped_file = clapper_cache_open (filename, &data, &error))) {
/* Do not delete if versions match and not expired */
if (g_strcmp0 (clapper_cache_read_string (&data),
clapper_enhancer_proxy_get_version (proxy)) == 0
&& clapper_cache_read_int64 (&data) > epoch_now) {
delete = FALSE;
}
g_mapped_file_unref (mapped_file);
} else if (error) {
if (error->domain == G_FILE_ERROR && error->code == G_FILE_ERROR_NOENT)
GST_DEBUG_OBJECT (self, "No cached harvest file found");
else
GST_ERROR_OBJECT (self, "Could not read cached harvest file, reason: %s", error->message);
g_clear_error (&error);
}
if (delete) {
if (G_LIKELY (g_file_delete (file, NULL, &error))) {
GST_TRACE_OBJECT (self, "Deleted cached harvest: \"%s\"", filename);
} else {
GST_ERROR_OBJECT (self, "Could not delete harvest: \"%s\", reason: %s",
filename, GST_STR_NULL (error->message));
g_error_free (error);
}
}
g_free (filename);
}
static inline void
_cache_proxy_harvests_cleanup (ClapperEnhancerDirector *self,
ClapperEnhancerProxy *proxy, const gint64 epoch_now)
{
GFile *dir;
GFileEnumerator *dir_enum;
GError *error = NULL;
dir = g_file_new_build_filename (g_get_user_cache_dir (), CLAPPER_API_NAME,
"enhancers", clapper_enhancer_proxy_get_module_name (proxy),
"harvests", NULL);
if ((dir_enum = g_file_enumerate_children (dir,
G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_TYPE,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &error))) {
while (TRUE) {
GFileInfo *info = NULL;
GFile *child = NULL;
if (!g_file_enumerator_iterate (dir_enum, &info,
&child, NULL, &error) || !info)
break;
if (G_LIKELY (g_file_info_get_file_type (info) == G_FILE_TYPE_REGULAR
&& g_str_has_suffix (g_file_info_get_name (info), ".bin")))
_harvest_delete_if_expired (self, proxy, child, epoch_now);
}
g_object_unref (dir_enum);
}
if (error) {
if (error->domain != G_IO_ERROR || error->code != G_IO_ERROR_NOT_FOUND) {
gchar *path = g_file_get_path (dir);
GST_ERROR_OBJECT (self, "Could not cleanup in dir: \"%s\", reason: %s",
path, GST_STR_NULL (error->message));
g_free (path);
}
g_error_free (error);
}
g_object_unref (dir);
}
static gboolean
_cache_cleanup_func (ClapperEnhancerDirector *self)
{
GMappedFile *mapped_file;
GDateTime *date;
GError *error = NULL;
gchar *filename;
const gchar *data;
gint64 since_cleanup, epoch_now, epoch_last = 0;
date = g_date_time_new_now_utc ();
epoch_now = g_date_time_to_unix (date);
g_date_time_unref (date);
filename = g_build_filename (g_get_user_cache_dir (), CLAPPER_API_NAME,
"enhancers", "cleanup.bin", NULL);
if ((mapped_file = clapper_cache_open (filename, &data, &error))) {
epoch_last = clapper_cache_read_int64 (&data);
g_mapped_file_unref (mapped_file);
} else if (error) {
if (error->domain == G_FILE_ERROR && error->code == G_FILE_ERROR_NOENT)
GST_DEBUG_OBJECT (self, "No cache cleanup file found");
else
GST_ERROR_OBJECT (self, "Could not read cache cleanup file, reason: %s", error->message);
g_clear_error (&error);
}
since_cleanup = epoch_now - epoch_last;
if (since_cleanup >= CLEANUP_INTERVAL) {
ClapperEnhancerProxyList *proxies;
guint i, n_proxies;
GByteArray *bytes;
GST_TRACE_OBJECT (self, "Time for cache cleanup, last was %"
CLAPPER_TIME_FORMAT " ago", CLAPPER_TIME_ARGS (since_cleanup));
/* Start with writing to cache cleanup time,
* so other directors can find it earlier */
if ((bytes = clapper_cache_create ())) {
clapper_cache_store_int64 (bytes, epoch_now);
if (clapper_cache_write (filename, bytes, &error)) {
GST_TRACE_OBJECT (self, "Written data to cache cleanup file, cleanup time: %"
G_GINT64_FORMAT, epoch_now);
} else if (error) {
GST_ERROR_OBJECT (self, "Could not write cache cleanup data, reason: %s", error->message);
g_clear_error (&error);
}
g_byte_array_free (bytes, TRUE);
}
/* Now do cleanup */
proxies = clapper_get_global_enhancer_proxies ();
n_proxies = clapper_enhancer_proxy_list_get_n_proxies (proxies);
for (i = 0; i < n_proxies; ++i) {
ClapperEnhancerProxy *proxy = clapper_enhancer_proxy_list_peek_proxy (proxies, i);
if (!clapper_enhancer_proxy_target_has_interface (proxy, CLAPPER_TYPE_EXTRACTABLE))
continue;
_cache_proxy_harvests_cleanup (self, proxy, epoch_now);
}
} else {
GST_TRACE_OBJECT (self, "No cache cleanup yet, last was %"
CLAPPER_TIME_FORMAT " ago", CLAPPER_TIME_ARGS (since_cleanup));
}
g_free (filename);
return G_SOURCE_REMOVE;
}
/*
* clapper_enhancer_director_new:
*
@@ -153,6 +325,8 @@ clapper_enhancer_director_extract (ClapperEnhancerDirector *self,
GCancellable *cancellable, GError **error)
{
ClapperEnhancerDirectorData *data = g_new (ClapperEnhancerDirectorData, 1);
GMainContext *context;
ClapperHarvest *harvest;
data->director = self;
data->filtered_proxies = filtered_proxies;
@@ -160,10 +334,18 @@ clapper_enhancer_director_extract (ClapperEnhancerDirector *self,
data->cancellable = cancellable;
data->error = error;
return CLAPPER_HARVEST_CAST (clapper_shared_utils_context_invoke_sync_full (
clapper_threaded_object_get_context (CLAPPER_THREADED_OBJECT_CAST (self)),
context = clapper_threaded_object_get_context (CLAPPER_THREADED_OBJECT_CAST (self));
harvest = CLAPPER_HARVEST_CAST (clapper_shared_utils_context_invoke_sync_full (context,
(GThreadFunc) clapper_enhancer_director_extract_in_thread,
data, (GDestroyNotify) g_free));
/* Run cleanup async. Since context belongs to "self", do not ref it.
* This ensures clean shutdown with thread stop function called. */
if (!g_cancellable_is_cancelled (cancellable) && !clapper_cache_is_disabled ())
g_main_context_invoke (context, (GSourceFunc) _cache_cleanup_func, self);
return harvest;
}
static void

View File

@@ -26,12 +26,12 @@
G_BEGIN_DECLS
#define CLAPPER_TYPE_ENHANCER_SRC (clapper_enhancer_src_get_type())
#define CLAPPER_ENHANCER_SRC_CAST(obj) ((ClapperEnhancerSrc *)(obj))
#define CLAPPER_TYPE_EXTRACTABLE_SRC (clapper_extractable_src_get_type())
#define CLAPPER_EXTRACTABLE_SRC_CAST(obj) ((ClapperExtractableSrc *)(obj))
G_GNUC_INTERNAL
G_DECLARE_FINAL_TYPE (ClapperEnhancerSrc, clapper_enhancer_src, CLAPPER, ENHANCER_SRC, GstPushSrc)
G_DECLARE_FINAL_TYPE (ClapperExtractableSrc, clapper_extractable_src, CLAPPER, EXTRACTABLE_SRC, GstPushSrc)
GST_ELEMENT_REGISTER_DECLARE (clapperenhancersrc)
GST_ELEMENT_REGISTER_DECLARE (clapperextractablesrc)
G_END_DECLS

View File

@@ -19,7 +19,7 @@
#include "config.h"
#include "clapper-enhancer-src-private.h"
#include "clapper-extractable-src-private.h"
#include "clapper-enhancer-director-private.h"
#include "../clapper-basic-functions.h"
@@ -28,13 +28,13 @@
#include "../clapper-extractable.h"
#include "../clapper-harvest-private.h"
#define GST_CAT_DEFAULT clapper_enhancer_src_debug
#define GST_CAT_DEFAULT clapper_extractable_src_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define CHECK_SCHEME_IS_HTTPS(scheme) (g_str_has_prefix (scheme, "http") \
&& (scheme[4] == '\0' || (scheme[4] == 's' && scheme[5] == '\0')))
struct _ClapperEnhancerSrc
struct _ClapperExtractableSrc
{
GstPushSrc parent;
@@ -65,7 +65,7 @@ static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
GST_STATIC_CAPS_ANY);
static GstURIType
clapper_enhancer_src_uri_handler_get_type (GType type)
clapper_extractable_src_uri_handler_get_type (GType type)
{
return GST_URI_SRC;
}
@@ -145,19 +145,19 @@ _host_fixup (const gchar *host)
}
/*
* _enhancer_check_for_uri:
* @self: a #ClapperEnhancerSrc
* _extractable_check_for_uri:
* @self: a #ClapperExtractableSrc
* @uri: a #GUri
*
* Check whether there is at least one enhancer for @uri in global list.
* Check whether there is at least one extractable enhancer for @uri in global list.
* This is used to reject URI early, thus making playbin choose different
* source element. It uses global list, since at this stage element is not
* yet placed within pipeline, so it cannot get proxies from player.
*
* Returns: whether at least one enhancer advertises support for given URI.
* Returns: whether at least one extractable enhancer advertises support for given URI.
*/
static gboolean
_enhancer_check_for_uri (ClapperEnhancerSrc *self, GUri *uri)
_extractable_check_for_uri (ClapperExtractableSrc *self, GUri *uri)
{
ClapperEnhancerProxyList *proxies = clapper_get_global_enhancer_proxies ();
gboolean is_https;
@@ -168,7 +168,7 @@ _enhancer_check_for_uri (ClapperEnhancerSrc *self, GUri *uri)
if (host)
host = _host_fixup (host);
GST_INFO_OBJECT (self, "Enhancer check, scheme: \"%s\", host: \"%s\"",
GST_INFO_OBJECT (self, "Extractable check, scheme: \"%s\", host: \"%s\"",
scheme, GST_STR_NULL (host));
/* Whether "http(s)" scheme is used */
@@ -191,8 +191,8 @@ _enhancer_check_for_uri (ClapperEnhancerSrc *self, GUri *uri)
}
/*
* _filter_enhancers_for_uri:
* @self: a #ClapperEnhancerSrc
* _filter_extractables_for_uri:
* @self: a #ClapperExtractableSrc
* @proxies: a #ClapperEnhancerProxyList
* @uri: a #GUri
*
@@ -202,7 +202,7 @@ _enhancer_check_for_uri (ClapperEnhancerSrc *self, GUri *uri)
* Returns: (transfer full): A sublist in the form of #GList with proxies.
*/
static GList *
_filter_enhancers_for_uri (ClapperEnhancerSrc *self,
_filter_extractables_for_uri (ClapperExtractableSrc *self,
ClapperEnhancerProxyList *proxies, GUri *uri)
{
GList *sublist = NULL;
@@ -214,7 +214,7 @@ _filter_enhancers_for_uri (ClapperEnhancerSrc *self,
if (host)
host = _host_fixup (host);
GST_INFO_OBJECT (self, "Enhancer filter, scheme: \"%s\", host: \"%s\"",
GST_INFO_OBJECT (self, "Extractable filter, scheme: \"%s\", host: \"%s\"",
scheme, GST_STR_NULL (host));
/* Whether "http(s)" scheme is used */
@@ -239,7 +239,7 @@ _filter_enhancers_for_uri (ClapperEnhancerSrc *self,
}
static const gchar *const *
clapper_enhancer_src_uri_handler_get_protocols (GType type)
clapper_extractable_src_uri_handler_get_protocols (GType type)
{
static GOnce schemes_once = G_ONCE_INIT;
@@ -248,9 +248,9 @@ clapper_enhancer_src_uri_handler_get_protocols (GType type)
}
static gchar *
clapper_enhancer_src_uri_handler_get_uri (GstURIHandler *handler)
clapper_extractable_src_uri_handler_get_uri (GstURIHandler *handler)
{
ClapperEnhancerSrc *self = CLAPPER_ENHANCER_SRC_CAST (handler);
ClapperExtractableSrc *self = CLAPPER_EXTRACTABLE_SRC_CAST (handler);
gchar *uri;
GST_OBJECT_LOCK (self);
@@ -261,10 +261,10 @@ clapper_enhancer_src_uri_handler_get_uri (GstURIHandler *handler)
}
static gboolean
clapper_enhancer_src_uri_handler_set_uri (GstURIHandler *handler,
clapper_extractable_src_uri_handler_set_uri (GstURIHandler *handler,
const gchar *uri, GError **error)
{
ClapperEnhancerSrc *self = CLAPPER_ENHANCER_SRC_CAST (handler);
ClapperExtractableSrc *self = CLAPPER_EXTRACTABLE_SRC_CAST (handler);
GUri *guri;
const gchar *const *protocols;
gboolean supported = FALSE;
@@ -300,7 +300,7 @@ clapper_enhancer_src_uri_handler_set_uri (GstURIHandler *handler,
return FALSE;
}
if (!_enhancer_check_for_uri (self, guri)) {
if (!_extractable_check_for_uri (self, guri)) {
g_set_error (error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI,
"None of the available enhancers can handle this URI");
g_uri_unref (guri);
@@ -324,22 +324,22 @@ clapper_enhancer_src_uri_handler_set_uri (GstURIHandler *handler,
static void
_uri_handler_iface_init (GstURIHandlerInterface *iface)
{
iface->get_type = clapper_enhancer_src_uri_handler_get_type;
iface->get_protocols = clapper_enhancer_src_uri_handler_get_protocols;
iface->get_uri = clapper_enhancer_src_uri_handler_get_uri;
iface->set_uri = clapper_enhancer_src_uri_handler_set_uri;
iface->get_type = clapper_extractable_src_uri_handler_get_type;
iface->get_protocols = clapper_extractable_src_uri_handler_get_protocols;
iface->get_uri = clapper_extractable_src_uri_handler_get_uri;
iface->set_uri = clapper_extractable_src_uri_handler_set_uri;
}
#define parent_class clapper_enhancer_src_parent_class
G_DEFINE_TYPE_WITH_CODE (ClapperEnhancerSrc, clapper_enhancer_src, GST_TYPE_PUSH_SRC,
#define parent_class clapper_extractable_src_parent_class
G_DEFINE_TYPE_WITH_CODE (ClapperExtractableSrc, clapper_extractable_src, GST_TYPE_PUSH_SRC,
G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER, _uri_handler_iface_init));
GST_ELEMENT_REGISTER_DEFINE (clapperenhancersrc, "clapperenhancersrc",
512, CLAPPER_TYPE_ENHANCER_SRC);
GST_ELEMENT_REGISTER_DEFINE (clapperextractablesrc, "clapperextractablesrc",
512, CLAPPER_TYPE_EXTRACTABLE_SRC);
static gboolean
clapper_enhancer_src_start (GstBaseSrc *base_src)
clapper_extractable_src_start (GstBaseSrc *base_src)
{
ClapperEnhancerSrc *self = CLAPPER_ENHANCER_SRC_CAST (base_src);
ClapperExtractableSrc *self = CLAPPER_EXTRACTABLE_SRC_CAST (base_src);
gboolean can_start;
GST_DEBUG_OBJECT (self, "Start");
@@ -358,9 +358,9 @@ clapper_enhancer_src_start (GstBaseSrc *base_src)
}
static gboolean
clapper_enhancer_src_stop (GstBaseSrc *base_src)
clapper_extractable_src_stop (GstBaseSrc *base_src)
{
ClapperEnhancerSrc *self = CLAPPER_ENHANCER_SRC_CAST (base_src);
ClapperExtractableSrc *self = CLAPPER_EXTRACTABLE_SRC_CAST (base_src);
GST_DEBUG_OBJECT (self, "Stop");
@@ -370,9 +370,9 @@ clapper_enhancer_src_stop (GstBaseSrc *base_src)
}
static gboolean
clapper_enhancer_src_get_size (GstBaseSrc *base_src, guint64 *size)
clapper_extractable_src_get_size (GstBaseSrc *base_src, guint64 *size)
{
ClapperEnhancerSrc *self = CLAPPER_ENHANCER_SRC_CAST (base_src);
ClapperExtractableSrc *self = CLAPPER_EXTRACTABLE_SRC_CAST (base_src);
if (self->buf_size > 0) {
*size = self->buf_size;
@@ -383,15 +383,15 @@ clapper_enhancer_src_get_size (GstBaseSrc *base_src, guint64 *size)
}
static gboolean
clapper_enhancer_src_is_seekable (GstBaseSrc *base_src)
clapper_extractable_src_is_seekable (GstBaseSrc *base_src)
{
return FALSE;
}
static gboolean
clapper_enhancer_src_unlock (GstBaseSrc *base_src)
clapper_extractable_src_unlock (GstBaseSrc *base_src)
{
ClapperEnhancerSrc *self = CLAPPER_ENHANCER_SRC_CAST (base_src);
ClapperExtractableSrc *self = CLAPPER_EXTRACTABLE_SRC_CAST (base_src);
GST_LOG_OBJECT (self, "Cancel triggered");
g_cancellable_cancel (self->cancellable);
@@ -400,9 +400,9 @@ clapper_enhancer_src_unlock (GstBaseSrc *base_src)
}
static gboolean
clapper_enhancer_src_unlock_stop (GstBaseSrc *base_src)
clapper_extractable_src_unlock_stop (GstBaseSrc *base_src)
{
ClapperEnhancerSrc *self = CLAPPER_ENHANCER_SRC_CAST (base_src);
ClapperExtractableSrc *self = CLAPPER_EXTRACTABLE_SRC_CAST (base_src);
GST_LOG_OBJECT (self, "Resetting cancellable");
@@ -414,7 +414,7 @@ clapper_enhancer_src_unlock_stop (GstBaseSrc *base_src)
/* Pushes tags, toc and request headers downstream (all transfer full) */
static void
_push_events (ClapperEnhancerSrc *self, GstTagList *tags, GstToc *toc,
_push_events (ClapperExtractableSrc *self, GstTagList *tags, GstToc *toc,
GstStructure *headers, gboolean updated)
{
GstEvent *event;
@@ -462,9 +462,9 @@ _push_events (ClapperEnhancerSrc *self, GstTagList *tags, GstToc *toc,
}
static GstFlowReturn
clapper_enhancer_src_create (GstPushSrc *push_src, GstBuffer **outbuf)
clapper_extractable_src_create (GstPushSrc *push_src, GstBuffer **outbuf)
{
ClapperEnhancerSrc *self = CLAPPER_ENHANCER_SRC_CAST (push_src);
ClapperExtractableSrc *self = CLAPPER_EXTRACTABLE_SRC_CAST (push_src);
ClapperEnhancerProxyList *proxies;
GList *filtered_proxies;
GUri *guri;
@@ -502,7 +502,7 @@ clapper_enhancer_src_create (GstPushSrc *push_src, GstBuffer **outbuf)
GST_OBJECT_UNLOCK (self);
filtered_proxies = _filter_enhancers_for_uri (self, proxies, guri);
filtered_proxies = _filter_extractables_for_uri (self, proxies, guri);
gst_object_unref (proxies);
harvest = clapper_enhancer_director_extract (self->director,
@@ -554,7 +554,7 @@ _handle_uri_query (GstQuery *query)
}
static gboolean
clapper_enhancer_src_query (GstBaseSrc *base_src, GstQuery *query)
clapper_extractable_src_query (GstBaseSrc *base_src, GstQuery *query)
{
gboolean ret = FALSE;
@@ -573,7 +573,7 @@ clapper_enhancer_src_query (GstBaseSrc *base_src, GstQuery *query)
}
static void
clapper_enhancer_src_set_enhancer_proxies (ClapperEnhancerSrc *self,
clapper_extractable_src_set_enhancer_proxies (ClapperExtractableSrc *self,
ClapperEnhancerProxyList *enhancer_proxies)
{
GST_OBJECT_LOCK (self);
@@ -583,15 +583,15 @@ clapper_enhancer_src_set_enhancer_proxies (ClapperEnhancerSrc *self,
}
static void
clapper_enhancer_src_init (ClapperEnhancerSrc *self)
clapper_extractable_src_init (ClapperExtractableSrc *self)
{
self->cancellable = g_cancellable_new ();
}
static void
clapper_enhancer_src_dispose (GObject *object)
clapper_extractable_src_dispose (GObject *object)
{
ClapperEnhancerSrc *self = CLAPPER_ENHANCER_SRC_CAST (object);
ClapperExtractableSrc *self = CLAPPER_EXTRACTABLE_SRC_CAST (object);
GST_OBJECT_LOCK (self);
g_clear_object (&self->director);
@@ -601,9 +601,9 @@ clapper_enhancer_src_dispose (GObject *object)
}
static void
clapper_enhancer_src_finalize (GObject *object)
clapper_extractable_src_finalize (GObject *object)
{
ClapperEnhancerSrc *self = CLAPPER_ENHANCER_SRC_CAST (object);
ClapperExtractableSrc *self = CLAPPER_EXTRACTABLE_SRC_CAST (object);
GST_TRACE_OBJECT (self, "Finalize");
@@ -616,10 +616,10 @@ clapper_enhancer_src_finalize (GObject *object)
}
static void
clapper_enhancer_src_set_property (GObject *object, guint prop_id,
clapper_extractable_src_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
ClapperEnhancerSrc *self = CLAPPER_ENHANCER_SRC_CAST (object);
ClapperExtractableSrc *self = CLAPPER_EXTRACTABLE_SRC_CAST (object);
switch (prop_id) {
case PROP_URI:{
@@ -632,7 +632,7 @@ clapper_enhancer_src_set_property (GObject *object, guint prop_id,
break;
}
case PROP_ENHANCER_PROXIES:
clapper_enhancer_src_set_enhancer_proxies (self, g_value_get_object (value));
clapper_extractable_src_set_enhancer_proxies (self, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -641,10 +641,10 @@ clapper_enhancer_src_set_property (GObject *object, guint prop_id,
}
static void
clapper_enhancer_src_get_property (GObject *object, guint prop_id,
clapper_extractable_src_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
ClapperEnhancerSrc *self = CLAPPER_ENHANCER_SRC_CAST (object);
ClapperExtractableSrc *self = CLAPPER_EXTRACTABLE_SRC_CAST (object);
switch (prop_id) {
case PROP_URI:
@@ -657,30 +657,30 @@ clapper_enhancer_src_get_property (GObject *object, guint prop_id,
}
static void
clapper_enhancer_src_class_init (ClapperEnhancerSrcClass *klass)
clapper_extractable_src_class_init (ClapperExtractableSrcClass *klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
GstElementClass *gstelement_class = (GstElementClass *) klass;
GstBaseSrcClass *gstbasesrc_class = (GstBaseSrcClass *) klass;
GstPushSrcClass *gstpushsrc_class = (GstPushSrcClass *) klass;
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "clapperenhancersrc", 0,
"Clapper Enhancer Source");
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "clapperextractablesrc", 0,
"Clapper Extractable Source");
gobject_class->set_property = clapper_enhancer_src_set_property;
gobject_class->get_property = clapper_enhancer_src_get_property;
gobject_class->dispose = clapper_enhancer_src_dispose;
gobject_class->finalize = clapper_enhancer_src_finalize;
gobject_class->set_property = clapper_extractable_src_set_property;
gobject_class->get_property = clapper_extractable_src_get_property;
gobject_class->dispose = clapper_extractable_src_dispose;
gobject_class->finalize = clapper_extractable_src_finalize;
gstbasesrc_class->start = clapper_enhancer_src_start;
gstbasesrc_class->stop = clapper_enhancer_src_stop;
gstbasesrc_class->get_size = clapper_enhancer_src_get_size;
gstbasesrc_class->is_seekable = clapper_enhancer_src_is_seekable;
gstbasesrc_class->unlock = clapper_enhancer_src_unlock;
gstbasesrc_class->unlock_stop = clapper_enhancer_src_unlock_stop;
gstbasesrc_class->query = clapper_enhancer_src_query;
gstbasesrc_class->start = clapper_extractable_src_start;
gstbasesrc_class->stop = clapper_extractable_src_stop;
gstbasesrc_class->get_size = clapper_extractable_src_get_size;
gstbasesrc_class->is_seekable = clapper_extractable_src_is_seekable;
gstbasesrc_class->unlock = clapper_extractable_src_unlock;
gstbasesrc_class->unlock_stop = clapper_extractable_src_unlock_stop;
gstbasesrc_class->query = clapper_extractable_src_query;
gstpushsrc_class->create = clapper_enhancer_src_create;
gstpushsrc_class->create = clapper_extractable_src_create;
param_specs[PROP_URI] = g_param_spec_string ("uri",
"URI", "URI", NULL,
@@ -694,7 +694,7 @@ clapper_enhancer_src_class_init (ClapperEnhancerSrcClass *klass)
gst_element_class_add_static_pad_template (gstelement_class, &src_template);
gst_element_class_set_static_metadata (gstelement_class, "Clapper Enhancer Source",
"Source", "A source element that uses Clapper Enhancers to produce data",
gst_element_class_set_static_metadata (gstelement_class, "Clapper Extractable Source",
"Source", "A source element that uses Clapper extractable enhancers to produce data",
"Rafał Dzięgiel <rafostar.github@gmail.com>");
}

View File

@@ -27,7 +27,7 @@
#include "../clapper-extractable.h"
#include "clapper-plugin-private.h"
#include "clapper-enhancer-src-private.h"
#include "clapper-extractable-src-private.h"
#include "clapper-uri-list-demux-private.h"
/*
@@ -67,7 +67,7 @@ clapper_gst_plugin_init (GstPlugin *plugin)
/* Avoid registering an URI handler without schemes */
if (clapper_gst_plugin_has_enhancers (global_proxies, CLAPPER_TYPE_EXTRACTABLE))
res |= GST_ELEMENT_REGISTER (clapperenhancersrc, plugin);
res |= GST_ELEMENT_REGISTER (clapperextractablesrc, plugin);
res |= GST_ELEMENT_REGISTER (clapperurilistdemux, plugin);

View File

@@ -193,7 +193,7 @@ _feature_filter (GstPluginFeature *feature, const gchar *search_proto)
feature_name = gst_plugin_feature_get_name (feature);
/* Do not loop endlessly creating our own sources and demuxers */
if (!feature_name || strcmp (feature_name, "clapperenhancersrc") == 0)
if (!feature_name || strcmp (feature_name, "clapperextractablesrc") == 0)
return FALSE;
protocols = gst_element_factory_get_uri_protocols (factory);

View File

@@ -55,7 +55,6 @@ config_h.set_quoted('PACKAGE_ORIGIN', 'https://github.com/Rafostar/clapper')
config_h.set_quoted('PLUGIN_DESC', 'Clapper elements')
config_h.set_quoted('PLUGIN_LICENSE', 'LGPL')
config_h.set_quoted('CLAPPER_API_NAME', clapper_api_name)
config_h.set_quoted('CLAPPER_ENHANCERS_ID', 'com.github.rafostar.Clapper.Enhancers')
config_h.set_quoted('CLAPPER_ENHANCERS_PATH', clapper_enhancers_dir)
configure_file(
@@ -156,7 +155,7 @@ clapper_sources = [
'clapper-utils.c',
'clapper-video-stream.c',
'gst/clapper-plugin.c',
'gst/clapper-enhancer-src.c',
'gst/clapper-extractable-src.c',
'gst/clapper-enhancer-director.c',
'gst/clapper-uri-list-demux.c',
'../shared/clapper-shared-utils.c',
@@ -236,7 +235,6 @@ if build_gir
clapper_enums,
],
extra_args: [
gir_init_section,
'--quiet',
'--warn-all',
'-DCLAPPER_COMPILATION',

View File

@@ -4,12 +4,6 @@ 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_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')