Commit 2f4517a7 authored by Alessandro Decina's avatar Alessandro Decina Committed by Wim Taymans
Browse files

ext/annodex/gstannodex.c: Do some extra sanity checks.

Original commit message from CVS:
Patch by: Alessandro Decina <alessandro at nnva dot org>
* ext/annodex/gstannodex.c: (gst_annodex_granule_to_time):
Do some extra sanity checks.
Fixes #350340.
* ext/annodex/gstcmmlenc.c: (gst_cmml_enc_change_state),
(gst_cmml_enc_parse_tag_head), (gst_cmml_enc_parse_tag_clip),
(gst_cmml_enc_push_clip), (gst_cmml_enc_push):
Check if clip->start_time is valid before adding the clip to the
track list.
Reset enc->preamble going from PAUSED to READY.
Don't use GST_FLOW_UNEXPECTED for wrong usage of the element, it is
only used for EOS.
Only post an error message if we were the one that created the fatal
GstFlowReturn value.
* ext/annodex/gstcmmlutils.c: (gst_cmml_clock_time_from_npt),
(gst_cmml_clock_time_to_granule), (gst_cmml_track_list_has_clip):
Parse the seconds field of the npt-sec time format using %llu rather than
%d and check that the value scaled by GST_SECOND doesn't overflow.
Use guint64(s) to represent the keyindex and keyoffset fields of a granulepos.
Lookup a clip's track with clip->track rather than clip->id which
makes no sense.
Identify a clip by its track and start time and not its xml id.
do some more input checking and make sure we don't do undefined shifts.
* tests/check/elements/cmmldec.c: (setup_cmmldec),
(teardown_cmmldec), (check_output_buffer_is_equal), (push_data),
(cmml_tag_message_pop), (check_headers), (push_clip_full),
(push_clip), (push_empty_clip), (check_output_clip),
(GST_START_TEST), (cmmldec_suite):
* tests/check/elements/cmmlenc.c: (setup_cmmlenc),
(teardown_cmmlenc), (check_output_buffer_is_equal), (push_data),
(check_headers), (push_clip), (check_clip_times), (check_clip),
(check_empty_clip), (GST_START_TEST), (cmmlenc_suite):
Added some more checks.
parent 2019f527
2006-08-25 Wim Taymans <wim@fluendo.com>
Patch by: Alessandro Decina <alessandro at nnva dot org>
* ext/annodex/gstannodex.c: (gst_annodex_granule_to_time):
Do some extra sanity checks.
Fixes #350340.
* ext/annodex/gstcmmlenc.c: (gst_cmml_enc_change_state),
(gst_cmml_enc_parse_tag_head), (gst_cmml_enc_parse_tag_clip),
(gst_cmml_enc_push_clip), (gst_cmml_enc_push):
Check if clip->start_time is valid before adding the clip to the
track list.
Reset enc->preamble going from PAUSED to READY.
Don't use GST_FLOW_UNEXPECTED for wrong usage of the element, it is
only used for EOS.
Only post an error message if we were the one that created the fatal
GstFlowReturn value.
* ext/annodex/gstcmmlutils.c: (gst_cmml_clock_time_from_npt),
(gst_cmml_clock_time_to_granule), (gst_cmml_track_list_has_clip):
Parse the seconds field of the npt-sec time format using %llu rather than
%d and check that the value scaled by GST_SECOND doesn't overflow.
Use guint64(s) to represent the keyindex and keyoffset fields of a granulepos.
Lookup a clip's track with clip->track rather than clip->id which
makes no sense.
Identify a clip by its track and start time and not its xml id.
do some more input checking and make sure we don't do undefined shifts.
* tests/check/elements/cmmldec.c: (setup_cmmldec),
(teardown_cmmldec), (check_output_buffer_is_equal), (push_data),
(cmml_tag_message_pop), (check_headers), (push_clip_full),
(push_clip), (push_empty_clip), (check_output_clip),
(GST_START_TEST), (cmmldec_suite):
* tests/check/elements/cmmlenc.c: (setup_cmmlenc),
(teardown_cmmlenc), (check_output_buffer_is_equal), (push_data),
(check_headers), (push_clip), (check_clip_times), (check_clip),
(check_empty_clip), (GST_START_TEST), (cmmlenc_suite):
Added some more checks.
2006-08-24 Stefan Kost <ensonic@users.sf.net>
* gst/audiofxgood/audiopanorama.c: (gst_audio_panorama_class_init),
......
......@@ -39,13 +39,15 @@ gst_annodex_granule_to_time (gint64 granulepos, gint64 granulerate_n,
gint64 granulerate;
GstClockTime res;
g_return_val_if_fail (granuleshift <= 64, GST_CLOCK_TIME_NONE);
if (granulepos == -1)
return GST_CLOCK_TIME_NONE;
if (granulepos == 0 || granulerate_n == 0 || granulerate_d == 0)
return 0;
if (granuleshift != 0) {
if (granuleshift != 0 && granuleshift != 64) {
keyindex = granulepos >> granuleshift;
keyoffset = granulepos - (keyindex << granuleshift);
granulepos = keyindex + keyoffset;
......
......@@ -259,6 +259,7 @@ gst_cmml_enc_change_state (GstElement * element, GstStateChange transition)
gst_cmml_track_list_destroy (enc->tracks);
enc->tracks = NULL;
g_free (enc->preamble);
enc->preamble = NULL;
gst_cmml_parser_free (enc->parser);
break;
}
......@@ -468,7 +469,7 @@ gst_cmml_enc_parse_tag_head (GstCmmlEnc * enc, GstCmmlTagHead * head)
flow_unexpected:
GST_ELEMENT_ERROR (enc, STREAM, ENCODE,
(NULL), ("got head tag before preamble"));
enc->flow_return = GST_FLOW_UNEXPECTED;
enc->flow_return = GST_FLOW_ERROR;
return;
push_error:
gst_caps_unref (caps);
......@@ -507,6 +508,14 @@ gst_cmml_enc_parse_tag_clip (GstCmmlEnc * enc, GstCmmlTagClip * clip)
(gchar *) clip->track);
if (prev_clip) {
prev_clip_time = prev_clip->start_time;
if (prev_clip_time > clip->start_time) {
GST_ELEMENT_ERROR (enc, STREAM, ENCODE,
(NULL), ("previous clip start time > current clip (%s) start time",
clip->id));
enc->flow_return = GST_FLOW_ERROR;
return;
}
/* we don't need the prev clip anymore */
gst_cmml_track_list_del_clip (enc->tracks, prev_clip);
}
......@@ -526,12 +535,6 @@ gst_cmml_enc_push_clip (GstCmmlEnc * enc, GstCmmlTagClip * clip,
gchar *clip_string;
gint64 granulepos;
if (prev_clip_time != GST_CLOCK_TIME_NONE &&
prev_clip_time > clip->start_time) {
GST_WARNING_OBJECT (enc,
"previous clip start time > current clip (%s) start time", clip->id);
}
/* encode the clip */
clip_string =
(gchar *) gst_cmml_parser_tag_clip_to_string (enc->parser, clip);
......@@ -591,8 +594,7 @@ gst_cmml_enc_push (GstCmmlEnc * enc, GstBuffer * buffer)
res = gst_pad_push (enc->srcpad, buffer);
if (GST_FLOW_IS_FATAL (res))
GST_ELEMENT_ERROR (enc, STREAM, ENCODE,
(NULL), ("could not push buffer: %s", gst_flow_get_name (res)));
GST_WARNING_OBJECT (enc, "push returned: %s", gst_flow_get_name (res));
return res;
}
......
......@@ -58,15 +58,17 @@ gst_cmml_clock_time_from_npt (const gchar * time)
seconds_t = seconds * GST_SECOND;
} else {
guint64 u64seconds;
/* parse npt-sec */
hours_t = 0;
minutes = 0;
fields = sscanf (time, "%d.%d", &seconds, &mseconds);
fields = sscanf (time, "%llu.%d", &u64seconds, &mseconds);
if (seconds < 0)
goto bad_input;
seconds_t = gst_util_uint64_scale (seconds, GST_SECOND, 1);
if (seconds == G_MAXUINT64)
seconds_t = gst_util_uint64_scale_int (u64seconds, GST_SECOND, 1);
if (seconds_t == G_MAXUINT64)
goto overflow;
}
......@@ -177,9 +179,13 @@ gst_cmml_clock_time_to_granule (GstClockTime prev_time,
GstClockTime current_time, gint64 granulerate_n, gint64 granulerate_d,
guint8 granuleshift)
{
gint64 keyindex, keyoffset, granulepos;
guint64 keyindex, keyoffset, granulepos, maxoffset;
gint64 granulerate;
g_return_val_if_fail (granulerate_d != 0, -1);
g_return_val_if_fail (granuleshift > 0, -1);
g_return_val_if_fail (granuleshift <= 64, -1);
if (prev_time == GST_CLOCK_TIME_NONE)
prev_time = 0;
......@@ -191,14 +197,23 @@ gst_cmml_clock_time_to_granule (GstClockTime prev_time,
granulerate_d, granulerate_n);
prev_time = prev_time / granulerate;
if (prev_time > (((guint64) 1 << (64 - granuleshift)) - 1))
/* granuleshift == 64 should be a << 0 shift, which is defined */
maxoffset = ((guint64) 1 << (64 - granuleshift)) - 1;
if (prev_time > maxoffset)
/* we need more than 64 - granuleshift bits to encode prev_time */
goto overflow;
keyindex = prev_time << granuleshift;
keyoffset = (current_time / granulerate) - prev_time;
if (keyoffset > ((guint64) 1 << granuleshift) - 1)
/* make sure we don't shift to the limits of the types as this is undefined. */
if (granuleshift == 64)
maxoffset = G_MAXUINT64;
else
maxoffset = ((guint64) 1 << granuleshift) - 1;
if (keyoffset > maxoffset)
/* we need more than granuleshift bits to encode prev_time - current_time */
goto overflow;
......@@ -301,16 +316,13 @@ gst_cmml_track_list_has_clip (GHashTable * tracks, GstCmmlTagClip * clip)
GstCmmlTrack *track;
GList *walk;
GstCmmlTagClip *tmp;
gchar *clip_id = (gchar *) clip->id;
gboolean res = FALSE;
g_return_val_if_fail (clip_id != NULL, FALSE);
track = g_hash_table_lookup (tracks, clip_id);
track = g_hash_table_lookup (tracks, (gchar *) clip->track);
if (track) {
for (walk = track->clips; walk; walk = g_list_next (walk)) {
tmp = GST_CMML_TAG_CLIP (walk->data);
if (!strcmp ((gchar *) tmp->id, clip_id)) {
if (tmp->start_time == clip->start_time) {
res = TRUE;
break;
}
......
......@@ -22,7 +22,6 @@
*/
#include <gst/check/gstcheck.h>
#include <gst/tag/tag.h>
#define SINK_CAPS "text/x-cmml"
......@@ -34,16 +33,13 @@
"\xe8\x03\x00\x00\x00\x00\x00\x00"\
"\x01\x00\x00\x00\x00\x00\x00\x00"\
"\x20"
#define IDENT_HEADER_SIZE 29
#define XML_PREAMBLE \
#define PREAMBLE_NO_PI \
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"\
"<!DOCTYPE cmml SYSTEM \"cmml.dtd\">\n"\
#define PREAMBLE \
XML_PREAMBLE "<?cmml?>"
#define PREAMBLE_DECODED \
XML_PREAMBLE "<cmml >"
"<!DOCTYPE cmml SYSTEM \"cmml.dtd\">\n"
#define PREAMBLE PREAMBLE_NO_PI "<?cmml?>"
#define PREAMBLE_DECODED PREAMBLE_NO_PI "<cmml >"
#define HEAD_TAG \
"<head>"\
......@@ -73,15 +69,31 @@
"<meta name=\"test\" content=\"test content\"/>"\
"</clip>"
#define EMPTY_CLIP_TEMPLATE \
"<clip id=\"%s\" track=\"%s\" />"
#define END_TAG \
"</cmml>"
#define fail_unless_equals_flow_return(a, b) \
G_STMT_START { \
gchar *a_up = g_ascii_strup (gst_flow_get_name (a), -1); \
gchar *b_up = g_ascii_strup (gst_flow_get_name (b), -1); \
fail_unless (a == b, \
"'" #a "' (GST_FLOW_%s) is not equal to '" #b "' (GST_FLOW_%s)", \
a_up, b_up); \
g_free (a_up); \
g_free (b_up); \
} G_STMT_END;
static GstElement *cmmldec;
static GstBus *bus;
static GstFlowReturn flow;
GList *buffers;
GList *current_buf = NULL;
gint64 granulerate;
guint8 granuleshift;
GstPad *srcpad, *sinkpad;
static GList *current_buf;
static gint64 granulerate;
static guint8 granuleshift;
static GstPad *srcpad, *sinkpad;
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
......@@ -117,12 +129,9 @@ buffer_unref (void *buffer, void *user_data)
gst_buffer_unref (GST_BUFFER (buffer));
}
GstElement *
static void
setup_cmmldec ()
{
GstElement *cmmldec;
GstBus *bus;
GST_DEBUG ("setup_cmmldec");
cmmldec = gst_check_setup_element ("cmmldec");
srcpad = gst_check_setup_src_pad (cmmldec, &srctemplate, NULL);
......@@ -138,23 +147,20 @@ setup_cmmldec ()
granulerate = GST_SECOND / 1000;
granuleshift = 32;
buffers = NULL;
return cmmldec;
}
static void
cleanup_cmmldec (GstElement * cmmldec)
teardown_cmmldec ()
{
GstBus *bus;
g_list_foreach (buffers, buffer_unref, NULL);
g_list_free (buffers);
buffers = NULL;
current_buf = NULL;
bus = GST_ELEMENT_BUS (cmmldec);
gst_bus_set_flushing (bus, TRUE);
gst_object_unref (bus);
GST_DEBUG ("cleanup_cmmldec");
GST_DEBUG ("teardown_cmmldec");
gst_check_teardown_src_pad (cmmldec);
gst_check_teardown_sink_pad (cmmldec);
gst_check_teardown_element (cmmldec);
......@@ -164,7 +170,16 @@ static void
check_output_buffer_is_equal (const gchar * name,
const gchar * data, gint refcount)
{
GstBuffer *buffer = GST_BUFFER (current_buf->data);
GstBuffer *buffer;
if (current_buf == NULL)
current_buf = buffers;
else
current_buf = g_list_next (current_buf);
fail_unless (current_buf != NULL);
buffer = GST_BUFFER (current_buf->data);
ASSERT_OBJECT_REFCOUNT (buffer, name, refcount);
fail_unless (memcmp (GST_BUFFER_DATA (buffer), data,
......@@ -172,63 +187,128 @@ check_output_buffer_is_equal (const gchar * name,
"'%s' (%s) is not equal to (%s)", name, GST_BUFFER_DATA (buffer), data);
}
static void
push_data (const gchar * name,
const gchar * data, gint size, gint64 granulepos,
GstFlowReturn expected_return)
static GstFlowReturn
push_data (const gchar * name, const gchar * data, gint size, gint64 granulepos)
{
GstBuffer *buffer;
GstFlowReturn res;
buffer = buffer_new (data, size);
GST_BUFFER_OFFSET_END (buffer) = granulepos;
res = gst_pad_push (srcpad, buffer);
fail_unless (res == expected_return,
"pushing %s returned %d not %d", name, res, expected_return);
return gst_pad_push (srcpad, buffer);
}
static GObject *
cmml_tag_message_pop (GstBus * bus, const gchar * tag)
{
GstMessage *message;
GstTagList *taglist;
const GValue *value;
GObject *obj;
message = gst_bus_poll (bus, GST_MESSAGE_TAG, 0);
if (message == NULL)
return NULL;
gst_message_parse_tag (message, &taglist);
value = gst_tag_list_get_value_index (taglist, tag, 0);
if (value == NULL) {
gst_message_unref (message);
gst_tag_list_free (taglist);
return NULL;
}
obj = g_value_dup_object (value);
gst_message_unref (message);
gst_tag_list_free (taglist);
return obj;
}
static void
check_headers ()
{
GObject *head_tag;
gchar *title, *base;
GValueArray *meta;
/* push the ident header */
push_data ("ident-header", IDENT_HEADER, 29, 0, GST_FLOW_OK);
/* push the cmml start tag */
push_data ("preamble", PREAMBLE, strlen (PREAMBLE), 0, GST_FLOW_OK);
flow = push_data ("ident-header", IDENT_HEADER, IDENT_HEADER_SIZE, 0);
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
/* push the cmml preamble */
flow = push_data ("preamble", PREAMBLE, strlen (PREAMBLE), 0);
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
/* push the head tag */
push_data ("head", HEAD_TAG, strlen (HEAD_TAG), 0, GST_FLOW_OK);
flow = push_data ("head", HEAD_TAG, strlen (HEAD_TAG), 0);
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
current_buf = buffers;
fail_unless_equals_int (g_list_length (current_buf), 2);
fail_unless_equals_int (g_list_length (buffers), 2);
/* check the preamble */
/* check the decoded preamble */
check_output_buffer_is_equal ("cmml-preamble-buffer", PREAMBLE_DECODED, 1);
/* check the decoded head tag */
current_buf = current_buf->next;
check_output_buffer_is_equal ("head-tag-buffer", HEAD_TAG_DECODED, 1);
/* check the GstCmmlTagHead tag object */
head_tag = cmml_tag_message_pop (bus, GST_TAG_CMML_HEAD);
fail_unless (head_tag != NULL);
g_object_get (head_tag,
"title", &title, "base-uri", &base, "meta", &meta, NULL);
fail_unless_equals_string ("The Research Hunter", title);
fail_unless (base == NULL);
fail_unless (meta != NULL);
fail_unless_equals_int (meta->n_values, 10);
g_free (title);
g_free (base);
g_value_array_free (meta);
g_object_unref (head_tag);
}
static void
push_clip (const gchar * name, const gchar * track, GstClockTime prev,
GstClockTime start, GstClockTime end, GstFlowReturn expected_return)
static GstFlowReturn
push_clip_full (const gchar * name, const gchar * track, const gchar * template,
GstClockTime prev, GstClockTime start)
{
gchar *clip;
gint64 keyindex, keyoffset, granulepos;
GstFlowReturn res;
if (track == NULL)
track = "default";
if (prev == GST_CLOCK_TIME_NONE)
prev = 0;
keyindex = prev / granulerate << granuleshift;
keyoffset = (start - prev) / granulerate;
granulepos = keyindex + keyoffset;
clip = g_strdup_printf (CLIP_TEMPLATE, name, track);
push_data (name, clip, strlen (clip), granulepos, expected_return);
clip = g_strdup_printf (template, name, track);
res = push_data (name, clip, strlen (clip), granulepos);
g_free (clip);
return res;
}
static GstFlowReturn
push_clip (const gchar * name, const gchar * track,
GstClockTime prev, GstClockTime start)
{
return push_clip_full (name, track, CLIP_TEMPLATE, prev, start);
}
static GstFlowReturn
push_empty_clip (const gchar * name, const gchar * track, GstClockTime start)
{
return push_clip_full (name, track,
EMPTY_CLIP_TEMPLATE, GST_CLOCK_TIME_NONE, start);
}
static void
check_clip (const gchar * name, const gchar * track,
check_output_clip (const gchar * name, const gchar * track,
const gchar * start, const gchar * end)
{
gchar *decoded_clip;
......@@ -236,58 +316,60 @@ check_clip (const gchar * name, const gchar * track,
if (track == NULL)
track = "default";
current_buf = current_buf->next;
fail_unless (g_list_length (current_buf));
decoded_clip = g_strdup_printf (CLIP_TEMPLATE_DECODED, name, track, start);
check_output_buffer_is_equal (name, decoded_clip, 1);
g_free (decoded_clip);
}
static void
check_end ()
{
current_buf = current_buf->next;
check_output_buffer_is_equal ("cmml-end-tag", END_TAG, 1);
}
GST_START_TEST (test_dec)
{
GstElement *cmmldec;
cmmldec = setup_cmmldec ();
GstClockTime clip1_start = 1 * GST_SECOND + 234 * GST_MSECOND;
GstClockTime clip2_start = clip1_start;
GstClockTime clip3_start =
((100 * 3600) + (59 * 60) + 59) * GST_SECOND + 678 * GST_MSECOND;
check_headers ();
push_clip ("clip-1", "default",
0, 1 * GST_SECOND + 234 * GST_MSECOND, 0, GST_FLOW_OK);
push_clip ("clip-2", "othertrack",
0, 4 * GST_SECOND + 321 * GST_MSECOND, 0, GST_FLOW_OK);
push_clip ("clip-3", "default",
1 * GST_SECOND + 234 * GST_MSECOND,
((100 * 3600) + (59 * 60) + 59) * GST_SECOND + 678 * GST_MSECOND, 0,
GST_FLOW_OK);
flow = push_clip ("clip-1", "default", GST_CLOCK_TIME_NONE, clip1_start);
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
flow = push_clip ("clip-2", "othertrack", GST_CLOCK_TIME_NONE, clip2_start);
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
flow = push_clip ("clip-3", "default", clip1_start, clip3_start);
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
/* send EOS to flush clip-2 and clip-3 */
gst_pad_send_event (GST_PAD_PEER (srcpad), gst_event_new_eos ());
check_clip ("clip-1", "default", "0:00:01.234", NULL);
check_clip ("clip-2", "othertrack", "0:00:04.321", NULL);
check_clip ("clip-3", "default", "100:59:59.678", NULL);
check_end ();
check_output_clip ("clip-1", "default", "0:00:01.234", NULL);
check_output_clip ("clip-2", "othertrack", "0:00:01.234", NULL);
check_output_clip ("clip-3", "default", "100:59:59.678", NULL);
check_output_buffer_is_equal ("cmml-end-tag", END_TAG, 1);
}
GST_END_TEST;
cleanup_cmmldec (cmmldec);
GST_START_TEST (test_preamble_no_pi)
{
flow = push_data ("ident-header", IDENT_HEADER, IDENT_HEADER_SIZE, 0);
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
fail_unless_equals_int (g_list_length (buffers), 0);
flow = push_data ("preamble-no-pi",
PREAMBLE_NO_PI, strlen (PREAMBLE_NO_PI), 0);
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
fail_unless_equals_int (g_list_length (buffers), 1);
check_output_buffer_is_equal ("cmml-preamble-buffer",
PREAMBLE_NO_PI "<cmml>", 1);
}
GST_END_TEST;
GST_START_TEST (test_tags)
{
GstElement *cmmldec;
GstBus *bus;
GstMessage *message;
GstTagList *tags;
const GValue *tag_val;
GObject *tag;
gchar *title, *base;
gboolean empty;
gchar *id, *track;
gint64 start_time, end_time;
......@@ -295,51 +377,15 @@ GST_START_TEST (test_tags)
gchar *img_src, *img_alt;
gchar *desc;
GValueArray *meta;
cmmldec = setup_cmmldec ();
bus = gst_element_get_bus (cmmldec);
GstClockTime clip1_start;
check_headers ();
/* read the GstCmmlTagHead tag */
message = gst_bus_poll (bus, GST_MESSAGE_TAG, -1);
fail_unless (message != NULL);
gst_message_parse_tag (message, &tags);
fail_unless (tags != NULL);
clip1_start = 1 * GST_SECOND + 234 * GST_MSECOND;
flow = push_clip ("clip-1", "default", 0, clip1_start);
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
tag_val = gst_tag_list_get_value_index (tags, GST_TAG_CMML_HEAD, 0);
fail_unless (tag_val != NULL);
tag = g_value_get_object (tag_val);
fail_unless (tag != NULL);
g_object_get (tag, "title", &title, "base-uri", &base, "meta", &meta, NULL);
fail_unless_equals_string ("The Research Hunter", title);
fail_unless (base == NULL);
fail_unless (meta != NULL);
fail_unless_equals_int (meta->n_values, 10);
gst_message_unref (message);
gst_tag_list_free (tags);
g_free (title);
g_free (base);
g_value_array_free (meta);
push_clip ("clip-1", "default",
0, 1 * GST_SECOND + 234 * GST_MSECOND, 0, GST_FLOW_OK);
/* read the GstCmmlTagClip */
message = gst_bus_poll (bus, GST_MESSAGE_TAG, -1);
fail_unless (message != NULL);
gst_message_parse_tag (message, &tags);
fail_unless (tags != NULL);
tag_val = gst_tag_list_get_value_index (tags, GST_TAG_CMML_CLIP, 0);
fail_unless (tag_val != NULL);
tag = g_value_get_object (tag_val);
tag = cmml_tag_message_pop (bus, GST_TAG_CMML_CLIP);
fail_unless (tag != NULL);
g_object_get (tag, "id", &id, "empty", &empty, "track", &track,
......@@ -369,40 +415,149 @@ GST_START_TEST (test_tags)
g_free (img_alt);
g_free (desc);
g_value_array_free (meta);
gst_tag_list_free (tags);
gst_message_unref (message);