Merge branch 'master' into 0.11

Conflicts:
	gst/gstregistry.h
This commit is contained in:
Wim Taymans 2011-03-02 11:08:34 +01:00
commit 230c3455ac
21 changed files with 527 additions and 22 deletions

2
common

@ -1 +1 @@
Subproject commit 1de7f6ab2d4bc1af69f06079cf0f4e2cbbfdc178
Subproject commit 6aec6b9716c184c60c4bc6a5916a2471cfa8c8cd

View file

@ -723,7 +723,7 @@ AC_SUBST(GST_OBJ_LIBS)
dnl GST_PLUGIN_LDFLAGS
dnl LDFLAGS for plugins; includes GST_ALL_LDFLAGS
GST_PLUGIN_LDFLAGS="-module -avoid-version -export-symbols-regex '^[_]*gst_plugin_desc\$\$' $GST_ALL_LDFLAGS"
GST_PLUGIN_LDFLAGS="-module -avoid-version -export-symbols-regex '^[_]*gst_plugin_desc.*' $GST_ALL_LDFLAGS"
AC_SUBST(GST_PLUGIN_LDFLAGS, "$GST_PLUGIN_LDFLAGS")
dnl plugin scanner locations

View file

@ -76,8 +76,8 @@ you will then have to provide them with:
<listitem><para>your e-mail address</para></listitem>
<listitem><para>a copy of your public sshv2 identity.
If you do not have this yet, you can generate it by running
"ssh-keygen -t dsa". The resulting public key
will be in <filename>.ssh/id_dsa.pub</filename></para></listitem>
"ssh-keygen -t rsa -f ~/.ssh/id_rsa.pub-fdo". The resulting public key
will be in <filename>~/.ssh/id_rsa.pub-fdo</filename></para></listitem>
<listitem><para>your GPG fingerprint. This would allow you to
add and remove ssh keys to your account.
</para></listitem>

View file

@ -2551,6 +2551,7 @@ gst_uri_has_protocol
gst_uri_get_protocol
gst_uri_get_location
gst_uri_construct
gst_filename_to_uri
gst_element_make_from_uri
gst_uri_handler_get_uri_type
gst_uri_handler_get_protocols

View file

@ -243,8 +243,9 @@ plugins frequently, it will save time when doing gst_init().
Useful Orc environment variable. Set ORC_CODE=debug to enable debuggers
such as gdb to create useful backtraces from Orc-generated code. Set
ORC_CODE=backup or ORC_CODE=emulate if you suspect Orc's SIMD code
generator is producing incorrect code. (Quite a few important
generator is producing incorrect code (Quite a few important
GStreamer plugins like videotestsrc, audioconvert or audioresample use Orc).
One can also combine flags like ORC_CODE=backup,debug.
</para>
</formalpara>

View file

@ -1,6 +1,7 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
* Copyright (C) 2011 Tim-Philipp Müller <tim centricular net>
*
* gsturi.c: register URI handlers
*
@ -782,3 +783,115 @@ gst_uri_handler_new_uri (GstURIHandler * handler, const gchar * uri)
g_signal_emit (handler, gst_uri_handler_signals[NEW_URI], 0, uri);
}
static gchar *
gst_file_utils_canonicalise_path (const gchar * path)
{
gchar **parts, **p, *clean_path;
#ifdef G_OS_WIN32
{
GST_WARNING ("FIXME: canonicalise win32 path");
return g_strdup (path);
}
#endif
parts = g_strsplit (path, "/", -1);
p = parts;
while (*p != NULL) {
if (strcmp (*p, ".") == 0) {
/* just move all following parts on top of this, incl. NUL terminator */
g_free (*p);
g_memmove (p, p + 1, (g_strv_length (p + 1) + 1) * sizeof (gchar *));
/* re-check the new current part again in the next iteration */
continue;
} else if (strcmp (*p, "..") == 0 && p > parts) {
/* just move all following parts on top of the previous part, incl.
* NUL terminator */
g_free (*(p - 1));
g_free (*p);
g_memmove (p - 1, p + 1, (g_strv_length (p + 1) + 1) * sizeof (gchar *));
/* re-check the new current part again in the next iteration */
--p;
continue;
}
++p;
}
if (*path == '/') {
guint num_parts;
num_parts = g_strv_length (parts) + 1; /* incl. terminator */
parts = g_renew (gchar *, parts, num_parts + 1);
g_memmove (parts + 1, parts, num_parts * sizeof (gchar *));
parts[0] = g_strdup ("/");
}
clean_path = g_build_filenamev (parts);
g_strfreev (parts);
return clean_path;
}
static gboolean
file_path_contains_relatives (const gchar * path)
{
return (strstr (path, "/./") != NULL || strstr (path, "/../") != NULL ||
strstr (path, G_DIR_SEPARATOR_S "." G_DIR_SEPARATOR_S) != NULL ||
strstr (path, G_DIR_SEPARATOR_S ".." G_DIR_SEPARATOR_S) != NULL);
}
/**
* gst_filename_to_uri:
* @filename: absolute or relative file name path
* @error: pointer to error, or NULL
*
* Similar to g_filename_to_uri(), but attempts to handle relative file paths
* as well. Before converting @filename into an URI, it will be prefixed by
* the current working directory if it is a relative path, and then the path
* will be canonicalised so that it doesn't contain any './' or '../' segments.
*
* On Windows #filename should be in UTF-8 encoding.
*
* Since: 0.10.33
*/
gchar *
gst_filename_to_uri (const gchar * filename, GError ** error)
{
gchar *abs_location = NULL;
gchar *uri, *abs_clean;
g_return_val_if_fail (filename != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
if (g_path_is_absolute (filename)) {
if (!file_path_contains_relatives (filename)) {
uri = g_filename_to_uri (filename, NULL, error);
goto beach;
}
abs_location = g_strdup (filename);
} else {
gchar *cwd;
cwd = g_get_current_dir ();
abs_location = g_build_filename (cwd, filename, NULL);
g_free (cwd);
if (!file_path_contains_relatives (abs_location)) {
uri = g_filename_to_uri (abs_location, NULL, error);
goto beach;
}
}
/* path is now absolute, but contains '.' or '..' */
abs_clean = gst_file_utils_canonicalise_path (abs_location);
GST_LOG ("'%s' -> '%s' -> '%s'", filename, abs_location, abs_clean);
uri = g_filename_to_uri (abs_clean, NULL, error);
g_free (abs_clean);
beach:
g_free (abs_location);
GST_DEBUG ("'%s' -> '%s'", filename, uri);
return uri;
}

View file

@ -133,6 +133,9 @@ gchar * gst_uri_get_location (const gchar * uri);
gchar * gst_uri_construct (const gchar * protocol,
const gchar * location);
gchar * gst_filename_to_uri (const gchar * filename,
GError ** error);
GstElement * gst_element_make_from_uri (const GstURIType type,
const gchar * uri,
const gchar * elementname);

View file

@ -1554,6 +1554,8 @@ pad_link_maybe_ghosting (GstPad * src, GstPad * sink, GstPadLinkCheck flags)
* is the same as calling gst_element_link_pads() and the recommended way of
* linking pads with safety checks applied.
*
* This is a convenience function for gst_pad_link_full().
*
* Returns: TRUE if the pads could be linked, FALSE otherwise.
*
* Since: 0.10.30
@ -2012,6 +2014,8 @@ gst_element_link_filtered (GstElement * src, GstElement * dest,
* @destpadname: the name of the #GstPad in destination element.
*
* Unlinks the two named pads of the source and destination elements.
*
* This is a convenience function for gst_pad_unlink().
*/
void
gst_element_unlink_pads (GstElement * src, const gchar * srcpadname,
@ -2162,7 +2166,8 @@ gst_element_unlink (GstElement * src, GstElement * dest)
* @cur: (out) (allow-none): a location in which to store the current
* position, or NULL.
*
* Queries an element for the stream position.
* Queries an element for the stream position. If one repeatedly calls this
* function one can also create and reuse it in gst_element_query().
*
* Returns: TRUE if the query could be performed.
*/

View file

@ -22,7 +22,7 @@
/**
* SECTION:gstcontrollergobject
* @short_description: #GObject convinience methods for using dynamic properties
* @short_description: #GObject convenience methods for using dynamic properties
* @see_also: #GstController
*
* These methods allow to use some #GstController functionallity directly from

View file

@ -302,7 +302,9 @@ gst_file_sink_set_location (GstFileSink * sink, const gchar * location)
/* we store the filename as we received it from the application. On Windows
* this should be in UTF8 */
sink->filename = g_strdup (location);
sink->uri = g_filename_to_uri (sink->filename, NULL, NULL);
sink->uri = gst_filename_to_uri (location, NULL);
GST_INFO ("filename : %s", sink->filename);
GST_INFO ("uri : %s", sink->uri);
} else {
sink->filename = NULL;
sink->uri = NULL;

View file

@ -367,10 +367,12 @@ gst_file_src_set_location (GstFileSrc * src, const gchar * location)
src->filename = NULL;
src->uri = NULL;
} else {
/* we store the filename as received by the application. On Windoes this
/* we store the filename as received by the application. On Windows this
* should be UTF8 */
src->filename = g_strdup (location);
src->uri = g_filename_to_uri (src->filename, NULL, NULL);
src->uri = gst_filename_to_uri (location, NULL);
GST_INFO ("filename : %s", src->filename);
GST_INFO ("uri : %s", src->uri);
}
g_object_notify (G_OBJECT (src), "location");
gst_uri_handler_new_uri (GST_URI_HANDLER (src), src->uri);

View file

@ -146,12 +146,14 @@ TESTS = $(check_PROGRAMS)
noinst_HEADERS = \
gst/capslist.h \
gst/struct_arm.h \
gst/struct_i386.h \
gst/struct_hppa.h \
gst/struct_ppc32.h \
gst/struct_ppc64.h \
gst/struct_sparc.h \
gst/struct_x86_64.h \
libs/struct_arm.h \
libs/struct_i386.h \
libs/struct_hppa.h \
libs/struct_ppc32.h \

View file

@ -384,6 +384,67 @@ GST_START_TEST (test_uri_interface)
GST_END_TEST;
static void
check_uri_for_location (GstElement * e, const gchar * location,
const gchar * uri)
{
GstQuery *query;
gchar *query_uri = NULL;
g_object_set (e, "location", location, NULL);
query = gst_query_new_uri ();
fail_unless (gst_element_query (e, query));
gst_query_parse_uri (query, &query_uri);
gst_query_unref (query);
if (uri != NULL) {
fail_unless_equals_string (query_uri, uri);
} else {
gchar *fn;
fail_unless (gst_uri_is_valid (query_uri));
fn = g_filename_from_uri (query_uri, NULL, NULL);
fail_unless (g_path_is_absolute (fn));
fail_unless (fn != NULL);
g_free (fn);
}
g_free (query_uri);
}
GST_START_TEST (test_uri_query)
{
GstElement *src;
src = setup_filesrc ();
#ifdef G_OS_UNIX
{
GST_INFO ("*nix");
check_uri_for_location (src, "/i/do/not/exist", "file:///i/do/not/exist");
check_uri_for_location (src, "/i/do/not/../exist", "file:///i/do/exist");
check_uri_for_location (src, "/i/do/not/.././exist", "file:///i/do/exist");
check_uri_for_location (src, "/i/./do/not/../exist", "file:///i/do/exist");
check_uri_for_location (src, "/i/do/./not/../exist", "file:///i/do/exist");
check_uri_for_location (src, "/i/do/not/./../exist", "file:///i/do/exist");
check_uri_for_location (src, "/i/./do/./././././exist",
"file:///i/do/exist");
check_uri_for_location (src, "/i/do/not/../../exist", "file:///i/exist");
check_uri_for_location (src, "/i/../not/../exist", "file:///exist");
/* hard to test relative URIs, just make sure it returns an URI of sorts */
check_uri_for_location (src, "foo", NULL);
check_uri_for_location (src, "foo/../bar", NULL);
check_uri_for_location (src, "./foo", NULL);
check_uri_for_location (src, "../foo", NULL);
check_uri_for_location (src, "foo/./bar", NULL);
}
#endif
cleanup_filesrc (src);
}
GST_END_TEST;
static Suite *
filesrc_suite (void)
{
@ -396,6 +457,7 @@ filesrc_suite (void)
tcase_add_test (tc_chain, test_pull);
tcase_add_test (tc_chain, test_coverage);
tcase_add_test (tc_chain, test_uri_interface);
tcase_add_test (tc_chain, test_uri_query);
return s;
}

View file

@ -46,6 +46,10 @@
#include "struct_sparc.h"
#define HAVE_ABI_SIZES TRUE
#else
#ifdef HAVE_CPU_ARM
#include "struct_arm.h"
#define HAVE_ABI_SIZES TRUE
#else
/* in case someone wants to generate a new arch */
#include "struct_i386.h"
#define HAVE_ABI_SIZES FALSE
@ -55,6 +59,7 @@
#endif
#endif
#endif
#endif
GST_START_TEST (test_ABI)
{

View file

@ -0,0 +1,73 @@
GstCheckABIStruct list[] = {
{"GstBin", sizeof (GstBin), 192},
{"GstBinClass", sizeof (GstBinClass), 288},
{"GstBuffer", sizeof (GstBuffer), 88},
{"GstBufferClass", sizeof (GstBufferClass), 16},
{"GstBus", sizeof (GstBus), 80},
{"GstBusClass", sizeof (GstBusClass), 144},
{"GstCaps", sizeof (GstCaps), 32},
{"GstStaticCaps", sizeof (GstStaticCaps), 52},
{"GstChildProxyInterface", sizeof (GstChildProxyInterface), 40},
{"GstClock", sizeof (GstClock), 176},
{"GstClockClass", sizeof (GstClockClass), 160},
{"GstElement", sizeof (GstElement), 136},
{"GstElementClass", sizeof (GstElementClass), 248},
{"GstElementFactory", sizeof (GstElementFactory), 144},
{"GstElementFactoryClass", sizeof (GstElementFactoryClass), 152},
{"GstElementDetails", sizeof (GstElementDetails), 32},
{"GstEvent", sizeof (GstEvent), 48},
{"GstEventClass", sizeof (GstEventClass), 32},
{"GstFormatDefinition", sizeof (GstFormatDefinition), 16},
{"GstIndexEntry", sizeof (GstIndexEntry), 20},
{"GstIndexGroup", sizeof (GstIndexGroup), 16},
{"GstIndex", sizeof (GstIndex), 100},
{"GstIndexClass", sizeof (GstIndexClass), 156},
{"GstIndexAssociation", sizeof (GstIndexAssociation), 16},
{"GstIndexFactory", sizeof (GstIndexFactory), 96},
{"GstIndexFactoryClass", sizeof (GstIndexFactoryClass), 152},
{"GstDebugCategory", sizeof (GstDebugCategory), 16},
{"GstImplementsInterfaceClass", sizeof (GstImplementsInterfaceClass), 28},
{"GstIterator", sizeof (GstIterator), 52},
{"GstMessage", sizeof (GstMessage), 64},
{"GstMessageClass", sizeof (GstMessageClass), 32},
{"GstMiniObject", sizeof (GstMiniObject), 16},
{"GstMiniObjectClass", sizeof (GstMiniObjectClass), 16},
{"GstObject", sizeof (GstObject), 40},
{"GstObjectClass", sizeof (GstObjectClass), 120},
{"GstPad", sizeof (GstPad), 188},
{"GstPadClass", sizeof (GstPadClass), 152},
{"GstPadTemplate", sizeof (GstPadTemplate), 72},
{"GstPadTemplateClass", sizeof (GstPadTemplateClass), 140},
{"GstStaticPadTemplate", sizeof (GstStaticPadTemplate), 64},
{"GstPipeline", sizeof (GstPipeline), 232},
{"GstPipelineClass", sizeof (GstPipelineClass), 304},
{"GstPlugin", sizeof (GstPlugin), 152},
{"GstPluginClass", sizeof (GstPluginClass), 136},
{"GstPluginDesc", sizeof (GstPluginDesc), 56},
{"GstPluginFeature", sizeof (GstPluginFeature), 72},
{"GstPluginFeatureClass", sizeof (GstPluginFeatureClass), 136},
{"GstQueryTypeDefinition", sizeof (GstQueryTypeDefinition), 16},
{"GstQuery", sizeof (GstQuery), 28},
{"GstQueryClass", sizeof (GstQueryClass), 32},
{"GstRegistry", sizeof (GstRegistry), 72},
{"GstRegistryClass", sizeof (GstRegistryClass), 144},
{"GstSegment", sizeof (GstSegment), 88},
{"GstStructure", sizeof (GstStructure), 20},
{"GstSystemClock", sizeof (GstSystemClock), 200},
{"GstSystemClockClass", sizeof (GstSystemClockClass), 176},
{"GstTagSetterIFace", sizeof (GstTagSetterIFace), 8},
{"GstTask", sizeof (GstTask), 80},
{"GstTaskClass", sizeof (GstTaskClass), 140},
{"GstTrace", sizeof (GstTrace), 20},
{"GstTraceEntry", sizeof (GstTraceEntry), 128},
{"GstAllocTrace", sizeof (GstAllocTrace), 16},
{"GstTypeFind", sizeof (GstTypeFind), 32},
{"GstTypeFindFactory", sizeof (GstTypeFindFactory), 108},
{"GstTypeFindFactoryClass", sizeof (GstTypeFindFactoryClass), 152},
{"GstURIHandlerInterface", sizeof (GstURIHandlerInterface), 44},
{"GstValueTable", sizeof (GstValueTable), 32},
{"GstXML", sizeof (GstXML), 64},
{"GstXMLClass", sizeof (GstXMLClass), 144},
{NULL, 0, 0}
};

View file

@ -59,6 +59,10 @@
#include "struct_sparc.h"
#define HAVE_ABI_SIZES TRUE
#else
#ifdef HAVE_CPU_ARM
#include "struct_arm.h"
#define HAVE_ABI_SIZES TRUE
#else
/* in case someone wants to generate a new arch */
#include "struct_i386.h"
#define HAVE_ABI_SIZES FALSE
@ -68,6 +72,7 @@
#endif
#endif
#endif
#endif
GST_START_TEST (test_ABI)
{

View file

@ -0,0 +1,26 @@
GstCheckABIStruct list[] = {
{"GstAdapter", sizeof (GstAdapter), 52},
{"GstAdapterClass", sizeof (GstAdapterClass), 84},
{"GstBaseSink", sizeof (GstBaseSink), 408},
{"GstBaseSinkClass", sizeof (GstBaseSinkClass), 368},
{"GstBaseSrc", sizeof (GstBaseSrc), 392},
{"GstBaseSrcClass", sizeof (GstBaseSrcClass), 376},
{"GstBaseTransform", sizeof (GstBaseTransform), 368},
{"GstBaseTransformClass", sizeof (GstBaseTransformClass), 376},
{"GstCollectData", sizeof (GstCollectData), 120},
{"GstCollectPads", sizeof (GstCollectPads), 92},
{"GstCollectPadsClass", sizeof (GstCollectPadsClass), 136},
{"GstPushSrc", sizeof (GstPushSrc), 408},
{"GstPushSrcClass", sizeof (GstPushSrcClass), 396},
{"GstTimedValue", sizeof (GstTimedValue), 32},
{"GstValueArray", sizeof (GstValueArray), 24},
{"GstController", sizeof (GstController), 40},
{"GstControllerClass", sizeof (GstControllerClass), 84},
{"GstNetClientClock", sizeof (GstNetClientClock), 256},
{"GstNetClientClockClass", sizeof (GstNetClientClockClass), 192},
{"GstNetTimePacket", sizeof (GstNetTimePacket), 16},
{"GstNetTimeProvider", sizeof (GstNetTimeProvider), 84},
{"GstNetTimeProviderClass", sizeof (GstNetTimeProviderClass), 120},
{NULL, 0, 0}
};

View file

@ -865,13 +865,19 @@ print_pad_info (GstElement * element)
}
}
#if 0
static gint
compare_signal_names (GSignalQuery * a, GSignalQuery * b)
static gboolean
has_sometimes_template (GstElement * element)
{
return strcmp (a->signal_name, b->signal_name);
GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
GList *l;
for (l = klass->padtemplates; l != NULL; l = l->next) {
if (GST_PAD_TEMPLATE (l->data)->presence == GST_PAD_SOMETIMES)
return TRUE;
}
return FALSE;
}
#endif
static void
print_signal_info (GstElement * element)
@ -886,6 +892,22 @@ print_signal_info (GstElement * element)
for (k = 0; k < 2; k++) {
found_signals = NULL;
/* For elements that have sometimes pads, also list a few useful GstElement
* signals. Put these first, so element-specific ones come later. */
if (k == 0 && has_sometimes_template (element)) {
query = g_new0 (GSignalQuery, 1);
g_signal_query (g_signal_lookup ("pad-added", GST_TYPE_ELEMENT), query);
found_signals = g_slist_append (found_signals, query);
query = g_new0 (GSignalQuery, 1);
g_signal_query (g_signal_lookup ("pad-removed", GST_TYPE_ELEMENT), query);
found_signals = g_slist_append (found_signals, query);
query = g_new0 (GSignalQuery, 1);
g_signal_query (g_signal_lookup ("no-more-pads", GST_TYPE_ELEMENT),
query);
found_signals = g_slist_append (found_signals, query);
}
for (type = G_OBJECT_TYPE (element); type; type = g_type_parent (type)) {
if (type == GST_TYPE_ELEMENT || type == GST_TYPE_OBJECT)
break;

View file

@ -4,7 +4,7 @@ gst\-launch \- build and run a GStreamer pipeline
.SH "SYNOPSIS"
\fBgst\-launch\fR \fI[OPTION...]\fR PIPELINE\-DESCRIPTION
.SH "DESCRIPTION"
.LP
.LP
\fIgst\-launch\fP is a tool that builds and runs basic
\fIGStreamer\fP pipelines.
@ -44,6 +44,10 @@ Force an EOS event on sources before shutting the pipeline down. This is
useful to make sure muxers create readable files when a muxing pipeline is
shut down forcefully via Control-C.
.TP 8
.B \-i, \-\-index
Gather and print index statistics. This is mostly useful for playback or
recording pipelines.
.TP 8
.B \-o FILE, \-\-output=FILE
Save XML representation of pipeline to FILE and exit (DEPRECATED, DO NOT USE)
.TP 8
@ -114,7 +118,7 @@ plugins to preload is to use the environment variable GST_PLUGIN_PATH
.SH "PIPELINE DESCRIPTION"
A pipeline consists \fIelements\fR and \fIlinks\fR. \fIElements\fR can be put
A pipeline consists \fIelements\fR and \fIlinks\fR. \fIElements\fR can be put
into \fIbins\fR of different sorts. \fIElements\fR, \fIlinks\fR and \fIbins\fR
can be specified in a pipeline description in any order.
@ -138,7 +142,7 @@ Enumeration properties can be set by name, nick or value.
\fI[BINTYPE.]\fR ( \fI[PROPERTY1 ...]\fR PIPELINE-DESCRIPTION )
.br
Specifies that a bin of type BINTYPE is created and the given properties are
Specifies that a bin of type BINTYPE is created and the given properties are
set. Every element between the braces is put into the bin. Please note the dot
that has to be used after the BINTYPE. You will almost never need this
functionality, it is only really useful for applications using the
@ -194,11 +198,11 @@ and the type can have the following case-insensitive values:
.br
- \fBl\fR or \fBlist\fR for lists
.br
If no type was given, the following order is tried: integer, float, boolean,
If no type was given, the following order is tried: integer, float, boolean,
string.
.br
Integer values must be parsable by \fBstrtol()\fP, floats by \fBstrtod()\fP. FOURCC values may
either be integers or strings. Boolean values are (case insensitive) \fIyes\fR,
either be integers or strings. Boolean values are (case insensitive) \fIyes\fR,
\fIno\fR, \fItrue\fR or \fIfalse\fR and may like strings be escaped with " or '.
.br
Ranges are in this format: [ VALUE, VALUE ]
@ -390,7 +394,7 @@ automatically. To make this even easier, you can use the playbin element:
.B
gst\-launch playbin uri=file:///home/joe/foo.avi
.br
.B Filtered connections
@ -438,7 +442,7 @@ Specifies a list of directories to scan for additional plugins.
These take precedence over the system plugins.
.TP
\fBGST_PLUGIN_SYSTEM_PATH\fR
Specifies a list of plugins that are always loaded by default. If not set,
Specifies a list of plugins that are always loaded by default. If not set,
this defaults to the system-installed path, and the plugins installed in the
user's home directory
.TP

View file

@ -177,6 +177,159 @@ fault_setup (void)
}
#endif /* DISABLE_FAULT_HANDLER */
typedef struct _GstIndexStats
{
gint id;
gchar *desc;
guint num_frames;
guint num_keyframes;
guint num_dltframes;
GstClockTime last_keyframe;
GstClockTime last_dltframe;
GstClockTime min_keyframe_gap;
GstClockTime max_keyframe_gap;
GstClockTime avg_keyframe_gap;
} GstIndexStats;
static void
entry_added (GstIndex * index, GstIndexEntry * entry, gpointer user_data)
{
GPtrArray *index_stats = (GPtrArray *) user_data;
GstIndexStats *s;
switch (entry->type) {
case GST_INDEX_ENTRY_ID:
/* we have a new writer */
GST_DEBUG_OBJECT (index, "id %d: describes writer %s", entry->id,
GST_INDEX_ID_DESCRIPTION (entry));
if (entry->id >= index_stats->len) {
g_ptr_array_set_size (index_stats, entry->id + 1);
}
s = g_new (GstIndexStats, 1);
s->id = entry->id;
s->desc = g_strdup (GST_INDEX_ID_DESCRIPTION (entry));
s->num_frames = s->num_keyframes = s->num_dltframes = 0;
s->last_keyframe = s->last_dltframe = GST_CLOCK_TIME_NONE;
s->min_keyframe_gap = s->max_keyframe_gap = s->avg_keyframe_gap =
GST_CLOCK_TIME_NONE;
g_ptr_array_index (index_stats, entry->id) = s;
break;
case GST_INDEX_ENTRY_FORMAT:
/* have not found any code calling this */
GST_DEBUG_OBJECT (index, "id %d: registered format %d for %s\n",
entry->id, GST_INDEX_FORMAT_FORMAT (entry),
GST_INDEX_FORMAT_KEY (entry));
break;
case GST_INDEX_ENTRY_ASSOCIATION:
{
gint64 ts;
GstAssocFlags flags = GST_INDEX_ASSOC_FLAGS (entry);
s = g_ptr_array_index (index_stats, entry->id);
gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &ts);
if (flags & GST_ASSOCIATION_FLAG_KEY_UNIT) {
s->num_keyframes++;
if (GST_CLOCK_TIME_IS_VALID (ts)) {
if (GST_CLOCK_TIME_IS_VALID (s->last_keyframe)) {
GstClockTimeDiff d = GST_CLOCK_DIFF (s->last_keyframe, ts);
if (G_UNLIKELY (d < 0)) {
GST_WARNING ("received out-of-order keyframe at %"
GST_TIME_FORMAT, GST_TIME_ARGS (ts));
/* FIXME: does it still make sense to use that for the statistics */
d = GST_CLOCK_DIFF (ts, s->last_keyframe);
}
if (GST_CLOCK_TIME_IS_VALID (s->min_keyframe_gap)) {
if (d < s->min_keyframe_gap)
s->min_keyframe_gap = d;
} else {
s->min_keyframe_gap = d;
}
if (GST_CLOCK_TIME_IS_VALID (s->max_keyframe_gap)) {
if (d > s->max_keyframe_gap)
s->max_keyframe_gap = d;
} else {
s->max_keyframe_gap = d;
}
if (GST_CLOCK_TIME_IS_VALID (s->avg_keyframe_gap)) {
s->avg_keyframe_gap = (d + s->num_frames * s->avg_keyframe_gap) /
(s->num_frames + 1);
} else {
s->avg_keyframe_gap = d;
}
}
s->last_keyframe = ts;
}
}
if (flags & GST_ASSOCIATION_FLAG_DELTA_UNIT) {
s->num_dltframes++;
if (GST_CLOCK_TIME_IS_VALID (ts)) {
s->last_dltframe = ts;
}
}
s->num_frames++;
break;
}
default:
break;
}
}
/* print statistics from the entry_added callback, free the entries */
static void
print_index_stats (GPtrArray * index_stats)
{
gint i;
if (index_stats->len) {
g_print (_("Index statistics\n"));
}
for (i = 0; i < index_stats->len; i++) {
GstIndexStats *s = g_ptr_array_index (index_stats, i);
if (s) {
g_print ("id %d, %s\n", s->id, s->desc);
if (s->num_frames) {
GstClockTime last_frame = s->last_keyframe;
if (GST_CLOCK_TIME_IS_VALID (s->last_dltframe)) {
if (!GST_CLOCK_TIME_IS_VALID (last_frame) ||
(s->last_dltframe > last_frame))
last_frame = s->last_dltframe;
}
if (GST_CLOCK_TIME_IS_VALID (last_frame)) {
g_print (" total time = %" GST_TIME_FORMAT "\n",
GST_TIME_ARGS (last_frame));
}
g_print (" frame/keyframe rate = %u / %u = ", s->num_frames,
s->num_keyframes);
if (s->num_keyframes)
g_print ("%lf\n", s->num_frames / (gdouble) s->num_keyframes);
else
g_print ("-\n");
if (s->num_keyframes) {
g_print (" min/avg/max keyframe gap = %" GST_TIME_FORMAT ", %"
GST_TIME_FORMAT ", %" GST_TIME_FORMAT "\n",
GST_TIME_ARGS (s->min_keyframe_gap),
GST_TIME_ARGS (s->avg_keyframe_gap),
GST_TIME_ARGS (s->max_keyframe_gap));
}
} else {
g_print (" no stats\n");
}
g_free (s->desc);
g_free (s);
}
}
}
static void
print_error_message (GstMessage * msg)
{
@ -668,6 +821,7 @@ main (int argc, char *argv[])
gboolean no_sigusr_handler = FALSE;
gboolean trace = FALSE;
gboolean eos_on_shutdown = FALSE;
gboolean check_index = FALSE;
gchar *savefile = NULL;
gchar *exclude_args = NULL;
#ifndef GST_DISABLE_OPTION_PARSING
@ -690,12 +844,16 @@ main (int argc, char *argv[])
N_("Print alloc trace (if enabled at compile time)"), NULL},
{"eos-on-shutdown", 'e', 0, G_OPTION_ARG_NONE, &eos_on_shutdown,
N_("Force EOS on sources before shutting the pipeline down"), NULL},
{"index", 'i', 0, G_OPTION_ARG_NONE, &check_index,
N_("Gather and print index statistics"), NULL},
GST_TOOLS_GOPTION_VERSION,
{NULL}
};
GOptionContext *ctx;
GError *err = NULL;
#endif
GstIndex *index;
GPtrArray *index_stats = NULL;
gchar **argvn;
GError *error = NULL;
gint res = 0;
@ -798,6 +956,21 @@ main (int argc, char *argv[])
pipeline = real_pipeline;
}
if (check_index) {
/* gst_index_new() creates a null-index, it does not store anything, but
* the entry-added signal works and this is what we use to build the
* statistics */
index = gst_index_new ();
if (index) {
index_stats = g_ptr_array_new ();
g_signal_connect (G_OBJECT (index), "entry-added",
G_CALLBACK (entry_added), index_stats);
g_object_set (G_OBJECT (index), "resolver", GST_INDEX_RESOLVER_GTYPE,
NULL);
gst_element_set_index (pipeline, index);
}
}
bus = gst_element_get_bus (pipeline);
gst_bus_set_sync_handler (bus, bus_sync_handler, (gpointer) pipeline);
gst_object_unref (bus);
@ -890,6 +1063,11 @@ main (int argc, char *argv[])
gst_element_set_state (pipeline, GST_STATE_READY);
gst_element_get_state (pipeline, &state, &pending, GST_CLOCK_TIME_NONE);
if (check_index) {
print_index_stats (index_stats);
g_ptr_array_free (index_stats, TRUE);
}
end:
PRINT (_("Setting pipeline to NULL ...\n"));
gst_element_set_state (pipeline, GST_STATE_NULL);

View file

@ -407,6 +407,7 @@ EXPORTS
gst_event_type_get_name
gst_event_type_get_type
gst_event_type_to_quark
gst_filename_to_uri
gst_filter_run
gst_flow_get_name
gst_flow_return_get_type