mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 11:41:09 +00:00
registry: Add registry helper phase 1
Phase 1 of adding the registry scan helper
This commit is contained in:
parent
1f4e477033
commit
51675e0c2a
18 changed files with 1901 additions and 1091 deletions
|
@ -681,6 +681,7 @@ libs/gst/check/libcheck/Makefile
|
|||
libs/gst/check/libcheck/check.h
|
||||
libs/gst/controller/Makefile
|
||||
libs/gst/dataprotocol/Makefile
|
||||
libs/gst/helpers/Makefile
|
||||
libs/gst/net/Makefile
|
||||
plugins/Makefile
|
||||
plugins/indexers/Makefile
|
||||
|
|
|
@ -33,6 +33,8 @@ gst_update_registry
|
|||
<SUBSECTION Private>
|
||||
GST_QUARK
|
||||
GstQuarkId
|
||||
GstPluginLoader
|
||||
GstPluginLoaderFuncs
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
|
|
|
@ -82,11 +82,13 @@ libgstreamer_@GST_MAJORMINOR@_la_SOURCES = \
|
|||
gstpipeline.c \
|
||||
gstplugin.c \
|
||||
gstpluginfeature.c \
|
||||
gstpluginloader.c \
|
||||
gstpoll.c \
|
||||
gstpreset.c \
|
||||
gstquark.c \
|
||||
gstquery.c \
|
||||
gstregistry.c \
|
||||
gstregistrychunks.c \
|
||||
gstsegment.c \
|
||||
gststructure.c \
|
||||
gstsystemclock.c \
|
||||
|
@ -200,8 +202,10 @@ noinst_HEADERS = \
|
|||
glib-compat-private.h \
|
||||
gst-i18n-lib.h \
|
||||
gst-i18n-app.h \
|
||||
gstpluginloader.h \
|
||||
gstquark.h \
|
||||
gstregistrybinary.h \
|
||||
gstregistrychunks.h \
|
||||
gst_private.h
|
||||
|
||||
gstmarshal.h: gstmarshal.list
|
||||
|
|
|
@ -99,13 +99,13 @@ void _gst_value_initialize (void);
|
|||
/* Private registry functions */
|
||||
gboolean _priv_gst_registry_remove_cache_plugins (GstRegistry *registry);
|
||||
void _priv_gst_registry_cleanup (void);
|
||||
gboolean _gst_plugin_loader_client_run (void);
|
||||
|
||||
/* used in both gststructure.c and gstcaps.c; numbers are completely made up */
|
||||
#define STRUCTURE_ESTIMATED_STRING_LEN(s) (16 + (s)->fields->len * 22)
|
||||
|
||||
gboolean priv_gst_structure_append_to_gstring (const GstStructure * structure,
|
||||
GString * s);
|
||||
|
||||
/* registry cache backends */
|
||||
/* FIXME 0.11: use priv_ prefix */
|
||||
gboolean gst_registry_binary_read_cache (GstRegistry * registry, const char *location);
|
||||
|
@ -117,6 +117,11 @@ gboolean gst_registry_binary_write_cache (GstRegistry * registry, const char *
|
|||
((c) == '-') || ((c) == '+') || ((c) == '/') || ((c) == ':') || \
|
||||
((c) == '.'))
|
||||
|
||||
#ifndef GST_DISABLE_REGISTRY
|
||||
/* Secret variable to initialise gst without registry cache */
|
||||
extern gboolean _gst_disable_registry_cache;
|
||||
#endif
|
||||
|
||||
/*** debugging categories *****************************************************/
|
||||
|
||||
#ifndef GST_REMOVE_GST_DEBUG
|
||||
|
|
536
gst/gstpluginloader.c
Normal file
536
gst/gstpluginloader.c
Normal file
|
@ -0,0 +1,536 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2008 Jan Schmidt <jan.schmidt@sun.com>
|
||||
*
|
||||
* gstpluginloader.c: GstPluginLoader helper for loading plugin files
|
||||
* out of process.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#ifndef G_OS_WIN32
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
|
||||
#include <gst/gst_private.h>
|
||||
#include <gst/gstconfig.h>
|
||||
|
||||
#include <gst/gstpoll.h>
|
||||
#include <gst/gstutils.h>
|
||||
|
||||
#include <gst/gstpluginloader.h>
|
||||
#include <gst/gstregistrychunks.h>
|
||||
|
||||
#define GST_CAT_DEFAULT GST_CAT_PLUGIN_LOADING
|
||||
|
||||
static GstPluginLoader *plugin_loader_new (GstRegistry * registry);
|
||||
static gboolean plugin_loader_free (GstPluginLoader * loader);
|
||||
static gboolean plugin_loader_load (GstPluginLoader * loader,
|
||||
const gchar * filename);
|
||||
|
||||
const GstPluginLoaderFuncs _priv_gst_plugin_loader_funcs = {
|
||||
plugin_loader_new, plugin_loader_free, plugin_loader_load
|
||||
};
|
||||
|
||||
struct _GstPluginLoader
|
||||
{
|
||||
GstRegistry *registry;
|
||||
GstPoll *fdset;
|
||||
|
||||
gboolean child_started;
|
||||
GPid child_pid;
|
||||
GstPollFD fd_w;
|
||||
GstPollFD fd_r;
|
||||
|
||||
gboolean is_child;
|
||||
gboolean got_plugin_details;
|
||||
|
||||
/* Transmit buffer */
|
||||
guint8 *tx_buf;
|
||||
guint tx_buf_size;
|
||||
guint tx_buf_write;
|
||||
guint tx_buf_read;
|
||||
|
||||
guint32 next_tag;
|
||||
|
||||
guint8 *rx_buf;
|
||||
guint rx_buf_size;
|
||||
gboolean rx_done;
|
||||
};
|
||||
|
||||
#define PACKET_EXIT 1
|
||||
#define PACKET_LOAD_PLUGIN 2
|
||||
#define PACKET_STARTING_LOAD 3
|
||||
#define PACKET_PLUGIN_DETAILS 4
|
||||
|
||||
#define BUF_INIT_SIZE 512
|
||||
#define BUF_GROW_EXTRA 512
|
||||
#define HEADER_SIZE 8
|
||||
#define ALIGNMENT (sizeof (void *))
|
||||
|
||||
|
||||
static gboolean gst_plugin_loader_spawn (GstPluginLoader * loader);
|
||||
static void put_packet (GstPluginLoader * loader, guint type, guint32 tag,
|
||||
const guint8 * payload, guint32 payload_len);
|
||||
static gboolean exchange_packets (GstPluginLoader * l);
|
||||
|
||||
static GstPluginLoader *
|
||||
plugin_loader_new (GstRegistry * registry)
|
||||
{
|
||||
GstPluginLoader *l = g_new0 (GstPluginLoader, 1);
|
||||
|
||||
if (registry)
|
||||
l->registry = gst_object_ref (registry);
|
||||
l->fdset = gst_poll_new (FALSE);
|
||||
gst_poll_fd_init (&l->fd_w);
|
||||
gst_poll_fd_init (&l->fd_r);
|
||||
|
||||
l->tx_buf_size = BUF_INIT_SIZE;
|
||||
l->tx_buf = g_malloc (BUF_INIT_SIZE);
|
||||
|
||||
l->next_tag = 0;
|
||||
|
||||
l->rx_buf_size = BUF_INIT_SIZE;
|
||||
l->rx_buf = g_malloc (BUF_INIT_SIZE);
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
plugin_loader_free (GstPluginLoader * loader)
|
||||
{
|
||||
gboolean got_plugin_details;
|
||||
|
||||
fsync (loader->fd_w.fd);
|
||||
|
||||
if (loader->child_started) {
|
||||
put_packet (loader, PACKET_EXIT, 0, NULL, 0);
|
||||
|
||||
/* Swap packets with the child until it exits */
|
||||
while (!loader->rx_done && exchange_packets (loader)) {
|
||||
};
|
||||
|
||||
close (loader->fd_w.fd);
|
||||
close (loader->fd_r.fd);
|
||||
|
||||
#ifndef G_OS_WIN32
|
||||
GST_LOG ("waiting for child process to exit");
|
||||
waitpid (loader->child_pid, NULL, 0);
|
||||
#else
|
||||
g_warning ("FIXME: Implement child process shutdown for Win32");
|
||||
#endif
|
||||
g_spawn_close_pid (loader->child_pid);
|
||||
} else {
|
||||
close (loader->fd_w.fd);
|
||||
close (loader->fd_r.fd);
|
||||
}
|
||||
|
||||
gst_poll_free (loader->fdset);
|
||||
|
||||
g_free (loader->rx_buf);
|
||||
g_free (loader->tx_buf);
|
||||
|
||||
if (loader->registry)
|
||||
gst_object_unref (loader->registry);
|
||||
|
||||
got_plugin_details = loader->got_plugin_details;
|
||||
|
||||
g_free (loader);
|
||||
|
||||
return got_plugin_details;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
plugin_loader_load (GstPluginLoader * loader, const gchar * filename)
|
||||
{
|
||||
if (!loader->child_started) {
|
||||
if (!gst_plugin_loader_spawn (loader))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Send a packet to the child requesting that it load the given file */
|
||||
GST_LOG_OBJECT (loader->registry,
|
||||
"Sending file %s to child. tag %u", filename, loader->next_tag);
|
||||
|
||||
put_packet (loader, PACKET_LOAD_PLUGIN, loader->next_tag,
|
||||
(guint8 *) filename, strlen (filename) + 1);
|
||||
|
||||
loader->next_tag++;
|
||||
|
||||
if (!exchange_packets (loader))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_plugin_loader_spawn (GstPluginLoader * loader)
|
||||
{
|
||||
char *helper_bin =
|
||||
"/home/jan/devel/gstreamer/head/gstreamer/libs/gst/helpers/plugin-scanner";
|
||||
char *argv[] = { helper_bin, "-l", NULL };
|
||||
|
||||
if (!g_spawn_async_with_pipes (NULL, argv, NULL,
|
||||
G_SPAWN_DO_NOT_REAP_CHILD /* | G_SPAWN_STDERR_TO_DEV_NULL */ ,
|
||||
NULL, NULL, &loader->child_pid, &loader->fd_w.fd, &loader->fd_r.fd,
|
||||
NULL, NULL))
|
||||
return FALSE;
|
||||
|
||||
gst_poll_add_fd (loader->fdset, &loader->fd_w);
|
||||
|
||||
gst_poll_add_fd (loader->fdset, &loader->fd_r);
|
||||
gst_poll_fd_ctl_read (loader->fdset, &loader->fd_r, TRUE);
|
||||
|
||||
loader->child_started = TRUE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
_gst_plugin_loader_client_run ()
|
||||
{
|
||||
GstPluginLoader *l;
|
||||
|
||||
l = plugin_loader_new (NULL);
|
||||
if (l == NULL)
|
||||
return FALSE;
|
||||
|
||||
l->fd_w.fd = 1; /* STDOUT */
|
||||
gst_poll_add_fd (l->fdset, &l->fd_w);
|
||||
|
||||
l->fd_r.fd = 0; /* STDIN */
|
||||
gst_poll_add_fd (l->fdset, &l->fd_r);
|
||||
gst_poll_fd_ctl_read (l->fdset, &l->fd_r, TRUE);
|
||||
|
||||
l->is_child = TRUE;
|
||||
|
||||
GST_DEBUG ("Plugin scanner child running. Waiting for instructions");
|
||||
|
||||
/* Loop, listening for incoming packets on the fd and writing responses */
|
||||
while (!l->rx_done && exchange_packets (l));
|
||||
|
||||
plugin_loader_free (l);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
put_packet (GstPluginLoader * l, guint type, guint32 tag,
|
||||
const guint8 * payload, guint32 payload_len)
|
||||
{
|
||||
guint8 *out;
|
||||
guint len = payload_len + HEADER_SIZE;
|
||||
|
||||
if (l->tx_buf_write + len >= l->tx_buf_size) {
|
||||
l->tx_buf_size = l->tx_buf_write + len + BUF_GROW_EXTRA;
|
||||
l->tx_buf = g_realloc (l->tx_buf, l->tx_buf_size);
|
||||
}
|
||||
|
||||
out = l->tx_buf + l->tx_buf_write;
|
||||
|
||||
out[0] = type;
|
||||
GST_WRITE_UINT24_BE (out + 1, tag);
|
||||
GST_WRITE_UINT32_BE (out + 4, payload_len);
|
||||
memcpy (out + HEADER_SIZE, payload, payload_len);
|
||||
|
||||
l->tx_buf_write += len;
|
||||
gst_poll_fd_ctl_write (l->fdset, &l->fd_w, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
put_chunk (GstPluginLoader * l, GstRegistryChunk * chunk, guint * pos)
|
||||
{
|
||||
guint padsize = 0;
|
||||
guint len;
|
||||
guint8 *out;
|
||||
|
||||
/* Might need to align the chunk */
|
||||
if (chunk->align && ((*pos) % ALIGNMENT) != 0)
|
||||
padsize = ALIGNMENT - ((*pos) % ALIGNMENT);
|
||||
|
||||
len = padsize + chunk->size;
|
||||
|
||||
if (l->tx_buf_write + len >= l->tx_buf_size) {
|
||||
l->tx_buf_size = l->tx_buf_write + len + BUF_GROW_EXTRA;
|
||||
l->tx_buf = g_realloc (l->tx_buf, l->tx_buf_size);
|
||||
}
|
||||
|
||||
out = l->tx_buf + l->tx_buf_write;
|
||||
memcpy (out + padsize, chunk->data, chunk->size);
|
||||
|
||||
l->tx_buf_write += len;
|
||||
*pos += len;
|
||||
|
||||
gst_poll_fd_ctl_write (l->fdset, &l->fd_w, TRUE);
|
||||
};
|
||||
|
||||
static gboolean
|
||||
write_one (GstPluginLoader * l)
|
||||
{
|
||||
guint8 *out;
|
||||
guint32 to_write;
|
||||
int res;
|
||||
|
||||
if (l->tx_buf_read + HEADER_SIZE > l->tx_buf_write)
|
||||
return FALSE;
|
||||
|
||||
out = l->tx_buf + l->tx_buf_read;
|
||||
to_write = GST_READ_UINT32_BE (out + 4) + HEADER_SIZE;
|
||||
l->tx_buf_read += to_write;
|
||||
|
||||
GST_LOG ("Writing packet of size %d bytes to fd %d", to_write, l->fd_w.fd);
|
||||
|
||||
do {
|
||||
res = write (l->fd_w.fd, out, to_write);
|
||||
if (res > 0) {
|
||||
to_write -= res;
|
||||
out += res;
|
||||
}
|
||||
} while (to_write > 0 && res < 0 && (errno == EAGAIN || errno == EINTR));
|
||||
|
||||
if (l->tx_buf_read == l->tx_buf_write) {
|
||||
gst_poll_fd_ctl_write (l->fdset, &l->fd_w, FALSE);
|
||||
l->tx_buf_read = l->tx_buf_write = 0;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
do_plugin_load (GstPluginLoader * l, const gchar * filename, guint tag)
|
||||
{
|
||||
GstPlugin *newplugin;
|
||||
GList *chunks = NULL;
|
||||
|
||||
GST_DEBUG ("Plugin scanner loading file %s. tag %u\n", filename, tag);
|
||||
put_packet (l, PACKET_STARTING_LOAD, tag, NULL, 0);
|
||||
|
||||
newplugin = gst_plugin_load_file ((gchar *) filename, NULL);
|
||||
if (newplugin) {
|
||||
guint hdr_pos;
|
||||
guint offset;
|
||||
|
||||
/* Now serialise the plugin details and send */
|
||||
if (!_priv_gst_registry_chunks_save_plugin (&chunks,
|
||||
gst_registry_get_default (), newplugin))
|
||||
goto fail;
|
||||
|
||||
/* Store where the header is, write an empty one, then write
|
||||
* all the payload chunks, then fix up the header size */
|
||||
hdr_pos = l->tx_buf_write;
|
||||
offset = HEADER_SIZE;
|
||||
put_packet (l, PACKET_PLUGIN_DETAILS, tag, NULL, 0);
|
||||
|
||||
if (chunks) {
|
||||
GList *walk;
|
||||
for (walk = chunks; walk; walk = g_list_next (walk)) {
|
||||
GstRegistryChunk *cur = walk->data;
|
||||
put_chunk (l, cur, &offset);
|
||||
|
||||
if (!(cur->flags & GST_REGISTRY_CHUNK_FLAG_CONST))
|
||||
g_free (cur->data);
|
||||
g_free (cur);
|
||||
}
|
||||
|
||||
g_list_free (chunks);
|
||||
|
||||
/* Store the size of the written payload */
|
||||
GST_WRITE_UINT32_BE (l->tx_buf + hdr_pos + 4, offset - HEADER_SIZE);
|
||||
}
|
||||
|
||||
gst_object_unref (newplugin);
|
||||
} else {
|
||||
put_packet (l, PACKET_PLUGIN_DETAILS, tag, NULL, 0);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
fail:
|
||||
put_packet (l, PACKET_PLUGIN_DETAILS, tag, NULL, 0);
|
||||
if (chunks) {
|
||||
GList *walk;
|
||||
for (walk = chunks; walk; walk = g_list_next (walk)) {
|
||||
GstRegistryChunk *cur = walk->data;
|
||||
|
||||
if (!(cur->flags & GST_REGISTRY_CHUNK_FLAG_CONST))
|
||||
g_free (cur->data);
|
||||
g_free (cur);
|
||||
}
|
||||
|
||||
g_list_free (chunks);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_rx_packet (GstPluginLoader * l,
|
||||
guint pack_type, guint32 tag, guint8 * payload, guint payload_len)
|
||||
{
|
||||
gboolean res = TRUE;
|
||||
|
||||
switch (pack_type) {
|
||||
case PACKET_EXIT:
|
||||
gst_poll_fd_ctl_read (l->fdset, &l->fd_r, FALSE);
|
||||
if (l->is_child) {
|
||||
/* Respond, then we keep looping until the parent closes the fd */
|
||||
put_packet (l, PACKET_EXIT, 0, NULL, 0);
|
||||
} else {
|
||||
l->rx_done = TRUE; /* All done reading from child */
|
||||
}
|
||||
return TRUE;
|
||||
case PACKET_LOAD_PLUGIN:{
|
||||
|
||||
if (!l->is_child)
|
||||
return TRUE;
|
||||
|
||||
/* Payload is the filename to load */
|
||||
res = do_plugin_load (l, (gchar *) payload, tag);
|
||||
|
||||
break;
|
||||
}
|
||||
case PACKET_STARTING_LOAD:
|
||||
GST_LOG_OBJECT (l->registry,
|
||||
"child started loading plugin w/ tag %u", tag);
|
||||
break;
|
||||
case PACKET_PLUGIN_DETAILS:{
|
||||
gchar *tmp = (gchar *) payload;
|
||||
|
||||
GST_DEBUG_OBJECT (l->registry,
|
||||
"child loaded plugin w/ tag %u. %d bytes info", tag, payload_len);
|
||||
|
||||
if (payload_len > 0) {
|
||||
GstPlugin *newplugin;
|
||||
_priv_gst_registry_chunks_load_plugin (l->registry, &tmp,
|
||||
tmp + payload_len, &newplugin);
|
||||
newplugin->flags &= ~GST_PLUGIN_FLAG_CACHED;
|
||||
GST_LOG_OBJECT (l->registry,
|
||||
"marking plugin %p as registered as %s", newplugin,
|
||||
newplugin->filename);
|
||||
newplugin->registered = TRUE;
|
||||
|
||||
/* We got a set of plugin details - remember it for later */
|
||||
l->got_plugin_details = TRUE;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return FALSE; /* Invalid packet -> something is wrong */
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
read_one (GstPluginLoader * l)
|
||||
{
|
||||
guint32 to_read, packet_len, tag;
|
||||
guint8 *in;
|
||||
gint res;
|
||||
|
||||
to_read = HEADER_SIZE;
|
||||
in = l->rx_buf;
|
||||
do {
|
||||
res = read (l->fd_r.fd, in, to_read);
|
||||
if (res > 0) {
|
||||
to_read -= res;
|
||||
in += res;
|
||||
}
|
||||
} while (to_read > 0 && res < 0 && (errno == EAGAIN || errno == EINTR));
|
||||
|
||||
if (res < 0) {
|
||||
GST_LOG ("Failed reading packet header");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
packet_len = GST_READ_UINT32_BE (l->rx_buf + 4);
|
||||
|
||||
if (packet_len + HEADER_SIZE >= l->rx_buf_size) {
|
||||
l->rx_buf_size = packet_len + HEADER_SIZE + BUF_GROW_EXTRA;
|
||||
l->rx_buf = g_realloc (l->rx_buf, l->rx_buf_size);
|
||||
}
|
||||
|
||||
in = l->rx_buf + HEADER_SIZE;
|
||||
to_read = packet_len;
|
||||
do {
|
||||
res = read (l->fd_r.fd, in, to_read);
|
||||
if (res > 0) {
|
||||
to_read -= res;
|
||||
in += res;
|
||||
}
|
||||
} while (to_read > 0 && res < 0 && (errno == EAGAIN || errno == EINTR));
|
||||
|
||||
if (res < 0) {
|
||||
GST_ERROR ("Packet payload read failed");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
tag = GST_READ_UINT24_BE (l->rx_buf + 1);
|
||||
|
||||
return handle_rx_packet (l, l->rx_buf[0], tag,
|
||||
l->rx_buf + HEADER_SIZE, packet_len);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
exchange_packets (GstPluginLoader * l)
|
||||
{
|
||||
gint res;
|
||||
|
||||
/* Wait for activity on our FDs */
|
||||
do {
|
||||
do {
|
||||
res = gst_poll_wait (l->fdset, GST_CLOCK_TIME_NONE);
|
||||
} while (res == -1 && (errno == EINTR || errno == EAGAIN));
|
||||
|
||||
if (res < 0)
|
||||
return FALSE;
|
||||
|
||||
GST_DEBUG ("Poll res = %d. %d bytes pending for write", res,
|
||||
l->tx_buf_write - l->tx_buf_read);
|
||||
|
||||
if (!l->rx_done) {
|
||||
if (gst_poll_fd_has_error (l->fdset, &l->fd_r) ||
|
||||
gst_poll_fd_has_closed (l->fdset, &l->fd_r)) {
|
||||
GST_LOG ("read fd %d closed/errored", l->fd_r.fd);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (gst_poll_fd_can_read (l->fdset, &l->fd_r)) {
|
||||
if (!read_one (l))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (l->tx_buf_read < l->tx_buf_write) {
|
||||
if (gst_poll_fd_has_error (l->fdset, &l->fd_w) ||
|
||||
gst_poll_fd_has_closed (l->fdset, &l->fd_r)) {
|
||||
GST_ERROR ("write fd %d closed/errored", l->fd_w.fd);
|
||||
return FALSE;
|
||||
}
|
||||
if (gst_poll_fd_can_write (l->fdset, &l->fd_w)) {
|
||||
if (!write_one (l))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
} while (l->tx_buf_read < l->tx_buf_write);
|
||||
|
||||
return TRUE;
|
||||
}
|
38
gst/gstpluginloader.h
Normal file
38
gst/gstpluginloader.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2008 Jan Schmidt <jan.schmidt@sun.com>
|
||||
*
|
||||
* gstpluginloader.h: Helper for out-of-process plugin loading. Private header.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef __GST_PLUGINLOADER_H__
|
||||
#define __GST_PLUGINLOADER_H__
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GstPluginLoader GstPluginLoader;
|
||||
|
||||
typedef struct _GstPluginLoaderFuncs {
|
||||
GstPluginLoader * (*create)(GstRegistry *registry);
|
||||
gboolean (*destroy)(GstPluginLoader *loader);
|
||||
gboolean (*load)(GstPluginLoader *loader, const gchar *filename);
|
||||
} GstPluginLoaderFuncs;
|
||||
|
||||
extern const GstPluginLoaderFuncs _priv_gst_plugin_loader_funcs;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_PLUGINLOADER_H__ */
|
|
@ -113,6 +113,8 @@
|
|||
#include "gstmarshal.h"
|
||||
#include "gstfilter.h"
|
||||
|
||||
#include "gstpluginloader.h"
|
||||
|
||||
#include "gst-i18n-lib.h"
|
||||
|
||||
#define GST_CAT_DEFAULT GST_CAT_REGISTRY
|
||||
|
@ -138,6 +140,9 @@ extern GSList *_priv_gst_preload_plugins;
|
|||
/*set to TRUE when registry needn't to be updated */
|
||||
gboolean _priv_gst_disable_registry_update = FALSE;
|
||||
extern GList *_priv_gst_plugin_paths;
|
||||
|
||||
/* Set to TRUE when the registry cache should be disabled */
|
||||
gboolean _gst_disable_registry_cache = FALSE;
|
||||
#endif
|
||||
|
||||
/* Element signals and args */
|
||||
|
@ -819,15 +824,109 @@ gst_registry_lookup (GstRegistry * registry, const char *filename)
|
|||
return plugin;
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
REGISTRY_SCAN_HELPER_NOT_STARTED = 0,
|
||||
REGISTRY_SCAN_HELPER_DISABLED,
|
||||
REGISTRY_SCAN_HELPER_RUNNING
|
||||
} GstRegistryScanHelperState;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GstRegistry *registry;
|
||||
GstRegistryScanHelperState helper_state;
|
||||
GstPluginLoader *helper;
|
||||
gboolean changed;
|
||||
} GstRegistryScanContext;
|
||||
|
||||
static void
|
||||
init_scan_context (GstRegistryScanContext * context, GstRegistry * registry)
|
||||
{
|
||||
gboolean do_fork;
|
||||
|
||||
context->registry = registry;
|
||||
|
||||
/* see if forking is enabled and set up the scan helper state accordingly */
|
||||
do_fork = _gst_enable_registry_fork;
|
||||
if (do_fork) {
|
||||
const gchar *fork_env;
|
||||
|
||||
/* forking enabled, see if it is disabled with an env var */
|
||||
if ((fork_env = g_getenv ("GST_REGISTRY_FORK"))) {
|
||||
/* fork enabled for any value different from "no" */
|
||||
do_fork = strcmp (fork_env, "no") != 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (do_fork)
|
||||
context->helper_state = REGISTRY_SCAN_HELPER_NOT_STARTED;
|
||||
else
|
||||
context->helper_state = REGISTRY_SCAN_HELPER_DISABLED;
|
||||
|
||||
context->helper = NULL;
|
||||
context->changed = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
clear_scan_context (GstRegistryScanContext * context)
|
||||
{
|
||||
if (context->helper) {
|
||||
context->changed |= _priv_gst_plugin_loader_funcs.destroy (context->helper);
|
||||
context->helper = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_registry_scan_path_level (GstRegistry * registry, const gchar * path,
|
||||
int level)
|
||||
gst_registry_scan_plugin_file (GstRegistryScanContext * context,
|
||||
const gchar * filename)
|
||||
{
|
||||
gboolean changed = FALSE;
|
||||
GstPlugin *newplugin = NULL;
|
||||
|
||||
/* Have a plugin to load - see if the scan-helper needs starting */
|
||||
if (context->helper_state == REGISTRY_SCAN_HELPER_NOT_STARTED) {
|
||||
GST_DEBUG ("Starting plugin scanner for file %s", filename);
|
||||
context->helper = _priv_gst_plugin_loader_funcs.create (context->registry);
|
||||
if (context->helper != NULL)
|
||||
context->helper_state = REGISTRY_SCAN_HELPER_RUNNING;
|
||||
else
|
||||
context->helper_state = REGISTRY_SCAN_HELPER_DISABLED;
|
||||
}
|
||||
|
||||
if (context->helper_state == REGISTRY_SCAN_HELPER_RUNNING) {
|
||||
GST_DEBUG ("Using scan-helper to load plugin %s", filename);
|
||||
if (!_priv_gst_plugin_loader_funcs.load (context->helper, filename)) {
|
||||
g_warning ("External plugin loader failed...");
|
||||
context->helper_state = REGISTRY_SCAN_HELPER_DISABLED;
|
||||
}
|
||||
} else {
|
||||
/* Load plugin the old fashioned way... */
|
||||
|
||||
/* We don't use a GError here because a failure to load some shared
|
||||
* objects as plugins is normal (particularly in the uninstalled case)
|
||||
*/
|
||||
newplugin = gst_plugin_load_file (filename, NULL);
|
||||
}
|
||||
|
||||
if (newplugin) {
|
||||
GST_DEBUG_OBJECT (context->registry, "marking new plugin %p as registered",
|
||||
newplugin);
|
||||
newplugin->registered = TRUE;
|
||||
gst_object_unref (newplugin);
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_registry_scan_path_level (GstRegistryScanContext * context,
|
||||
const gchar * path, int level)
|
||||
{
|
||||
GDir *dir;
|
||||
const gchar *dirent;
|
||||
gchar *filename;
|
||||
GstPlugin *plugin;
|
||||
GstPlugin *newplugin;
|
||||
gboolean changed = FALSE;
|
||||
|
||||
dir = g_dir_open (path, 0, NULL);
|
||||
|
@ -849,7 +948,7 @@ gst_registry_scan_path_level (GstRegistry * registry, const gchar * path,
|
|||
/* skip the .debug directory, these contain elf files that are not
|
||||
* useful or worse, can crash dlopen () */
|
||||
if (g_str_equal (dirent, ".debug") || g_str_equal (dirent, ".git")) {
|
||||
GST_LOG_OBJECT (registry, "ignoring .debug or .git directory");
|
||||
GST_LOG_OBJECT (context->registry, "ignoring .debug or .git directory");
|
||||
g_free (filename);
|
||||
continue;
|
||||
}
|
||||
|
@ -857,17 +956,19 @@ gst_registry_scan_path_level (GstRegistry * registry, const gchar * path,
|
|||
* is inconsistent with other PATH environment variables
|
||||
*/
|
||||
if (level > 0) {
|
||||
GST_LOG_OBJECT (registry, "recursing into directory %s", filename);
|
||||
changed |= gst_registry_scan_path_level (registry, filename, level - 1);
|
||||
GST_LOG_OBJECT (context->registry, "recursing into directory %s",
|
||||
filename);
|
||||
changed |= gst_registry_scan_path_level (context, filename, level - 1);
|
||||
} else {
|
||||
GST_LOG_OBJECT (registry, "not recursing into directory %s, "
|
||||
GST_LOG_OBJECT (context->registry, "not recursing into directory %s, "
|
||||
"recursion level too deep", filename);
|
||||
}
|
||||
g_free (filename);
|
||||
continue;
|
||||
}
|
||||
if (!(file_status.st_mode & S_IFREG)) {
|
||||
GST_LOG_OBJECT (registry, "%s is not a regular file, ignoring", filename);
|
||||
GST_LOG_OBJECT (context->registry, "%s is not a regular file, ignoring",
|
||||
filename);
|
||||
g_free (filename);
|
||||
continue;
|
||||
}
|
||||
|
@ -876,22 +977,24 @@ gst_registry_scan_path_level (GstRegistry * registry, const gchar * path,
|
|||
&& !g_str_has_suffix (dirent, GST_EXTRA_MODULE_SUFFIX)
|
||||
#endif
|
||||
) {
|
||||
GST_LOG_OBJECT (registry, "extension is not recognized as module file, "
|
||||
"ignoring file %s", filename);
|
||||
GST_LOG_OBJECT (context->registry,
|
||||
"extension is not recognized as module file, ignoring file %s",
|
||||
filename);
|
||||
g_free (filename);
|
||||
continue;
|
||||
}
|
||||
|
||||
GST_LOG_OBJECT (registry, "file %s looks like a possible module", filename);
|
||||
GST_LOG_OBJECT (context->registry, "file %s looks like a possible module",
|
||||
filename);
|
||||
|
||||
/* plug-ins are considered unique by basename; if the given name
|
||||
* was already seen by the registry, we ignore it */
|
||||
plugin = gst_registry_lookup (registry, filename);
|
||||
plugin = gst_registry_lookup (context->registry, filename);
|
||||
if (plugin) {
|
||||
gboolean env_vars_changed, deps_changed = FALSE;
|
||||
|
||||
if (plugin->registered) {
|
||||
GST_DEBUG_OBJECT (registry,
|
||||
GST_DEBUG_OBJECT (context->registry,
|
||||
"plugin already registered from path \"%s\"",
|
||||
GST_STR_NULL (plugin->filename));
|
||||
g_free (filename);
|
||||
|
@ -901,52 +1004,37 @@ gst_registry_scan_path_level (GstRegistry * registry, const gchar * path,
|
|||
|
||||
env_vars_changed = _priv_plugin_deps_env_vars_changed (plugin);
|
||||
|
||||
/* If a file with a certain basename is seen on a different path,
|
||||
* update the plugin to ensure the registry cache will reflect up
|
||||
* to date information */
|
||||
|
||||
if (plugin->file_mtime == file_status.st_mtime &&
|
||||
plugin->file_size == file_status.st_size && !env_vars_changed &&
|
||||
!(deps_changed = _priv_plugin_deps_files_changed (plugin))) {
|
||||
GST_LOG_OBJECT (registry, "file %s cached", filename);
|
||||
!(deps_changed = _priv_plugin_deps_files_changed (plugin)) &&
|
||||
strcmp (plugin->filename, filename) == 0) {
|
||||
GST_LOG_OBJECT (context->registry, "file %s cached", filename);
|
||||
plugin->flags &= ~GST_PLUGIN_FLAG_CACHED;
|
||||
GST_LOG_OBJECT (registry, "marking plugin %p as registered as %s",
|
||||
plugin, filename);
|
||||
GST_LOG_OBJECT (context->registry,
|
||||
"marking plugin %p as registered as %s", plugin, filename);
|
||||
plugin->registered = TRUE;
|
||||
/* Update the file path on which we've seen this cached plugin
|
||||
* to ensure the registry cache will reflect up to date information */
|
||||
if (strcmp (plugin->filename, filename) != 0) {
|
||||
g_free (plugin->filename);
|
||||
plugin->filename = g_strdup (filename);
|
||||
changed = TRUE;
|
||||
}
|
||||
} else {
|
||||
GST_INFO_OBJECT (registry, "cached info for %s is stale", filename);
|
||||
GST_DEBUG_OBJECT (registry, "mtime %ld != %ld or size %"
|
||||
GST_INFO_OBJECT (context->registry, "cached info for %s is stale",
|
||||
filename);
|
||||
GST_DEBUG_OBJECT (context->registry, "mtime %ld != %ld or size %"
|
||||
G_GINT64_FORMAT " != %" G_GINT64_FORMAT " or external dependency "
|
||||
"env_vars changed: %d or external dependencies changed: %d",
|
||||
plugin->file_mtime, file_status.st_mtime,
|
||||
(gint64) plugin->file_size, (gint64) file_status.st_size,
|
||||
env_vars_changed, deps_changed);
|
||||
gst_registry_remove_plugin (gst_registry_get_default (), plugin);
|
||||
/* We don't use a GError here because a failure to load some shared
|
||||
* objects as plugins is normal (particularly in the uninstalled case)
|
||||
*/
|
||||
newplugin = gst_plugin_load_file (filename, NULL);
|
||||
if (newplugin) {
|
||||
GST_DEBUG_OBJECT (registry, "marking new plugin %p as registered",
|
||||
newplugin);
|
||||
newplugin->registered = TRUE;
|
||||
gst_object_unref (newplugin);
|
||||
}
|
||||
changed = TRUE;
|
||||
gst_registry_remove_plugin (context->registry, plugin);
|
||||
changed |= gst_registry_scan_plugin_file (context, filename);
|
||||
}
|
||||
gst_object_unref (plugin);
|
||||
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (registry, "file %s not yet in registry", filename);
|
||||
newplugin = gst_plugin_load_file (filename, NULL);
|
||||
if (newplugin) {
|
||||
newplugin->registered = TRUE;
|
||||
gst_object_unref (newplugin);
|
||||
changed = TRUE;
|
||||
}
|
||||
GST_DEBUG_OBJECT (context->registry, "file %s not yet in registry",
|
||||
filename);
|
||||
changed |= gst_registry_scan_plugin_file (context, filename);
|
||||
}
|
||||
|
||||
g_free (filename);
|
||||
|
@ -957,6 +1045,20 @@ gst_registry_scan_path_level (GstRegistry * registry, const gchar * path,
|
|||
return changed;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_registry_scan_path_internal (GstRegistryScanContext * context,
|
||||
const gchar * path)
|
||||
{
|
||||
gboolean changed;
|
||||
|
||||
GST_DEBUG_OBJECT (context->registry, "scanning path %s", path);
|
||||
changed = gst_registry_scan_path_level (context, path, 10);
|
||||
|
||||
GST_DEBUG_OBJECT (context->registry, "registry changed in path %s: %d", path,
|
||||
changed);
|
||||
return changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_registry_scan_path:
|
||||
* @registry: the registry to add found plugins to
|
||||
|
@ -970,17 +1072,20 @@ gst_registry_scan_path_level (GstRegistry * registry, const gchar * path,
|
|||
gboolean
|
||||
gst_registry_scan_path (GstRegistry * registry, const gchar * path)
|
||||
{
|
||||
gboolean changed;
|
||||
GstRegistryScanContext context;
|
||||
gboolean result;
|
||||
|
||||
g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
|
||||
g_return_val_if_fail (path != NULL, FALSE);
|
||||
|
||||
GST_DEBUG_OBJECT (registry, "scanning path %s", path);
|
||||
changed = gst_registry_scan_path_level (registry, path, 10);
|
||||
init_scan_context (&context, registry);
|
||||
|
||||
GST_DEBUG_OBJECT (registry, "registry changed in path %s: %d", path, changed);
|
||||
result = gst_registry_scan_path_internal (&context, path);
|
||||
|
||||
return changed;
|
||||
clear_scan_context (&context);
|
||||
result |= context.changed;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -1157,8 +1262,12 @@ scan_and_update_registry (GstRegistry * default_registry,
|
|||
const gchar *plugin_path;
|
||||
gboolean changed = FALSE;
|
||||
GList *l;
|
||||
GstRegistryScanContext context;
|
||||
|
||||
GST_INFO ("Validating plugins from registry cache: %s", registry_file);
|
||||
|
||||
init_scan_context (&context, default_registry);
|
||||
|
||||
GST_INFO ("Validating registry cache: %s", registry_file);
|
||||
/* It sounds tempting to just compare the mtime of directories with the mtime
|
||||
* of the registry cache, but it does not work. It would not catch updated
|
||||
* plugins, which might bring more or less features.
|
||||
|
@ -1168,7 +1277,7 @@ scan_and_update_registry (GstRegistry * default_registry,
|
|||
GST_DEBUG ("scanning paths added via --gst-plugin-path");
|
||||
for (l = _priv_gst_plugin_paths; l != NULL; l = l->next) {
|
||||
GST_INFO ("Scanning plugin path: \"%s\"", (gchar *) l->data);
|
||||
changed |= gst_registry_scan_path (default_registry, (gchar *) l->data);
|
||||
changed |= gst_registry_scan_path_internal (&context, (gchar *) l->data);
|
||||
}
|
||||
/* keep plugin_paths around in case a re-scan is forced later on */
|
||||
|
||||
|
@ -1182,7 +1291,7 @@ scan_and_update_registry (GstRegistry * default_registry,
|
|||
GST_DEBUG ("GST_PLUGIN_PATH set to %s", plugin_path);
|
||||
list = g_strsplit (plugin_path, G_SEARCHPATH_SEPARATOR_S, 0);
|
||||
for (i = 0; list[i]; i++) {
|
||||
changed |= gst_registry_scan_path (default_registry, list[i]);
|
||||
changed |= gst_registry_scan_path_internal (&context, list[i]);
|
||||
}
|
||||
g_strfreev (list);
|
||||
} else {
|
||||
|
@ -1203,12 +1312,12 @@ scan_and_update_registry (GstRegistry * default_registry,
|
|||
home_plugins = g_build_filename (g_get_home_dir (),
|
||||
".gstreamer-" GST_MAJORMINOR, "plugins", NULL);
|
||||
GST_DEBUG ("scanning home plugins %s", home_plugins);
|
||||
changed |= gst_registry_scan_path (default_registry, home_plugins);
|
||||
changed |= gst_registry_scan_path_internal (&context, home_plugins);
|
||||
g_free (home_plugins);
|
||||
|
||||
/* add the main (installed) library path */
|
||||
GST_DEBUG ("scanning main plugins %s", PLUGINDIR);
|
||||
changed |= gst_registry_scan_path (default_registry, PLUGINDIR);
|
||||
changed |= gst_registry_scan_path_internal (&context, PLUGINDIR);
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
{
|
||||
|
@ -1222,7 +1331,7 @@ scan_and_update_registry (GstRegistry * default_registry,
|
|||
dir = g_build_filename (base_dir, "lib", "gstreamer-0.10", NULL);
|
||||
GST_DEBUG ("scanning DLL dir %s", dir);
|
||||
|
||||
changed |= gst_registry_scan_path (default_registry, dir);
|
||||
changed |= gst_registry_scan_path_internal (&context, dir);
|
||||
|
||||
g_free (dir);
|
||||
g_free (base_dir);
|
||||
|
@ -1235,11 +1344,14 @@ scan_and_update_registry (GstRegistry * default_registry,
|
|||
GST_DEBUG ("GST_PLUGIN_SYSTEM_PATH set to %s", plugin_path);
|
||||
list = g_strsplit (plugin_path, G_SEARCHPATH_SEPARATOR_S, 0);
|
||||
for (i = 0; list[i]; i++) {
|
||||
changed |= gst_registry_scan_path (default_registry, list[i]);
|
||||
changed |= gst_registry_scan_path_internal (&context, list[i]);
|
||||
}
|
||||
g_strfreev (list);
|
||||
}
|
||||
|
||||
clear_scan_context (&context);
|
||||
changed |= context.changed;
|
||||
|
||||
/* Remove cached plugins so stale info is cleared. */
|
||||
changed |= gst_registry_remove_cache_plugins (default_registry);
|
||||
|
||||
|
@ -1265,131 +1377,14 @@ scan_and_update_registry (GstRegistry * default_registry,
|
|||
return REGISTRY_SCAN_AND_UPDATE_SUCCESS_UPDATED;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ensure_current_registry_nonforking (GstRegistry * default_registry,
|
||||
const gchar * registry_file, GError ** error)
|
||||
{
|
||||
/* fork() not available */
|
||||
GST_DEBUG ("Updating registry cache in-process");
|
||||
scan_and_update_registry (default_registry, registry_file, TRUE, error);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* when forking is not available this function always does nothing but return
|
||||
* TRUE immediatly */
|
||||
static gboolean
|
||||
ensure_current_registry_forking (GstRegistry * default_registry,
|
||||
const gchar * registry_file, GError ** error)
|
||||
{
|
||||
#ifdef HAVE_FORK
|
||||
pid_t pid;
|
||||
int pfd[2];
|
||||
int ret;
|
||||
|
||||
/* We fork here, and let the child read and possibly rebuild the registry.
|
||||
* After that, the parent will re-read the freshly generated registry. */
|
||||
GST_DEBUG ("forking to update registry");
|
||||
|
||||
if (pipe (pfd) == -1) {
|
||||
g_set_error (error, GST_CORE_ERROR, GST_CORE_ERROR_FAILED,
|
||||
_("Error re-scanning registry %s: %s"),
|
||||
", could not create pipes. Error", g_strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pid = fork ();
|
||||
if (pid == -1) {
|
||||
GST_ERROR ("Failed to fork()");
|
||||
g_set_error (error, GST_CORE_ERROR, GST_CORE_ERROR_FAILED,
|
||||
_("Error re-scanning registry %s: %s"),
|
||||
", failed to fork. Error", g_strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
gint result_code;
|
||||
|
||||
/* this is the child. Close the read pipe */
|
||||
(void) close (pfd[0]);
|
||||
|
||||
GST_DEBUG ("child reading registry cache");
|
||||
result_code =
|
||||
scan_and_update_registry (default_registry, registry_file, TRUE, NULL);
|
||||
|
||||
/* need to use _exit, so that any exit handlers registered don't
|
||||
* bring down the main program */
|
||||
GST_DEBUG ("child exiting: %d", result_code);
|
||||
|
||||
/* make valgrind happy (yes, you can call it insane) */
|
||||
g_free ((char *) registry_file);
|
||||
|
||||
/* write a result byte to the pipe */
|
||||
do {
|
||||
ret = write (pfd[1], &result_code, sizeof (result_code));
|
||||
} while (ret == -1 && errno == EINTR);
|
||||
/* if ret == -1 now, we could not write to pipe, probably
|
||||
* means parent has exited before us */
|
||||
(void) close (pfd[1]);
|
||||
|
||||
_exit (0);
|
||||
} else {
|
||||
gint result_code;
|
||||
|
||||
/* parent. Close write pipe */
|
||||
(void) close (pfd[1]);
|
||||
|
||||
/* Wait for result from the pipe */
|
||||
GST_DEBUG ("Waiting for data from child");
|
||||
do {
|
||||
ret = read (pfd[0], &result_code, sizeof (result_code));
|
||||
} while (ret == -1 && errno == EINTR);
|
||||
|
||||
if (ret == -1) {
|
||||
g_set_error (error, GST_CORE_ERROR, GST_CORE_ERROR_FAILED,
|
||||
_("Error re-scanning registry %s: %s"),
|
||||
", read returned error", g_strerror (errno));
|
||||
close (pfd[0]);
|
||||
return FALSE;
|
||||
}
|
||||
(void) close (pfd[0]);
|
||||
|
||||
/* Wait to ensure the child is reaped, but ignore the result */
|
||||
GST_DEBUG ("parent waiting on child");
|
||||
waitpid (pid, NULL, 0);
|
||||
GST_DEBUG ("parent done waiting on child");
|
||||
|
||||
if (ret == 0) {
|
||||
GST_ERROR ("child did not exit normally, terminated by signal");
|
||||
g_set_error (error, GST_CORE_ERROR, GST_CORE_ERROR_FAILED,
|
||||
_("Error re-scanning registry %s"), ", child terminated by signal");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (result_code == REGISTRY_SCAN_AND_UPDATE_SUCCESS_UPDATED) {
|
||||
GST_DEBUG ("Child succeeded. Parent reading registry cache");
|
||||
gst_registry_remove_cache_plugins (default_registry);
|
||||
#ifdef USE_BINARY_REGISTRY
|
||||
gst_registry_binary_read_cache (default_registry, registry_file);
|
||||
#else
|
||||
gst_registry_xml_read_cache (default_registry, registry_file);
|
||||
#endif
|
||||
} else if (result_code == REGISTRY_SCAN_AND_UPDATE_FAILURE) {
|
||||
GST_DEBUG ("Child failed. Parent re-scanning registry, ignoring errors.");
|
||||
scan_and_update_registry (default_registry, registry_file, FALSE, NULL);
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_FORK */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ensure_current_registry (GError ** error)
|
||||
{
|
||||
gchar *registry_file;
|
||||
GstRegistry *default_registry;
|
||||
gboolean ret = TRUE;
|
||||
gboolean do_update;
|
||||
gboolean have_cache;
|
||||
gboolean do_update = TRUE;
|
||||
gboolean have_cache = TRUE;
|
||||
|
||||
default_registry = gst_registry_get_default ();
|
||||
registry_file = g_strdup (g_getenv ("GST_REGISTRY"));
|
||||
|
@ -1398,8 +1393,11 @@ ensure_current_registry (GError ** error)
|
|||
".gstreamer-" GST_MAJORMINOR, "registry." HOST_CPU ".bin", NULL);
|
||||
}
|
||||
|
||||
GST_INFO ("reading registry cache: %s", registry_file);
|
||||
have_cache = gst_registry_binary_read_cache (default_registry, registry_file);
|
||||
if (!_gst_disable_registry_cache) {
|
||||
GST_INFO ("reading registry cache: %s", registry_file);
|
||||
have_cache = gst_registry_binary_read_cache (default_registry,
|
||||
registry_file);
|
||||
}
|
||||
|
||||
if (have_cache) {
|
||||
do_update = !_priv_gst_disable_registry_update;
|
||||
|
@ -1410,8 +1408,6 @@ ensure_current_registry (GError ** error)
|
|||
/* do update for any value different from "no" */
|
||||
do_update = (strcmp (update_env, "no") != 0);
|
||||
}
|
||||
} else {
|
||||
do_update = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#ifndef __GST_REGISTRY_H__
|
||||
#define __GST_REGISTRY_H__
|
||||
|
||||
#include <stdio.h> /* FIXME: because of cache_file below */
|
||||
#include <gst/gstconfig.h>
|
||||
#include <gst/gstplugin.h>
|
||||
#include <gst/gstpluginfeature.h>
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -33,6 +33,8 @@
|
|||
#include <gst/gstpad.h>
|
||||
#include <gst/gstregistry.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* GST_MAGIC_BINARY_REGISTRY_STR:
|
||||
*
|
||||
|
@ -68,117 +70,11 @@ typedef struct _GstBinaryRegistryMagic
|
|||
gchar version[GST_MAGIC_BINARY_VERSION_LEN];
|
||||
} GstBinaryRegistryMagic;
|
||||
|
||||
/*
|
||||
* we reference strings directly from the plugins and in this case set CONST to
|
||||
* avoid freeing them
|
||||
*/
|
||||
enum {
|
||||
GST_BINARY_REGISTRY_FLAG_NONE = 0,
|
||||
GST_BINARY_REGISTRY_FLAG_CONST = 1
|
||||
};
|
||||
|
||||
/*
|
||||
* GstBinaryChunk:
|
||||
*
|
||||
* Header for binary blobs
|
||||
*/
|
||||
typedef struct _GstBinaryChunk
|
||||
{
|
||||
gpointer data;
|
||||
guint size;
|
||||
guint flags;
|
||||
gboolean align;
|
||||
} GstBinaryChunk;
|
||||
|
||||
/*
|
||||
* GstBinaryPluginElement:
|
||||
*
|
||||
* @nfeatures: says how many binary plugin feature structures we will have
|
||||
* right after the structure itself.
|
||||
*
|
||||
* A structure containing (staticely) every information needed for a plugin
|
||||
*/
|
||||
|
||||
typedef struct _GstBinaryPluginElement
|
||||
{
|
||||
gulong file_size;
|
||||
gulong file_mtime;
|
||||
|
||||
guint n_deps;
|
||||
|
||||
guint nfeatures;
|
||||
} GstBinaryPluginElement;
|
||||
|
||||
/* GstBinaryDep:
|
||||
*/
|
||||
typedef struct _GstBinaryDep
|
||||
{
|
||||
guint flags;
|
||||
guint n_env_vars;
|
||||
guint n_paths;
|
||||
guint n_names;
|
||||
|
||||
guint env_hash;
|
||||
guint stat_hash;
|
||||
} GstBinaryDep;
|
||||
|
||||
/*
|
||||
* GstBinaryPluginFeature:
|
||||
* @rank: rank of the feature
|
||||
*
|
||||
* A structure containing the plugin features
|
||||
*/
|
||||
typedef struct _GstBinaryPluginFeature
|
||||
{
|
||||
gulong rank;
|
||||
} GstBinaryPluginFeature;
|
||||
|
||||
/*
|
||||
* GstBinaryElementFactory:
|
||||
* @npadtemplates: stores the number of GstBinaryPadTemplate structures
|
||||
* following the structure
|
||||
* @ninterfaces: stores the number of interface names following the structure
|
||||
* @nuriprotocols: stores the number of protocol strings following the structure
|
||||
*
|
||||
* A structure containing the element factory fields
|
||||
*/
|
||||
typedef struct _GstBinaryElementFactory
|
||||
{
|
||||
GstBinaryPluginFeature plugin_feature;
|
||||
|
||||
guint npadtemplates;
|
||||
guint ninterfaces;
|
||||
guint nuriprotocols;
|
||||
} GstBinaryElementFactory;
|
||||
|
||||
/*
|
||||
* GstBinaryTypeFindFactory:
|
||||
* @nextensions: stores the number of typefind extensions
|
||||
*
|
||||
* A structure containing the element factory fields
|
||||
*/
|
||||
typedef struct _GstBinaryTypeFindFactory
|
||||
{
|
||||
GstBinaryPluginFeature plugin_feature;
|
||||
|
||||
guint nextensions;
|
||||
} GstBinaryTypeFindFactory;
|
||||
|
||||
/*
|
||||
* GstBinaryPadTemplate:
|
||||
*
|
||||
* A structure containing the static pad templates of a plugin feature
|
||||
*/
|
||||
typedef struct _GstBinaryPadTemplate
|
||||
{
|
||||
guint direction; /* Either 0:"sink" or 1:"src" */
|
||||
GstPadPresence presence;
|
||||
} GstBinaryPadTemplate;
|
||||
|
||||
|
||||
/* Function prototypes */
|
||||
gboolean gst_registry_binary_write_cache(GstRegistry *registry, const char *location);
|
||||
gboolean gst_registry_binary_read_cache(GstRegistry *registry, const char *location);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* !__GST_REGISTRYBINARY_H__ */
|
||||
|
||||
|
|
798
gst/gstregistrychunks.c
Normal file
798
gst/gstregistrychunks.c
Normal file
|
@ -0,0 +1,798 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2006 Josep Torra <josep@fluendo.com>
|
||||
* 2006 Mathieu Garcia <matthieu@fluendo.com>
|
||||
* 2006,2007 Stefan Kost <ensonic@users.sf.net>
|
||||
* 2008 Sebastian Dröge <slomo@circular-chaos.org>
|
||||
* 2008 Jan Schmidt <jan.schmidt@sun.com>
|
||||
*
|
||||
* gstregistrychunks.c: GstRegistryChunk helper for serialising/deserialising
|
||||
* plugin entries and features.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <gst/gst_private.h>
|
||||
#include <gst/gstconfig.h>
|
||||
#include <gst/gstelement.h>
|
||||
#include <gst/gsttypefind.h>
|
||||
#include <gst/gsttypefindfactory.h>
|
||||
#include <gst/gsturi.h>
|
||||
#include <gst/gstinfo.h>
|
||||
#include <gst/gstenumtypes.h>
|
||||
#include <gst/gstpadtemplate.h>
|
||||
|
||||
#include <gst/gstregistrychunks.h>
|
||||
|
||||
#define GST_CAT_DEFAULT GST_CAT_REGISTRY
|
||||
|
||||
/* count string length, but return -1 if we hit the eof */
|
||||
static gint
|
||||
_strnlen (const gchar * str, gint maxlen)
|
||||
{
|
||||
gint len = 0;
|
||||
|
||||
if (G_UNLIKELY (len == maxlen))
|
||||
return -1;
|
||||
|
||||
while (*str++ != '\0') {
|
||||
len++;
|
||||
if (G_UNLIKELY (len == maxlen))
|
||||
return -1;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Macros */
|
||||
#define unpack_element(inptr, outptr, element, endptr, error_label) G_STMT_START{ \
|
||||
if (inptr + sizeof(element) >= endptr) \
|
||||
goto error_label; \
|
||||
outptr = (element *) inptr; \
|
||||
inptr += sizeof (element); \
|
||||
}G_STMT_END
|
||||
|
||||
#define unpack_const_string(inptr, outptr, endptr, error_label) G_STMT_START{\
|
||||
gint _len = _strnlen (inptr, (endptr-inptr)); \
|
||||
if (_len == -1) \
|
||||
goto error_label; \
|
||||
outptr = g_intern_string ((const gchar *)inptr); \
|
||||
inptr += _len + 1; \
|
||||
}G_STMT_END
|
||||
|
||||
#define unpack_string(inptr, outptr, endptr, error_label) G_STMT_START{\
|
||||
gint _len = _strnlen (inptr, (endptr-inptr)); \
|
||||
if (_len == -1) \
|
||||
goto error_label; \
|
||||
outptr = g_memdup ((gconstpointer)inptr, _len + 1); \
|
||||
inptr += _len + 1; \
|
||||
}G_STMT_END
|
||||
|
||||
#define ALIGNMENT (sizeof (void *))
|
||||
#define alignment(_address) (gsize)_address%ALIGNMENT
|
||||
#define align(_ptr) _ptr += (( alignment(_ptr) == 0) ? 0 : ALIGNMENT-alignment(_ptr))
|
||||
|
||||
/*
|
||||
* gst_registry_chunks_save_const_string:
|
||||
*
|
||||
* Store a const string in a binary chunk.
|
||||
*
|
||||
* Returns: %TRUE for success
|
||||
*/
|
||||
inline static gboolean
|
||||
gst_registry_chunks_save_const_string (GList ** list, const gchar * str)
|
||||
{
|
||||
GstRegistryChunk *chunk;
|
||||
|
||||
if (G_UNLIKELY (str == NULL)) {
|
||||
GST_ERROR ("unexpected NULL string in plugin or plugin feature data");
|
||||
str = "";
|
||||
}
|
||||
|
||||
chunk = g_malloc (sizeof (GstRegistryChunk));
|
||||
chunk->data = (gpointer) str;
|
||||
chunk->size = strlen ((gchar *) chunk->data) + 1;
|
||||
chunk->flags = GST_REGISTRY_CHUNK_FLAG_CONST;
|
||||
chunk->align = FALSE;
|
||||
*list = g_list_prepend (*list, chunk);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* gst_registry_chunks_save_string:
|
||||
*
|
||||
* Store a string in a binary chunk.
|
||||
*
|
||||
* Returns: %TRUE for success
|
||||
*/
|
||||
inline static gboolean
|
||||
gst_registry_chunks_save_string (GList ** list, gchar * str)
|
||||
{
|
||||
GstRegistryChunk *chunk;
|
||||
|
||||
chunk = g_malloc (sizeof (GstRegistryChunk));
|
||||
chunk->data = str;
|
||||
chunk->size = strlen ((gchar *) chunk->data) + 1;
|
||||
chunk->flags = GST_REGISTRY_CHUNK_FLAG_NONE;
|
||||
chunk->align = FALSE;
|
||||
*list = g_list_prepend (*list, chunk);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* gst_registry_chunks_save_data:
|
||||
*
|
||||
* Store some data in a binary chunk.
|
||||
*
|
||||
* Returns: the initialized chunk
|
||||
*/
|
||||
inline static GstRegistryChunk *
|
||||
gst_registry_chunks_make_data (gpointer data, gulong size)
|
||||
{
|
||||
GstRegistryChunk *chunk;
|
||||
|
||||
chunk = g_malloc (sizeof (GstRegistryChunk));
|
||||
chunk->data = data;
|
||||
chunk->size = size;
|
||||
chunk->flags = GST_REGISTRY_CHUNK_FLAG_NONE;
|
||||
chunk->align = TRUE;
|
||||
return chunk;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* gst_registry_chunks_save_pad_template:
|
||||
*
|
||||
* Store pad_templates in binary chunks.
|
||||
*
|
||||
* Returns: %TRUE for success
|
||||
*/
|
||||
static gboolean
|
||||
gst_registry_chunks_save_pad_template (GList ** list,
|
||||
GstStaticPadTemplate * template)
|
||||
{
|
||||
GstRegistryChunkPadTemplate *pt;
|
||||
GstRegistryChunk *chk;
|
||||
|
||||
pt = g_malloc0 (sizeof (GstRegistryChunkPadTemplate));
|
||||
chk =
|
||||
gst_registry_chunks_make_data (pt, sizeof (GstRegistryChunkPadTemplate));
|
||||
|
||||
pt->presence = template->presence;
|
||||
pt->direction = template->direction;
|
||||
|
||||
/* pack pad template strings */
|
||||
gst_registry_chunks_save_const_string (list,
|
||||
(gchar *) (template->static_caps.string));
|
||||
gst_registry_chunks_save_const_string (list, template->name_template);
|
||||
|
||||
*list = g_list_prepend (*list, chk);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* gst_registry_chunks_save_feature:
|
||||
*
|
||||
* Store features in binary chunks.
|
||||
*
|
||||
* Returns: %TRUE for success
|
||||
*/
|
||||
static gboolean
|
||||
gst_registry_chunks_save_feature (GList ** list, GstPluginFeature * feature)
|
||||
{
|
||||
const gchar *type_name = g_type_name (G_OBJECT_TYPE (feature));
|
||||
GstRegistryChunkPluginFeature *pf = NULL;
|
||||
GstRegistryChunk *chk = NULL;
|
||||
GList *walk;
|
||||
|
||||
if (!type_name) {
|
||||
GST_ERROR ("NULL feature type_name, aborting.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (GST_IS_ELEMENT_FACTORY (feature)) {
|
||||
GstRegistryChunkElementFactory *ef;
|
||||
GstElementFactory *factory = GST_ELEMENT_FACTORY (feature);
|
||||
|
||||
ef = g_malloc0 (sizeof (GstRegistryChunkElementFactory));
|
||||
chk =
|
||||
gst_registry_chunks_make_data (ef,
|
||||
sizeof (GstRegistryChunkElementFactory));
|
||||
ef->npadtemplates = ef->ninterfaces = ef->nuriprotocols = 0;
|
||||
pf = (GstRegistryChunkPluginFeature *) ef;
|
||||
|
||||
/* save interfaces */
|
||||
for (walk = factory->interfaces; walk;
|
||||
walk = g_list_next (walk), ef->ninterfaces++) {
|
||||
gst_registry_chunks_save_const_string (list, (gchar *) walk->data);
|
||||
}
|
||||
GST_DEBUG ("Saved %d Interfaces", ef->ninterfaces);
|
||||
/* save uritypes */
|
||||
if (GST_URI_TYPE_IS_VALID (factory->uri_type)) {
|
||||
if (factory->uri_protocols && *factory->uri_protocols) {
|
||||
GstRegistryChunk *subchk;
|
||||
gchar **protocol;
|
||||
|
||||
subchk =
|
||||
gst_registry_chunks_make_data (&factory->uri_type,
|
||||
sizeof (factory->uri_type));
|
||||
subchk->flags = GST_REGISTRY_CHUNK_FLAG_CONST;
|
||||
|
||||
protocol = factory->uri_protocols;
|
||||
while (*protocol) {
|
||||
gst_registry_chunks_save_const_string (list, *protocol++);
|
||||
ef->nuriprotocols++;
|
||||
}
|
||||
*list = g_list_prepend (*list, subchk);
|
||||
GST_DEBUG ("Saved %d UriTypes", ef->nuriprotocols);
|
||||
} else {
|
||||
g_warning ("GStreamer feature '%s' is URI handler but does not provide"
|
||||
" any protocols it can handle", feature->name);
|
||||
}
|
||||
}
|
||||
|
||||
/* save pad-templates */
|
||||
for (walk = factory->staticpadtemplates; walk;
|
||||
walk = g_list_next (walk), ef->npadtemplates++) {
|
||||
GstStaticPadTemplate *template = walk->data;
|
||||
|
||||
if (!gst_registry_chunks_save_pad_template (list, template)) {
|
||||
GST_ERROR ("Can't fill pad template, aborting.");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* pack element factory strings */
|
||||
gst_registry_chunks_save_const_string (list, factory->details.author);
|
||||
gst_registry_chunks_save_const_string (list, factory->details.description);
|
||||
gst_registry_chunks_save_const_string (list, factory->details.klass);
|
||||
gst_registry_chunks_save_const_string (list, factory->details.longname);
|
||||
} else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
|
||||
GstRegistryChunkTypeFindFactory *tff;
|
||||
GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (feature);
|
||||
gchar *str;
|
||||
|
||||
tff = g_malloc0 (sizeof (GstRegistryChunkTypeFindFactory));
|
||||
chk =
|
||||
gst_registry_chunks_make_data (tff,
|
||||
sizeof (GstRegistryChunkTypeFindFactory));
|
||||
tff->nextensions = 0;
|
||||
pf = (GstRegistryChunkPluginFeature *) tff;
|
||||
|
||||
/* save extensions */
|
||||
if (factory->extensions) {
|
||||
while (factory->extensions[tff->nextensions]) {
|
||||
gst_registry_chunks_save_const_string (list,
|
||||
factory->extensions[tff->nextensions++]);
|
||||
}
|
||||
}
|
||||
/* save caps */
|
||||
if (factory->caps) {
|
||||
/* we copy the caps here so we can simplify them before saving. This
|
||||
* is a lot faster when loading them later on */
|
||||
GstCaps *copy = gst_caps_copy (factory->caps);
|
||||
|
||||
gst_caps_do_simplify (copy);
|
||||
str = gst_caps_to_string (copy);
|
||||
gst_caps_unref (copy);
|
||||
gst_registry_chunks_save_string (list, str);
|
||||
} else {
|
||||
gst_registry_chunks_save_const_string (list, "");
|
||||
}
|
||||
} else if (GST_IS_INDEX_FACTORY (feature)) {
|
||||
GstIndexFactory *factory = GST_INDEX_FACTORY (feature);
|
||||
|
||||
pf = g_malloc0 (sizeof (GstRegistryChunkPluginFeature));
|
||||
chk =
|
||||
gst_registry_chunks_make_data (pf,
|
||||
sizeof (GstRegistryChunkPluginFeature));
|
||||
pf->rank = feature->rank;
|
||||
|
||||
/* pack element factory strings */
|
||||
gst_registry_chunks_save_const_string (list, factory->longdesc);
|
||||
} else {
|
||||
GST_WARNING ("unhandled feature type '%s'", type_name);
|
||||
}
|
||||
|
||||
if (pf) {
|
||||
pf->rank = feature->rank;
|
||||
*list = g_list_prepend (*list, chk);
|
||||
|
||||
/* pack plugin feature strings */
|
||||
gst_registry_chunks_save_const_string (list, feature->name);
|
||||
gst_registry_chunks_save_const_string (list, (gchar *) type_name);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Errors */
|
||||
fail:
|
||||
g_free (chk);
|
||||
g_free (pf);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_registry_chunks_save_plugin_dep (GList ** list, GstPluginDep * dep)
|
||||
{
|
||||
GstRegistryChunkDep *ed;
|
||||
GstRegistryChunk *chk;
|
||||
gchar **s;
|
||||
|
||||
ed = g_new0 (GstRegistryChunkDep, 1);
|
||||
chk = gst_registry_chunks_make_data (ed, sizeof (GstRegistryChunkDep));
|
||||
|
||||
ed->flags = dep->flags;
|
||||
ed->n_env_vars = 0;
|
||||
ed->n_paths = 0;
|
||||
ed->n_names = 0;
|
||||
|
||||
ed->env_hash = dep->env_hash;
|
||||
ed->stat_hash = dep->stat_hash;
|
||||
|
||||
for (s = dep->env_vars; s != NULL && *s != NULL; ++s, ++ed->n_env_vars)
|
||||
gst_registry_chunks_save_string (list, g_strdup (*s));
|
||||
|
||||
for (s = dep->paths; s != NULL && *s != NULL; ++s, ++ed->n_paths)
|
||||
gst_registry_chunks_save_string (list, g_strdup (*s));
|
||||
|
||||
for (s = dep->names; s != NULL && *s != NULL; ++s, ++ed->n_names)
|
||||
gst_registry_chunks_save_string (list, g_strdup (*s));
|
||||
|
||||
*list = g_list_prepend (*list, chk);
|
||||
|
||||
GST_LOG ("Saved external plugin dependency");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* _priv_gst_registry_chunks_save_plugin:
|
||||
*
|
||||
* Adapt a GstPlugin to our GstRegistryChunkPluginElement structure, and
|
||||
* prepend it as a GstRegistryChunk in the provided list.
|
||||
*
|
||||
*/
|
||||
gboolean
|
||||
_priv_gst_registry_chunks_save_plugin (GList ** list, GstRegistry * registry,
|
||||
GstPlugin * plugin)
|
||||
{
|
||||
GstRegistryChunkPluginElement *pe;
|
||||
GstRegistryChunk *chk;
|
||||
GList *plugin_features = NULL;
|
||||
GList *walk;
|
||||
|
||||
pe = g_malloc0 (sizeof (GstRegistryChunkPluginElement));
|
||||
chk =
|
||||
gst_registry_chunks_make_data (pe,
|
||||
sizeof (GstRegistryChunkPluginElement));
|
||||
|
||||
pe->file_size = plugin->file_size;
|
||||
pe->file_mtime = plugin->file_mtime;
|
||||
pe->nfeatures = 0;
|
||||
pe->n_deps = 0;
|
||||
|
||||
/* pack external deps */
|
||||
for (walk = plugin->priv->deps; walk != NULL; walk = walk->next) {
|
||||
if (!gst_registry_chunks_save_plugin_dep (list, walk->data)) {
|
||||
GST_ERROR ("Could not save external plugin dependency, aborting.");
|
||||
goto fail;
|
||||
}
|
||||
++pe->n_deps;
|
||||
}
|
||||
|
||||
/* pack plugin features */
|
||||
plugin_features =
|
||||
gst_registry_get_feature_list_by_plugin (registry, plugin->desc.name);
|
||||
for (walk = plugin_features; walk; walk = g_list_next (walk), pe->nfeatures++) {
|
||||
GstPluginFeature *feature = GST_PLUGIN_FEATURE (walk->data);
|
||||
|
||||
if (!gst_registry_chunks_save_feature (list, feature)) {
|
||||
GST_ERROR ("Can't fill plugin feature, aborting.");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
gst_plugin_feature_list_free (plugin_features);
|
||||
|
||||
/* pack cache data */
|
||||
if (plugin->priv->cache_data) {
|
||||
gchar *cache_str = gst_structure_to_string (plugin->priv->cache_data);
|
||||
gst_registry_chunks_save_string (list, cache_str);
|
||||
} else {
|
||||
gst_registry_chunks_save_const_string (list, "");
|
||||
}
|
||||
|
||||
/* pack plugin element strings */
|
||||
gst_registry_chunks_save_const_string (list, plugin->desc.origin);
|
||||
gst_registry_chunks_save_const_string (list, plugin->desc.package);
|
||||
gst_registry_chunks_save_const_string (list, plugin->desc.source);
|
||||
gst_registry_chunks_save_const_string (list, plugin->desc.license);
|
||||
gst_registry_chunks_save_const_string (list, plugin->desc.version);
|
||||
gst_registry_chunks_save_const_string (list, plugin->filename);
|
||||
gst_registry_chunks_save_const_string (list, plugin->desc.description);
|
||||
gst_registry_chunks_save_const_string (list, plugin->desc.name);
|
||||
|
||||
*list = g_list_prepend (*list, chk);
|
||||
|
||||
GST_DEBUG ("Found %d features in plugin \"%s\"", pe->nfeatures,
|
||||
plugin->desc.name);
|
||||
return TRUE;
|
||||
|
||||
/* Errors */
|
||||
fail:
|
||||
gst_plugin_feature_list_free (plugin_features);
|
||||
g_free (chk);
|
||||
g_free (pe);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* gst_registry_chunks_load_pad_template:
|
||||
*
|
||||
* Make a new GstStaticPadTemplate from current GstRegistryChunkPadTemplate
|
||||
* structure.
|
||||
*
|
||||
* Returns: new GstStaticPadTemplate
|
||||
*/
|
||||
static gboolean
|
||||
gst_registry_chunks_load_pad_template (GstElementFactory * factory, gchar ** in,
|
||||
gchar * end)
|
||||
{
|
||||
GstRegistryChunkPadTemplate *pt;
|
||||
GstStaticPadTemplate *template = NULL;
|
||||
|
||||
align (*in);
|
||||
GST_DEBUG ("Reading/casting for GstRegistryChunkPadTemplate at address %p",
|
||||
*in);
|
||||
unpack_element (*in, pt, GstRegistryChunkPadTemplate, end, fail);
|
||||
|
||||
template = g_new0 (GstStaticPadTemplate, 1);
|
||||
template->presence = pt->presence;
|
||||
template->direction = pt->direction;
|
||||
|
||||
/* unpack pad template strings */
|
||||
unpack_const_string (*in, template->name_template, end, fail);
|
||||
unpack_string (*in, template->static_caps.string, end, fail);
|
||||
|
||||
__gst_element_factory_add_static_pad_template (factory, template);
|
||||
GST_DEBUG ("Added pad_template %s", template->name_template);
|
||||
|
||||
return TRUE;
|
||||
fail:
|
||||
GST_INFO ("Reading pad template failed");
|
||||
g_free (template);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* gst_registry_chunks_load_feature:
|
||||
*
|
||||
* Make a new GstPluginFeature from current binary plugin feature structure
|
||||
*
|
||||
* Returns: new GstPluginFeature
|
||||
*/
|
||||
static gboolean
|
||||
gst_registry_chunks_load_feature (GstRegistry * registry, gchar ** in,
|
||||
gchar * end, const gchar * plugin_name)
|
||||
{
|
||||
GstRegistryChunkPluginFeature *pf = NULL;
|
||||
GstPluginFeature *feature = NULL;
|
||||
gchar *type_name = NULL, *str;
|
||||
GType type;
|
||||
guint i;
|
||||
|
||||
/* unpack plugin feature strings */
|
||||
unpack_string (*in, type_name, end, fail);
|
||||
|
||||
if (G_UNLIKELY (!type_name)) {
|
||||
GST_ERROR ("No feature type name");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GST_DEBUG ("Plugin '%s' feature typename : '%s'", plugin_name, type_name);
|
||||
|
||||
if (G_UNLIKELY (!(type = g_type_from_name (type_name)))) {
|
||||
GST_ERROR ("Unknown type from typename '%s' for plugin '%s'", type_name,
|
||||
plugin_name);
|
||||
g_free (type_name);
|
||||
return FALSE;
|
||||
}
|
||||
if (G_UNLIKELY ((feature = g_object_new (type, NULL)) == NULL)) {
|
||||
GST_ERROR ("Can't create feature from type");
|
||||
g_free (type_name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (!GST_IS_PLUGIN_FEATURE (feature))) {
|
||||
GST_ERROR ("typename : '%s' is not a plugin feature", type_name);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* unpack more plugin feature strings */
|
||||
unpack_string (*in, feature->name, end, fail);
|
||||
|
||||
if (GST_IS_ELEMENT_FACTORY (feature)) {
|
||||
GstRegistryChunkElementFactory *ef;
|
||||
guint n;
|
||||
GstElementFactory *factory = GST_ELEMENT_FACTORY_CAST (feature);
|
||||
|
||||
align (*in);
|
||||
GST_LOG ("Reading/casting for GstRegistryChunkElementFactory at address %p",
|
||||
*in);
|
||||
unpack_element (*in, ef, GstRegistryChunkElementFactory, end, fail);
|
||||
pf = (GstRegistryChunkPluginFeature *) ef;
|
||||
|
||||
/* unpack element factory strings */
|
||||
unpack_string (*in, factory->details.longname, end, fail);
|
||||
unpack_string (*in, factory->details.klass, end, fail);
|
||||
unpack_string (*in, factory->details.description, end, fail);
|
||||
unpack_string (*in, factory->details.author, end, fail);
|
||||
n = ef->npadtemplates;
|
||||
GST_DEBUG ("Element factory : '%s' with npadtemplates=%d",
|
||||
factory->details.longname, n);
|
||||
|
||||
/* load pad templates */
|
||||
for (i = 0; i < n; i++) {
|
||||
if (G_UNLIKELY (!gst_registry_chunks_load_pad_template (factory, in,
|
||||
end))) {
|
||||
GST_ERROR ("Error while loading binary pad template");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* load uritypes */
|
||||
if (G_UNLIKELY ((n = ef->nuriprotocols))) {
|
||||
GST_DEBUG ("Reading %d UriTypes at address %p", n, *in);
|
||||
|
||||
align (*in);
|
||||
factory->uri_type = *((guint *) * in);
|
||||
*in += sizeof (factory->uri_type);
|
||||
/*unpack_element(*in, &factory->uri_type, factory->uri_type, end, fail); */
|
||||
|
||||
factory->uri_protocols = g_new0 (gchar *, n + 1);
|
||||
for (i = 0; i < n; i++) {
|
||||
unpack_string (*in, str, end, fail);
|
||||
factory->uri_protocols[i] = str;
|
||||
}
|
||||
}
|
||||
/* load interfaces */
|
||||
if (G_UNLIKELY ((n = ef->ninterfaces))) {
|
||||
GST_DEBUG ("Reading %d Interfaces at address %p", n, *in);
|
||||
for (i = 0; i < n; i++) {
|
||||
unpack_string (*in, str, end, fail);
|
||||
__gst_element_factory_add_interface (factory, str);
|
||||
g_free (str);
|
||||
}
|
||||
}
|
||||
} else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
|
||||
GstRegistryChunkTypeFindFactory *tff;
|
||||
GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (feature);
|
||||
|
||||
align (*in);
|
||||
GST_DEBUG
|
||||
("Reading/casting for GstRegistryChunkPluginFeature at address %p",
|
||||
*in);
|
||||
unpack_element (*in, tff, GstRegistryChunkTypeFindFactory, end, fail);
|
||||
pf = (GstRegistryChunkPluginFeature *) tff;
|
||||
|
||||
/* load caps */
|
||||
unpack_string (*in, str, end, fail);
|
||||
factory->caps = (str && *str) ? gst_caps_from_string (str) : NULL;
|
||||
g_free (str);
|
||||
/* load extensions */
|
||||
if (tff->nextensions) {
|
||||
GST_DEBUG ("Reading %d Typefind extensions at address %p",
|
||||
tff->nextensions, *in);
|
||||
factory->extensions = g_new0 (gchar *, tff->nextensions + 1);
|
||||
for (i = 0; i < tff->nextensions; i++) {
|
||||
unpack_string (*in, str, end, fail);
|
||||
factory->extensions[i] = str;
|
||||
}
|
||||
}
|
||||
} else if (GST_IS_INDEX_FACTORY (feature)) {
|
||||
GstIndexFactory *factory = GST_INDEX_FACTORY (feature);
|
||||
|
||||
align (*in);
|
||||
GST_DEBUG
|
||||
("Reading/casting for GstRegistryChunkPluginFeature at address %p",
|
||||
*in);
|
||||
unpack_element (*in, pf, GstRegistryChunkPluginFeature, end, fail);
|
||||
|
||||
/* unpack index factory strings */
|
||||
unpack_string (*in, factory->longdesc, end, fail);
|
||||
} else {
|
||||
GST_WARNING ("unhandled factory type : %s", G_OBJECT_TYPE_NAME (feature));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
feature->rank = pf->rank;
|
||||
|
||||
/* should already be the interned string, but better make sure */
|
||||
feature->plugin_name = g_intern_string (plugin_name);
|
||||
|
||||
gst_registry_add_feature (registry, feature);
|
||||
GST_DEBUG ("Added feature %s", feature->name);
|
||||
|
||||
g_free (type_name);
|
||||
return TRUE;
|
||||
|
||||
/* Errors */
|
||||
fail:
|
||||
GST_INFO ("Reading plugin feature failed");
|
||||
g_free (type_name);
|
||||
if (feature) {
|
||||
if (GST_IS_OBJECT (feature))
|
||||
gst_object_unref (feature);
|
||||
else
|
||||
g_object_unref (feature);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gchar **
|
||||
gst_registry_chunks_load_plugin_dep_strv (gchar ** in, gchar * end, guint n)
|
||||
{
|
||||
gchar **arr;
|
||||
|
||||
if (n == 0)
|
||||
return NULL;
|
||||
|
||||
arr = g_new0 (gchar *, n + 1);
|
||||
while (n > 0) {
|
||||
unpack_string (*in, arr[n - 1], end, fail);
|
||||
--n;
|
||||
}
|
||||
return arr;
|
||||
fail:
|
||||
GST_INFO ("Reading plugin dependency strings failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_registry_chunks_load_plugin_dep (GstPlugin * plugin, gchar ** in,
|
||||
gchar * end)
|
||||
{
|
||||
GstPluginDep *dep;
|
||||
GstRegistryChunkDep *d;
|
||||
gchar **s;
|
||||
|
||||
align (*in);
|
||||
GST_LOG_OBJECT (plugin, "Unpacking GstRegistryChunkDep from %p", *in);
|
||||
unpack_element (*in, d, GstRegistryChunkDep, end, fail);
|
||||
|
||||
dep = g_new0 (GstPluginDep, 1);
|
||||
|
||||
dep->env_hash = d->env_hash;
|
||||
dep->stat_hash = d->stat_hash;
|
||||
|
||||
dep->flags = d->flags;
|
||||
|
||||
dep->names = gst_registry_chunks_load_plugin_dep_strv (in, end, d->n_names);
|
||||
dep->paths = gst_registry_chunks_load_plugin_dep_strv (in, end, d->n_paths);
|
||||
dep->env_vars =
|
||||
gst_registry_chunks_load_plugin_dep_strv (in, end, d->n_env_vars);
|
||||
|
||||
plugin->priv->deps = g_list_append (plugin->priv->deps, dep);
|
||||
|
||||
GST_DEBUG_OBJECT (plugin, "Loaded external plugin dependency from registry: "
|
||||
"env_hash: %08x, stat_hash: %08x", dep->env_hash, dep->stat_hash);
|
||||
for (s = dep->env_vars; s != NULL && *s != NULL; ++s)
|
||||
GST_LOG_OBJECT (plugin, " evar: %s", *s);
|
||||
for (s = dep->paths; s != NULL && *s != NULL; ++s)
|
||||
GST_LOG_OBJECT (plugin, " path: %s", *s);
|
||||
for (s = dep->names; s != NULL && *s != NULL; ++s)
|
||||
GST_LOG_OBJECT (plugin, " name: %s", *s);
|
||||
|
||||
return TRUE;
|
||||
fail:
|
||||
GST_INFO ("Reading plugin dependency failed");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* _priv_gst_registry_chunks_load_plugin:
|
||||
*
|
||||
* Make a new GstPlugin from current GstRegistryChunkPluginElement structure
|
||||
* and add it to the GstRegistry. Return an offset to the next
|
||||
* GstRegistryChunkPluginElement structure.
|
||||
*/
|
||||
gboolean
|
||||
_priv_gst_registry_chunks_load_plugin (GstRegistry * registry, gchar ** in,
|
||||
gchar * end, GstPlugin ** out_plugin)
|
||||
{
|
||||
GstRegistryChunkPluginElement *pe;
|
||||
GstPlugin *plugin = NULL;
|
||||
gchar *cache_str = NULL;
|
||||
guint i, n;
|
||||
|
||||
align (*in);
|
||||
GST_LOG ("Reading/casting for GstRegistryChunkPluginElement at address %p",
|
||||
*in);
|
||||
unpack_element (*in, pe, GstRegistryChunkPluginElement, end, fail);
|
||||
|
||||
plugin = g_object_new (GST_TYPE_PLUGIN, NULL);
|
||||
|
||||
/* TODO: also set GST_PLUGIN_FLAG_CONST */
|
||||
plugin->flags |= GST_PLUGIN_FLAG_CACHED;
|
||||
plugin->file_mtime = pe->file_mtime;
|
||||
plugin->file_size = pe->file_size;
|
||||
|
||||
/* unpack plugin element strings */
|
||||
unpack_const_string (*in, plugin->desc.name, end, fail);
|
||||
unpack_string (*in, plugin->desc.description, end, fail);
|
||||
unpack_string (*in, plugin->filename, end, fail);
|
||||
unpack_const_string (*in, plugin->desc.version, end, fail);
|
||||
unpack_const_string (*in, plugin->desc.license, end, fail);
|
||||
unpack_const_string (*in, plugin->desc.source, end, fail);
|
||||
unpack_const_string (*in, plugin->desc.package, end, fail);
|
||||
unpack_const_string (*in, plugin->desc.origin, end, fail);
|
||||
GST_LOG ("read strings for name='%s'", plugin->desc.name);
|
||||
GST_LOG (" desc.description='%s'", plugin->desc.description);
|
||||
GST_LOG (" filename='%s'", plugin->filename);
|
||||
GST_LOG (" desc.version='%s'", plugin->desc.version);
|
||||
GST_LOG (" desc.license='%s'", plugin->desc.license);
|
||||
GST_LOG (" desc.source='%s'", plugin->desc.source);
|
||||
GST_LOG (" desc.package='%s'", plugin->desc.package);
|
||||
GST_LOG (" desc.origin='%s'", plugin->desc.origin);
|
||||
|
||||
/* unpack cache data */
|
||||
unpack_string (*in, cache_str, end, fail);
|
||||
if (*cache_str) {
|
||||
plugin->priv->cache_data = gst_structure_from_string (cache_str, NULL);
|
||||
}
|
||||
g_free (cache_str);
|
||||
|
||||
plugin->basename = g_path_get_basename (plugin->filename);
|
||||
|
||||
/* Takes ownership of plugin */
|
||||
gst_registry_add_plugin (registry, plugin);
|
||||
n = pe->nfeatures;
|
||||
GST_DEBUG ("Added plugin '%s' plugin with %d features from binary registry",
|
||||
plugin->desc.name, n);
|
||||
|
||||
/* Load plugin features */
|
||||
for (i = 0; i < n; i++) {
|
||||
if (G_UNLIKELY (!gst_registry_chunks_load_feature (registry, in, end,
|
||||
plugin->desc.name))) {
|
||||
GST_ERROR ("Error while loading binary feature");
|
||||
gst_registry_remove_plugin (registry, plugin);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Load external plugin dependencies */
|
||||
for (i = 0; i < pe->n_deps; ++i) {
|
||||
if (G_UNLIKELY (!gst_registry_chunks_load_plugin_dep (plugin, in, end))) {
|
||||
GST_ERROR_OBJECT (plugin, "Could not read external plugin dependency");
|
||||
gst_registry_remove_plugin (registry, plugin);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (out_plugin)
|
||||
*out_plugin = plugin;
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* Errors */
|
||||
fail:
|
||||
GST_INFO ("Reading plugin failed");
|
||||
return FALSE;
|
||||
}
|
150
gst/gstregistrychunks.h
Normal file
150
gst/gstregistrychunks.h
Normal file
|
@ -0,0 +1,150 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2006 Josep Torra <josep@fluendo.com>
|
||||
* Copyright (C) 2006 Mathieu Garcia <matthieu@fluendo.com>
|
||||
* Copyright (C) 2006 Stefan Kost <ensonic@sonicpulse.de>
|
||||
*
|
||||
* gstregistrybinary.h: Header for registry handling
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef __GST_REGISTRYCHUNKS_H__
|
||||
#define __GST_REGISTRYCHUNKS_H__
|
||||
|
||||
#include <gst/gstpad.h>
|
||||
#include <gst/gstregistry.h>
|
||||
|
||||
/*
|
||||
* we reference strings directly from the plugins and in this case set CONST to
|
||||
* avoid freeing them
|
||||
*/
|
||||
enum {
|
||||
GST_REGISTRY_CHUNK_FLAG_NONE = 0,
|
||||
GST_REGISTRY_CHUNK_FLAG_CONST = 1
|
||||
};
|
||||
|
||||
/*
|
||||
* GstRegistryChunk:
|
||||
*
|
||||
* Header for binary blobs
|
||||
*/
|
||||
typedef struct _GstRegistryChunk
|
||||
{
|
||||
gpointer data;
|
||||
guint size;
|
||||
guint flags;
|
||||
gboolean align;
|
||||
} GstRegistryChunk;
|
||||
|
||||
/*
|
||||
* GstRegistryChunkPluginElement:
|
||||
*
|
||||
* @n_deps: Says how many dependency structures follows.
|
||||
*
|
||||
* @nfeatures: says how many binary plugin feature structures we will have
|
||||
* right after the structure itself.
|
||||
*
|
||||
* A structure containing (staticely) every information needed for a plugin
|
||||
*/
|
||||
|
||||
typedef struct _GstRegistryChunkPluginElement
|
||||
{
|
||||
gulong file_size;
|
||||
gulong file_mtime;
|
||||
|
||||
guint n_deps;
|
||||
|
||||
guint nfeatures;
|
||||
} GstRegistryChunkPluginElement;
|
||||
|
||||
/* GstRegistryChunkDep:
|
||||
*/
|
||||
typedef struct _GstRegistryChunkDep
|
||||
{
|
||||
guint flags;
|
||||
guint n_env_vars;
|
||||
guint n_paths;
|
||||
guint n_names;
|
||||
|
||||
guint env_hash;
|
||||
guint stat_hash;
|
||||
} GstRegistryChunkDep;
|
||||
|
||||
/*
|
||||
* GstRegistryChunkPluginFeature:
|
||||
* @rank: rank of the feature
|
||||
*
|
||||
* A structure containing the plugin features
|
||||
*/
|
||||
typedef struct _GstRegistryChunkPluginFeature
|
||||
{
|
||||
gulong rank;
|
||||
} GstRegistryChunkPluginFeature;
|
||||
|
||||
/*
|
||||
* GstRegistryChunkElementFactory:
|
||||
* @npadtemplates: stores the number of GstRegistryChunkPadTemplate structures
|
||||
* following the structure
|
||||
* @ninterfaces: stores the number of interface names following the structure
|
||||
* @nuriprotocols: stores the number of protocol strings following the structure
|
||||
*
|
||||
* A structure containing the element factory fields
|
||||
*/
|
||||
typedef struct _GstRegistryChunkElementFactory
|
||||
{
|
||||
GstRegistryChunkPluginFeature plugin_feature;
|
||||
|
||||
guint npadtemplates;
|
||||
guint ninterfaces;
|
||||
guint nuriprotocols;
|
||||
} GstRegistryChunkElementFactory;
|
||||
|
||||
/*
|
||||
* GstRegistryChunkTypeFindFactory:
|
||||
* @nextensions: stores the number of typefind extensions
|
||||
*
|
||||
* A structure containing the element factory fields
|
||||
*/
|
||||
typedef struct _GstRegistryChunkTypeFindFactory
|
||||
{
|
||||
GstRegistryChunkPluginFeature plugin_feature;
|
||||
|
||||
guint nextensions;
|
||||
} GstRegistryChunkTypeFindFactory;
|
||||
|
||||
/*
|
||||
* GstRegistryChunkPadTemplate:
|
||||
*
|
||||
* A structure containing the static pad templates of a plugin feature
|
||||
*/
|
||||
typedef struct _GstRegistryChunkPadTemplate
|
||||
{
|
||||
guint direction; /* Either 0:"sink" or 1:"src" */
|
||||
GstPadPresence presence;
|
||||
} GstRegistryChunkPadTemplate;
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
gboolean
|
||||
_priv_gst_registry_chunks_save_plugin (GList ** list, GstRegistry * registry,
|
||||
GstPlugin * plugin);
|
||||
|
||||
gboolean
|
||||
_priv_gst_registry_chunks_load_plugin (GstRegistry * registry, gchar ** in,
|
||||
gchar *end, GstPlugin **out_plugin);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_REGISTRYCHUNKS_H__ */
|
|
@ -18,7 +18,13 @@ endif
|
|||
endif
|
||||
endif
|
||||
|
||||
if GST_DISABLE_REGISTRY
|
||||
SUBDIRS_HELPERS =
|
||||
else
|
||||
SUBDIRS_HELPERS = helpers
|
||||
endif
|
||||
|
||||
SUBDIRS_ALWAYS = base controller dataprotocol
|
||||
|
||||
SUBDIRS = $(SUBDIRS_ALWAYS) $(SUBDIRS_CHECK) $(SUBDIRS_NET)
|
||||
DIST_SUBDIRS = $(SUBDIRS_ALWAYS) check net
|
||||
SUBDIRS = $(SUBDIRS_ALWAYS) $(SUBDIRS_CHECK) $(SUBDIRS_NET) $(SUBDIRS_HELPERS)
|
||||
DIST_SUBDIRS = $(SUBDIRS_ALWAYS) check net helpers
|
||||
|
|
2
libs/gst/helpers/.gitignore
vendored
Normal file
2
libs/gst/helpers/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
plugin-scanner
|
||||
*.o
|
7
libs/gst/helpers/Makefile.am
Normal file
7
libs/gst/helpers/Makefile.am
Normal file
|
@ -0,0 +1,7 @@
|
|||
# helpers_PROGRAMS = plugin-scanner
|
||||
# FIXME: Subst helpersdir in configure.ac
|
||||
noinst_PROGRAMS = plugin-scanner
|
||||
|
||||
plugin_scanner_SOURCES = plugin-scanner.c
|
||||
plugin_scanner_CFLAGS = $(GST_OBJ_CFLAGS)
|
||||
plugin_scanner_LDFLAGS = $(GST_OBJ_LIBS)
|
67
libs/gst/helpers/plugin-scanner.c
Normal file
67
libs/gst/helpers/plugin-scanner.c
Normal file
|
@ -0,0 +1,67 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2008 Jan Schmidt <jan.schmidt@sun.com>
|
||||
*
|
||||
* plugin-scanner.c: tool to load plugins out of process for scanning
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Helper binary that does plugin-loading out of process and feeds results
|
||||
* back to the parent over fds.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/gst_private.h>
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
gboolean res;
|
||||
char **my_argv;
|
||||
int my_argc;
|
||||
|
||||
if (argc != 2 || strcmp (argv[1], "-l"))
|
||||
return 1;
|
||||
|
||||
if (!g_thread_supported ())
|
||||
g_thread_init (NULL);
|
||||
|
||||
my_argc = 2;
|
||||
my_argv = g_malloc (my_argc * sizeof (char *));
|
||||
my_argv[0] = argv[0];
|
||||
my_argv[1] = "--gst-disable-registry-update";
|
||||
|
||||
#ifndef GST_DISABLE_REGISTRY
|
||||
_gst_disable_registry_cache = TRUE;
|
||||
#endif
|
||||
|
||||
res = gst_init_check (&my_argc, &my_argv, NULL);
|
||||
|
||||
g_free (my_argv);
|
||||
if (!res)
|
||||
return 1;
|
||||
|
||||
/* Create registry scanner listener and run */
|
||||
if (!_gst_plugin_loader_client_run ())
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -34,6 +34,11 @@ plugin_name_cmp (GstPlugin * a, GstPlugin * b)
|
|||
return strcmp (name_a, name_b);
|
||||
}
|
||||
|
||||
static gint
|
||||
plugin_ptr_cmp (GstPlugin * a, GstPlugin * b)
|
||||
{
|
||||
return (a == b) ? 0 : 1;
|
||||
}
|
||||
|
||||
static void
|
||||
print_plugin (const gchar * marker, GstRegistry * registry, GstPlugin * plugin)
|
||||
|
@ -43,8 +48,9 @@ print_plugin (const gchar * marker, GstRegistry * registry, GstPlugin * plugin)
|
|||
|
||||
name = gst_plugin_get_name (plugin);
|
||||
|
||||
GST_DEBUG ("%s: plugin %p %d %s", marker, plugin,
|
||||
GST_OBJECT_REFCOUNT (plugin), name);
|
||||
GST_DEBUG ("%s: plugin %p %d %s file: %s", marker, plugin,
|
||||
GST_OBJECT_REFCOUNT (plugin), name,
|
||||
GST_STR_NULL (gst_plugin_get_filename (plugin)));
|
||||
|
||||
features = gst_registry_get_feature_list_by_plugin (registry, name);
|
||||
for (f = features; f != NULL; f = f->next) {
|
||||
|
@ -100,9 +106,9 @@ GST_START_TEST (test_registry_update)
|
|||
GST_LOG (" -----------------------------------");
|
||||
|
||||
/* static plugins should have the same refcount as before (ie. 2), whereas
|
||||
* file-based plugins should have been replaced by a newly-created objects
|
||||
* (when reading the updated registry.xml file), so there should be only one
|
||||
* reference left for those, and that's ours */
|
||||
* file-based plugins *may* have been replaced by a newly-created object
|
||||
* if the on-disk file changed (and was not yet loaded). There should be
|
||||
* only one reference left for those, and that's ours */
|
||||
for (l = plugins_before; l; l = l->next) {
|
||||
GstPlugin *plugin;
|
||||
|
||||
|
@ -111,8 +117,8 @@ GST_START_TEST (test_registry_update)
|
|||
print_plugin ("before2", registry, plugin);
|
||||
|
||||
if (gst_plugin_get_filename (plugin)) {
|
||||
/* file-based plugin */
|
||||
ASSERT_OBJECT_REFCOUNT (plugin, "plugin", 1);
|
||||
/* file-based plugin. */
|
||||
ASSERT_OBJECT_REFCOUNT_BETWEEN (plugin, "plugin", 1, 2);
|
||||
} else {
|
||||
/* static plugin */
|
||||
ASSERT_OBJECT_REFCOUNT (plugin, "plugin", 2);
|
||||
|
@ -123,20 +129,27 @@ GST_START_TEST (test_registry_update)
|
|||
|
||||
plugins_after = gst_registry_get_plugin_list (registry);
|
||||
for (l = plugins_after; l; l = l->next) {
|
||||
GstPlugin *plugin;
|
||||
|
||||
plugin = GST_PLUGIN (l->data);
|
||||
GstPlugin *plugin = GST_PLUGIN (l->data);
|
||||
|
||||
print_plugin ("after ", registry, plugin);
|
||||
|
||||
/* file-based plugins should have a refcount of 2 (one for the registry,
|
||||
* one for us for the list), static plugins should have one of 3 (one for
|
||||
* the registry, one for the new list and one for the old list).
|
||||
* one for us for the list) or 3 (one for the registry, one for the before
|
||||
* list, one for the after list), static plugins should have one of 3
|
||||
* (one for the registry, one for the new list and one for the old list).
|
||||
* This implicitly also makes sure that all static plugins are the same
|
||||
* objects as they were before and that all non-static ones have been
|
||||
* objects as they were before. Non-static ones may or may not have been
|
||||
* replaced by new objects */
|
||||
if (gst_plugin_get_filename (plugin)) {
|
||||
ASSERT_OBJECT_REFCOUNT (plugin, "plugin", 2);
|
||||
if (g_list_find_custom (plugins_before, plugin,
|
||||
(GCompareFunc) plugin_ptr_cmp) != NULL) {
|
||||
/* Same plugin existed in the before list. Refcount must be 3 */
|
||||
ASSERT_OBJECT_REFCOUNT (plugin, "plugin", 3);
|
||||
} else {
|
||||
/* This plugin is newly created, so should only exist in the after list
|
||||
* and the registry: Refcount must be 2 */
|
||||
ASSERT_OBJECT_REFCOUNT (plugin, "plugin", 2);
|
||||
}
|
||||
} else {
|
||||
ASSERT_OBJECT_REFCOUNT (plugin, "plugin", 3);
|
||||
}
|
||||
|
@ -165,15 +178,19 @@ GST_START_TEST (test_registry_update)
|
|||
|
||||
new_identity = gst_registry_lookup_feature (registry, "identity");
|
||||
fail_unless (new_identity != NULL, "Can't find plugin feature 'identity'");
|
||||
#if 0
|
||||
fail_unless (old_identity != new_identity, "Old and new 'identity' feature "
|
||||
"should be different but are the same object");
|
||||
|
||||
ASSERT_OBJECT_REFCOUNT (old_identity, "old identity feature after update", 1);
|
||||
#endif
|
||||
|
||||
new_pipeline = gst_registry_lookup_feature (registry, "pipeline");
|
||||
fail_unless (new_pipeline != NULL, "Can't find plugin feature 'pipeline'");
|
||||
#if 0
|
||||
fail_unless (old_pipeline == new_pipeline, "Old and new 'pipeline' feature "
|
||||
"objects should be the same, but are different objects");
|
||||
#endif
|
||||
|
||||
gst_plugin_list_free (plugins_before);
|
||||
plugins_before = NULL;
|
||||
|
|
|
@ -42,8 +42,10 @@ EXPORTS
|
|||
_gst_debug_get_category
|
||||
_gst_debug_nameof_funcptr
|
||||
_gst_debug_register_funcptr
|
||||
_gst_disable_registry_cache DATA
|
||||
_gst_element_error_printf
|
||||
_gst_elementclass_factory DATA
|
||||
_gst_plugin_loader_client_run
|
||||
_gst_plugin_register_static
|
||||
_gst_trace_add_entry
|
||||
_gst_trace_mutex DATA
|
||||
|
|
Loading…
Reference in a new issue