mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-18 07:47:17 +00:00
Merge branch 'master' into 0.11
Conflicts: gst/gstregistry.h
This commit is contained in:
commit
230c3455ac
21 changed files with 527 additions and 22 deletions
2
common
2
common
|
@ -1 +1 @@
|
|||
Subproject commit 1de7f6ab2d4bc1af69f06079cf0f4e2cbbfdc178
|
||||
Subproject commit 6aec6b9716c184c60c4bc6a5916a2471cfa8c8cd
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
113
gst/gsturi.c
113
gst/gsturi.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
73
tests/check/gst/struct_arm.h
Normal file
73
tests/check/gst/struct_arm.h
Normal 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}
|
||||
};
|
|
@ -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)
|
||||
{
|
||||
|
|
26
tests/check/libs/struct_arm.h
Normal file
26
tests/check/libs/struct_arm.h
Normal 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}
|
||||
};
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue