mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-25 01:30:38 +00:00
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.
This commit is contained in:
parent
2019f527f7
commit
2f4517a70b
6 changed files with 618 additions and 295 deletions
40
ChangeLog
40
ChangeLog
|
@ -1,3 +1,43 @@
|
|||
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>"
|
||||
|
||||
GList *buffers;
|
||||
GList *current_buf = NULL;
|
||||
gint64 granulerate;
|
||||
guint8 granuleshift;
|
||||
#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;
|
||||
|
||||
GstPad *srcpad, *sinkpad;
|
||||
static GstElement *cmmldec;
|
||||
static GstBus *bus;
|
||||
static GstFlowReturn flow;
|
||||
GList *buffers;
|
||||
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);
|
||||
}
|
||||
|
||||
cleanup_cmmldec (cmmldec);
|
||||
GST_END_TEST;
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
gst_message_parse_tag (message, &tags);
|
||||
fail_unless (tags != NULL);
|
||||
|
||||
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,10 +415,129 @@ 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);
|
||||
gst_object_unref (bus);
|
||||
cleanup_cmmldec (cmmldec);
|
||||
g_object_unref (tag);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (test_wait_clip_end)
|
||||
{
|
||||
GObject *tag;
|
||||
gchar *id;
|
||||
GstClockTime end_time = 0;
|
||||
|
||||
g_object_set (cmmldec, "wait-clip-end-time", TRUE, NULL);
|
||||
|
||||
check_headers ();
|
||||
|
||||
GstClockTime clip1_start = 1 * GST_SECOND + 234 * GST_MSECOND;
|
||||
GstClockTime clip2_start = 2 * GST_SECOND + 234 * GST_MSECOND;
|
||||
GstClockTime clip3_start = 3 * GST_SECOND + 234 * GST_MSECOND;
|
||||
GstClockTime clip3_end = 4 * GST_SECOND + 234 * GST_MSECOND;
|
||||
GstClockTime clip4_start = 5 * GST_SECOND + 234 * GST_MSECOND;
|
||||
|
||||
flow = push_clip ("clip-1", "default", 0, clip1_start);
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
|
||||
/* no tag has been posted yet */
|
||||
fail_unless (cmml_tag_message_pop (bus, GST_TAG_CMML_CLIP) == NULL);
|
||||
|
||||
flow = push_clip ("clip-2", "default", clip1_start, clip2_start);
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
|
||||
|
||||
tag = cmml_tag_message_pop (bus, GST_TAG_CMML_CLIP);
|
||||
fail_unless (tag != NULL);
|
||||
g_object_get (tag, "id", &id, "end-time", &end_time, NULL);
|
||||
/* clip-1 is posted when clip-2 is decoded. clip-1 ends when clip-2 starts */
|
||||
fail_unless_equals_string (id, "clip-1");
|
||||
fail_unless_equals_int (end_time, clip2_start);
|
||||
g_free (id);
|
||||
g_object_unref (tag);
|
||||
|
||||
flow = push_clip ("clip-3", "default", clip2_start, clip3_start);
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
|
||||
|
||||
tag = cmml_tag_message_pop (bus, GST_TAG_CMML_CLIP);
|
||||
fail_unless (tag != NULL);
|
||||
g_object_get (tag, "id", &id, "end-time", &end_time, NULL);
|
||||
/* clip-2 is posted when clip-3 is decoded. It ends when clip-3 starts */
|
||||
fail_unless_equals_string (id, "clip-2");
|
||||
fail_unless_equals_int (end_time, clip3_start);
|
||||
g_free (id);
|
||||
g_object_unref (tag);
|
||||
|
||||
flow = push_empty_clip ("empty-clip", "default", clip3_end);
|
||||
tag = cmml_tag_message_pop (bus, GST_TAG_CMML_CLIP);
|
||||
fail_unless (tag != NULL);
|
||||
g_object_get (tag, "id", &id, "end-time", &end_time, NULL);
|
||||
/* clip-3 ends when empty-clip is decoded */
|
||||
fail_unless_equals_string (id, "clip-3");
|
||||
fail_unless_equals_int (end_time, clip3_end);
|
||||
g_free (id);
|
||||
g_object_unref (tag);
|
||||
|
||||
flow = push_clip ("clip-4", "default", clip3_start, clip4_start);
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
|
||||
|
||||
/* an empty clip just marks the end of the previous one, so no tag is posted
|
||||
* for empty-clip */
|
||||
fail_unless (cmml_tag_message_pop (bus, GST_TAG_CMML_CLIP) == NULL);
|
||||
/* send EOS to flush clip-4 */
|
||||
gst_pad_send_event (GST_PAD_PEER (srcpad), gst_event_new_eos ());
|
||||
|
||||
tag = cmml_tag_message_pop (bus, GST_TAG_CMML_CLIP);
|
||||
fail_unless (tag != NULL);
|
||||
g_object_get (tag, "id", &id, NULL);
|
||||
fail_unless_equals_string (id, "clip-4");
|
||||
g_free (id);
|
||||
g_object_unref (tag);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (test_weird_input)
|
||||
{
|
||||
const gchar *bad_xml = "<?xml version=\"1.0\"?><a><b></a>";
|
||||
|
||||
/* malformed ident header */
|
||||
flow = push_data ("bad-ident-header", "CMML\0\0\0\0garbage", 15, 0);
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_ERROR);
|
||||
|
||||
/* push invalid xml */
|
||||
flow = push_data ("bad-xml", bad_xml, strlen (bad_xml), 0);
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_ERROR);
|
||||
|
||||
/* and now for something completely different: an empty buffer. This is valid
|
||||
* as 'NIL' EOS pages are allowed */
|
||||
flow = push_data ("empty-eos", NULL, 0, 0);
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (test_sink_query_convert)
|
||||
{
|
||||
guint64 keyindex, keyoffset, granulepos;
|
||||
GstClockTime index_time, offset_time;
|
||||
GstFormat dstfmt = GST_FORMAT_TIME;
|
||||
gint64 dstval;
|
||||
|
||||
/* send headers to set the granulerate */
|
||||
check_headers ();
|
||||
|
||||
/* create a 1|1 granulepos */
|
||||
index_time = 1 * GST_SECOND;
|
||||
offset_time = 1 * GST_SECOND;
|
||||
|
||||
keyindex = (index_time / granulerate) << granuleshift;
|
||||
keyoffset = offset_time / granulerate;
|
||||
granulepos = keyindex + keyoffset;
|
||||
|
||||
fail_unless (gst_pad_query_convert (GST_PAD_PEER (srcpad),
|
||||
GST_FORMAT_DEFAULT, granulepos, &dstfmt, &dstval));
|
||||
|
||||
fail_unless (dstfmt == GST_FORMAT_TIME);
|
||||
/* fail unless dstval == index + offset */
|
||||
fail_unless_equals_int (2 * GST_SECOND, dstval);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
@ -381,28 +546,18 @@ Suite *
|
|||
cmmldec_suite ()
|
||||
{
|
||||
Suite *s = suite_create ("cmmldec");
|
||||
TCase *tc_chain = tcase_create ("general");
|
||||
TCase *tc_general = tcase_create ("general");
|
||||
|
||||
suite_add_tcase (s, tc_chain);
|
||||
tcase_add_test (tc_chain, test_dec);
|
||||
tcase_add_test (tc_chain, test_tags);
|
||||
suite_add_tcase (s, tc_general);
|
||||
tcase_add_checked_fixture (tc_general, setup_cmmldec, teardown_cmmldec);
|
||||
tcase_add_test (tc_general, test_dec);
|
||||
tcase_add_test (tc_general, test_tags);
|
||||
tcase_add_test (tc_general, test_preamble_no_pi);
|
||||
tcase_add_test (tc_general, test_wait_clip_end);
|
||||
tcase_add_test (tc_general, test_sink_query_convert);
|
||||
tcase_add_test (tc_general, test_weird_input);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int nf;
|
||||
|
||||
Suite *s = cmmldec_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;
|
||||
}
|
||||
GST_CHECK_MAIN (cmmldec);
|
||||
|
|
|
@ -71,9 +71,6 @@
|
|||
|
||||
#define HEAD_TAG_ENCODED HEAD_TAG
|
||||
|
||||
#define END_TAG \
|
||||
"</cmml>"
|
||||
|
||||
#define CLIP_TEMPLATE \
|
||||
"<clip id=\"%s\" track=\"%s\" start=\"%s\">"\
|
||||
"<a href=\"http://www.annodex.org/\">http://www.annodex.org</a>"\
|
||||
|
@ -82,6 +79,14 @@
|
|||
"<meta name=\"test\" content=\"test content\"/>"\
|
||||
"</clip>"
|
||||
|
||||
#define ENDED_CLIP_TEMPLATE \
|
||||
"<clip id=\"%s\" track=\"%s\" start=\"%s\" end=\"%s\">"\
|
||||
"<a href=\"http://www.annodex.org/\">http://www.annodex.org</a>"\
|
||||
"<img src=\"images/index.jpg\"/>"\
|
||||
"<desc>Annodex Foundation</desc>"\
|
||||
"<meta name=\"test\" content=\"test content\"/>"\
|
||||
"</clip>"
|
||||
|
||||
#define CLIP_TEMPLATE_ENCODED \
|
||||
"<clip id=\"%s\" track=\"%s\">"\
|
||||
"<a href=\"http://www.annodex.org/\">http://www.annodex.org</a>"\
|
||||
|
@ -90,12 +95,28 @@
|
|||
"<meta name=\"test\" content=\"test content\"/>"\
|
||||
"</clip>"
|
||||
|
||||
GList *buffers;
|
||||
GList *current_buf = NULL;
|
||||
guint64 granulerate;
|
||||
guint8 granuleshift;
|
||||
#define EMPTY_CLIP_TEMPLATE_ENCODED \
|
||||
"<clip track=\"%s\"/>"
|
||||
|
||||
GstPad *srcpad, *sinkpad;
|
||||
#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;
|
||||
|
||||
GList *buffers;
|
||||
static GList *current_buf;
|
||||
static guint64 granulerate;
|
||||
static guint8 granuleshift;
|
||||
static GstElement *cmmlenc;
|
||||
static GstBus *bus;
|
||||
static GstFlowReturn flow;
|
||||
static GstPad *srcpad, *sinkpad;
|
||||
|
||||
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
|
@ -109,7 +130,7 @@ static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
|
|||
GST_STATIC_CAPS (SRC_CAPS)
|
||||
);
|
||||
|
||||
GstBuffer *
|
||||
static GstBuffer *
|
||||
buffer_new (const gchar * buffer_data, guint size)
|
||||
{
|
||||
GstBuffer *buffer;
|
||||
|
@ -130,11 +151,9 @@ buffer_unref (void *buffer, void *user_data)
|
|||
gst_buffer_unref (GST_BUFFER (buffer));
|
||||
}
|
||||
|
||||
GstElement *
|
||||
static void
|
||||
setup_cmmlenc ()
|
||||
{
|
||||
GstElement *cmmlenc;
|
||||
GstBus *bus;
|
||||
guint64 granulerate_n, granulerate_d;
|
||||
|
||||
GST_DEBUG ("setup_cmmlenc");
|
||||
|
@ -155,25 +174,21 @@ setup_cmmlenc ()
|
|||
"granule-shift", &granuleshift, NULL);
|
||||
|
||||
granulerate = GST_SECOND * granulerate_d / granulerate_n;
|
||||
buffers = NULL;
|
||||
return cmmlenc;
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup_cmmlenc (GstElement * cmmlenc)
|
||||
teardown_cmmlenc ()
|
||||
{
|
||||
GstBus *bus;
|
||||
|
||||
/* free encoded buffers */
|
||||
g_list_foreach (buffers, buffer_unref, NULL);
|
||||
g_list_free (buffers);
|
||||
buffers = NULL;
|
||||
current_buf = NULL;
|
||||
|
||||
bus = GST_ELEMENT_BUS (cmmlenc);
|
||||
gst_bus_set_flushing (bus, TRUE);
|
||||
gst_object_unref (bus);
|
||||
|
||||
GST_DEBUG ("cleanup_cmmlenc");
|
||||
GST_DEBUG ("teardown_cmmlenc");
|
||||
gst_check_teardown_src_pad (cmmlenc);
|
||||
gst_check_teardown_sink_pad (cmmlenc);
|
||||
gst_check_teardown_element (cmmlenc);
|
||||
|
@ -183,7 +198,15 @@ 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,
|
||||
|
@ -191,58 +214,75 @@ 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, GstFlowReturn expected_return)
|
||||
static GstFlowReturn
|
||||
push_data (const gchar * name, const gchar * data, gint size)
|
||||
{
|
||||
GstBuffer *buffer;
|
||||
GstFlowReturn res;
|
||||
|
||||
buffer = buffer_new (data, size);
|
||||
res = gst_pad_push (srcpad, buffer);
|
||||
fail_unless (res == expected_return,
|
||||
"pushing %s returned %d not %d", name, res, expected_return);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
check_headers ()
|
||||
{
|
||||
/* push the cmml start tag */
|
||||
push_data ("preamble", PREAMBLE, strlen (PREAMBLE), GST_FLOW_OK);
|
||||
/* push the stream tag */
|
||||
push_data ("stream", STREAM_TAG, strlen (STREAM_TAG), GST_FLOW_OK);
|
||||
/* push the head tag */
|
||||
push_data ("head", HEAD_TAG, strlen (HEAD_TAG), GST_FLOW_OK);
|
||||
flow = push_data ("preamble", PREAMBLE, strlen (PREAMBLE));
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
|
||||
|
||||
/* should output the cmml ident header and the cmml start tag transformed
|
||||
* into a processing instruction */
|
||||
current_buf = buffers;
|
||||
fail_unless_equals_int (g_list_length (current_buf), 3);
|
||||
/* push the stream tag */
|
||||
flow = push_data ("stream", STREAM_TAG, strlen (STREAM_TAG));
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
|
||||
/* push the head tag */
|
||||
flow = push_data ("head", HEAD_TAG, strlen (HEAD_TAG));
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
|
||||
|
||||
/* should output 3 buffers: the ident, preamble and head headers */
|
||||
fail_unless_equals_int (g_list_length (buffers), 3);
|
||||
|
||||
/* check the ident header */
|
||||
check_output_buffer_is_equal ("cmml-ident-buffer", IDENT_HEADER, 1);
|
||||
|
||||
/* check the cmml processing instruction */
|
||||
current_buf = current_buf->next;
|
||||
check_output_buffer_is_equal ("cmml-preamble-buffer", PREAMBLE_ENCODED, 1);
|
||||
|
||||
/* check the encoded head tag */
|
||||
current_buf = current_buf->next;
|
||||
check_output_buffer_is_equal ("head-tag-buffer", HEAD_TAG_ENCODED, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
static GstFlowReturn
|
||||
push_clip (const gchar * name, const gchar * track,
|
||||
const gchar * start, const gchar * end, GstFlowReturn expected_return)
|
||||
const gchar * start, const gchar * end)
|
||||
{
|
||||
gchar *clip;
|
||||
GstFlowReturn res;
|
||||
|
||||
if (track == NULL)
|
||||
track = "default";
|
||||
|
||||
if (end != NULL)
|
||||
clip = g_strdup_printf (ENDED_CLIP_TEMPLATE, name, track, start, end);
|
||||
else
|
||||
clip = g_strdup_printf (CLIP_TEMPLATE, name, track, start);
|
||||
push_data (name, clip, strlen (clip), expected_return);
|
||||
res = push_data (name, clip, strlen (clip));
|
||||
g_free (clip);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
check_clip_times (GstBuffer * buffer, GstClockTime start, GstClockTime prev)
|
||||
{
|
||||
guint64 keyindex, keyoffset, granulepos;
|
||||
|
||||
granulepos = GST_BUFFER_OFFSET_END (buffer);
|
||||
if (granuleshift == 0 || granuleshift == 64)
|
||||
keyindex = 0;
|
||||
else
|
||||
keyindex = granulepos >> granuleshift;
|
||||
keyoffset = granulepos - (keyindex << granuleshift);
|
||||
fail_unless_equals_uint64 (keyindex * granulerate, prev);
|
||||
fail_unless_equals_uint64 ((keyindex + keyoffset) * granulerate, start);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -251,126 +291,198 @@ check_clip (const gchar * name, const gchar * track,
|
|||
{
|
||||
gchar *encoded_clip;
|
||||
GstBuffer *buffer;
|
||||
gint64 keyindex, keyoffset, granulepos;
|
||||
|
||||
if (track == NULL)
|
||||
track = "default";
|
||||
|
||||
current_buf = current_buf->next;
|
||||
fail_unless (g_list_length (current_buf));
|
||||
encoded_clip = g_strdup_printf (CLIP_TEMPLATE_ENCODED, name, track);
|
||||
check_output_buffer_is_equal (name, encoded_clip, 1);
|
||||
g_free (encoded_clip);
|
||||
buffer = GST_BUFFER (current_buf->data);
|
||||
granulepos = GST_BUFFER_OFFSET_END (GST_BUFFER (buffer));
|
||||
keyindex = granulepos >> granuleshift;
|
||||
keyoffset = granulepos - (keyindex << granuleshift);
|
||||
fail_unless_equals_uint64 (keyindex * granulerate, prev);
|
||||
fail_unless_equals_uint64 ((keyindex + keyoffset) * granulerate, start);
|
||||
check_clip_times (buffer, start, prev);
|
||||
}
|
||||
|
||||
static void
|
||||
push_end ()
|
||||
check_empty_clip (const gchar * name, const gchar * track,
|
||||
GstClockTime start, GstClockTime prev)
|
||||
{
|
||||
push_data ("end", END_TAG, strlen (END_TAG), GST_FLOW_OK);
|
||||
}
|
||||
gchar *encoded_clip;
|
||||
GstBuffer *buffer;
|
||||
|
||||
static void
|
||||
check_end ()
|
||||
{
|
||||
/* should output the EOS page */
|
||||
current_buf = current_buf->next;
|
||||
fail_unless_equals_int (g_list_length (current_buf), 1);
|
||||
check_output_buffer_is_equal ("cmml-eos-buffer", NULL, 1);
|
||||
encoded_clip = g_strdup_printf (EMPTY_CLIP_TEMPLATE_ENCODED, track);
|
||||
check_output_buffer_is_equal (name, encoded_clip, 1);
|
||||
g_free (encoded_clip);
|
||||
buffer = GST_BUFFER (current_buf->data);
|
||||
check_clip_times (buffer, start, prev);
|
||||
}
|
||||
|
||||
GST_START_TEST (test_enc)
|
||||
{
|
||||
GstElement *cmmlenc;
|
||||
|
||||
cmmlenc = setup_cmmlenc ();
|
||||
|
||||
check_headers ();
|
||||
|
||||
push_clip ("clip-1", "default", "1.234", NULL, GST_FLOW_OK);
|
||||
check_clip ("clip-1", "default", 1234 * granulerate, 0);
|
||||
flow = push_clip ("clip-1", "default", "1.234", NULL);
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
|
||||
check_clip ("clip-1", "default", 1 * GST_SECOND + 234 * GST_MSECOND, 0);
|
||||
|
||||
push_clip ("clip-2", NULL, "5.678", NULL, GST_FLOW_OK);
|
||||
check_clip ("clip-2", "default", 5678 * granulerate, 1234 * granulerate);
|
||||
flow = push_clip ("clip-2", "default", "5.678", NULL);
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
|
||||
check_clip ("clip-2", "default",
|
||||
5 * GST_SECOND + 678 * GST_MSECOND, 1 * GST_SECOND + 234 * GST_MSECOND);
|
||||
|
||||
push_clip ("clip-3", "othertrack", "9.123", NULL, GST_FLOW_OK);
|
||||
check_clip ("clip-3", "othertrack", 9123 * granulerate, 0);
|
||||
flow = push_clip ("clip-3", "othertrack", "9.123", NULL);
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
|
||||
check_clip ("clip-3", "othertrack", 9 * GST_SECOND + 123 * GST_MSECOND, 0);
|
||||
|
||||
push_end ();
|
||||
check_end ();
|
||||
|
||||
cleanup_cmmlenc (cmmlenc);
|
||||
flow = push_data ("end-tag", "</cmml>", strlen ("</cmml>"));
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
|
||||
check_output_buffer_is_equal ("cmml-eos", NULL, 1);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (test_bad_start_time)
|
||||
GST_START_TEST (test_clip_end_time)
|
||||
{
|
||||
GstElement *cmmlenc;
|
||||
|
||||
cmmlenc = setup_cmmlenc ();
|
||||
|
||||
check_headers ();
|
||||
|
||||
push_clip ("clip-1", "default", "1000:00:00.000", NULL, GST_FLOW_OK);
|
||||
check_clip ("clip-1", "default", (guint64) 3600000 * 1000 * granulerate, 0);
|
||||
/* push a clip that starts at 1.234 an ends at 2.234 */
|
||||
flow = push_clip ("clip-1", "default", "1.234", "2.234");
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
|
||||
check_clip ("clip-1", "default", 1 * GST_SECOND + 234 * GST_MSECOND, 0);
|
||||
|
||||
/* keyindex overflow: npt:1000:00:00.000 doesn't fit in 32 bits */
|
||||
push_clip ("clip-2", NULL, "5.678", NULL, GST_FLOW_ERROR);
|
||||
/* now check that the encoder created an empty clip starting at 2.234 to mark
|
||||
* the end of clip-1 */
|
||||
check_empty_clip ("clip-1-end", "default",
|
||||
2 * GST_SECOND + 234 * GST_MSECOND, 1 * GST_SECOND + 234 * GST_MSECOND);
|
||||
|
||||
/* other tracks should work */
|
||||
push_clip ("clip-3", "othertrack", "9.123", NULL, GST_FLOW_OK);
|
||||
check_clip ("clip-3", "othertrack", 9123 * granulerate, 0);
|
||||
|
||||
/* bad msecs */
|
||||
push_clip ("clip-bad-msecs", "default", "0.1000", NULL, GST_FLOW_ERROR);
|
||||
|
||||
/* bad secs */
|
||||
push_clip ("clip-bad-secs", "default", "00:00:60.123", NULL, GST_FLOW_ERROR);
|
||||
|
||||
/* bad minutes */
|
||||
push_clip ("clip-bad-minutes", "default", "00:60:12.345",
|
||||
NULL, GST_FLOW_ERROR);
|
||||
|
||||
/* bad hours */
|
||||
push_clip ("clip-bad-hours", "default", "10000:12:34.567",
|
||||
NULL, GST_FLOW_ERROR);
|
||||
|
||||
push_end ();
|
||||
check_end ();
|
||||
|
||||
cleanup_cmmlenc (cmmlenc);
|
||||
/* now push another clip on the same track and check that the keyindex part of
|
||||
* the granulepos points to clip-1 and not to the empty clip */
|
||||
flow = push_clip ("clip-2", "default", "5", NULL);
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
|
||||
check_clip ("clip-2", "default",
|
||||
5 * GST_SECOND, 1 * GST_SECOND + 234 * GST_MSECOND);
|
||||
}
|
||||
GST_END_TEST static Suite *
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (test_time_order)
|
||||
{
|
||||
check_headers ();
|
||||
|
||||
/* clips belonging to the same track must have start times in non decreasing
|
||||
* order */
|
||||
flow = push_clip ("clip-1", "default", "1000:00:00.000", NULL);
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
|
||||
check_clip ("clip-1", "default", 3600 * 1000 * GST_SECOND, 0);
|
||||
|
||||
/* this will make the encoder throw an error message */
|
||||
flow = push_clip ("clip-2", "default", "5.678", NULL);
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_ERROR);
|
||||
|
||||
flow = push_clip ("clip-3", "default", "1000:00:00.001", NULL);
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
|
||||
check_clip ("clip-3", "default",
|
||||
3600 * 1000 * GST_SECOND + 1 * GST_MSECOND, 3600 * 1000 * GST_SECOND);
|
||||
|
||||
/* tracks don't interfere with each other */
|
||||
flow = push_clip ("clip-4", "othertrack", "9.123", NULL);
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
|
||||
check_clip ("clip-4", "othertrack", 9 * GST_SECOND + 123 * GST_MSECOND, 0);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (test_time_parsing)
|
||||
{
|
||||
check_headers ();
|
||||
|
||||
flow = push_clip ("bad-msecs", "default", "0.1000", NULL);
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_ERROR);
|
||||
|
||||
flow = push_clip ("bad-secs", "default", "00:00:60.123", NULL);
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_ERROR);
|
||||
|
||||
flow = push_clip ("bad-minutes", "default", "00:60:12.345", NULL);
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_ERROR);
|
||||
|
||||
/* this fails since we can't store 5124096 * 3600 * GST_SECOND in a
|
||||
* GstClockTime */
|
||||
flow = push_clip ("bad-hours", "default", "5124096:00:00.000", NULL);
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_ERROR);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (test_time_limits)
|
||||
{
|
||||
check_headers ();
|
||||
|
||||
/* ugly hack to make sure that the following checks actually overflow parsing
|
||||
* the times in gst_cmml_clock_time_from_npt rather than converting them to
|
||||
* granulepos in gst_cmml_clock_time_to_granule */
|
||||
granuleshift = 64;
|
||||
g_object_set (cmmlenc, "granule-shift", granuleshift, NULL);
|
||||
|
||||
/* 5124095:34:33.709 is the max npt-hhmmss time representable with
|
||||
* GstClockTime */
|
||||
flow = push_clip ("max-npt-hhmmss", "foo", "5124095:34:33.709", NULL);
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
|
||||
check_clip ("max-npt-hhmmss", "foo",
|
||||
(GstClockTime) 5124095 * 3600 * GST_SECOND + 34 * 60 * GST_SECOND +
|
||||
33 * GST_SECOND + 709 * GST_MSECOND, 0);
|
||||
|
||||
flow = push_clip ("overflow-max-npt-hhmmss", "overflows",
|
||||
"5124095:34:33.710", NULL);
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_ERROR);
|
||||
|
||||
/* 18446744073.709 is the max ntp-sec time */
|
||||
flow = push_clip ("max-npt-secs", "bar", "18446744073.709", NULL);
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
|
||||
check_clip ("max-npt-secs", "bar",
|
||||
(GstClockTime) 5124095 * 3600 * GST_SECOND + 34 * 60 * GST_SECOND +
|
||||
33 * GST_SECOND + 709 * GST_MSECOND, 0);
|
||||
|
||||
/* overflow doing 18446744074 * GST_SECOND */
|
||||
flow = push_clip ("overflow-max-npt-secs", "overflows",
|
||||
"18446744074.000", NULL);
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_ERROR);
|
||||
|
||||
/* overflow doing seconds + milliseconds */
|
||||
flow = push_clip ("overflow-max-npt-secs-msecs", "overflows",
|
||||
"18446744073.710", NULL);
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_ERROR);
|
||||
|
||||
/* reset granuleshift to 32 to check keyoffset overflows in
|
||||
* gst_cmml_clock_time_to_granule */
|
||||
granuleshift = 32;
|
||||
g_object_set (cmmlenc, "granule-shift", granuleshift, NULL);
|
||||
|
||||
/* 1193:02:47.295 is the max time we can encode in the keyoffset part of a
|
||||
* granulepos given a granuleshift of 32 */
|
||||
flow = push_clip ("max-granule-keyoffset", "baz", "1193:02:47.295", NULL);
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_OK);
|
||||
check_clip ("max-granule-keyoffset", "baz",
|
||||
1193 * 3600 * GST_SECOND + 2 * 60 * GST_SECOND +
|
||||
47 * GST_SECOND + 295 * GST_MSECOND, 0);
|
||||
|
||||
flow = push_clip ("overflow-max-granule-keyoffset", "overflows",
|
||||
"1193:02:47.296", NULL);
|
||||
fail_unless_equals_flow_return (flow, GST_FLOW_ERROR);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static Suite *
|
||||
cmmlenc_suite ()
|
||||
{
|
||||
Suite *s = suite_create ("cmmlenc");
|
||||
TCase *tc_chain = tcase_create ("general");
|
||||
TCase *tc_general = tcase_create ("general");
|
||||
|
||||
suite_add_tcase (s, tc_general);
|
||||
tcase_add_checked_fixture (tc_general, setup_cmmlenc, teardown_cmmlenc);
|
||||
tcase_add_test (tc_general, test_enc);
|
||||
tcase_add_test (tc_general, test_clip_end_time);
|
||||
tcase_add_test (tc_general, test_time_order);
|
||||
tcase_add_test (tc_general, test_time_parsing);
|
||||
tcase_add_test (tc_general, test_time_limits);
|
||||
|
||||
suite_add_tcase (s, tc_chain);
|
||||
tcase_add_test (tc_chain, test_enc);
|
||||
tcase_add_test (tc_chain, test_bad_start_time);
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int nf;
|
||||
|
||||
Suite *s = cmmlenc_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;
|
||||
}
|
||||
GST_CHECK_MAIN (cmmlenc);
|
||||
|
|
Loading…
Reference in a new issue