Merge branch 'master' into 0.11-fdo

Conflicts:
	gst-libs/gst/tag/gstxmptag.c
This commit is contained in:
Wim Taymans 2011-03-30 20:23:54 +02:00
commit adaf08f143
13 changed files with 857 additions and 16 deletions

View file

@ -2,13 +2,13 @@ libgsttagincludedir = \
$(includedir)/gstreamer-@GST_MAJORMINOR@/gst/tag
libgsttaginclude_HEADERS = \
tag.h gsttagdemux.h
tag.h gsttagdemux.h xmpwriter.h
lib_LTLIBRARIES = libgsttag-@GST_MAJORMINOR@.la
libgsttag_@GST_MAJORMINOR@_la_SOURCES = \
gstvorbistag.c gstid3tag.c gstxmptag.c gstexiftag.c \
lang.c tags.c gsttagdemux.c gsttageditingprivate.c
lang.c tags.c gsttagdemux.c gsttageditingprivate.c xmpwriter.c
libgsttag_@GST_MAJORMINOR@_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
libgsttag_@GST_MAJORMINOR@_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS) $(LIBM)
libgsttag_@GST_MAJORMINOR@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS)

View file

@ -35,6 +35,7 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "tag.h"
#include <gst/gsttagsetter.h>
#include "gsttageditingprivate.h"
#include <stdio.h>
@ -43,6 +44,32 @@
#include <time.h>
#include <ctype.h>
static const gchar *schema_list[] = {
"dc",
"xap",
"tiff",
"exif",
"photoshop",
"Iptc4xmpCore",
NULL
};
/**
* gst_tag_xmp_list_schemas:
*
* Gets the list of supported schemas in the xmp lib
*
* Returns: a %NULL terminated array of strings with the schema names
*
* Since: 0.10.33
*/
const gchar **
gst_tag_xmp_list_schemas (void)
{
return schema_list;
}
typedef struct _XmpSerializationData XmpSerializationData;
typedef struct _XmpTag XmpTag;
/*
@ -63,6 +90,28 @@ typedef void (*XmpDeserializationFunc) (XmpTag * xmptag, GstTagList * taglist,
const gchar * gst_tag, const gchar * xmp_tag_value,
const gchar * str, GSList ** pending_tags);
struct _XmpSerializationData
{
GString *data;
const gchar **schemas;
};
static gboolean
xmp_serialization_data_use_schema (XmpSerializationData * serdata,
const gchar * schemaname)
{
gint i = 0;
if (serdata->schemas == NULL)
return TRUE;
while (serdata->schemas[i] != NULL) {
if (strcmp (serdata->schemas[i], schemaname) == 0)
return TRUE;
i++;
}
return FALSE;
}
#define GST_XMP_TAG_TYPE_SIMPLE 0
#define GST_XMP_TAG_TYPE_BAG 1
@ -192,18 +241,22 @@ _gst_xmp_schema_add_simple_mapping (GstXmpSchema * schema,
* have our lists modified during usage
*/
static GPtrArray *
_xmp_tag_get_mapping (const gchar * gst_tag)
_xmp_tag_get_mapping (const gchar * gst_tag, XmpSerializationData * serdata)
{
GPtrArray *ret = NULL;
GHashTableIter iter;
GQuark key = g_quark_from_string (gst_tag);
gpointer iterkey, value;
const gchar *schemaname;
g_hash_table_iter_init (&iter, __xmp_schemas);
while (!ret && g_hash_table_iter_next (&iter, &iterkey, &value)) {
GstXmpSchema *schema = (GstXmpSchema *) value;
ret = (GPtrArray *) gst_xmp_schema_lookup (schema, GUINT_TO_POINTER (key));
schemaname = g_quark_to_string (GPOINTER_TO_UINT (iterkey));
if (xmp_serialization_data_use_schema (serdata, schemaname))
ret =
(GPtrArray *) gst_xmp_schema_lookup (schema, GUINT_TO_POINTER (key));
}
return ret;
}
@ -818,7 +871,7 @@ _init_xmp_tag_map ()
schema = gst_xmp_schema_new ();
_gst_xmp_schema_add_simple_mapping (schema, GST_TAG_USER_RATING,
"xmp:Rating", GST_XMP_TAG_TYPE_SIMPLE, NULL, deserialize_xmp_rating);
_gst_xmp_add_schema ("xmp", schema);
_gst_xmp_add_schema ("xap", schema);
/* tiff */
schema = gst_xmp_schema_new ();
@ -1455,12 +1508,13 @@ static void
write_one_tag (const GstTagList * list, const gchar * tag, gpointer user_data)
{
guint i = 0, ct = gst_tag_list_get_tag_size (list, tag), tag_index;
GString *data = user_data;
XmpSerializationData *serialization_data = user_data;
GString *data = serialization_data->data;
GPtrArray *xmp_tag_array = NULL;
char *s;
/* map gst-tag to xmp tag */
xmp_tag_array = _xmp_tag_get_mapping (tag);
xmp_tag_array = _xmp_tag_get_mapping (tag, serialization_data);
if (!xmp_tag_array) {
GST_WARNING ("no mapping for %s to xmp", tag);
@ -1518,25 +1572,34 @@ write_one_tag (const GstTagList * list, const gchar * tag, gpointer user_data)
}
/**
* gst_tag_list_to_xmp_buffer:
* gst_tag_list_to_xmp_buffer_full:
* @list: tags
* @read_only: does the container forbid inplace editing
* @schemas: %NULL terminated array of schemas to be used on serialization
*
* Formats a taglist as a xmp packet.
* Formats a taglist as a xmp packet using only the selected
* schemas. An empty list (%NULL) means that all schemas should
* be used
*
* Returns: new buffer or %NULL, unref the buffer when done
*
* Since: 0.10.29
* Since: 0.10.33
*/
GstBuffer *
gst_tag_list_to_xmp_buffer (const GstTagList * list, gboolean read_only)
gst_tag_list_to_xmp_buffer_full (const GstTagList * list, gboolean read_only,
const gchar ** schemas)
{
GstBuffer *buffer = NULL;
GString *str = g_string_sized_new (4096);
XmpSerializationData serialization_data;
GString *data;
guint i;
gsize size;
gpointer data;
serialization_data.data = g_string_sized_new (4096);
serialization_data.schemas = schemas;
data = serialization_data.data;
xmp_tags_initialize ();
g_return_val_if_fail (GST_IS_TAG_LIST (list), NULL);
@ -1550,15 +1613,17 @@ gst_tag_list_to_xmp_buffer (const GstTagList * list, gboolean read_only)
"<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"");
i = 0;
while (ns_match[i].ns_prefix) {
g_string_append_printf (str, " xmlns:%s=\"%s\"", ns_match[i].ns_prefix,
ns_match[i].ns_uri);
if (xmp_serialization_data_use_schema (&serialization_data,
ns_match[i].ns_prefix))
g_string_append_printf (data, " xmlns:%s=\"%s\"",
ns_match[i].ns_prefix, ns_match[i].ns_uri);
i++;
}
g_string_append (str, ">\n");
g_string_append (str, "<rdf:Description rdf:about=\"\">\n");
/* iterate the taglist */
gst_tag_list_foreach (list, write_one_tag, str);
gst_tag_list_foreach (list, write_one_tag, &serialization_data);
/* xmp footer */
g_string_append (str, "</rdf:Description>\n");
@ -1587,5 +1652,22 @@ gst_tag_list_to_xmp_buffer (const GstTagList * list, gboolean read_only)
return buffer;
}
/**
* gst_tag_list_to_xmp_buffer:
* @list: tags
* @read_only: does the container forbid inplace editing
*
* Formats a taglist as a xmp packet.
*
* Returns: new buffer or %NULL, unref the buffer when done
*
* Since: 0.10.29
*/
GstBuffer *
gst_tag_list_to_xmp_buffer (const GstTagList * list, gboolean read_only)
{
return gst_tag_list_to_xmp_buffer_full (list, read_only, NULL);
}
#undef gst_xmp_schema_lookup
#undef gst_xmp_schema_insert

View file

@ -479,6 +479,9 @@ gboolean gst_tag_list_add_id3_image (GstTagList * tag_list,
GstTagList * gst_tag_list_from_xmp_buffer (GstBuffer * buffer);
GstBuffer * gst_tag_list_to_xmp_buffer (const GstTagList * list,
gboolean read_only);
GstBuffer * gst_tag_list_to_xmp_buffer_full (const GstTagList * list,
gboolean read_only, const gchar ** schemas);
const gchar** gst_tag_xmp_list_schemas (void);
/* functions related to exif */
GstBuffer * gst_tag_list_to_exif_buffer (const GstTagList * taglist,

View file

@ -0,0 +1,322 @@
/* GStreamer XmpConfig
* Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk>
*
* 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.
*/
/**
* SECTION:gstxmpconfig
* @short_description: Interface for elements that provide XMP serialization
*
* <refsect2>
* <para>
* This interface is implemented by elements that are able to do XMP serialization. Examples for
* such elements are #jifmux and #qtmux.
* </para>
* <para>
* Applications can use this interface to configure which XMP schemas should be used when serializing
* tags into XMP. Schemas are represented by their names, a full list of the supported schemas can be
* obtained from gst_tag_xmp_list_schemas(). By default, all schemas are used.
* </para>
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "xmpwriter.h"
#include <string.h>
#include <gst/tag/tag.h>
static GQuark tag_xmp_writer_key;
typedef struct
{
GSList *schemas;
GStaticMutex lock;
} GstTagXmpWriterData;
GType
gst_tag_xmp_writer_get_type (void)
{
static volatile gsize xmp_config_type = 0;
if (g_once_init_enter (&xmp_config_type)) {
GType _type;
static const GTypeInfo xmp_config_info = {
sizeof (GstTagXmpWriterInterface), /* class_size */
NULL, /* base_init */
NULL, /* base_finalize */
NULL,
NULL, /* class_finalize */
NULL, /* class_data */
0,
0,
NULL
};
_type = g_type_register_static (G_TYPE_INTERFACE, "GstTagXmpWriter",
&xmp_config_info, 0);
tag_xmp_writer_key = g_quark_from_static_string ("GST_TAG_XMP_WRITER");
g_type_interface_add_prerequisite (_type, GST_TYPE_ELEMENT);
g_once_init_leave (&xmp_config_type, _type);
}
return xmp_config_type;
}
static void
gst_tag_xmp_writer_data_add_schema_unlocked (GstTagXmpWriterData * data,
const gchar * schema)
{
if (!g_slist_find_custom (data->schemas, schema, (GCompareFunc) strcmp)) {
data->schemas = g_slist_prepend (data->schemas, g_strdup (schema));
}
}
static void
gst_tag_xmp_writer_data_add_all_schemas_unlocked (GstTagXmpWriterData * data)
{
const gchar **schemas;
gint i = 0;
/* initialize it with all schemas */
schemas = gst_tag_xmp_list_schemas ();
while (schemas[i] != NULL) {
gst_tag_xmp_writer_data_add_schema_unlocked (data, schemas[i]);
i++;
}
}
static void
gst_tag_xmp_writer_data_free (gpointer p)
{
GstTagXmpWriterData *data = (GstTagXmpWriterData *) p;
GSList *iter;
if (data->schemas) {
for (iter = data->schemas; iter; iter = g_slist_next (iter)) {
g_free (iter->data);
}
g_slist_free (data->schemas);
}
g_static_mutex_free (&data->lock);
g_slice_free (GstTagXmpWriterData, data);
}
static GstTagXmpWriterData *
gst_tag_xmp_writer_get_data (GstTagXmpWriter * xmpconfig)
{
GstTagXmpWriterData *data;
data = g_object_get_qdata (G_OBJECT (xmpconfig), tag_xmp_writer_key);
if (!data) {
static GStaticMutex create_mutex = G_STATIC_MUTEX_INIT;
/* make sure no other thread is creating a GstTagXmpWriterData at the same time */
g_static_mutex_lock (&create_mutex);
data = g_object_get_qdata (G_OBJECT (xmpconfig), tag_xmp_writer_key);
if (!data) {
data = g_slice_new (GstTagXmpWriterData);
g_static_mutex_init (&data->lock);
data->schemas = NULL;
gst_tag_xmp_writer_data_add_all_schemas_unlocked (data);
g_object_set_qdata_full (G_OBJECT (xmpconfig), tag_xmp_writer_key, data,
gst_tag_xmp_writer_data_free);
}
g_static_mutex_unlock (&create_mutex);
}
return data;
}
/**
* gst_tag_xmp_writer_add_all_schemas:
* @config: a #GstTagXmpWriter
*
* Adds all available XMP schemas to the configuration. Meaning that
* all will be used.
*
* Since: 0.10.33
*/
void
gst_tag_xmp_writer_add_all_schemas (GstTagXmpWriter * config)
{
GstTagXmpWriterData *data;
g_return_if_fail (GST_IS_TAG_XMP_WRITER (config));
data = gst_tag_xmp_writer_get_data (config);
g_static_mutex_lock (&data->lock);
gst_tag_xmp_writer_data_add_all_schemas_unlocked (data);
g_static_mutex_unlock (&data->lock);
}
/**
* gst_tag_xmp_writer_add_schema:
* @config: a #GstTagXmpWriter
* @schema: the schema to be added
*
* Adds @schema to the list schemas
*
* Since: 0.10.33
*/
void
gst_tag_xmp_writer_add_schema (GstTagXmpWriter * config, const gchar * schema)
{
GstTagXmpWriterData *data;
g_return_if_fail (GST_IS_TAG_XMP_WRITER (config));
data = gst_tag_xmp_writer_get_data (config);
g_static_mutex_lock (&data->lock);
gst_tag_xmp_writer_data_add_schema_unlocked (data, schema);
g_static_mutex_unlock (&data->lock);
}
/**
* gst_tag_xmp_writer_has_schema:
* @config: a #GstTagXmpWriter
* @schema: the schema to test
*
* Checks if @schema is going to be used
*
* Returns: %TRUE if it is going to be used
* Since: 0.10.33
*/
gboolean
gst_tag_xmp_writer_has_schema (GstTagXmpWriter * config, const gchar * schema)
{
GstTagXmpWriterData *data;
gboolean ret = FALSE;
GSList *iter;
g_return_val_if_fail (GST_IS_TAG_XMP_WRITER (config), FALSE);
data = gst_tag_xmp_writer_get_data (config);
g_static_mutex_lock (&data->lock);
for (iter = data->schemas; iter; iter = g_slist_next (iter)) {
if (strcmp ((const gchar *) iter->data, schema) == 0) {
ret = TRUE;
break;
}
}
g_static_mutex_unlock (&data->lock);
return ret;
}
/**
* gst_tag_xmp_writer_remove_schema:
* @config: a #GstTagXmpWriter
* @schema: the schema to remove
*
* Removes a schema from the list of schemas to use. Nothing is done if
* the schema wasn't in the list
*
* Since: 0.10.33
*/
void
gst_tag_xmp_writer_remove_schema (GstTagXmpWriter * config,
const gchar * schema)
{
GstTagXmpWriterData *data;
GSList *iter = NULL;
g_return_if_fail (GST_IS_TAG_XMP_WRITER (config));
data = gst_tag_xmp_writer_get_data (config);
g_static_mutex_lock (&data->lock);
for (iter = data->schemas; iter; iter = g_slist_next (iter)) {
if (strcmp ((const gchar *) iter->data, schema) == 0) {
g_free (iter->data);
data->schemas = g_slist_delete_link (data->schemas, iter);
break;
}
}
g_static_mutex_unlock (&data->lock);
}
/**
* gst_tag_xmp_writer_remove_all_schemas:
* @config: a #GstTagXmpWriter
*
* Removes all schemas from the list of schemas to use. Meaning that no
* XMP will be generated.
*
* Since: 0.10.33
*/
void
gst_tag_xmp_writer_remove_all_schemas (GstTagXmpWriter * config)
{
GstTagXmpWriterData *data;
GSList *iter;
g_return_if_fail (GST_IS_TAG_XMP_WRITER (config));
data = gst_tag_xmp_writer_get_data (config);
g_static_mutex_lock (&data->lock);
if (data->schemas) {
for (iter = data->schemas; iter; iter = g_slist_next (iter)) {
g_free (iter->data);
}
g_slist_free (data->schemas);
}
data->schemas = NULL;
g_static_mutex_unlock (&data->lock);
}
GstBuffer *
gst_tag_xmp_writer_tag_list_to_xmp_buffer (GstTagXmpWriter * config,
const GstTagList * taglist, gboolean read_only)
{
GstTagXmpWriterData *data;
GstBuffer *buf = NULL;
const gchar **array;
gint i = 0;
GSList *iter;
g_return_val_if_fail (GST_IS_TAG_XMP_WRITER (config), NULL);
data = gst_tag_xmp_writer_get_data (config);
g_static_mutex_lock (&data->lock);
if (data->schemas) {
array = g_new0 (const gchar *, g_slist_length (data->schemas) + 1);
if (array) {
for (iter = data->schemas; iter; iter = g_slist_next (iter)) {
array[i++] = (const gchar *) iter->data;
}
buf = gst_tag_list_to_xmp_buffer_full (taglist, read_only, array);
g_free (array);
}
}
g_static_mutex_unlock (&data->lock);
return buf;
}

View file

@ -0,0 +1,68 @@
/* GStreamer XmpConfig
* Copyright (C) 2011 Thiago Santos <thiago.sousa.santos@collabora.co.uk>
*
* 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 __TAG_XMP_WRITER_H__
#define __TAG_XMP_WRITER_H__
#include <gst/gst.h>
G_BEGIN_DECLS
#define GST_TYPE_TAG_XMP_WRITER \
(gst_tag_xmp_writer_get_type ())
#define GST_TAG_XMP_WRITER(obj) \
(GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_TAG_XMP_WRITER, GstTagXmpWriter))
#define GST_TAG_XMP_WRITER_INTERFACE(iface) \
(G_TYPE_CHECK_INTERFACE_CAST ((iface), GST_TYPE_TAG_XMP_WRITER, GstTagXmpWriterInterface))
#define GST_IS_TAG_XMP_WRITER(obj) \
(GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_TAG_XMP_WRITER))
#define GST_IS_TAG_XMP_WRITER_INTERFACE(iface) \
(G_TYPE_CHECK_INTERFACE_TYPE ((iface), GST_TYPE_TAG_XMP_WRITER))
#define GST_TAG_XMP_WRITER_GET_INTERFACE(inst) \
(G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_TAG_XMP_WRITER, GstTagXmpWriterInterface))
typedef struct _GstTagXmpWriter GstTagXmpWriter;
typedef struct _GstTagXmpWriterInterface GstTagXmpWriterInterface;
struct _GstTagXmpWriterInterface {
GTypeInterface parent;
};
GType gst_tag_xmp_writer_get_type (void);
void gst_tag_xmp_writer_add_all_schemas (GstTagXmpWriter * config);
void gst_tag_xmp_writer_add_schema (GstTagXmpWriter * config,
const gchar * schema);
gboolean gst_tag_xmp_writer_has_schema (GstTagXmpWriter * config,
const gchar * schema);
void gst_tag_xmp_writer_remove_schema (GstTagXmpWriter * config,
const gchar * schema);
void gst_tag_xmp_writer_remove_all_schemas (GstTagXmpWriter * config);
GstBuffer* gst_tag_xmp_writer_tag_list_to_xmp_buffer (GstTagXmpWriter * config,
const GstTagList * taglist,
gboolean read_only);
G_END_DECLS
#endif /* __TAG_XMP_WRITER_H__ */

View file

@ -266,6 +266,41 @@ uri_type_find (GstTypeFind * tf, gpointer unused)
}
}
/*** application/x-hls ***/
static GstStaticCaps hls_caps = GST_STATIC_CAPS ("application/x-hls");
#define HLS_CAPS (gst_static_caps_get(&hls_caps))
/* See http://tools.ietf.org/html/draft-pantos-http-live-streaming-05 */
static void
hls_type_find (GstTypeFind * tf, gpointer unused)
{
DataScanCtx c = { 0, NULL, 0 };
if (G_UNLIKELY (!data_scan_ctx_ensure_data (tf, &c, 7)))
return;
if (memcmp (c.data, "#EXTM3U", 7))
return;
data_scan_ctx_advance (tf, &c, 7);
/* Check only the first 256 bytes */
while (c.offset < 256) {
if (G_UNLIKELY (!data_scan_ctx_ensure_data (tf, &c, 21)))
return;
/* Search for # comment lines */
if (c.data[0] == '#' && (memcmp (c.data, "#EXT-X-TARGETDURATION", 21) == 0
|| memcmp (c.data, "#EXT-X-STREAM-INF", 17) == 0)) {
gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, HLS_CAPS);
return;
}
data_scan_ctx_advance (tf, &c, 1);
}
}
/*** application/xml **********************************************************/
@ -4161,6 +4196,7 @@ plugin_init (GstPlugin * plugin)
static const gchar *shn_exts[] = { "shn", NULL };
static const gchar *ape_exts[] = { "ape", NULL };
static const gchar *uri_exts[] = { "ram", NULL };
static const gchar *hls_exts[] = { "m3u8", NULL };
static const gchar *sdp_exts[] = { "sdp", NULL };
static const gchar *smil_exts[] = { "smil", NULL };
static const gchar *html_exts[] = { "htm", "html", NULL };
@ -4324,6 +4360,8 @@ plugin_init (GstPlugin * plugin)
utf8_exts, UTF8_CAPS, NULL, NULL);
TYPE_FIND_REGISTER (plugin, "text/uri-list", GST_RANK_MARGINAL, uri_type_find,
uri_exts, URI_CAPS, NULL, NULL);
TYPE_FIND_REGISTER (plugin, "application/x-hls", GST_RANK_MARGINAL,
hls_type_find, hls_exts, HLS_CAPS, NULL, NULL);
TYPE_FIND_REGISTER (plugin, "application/sdp", GST_RANK_SECONDARY,
sdp_type_find, sdp_exts, SDP_CAPS, NULL, NULL);
TYPE_FIND_REGISTER (plugin, "application/smil", GST_RANK_SECONDARY,

View file

@ -150,6 +150,7 @@ check_PROGRAMS = \
libs/rtsp \
libs/tag \
libs/video \
libs/xmpwriter \
$(cxx_checks) \
$(check_orc) \
pipelines/simple-launch-lines \
@ -307,6 +308,17 @@ libs_profile_CFLAGS = \
libs_profile_LDADD = \
$(top_builddir)/gst-libs/gst/pbutils/libgstpbutils-@GST_MAJORMINOR@.la $(LDADD)
libs_xmpwriter_CFLAGS = \
$(GST_PLUGINS_BASE_CFLAGS) \
$(GST_BASE_CFLAGS) \
$(AM_CFLAGS)
libs_xmpwriter_LDADD = \
$(top_builddir)/gst-libs/gst/tag/libgsttag-@GST_MAJORMINOR@.la \
$(GST_BASE_LIBS) \
$(LDADD)
libs_gstlibscpp_SOURCES = libs/gstlibscpp.cc
elements_appsink_CFLAGS = \

View file

@ -504,7 +504,8 @@ GST_START_TEST (test_encodebin_render_audio_only_static)
fail_unless (gst_element_link_many (audiotestsrc, ebin, fakesink, NULL));
/* Requesting a new pad should fail */
fail_if (gst_element_get_request_pad (ebin, "audio_0") != NULL);
ASSERT_CRITICAL (gst_element_get_request_pad (ebin, "audio_0"));
sinkcaps = gst_caps_new_simple ("audio/x-raw-int", NULL);
g_signal_emit_by_name (ebin, "request-pad", sinkcaps, &sinkpad);
gst_caps_unref (sinkcaps);

View file

@ -370,6 +370,20 @@ GST_START_TEST (test_random_data)
GST_END_TEST;
GST_START_TEST (test_hls_m3u8)
{
const gchar *type;
GstCaps *caps = NULL;
caps = typefind_test_file ("hls.m3u8");
type = gst_structure_get_name (gst_caps_get_structure (caps, 0));
fail_unless_equals_string (type, "application/x-hls");
gst_caps_unref (caps);
}
GST_END_TEST;
static Suite *
typefindfunctions_suite (void)
{
@ -385,6 +399,7 @@ typefindfunctions_suite (void)
tcase_add_test (tc_chain, test_ac3);
tcase_add_test (tc_chain, test_eac3);
tcase_add_test (tc_chain, test_random_data);
tcase_add_test (tc_chain, test_hls_m3u8);
return s;
}

View file

@ -0,0 +1,275 @@
/* GStreamer
*
* unit tests for xmp config library
*
* Copyright (C) 2011 Thiago Santos <thiago.sousa.santos@collabora.co.uk>
*
* 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/check/gstcheck.h>
#include <gst/tag/tag.h>
#include <gst/tag/xmpwriter.h>
#include <string.h>
#define TEST_ELEMENT_TYPE (test_element_get_type())
typedef struct TestElement TestElement;
typedef struct TestElementClass TestElementClass;
struct TestElement
{
GstElement parent;
};
struct TestElementClass
{
GstElementClass parent_class;
};
GType test_element_get_type (void);
static void init_interface (GType type);
GST_BOILERPLATE_FULL (TestElement, test_element, GstElement, GST_TYPE_ELEMENT,
init_interface);
static void
init_interface (GType type)
{
static const GInterfaceInfo tagxmpwriter_info = {
NULL,
NULL,
NULL,
};
g_type_add_interface_static (type, GST_TYPE_TAG_XMP_WRITER,
&tagxmpwriter_info);
}
static void
test_element_base_init (gpointer klass)
{
}
static void
test_element_class_init (TestElementClass * klass)
{
}
static void
test_element_init (TestElement * this, TestElementClass * klass)
{
}
static void
tag_list_equals (GstTagList * taglist, GstTagList * taglist2)
{
const gchar *name_sent, *name_recv;
const GValue *value_sent, *value_recv;
gboolean found;
gint comparison;
gint n_recv;
gint n_sent;
gint i, j;
/* verify tags */
fail_unless (taglist2 != NULL);
n_recv = gst_structure_n_fields (taglist2);
n_sent = gst_structure_n_fields (taglist);
fail_unless (n_recv == n_sent);
fail_unless (n_sent > 0);
/* FIXME: compare taglist values */
for (i = 0; i < n_sent; i++) {
name_sent = gst_structure_nth_field_name (taglist, i);
value_sent = gst_structure_get_value (taglist, name_sent);
found = FALSE;
for (j = 0; j < n_recv; j++) {
name_recv = gst_structure_nth_field_name (taglist2, j);
if (!strcmp (name_sent, name_recv)) {
value_recv = gst_structure_get_value (taglist2, name_recv);
comparison = gst_value_compare (value_sent, value_recv);
if (comparison != GST_VALUE_EQUAL) {
gchar *vs = g_strdup_value_contents (value_sent);
gchar *vr = g_strdup_value_contents (value_recv);
GST_DEBUG ("sent = %s:'%s', recv = %s:'%s'",
G_VALUE_TYPE_NAME (value_sent), vs,
G_VALUE_TYPE_NAME (value_recv), vr);
g_free (vs);
g_free (vr);
}
if (comparison != GST_VALUE_EQUAL &&
G_VALUE_HOLDS (value_sent, G_TYPE_DOUBLE)) {
gdouble vs;
gdouble vr;
/* add some tolerance for doubles */
vs = g_value_get_double (value_sent);
vr = g_value_get_double (value_recv);
if (vr >= vs - 0.001 && vr <= vs + 0.001)
comparison = GST_VALUE_EQUAL;
}
fail_unless (comparison == GST_VALUE_EQUAL,
"tag item %s has been received with different type or value",
name_sent);
found = TRUE;
break;
}
}
fail_unless (found, "tag item %s is lost", name_sent);
}
}
static gboolean
gst_buffer_equals (GstBuffer * buf_a, GstBuffer * buf_b)
{
if (GST_BUFFER_SIZE (buf_a) != GST_BUFFER_SIZE (buf_b))
return FALSE;
return memcmp (GST_BUFFER_DATA (buf_a), GST_BUFFER_DATA (buf_b),
GST_BUFFER_SIZE (buf_a)) == 0;
}
static GstTagList *
create_taglist (void)
{
return gst_tag_list_new_full (GST_TAG_ARTIST, "artist",
GST_TAG_TITLE, "title", GST_TAG_COPYRIGHT, "copyright", NULL);
}
GST_START_TEST (test_no_xmp)
{
GstTagList *taglist = create_taglist ();
GstElement *test_element =
(GstElement *) g_object_new (TEST_ELEMENT_TYPE, NULL);
gst_tag_xmp_writer_remove_all_schemas (GST_TAG_XMP_WRITER (test_element));
fail_unless (gst_tag_xmp_writer_tag_list_to_xmp_buffer (GST_TAG_XMP_WRITER
(test_element), taglist, TRUE) == NULL);
gst_object_unref (test_element);
gst_tag_list_free (taglist);
}
GST_END_TEST;
GST_START_TEST (test_default)
{
GstTagList *taglist = create_taglist ();
GstElement *test_element =
(GstElement *) g_object_new (TEST_ELEMENT_TYPE, NULL);
GstBuffer *buf;
GstBuffer *buf2;
buf =
gst_tag_xmp_writer_tag_list_to_xmp_buffer (GST_TAG_XMP_WRITER
(test_element), taglist, TRUE);
buf2 = gst_tag_list_to_xmp_buffer (taglist, TRUE);
fail_unless (gst_buffer_equals (buf, buf2));
gst_object_unref (test_element);
gst_buffer_unref (buf);
gst_buffer_unref (buf2);
gst_tag_list_free (taglist);
}
GST_END_TEST;
GST_START_TEST (test_disable)
{
GstTagList *taglist;
GstTagList *taglist2;
GstElement *test_element =
(GstElement *) g_object_new (TEST_ELEMENT_TYPE, NULL);
GstBuffer *buf;
const gchar *str;
taglist = gst_tag_list_new_full (GST_TAG_ARTIST, "artist", NULL);
/* add a tag that is mapped on xmp schema (as of Mar, 21th 2011) */
gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_USER_RATING, 5,
NULL);
buf =
gst_tag_xmp_writer_tag_list_to_xmp_buffer (GST_TAG_XMP_WRITER
(test_element), taglist, TRUE);
taglist2 = gst_tag_list_from_xmp_buffer (buf);
tag_list_equals (taglist, taglist2);
gst_tag_list_free (taglist2);
gst_buffer_unref (buf);
gst_tag_xmp_writer_remove_schema (GST_TAG_XMP_WRITER (test_element), "xap");
buf =
gst_tag_xmp_writer_tag_list_to_xmp_buffer (GST_TAG_XMP_WRITER
(test_element), taglist, TRUE);
taglist2 = gst_tag_list_from_xmp_buffer (buf);
/* artist should be there, but rating shouldn't */
fail_unless (gst_tag_list_peek_string_index (taglist2, GST_TAG_ARTIST, 0,
&str));
fail_unless (gst_tag_list_get_value_index (taglist2, GST_TAG_USER_RATING,
0) == NULL);
gst_tag_list_free (taglist2);
gst_buffer_unref (buf);
gst_object_unref (test_element);
gst_tag_list_free (taglist);
}
GST_END_TEST;
static Suite *
xmp_config_suite (void)
{
Suite *s = suite_create ("xmpconfig interface");
TCase *tc_chain = tcase_create ("configuration");
suite_add_tcase (s, tc_chain);
tcase_add_test (tc_chain, test_no_xmp);
tcase_add_test (tc_chain, test_default);
tcase_add_test (tc_chain, test_disable);
return s;
}
int
main (int argc, char **argv)
{
int nf;
Suite *s = xmp_config_suite ();
SRunner *sr = srunner_create (s);
gst_check_init (&argc, &argv);
srunner_run_all (sr, CK_NORMAL);
nf = srunner_ntests_failed (sr);
srunner_free (sr);
return nf;
}

View file

@ -1,3 +1,4 @@
EXTRA_DIST = \
623663.mts \
hls.m3u8 \
partialframe.mjpeg

15
tests/files/hls.m3u8 Normal file
View file

@ -0,0 +1,15 @@
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=246221
0240/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=38872
0064/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=153059
0150/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=455394
0440/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=650356
0640/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=861738
0840/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1258987
1240/prog_index.m3u8

View file

@ -25,9 +25,18 @@ EXPORTS
gst_tag_list_to_exif_buffer_with_tiff_header
gst_tag_list_to_vorbiscomment_buffer
gst_tag_list_to_xmp_buffer
gst_tag_list_to_xmp_buffer_full
gst_tag_parse_extended_comment
gst_tag_register_musicbrainz_tags
gst_tag_to_id3_tag
gst_tag_to_vorbis_comments
gst_tag_to_vorbis_tag
gst_tag_xmp_list_schemas
gst_tag_xmp_writer_add_all_schemas
gst_tag_xmp_writer_add_schema
gst_tag_xmp_writer_get_type
gst_tag_xmp_writer_has_schema
gst_tag_xmp_writer_remove_all_schemas
gst_tag_xmp_writer_remove_schema
gst_tag_xmp_writer_tag_list_to_xmp_buffer
gst_vorbis_tag_add