diff options
author | Olivier Naudan <o-naudan@ti.com> | 2012-04-16 08:10:18 -0400 |
---|---|---|
committer | Olivier Naudan <o-naudan@ti.com> | 2012-04-16 08:10:18 -0400 |
commit | b28313f8d15c35cc3b5ef6f975d24dcaef9736cf (patch) | |
tree | 82fce69684830e7e0b9563d7161e57a608b2b8c5 /tests/check/elements |
Imported Upstream version 0.11.90upstream/0.11.90
Diffstat (limited to 'tests/check/elements')
40 files changed, 16208 insertions, 0 deletions
diff --git a/tests/check/elements/asfmux.c b/tests/check/elements/asfmux.c new file mode 100644 index 00000000..de0007e3 --- /dev/null +++ b/tests/check/elements/asfmux.c @@ -0,0 +1,222 @@ +/* GStreamer + * + * unit test for asfmux + * + * Copyright (C) <2008> Thiago Santos <thiagoss@embedded.ufcg.edu.br> + * + * 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. + */ + +#include <unistd.h> + +#include <gst/check/gstcheck.h> + +/* For ease of programming we use globals to keep refs for our floating + * src and sink pads we create; otherwise we always have to do get_pad, + * get_peer, and then remove references in every test function */ +static GstPad *mysrcpad, *mysinkpad; + +#define AUDIO_CAPS_STRING "audio/x-wma, " \ + "channels = (int) 2, " \ + "rate = (int) 8000, " \ + "wmaversion = (int) 2, " \ + "block-align = (int) 14, " \ + "bitrate = (int) 64000" + +#define VIDEO_CAPS_STRING "video/x-wmv, " \ + "width = (int) 384, " \ + "height = (int) 288, " \ + "framerate = (fraction) 25/1, " \ + "wmvversion = (int) 2" + +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-ms-asf")); +static GstStaticPadTemplate srcvideotemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (VIDEO_CAPS_STRING)); +static GstStaticPadTemplate srcaudiotemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (AUDIO_CAPS_STRING)); + +static GstPad * +setup_src_pad (GstElement * element, + GstStaticPadTemplate * template, GstCaps * caps, const gchar * sinkname) +{ + GstPad *srcpad, *sinkpad; + + GST_DEBUG_OBJECT (element, "setting up sending pad"); + /* sending pad */ + srcpad = gst_pad_new_from_static_template (template, "src"); + fail_if (srcpad == NULL, "Could not create a srcpad"); + ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 1); + + if (!(sinkpad = gst_element_get_static_pad (element, sinkname))) + sinkpad = gst_element_get_request_pad (element, sinkname); + fail_if (sinkpad == NULL, "Could not get sink pad from %s", + GST_ELEMENT_NAME (element)); + /* references are owned by: 1) us, 2) asfmux, 3) collect pads */ + ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 3); + if (caps) + fail_unless (gst_pad_set_caps (srcpad, caps)); + fail_unless (gst_pad_link (srcpad, sinkpad) == GST_PAD_LINK_OK, + "Could not link source and %s sink pads", GST_ELEMENT_NAME (element)); + gst_object_unref (sinkpad); /* because we got it higher up */ + + /* references are owned by: 1) asfmux, 2) collect pads */ + ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2); + + return srcpad; +} + +static void +teardown_src_pad (GstElement * element, const gchar * sinkname) +{ + GstPad *srcpad, *sinkpad; + gchar *padname; + + /* clean up floating src pad */ + padname = g_strdup_printf (sinkname, 1); + if (!(sinkpad = gst_element_get_static_pad (element, padname))) + sinkpad = gst_element_get_request_pad (element, padname); + g_free (padname); + + fail_if (sinkpad == NULL, "sinkpad is null"); + + /* pad refs held by 1) asfmux 2) collectpads and 3) us (through _get) */ + ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 3); + fail_unless (gst_pad_is_linked (sinkpad)); + srcpad = gst_pad_get_peer (sinkpad); + + fail_if (srcpad == NULL, "Couldn't get srcpad"); + gst_pad_unlink (srcpad, sinkpad); + + /* after unlinking, pad refs still held by + * 1) asfmux and 2) collectpads and 3) us (through _get) */ + ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 3); + gst_object_unref (sinkpad); + /* one more ref is held by element itself */ + + /* pad refs held by both creator and this function (through _get_peer) */ + ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 2); + gst_object_unref (srcpad); + gst_object_unref (srcpad); +} + +static GstElement * +setup_asfmux (GstStaticPadTemplate * srctemplate, const gchar * sinkname) +{ + GstElement *asfmux; + + GST_DEBUG ("setup_asfmux"); + asfmux = gst_check_setup_element ("asfmux"); + + mysrcpad = setup_src_pad (asfmux, srctemplate, NULL, sinkname); + mysinkpad = gst_check_setup_sink_pad (asfmux, &sinktemplate); + gst_pad_set_active (mysrcpad, TRUE); + gst_pad_set_active (mysinkpad, TRUE); + return asfmux; +} + +static void +cleanup_asfmux (GstElement * asfmux, const gchar * sinkname) +{ + GST_DEBUG ("cleanup_asfmux"); + gst_element_set_state (asfmux, GST_STATE_NULL); + gst_pad_set_active (mysrcpad, FALSE); + gst_pad_set_active (mysinkpad, FALSE); + teardown_src_pad (asfmux, sinkname); + gst_check_teardown_sink_pad (asfmux); + gst_check_teardown_element (asfmux); +} + +static void +check_asfmux_pad (GstStaticPadTemplate * srctemplate, + const gchar * src_caps_string, const gchar * sinkname) +{ + GstElement *asfmux; + GstBuffer *inbuffer; + GstCaps *caps; + GstFlowReturn ret; + GList *l; + + asfmux = setup_asfmux (srctemplate, sinkname); + fail_unless (gst_element_set_state (asfmux, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (1); + caps = gst_caps_from_string (src_caps_string); + gst_pad_set_caps (mysrcpad, caps); + gst_caps_unref (caps); + GST_BUFFER_TIMESTAMP (inbuffer) = 0; + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + ret = gst_pad_push (mysrcpad, inbuffer); + fail_unless (ret == GST_FLOW_OK, "Pad push returned: %d", ret); + + cleanup_asfmux (asfmux, sinkname); + for (l = buffers; l; l = l->next) + gst_buffer_unref (l->data); + g_list_free (buffers); + buffers = NULL; +} + +GST_START_TEST (test_video_pad) +{ + check_asfmux_pad (&srcvideotemplate, VIDEO_CAPS_STRING, "video_%u"); +} + +GST_END_TEST; + +GST_START_TEST (test_audio_pad) +{ + check_asfmux_pad (&srcaudiotemplate, AUDIO_CAPS_STRING, "audio_%u"); +} + +GST_END_TEST; + +static Suite * +asfmux_suite (void) +{ + Suite *s = suite_create ("asfmux"); + TCase *tc_chain = tcase_create ("general"); + tcase_add_test (tc_chain, test_video_pad); + tcase_add_test (tc_chain, test_audio_pad); + + suite_add_tcase (s, tc_chain); + + return s; +} + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = asfmux_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; +} diff --git a/tests/check/elements/assrender.c b/tests/check/elements/assrender.c new file mode 100644 index 00000000..c07c36ed --- /dev/null +++ b/tests/check/elements/assrender.c @@ -0,0 +1,298 @@ +/* GStreamer + * Copyright (C) 2010 Sebastian Dröge <sebastian.droege@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. + */ + +#include <string.h> + +#include <gst/check/gstcheck.h> +#include <gst/video/video.h> +#include <gst/app/gstappsrc.h> + +static gboolean +bus_handler (GstBus * bus, GstMessage * message, gpointer data) +{ + GMainLoop *loop = (GMainLoop *) data; + + switch (message->type) { + case GST_MESSAGE_EOS: + g_main_loop_quit (loop); + break; + case GST_MESSAGE_WARNING: + case GST_MESSAGE_ERROR:{ + GError *gerror; + gchar *debug; + + if (message->type == GST_MESSAGE_WARNING) + gst_message_parse_warning (message, &gerror, &debug); + else + gst_message_parse_error (message, &gerror, &debug); + gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug); + gst_message_unref (message); + g_error_free (gerror); + g_free (debug); + g_main_loop_quit (loop); + break; + } + default: + break; + } + + return TRUE; +} + +typedef struct +{ + GstClockTime ts; + GstClockTime duration; + const gchar buf[]; +} TestBuffer; + +static const TestBuffer buf0 = { + 0, + 0, + "[Script Info]\n" + "; This is a Sub Station Alpha v4 script.\n" + "; For Sub Station Alpha info and downloads,\n" + "; go to http://www.eswat.demon.co.uk/\n" + "Title: Some Test\n" + "Script Updated By: version 2.8.01\n" + "ScriptType: v4.00\n" + "Collisions: Normal\n" + "PlayResY: 200\n" + "PlayDepth: 0\n" + "Timer: 100,0000\n" + " \n" + "[V4 Styles]\n" + "Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline, Shadow, \n" + " Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding\n" + "Style: DefaultVCD, Arial,28,11861244,11861244,11861244,-2147483640,-1,0,1,1,2,2,30,30,30,0,0\n" + " \n" + "[Events]\n" + "Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text" +}; + +static const TestBuffer buf1 = { + 40 * GST_MSECOND, + 60 * GST_MSECOND, + "1,,DefaultVCD, NTP,0000,0000,0000,,Some Test Blabla" +}; + +static void +sink_handoff_cb_xRGB (GstElement * object, GstBuffer * buffer, GstPad * pad, + gpointer user_data) +{ + guint *sink_pos = (guint *) user_data; + gboolean contains_text = (*sink_pos == 1 || *sink_pos == 2); + guint i, j; + GstMapInfo map; + gboolean all_red = TRUE; + + gst_buffer_map (buffer, &map, GST_MAP_READ); + + fail_unless_equals_int (map.size, 640 * 480 * 4); + + for (i = 0; i < 640; i++) { + for (j = 0; j < 480; j++) { + all_red = all_red && (map.data[i * 480 * 4 + j * 4 + 1] == 255 && + map.data[i * 480 * 4 + j * 4 + 2] == 0 && + map.data[i * 480 * 4 + j * 4 + 3] == 0); + } + } + gst_buffer_unmap (buffer, &map); + + fail_unless (contains_text != all_red, + "Frame %d is incorrect (all red %d, contains text %d)", *sink_pos, + all_red, contains_text); + *sink_pos = *sink_pos + 1; +} + +static void +sink_handoff_cb_I420 (GstElement * object, GstBuffer * buffer, GstPad * pad, + gpointer user_data) +{ + guint *sink_pos = (guint *) user_data; + gboolean contains_text = (*sink_pos == 1 || *sink_pos == 2); + guint c, i, j; + gboolean all_red = TRUE; + guint8 *comp; + gint comp_stride, comp_width, comp_height; + const guint8 color[] = { 81, 90, 240 }; + GstVideoInfo info; + GstVideoFrame frame; + + gst_video_info_init (&info); + gst_video_info_set_format (&info, GST_VIDEO_FORMAT_I420, 640, 480); + + gst_video_frame_map (&frame, &info, buffer, GST_MAP_READ); + + for (c = 0; c < 3; c++) { + comp = GST_VIDEO_FRAME_COMP_DATA (&frame, c); + comp_stride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, c); + comp_width = GST_VIDEO_FRAME_COMP_WIDTH (&frame, c); + comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (&frame, c); + + for (i = 0; i < comp_height; i++) { + for (j = 0; j < comp_width; j++) { + all_red = all_red && (comp[i * comp_stride + j] == color[c]); + } + } + } + gst_video_frame_unmap (&frame); + + fail_unless (contains_text != all_red, + "Frame %d is incorrect (all red %d, contains text %d)", *sink_pos, + all_red, contains_text); + *sink_pos = *sink_pos + 1; +} + +static gulong probe_id = 0; + +static GstPadProbeReturn +src_buffer_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) +{ + GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER (info); + GstPad *otherpad = GST_PAD (user_data); + + if (GST_BUFFER_TIMESTAMP (buffer) == buf1.ts) + gst_pad_remove_probe (otherpad, probe_id); + + return GST_PAD_PROBE_OK; +} + +#define CREATE_BASIC_TEST(format) \ +GST_START_TEST (test_assrender_basic_##format) \ +{ \ + GstElement *pipeline; \ + GstElement *appsrc, *videotestsrc, *capsfilter, *assrender, *fakesink; \ + guint sink_pos = 0; \ + GstCaps *video_caps; \ + GstCaps *text_caps; \ + GstBuffer *buf; \ + GstBus *bus; \ + GMainLoop *loop; \ + GstPad *pad, *blocked_pad; \ + guint bus_watch = 0; \ + GstVideoInfo info; \ + \ + pipeline = gst_pipeline_new ("pipeline"); \ + fail_unless (pipeline != NULL); \ + \ + capsfilter = gst_element_factory_make ("capsfilter", NULL); \ + fail_unless (capsfilter != NULL); \ + gst_video_info_init (&info); \ + gst_video_info_set_format (&info, GST_VIDEO_FORMAT_##format, 640, 480); \ + info.fps_n = 25; \ + info.fps_d = 1; \ + video_caps = gst_video_info_to_caps (&info); \ + g_object_set (capsfilter, "caps", video_caps, NULL); \ + gst_caps_unref (video_caps); \ + blocked_pad = gst_element_get_static_pad (capsfilter, "src"); \ + gst_pad_add_probe (blocked_pad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, NULL, NULL, NULL); \ + \ + appsrc = gst_element_factory_make ("appsrc", NULL); \ + fail_unless (appsrc != NULL); \ + buf = gst_buffer_new_and_alloc (strlen (buf0.buf) + 1); \ + gst_buffer_fill (buf, 0, buf0.buf, strlen (buf0.buf) + 1); \ + GST_BUFFER_TIMESTAMP (buf) = buf0.ts; \ + GST_BUFFER_DURATION (buf) = buf0.duration; \ + text_caps = \ + gst_caps_new_simple ("application/x-ssa", "codec_data", GST_TYPE_BUFFER, \ + buf, NULL); \ + gst_buffer_unref (buf); \ + gst_app_src_set_caps (GST_APP_SRC (appsrc), text_caps); \ + g_object_set (appsrc, "format", GST_FORMAT_TIME, NULL); \ + pad = gst_element_get_static_pad (appsrc, "src"); \ + probe_id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, src_buffer_probe_cb, \ + gst_object_ref (blocked_pad), (GDestroyNotify) gst_object_unref); \ + gst_object_unref (blocked_pad); \ + gst_object_unref (pad); \ + \ + videotestsrc = gst_element_factory_make ("videotestsrc", NULL); \ + fail_unless (videotestsrc != NULL); \ + g_object_set (videotestsrc, "num-buffers", 5, "pattern", 4, NULL); \ + \ + assrender = gst_element_factory_make ("assrender", NULL); \ + fail_unless (assrender != NULL); \ + \ + fakesink = gst_element_factory_make ("fakesink", NULL); \ + fail_unless (fakesink != NULL); \ + g_object_set (fakesink, "signal-handoffs", TRUE, "async", FALSE, NULL); \ + g_signal_connect (fakesink, "handoff", G_CALLBACK (sink_handoff_cb_##format), \ + &sink_pos); \ + \ + gst_bin_add_many (GST_BIN (pipeline), appsrc, videotestsrc, capsfilter, \ + assrender, fakesink, NULL); \ + \ + fail_unless (gst_element_link_pads (appsrc, "src", assrender, "text_sink")); \ + fail_unless (gst_element_link_pads (videotestsrc, "src", capsfilter, "sink")); \ + fail_unless (gst_element_link_pads (capsfilter, "src", assrender, \ + "video_sink")); \ + fail_unless (gst_element_link_pads (assrender, "src", fakesink, "sink")); \ + \ + loop = g_main_loop_new (NULL, TRUE); \ + fail_unless (loop != NULL); \ + \ + bus = gst_element_get_bus (pipeline); \ + fail_unless (bus != NULL); \ + bus_watch = gst_bus_add_watch (bus, bus_handler, loop); \ + gst_object_unref (bus); \ + \ + fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_PLAYING), \ + GST_STATE_CHANGE_SUCCESS); \ + \ + buf = gst_buffer_new_and_alloc (strlen (buf1.buf) + 1); \ + gst_buffer_fill (buf, 0, buf1.buf, strlen (buf1.buf) + 1); \ + GST_BUFFER_TIMESTAMP (buf) = buf1.ts; \ + GST_BUFFER_DURATION (buf) = buf1.duration; \ + gst_app_src_push_buffer (GST_APP_SRC (appsrc), buf); \ + gst_caps_unref (text_caps); \ + gst_app_src_end_of_stream (GST_APP_SRC (appsrc)); \ + \ + g_main_loop_run (loop); \ + \ + gst_element_set_state (pipeline, GST_STATE_NULL); \ + \ + fail_unless_equals_int (sink_pos, 5); \ + \ + g_object_unref (pipeline); \ + g_main_loop_unref (loop); \ + g_source_remove (bus_watch); \ +} \ +\ +GST_END_TEST; + +CREATE_BASIC_TEST (xRGB); +CREATE_BASIC_TEST (I420); + +static Suite * +assrender_suite (void) +{ + Suite *s = suite_create ("assrender"); + TCase *tc_chain = tcase_create ("linear"); + + /* time out after 120s, not the default 3 */ + tcase_set_timeout (tc_chain, 120); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_assrender_basic_xRGB); + tcase_add_test (tc_chain, test_assrender_basic_I420); + + return s; +} + +GST_CHECK_MAIN (assrender); diff --git a/tests/check/elements/autoconvert.c b/tests/check/elements/autoconvert.c new file mode 100644 index 00000000..680464c1 --- /dev/null +++ b/tests/check/elements/autoconvert.c @@ -0,0 +1,243 @@ +/* GStreamer + * + * unit test for autoconvert element + * Copyright (C) 2009 Jan Schmidt <thaytan@noraisin.net> + * + * 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/gst.h> +#include <gst/check/gstcheck.h> + +/* Define 2 element factories for testing with */ +typedef GstBin TestElement1; +typedef GstBinClass TestElement1Class; +typedef GstBin TestElement2; +typedef GstBinClass TestElement2Class; + +GType test_element1_get_type (void); +G_DEFINE_TYPE (TestElement1, test_element1, GST_TYPE_BIN); +GType test_element2_get_type (void); +G_DEFINE_TYPE (TestElement2, test_element2, GST_TYPE_BIN); + +static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, GST_PAD_ALWAYS, + GST_STATIC_CAPS ("test/caps,type=(int)[1,2]")); +static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, GST_PAD_ALWAYS, + GST_STATIC_CAPS ("test/caps,type=(int)[1,2]")); + +static void +setup (void) +{ + /* Register our test elements */ + fail_unless (gst_element_register (NULL, "testelement1", GST_RANK_NONE, + test_element1_get_type ())); + fail_unless (gst_element_register (NULL, "testelement2", GST_RANK_NONE, + test_element2_get_type ())); +} + +static void +teardown (void) +{ +} + +static void +set_autoconvert_factories (GstElement * autoconvert) +{ + const gchar *desired_features[] = { "testelement1", "testelement2" }; + GstElementFactory *feature; + GList *factories = NULL; + gint i; + + for (i = 0; i < G_N_ELEMENTS (desired_features); i++) { + feature = + GST_ELEMENT_FACTORY_CAST (gst_registry_find_feature + (gst_registry_get (), desired_features[i], GST_TYPE_ELEMENT_FACTORY)); + fail_if (feature == NULL, "Test element %s was not found in registry", + desired_features[i]); + factories = g_list_prepend (factories, feature); + } + + g_object_set (G_OBJECT (autoconvert), "factories", factories, NULL); + + g_list_free (factories); +} + +typedef struct +{ + gint n; + GstCaps *caps; +} TestContext; + +static void +generate_test_buffer (GstPad * src, TestContext * ctx) +{ + GstBuffer *buf; + + if (ctx->n == 0) { + ctx->caps = gst_caps_from_string ("test/caps,type=(int)1"); + } else if (ctx->n == 10) { + gst_caps_unref (ctx->caps); + ctx->caps = gst_caps_from_string ("test/caps,type=(int)2"); + } + + buf = gst_buffer_new_and_alloc (4096); + gst_pad_set_caps (src, ctx->caps); + + GST_LOG ("Pushing test buffer, caps %" GST_PTR_FORMAT, ctx->caps); + fail_unless (gst_pad_push (src, buf) == GST_FLOW_OK); +} + +GST_START_TEST (test_autoconvert_simple) +{ + GstPad *test_src_pad, *test_sink_pad; + GstElement *autoconvert = gst_check_setup_element ("autoconvert"); + GstBus *bus = gst_bus_new (); + TestContext ctx = { 0 }; + + set_autoconvert_factories (autoconvert); + + test_src_pad = gst_check_setup_src_pad (autoconvert, &src_factory); + gst_pad_set_active (test_src_pad, TRUE); + test_sink_pad = gst_check_setup_sink_pad (autoconvert, &sink_factory); + gst_pad_set_active (test_sink_pad, TRUE); + + gst_element_set_state (GST_ELEMENT_CAST (autoconvert), GST_STATE_PLAYING); + + /* Push 20 items */ + for (ctx.n = 0; ctx.n < 20; ctx.n++) + generate_test_buffer (test_src_pad, &ctx); + + /* Check all the items arrived */ + fail_unless_equals_int (g_list_length (buffers), 20); + + while (TRUE) { + GstMessage *msg = gst_bus_pop (bus); + if (!msg) + break; + + GST_DEBUG ("got message %s", + gst_message_type_get_name (GST_MESSAGE_TYPE (msg))); + fail_if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR); + } + + gst_element_set_state ((GstElement *) autoconvert, GST_STATE_NULL); + + gst_bus_set_flushing (bus, TRUE); + gst_object_unref (bus); + + gst_pad_set_active (test_src_pad, FALSE); + gst_pad_set_active (test_sink_pad, FALSE); + gst_check_teardown_src_pad (autoconvert); + gst_check_teardown_sink_pad (autoconvert); + gst_check_teardown_element (autoconvert); +} + +GST_END_TEST; + +static Suite * +autoconvert_suite (void) +{ + Suite *s = suite_create ("autoconvert"); + TCase *tc_basic = tcase_create ("general"); + + suite_add_tcase (s, tc_basic); + tcase_add_checked_fixture (tc_basic, setup, teardown); + tcase_add_test (tc_basic, test_autoconvert_simple); + + return s; +} + +/* Implementation of the test elements */ + +static void +configure_test_element (GstBin * bin, const gchar * capsfilter) +{ + GstElement *filter; + GstElement *identity; + GstPad *pad, *ghostpad; + GstPadTemplate *test_static_templ; + + filter = gst_element_factory_make ("capsfilter", NULL); + fail_unless (filter != NULL); + gst_util_set_object_arg (G_OBJECT (filter), "caps", capsfilter); + + identity = gst_element_factory_make ("identity", NULL); + fail_unless (identity != NULL); + + gst_bin_add_many (bin, filter, identity, NULL); + fail_unless (gst_element_link_many (filter, identity, NULL) == TRUE); + + + test_static_templ = gst_static_pad_template_get (&sink_factory); + pad = gst_element_get_static_pad (filter, "sink"); + ghostpad = gst_ghost_pad_new_from_template ("sink", pad, test_static_templ); + gst_element_add_pad (GST_ELEMENT_CAST (bin), ghostpad); + gst_object_unref (pad); + gst_object_unref (test_static_templ); + + test_static_templ = gst_static_pad_template_get (&src_factory); + pad = gst_element_get_static_pad (identity, "src"); + ghostpad = gst_ghost_pad_new_from_template ("src", pad, test_static_templ); + gst_element_add_pad (GST_ELEMENT_CAST (bin), ghostpad); + gst_object_unref (pad); + gst_object_unref (test_static_templ); +} + +static void +test_element1_class_init (TestElement1Class * klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + GstPadTemplate *src_template, *sink_template; + + src_template = gst_static_pad_template_get (&src_factory); + gst_element_class_add_pad_template (element_class, src_template); + + sink_template = gst_static_pad_template_get (&sink_factory); + gst_element_class_add_pad_template (element_class, sink_template); +} + +static void +test_element1_init (TestElement1 * elem) +{ + configure_test_element (GST_BIN_CAST (elem), "test/caps,type=(int)1"); +} + +static void +test_element2_class_init (TestElement2Class * klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + GstPadTemplate *src_template, *sink_template; + + src_template = gst_static_pad_template_get (&src_factory); + gst_element_class_add_pad_template (element_class, src_template); + + sink_template = gst_static_pad_template_get (&sink_factory); + gst_element_class_add_pad_template (element_class, sink_template); +} + +static void +test_element2_init (TestElement2 * elem) +{ + configure_test_element (GST_BIN_CAST (elem), "test/caps,type=(int)2"); +} + +GST_CHECK_MAIN (autoconvert); diff --git a/tests/check/elements/autovideoconvert.c b/tests/check/elements/autovideoconvert.c new file mode 100644 index 00000000..609c730a --- /dev/null +++ b/tests/check/elements/autovideoconvert.c @@ -0,0 +1,139 @@ +/* GStreamer + * + * unit test for autovideoconvert element + * Copyright (C) 2009 Jan Schmidt <thaytan@noraisin.net> + * Copyright (C) 2010 ST-Ericsson SA + * @author: Benjamin Gaignard <benjamin.gaignard@stericsson.com> + * + * 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/gst.h> +#include <gst/check/gstcheck.h> + +typedef struct +{ + GMainLoop *loop; + gboolean eos; +} OnMessageUserData; + +static void +on_message_cb (GstBus * bus, GstMessage * message, gpointer user_data) +{ + OnMessageUserData *d = user_data; + + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_ERROR: + case GST_MESSAGE_WARNING: + g_assert_not_reached (); + break; + case GST_MESSAGE_EOS: + g_main_loop_quit (d->loop); + d->eos = TRUE; + break; + default: + break; + } +} + +static void +run_test (const gchar * pipeline_string) +{ + GstElement *pipeline; + GstBus *bus; + GMainLoop *loop; + OnMessageUserData omud = { NULL, }; + GstStateChangeReturn ret; + + GST_DEBUG ("Testing pipeline '%s'", pipeline_string); + + pipeline = gst_parse_launch (pipeline_string, NULL); + fail_unless (pipeline != NULL); + loop = g_main_loop_new (NULL, FALSE); + + bus = gst_element_get_bus (pipeline); + fail_unless (bus != NULL); + gst_bus_add_signal_watch (bus); + + omud.loop = loop; + omud.eos = FALSE; + + g_signal_connect (bus, "message", (GCallback) on_message_cb, &omud); + + gst_object_unref (bus); + + ret = gst_element_set_state (pipeline, GST_STATE_PLAYING); + fail_unless (ret == GST_STATE_CHANGE_SUCCESS + || ret == GST_STATE_CHANGE_ASYNC); + + g_main_loop_run (loop); + + fail_unless (gst_element_set_state (pipeline, + GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS); + + fail_unless (omud.eos == TRUE); + + gst_object_unref (pipeline); + g_main_loop_unref (loop); + +} + +GST_START_TEST (test_autovideoconvert_rbg2bayer) +{ + gchar *pipeline; + + pipeline = + g_strdup_printf + ("videotestsrc num-buffers=1 ! video/x-raw,format=ARGB,depth=32,width=100,height=100,framerate=10/1 ! autovideoconvert ! video/x-bayer,width=100,height=100,format=bggr,framerate=10/1 ! fakesink"); + + run_test (pipeline); + g_free (pipeline); +} + +GST_END_TEST; + +GST_START_TEST (test_autovideoconvert_videoconvert) +{ + gchar *pipeline; + + pipeline = + g_strdup_printf + ("videotestsrc num-buffers=1 ! video/x-raw, format=RGB,width=100,height=100,framerate=10/1 ! autovideoconvert ! video/x-raw,format=BGR,width=100,height=100,framerate=10/1 ! fakesink"); + + run_test (pipeline); + g_free (pipeline); +} + +GST_END_TEST; + +static Suite * +autovideoconvert_suite (void) +{ + Suite *s = suite_create ("autovideoconvert"); + TCase *tc_basic = tcase_create ("general"); + + suite_add_tcase (s, tc_basic); + tcase_add_test (tc_basic, test_autovideoconvert_rbg2bayer); + tcase_add_test (tc_basic, test_autovideoconvert_videoconvert); + + return s; +} + +GST_CHECK_MAIN (autovideoconvert); diff --git a/tests/check/elements/baseaudiovisualizer.c b/tests/check/elements/baseaudiovisualizer.c new file mode 100644 index 00000000..f1458a28 --- /dev/null +++ b/tests/check/elements/baseaudiovisualizer.c @@ -0,0 +1,179 @@ +/* GStreamer + * Copyright (C) <2011> Stefan Kost <ensonic@users.sf.net> + * + * unit test for the baseaudiovisualizer class + * + * 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. + */ + +#include <gst/check/gstcheck.h> + +#include <gst/gst.h> +#include <string.h> + +#include "gstbaseaudiovisualizer.h" + +/* dummy subclass for testing */ + +#define GST_TYPE_TEST_SCOPE (gst_test_scope_get_type()) +#define GST_TEST_SCOPE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TEST_SCOPE,GstTestScope)) +#define GST_TEST_SCOPE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TEST_SCOPE,GstTestScopeClass)) +typedef struct _GstTestScope GstTestScope; +typedef struct _GstTestScopeClass GstTestScopeClass; + +struct _GstTestScope +{ + GstBaseAudioVisualizer parent; +}; + +struct _GstTestScopeClass +{ + GstBaseAudioVisualizerClass parent_class; +}; + +static GstStaticPadTemplate gst_test_scope_src_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("xRGB")) + ); + +static GstStaticPadTemplate gst_test_scope_sink_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-raw, " + "format = (string) " GST_AUDIO_NE (S16) ", " + "layout = (string) interleaved, " + "channels = (int) 2, " + "channel-mask = (bitmask) 3, " "rate = (int) 44100") + ); + +static GType gst_test_scope_get_type (void); + +G_DEFINE_TYPE (GstTestScope, gst_test_scope, GST_TYPE_BASE_AUDIO_VISUALIZER); + +static void +gst_test_scope_class_init (GstTestScopeClass * g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_set_details_simple (element_class, "test scope", + "Visualization", + "Dummy test scope", "Stefan Kost <ensonic@users.sf.net>"); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_test_scope_src_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_test_scope_sink_template)); +} + +static void +gst_test_scope_init (GstTestScope * scope) +{ + /* do nothing */ +} + +/* tests */ +#define CAPS "audio/x-raw, " \ + "format = (string) " GST_AUDIO_NE (S16) ", " \ + "layout = (string) interleaved, " \ + "rate = (int) 44100, " \ + "channels = (int) 2, " \ + "channel-mask = (bitmask) 3" + +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-raw, " + "format = (string) xRGB, " + "width = (int) 320, " + "height = (int) 240, " "framerate = (fraction) 30/1") + ); +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (CAPS) + ); + +GST_START_TEST (count_in_out) +{ + GstElement *elem; + GstPad *srcpad, *sinkpad; + GstBuffer *buffer; + GstCaps *caps; + + /* setup up */ + elem = gst_check_setup_element ("testscope"); + srcpad = gst_check_setup_src_pad (elem, &srctemplate); + sinkpad = gst_check_setup_sink_pad (elem, &sinktemplate); + gst_pad_set_active (srcpad, TRUE); + gst_pad_set_active (sinkpad, TRUE); + + fail_unless (gst_element_set_state (elem, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + caps = gst_caps_from_string (CAPS); + gst_pad_set_caps (srcpad, caps); + gst_caps_unref (caps); + + /* push 1s audio to get 30 video-frames */ + buffer = gst_buffer_new_and_alloc (44100 * 2 * sizeof (gint16)); + ASSERT_BUFFER_REFCOUNT (buffer, "buffer", 1); + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (srcpad, buffer) == GST_FLOW_OK); + /* ... but it ends up being collected on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (buffer, "buffer", 1); + fail_unless_equals_int (g_list_length (buffers), 30); + + /* clean up */ + g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL); + g_list_free (buffers); + buffers = NULL; + + gst_pad_set_active (srcpad, FALSE); + gst_pad_set_active (sinkpad, FALSE); + gst_check_teardown_src_pad (elem); + gst_check_teardown_sink_pad (elem); + gst_check_teardown_element (elem); +} + +GST_END_TEST; + +static void +baseaudiovisualizer_init (void) +{ + gst_element_register (NULL, "testscope", GST_RANK_NONE, GST_TYPE_TEST_SCOPE); +} + +static Suite * +baseaudiovisualizer_suite (void) +{ + Suite *s = suite_create ("baseaudiovisualizer"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_checked_fixture (tc_chain, baseaudiovisualizer_init, NULL); + + tcase_add_test (tc_chain, count_in_out); + + return s; +} + + +GST_CHECK_MAIN (baseaudiovisualizer); diff --git a/tests/check/elements/camerabin.c b/tests/check/elements/camerabin.c new file mode 100644 index 00000000..6d353d97 --- /dev/null +++ b/tests/check/elements/camerabin.c @@ -0,0 +1,847 @@ +/* GStreamer + * + * unit test for camerabin basic operations + * Copyright (C) 2008 Nokia Corporation <multimedia@maemo.org> + * + * + * 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 <unistd.h> +#include <glib.h> +#include <glib/gstdio.h> +#include <gst/gst.h> +#include <gst/check/gstcheck.h> +#include <gst/interfaces/photography.h> + +#define SINGLE_IMAGE_FILENAME "image" +#define SINGLE_IMAGE_WITH_FLAGS_FILENAME "image_with_flags" +#define SEQUENTIAL_IMAGES_FILENAME "sequential_image" +#define BURST_IMAGE_FILENAME "burst_image" +#define VIDEO_FILENAME "video" +#define VIDEO_WITH_FLAGS_FILENAME "video_with_flags" +#define VIDEO_PAUSE_FILENAME "video_pause" +#define VIDEO_NOAUDIO_FILENAME "video_noaudio" +#define CYCLE_IMAGE_FILENAME "cycle_image" +#define CYCLE_VIDEO_FILENAME "cycle_video" +#define TAGLISTS_COUNT 3 +#define CYCLE_COUNT_MAX 2 +#define SEQUENTIAL_IMAGES_COUNT 3 +#define MAX_BURST_IMAGES 10 +#define PHOTO_SETTING_DELAY_US 0 + +static GstElement *camera; +static guint bus_source; +static GMainLoop *main_loop; +static guint cycle_count = 0; +static gboolean received_preview_msg = FALSE; +static GstTagList *taglists[TAGLISTS_COUNT]; +static GstTagList *validation_taglist; + +/* helper function for filenames */ +static const gchar * +make_test_file_name (const gchar * base_name, gint num) +{ + static gchar file_name[1000]; + + g_snprintf (file_name, 999, "%s" G_DIR_SEPARATOR_S + "gstcamerabintest_%s_%03d.cap", g_get_tmp_dir (), base_name, num); + + GST_INFO ("capturing to: %s (cycle: %d)", file_name, cycle_count); + return file_name; +} + +/* burst capture is not supported in camerabin for the moment */ +#ifdef ENABLE_BURST_CAPTURE +static const gchar * +make_test_seq_file_name (const gchar * base_name) +{ + static gchar file_name[1000]; + + g_snprintf (file_name, 999, "%s" G_DIR_SEPARATOR_S "%02u_%s", + g_get_tmp_dir (), captured_images, base_name); + + GST_INFO ("capturing to: %s", file_name); + return file_name; +} +#endif +/* signal handlers */ + +static gboolean +handle_image_captured_cb (gpointer data) +{ + GMainLoop *loop = (GMainLoop *) data; + + /* unblock viewfinder */ + g_object_set (camera, "block-after-capture", FALSE, NULL); + + GST_DEBUG ("handle_image_captured_cb, cycle: %d", cycle_count); + if (cycle_count == 0) { + GST_DEBUG ("all cycles done"); + g_main_loop_quit (loop); + } else { + /* Set video recording mode */ + g_object_set (camera, "mode", 1, + "filename", make_test_file_name (CYCLE_VIDEO_FILENAME, cycle_count), + NULL); + /* Record video */ + g_signal_emit_by_name (camera, "capture-start", NULL); + g_usleep (G_USEC_PER_SEC); + g_signal_emit_by_name (camera, "capture-stop", NULL); + GST_DEBUG ("video captured"); + + /* Set still image mode */ + g_object_set (camera, "mode", 0, + "filename", make_test_file_name (CYCLE_IMAGE_FILENAME, cycle_count), + NULL); + + cycle_count--; + GST_DEBUG ("next cycle: %d", cycle_count); + + /* Take a picture */ + g_signal_emit_by_name (camera, "capture-start", NULL); + } + GST_DEBUG ("handle_image_captured_cb done"); + return FALSE; +} + +static gboolean +capture_done (GstElement * elem, const gchar * filename, gpointer user_data) +{ + GMainLoop *loop = (GMainLoop *) user_data; + + g_idle_add ((GSourceFunc) handle_image_captured_cb, loop); + + GST_INFO ("image saved"); + + return FALSE; +} + +/* configuration */ + +static gboolean +set_and_check_camerabin_element (GstElement * camera, const char *property, + GstElement * element) +{ + GstElement *element_check; + gboolean ret = FALSE; + + if (element) { + g_object_set (camera, property, element, NULL); + g_object_get (camera, property, &element_check, NULL); + if (element_check == element) + ret = TRUE; + if (element_check) + g_object_unref (element_check); + } + return ret; +} + +static void +setup_camerabin_elements (GstElement * camera) +{ + GstElement *vfsink, *audiosrc, *videosrc, *audioenc, *videoenc, *imageenc, + *videomux, *viewfinder_filter, *imagepp, *videopp, *formatter; + GstCaps *audiocaps, *videocaps; + + /* Use fakesink for view finder */ + vfsink = gst_element_factory_make ("fakesink", NULL); + g_object_set (vfsink, "sync", TRUE, NULL); + audiosrc = gst_element_factory_make ("audiotestsrc", NULL); + g_object_set (audiosrc, "is-live", TRUE, NULL); + videosrc = gst_element_factory_make ("videotestsrc", NULL); + /* Set pattern to white (3) to avoid timeouts */ + g_object_set (videosrc, "is-live", TRUE, "pattern", 3, NULL); + audioenc = gst_element_factory_make ("capsfilter", NULL); + audiocaps = gst_caps_from_string ("audio/x-raw-int"); + g_object_set (audioenc, "caps", audiocaps, NULL); + gst_caps_unref (audiocaps); + videoenc = gst_element_factory_make ("capsfilter", NULL); + videocaps = gst_caps_from_string ("video/x-raw-yuv"); + g_object_set (videoenc, "caps", videocaps, NULL); + gst_caps_unref (videocaps); + videomux = gst_element_factory_make ("avimux", NULL); + imageenc = gst_element_factory_make ("jpegenc", NULL); + viewfinder_filter = gst_element_factory_make ("identity", NULL); + imagepp = gst_element_factory_make ("identity", NULL); + videopp = gst_element_factory_make ("identity", NULL); + formatter = gst_element_factory_make ("jifmux", NULL); + + if (set_and_check_camerabin_element (camera, "viewfinder-sink", vfsink) + && set_and_check_camerabin_element (camera, "audio-source", audiosrc) + && set_and_check_camerabin_element (camera, "video-source", videosrc) + && set_and_check_camerabin_element (camera, "audio-encoder", audioenc) + && set_and_check_camerabin_element (camera, "video-encoder", videoenc) + && set_and_check_camerabin_element (camera, "image-encoder", imageenc) + && set_and_check_camerabin_element (camera, "video-muxer", videomux) + && set_and_check_camerabin_element (camera, "viewfinder-filter", + viewfinder_filter) + && set_and_check_camerabin_element (camera, "image-post-processing", + imagepp) + && set_and_check_camerabin_element (camera, "video-post-processing", + videopp) + && set_and_check_camerabin_element (camera, "image-formatter", formatter)) { + GST_INFO ("element properties set and checked"); + } else { + GST_WARNING ("error setting up test plugins"); + } +} + +static gboolean +capture_bus_cb (GstBus * bus, GstMessage * message, gpointer data) +{ + GMainLoop *loop = (GMainLoop *) data; + const GstStructure *st; + + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_ERROR:{ + GError *err = NULL; + gchar *debug = NULL; + + gst_message_parse_error (message, &err, &debug); + GST_WARNING ("ERROR: %s [%s]", err->message, debug); + g_error_free (err); + g_free (debug); + /* Write debug graph to file */ + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (camera), + GST_DEBUG_GRAPH_SHOW_ALL, "camerabin.error"); + + fail_if (TRUE, "error while capturing"); + g_main_loop_quit (loop); + break; + } + case GST_MESSAGE_WARNING:{ + GError *err = NULL; + gchar *debug = NULL; + + gst_message_parse_warning (message, &err, &debug); + GST_WARNING ("WARNING: %s [%s]", err->message, debug); + g_error_free (err); + g_free (debug); + /* Write debug graph to file */ + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (camera), + GST_DEBUG_GRAPH_SHOW_ALL, "camerabin.warning"); + break; + } + case GST_MESSAGE_EOS: + GST_DEBUG ("eos"); + g_main_loop_quit (loop); + break; + default: + st = gst_message_get_structure (message); + if (st && gst_structure_has_name (st, "image-captured")) { + gboolean ready = FALSE; + GST_INFO ("image captured"); + g_object_get (camera, "ready-for-capture", &ready, NULL); + fail_if (!ready, "not ready for capture"); + } + break; + } + return TRUE; +} + +static GstBusSyncReply +bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data) +{ + const GstStructure *st; + st = gst_message_get_structure (message); + if (st) { + if (gst_structure_has_name (st, "preview-image")) { + GST_DEBUG ("get preview-image message"); + received_preview_msg = TRUE; + } + } + + + return GST_BUS_PASS; + +} + +static void +setup (void) +{ + GstTagSetter *setter; + gchar *desc_str; + GstCaps *filter_caps; + GstBus *bus; + gint i; + + GST_INFO ("init"); + + main_loop = g_main_loop_new (NULL, TRUE); + + camera = gst_check_setup_element ("camerabin"); + + setup_camerabin_elements (camera); + + g_signal_connect (camera, "image-done", G_CALLBACK (capture_done), main_loop); + + bus = gst_pipeline_get_bus (GST_PIPELINE (camera)); + bus_source = gst_bus_add_watch (bus, (GstBusFunc) capture_bus_cb, main_loop); + gst_bus_set_sync_handler (bus, bus_sync_callback, main_loop); + gst_object_unref (bus); + + filter_caps = gst_caps_from_string ("video/x-raw-yuv,format=(fourcc)I420"); + g_object_set (G_OBJECT (camera), "filter-caps", filter_caps, NULL); + gst_caps_unref (filter_caps); + + /* force a low framerate here to not timeout the tests because of the + * encoders */ + g_signal_emit_by_name (camera, "set-video-resolution-fps", 320, 240, 5, 1, + NULL); + + /* Set some default tags */ + setter = GST_TAG_SETTER (camera); + desc_str = g_strdup_printf ("Created by %s", g_get_real_name ()); + + gst_tag_setter_add_tags (setter, GST_TAG_MERGE_REPLACE, + GST_TAG_DESCRIPTION, desc_str, NULL); + g_free (desc_str); + + if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + GST_WARNING ("setting camerabin to PLAYING failed"); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + gst_object_unref (camera); + camera = NULL; + } + + /* create the taglists */ + for (i = 0; i < TAGLISTS_COUNT; i++) { + taglists[i] = gst_tag_list_new (GST_TAG_ARTIST, "test-artist", + GST_TAG_GEO_LOCATION_LONGITUDE, g_random_double_range (-180, 180), + GST_TAG_GEO_LOCATION_LATITUDE, g_random_double_range (-90, 90), + GST_TAG_GEO_LOCATION_ELEVATION, g_random_double_range (0, 3000), NULL); + } + + GST_INFO ("init finished"); +} + +static void +teardown (void) +{ + gint i; + + g_source_remove (bus_source); + + if (camera) + gst_check_teardown_element (camera); + + for (i = 0; i < TAGLISTS_COUNT; i++) { + gst_tag_list_free (taglists[i]); + } + + GST_INFO ("done"); +} + +static void +test_camerabin_properties (GstElement * cam) +{ + guint flags; + gfloat zoom; + gboolean mute; + + flags = 0x1f; + g_object_set (G_OBJECT (cam), "flags", flags, NULL); + g_object_get (G_OBJECT (cam), "flags", &flags, NULL); + fail_if (flags != 0x1f, "setting camerabin flags failed"); + + zoom = 2.0; + g_object_set (G_OBJECT (cam), "zoom", zoom, NULL); + g_object_get (G_OBJECT (cam), "zoom", &zoom, NULL); + fail_if (zoom != 2.0, "setting camerabin zoom failed"); + g_object_set (G_OBJECT (cam), "zoom", 1.0f, NULL); + + mute = TRUE; + g_object_set (G_OBJECT (cam), "mute", mute, NULL); + g_object_get (G_OBJECT (cam), "mute", &mute, NULL); + fail_if (mute != TRUE, "setting camerabin mute failed"); + g_object_set (G_OBJECT (cam), "mute", FALSE, NULL); +} + +static gboolean +validity_bus_cb (GstBus * bus, GstMessage * message, gpointer data) +{ + GMainLoop *loop = (GMainLoop *) data; + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_ERROR: + fail_if (TRUE, "validating captured data failed"); + g_main_loop_quit (loop); + break; + case GST_MESSAGE_EOS: + g_main_loop_quit (loop); + GST_DEBUG ("eos"); + break; + case GST_MESSAGE_TAG:{ + GstTagList *tags = NULL; + gst_message_parse_tag (message, &tags); + if (validation_taglist) { + gst_tag_list_insert (validation_taglist, tags, GST_TAG_MERGE_REPLACE); + gst_tag_list_free (tags); + } else + validation_taglist = tags; + break; + } + default: + break; + } + return TRUE; +} + +static void +validate_taglist_foreach (const GstTagList * list, const gchar * tag, + gpointer user_data) +{ + GstTagList *other = GST_TAG_LIST (user_data); + + const GValue *val1 = gst_tag_list_get_value_index (list, tag, 0); + const GValue *val2 = gst_tag_list_get_value_index (other, tag, 0); + + fail_if (val1 == NULL); + fail_if (val2 == NULL); + + fail_unless (gst_value_can_intersect (val1, val2)); +} + +static void +extract_jpeg_tags (const gchar * filename, gint num) +{ + guint source; + GstBus *bus; + GMainLoop *loop = g_main_loop_new (NULL, FALSE); + const gchar *filepath = make_test_file_name (filename, num); + gchar *pipeline_str = g_strdup_printf ("filesrc location=%s ! " + "jpegparse ! fakesink", filepath); + GstElement *pipeline; + + pipeline = gst_parse_launch (pipeline_str, NULL); + fail_unless (pipeline != NULL); + g_free (pipeline_str); + + bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); + source = gst_bus_add_watch (bus, (GstBusFunc) validity_bus_cb, loop); + + gst_element_set_state (pipeline, GST_STATE_PLAYING); + g_main_loop_run (loop); + gst_element_set_state (pipeline, GST_STATE_NULL); + + g_main_loop_unref (loop); + g_source_remove (source); + gst_object_unref (bus); + gst_object_unref (pipeline); +} + +/* Validate captured files by playing them with playbin + * and checking that no errors occur. */ +static gboolean +check_file_validity (const gchar * filename, gint num, GstTagList * taglist) +{ + guint source; + GstBus *bus; + GMainLoop *loop = g_main_loop_new (NULL, FALSE); + GstElement *playbin = gst_element_factory_make ("playbin2", NULL); + GstElement *fakevideo = gst_element_factory_make ("fakesink", NULL); + GstElement *fakeaudio = gst_element_factory_make ("fakesink", NULL); + gchar *uri = g_strconcat ("file://", make_test_file_name (filename, num), + NULL); + + GST_DEBUG ("checking uri: %s", uri); + g_object_set (G_OBJECT (playbin), "uri", uri, "video-sink", fakevideo, + "audio-sink", fakeaudio, NULL); + + validation_taglist = NULL; + bus = gst_pipeline_get_bus (GST_PIPELINE (playbin)); + source = gst_bus_add_watch (bus, (GstBusFunc) validity_bus_cb, loop); + + gst_element_set_state (playbin, GST_STATE_PLAYING); + g_main_loop_run (loop); + gst_element_set_state (playbin, GST_STATE_NULL); + + /* special handling for images (jpg) as jpegparse isn't plugged by + * default due to its current low rank */ + if (taglist && strstr (filename, "image")) { + extract_jpeg_tags (filename, num); + } + + /* check taglist */ + if (taglist) { + fail_if (validation_taglist == NULL); + + GST_DEBUG ("Comparing taglists %" GST_PTR_FORMAT "; with %" GST_PTR_FORMAT, + taglist, validation_taglist); + + gst_tag_list_foreach (taglist, validate_taglist_foreach, + validation_taglist); + } + if (validation_taglist) + gst_tag_list_free (validation_taglist); + + g_free (uri); + g_source_remove (source); + gst_object_unref (bus); + gst_object_unref (playbin); + g_main_loop_unref (loop); + + return TRUE; +} + +static void +remove_file (const gchar * fn_template, guint num) +{ + const gchar *fn; + + fn = make_test_file_name (fn_template, num); + GST_INFO ("removing %s", fn); + g_unlink (fn); +} + +GST_START_TEST (test_single_image_capture) +{ + gboolean ready = FALSE; + gboolean idle = FALSE; + if (!camera) + return; + + /* Test photography iface settings */ + gst_element_get_state (GST_ELEMENT (camera), NULL, NULL, (2 * GST_SECOND)); + test_camerabin_properties (camera); + + /* set flags to disable additional elements */ + g_object_set (camera, "flags", 0, NULL); + + /* set still image mode */ + g_object_set (camera, "mode", 0, + "filename", make_test_file_name (SINGLE_IMAGE_FILENAME, 0), NULL); + + /* don't run viewfinder after capture */ + g_object_set (camera, "block-after-capture", TRUE, NULL); + + /* check that capturing is possible */ + g_object_get (camera, "ready-for-capture", &ready, NULL); + fail_if (!ready, "not ready for capture"); + + /* check that the camera is idle */ + g_object_get (camera, "idle", &idle, NULL); + fail_if (!idle, "camera should be idle"); + + GST_INFO ("starting capture"); + g_signal_emit_by_name (camera, "capture-start", NULL); + + g_object_get (camera, "ready-for-capture", &ready, NULL); + fail_if (ready, "ready for capture during capture"); + + g_main_loop_run (main_loop); + + g_object_get (camera, "idle", &idle, NULL); + fail_if (!idle, "camera should be idle"); + + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + + check_file_validity (SINGLE_IMAGE_FILENAME, 0, NULL); + remove_file (SINGLE_IMAGE_FILENAME, 0); +} + +GST_END_TEST; + +GST_START_TEST (test_single_image_capture_with_flags) +{ + if (!camera) + return; + + /* set flags to enable modifier elements */ + g_object_set (camera, "flags", 79, NULL); + + /* set still image mode */ + g_object_set (camera, "mode", 0, + "filename", make_test_file_name (SINGLE_IMAGE_WITH_FLAGS_FILENAME, 0), + NULL); + + GST_INFO ("starting capture"); + g_signal_emit_by_name (camera, "capture-start", NULL); + + g_main_loop_run (main_loop); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + + check_file_validity (SINGLE_IMAGE_WITH_FLAGS_FILENAME, 0, NULL); + remove_file (SINGLE_IMAGE_WITH_FLAGS_FILENAME, 0); +} + +GST_END_TEST; + +GST_START_TEST (test_video_recording) +{ + GstCaps *preview_caps; + gboolean idle = FALSE; + preview_caps = gst_caps_from_string ("video/x-raw-rgb,width=320,height=240"); + + if (!camera) + return; + + /* set flags to disable additional elements */ + g_object_set (camera, "flags", 0, NULL); + + /* Set video recording mode */ + g_object_set (camera, "mode", 1, + "filename", make_test_file_name (VIDEO_WITH_FLAGS_FILENAME, 0), NULL); + + /* Set preview-caps */ + g_object_set (camera, "preview-caps", preview_caps, NULL); + gst_caps_unref (preview_caps); + + /* check that the camera is idle */ + g_object_get (camera, "idle", &idle, NULL); + fail_if (!idle, "camera should be idle"); + + GST_INFO ("starting capture"); + g_signal_emit_by_name (camera, "capture-start", NULL); + + g_object_get (camera, "idle", &idle, NULL); + fail_if (idle, "camera should not be idle"); + + /* Record for one seconds */ + g_usleep (G_USEC_PER_SEC); + + g_signal_emit_by_name (camera, "capture-stop", NULL); + + g_object_get (camera, "idle", &idle, NULL); + fail_if (!idle, "camera should be idle"); + + /* check if receiving the preview-image message */ + fail_if (!received_preview_msg, + "creating video recording preview image failed"); + + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + + check_file_validity (VIDEO_WITH_FLAGS_FILENAME, 0, NULL); + remove_file (VIDEO_WITH_FLAGS_FILENAME, 0); +} + +GST_END_TEST; + +GST_START_TEST (test_video_recording_with_flags) +{ + GstCaps *preview_caps; + preview_caps = gst_caps_from_string ("video/x-raw-rgb,width=320,height=240"); + + if (!camera) + return; + + /* set flags to enable modifier elements */ + g_object_set (camera, "flags", 95, NULL); + + /* Set video recording mode */ + g_object_set (camera, "mode", 1, + "filename", make_test_file_name (VIDEO_FILENAME, 0), NULL); + + /* Set preview-caps */ + g_object_set (camera, "preview-caps", preview_caps, NULL); + gst_caps_unref (preview_caps); + + GST_INFO ("starting capture"); + g_signal_emit_by_name (camera, "capture-start", NULL); + /* Record for one seconds */ + g_usleep (G_USEC_PER_SEC); + g_signal_emit_by_name (camera, "capture-stop", NULL); + + /*check if receiving the preview-image message */ + fail_if (!received_preview_msg, + "creating video recording preview image failed"); + + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + + check_file_validity (VIDEO_FILENAME, 0, NULL); + remove_file (VIDEO_FILENAME, 0); +} + +GST_END_TEST; + +GST_START_TEST (test_video_recording_pause) +{ + gboolean idle = FALSE; + if (!camera) + return; + + /* Set video recording mode */ + g_object_set (camera, "mode", 1, + "filename", make_test_file_name (VIDEO_PAUSE_FILENAME, 0), NULL); + + g_object_get (camera, "idle", &idle, NULL); + fail_unless (idle, "camera should be idle"); + + GST_INFO ("starting capture"); + g_signal_emit_by_name (camera, "capture-start", NULL); + + g_object_get (camera, "idle", &idle, NULL); + fail_if (idle, "camera shouldn't be idle when recording"); + + /* Record for one seconds */ + g_usleep (G_USEC_PER_SEC); + + GST_INFO ("pause capture"); + g_signal_emit_by_name (camera, "capture-pause", NULL); + + g_object_get (camera, "idle", &idle, NULL); + fail_if (idle, "camera shouldn't be idle when recording and paused"); + + /* Record for one seconds */ + g_usleep (G_USEC_PER_SEC); + + GST_INFO ("continue capture"); + g_signal_emit_by_name (camera, "capture-start", NULL); + + g_object_get (camera, "idle", &idle, NULL); + fail_if (idle, "camera shouldn't be idle when recording"); + + /* Record for one seconds */ + g_usleep (G_USEC_PER_SEC); + g_signal_emit_by_name (camera, "capture-stop", NULL); + + g_object_get (camera, "idle", &idle, NULL); + fail_unless (idle, "camera should be idle after capture-stop"); + + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + + check_file_validity (VIDEO_PAUSE_FILENAME, 0, NULL); + remove_file (VIDEO_PAUSE_FILENAME, 0); +} + +GST_END_TEST; + +GST_START_TEST (test_video_recording_no_audio) +{ + GstCaps *preview_caps; + preview_caps = gst_caps_from_string ("video/x-raw-rgb,width=320,height=240"); + + if (!camera) + return; + + /* set flags to disable audio elements */ + g_object_set (camera, "flags", 32, NULL); + + /* Set video recording mode */ + g_object_set (camera, "mode", 1, + "filename", make_test_file_name (VIDEO_NOAUDIO_FILENAME, 0), NULL); + + /* Set preview-caps */ + g_object_set (camera, "preview-caps", preview_caps, NULL); + gst_caps_unref (preview_caps); + + GST_INFO ("starting capture"); + g_signal_emit_by_name (camera, "capture-start", NULL); + /* Record for one seconds */ + g_usleep (G_USEC_PER_SEC); + g_signal_emit_by_name (camera, "capture-stop", NULL); + + /* check if receiving the preview-image message */ + fail_if (!received_preview_msg, + "creating video recording preview image failed"); + + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + + check_file_validity (VIDEO_NOAUDIO_FILENAME, 0, NULL); + remove_file (VIDEO_NOAUDIO_FILENAME, 0); +} + +GST_END_TEST; + +GST_START_TEST (test_image_video_cycle) +{ + gint i; + + if (!camera) + return; + + cycle_count = CYCLE_COUNT_MAX; + + /* set still image mode */ + g_object_set (camera, "mode", 0, + "filename", make_test_file_name (CYCLE_IMAGE_FILENAME, cycle_count), + NULL); + + GST_INFO ("starting capture"); + g_signal_emit_by_name (camera, "capture-start", NULL); + + g_main_loop_run (main_loop); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + + /* validate all the files */ + for (i = 2; i > 0; i--) { + check_file_validity (CYCLE_IMAGE_FILENAME, i, NULL); + remove_file (CYCLE_IMAGE_FILENAME, i); + check_file_validity (CYCLE_VIDEO_FILENAME, i, NULL); + remove_file (CYCLE_VIDEO_FILENAME, i); + } +} + +GST_END_TEST; + +GST_START_TEST (test_image_tags_setting) +{ + gint i; + + g_object_set (camera, "flags", 0, NULL); + g_object_set (camera, "block-after-capture", TRUE, NULL); + + GST_INFO ("starting capture series"); + + for (i = 0; i < SEQUENTIAL_IMAGES_COUNT; i++) { + g_object_set (camera, "filename", + make_test_file_name (SEQUENTIAL_IMAGES_FILENAME, i), NULL); + gst_tag_setter_merge_tags (GST_TAG_SETTER (camera), + taglists[i % TAGLISTS_COUNT], + gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (camera))); + g_signal_emit_by_name (camera, "capture-start", NULL); + g_main_loop_run (main_loop); + } + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + + for (i = 0; i < SEQUENTIAL_IMAGES_COUNT; i++) { + check_file_validity (SEQUENTIAL_IMAGES_FILENAME, i, + taglists[i % TAGLISTS_COUNT]); + remove_file (SEQUENTIAL_IMAGES_FILENAME, i); + } +} + +GST_END_TEST; + +static Suite * +camerabin_suite (void) +{ + Suite *s = suite_create ("camerabin"); + TCase *tc_basic = tcase_create ("general"); + + /* Test that basic operations run without errors */ + suite_add_tcase (s, tc_basic); + /* Increase timeout due to video recording */ + tcase_set_timeout (tc_basic, 20); + tcase_add_checked_fixture (tc_basic, setup, teardown); + tcase_add_test (tc_basic, test_single_image_capture); + tcase_add_test (tc_basic, test_single_image_capture_with_flags); + tcase_add_test (tc_basic, test_video_recording); + tcase_add_test (tc_basic, test_video_recording_with_flags); + tcase_add_test (tc_basic, test_video_recording_pause); + tcase_add_test (tc_basic, test_video_recording_no_audio); + tcase_add_test (tc_basic, test_image_video_cycle); + tcase_add_test (tc_basic, test_image_tags_setting); + + return s; +} + +GST_CHECK_MAIN (camerabin); diff --git a/tests/check/elements/camerabin2.c b/tests/check/elements/camerabin2.c new file mode 100644 index 00000000..d8bea462 --- /dev/null +++ b/tests/check/elements/camerabin2.c @@ -0,0 +1,1585 @@ +/* GStreamer + * + * unit test for camerabin2 basic operations + * Copyright (C) 2010 Nokia Corporation <multimedia@maemo.org> + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <unistd.h> +#include <glib.h> +#include <glib/gstdio.h> +#include <gst/gst.h> +#include <gst/video/video.h> +#include <gst/check/gstcheck.h> +#include <gst/basecamerabinsrc/gstbasecamerasrc.h> +#include <gst/pbutils/encoding-profile.h> + +#define IMAGE_FILENAME "image" +#define VIDEO_FILENAME "video" +#define CAPTURE_COUNT 3 +#define VIDEO_DURATION 5 + +#define VIDEO_PAD_SUPPORTED_CAPS "video/x-raw, format=RGB, width=600, height=480" +#define IMAGE_PAD_SUPPORTED_CAPS "video/x-raw, format=RGB, width=800, height=600" + +/* custom test camera src element */ +#define GST_TYPE_TEST_CAMERA_SRC \ + (gst_test_camera_src_get_type()) +#define GST_TEST_CAMERA_SRC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TEST_CAMERA_SRC,GstTestCameraSrc)) +#define GST_TEST_CAMERA_SRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TEST_CAMERA_SRC,GstTestCameraSrcClass)) +#define GST_IS_TEST_REVERSE_NEGOTIATION_SINK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TEST_CAMERA_SRC)) +#define GST_IS_TEST_REVERSE_NEGOTIATION_SINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TEST_CAMERA_SRC)) +#define GST_TEST_CAMERA_SRC_CAST(obj) ((GstTestCameraSrc *)obj) + +typedef struct _GstTestCameraSrc GstTestCameraSrc; +typedef struct _GstTestCameraSrcClass GstTestCameraSrcClass; +struct _GstTestCameraSrc +{ + GstBaseCameraSrc element; + + GstPad *vfpad; + GstPad *vidpad; + GstPad *imgpad; + + GstCameraBinMode mode; +}; + +struct _GstTestCameraSrcClass +{ + GstBaseCameraSrcClass parent_class; +}; + +GType gst_test_camera_src_get_type (void); + +#define gst_test_camera_src_parent_class parent_class +G_DEFINE_TYPE (GstTestCameraSrc, gst_test_camera_src, GST_TYPE_BASE_CAMERA_SRC); + +static gboolean +gst_test_camera_src_set_mode (GstBaseCameraSrc * src, GstCameraBinMode mode) +{ + GstTestCameraSrc *self = GST_TEST_CAMERA_SRC (src); + + self->mode = mode; + return TRUE; +} + +static gboolean +gst_test_camera_src_query (GstPad * pad, GstObject * parent, GstQuery * query) +{ + GstTestCameraSrc *self = (GstTestCameraSrc *) GST_PAD_PARENT (pad); + GstCaps *result = NULL; + gboolean ret = FALSE; + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_CAPS: + if (pad == self->vfpad) { + result = gst_caps_new_any (); + } else if (pad == self->vidpad) { + result = gst_caps_from_string (VIDEO_PAD_SUPPORTED_CAPS); + } else if (pad == self->imgpad) { + result = gst_caps_from_string (IMAGE_PAD_SUPPORTED_CAPS); + } else { + g_assert_not_reached (); + } + if (result) { + GstCaps *filter; + + gst_query_parse_caps (query, &filter); + if (filter) { + GstCaps *tmp; + tmp = gst_caps_intersect (result, filter); + gst_caps_replace (&result, tmp); + gst_caps_unref (tmp); + } + gst_query_set_caps_result (query, result); + ret = TRUE; + } + break; + default: + break; + } + + return ret; +} + +static void +gst_test_camera_src_class_init (GstTestCameraSrcClass * klass) +{ + GstBaseCameraSrcClass *gstbasecamera_class; + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); + + gstbasecamera_class = GST_BASE_CAMERA_SRC_CLASS (klass); + gstbasecamera_class->set_mode = gst_test_camera_src_set_mode; + + gst_element_class_set_details_simple (gstelement_class, + "Test Camera Src", + "Camera/Src", + "Some test camera src", + "Thiago Santos <thiago.sousa.santos@collabora.com>"); +} + +static void +gst_test_camera_src_init (GstTestCameraSrc * self) +{ + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (parent_class); + GstPadTemplate *template; + + /* create pads */ + template = gst_element_class_get_pad_template (gstelement_class, + GST_BASE_CAMERA_SRC_VIEWFINDER_PAD_NAME); + self->vfpad = gst_pad_new_from_template (template, + GST_BASE_CAMERA_SRC_VIEWFINDER_PAD_NAME); + gst_element_add_pad (GST_ELEMENT_CAST (self), self->vfpad); + + template = gst_element_class_get_pad_template (gstelement_class, + GST_BASE_CAMERA_SRC_IMAGE_PAD_NAME); + self->imgpad = gst_pad_new_from_template (template, + GST_BASE_CAMERA_SRC_IMAGE_PAD_NAME); + gst_element_add_pad (GST_ELEMENT_CAST (self), self->imgpad); + + template = gst_element_class_get_pad_template (gstelement_class, + GST_BASE_CAMERA_SRC_VIDEO_PAD_NAME); + self->vidpad = gst_pad_new_from_template (template, + GST_BASE_CAMERA_SRC_VIDEO_PAD_NAME); + gst_element_add_pad (GST_ELEMENT_CAST (self), self->vidpad); + + /* add get caps functions */ + gst_pad_set_query_function (self->vfpad, gst_test_camera_src_query); + gst_pad_set_query_function (self->vidpad, gst_test_camera_src_query); + gst_pad_set_query_function (self->imgpad, gst_test_camera_src_query); +} + +/* end of custom test camera src element */ + + +static GstElement *camera; +static guint bus_source; +static GMainLoop *main_loop; +static gint capture_count = 0; +guint32 test_id = 0; +static gchar *image_filename; +static gchar *video_filename; + +static GstBuffer *preview_buffer; +static gchar *preview_filename; +static GstCaps *preview_caps; +static GstTagList *tags_found; + +static gboolean +validity_bus_cb (GstBus * bus, GstMessage * message, gpointer data); + +static GstMessage *wait_for_element_message (GstElement * camera, + const gchar * name, GstClockTime timeout); + +static void +validate_taglist_foreach (const GstTagList * list, const gchar * tag, + gpointer user_data) +{ + GstTagList *other = GST_TAG_LIST (user_data); + + const GValue *val1 = gst_tag_list_get_value_index (list, tag, 0); + const GValue *val2 = gst_tag_list_get_value_index (other, tag, 0); + + GST_DEBUG ("checking tag '%s'", tag); + + fail_if (val1 == NULL); + fail_if (val2 == NULL); + + fail_unless (gst_value_compare (val1, val2) == GST_VALUE_EQUAL); +} + + +/* helper function for filenames */ +static gchar * +make_test_file_name (const gchar * base_name, gint num) +{ + /* num == -1 means to keep the %d in the resulting string to be used on + * multifilesink like location */ + if (num == -1) { + return g_strdup_printf ("%s" G_DIR_SEPARATOR_S + "gstcamerabin2test_%s_%u_%%03d.cap", g_get_tmp_dir (), base_name, + test_id); + } else { + return g_strdup_printf ("%s" G_DIR_SEPARATOR_S + "gstcamerabin2test_%s_%u_%03d.cap", g_get_tmp_dir (), base_name, + test_id, num); + } +} + +static const gchar * +make_const_file_name (const gchar * filename, gint num) +{ + static gchar file_name[1000]; + + /* num == -1 means to keep the %d in the resulting string to be used on + * multifilesink like location */ + g_snprintf (file_name, 999, filename, num); + + return file_name; +} + +/* configuration */ + +static gboolean +capture_bus_cb (GstBus * bus, GstMessage * message, gpointer data) +{ + GMainLoop *loop = (GMainLoop *) data; + const GstStructure *st; + + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_ERROR:{ + GError *err = NULL; + gchar *debug = NULL; + + gst_message_parse_error (message, &err, &debug); + GST_WARNING ("ERROR: %s [%s]", err->message, debug); + g_error_free (err); + g_free (debug); + /* Write debug graph to file */ + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (camera), + GST_DEBUG_GRAPH_SHOW_ALL, "camerabin.error"); + + fail_if (TRUE, "error while capturing"); + g_main_loop_quit (loop); + break; + } + case GST_MESSAGE_WARNING:{ + GError *err = NULL; + gchar *debug = NULL; + + gst_message_parse_warning (message, &err, &debug); + GST_WARNING ("WARNING: %s [%s]", err->message, debug); + g_error_free (err); + g_free (debug); + /* Write debug graph to file */ + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (camera), + GST_DEBUG_GRAPH_SHOW_ALL, "camerabin.warning"); + break; + } + case GST_MESSAGE_EOS: + GST_DEBUG ("eos"); + g_main_loop_quit (loop); + break; + default: + st = gst_message_get_structure (message); + if (st && gst_structure_has_name (st, "image-done")) { + GST_INFO ("image captured"); + } else if (st && gst_structure_has_name (st, + GST_BASE_CAMERA_SRC_PREVIEW_MESSAGE_NAME)) { + GstBuffer *buf; + const GValue *value; + + value = gst_structure_get_value (st, "buffer"); + fail_unless (value != NULL); + buf = gst_value_get_buffer (value); + + if (preview_buffer) + gst_buffer_unref (preview_buffer); + preview_buffer = gst_buffer_ref (buf); + g_free (preview_filename); + preview_filename = g_strdup (gst_structure_get_string (st, "location")); + } + break; + } + return TRUE; +} + +static void +check_preview_image (GstElement * camera, const gchar * filename, gint index) +{ + gchar *prev_filename = NULL; + + if (!preview_buffer && camera) { + GstMessage *msg = wait_for_element_message (camera, + GST_BASE_CAMERA_SRC_PREVIEW_MESSAGE_NAME, GST_CLOCK_TIME_NONE); + fail_unless (msg != NULL); + gst_message_unref (msg); + } + fail_unless (preview_buffer != NULL); + if (filename) { + if (index >= 0) { + prev_filename = g_strdup_printf (filename, index); + } else { + prev_filename = g_strdup (filename); + } + fail_unless (preview_filename != NULL); + fail_unless (strcmp (preview_filename, prev_filename) == 0); + } + if (preview_caps) { + /* TODO porting + fail_unless (GST_BUFFER_CAPS (preview_buffer) != NULL); + fail_unless (gst_caps_can_intersect (GST_BUFFER_CAPS (preview_buffer), + preview_caps)); + */ + } + g_free (prev_filename); +} + +static void +extract_jpeg_tags (const gchar * filename, gint num) +{ + GstBus *bus; + GMainLoop *loop = g_main_loop_new (NULL, FALSE); + const gchar *filepath = make_const_file_name (filename, num); + gchar *pipeline_str = g_strdup_printf ("filesrc location=%s ! " + "jpegparse ! fakesink", filepath); + GstElement *pipeline; + guint source; + + pipeline = gst_parse_launch (pipeline_str, NULL); + fail_unless (pipeline != NULL); + g_free (pipeline_str); + + bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); + source = gst_bus_add_watch (bus, (GstBusFunc) validity_bus_cb, loop); + + gst_element_set_state (pipeline, GST_STATE_PLAYING); + g_main_loop_run (loop); + gst_element_set_state (pipeline, GST_STATE_NULL); + + gst_object_unref (bus); + g_source_remove (source); + gst_object_unref (pipeline); + g_main_loop_unref (loop); +} + +static void +setup_wrappercamerabinsrc_videotestsrc (void) +{ + GstBus *bus; + GstElement *vfbin; + GstElement *fakevideosink; + GstElement *src; + GstElement *testsrc; + GstElement *audiosrc; + + GST_INFO ("init"); + + test_id = g_random_int (); + bus_source = 0; + + main_loop = g_main_loop_new (NULL, TRUE); + + camera = gst_check_setup_element ("camerabin2"); + fakevideosink = gst_element_factory_make ("fakesink", NULL); + src = gst_element_factory_make ("wrappercamerabinsrc", NULL); + testsrc = gst_element_factory_make ("videotestsrc", NULL); + audiosrc = gst_element_factory_make ("audiotestsrc", NULL); + + preview_caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT, + 320, "height", G_TYPE_INT, 240, NULL); + + g_object_set (G_OBJECT (testsrc), "is-live", TRUE, NULL); + g_object_set (G_OBJECT (audiosrc), "is-live", TRUE, NULL); + g_object_set (G_OBJECT (src), "video-source", testsrc, NULL); + g_object_set (G_OBJECT (camera), "camera-source", src, "preview-caps", + preview_caps, "post-previews", TRUE, "audio-source", audiosrc, NULL); + gst_object_unref (src); + gst_object_unref (testsrc); + gst_object_unref (audiosrc); + + vfbin = gst_bin_get_by_name (GST_BIN (camera), "vf-bin"); + g_object_set (G_OBJECT (vfbin), "video-sink", fakevideosink, NULL); + gst_object_unref (vfbin); + gst_object_unref (fakevideosink); + + bus = gst_pipeline_get_bus (GST_PIPELINE (camera)); + bus_source = gst_bus_add_watch (bus, (GstBusFunc) capture_bus_cb, main_loop); + gst_object_unref (bus); + + tags_found = NULL; + capture_count = 0; + image_filename = make_test_file_name (IMAGE_FILENAME, -1); + video_filename = make_test_file_name (VIDEO_FILENAME, -1); + + GST_INFO ("init finished"); +} + +static void +teardown (void) +{ + gst_element_set_state (camera, GST_STATE_NULL); + + if (camera) + gst_check_teardown_element (camera); + camera = NULL; + + if (bus_source) + g_source_remove (bus_source); + + if (main_loop) + g_main_loop_unref (main_loop); + main_loop = NULL; + + if (preview_caps) + gst_caps_unref (preview_caps); + preview_caps = NULL; + + if (preview_buffer) + gst_buffer_unref (preview_buffer); + preview_buffer = NULL; + + g_free (preview_filename); + preview_filename = NULL; + + if (tags_found) + gst_tag_list_free (tags_found); + tags_found = NULL; + + g_free (video_filename); + video_filename = NULL; + + g_free (image_filename); + image_filename = NULL; + + GST_INFO ("done"); +} + +static gboolean +validity_bus_cb (GstBus * bus, GstMessage * message, gpointer data) +{ + GMainLoop *loop = (GMainLoop *) data; + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_ERROR:{ + GError *err = NULL; + gchar *debug = NULL; + + gst_message_parse_error (message, &err, &debug); + + GST_ERROR ("Error: %s : %s", err->message, debug); + g_error_free (err); + g_free (debug); + + fail_if (TRUE, "validating captured data failed"); + g_main_loop_quit (loop); + } + break; + case GST_MESSAGE_EOS: + g_main_loop_quit (loop); + GST_DEBUG ("eos"); + break; + case GST_MESSAGE_TAG:{ + GstTagList *taglist = NULL; + + gst_message_parse_tag (message, &taglist); + if (tags_found) { + gst_tag_list_insert (tags_found, taglist, GST_TAG_MERGE_REPLACE); + gst_tag_list_free (taglist); + } else { + tags_found = taglist; + } + GST_DEBUG ("tags: %" GST_PTR_FORMAT, tags_found); + } + break; + default: + break; + } + return TRUE; +} + +/* checks that tags in @tags_a are in @tags_b */ +static gboolean +taglist_is_subset (GstTagList * tags_a, GstTagList * tags_b) +{ + gst_tag_list_foreach (tags_a, validate_taglist_foreach, tags_b); + return TRUE; +} + +/* Validate captured files by playing them with playbin + * and checking that no errors occur. */ +#define WITH_AUDIO TRUE +#define NO_AUDIO FALSE +static gboolean +check_file_validity (const gchar * filename, gint num, GstTagList * taglist, + gint width, gint height, gboolean has_audio) +{ + GstBus *bus; + GstPad *pad; + GstCaps *caps; + gint caps_width, caps_height; + GstState state; + guint source; + + GMainLoop *loop = g_main_loop_new (NULL, FALSE); + GstElement *playbin = gst_element_factory_make ("playbin2", NULL); + GstElement *fakevideo = gst_element_factory_make ("fakesink", NULL); + GstElement *fakeaudio = gst_element_factory_make ("fakesink", NULL); + gchar *uri = g_strconcat ("file://", make_const_file_name (filename, num), + NULL); + + GST_DEBUG ("checking uri: %s", uri); + g_object_set (G_OBJECT (playbin), "uri", uri, "video-sink", fakevideo, + "audio-sink", fakeaudio, NULL); + + bus = gst_pipeline_get_bus (GST_PIPELINE (playbin)); + source = gst_bus_add_watch (bus, (GstBusFunc) validity_bus_cb, loop); + + gst_element_set_state (playbin, GST_STATE_PAUSED); + gst_element_get_state (playbin, &state, NULL, GST_SECOND * 3); + + if (width != 0 && height != 0) { + g_signal_emit_by_name (playbin, "get-video-pad", 0, &pad, NULL); + g_assert (pad != NULL); + caps = gst_pad_get_current_caps (pad); + + g_assert (gst_structure_get_int (gst_caps_get_structure (caps, 0), + "width", &caps_width)); + g_assert (gst_structure_get_int (gst_caps_get_structure (caps, 0), + "height", &caps_height)); + + g_assert (width == caps_width); + g_assert (height == caps_height); + + gst_caps_unref (caps); + gst_object_unref (pad); + } + if (has_audio) { + g_signal_emit_by_name (playbin, "get-audio-pad", 0, &pad, NULL); + g_assert (pad != NULL); + gst_object_unref (pad); + } + + gst_element_set_state (playbin, GST_STATE_PLAYING); + g_main_loop_run (loop); + gst_element_set_state (playbin, GST_STATE_NULL); + + /* special handling for images (jpg) as jpegparse isn't plugged by + * default due to its current low rank */ + if (taglist && strstr (filename, "image")) { + extract_jpeg_tags (filename, num); + } + + if (taglist) { + fail_unless (tags_found != NULL); + fail_unless (taglist_is_subset (taglist, tags_found)); + } + + g_free (uri); + g_source_remove (source); + gst_object_unref (bus); + gst_object_unref (playbin); + g_main_loop_unref (loop); + + return TRUE; +} + +static void +remove_file (const gchar * fn_template, guint num) +{ + const gchar *fn; + + fn = make_const_file_name (fn_template, num); + GST_INFO ("removing %s", fn); + g_unlink (fn); +} + +static GstPadProbeReturn +filter_buffer_count (GstPad * pad, GstPadProbeInfo * info, gpointer data) +{ + gint *counter = data; + + (*counter)++; + + return GST_PAD_PROBE_OK; +} + +static GstMessage * +wait_for_element_message (GstElement * camera, const gchar * name, + GstClockTime timeout) +{ + GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (camera)); + GstMessage *msg; + + while (1) { + msg = gst_bus_timed_pop_filtered (bus, timeout, GST_MESSAGE_ERROR | + GST_MESSAGE_EOS | GST_MESSAGE_ELEMENT); + + if (msg) { + if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT) { + const GstStructure *st = gst_message_get_structure (msg); + if (gst_structure_has_name (st, + GST_BASE_CAMERA_SRC_PREVIEW_MESSAGE_NAME)) { + GstBuffer *buf; + const GValue *value; + + value = gst_structure_get_value (st, "buffer"); + fail_unless (value != NULL); + buf = gst_value_get_buffer (value); + + if (preview_buffer) + gst_buffer_unref (preview_buffer); + preview_buffer = gst_buffer_ref (buf); + g_free (preview_filename); + preview_filename = + g_strdup (gst_structure_get_string (st, "location")); + } + + if (gst_structure_has_name (st, name)) + break; + else + gst_message_unref (msg); + } else { + gst_message_unref (msg); + msg = NULL; + break; + } + } + } + + gst_object_unref (bus); + return msg; +} + +static void +wait_for_idle_state (void) +{ + gboolean idle = FALSE; + + /* not the ideal way, but should be enough for testing */ + while (idle == FALSE) { + g_object_get (camera, "idle", &idle, NULL); + if (idle) + break; + + GST_LOG ("waiting for idle state.."); + g_usleep (G_USEC_PER_SEC / 5); + } + fail_unless (idle); +} + +GST_START_TEST (test_single_image_capture) +{ + gboolean idle; + GstMessage *msg; + if (!camera) + return; + + /* set still image mode */ + g_object_set (camera, "mode", 1, "location", image_filename, NULL); + + if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + GST_WARNING ("setting camerabin to PLAYING failed"); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + gst_object_unref (camera); + camera = NULL; + } + GST_INFO ("starting capture"); + fail_unless (camera != NULL); + g_object_get (camera, "idle", &idle, NULL); + fail_unless (idle); + g_signal_emit_by_name (camera, "start-capture", NULL); + + msg = wait_for_element_message (camera, "image-done", GST_CLOCK_TIME_NONE); + fail_unless (msg != NULL); + gst_message_unref (msg); + + /* check that we got a preview image */ + check_preview_image (camera, image_filename, 0); + + wait_for_idle_state (); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + check_file_validity (image_filename, 0, NULL, 0, 0, NO_AUDIO); + remove_file (image_filename, 0); +} + +GST_END_TEST; + + +GST_START_TEST (test_multiple_image_captures) +{ + gboolean idle; + gint i; + gint widths[] = { 800, 640, 1280 }; + gint heights[] = { 600, 480, 1024 }; + + if (!camera) + return; + + /* set still image mode */ + g_object_set (camera, "mode", 1, "location", image_filename, NULL); + + if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + GST_WARNING ("setting camerabin to PLAYING failed"); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + gst_object_unref (camera); + camera = NULL; + } + fail_unless (camera != NULL); + g_object_get (camera, "idle", &idle, NULL); + fail_unless (idle); + GST_INFO ("starting capture"); + + for (i = 0; i < 3; i++) { + GstMessage *msg; + GstCaps *caps; + + caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT, + widths[i], "height", G_TYPE_INT, heights[i], NULL); + + g_object_set (camera, "image-capture-caps", caps, NULL); + gst_caps_unref (caps); + + g_signal_emit_by_name (camera, "start-capture", NULL); + + msg = wait_for_element_message (camera, "image-done", GST_CLOCK_TIME_NONE); + fail_unless (msg != NULL); + gst_message_unref (msg); + + check_preview_image (camera, image_filename, i); + } + + wait_for_idle_state (); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + for (i = 0; i < 3; i++) { + check_file_validity (image_filename, i, NULL, widths[i], heights[i], + NO_AUDIO); + remove_file (image_filename, i); + } +} + +GST_END_TEST; + +GST_START_TEST (test_single_video_recording) +{ + GstMessage *msg; + gboolean idle; + if (!camera) + return; + + /* Set video recording mode */ + g_object_set (camera, "mode", 2, "location", video_filename, NULL); + + if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + GST_WARNING ("setting camerabin to PLAYING failed"); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + gst_object_unref (camera); + camera = NULL; + } + + GST_INFO ("starting capture"); + fail_unless (camera != NULL); + g_object_get (camera, "idle", &idle, NULL); + fail_unless (idle); + g_signal_emit_by_name (camera, "start-capture", NULL); + + g_object_get (camera, "idle", &idle, NULL); + fail_unless (!idle); + + /* Record for one seconds */ + g_timeout_add_seconds (VIDEO_DURATION, (GSourceFunc) g_main_loop_quit, + main_loop); + g_main_loop_run (main_loop); + + g_signal_emit_by_name (camera, "stop-capture", NULL); + + check_preview_image (camera, video_filename, 0); + + msg = wait_for_element_message (camera, "video-done", GST_CLOCK_TIME_NONE); + fail_unless (msg != NULL); + gst_message_unref (msg); + + wait_for_idle_state (); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + + check_file_validity (video_filename, 0, NULL, 0, 0, WITH_AUDIO); + remove_file (video_filename, 0); + +} + +GST_END_TEST; + +GST_START_TEST (test_multiple_video_recordings) +{ + gboolean idle; + gint i; + gint widths[] = { 800, 640, 1280 }; + gint heights[] = { 600, 480, 1024 }; + gint fr[] = { 20, 30, 5 }; + + if (!camera) + return; + + /* Set video recording mode */ + g_object_set (camera, "mode", 2, "location", video_filename, NULL); + + if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + GST_WARNING ("setting camerabin to PLAYING failed"); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + gst_object_unref (camera); + camera = NULL; + } + + GST_INFO ("starting capture"); + fail_unless (camera != NULL); + g_object_get (camera, "idle", &idle, NULL); + fail_unless (idle); + for (i = 0; i < 3; i++) { + GstMessage *msg; + GstCaps *caps; + + caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT, + widths[i], "height", G_TYPE_INT, heights[i], "framerate", + GST_TYPE_FRACTION, fr[i], 1, NULL); + + g_object_set (camera, "video-capture-caps", caps, NULL); + + gst_caps_unref (caps); + + GST_LOG ("starting #%d with caps %" GST_PTR_FORMAT, i, caps); + g_signal_emit_by_name (camera, "start-capture", NULL); + + g_object_get (camera, "idle", &idle, NULL); + fail_unless (!idle); + + g_timeout_add_seconds (VIDEO_DURATION, (GSourceFunc) g_main_loop_quit, + main_loop); + g_main_loop_run (main_loop); + + GST_LOG ("stopping run %d", i); + g_signal_emit_by_name (camera, "stop-capture", NULL); + + msg = wait_for_element_message (camera, "video-done", GST_CLOCK_TIME_NONE); + fail_unless (msg != NULL); + gst_message_unref (msg); + + GST_LOG ("video done, checking preview image"); + check_preview_image (camera, video_filename, i); + + GST_LOG ("waiting for idle state"); + wait_for_idle_state (); + GST_LOG ("finished run %d", i); + } + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + + for (i = 0; i < 3; i++) { + check_file_validity (video_filename, i, NULL, widths[i], heights[i], + WITH_AUDIO); + remove_file (video_filename, i); + } +} + +GST_END_TEST; + +GST_START_TEST (test_image_video_cycle) +{ + gint i; + + if (!camera) + return; + + if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + GST_WARNING ("setting camerabin to PLAYING failed"); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + gst_object_unref (camera); + camera = NULL; + } + + GST_INFO ("starting capture"); + for (i = 0; i < 2; i++) { + GstMessage *msg; + const gchar *img_filename; + const gchar *vid_filename; + + wait_for_idle_state (); + + /* take a picture */ + img_filename = make_const_file_name (image_filename, i); + g_object_set (camera, "mode", 1, NULL); + g_object_set (camera, "location", img_filename, NULL); + g_signal_emit_by_name (camera, "start-capture", NULL); + + msg = wait_for_element_message (camera, "image-done", GST_CLOCK_TIME_NONE); + fail_unless (msg != NULL); + gst_message_unref (msg); + + check_preview_image (camera, img_filename, i); + + /* now go to video */ + vid_filename = make_const_file_name (video_filename, i); + g_object_set (camera, "mode", 2, NULL); + g_object_set (camera, "location", vid_filename, NULL); + + g_signal_emit_by_name (camera, "start-capture", NULL); + g_timeout_add_seconds (VIDEO_DURATION, (GSourceFunc) g_main_loop_quit, + main_loop); + g_main_loop_run (main_loop); + g_signal_emit_by_name (camera, "stop-capture", NULL); + + msg = wait_for_element_message (camera, "video-done", GST_CLOCK_TIME_NONE); + fail_unless (msg != NULL); + gst_message_unref (msg); + + check_preview_image (camera, vid_filename, i); + } + + wait_for_idle_state (); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + + /* validate all the files */ + for (i = 0; i < 2; i++) { + check_file_validity (image_filename, i, NULL, 0, 0, NO_AUDIO); + remove_file (image_filename, i); + check_file_validity (video_filename, i, NULL, 0, 0, WITH_AUDIO); + remove_file (video_filename, i); + } +} + +GST_END_TEST; + + +GST_START_TEST (test_image_capture_previews) +{ + gint i; + gint widths[] = { 800, 640, 1280 }; + gint heights[] = { 600, 480, 1024 }; + + if (!camera) + return; + + /* set still image mode */ + g_object_set (camera, "mode", 1, "location", image_filename, NULL); + + if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + GST_WARNING ("setting camerabin to PLAYING failed"); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + gst_object_unref (camera); + camera = NULL; + } + fail_unless (camera != NULL); + GST_INFO ("starting capture"); + + for (i = 0; i < 3; i++) { + GstMessage *msg; + GstCaps *caps; + + caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT, + widths[i], "height", G_TYPE_INT, heights[i], NULL); + + g_object_set (camera, "preview-caps", caps, NULL); + gst_caps_replace (&preview_caps, caps); + gst_caps_unref (caps); + + g_signal_emit_by_name (camera, "start-capture", NULL); + + msg = wait_for_element_message (camera, "image-done", GST_CLOCK_TIME_NONE); + fail_unless (msg != NULL); + gst_message_unref (msg); + + check_preview_image (camera, image_filename, i); + remove_file (image_filename, i); + + if (preview_buffer) + gst_buffer_unref (preview_buffer); + preview_buffer = NULL; + gst_caps_replace (&preview_caps, NULL); + } + + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); +} + +GST_END_TEST; + + +GST_START_TEST (test_image_capture_with_tags) +{ + gint i; + GstTagList *taglists[3]; + + if (!camera) + return; + + taglists[0] = gst_tag_list_new (GST_TAG_COMMENT, "test1", + GST_TAG_GEO_LOCATION_LATITUDE, 36.6, GST_TAG_GEO_LOCATION_LONGITUDE, + -12.5, + GST_TAG_COPYRIGHT, "My copyright notice", + GST_TAG_DEVICE_MANUFACTURER, "MyFavoriteBrand", + GST_TAG_DEVICE_MODEL, "123v42.1", + GST_TAG_DESCRIPTION, "some description", + GST_TAG_APPLICATION_NAME, "camerabin2 test", + GST_TAG_GEO_LOCATION_ELEVATION, 300.85, NULL); + taglists[1] = gst_tag_list_new (GST_TAG_COMMENT, "test2", + GST_TAG_GEO_LOCATION_LATITUDE, 1.6, GST_TAG_GEO_LOCATION_LONGITUDE, + 0.0, + GST_TAG_COPYRIGHT, "some cp", + GST_TAG_DEVICE_MANUFACTURER, "ABRAND", + GST_TAG_DEVICE_MODEL, "abcd", + GST_TAG_DESCRIPTION, "desc", + GST_TAG_APPLICATION_NAME, "another cam test", + GST_TAG_GEO_LOCATION_ELEVATION, 10.0, NULL); + taglists[2] = gst_tag_list_new (GST_TAG_COMMENT, "test3", + GST_TAG_GEO_LOCATION_LATITUDE, 1.3, GST_TAG_GEO_LOCATION_LONGITUDE, + -5.0, + GST_TAG_COPYRIGHT, "CC", + GST_TAG_DEVICE_MANUFACTURER, "Homemade", + GST_TAG_DEVICE_MODEL, "xpto", + GST_TAG_DESCRIPTION, "another description", + GST_TAG_APPLICATION_NAME, "cam2 test", + GST_TAG_GEO_LOCATION_ELEVATION, 0.0, NULL); + + /* set still image mode */ + g_object_set (camera, "mode", 1, "location", image_filename, NULL); + + if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + GST_WARNING ("setting camerabin to PLAYING failed"); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + gst_object_unref (camera); + camera = NULL; + } + fail_unless (camera != NULL); + GST_INFO ("starting capture"); + + for (i = 0; i < 3; i++) { + GstMessage *msg; + gst_tag_setter_merge_tags (GST_TAG_SETTER (camera), taglists[i], + GST_TAG_MERGE_REPLACE); + + g_signal_emit_by_name (camera, "start-capture", NULL); + + msg = wait_for_element_message (camera, "image-done", GST_CLOCK_TIME_NONE); + fail_unless (msg != NULL); + gst_message_unref (msg); + } + + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + + for (i = 0; i < 3; i++) { + check_file_validity (image_filename, i, taglists[i], 0, 0, NO_AUDIO); + gst_tag_list_free (taglists[i]); + remove_file (image_filename, i); + } +} + +GST_END_TEST; + + +GST_START_TEST (test_video_capture_with_tags) +{ + gint i; + GstTagList *taglists[3]; + + if (!camera) + return; + + taglists[0] = gst_tag_list_new (GST_TAG_COMMENT, "test1", NULL); + taglists[1] = gst_tag_list_new (GST_TAG_COMMENT, "test2", NULL); + taglists[2] = gst_tag_list_new (GST_TAG_COMMENT, "test3", NULL); + + /* set video mode */ + g_object_set (camera, "mode", 2, "location", video_filename, NULL); + + /* set a profile that has xmp support for more tags being saved */ + { + GstEncodingContainerProfile *profile; + GstCaps *caps; + + caps = + gst_caps_new_simple ("video/quicktime", "variant", G_TYPE_STRING, + "apple", NULL); + profile = gst_encoding_container_profile_new ("qt", "jpeg+qt", caps, NULL); + gst_caps_unref (caps); + + caps = gst_caps_new_simple ("image/jpeg", NULL, NULL); + if (!gst_encoding_container_profile_add_profile (profile, + (GstEncodingProfile *) gst_encoding_video_profile_new (caps, + NULL, NULL, 1))) { + GST_WARNING_OBJECT (camera, "Failed to create encoding profiles"); + } + gst_caps_unref (caps); + + g_object_set (camera, "video-profile", profile, NULL); + gst_encoding_profile_unref (profile); + } + + if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + GST_WARNING ("setting camerabin to PLAYING failed"); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + gst_object_unref (camera); + camera = NULL; + } + fail_unless (camera != NULL); + GST_INFO ("starting capture"); + + for (i = 0; i < 3; i++) { + GstMessage *msg; + + gst_tag_setter_merge_tags (GST_TAG_SETTER (camera), taglists[i], + GST_TAG_MERGE_REPLACE); + + g_signal_emit_by_name (camera, "start-capture", NULL); + + g_timeout_add_seconds (3, (GSourceFunc) g_main_loop_quit, main_loop); + g_main_loop_run (main_loop); + + g_signal_emit_by_name (camera, "stop-capture", NULL); + + msg = wait_for_element_message (camera, "video-done", GST_CLOCK_TIME_NONE); + fail_unless (msg != NULL); + gst_message_unref (msg); + } + + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + + for (i = 0; i < 3; i++) { + check_file_validity (video_filename, i, taglists[i], 0, 0, NO_AUDIO); + gst_tag_list_free (taglists[i]); + remove_file (video_filename, i); + } +} + +GST_END_TEST; + + +GST_START_TEST (test_supported_caps) +{ + GstCaps *padcaps = NULL; + GstCaps *expectedcaps; + GstElement *src; + + if (!camera) + return; + + src = g_object_new (GST_TYPE_TEST_CAMERA_SRC, NULL); + g_object_set (camera, "camera-source", src, NULL); + gst_object_unref (src); + + if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + GST_WARNING ("setting camerabin to PLAYING failed"); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + gst_object_unref (camera); + camera = NULL; + } + g_assert (camera != NULL); + + expectedcaps = gst_caps_from_string (VIDEO_PAD_SUPPORTED_CAPS); + g_object_get (G_OBJECT (camera), "video-capture-supported-caps", &padcaps, + NULL); + g_assert (expectedcaps != NULL); + g_assert (padcaps != NULL); + g_assert (gst_caps_is_equal (padcaps, expectedcaps)); + gst_caps_unref (expectedcaps); + gst_caps_unref (padcaps); + + expectedcaps = gst_caps_from_string (IMAGE_PAD_SUPPORTED_CAPS); + g_object_get (G_OBJECT (camera), "image-capture-supported-caps", &padcaps, + NULL); + g_assert (expectedcaps != NULL); + g_assert (padcaps != NULL); + g_assert (gst_caps_is_equal (padcaps, expectedcaps)); + gst_caps_unref (expectedcaps); + gst_caps_unref (padcaps); + + gst_element_set_state (camera, GST_STATE_NULL); +} + +GST_END_TEST; + + +GST_START_TEST (test_idle_property) +{ + GstMessage *msg; + gboolean idle; + if (!camera) + return; + + /* Set video recording mode */ + g_object_set (camera, "mode", 2, "location", video_filename, NULL); + + if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + GST_WARNING ("setting camerabin to PLAYING failed"); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + gst_object_unref (camera); + camera = NULL; + } + + GST_INFO ("starting capture"); + fail_unless (camera != NULL); + g_object_get (camera, "idle", &idle, NULL); + fail_unless (idle); + g_signal_emit_by_name (camera, "start-capture", NULL); + g_object_get (camera, "idle", &idle, NULL); + fail_unless (!idle); + + /* emit a second start-capture that should be ignored */ + g_signal_emit_by_name (camera, "start-capture", NULL); + g_object_get (camera, "idle", &idle, NULL); + fail_unless (!idle); + + /* Record for one seconds */ + g_timeout_add_seconds (VIDEO_DURATION, (GSourceFunc) g_main_loop_quit, + main_loop); + g_main_loop_run (main_loop); + + g_signal_emit_by_name (camera, "stop-capture", NULL); + + msg = wait_for_element_message (camera, "video-done", GST_CLOCK_TIME_NONE); + fail_unless (msg != NULL); + gst_message_unref (msg); + + check_preview_image (camera, video_filename, 0); + + wait_for_idle_state (); + + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + + check_file_validity (video_filename, 0, NULL, 0, 0, WITH_AUDIO); + remove_file (video_filename, 0); +} + +GST_END_TEST; + + +GST_START_TEST (test_image_custom_filter) +{ + GstElement *vf_filter; + GstElement *image_filter; + GstElement *preview_filter; + GstPad *pad; + gint vf_probe_counter = 0; + gint image_probe_counter = 0; + gint preview_probe_counter = 0; + + if (!camera) + return; + + vf_filter = gst_element_factory_make ("identity", "vf-filter"); + image_filter = gst_element_factory_make ("identity", "img-filter"); + preview_filter = gst_element_factory_make ("identity", "preview-filter"); + + pad = gst_element_get_static_pad (vf_filter, "src"); + gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, filter_buffer_count, + &vf_probe_counter, NULL); + gst_object_unref (pad); + + pad = gst_element_get_static_pad (image_filter, "src"); + gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, filter_buffer_count, + &image_probe_counter, NULL); + gst_object_unref (pad); + + pad = gst_element_get_static_pad (preview_filter, "src"); + gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, filter_buffer_count, + &preview_probe_counter, NULL); + gst_object_unref (pad); + + /* set still image mode and filters */ + g_object_set (camera, "mode", 1, + "location", image_filename, + "viewfinder-filter", vf_filter, "image-filter", image_filter, + "preview-filter", preview_filter, NULL); + + gst_object_unref (vf_filter); + gst_object_unref (preview_filter); + gst_object_unref (image_filter); + + if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + GST_WARNING ("setting camerabin to PLAYING failed"); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + gst_object_unref (camera); + camera = NULL; + } + GST_INFO ("starting capture"); + fail_unless (camera != NULL); + g_signal_emit_by_name (camera, "start-capture", NULL); + + g_timeout_add_seconds (3, (GSourceFunc) g_main_loop_quit, main_loop); + g_main_loop_run (main_loop); + + /* check that we got a preview image */ + check_preview_image (camera, image_filename, 0); + + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + check_file_validity (image_filename, 0, NULL, 0, 0, NO_AUDIO); + remove_file (image_filename, 0); + + fail_unless (vf_probe_counter > 0); + fail_unless (image_probe_counter == 1); + fail_unless (preview_probe_counter == 1); +} + +GST_END_TEST; + + +GST_START_TEST (test_video_custom_filter) +{ + GstElement *vf_filter; + GstElement *video_filter; + GstElement *preview_filter; + GstElement *audio_filter; + GstPad *pad; + gint vf_probe_counter = 0; + gint video_probe_counter = 0; + gint preview_probe_counter = 0; + gint audio_probe_counter = 0; + + if (!camera) + return; + + vf_filter = gst_element_factory_make ("identity", "vf-filter"); + video_filter = gst_element_factory_make ("identity", "video-filter"); + preview_filter = gst_element_factory_make ("identity", "preview-filter"); + audio_filter = gst_element_factory_make ("identity", "audio-filter"); + + pad = gst_element_get_static_pad (vf_filter, "src"); + gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, filter_buffer_count, + &vf_probe_counter, NULL); + gst_object_unref (pad); + + pad = gst_element_get_static_pad (video_filter, "src"); + gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, filter_buffer_count, + &video_probe_counter, NULL); + gst_object_unref (pad); + + pad = gst_element_get_static_pad (audio_filter, "src"); + gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, filter_buffer_count, + &audio_probe_counter, NULL); + gst_object_unref (pad); + + pad = gst_element_get_static_pad (preview_filter, "src"); + gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, filter_buffer_count, + &preview_probe_counter, NULL); + gst_object_unref (pad); + + /* set still image mode and filters */ + g_object_set (camera, "mode", 2, + "location", video_filename, + "viewfinder-filter", vf_filter, "video-filter", video_filter, + "preview-filter", preview_filter, "audio-filter", audio_filter, NULL); + + gst_object_unref (vf_filter); + gst_object_unref (preview_filter); + gst_object_unref (video_filter); + gst_object_unref (audio_filter); + + if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + GST_WARNING ("setting camerabin to PLAYING failed"); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + gst_object_unref (camera); + camera = NULL; + } + GST_INFO ("starting capture"); + fail_unless (camera != NULL); + g_signal_emit_by_name (camera, "start-capture", NULL); + + g_timeout_add_seconds (VIDEO_DURATION, (GSourceFunc) g_main_loop_quit, + main_loop); + g_main_loop_run (main_loop); + g_signal_emit_by_name (camera, "stop-capture", NULL); + + /* check that we got a preview image */ + check_preview_image (camera, video_filename, 0); + + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + check_file_validity (video_filename, 0, NULL, 0, 0, WITH_AUDIO); + remove_file (video_filename, 0); + + fail_unless (vf_probe_counter > 0); + fail_unless (video_probe_counter > 0); + fail_unless (audio_probe_counter > 0); + fail_unless (preview_probe_counter == 1); +} + +GST_END_TEST; + +#define LOCATION_SWITCHING_FILENAMES_COUNT 5 + +static gboolean +image_location_switch_do_capture (gpointer data) +{ + gchar **filenames = data; + if (capture_count >= LOCATION_SWITCHING_FILENAMES_COUNT) { + g_main_loop_quit (main_loop); + } + + g_object_set (camera, "location", filenames[capture_count], NULL); + g_signal_emit_by_name (camera, "start-capture", NULL); + capture_count++; + return FALSE; +} + +static void +image_location_switch_readyforcapture (GObject * obj, GParamSpec * pspec, + gpointer user_data) +{ + gboolean ready; + + g_object_get (obj, "ready-for-capture", &ready, NULL); + if (ready) { + g_idle_add (image_location_switch_do_capture, user_data); + } +}; + +/* + * Tests that setting the location and then doing an image + * capture will set this capture resulting filename to the + * correct location. + * + * There was a bug in which setting the location, issuing a capture + * and then setting a new location would cause this capture to have + * the location set after this capture. This test should prevent it + * from happening again. + */ +GST_START_TEST (test_image_location_switching) +{ + gchar *filenames[LOCATION_SWITCHING_FILENAMES_COUNT + 1]; + gint i; + glong notify_id; + GstCaps *caps; + GstElement *src; + GstMessage *msg; + + if (!camera) + return; + + g_object_get (camera, "camera-source", &src, NULL); + + for (i = 0; i < LOCATION_SWITCHING_FILENAMES_COUNT; i++) { + filenames[i] = make_test_file_name ("image-switching-filename-test", i); + } + filenames[LOCATION_SWITCHING_FILENAMES_COUNT] = NULL; + + /* set still image mode */ + g_object_set (camera, "mode", 1, NULL); + caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT, + 800, "height", G_TYPE_INT, 600, NULL); + g_object_set (camera, "image-capture-caps", caps, NULL); + gst_caps_unref (caps); + + if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + GST_WARNING ("setting camerabin to PLAYING failed"); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + gst_object_unref (camera); + camera = NULL; + } + fail_unless (camera != NULL); + GST_INFO ("starting capture"); + + notify_id = g_signal_connect (G_OBJECT (src), + "notify::ready-for-capture", + G_CALLBACK (image_location_switch_readyforcapture), filenames); + + g_idle_add (image_location_switch_do_capture, filenames); + g_main_loop_run (main_loop); + + msg = wait_for_element_message (camera, "image-done", GST_CLOCK_TIME_NONE); + fail_unless (msg != NULL); + gst_message_unref (msg); + + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + + for (i = 0; i < LOCATION_SWITCHING_FILENAMES_COUNT; i++) { + GST_INFO ("Checking for file: %s", filenames[i]); + fail_unless (g_file_test (filenames[i], G_FILE_TEST_IS_REGULAR)); + } + + for (i = 0; i < LOCATION_SWITCHING_FILENAMES_COUNT; i++) { + g_unlink (filenames[i]); + g_free (filenames[i]); + } + g_signal_handler_disconnect (src, notify_id); +} + +GST_END_TEST; + + +typedef struct _TestCaseDef +{ + const gchar *name; + gpointer setup_func; +} TestCaseDef; + +TestCaseDef tests[] = { + {"wrappercamerabinsrc", setup_wrappercamerabinsrc_videotestsrc} +}; + +static Suite * +camerabin_suite (void) +{ + GstElementFactory *jpegenc_factory; + Suite *s = suite_create ("camerabin2"); + gint i; + TCase *tc_generic = tcase_create ("generic"); + + jpegenc_factory = gst_element_factory_find ("jpegenc"); + if (jpegenc_factory == NULL) { + GST_WARNING ("Skipping camerabin2 tests because jpegenc is missing"); + goto end; + } + + suite_add_tcase (s, tc_generic); + tcase_add_checked_fixture (tc_generic, setup_wrappercamerabinsrc_videotestsrc, + teardown); + tcase_add_test (tc_generic, test_supported_caps); + + for (i = 0; i < G_N_ELEMENTS (tests); i++) { + TCase *tc_basic = tcase_create (tests[i].name); + suite_add_tcase (s, tc_basic); + + /* Increase timeout due to video recording */ + tcase_set_timeout (tc_basic, 60); + tcase_add_checked_fixture (tc_basic, tests[i].setup_func, teardown); + + tcase_add_test (tc_basic, test_single_image_capture); + tcase_add_test (tc_basic, test_single_video_recording); + tcase_add_test (tc_basic, test_image_video_cycle); + if (gst_plugin_feature_check_version ((GstPluginFeature *) jpegenc_factory, + 0, 10, 27)) + tcase_add_test (tc_basic, test_multiple_image_captures); + else + GST_WARNING ("Skipping image capture test because -good 0.10.27 is " + "needed"); + tcase_add_test (tc_basic, test_multiple_video_recordings); + + tcase_add_test (tc_basic, test_image_capture_previews); + tcase_add_test (tc_basic, test_image_capture_with_tags); + + tcase_add_test (tc_basic, test_video_capture_with_tags); + + tcase_add_test (tc_basic, test_idle_property); + + tcase_add_test (tc_basic, test_image_custom_filter); + tcase_add_test (tc_basic, test_video_custom_filter); + + tcase_add_test (tc_basic, test_image_location_switching); + } + +end: + return s; +} + +GST_CHECK_MAIN (camerabin); diff --git a/tests/check/elements/dataurisrc.c b/tests/check/elements/dataurisrc.c new file mode 100644 index 00000000..49c9bdbb --- /dev/null +++ b/tests/check/elements/dataurisrc.c @@ -0,0 +1,233 @@ +/* GStreamer unit test for dataurisrc + * + * Copyright (C) 2010 Tim-Philipp Müller <tim centricular net> + * + * 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. + */ + +#include <unistd.h> + +#include <gst/check/gstcheck.h> + +/* sine wave encoded in ogg/vorbis, created with: + * gst-launch-0.10 audiotestsrc num-buffers=110 ! audioconvert ! \ + * audio/x-raw,channels=1 ! vorbisenc ! oggmux ! \ + * filesink location=sine.ogg + * and then encoded to base64 */ +const gchar data_uri[] = "data:audio/ogg;base64," + "T2dnUwACAAAAAAAAAACVWbd7AAAAAHgH02kBHgF2b3JiaXMAAAAAAUSsAAAAAAAAgDgBAAAAAAC4" + "AU9nZ1MAAAAAAAAAAAAAlVm3ewEAAADrU8FRDkv///////////////+BA3ZvcmJpcx0AAABYaXBo" + "Lk9yZyBsaWJWb3JiaXMgSSAyMDA5MDcwOQEAAAAaAAAAREVTQ1JJUFRJT049YXVkaW90ZXN0IHdh" + "dmUBBXZvcmJpcyJCQ1YBAEAAACRzGCpGpXMWhBAaQlAZ4xxCzmvsGUJMEYIcMkxbyyVzkCGkoEKI" + "WyiB0JBVAABAAACHQXgUhIpBCCGEJT1YkoMnPQghhIg5eBSEaUEIIYQQQgghhBBCCCGERTlokoMn" + "QQgdhOMwOAyD5Tj4HIRFOVgQgydB6CCED0K4moOsOQghhCQ1SFCDBjnoHITCLCiKgsQwuBaEBDUo" + "jILkMMjUgwtCiJqDSTX4GoRnQXgWhGlBCCGEJEFIkIMGQcgYhEZBWJKDBjm4FITLQagahCo5CB+E" + "IDRkFQCQAACgoiiKoigKEBqyCgDIAAAQQFEUx3EcyZEcybEcCwgNWQUAAAEACAAAoEiKpEiO5EiS" + "JFmSJVmSJVmS5omqLMuyLMuyLMsyEBqyCgBIAABQUQxFcRQHCA1ZBQBkAAAIoDiKpViKpWiK54iO" + "CISGrAIAgAAABAAAEDRDUzxHlETPVFXXtm3btm3btm3btm3btm1blmUZCA1ZBQBAAAAQ0mlmqQaI" + "MAMZBkJDVgEACAAAgBGKMMSA0JBVAABAAACAGEoOogmtOd+c46BZDppKsTkdnEi1eZKbirk555xz" + "zsnmnDHOOeecopxZDJoJrTnnnMSgWQqaCa0555wnsXnQmiqtOeeccc7pYJwRxjnnnCateZCajbU5" + "55wFrWmOmkuxOeecSLl5UptLtTnnnHPOOeecc84555zqxekcnBPOOeecqL25lpvQxTnnnE/G6d6c" + "EM4555xzzjnnnHPOOeecIDRkFQAABABAEIaNYdwpCNLnaCBGEWIaMulB9+gwCRqDnELq0ehopJQ6" + "CCWVcVJKJwgNWQUAAAIAQAghhRRSSCGFFFJIIYUUYoghhhhyyimnoIJKKqmooowyyyyzzDLLLLPM" + "Ouyssw47DDHEEEMrrcRSU2011lhr7jnnmoO0VlprrbVSSimllFIKQkNWAQAgAAAEQgYZZJBRSCGF" + "FGKIKaeccgoqqIDQkFUAACAAgAAAAABP8hzRER3RER3RER3RER3R8RzPESVREiVREi3TMjXTU0VV" + "dWXXlnVZt31b2IVd933d933d+HVhWJZlWZZlWZZlWZZlWZZlWZYgNGQVAAACAAAghBBCSCGFFFJI" + "KcYYc8w56CSUEAgNWQUAAAIACAAAAHAUR3EcyZEcSbIkS9IkzdIsT/M0TxM9URRF0zRV0RVdUTdt" + "UTZl0zVdUzZdVVZtV5ZtW7Z125dl2/d93/d93/d93/d93/d9XQdCQ1YBABIAADqSIymSIimS4ziO" + "JElAaMgqAEAGAEAAAIriKI7jOJIkSZIlaZJneZaomZrpmZ4qqkBoyCoAABAAQAAAAAAAAIqmeIqp" + "eIqoeI7oiJJomZaoqZoryqbsuq7ruq7ruq7ruq7ruq7ruq7ruq7ruq7ruq7ruq7ruq7ruq4LhIas" + "AgAkAAB0JEdyJEdSJEVSJEdygNCQVQCADACAAAAcwzEkRXIsy9I0T/M0TxM90RM901NFV3SB0JBV" + "AAAgAIAAAAAAAAAMybAUy9EcTRIl1VItVVMt1VJF1VNVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV" + "VVVVVVVVVVVN0zRNEwgNWQkAAAEA0FpzzK2XjkHorJfIKKSg10455qTXzCiCnOcQMWOYx1IxQwzG" + "lkGElAVCQ1YEAFEAAIAxyDHEHHLOSeokRc45Kh2lxjlHqaPUUUqxplo7SqW2VGvjnKPUUcoopVpL" + "qx2lVGuqsQAAgAAHAIAAC6HQkBUBQBQAAIEMUgophZRizinnkFLKOeYcYoo5p5xjzjkonZTKOSed" + "kxIppZxjzinnnJTOSeack9JJKAAAIMABACDAQig0ZEUAECcA4HAcTZM0TRQlTRNFTxRd1xNF1ZU0" + "zTQ1UVRVTRRN1VRVWRZNVZYlTTNNTRRVUxNFVRVVU5ZNVbVlzzRt2VRV3RZV1bZlW/Z9V5Z13TNN" + "2RZV1bZNVbV1V5Z1XbZt3Zc0zTQ1UVRVTRRV11RV2zZV1bY1UXRdUVVlWVRVWXZdWddVV9Z9TRRV" + "1VNN2RVVVZZV2dVlVZZ1X3RV3VZd2ddVWdZ929aFX9Z9wqiqum7Krq6rsqz7si77uu3rlEnTTFMT" + "RVXVRFFVTVe1bVN1bVsTRdcVVdWWRVN1ZVWWfV91ZdnXRNF1RVWVZVFVZVmVZV13ZVe3RVXVbVV2" + "fd90XV2XdV1YZlv3hdN1dV2VZd9XZVn3ZV3H1nXf90zTtk3X1XXTVXXf1nXlmW3b+EVV1XVVloVf" + "lWXf14XheW7dF55RVXXdlF1fV2VZF25fN9q+bjyvbWPbPrKvIwxHvrAsXds2ur5NmHXd6BtD4TeG" + "NNO0bdNVdd10XV+Xdd1o67pQVFVdV2XZ91VX9n1b94Xh9n3fGFXX91VZFobVlp1h932l7guVVbaF" + "39Z155htXVh+4+j8vjJ0dVto67qxzL6uPLtxdIY+AgAABhwAAAJMKAOFhqwIAOIEABiEnENMQYgU" + "gxBCSCmEkFLEGITMOSkZc1JCKamFUlKLGIOQOSYlc05KKKGlUEpLoYTWQimxhVJabK3VmlqLNYTS" + "WiiltVBKi6mlGltrNUaMQcick5I5J6WU0loopbXMOSqdg5Q6CCmllFosKcVYOSclg45KByGlkkpM" + "JaUYQyqxlZRiLCnF2FpsucWYcyilxZJKbCWlWFtMObYYc44Yg5A5JyVzTkoopbVSUmuVc1I6CCll" + "DkoqKcVYSkoxc05KByGlDkJKJaUYU0qxhVJiKynVWEpqscWYc0sx1lBSiyWlGEtKMbYYc26x5dZB" + "aC2kEmMoJcYWY66ttRpDKbGVlGIsKdUWY629xZhzKCXGkkqNJaVYW425xhhzTrHlmlqsucXYa225" + "9Zpz0Km1WlNMubYYc465BVlz7r2D0FoopcVQSoyttVpbjDmHUmIrKdVYSoq1xZhza7H2UEqMJaVY" + "S0o1thhrjjX2mlqrtcWYa2qx5ppz7zHm2FNrNbcYa06x5Vpz7r3m1mMBAAADDgAAASaUgUJDVgIA" + "UQAABCFKMQahQYgx56Q0CDHmnJSKMecgpFIx5hyEUjLnIJSSUuYchFJSCqWkklJroZRSUmqtAACA" + "AgcAgAAbNCUWByg0ZCUAkAoAYHAcy/I8UTRV2XYsyfNE0TRV1bYdy/I8UTRNVbVty/NE0TRV1XV1" + "3fI8UTRVVXVdXfdEUTVV1XVlWfc9UTRVVXVdWfZ901RV1XVlWbaFXzRVV3VdWZZl31hd1XVlWbZ1" + "WxhW1XVdWZZtWzeGW9d13feFYTk6t27ruu/7wvE7xwAA8AQHAKACG1ZHOCkaCyw0ZCUAkAEAQBiD" + "kEFIIYMQUkghpRBSSgkAABhwAAAIMKEMFBqyEgCIAgAACJFSSimNlFJKKaWRUkoppZQSQgghhBBC" + "CCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQggFAPhPOAD4P9igKbE4QKEhKwGAcAAAwBilmHIMOgkp" + "NYw5BqGUlFJqrWGMMQilpNRaS5VzEEpJqbXYYqycg1BSSq3FGmMHIaXWWqyx1po7CCmlFmusOdgc" + "Smktxlhzzr33kFJrMdZac++9l9ZirDXn3IMQwrQUY6659uB77ym2WmvNPfgghFCx1Vpz8EEIIYSL" + "Mffcg/A9CCFcjDnnHoTwwQdhAAB3gwMARIKNM6wknRWOBhcashIACAkAIBBiijHnnIMQQgiRUow5" + "5xyEEEIoJVKKMeecgw5CCCVkjDnnHIQQQiillIwx55yDEEIJpZSSOecchBBCKKWUUjLnoIMQQgml" + "lFJK5xyEEEIIpZRSSumggxBCCaWUUkopIYQQQgmllFJKKSWEEEIJpZRSSimlhBBKKKWUUkoppZQQ" + "QimllFJKKaWUEkIopZRSSimllJJCKaWUUkoppZRSUiillFJKKaWUUkoJpZRSSimllJRSSQUAABw4" + "AAAEGEEnGVUWYaMJFx6AQkNWAgBAAAAUxFZTiZ1BzDFnqSEIMaipQkophjFDyiCmKVMKIYUhc4oh" + "AqHFVkvFAAAAEAQACAgJADBAUDADAAwOED4HQSdAcLQBAAhCZIZINCwEhweVABExFQAkJijkAkCF" + "xUXaxQV0GeCCLu46EEIQghDE4gAKSMDBCTc88YYn3OAEnaJSBwEAAAAAcAAADwAAxwUQEdEcRobG" + "BkeHxwdISAAAAAAAyADABwDAIQJERDSHkaGxwdHh8QESEgAAAAAAAAAAAAQEBAAAAAAAAgAAAAQE" + "T2dnUwAAwFIAAAAAAACVWbd7AgAAAPtNZ2oXKxQ4JiYlJSUmJSYmJSUlJiUmJiYmJSWM64s3q+wD" + "MAQAnICN1ydV8tWC8lN5Kk/lqTyVp/JUuqu7uqu7KgjDMEwAnO2rVb0qWHw+DQAAAAAAIC5HDwU6" + "yj7C62/u4teEkwiA2gAAAAAAAAAAAAAAbL8fuP/EQFh6odjwP2uvvNHgH/d6FLjkcubZXtUAAJ7K" + "3qo3ye0WocGOPxVMBwAAAAAAAAAAAAAA8H7XAwAAcm8vpwcAnsreqjfJ7RahwY4/FUwHAAAAAAAA" + "AAAAAADw/l0AAIB2r4kzAgCeyt4qNyntFqHBzv0KpgNQAAAAAAAAAAAAAODQowQAgPjtOQoAnsre" + "KjfJ/RYF7NyvYDoAAAAAAAAAAAAAAIBf3wMAgL2/NDECAJ7K3qo3Ke0WpcHOrQKmAxAAAAAAAAAA" + "AAAAIJoFAACIm3ZUAQCeyt4qN8ntFqnBjj8VTAcAAAAAAAAAAAAAAPDj9wAAgEnDb5MBAJ7K3io3" + "ye0WGuz4U8F0AAoAAAAAAAAAAAAAXG8xAQAgv8G5vgCeyt6qN8ntFqHBjj8VTAcAAAAAAAAAAAAA" + "APB1FwkAAIPev/QBAJ7K3qo3ye0WGuz4W8B0AAAAAAAAAAAAAAAAX29hAADAwMuzPgIAnsreKjcp" + "7RYa7PhTwHQAAgAAAAAAAAAAAACcv6UAAIDcBE+qAJ7K3io3yf0WAez4W8F0AAAAAAAAAAAAAAAA" + "P34XAABMFj2SAgCeyt6qNyntFqnBzv0KpgNQAAAAAAAAAAAAACCrSwAAkGUXUwAAnsreKjfJ/RYF" + "7PhTwXQAAAAAAAAAAAAAAAC/fhYAYGHvr03cAACeyt4qNyntFhrs+FPAdAACAAAAAAAAAAAAANz3" + "OAAAIHrqAhUAnsreqjfJ7RahwY4/FUwHAAAAAAAAAAAAAADw/l0BAEC7xG4ZAACeyt6qN8ntFhrs" + "+FvAdAAAAAAAAAAAAAAAAO9vQQIAQP7YG9MBAJ7K3qo3ye0WocGOPxVMBwAAAAAAAAAAAAAA8Ny1" + "BACAmsF9ngAAnsreKjfJ7RahwY4/FUwHAAAAAAAAAAAAAADw6+0AAMCi1mdeAACeyt7yNyntFgHs" + "3K9gOgABAAAAAAAAAAAAAFpnCgAAMI98WgAAnsre8jfJ7RYN7NyaYDoAAAAAAAAAAAAAAIA/fgMA" + "wLKxf1wEAE9nZ1MAAMCqAAAAAAAAlVm3ewMAAAD+9Ox8FiQlJSYmJSUlJSUmJSYlJSUmJiYmJSSe" + "yt4qNyntFqHBzv0KpgNQAAAAAAAAAAAAAKB9ZgkAAE6GCACeyt6qN8ntFqnBjj8VTAcAAAAAAAAA" + "AAAAAPD1lgEAwODweu8AnsreqjfJ7RYa7PhbwHQAAAAAAAAAAAAAAADPXQoAAKje6sUrAJ7K3qo3" + "ye0WocGOPxVMBwAAAAAAAAAAAAAAcN31AACA3K760gIAnsreqjfJ7RahwY4/FUwHAAAAAAAAAAAA" + "AADw/l0AAID2OV7SAgCeyt7yNyl1i1Bg5/4E0wEoAAAAAAAAAAAAAHDoQQIAQJxOjwQAnsreKjfJ" + "7Ratwc6tAqYDAAAAAAAAAAAAAAD46wcAgMDlal8mAJ7K3io3Ke0WqcHO/QKmAxAAAAAAAAAAAAAA" + "oN/DAACAaKfrAACeyt4qN8ntFqnBzv0KpgMAAAAAAAAAAAAAAPjxHQAAMJn8dhoAnsreqjfJ7RYa" + "7PhbwHQAAAAAAAAAAAAAAADXW0oAAMj7OMMnAJ7K3qo3ye0WocGOPxVMBwAAAAAAAAAAAAAA8HVX" + "CQAAtYu2eQMAnsreqjfJ7RYa7PhbwHQAAAAAAAAAAAAAAABfnwAAAAZN1vcBAJ7K3io3Ke0WocHO" + "/QqmAxAAAAAAAAAAAAAA4PzMAwAAzP8cqQIAnsreKjfJ/RYJ7PhTwHQAAAAAAAAAAAAAAAA/fhcA" + "AEx+XGYSAJ7K3qo3Ke0WpcHOrQqmA1AAAAAAAAAAAAAAIKtLAACQ841WAACeyt4qN8n9Fgns+FPB" + "dAAAAAAAAAAAAAAAAL9+FgAALDa84wEAnsreKjfJ7RaxwY6/FUwHIAAAAAAAAAAAAADA/V0LAACo" + "7vGKCgCeyt6qN8ntFqHBjj8VTAcAAAAAAAAAAAAAAPD+XQMAANplf5IRAJ7K3qo3ye0WGuz4W8B0" + "AAAAAAAAAAAAAAAA799lAgBAu9mnGQAAnsreKjcp7RYa7PhTwXQACgAAAAAAAAAAAAC83OUEAIDa" + "7i8rAACeyt4qN8n9FgHs+FvBdAAAAAAAAAAAAAAAAL9+BgAALNa/7Q4Ansreqjcp7Rapwc79CqYD" + "EAAAAAAAAAAAAAAgmgUAAIj5x6gAT2dnUwAAwAIBAAAAAACVWbd7BAAAAFDbxx4WJSUmJiYlJSUl" + "JiUmJSUlJSUlJiUmJZ7K3io3yf0WBezcr2A6AAAAAAAAAAAAAACAH78DAAA2flSWLwCeyt4qNynt" + "Fhrs+FPAdAAKAAAAAAAAAAAAALTPLAEAwPnmCAUAnsreqjfJ7RapwY4/FUwHAAAAAAAAAAAAAADw" + "9ZYBAMCg6Xo+AgCeyt6qN8ntFhrs+FvAdAAAAAAAAAAAAAAAAF93KQAAoHrhht4BAJ7K3qo3ye0W" + "ocGOPxVMBwAAAAAAAAAAAAAAcL3FAACAnA8zUwEAnsreKjfJ7RYa7PhTwHQAAAAAAAAAAAAAAAA/" + "PhkAAEymvJMWAJ7K3vI3Ke0WAezcr2A6AAUAAAAAAAAAAAAADj1IAACI5x0vAQCeyt4qN8n9Fg3s" + "3CpgOgAAAAAAAAAAAAAAgL9+AAAI7K317QAAnsreKjcp7Rahwc79CqYDEAAAAAAAAAAAAACg3+MA" + "AIAobSQBAJ7K3qo3ye0WqcGOPxVMBwAAAAAAAAAAAAAA8P5JAQBA+2yvaQAAnsreqjfJ7RYa7Phb" + "wHQAAAAAAAAAAAAAAADXW5AAAJDfzWAaAJ7K3qo3ye0WocGOPxVMBwAAAAAAAAAAAAAA8NxVAgBA" + "7TavXgAAnsreqjfJ7RahwY4/FUwHAAAAAAAAAAAAAADw9QkAAGBwWIM3AJ7K3vI3KXWLUGDn/gTT" + "AQgAAAAAAAAAAAAA0DpTAACAWUZ6AQCeyt4qN8ntFq3Bzq0CpgMAAAAAAAAAAAAAAPjjtwAALCfy" + "Y8UAnsre8jcp7RYB7NyvYDoABQAAAAAAAAAAAADaPU0AAHCOeIYEAJ7K3io3ye0WqcHO/QqmAwAA" + "AAAAAAAAAAAA+PX2AABgUftTrwCeyt6qN8ntFhrs+FvAdAAAAAAAAAAAAAAAAM9dDgAAqBrY7xkA" + "nsreqjfJ7RahwY4/FUwHAAAAAAAAAAAAAADwftcDAAByx9yUHgCeyt6qN8ntFhrs+FvAdAAAAAAA" + "AAAAAAAAAO/fJQAAaJfcNSMAnsreKjcp7Rahwc79CqYDUAAAAAAAAAAAAADgpUcJAADxk+crAACe" + "yt4qN8n9Fgns+FPAdAAAAAAAAAAAAAAAAL9+BgAALP7S1BAAT2dnUwAAwFoBAAAAAACVWbd7BQAA" + "ABLEbSgWJSUmJiYlJSUlJSYmJiYlJSUlJSYlJZ7K3lo3Kf0WbcDOrQqmAxAAAAAAAAAAAAAAIKof" + "AAAgmhXTAACeyt4qN8n9Fgns+FPAdAAAAAAAAAAAAAAAAD9+BwAATJ7eWzIAnsreKjfJ7RaxwY6/" + "BUwHoAAAAAAAAAAAAADAzVtMAADIj/+UAgCeyt6qN8ntFqHBjj8VTAcAAAAAAAAAAAAAAPD1iRIA" + "AAZeX/ABAJ7K3qo3ye0WGuz4W8B0AAAAAAAAAAAAAAAAX2cZAAAw6O0LHwEAnsreKjfJ7RYa7PhT" + "wXQAAgAAAAAAAAAAAABcbykAACC3/nlJAJ7K3io3yf0WAez4U8F0AAAAAAAAAAAAAAAAP34vAACY" + "dPsqBQCeyt6qNyntFqXBzq0CpgNQAAAAAAAAAAAAACCrSwAAkDfupAAAnsreKjfJ/RYF7NyvYDoA" + "AAAAAAAAAAAAAIBfPwEAgL2/NnUBAJ7K3io3Ke0WGuz4U8B0AAIAAAAAAAAAAAAA9HscAAAQvTNb" + "BQCeyt6qN8ntFqnBjj8VTAcAAAAAAAAAAAAAAPD+SQEAQLvnvAwAAJ7K3qo3ye0WGuz4W8B0AAAA" + "AAAAAAAAAAAA729BAgBA/p0l6QAAnsreqjfJ7RahwY4/FUwHAAAAAAAAAAAAAADw3LUEAIBai6M9" + "AQCeyt6qN8ntFqHBjj8FTAcAAAAAAAAAAAAAAPDr7QAAwOLZvXkBAJ7K3vI3Ke0WAezcr2A6AAEA" + "AAAAAAAAAAAAWmcKAAAwmy4gAACeyt4qN8ntFq3Bzq0KpgMAAAAAAAAAAAAAAPjjFwAAy8Yf7gEA" + "nsreKjcp7Rahwc79CqYDUAAAAAAAAAAAAACgfWYJAABOmg4BAJ7K3qo3ye0WqcGOPxVMBwAAAAAA" + "AAAAAAAA8PX2AABgcENGrwCeyt6qN8ntFhrs+FvAdAAAAAAAAAAAAAAAAM9dDgAAqK6f0SsAnsre" + "qjfJ7RahwY4/FUwHAAAAAAAAAAAAAABw3fUAAIDck43SAgCeyt6qN8ntFqHBjj8VTAcAAAAAAAAA" + "AAAAAPD+XQAAgPZO7fQAnsreKjcp7Rapwc79CqYDUAAAAAAAAAAAAADg0KMEAIB4XVMAAE9nZ1MA" + "AMCyAQAAAAAAlVm3ewYAAADDE4GEFiUkJSUmJSYlJSYlJiYmJiQlJSUlJiaeyt4qN8ntFqXBzv0K" + "pgMAAAAAAAAAAAAAAPj1PQAA2PtTwgQAnsre8jcp7RYB7NyfYDoAAQAAAAAAAAAAAAD6TQEAAOLr" + "jwUAnsreKjfJ7Rapwc79CqYDAAAAAAAAAAAAAAD48R0AADCp/OETAJ7K3qo3ye0WGuz4W8B0AAAA" + "AAAAAAAAAAAA11tKAADIZzylAwCeyt6qN8ntFqHBjj8VTAcAAAAAAAAAAAAAAPB1VwkAAEPzP+kN" + "AJ7K3qo3ye0WGuz4W8B0AAAAAAAAAAAAAAAAX28hAAAY+LzBBwCeyt4qNyntFqHBzv0KpgMQAAAA" + "AAAAAAAAAOD8zAMAAMzb/qMCAJ7K3io3yf0WCez4U8B0AAAAAAAAAAAAAAAAP34XAABMPpBLAgCe" + "yt7aN6nzFmXCzv0CpgNQAAAAAAAAAAAAACCrlwAAIL2kaAEAnsreKjfJ/RYF7PhTwXQAAAAAAAAA" + "AAAAAAC/fhYAYGHvK6M8AACeyt4qN8ntFhrs+FPAdAACAAAAAAAAAAAAANzftQAAgOqC/6sAnsre" + "qjfJ7RahwY4/FUwHAAAAAAAAAAAAAADw/l0DAADaeh7ICACeyt6qN8ntFhrs+FvAdAAAAAAAAAAA" + "AAAAAO9vngAA0B7vmekAAJ7K3qo3ye0WocGOPxVMBwAAAAAAAAAAAAAA8Ny1BACAWt+vaAEAnsre" + "KjfJ7RahwY4/FUwHAAAAAAAAAAAAAADw67sDAIBF3989AQCeyt7yNyntFgHs3K9gOgABAAAAAAAA" + "AAAAAKIRAAAgvnymAACeyt7yN8ntFgXs3C9gOgAAAAAAAAAAAAAAgD9+AwAANpqv+gEAnsreKjcp" + "7RYa7PhTwHQACgAAAAAAAAAAAAC0zywBAMC5cJgAAJ7K3qo3ye0WqcGOPxVMBwAAAAAAAAAAAAAA" + "8PWWAQDAYK0R7wCeyt6qN8ntFhrs+FvAdAAAAAAAAAAAAAAAAF93KQAAoPpNq1cAnsreqjfJ7Rah" + "wY4/FUwHAAAAAAAAAAAAAABwvcUAAIBcX6VTAQCeyt6qN8ntFqHBjj8FTAcAAAAAAAAAAAAAAPDj" + "uwAAAJM3TJgWAE9nZ1MAAMC2AQAAAAAAlVm3ewcAAAChMbyhATK+ur7krvf7iNcT84QFpAwAAAAA" + "AAAAAAAAAEAnELfPda81yNy2bdpbCkUt8amvXMHuAE9nZ1MABAC4AQAAAAAAlVm3ewgAAAA8WkRh" + "AWZeiL1v7LSgX1wHDrB3NhI3k3sSnaKJAAAAAAAAQOJJS94nzV+3/3r/2Ho5ub5tHN70XSuPfdZZ" + "C/9eZOtqZc5Zfl8wP5ZenOT3hbWPpZeE6jzjkdY3f+GXCblaF41qKouT/N7UyQA="; + +GST_START_TEST (test_playbin2) +{ + GstElement *playbin, *sink; + int loops = 2; + + playbin = gst_element_factory_make ("playbin", NULL); + sink = gst_element_factory_make ("fakesink", NULL); + + if (playbin == NULL || sink == NULL) { + GST_WARNING ("skipping test, no playbin or fakesink element(s)"); + return; + } + + g_object_set (playbin, "uri", data_uri, "audio-sink", sink, NULL); + + do { + GstMessage *msg; + + /* not checking return val on purpose, should always get an error on bus */ + gst_element_set_state (playbin, GST_STATE_PLAYING); + + msg = gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (playbin), + GST_CLOCK_TIME_NONE, GST_MESSAGE_EOS | GST_MESSAGE_ERROR); + + GST_INFO ("message: %" GST_PTR_FORMAT, msg); + if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) { + GError *err = NULL; + + gst_message_parse_error (msg, &err, NULL); + fail_unless (err->code == GST_CORE_ERROR_MISSING_PLUGIN || + err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND, + "Got unexpected error: %s", err->message); + g_error_free (err); + } + + gst_message_unref (msg); + gst_element_set_state (playbin, GST_STATE_NULL); + + --loops; + GST_INFO ("done, %d rounds left", loops); + } while (loops > 0); + + gst_element_set_state (playbin, GST_STATE_NULL); + gst_object_unref (playbin); +} + +GST_END_TEST; + +static Suite * +dataurisrc_suite (void) +{ + Suite *s = suite_create ("dataurisrc"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + + tcase_add_test (tc_chain, test_playbin2); + + return s; +} + +GST_CHECK_MAIN (dataurisrc); diff --git a/tests/check/elements/faac.c b/tests/check/elements/faac.c new file mode 100644 index 00000000..b82c58d1 --- /dev/null +++ b/tests/check/elements/faac.c @@ -0,0 +1,260 @@ +/* GStreamer + * + * unit test for faac + * + * Copyright (C) <2009> Mark Nauwelaerts <mnauw@users.sf.net> + * + * 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. + */ + +#include <unistd.h> + +#include <gst/check/gstcheck.h> +#include <gst/audio/audio.h> + +/* For ease of programming we use globals to keep refs for our floating + * src and sink pads we create; otherwise we always have to do get_pad, + * get_peer, and then remove references in every test function */ +static GstPad *mysrcpad, *mysinkpad; + +#define AUDIO_CAPS_STRING "audio/x-raw, " \ + "format = (string) " GST_AUDIO_NE (S16) ", "\ + "layout = (string) interleaved, " \ + "rate = (int) 48000, " \ + "channels = (int) 2, " \ + "channel-mask = (bitmask) 3" + +#define AAC_RAW_CAPS_STRING "audio/mpeg, " \ + "mpegversion = (int) 4, " \ + "rate = (int) 48000, " \ + "channels = (int) 2, " \ + "stream-format = \"raw\"," \ + "base-profile = \"lc\"" + +#define AAC_ADTS_CAPS_STRING "audio/mpeg, " \ + "mpegversion = (int) 4, " \ + "rate = (int) 48000, " \ + "channels = (int) 2, " \ + "stream-format = \"adts\"," \ + "base-profile = \"lc\"" + +static GstStaticPadTemplate sinktemplate_adts = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (AAC_ADTS_CAPS_STRING)); + +static GstStaticPadTemplate sinktemplate_raw = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (AAC_RAW_CAPS_STRING)); + +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (AUDIO_CAPS_STRING)); + + +static GstElement * +setup_faac (gboolean adts) +{ + GstElement *faac; + + GST_DEBUG ("setup_faac"); + faac = gst_check_setup_element ("faac"); + mysrcpad = gst_check_setup_src_pad (faac, &srctemplate); + + if (adts) + mysinkpad = gst_check_setup_sink_pad (faac, &sinktemplate_adts); + else + mysinkpad = gst_check_setup_sink_pad (faac, &sinktemplate_raw); + + gst_pad_set_active (mysrcpad, TRUE); + gst_pad_set_active (mysinkpad, TRUE); + + return faac; +} + +static void +cleanup_faac (GstElement * faac) +{ + GST_DEBUG ("cleanup_faac"); + gst_element_set_state (faac, GST_STATE_NULL); + + gst_pad_set_active (mysrcpad, FALSE); + gst_pad_set_active (mysinkpad, FALSE); + gst_check_teardown_src_pad (faac); + gst_check_teardown_sink_pad (faac); + gst_check_teardown_element (faac); +} + +static void +do_test (gboolean adts) +{ + GstElement *faac; + GstBuffer *inbuffer, *outbuffer; + GstCaps *caps; + gint i, num_buffers; + const gint nbuffers = 10; + + faac = setup_faac (adts); + fail_unless (gst_element_set_state (faac, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + /* corresponds to audio buffer mentioned in the caps */ + inbuffer = gst_buffer_new_and_alloc (1024 * nbuffers * 2 * 2); + /* makes valgrind's memcheck happier */ + gst_buffer_memset (inbuffer, 0, 0, 1024 * nbuffers * 2 * 2); + caps = gst_caps_from_string (AUDIO_CAPS_STRING); + gst_pad_set_caps (mysrcpad, caps); + gst_caps_unref (caps); + GST_BUFFER_TIMESTAMP (inbuffer) = 0; + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + + /* send eos to have all flushed if needed */ + fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()) == TRUE); + + num_buffers = g_list_length (buffers); + fail_unless_equals_int (num_buffers, nbuffers + 1); + + /* clean up buffers */ + for (i = 0; i < num_buffers; ++i) { + gint header = 0, id; + GstMapInfo map; + gsize size; + guint8 *data; + + outbuffer = GST_BUFFER (buffers->data); + fail_if (outbuffer == NULL); + + gst_buffer_map (outbuffer, &map, GST_MAP_READ); + data = map.data; + size = map.size; + + if (adts) { + gboolean protection; + gint k; + + fail_if (size < 7); + protection = !(data[1] & 0x1); + /* expect only 1 raw data block */ + k = (data[6] & 0x3) + 1; + fail_if (k != 1); + + header = 7; + if (protection) + header += (k - 1) * 2 + 2; + + /* check header */ + k = GST_READ_UINT16_BE (data) & 0xFFF6; + /* sync */ + fail_unless (k == 0xFFF0); + k = data[2]; + /* profile */ + fail_unless ((k >> 6) == 0x1); + /* rate */ + fail_unless (((k >> 2) & 0xF) == 0x3); + /* channels */ + fail_unless ((k & 0x1) == 0); + k = data[3]; + fail_unless ((k >> 6) == 0x2); + } else { + GstCaps *caps; + GstStructure *s; + const GValue *value; + GstBuffer *buf; + gint k; + GstMapInfo cmap; + + caps = gst_pad_get_current_caps (mysinkpad); + fail_if (caps == NULL); + s = gst_caps_get_structure (caps, 0); + fail_if (s == NULL); + value = gst_structure_get_value (s, "codec_data"); + fail_if (value == NULL); + buf = gst_value_get_buffer (value); + fail_if (buf == NULL); + gst_buffer_map (buf, &cmap, GST_MAP_READ); + fail_if (cmap.size < 2); + k = GST_READ_UINT16_BE (cmap.data); + gst_buffer_unmap (buf, &cmap); + /* profile, rate, channels */ + fail_unless ((k & 0xFFF8) == ((0x02 << 11) | (0x3 << 7) | (0x02 << 3))); + gst_caps_unref (caps); + } + + fail_if (size <= header); + id = data[header] & (0x7 << 5); + /* allow all but ID_END or ID_LFE */ + fail_if (id == 7 || id == 3); + gst_buffer_unmap (outbuffer, &map); + + buffers = g_list_remove (buffers, outbuffer); + + ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1); + gst_buffer_unref (outbuffer); + outbuffer = NULL; + } + + cleanup_faac (faac); + g_list_free (buffers); + buffers = NULL; +} + +GST_START_TEST (test_adts) +{ + do_test (TRUE); +} + +GST_END_TEST; + +GST_START_TEST (test_raw) +{ + do_test (FALSE); +} + +GST_END_TEST; + +static Suite * +faac_suite (void) +{ + Suite *s = suite_create ("faac"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_adts); + tcase_add_test (tc_chain, test_raw); + + return s; +} + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = faac_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; +} diff --git a/tests/check/elements/faad.c b/tests/check/elements/faad.c new file mode 100644 index 00000000..a97b8735 --- /dev/null +++ b/tests/check/elements/faad.c @@ -0,0 +1,221 @@ +/* GStreamer + * + * unit test for faad + * + * Copyright (C) <2009> Mark Nauwelaerts <mnauw@users.sf.net> + * + * 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. + */ + +#include <unistd.h> + +#include <gst/check/gstcheck.h> +#include <gst/audio/audio.h> + +/* For ease of programming we use globals to keep refs for our floating + * src and sink pads we create; otherwise we always have to do get_pad, + * get_peer, and then remove references in every test function */ +static GstPad *mysrcpad, *mysinkpad; + +#define AUDIO_CAPS_STRING "audio/x-raw, " \ + "format = (string) " GST_AUDIO_NE (S16) ", " \ + "rate = (int) 48000, " \ + "channels = (int) 2, " \ + "channel-mask = (bitmask) 3" + +#define AAC_CAPS_STRING "audio/mpeg, " \ + "mpegversion = (int) 4, " \ + "rate = (int) 48000, " \ + "channels = (int) 2, " \ + "framed = (boolean) true " + +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (AUDIO_CAPS_STRING)); + +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (AAC_CAPS_STRING)); + + +static GstElement * +setup_faad (void) +{ + GstElement *faad; + + GST_DEBUG ("setup_faad"); + faad = gst_check_setup_element ("faad"); + mysrcpad = gst_check_setup_src_pad (faad, &srctemplate); + mysinkpad = gst_check_setup_sink_pad (faad, &sinktemplate); + gst_pad_set_active (mysrcpad, TRUE); + gst_pad_set_active (mysinkpad, TRUE); + + return faad; +} + +static void +cleanup_faad (GstElement * faad) +{ + GST_DEBUG ("cleanup_faad"); + gst_element_set_state (faad, GST_STATE_NULL); + + gst_pad_set_active (mysrcpad, FALSE); + gst_pad_set_active (mysinkpad, FALSE); + gst_check_teardown_src_pad (faad); + gst_check_teardown_sink_pad (faad); + gst_check_teardown_element (faad); +} + +static void +do_test (GstBuffer * inbuffer, GstCaps * caps) +{ + GstElement *faad; + GstBuffer *outbuffer; + gint i, num_buffers; + const gint nbuffers = 2; + + faad = setup_faad (); + fail_unless (gst_element_set_state (faad, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + GST_BUFFER_TIMESTAMP (inbuffer) = 0; + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + + gst_pad_set_caps (mysrcpad, caps); + /* need to push twice to get faad output */ + gst_buffer_ref (inbuffer); + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + + /* send eos to have all flushed if needed */ + fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()) == TRUE); + + num_buffers = g_list_length (buffers); + fail_unless (num_buffers >= nbuffers - 1); + + /* clean up buffers */ + for (i = 0; i < num_buffers; ++i) { + gint size; + + outbuffer = GST_BUFFER (buffers->data); + fail_if (outbuffer == NULL); + + size = gst_buffer_get_size (outbuffer); + + /* 2 16-bit channels */ + fail_unless (size == 1024 * 2 * 2); + + buffers = g_list_remove (buffers, outbuffer); + + ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1); + gst_buffer_unref (outbuffer); + outbuffer = NULL; + } + + cleanup_faad (faad); + g_list_free (buffers); + buffers = NULL; +} + +static guint8 raw_data_block[] = { + 0x21, 0x1b, 0x80, 0x00, 0x7d, 0xe0, 0x00, 0x3e, 0xf1, 0xe7 +}; + +static guint8 adts_header[] = { + 0xff, 0xf8, 0x4c, 0x80, 0x02, 0x7f, 0xfc, 0x04, 0x40 +}; + +static guint8 codec_data[] = { + 0x11, 0x90 +}; + +GST_START_TEST (test_adts) +{ + gint size; + GstBuffer *buf, *header_buf; + GstCaps *caps; + + size = sizeof (adts_header); + header_buf = gst_buffer_new_and_alloc (size); + gst_buffer_fill (header_buf, 0, adts_header, size); + + size = sizeof (raw_data_block); + buf = gst_buffer_new_and_alloc (size); + gst_buffer_fill (buf, 0, raw_data_block, size); + + buf = gst_buffer_append (header_buf, buf); + caps = gst_caps_from_string (AAC_CAPS_STRING); + do_test (buf, caps); + gst_caps_unref (caps); +} + +GST_END_TEST; + +GST_START_TEST (test_raw) +{ + gint size; + GstBuffer *buf, *codec_buf; + GstCaps *caps; + + size = sizeof (codec_data); + codec_buf = gst_buffer_new_and_alloc (size); + gst_buffer_fill (codec_buf, 0, codec_data, size); + + size = sizeof (raw_data_block); + buf = gst_buffer_new_and_alloc (size); + gst_buffer_fill (buf, 0, raw_data_block, size); + caps = gst_caps_from_string (AAC_CAPS_STRING); + gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, codec_buf, NULL); + gst_buffer_unref (codec_buf); + + do_test (buf, caps); + gst_caps_unref (caps); +} + +GST_END_TEST; + +static Suite * +faad_suite (void) +{ + Suite *s = suite_create ("faad"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_adts); + tcase_add_test (tc_chain, test_raw); + + return s; +} + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = faad_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; +} diff --git a/tests/check/elements/h263parse.c b/tests/check/elements/h263parse.c new file mode 100644 index 00000000..4c23c619 --- /dev/null +++ b/tests/check/elements/h263parse.c @@ -0,0 +1,175 @@ +/* + * GStreamer + * + * unit test for h263parse + * + * Copyright (C) 2011 Nokia Corporation. All rights reserved. + * + * Contact: Stefan Kost <stefan.kost@nokia.com> + * + * 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. + */ + +#include <gst/check/gstcheck.h> +#include "parser.h" + +#define SRC_CAPS_TMPL "video/x-h263, framed=(boolean)false" +#define SINK_CAPS_TMPL "video/x-h263, framed=(boolean)true" + +GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (SINK_CAPS_TMPL) + ); + +GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (SRC_CAPS_TMPL) + ); + +/* some data */ + +#if 0 +static guint8 h263_iframe[] = { + /* keyframes all around */ + 0x00, 0x00, 0x80, 0x02, 0x1c, 0x88, 0x01, 0x00, + 0x11, 0xe0, 0x44, 0xc4, 0x04, 0x04, 0x04, 0x3f, + 0xff, 0xe6, 0x20, 0x20, 0x20, 0x21, 0xff, 0xff, + 0x31, 0x01, 0x01, 0x01, 0x0f, 0xff, 0xf9, 0x88, + 0x08, 0x08, 0x08, 0x7f, 0xff, 0x80 +}; +#endif + +static guint8 h263_iframe[] = { + /* keyframes all around */ + /* actually, this is a truncated keyframe, + * but don't tell anyone or try this at home */ + 0x00, 0x00, 0x80, 0x02, 0x0c, 0x04, 0x26, 0x20, + 0x20, 0x20, 0x21, 0xff, 0xff, 0x31, 0x01, 0x01, + 0x01, 0x0f, 0xff, 0xf9, 0x88, 0x08, 0x08, 0x08, + 0x7f, 0xff, 0xcc, 0x40, 0x40, 0x40, 0x43, 0xff, + 0xfe, 0x62, 0x02, 0x02, 0x02, 0x1f, 0xff, 0xf3, + 0x10, 0x10, 0x10, 0x10, 0xff, 0xff, 0x98, 0x80, + 0x80, 0x80, 0x87, 0xff, 0xfc, 0xc4, 0x04, 0x04, + 0x04, 0x3f, 0xff, 0xe6, 0x20, 0x20, 0x20, 0x21, + 0xff, 0xff, 0x31, 0x01, 0x01, 0x01, 0x0f, 0xff, + 0xf9, 0x88, 0x08, 0x08, 0x08, 0x7f, 0xff, 0xcc, + 0x40, 0x40, 0x40, 0x43, 0xff, 0xfe, 0x62, 0x02, + 0x02, 0x02, 0x1f, 0xff, 0xf3, 0x10, 0x10, 0x10, + 0x10, 0xff, 0xff, 0x98, 0x80, 0x80, 0x80, 0x87, + 0xff, 0xfc, 0xc4, 0x04, 0x04, 0x04, 0x3f, 0xff, + 0xe6, 0x20, 0x20, 0x20, 0x21, 0xff, 0xff, 0x31, + 0x01, 0x01, 0x01, 0x0f, 0xff, 0xf9, 0x88, 0x08 +}; + +GST_START_TEST (test_parse_normal) +{ + gst_parser_test_normal (h263_iframe, sizeof (h263_iframe)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_drain_single) +{ + gst_parser_test_drain_single (h263_iframe, sizeof (h263_iframe)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_split) +{ + gst_parser_test_split (h263_iframe, sizeof (h263_iframe)); +} + +GST_END_TEST; + + +#define structure_get_int(s,f) \ + (g_value_get_int(gst_structure_get_value(s,f))) +#define fail_unless_structure_field_int_equals(s,field,num) \ + fail_unless_equals_int (structure_get_int(s,field), num) + +GST_START_TEST (test_parse_detect_stream) +{ + GstCaps *caps; + GstStructure *s; + + caps = gst_parser_test_get_output_caps (h263_iframe, sizeof (h263_iframe), + NULL); + fail_unless (caps != NULL); + + /* Check that the negotiated caps are as expected */ + /* When codec_data is present, parser assumes that data is version 4 */ + GST_LOG ("mpegvideo output caps: %" GST_PTR_FORMAT, caps); + s = gst_caps_get_structure (caps, 0); + fail_unless (gst_structure_has_name (s, "video/x-h263")); + fail_unless_structure_field_int_equals (s, "width", 352); + fail_unless_structure_field_int_equals (s, "height", 288); + + gst_caps_unref (caps); +} + +GST_END_TEST; + + +static Suite * +h263parse_suite (void) +{ + Suite *s = suite_create ("h263parse"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_parse_normal); + tcase_add_test (tc_chain, test_parse_drain_single); + tcase_add_test (tc_chain, test_parse_split); + tcase_add_test (tc_chain, test_parse_detect_stream); + + return s; +} + + +/* + * TODO: + * - Both push- and pull-modes need to be tested + * * Pull-mode & EOS + */ + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = h263parse_suite (); + SRunner *sr = srunner_create (s); + + gst_check_init (&argc, &argv); + + /* init test context */ + ctx_factory = "h263parse"; + ctx_sink_template = &sinktemplate; + ctx_src_template = &srctemplate; + /* no timing info to parse */ + ctx_no_metadata = TRUE; + + srunner_run_all (sr, CK_NORMAL); + nf = srunner_ntests_failed (sr); + srunner_free (sr); + + return nf; +} diff --git a/tests/check/elements/h264parse.c b/tests/check/elements/h264parse.c new file mode 100644 index 00000000..8a767248 --- /dev/null +++ b/tests/check/elements/h264parse.c @@ -0,0 +1,402 @@ +/* + * GStreamer + * + * unit test for h264parse + * + * Copyright (C) 2011 Nokia Corporation. All rights reserved. + * + * Contact: Stefan Kost <stefan.kost@nokia.com> + * + * 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. + */ + +#include <gst/check/gstcheck.h> +#include "parser.h" + +#define SRC_CAPS_TMPL "video/x-h264, parsed=(boolean)false" +#define SINK_CAPS_TMPL "video/x-h264, parsed=(boolean)true" + +GstStaticPadTemplate sinktemplate_bs_nal = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (SINK_CAPS_TMPL + ", stream-format = (string) byte-stream, alignment = (string) nal") + ); + +GstStaticPadTemplate sinktemplate_avc_au = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (SINK_CAPS_TMPL + ", stream-format = (string) avc, alignment = (string) au") + ); + +GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (SRC_CAPS_TMPL) + ); + +/* some data */ + +/* SPS */ +static guint8 h264_sps[] = { + 0x00, 0x00, 0x00, 0x01, 0x67, 0x4d, 0x40, 0x15, + 0xec, 0xa4, 0xbf, 0x2e, 0x02, 0x20, 0x00, 0x00, + 0x03, 0x00, 0x2e, 0xe6, 0xb2, 0x80, 0x01, 0xe2, + 0xc5, 0xb2, 0xc0 +}; + +/* PPS */ +static guint8 h264_pps[] = { + 0x00, 0x00, 0x00, 0x01, 0x68, 0xeb, 0xec, 0xb2 +}; + +/* combines to this codec-data */ +static guint8 h264_codec_data[] = { + 0x01, 0x4d, 0x40, 0x15, 0xff, 0xe1, 0x00, 0x17, + 0x67, 0x4d, 0x40, 0x15, 0xec, 0xa4, 0xbf, 0x2e, + 0x02, 0x20, 0x00, 0x00, 0x03, 0x00, 0x2e, 0xe6, + 0xb2, 0x80, 0x01, 0xe2, 0xc5, 0xb2, 0xc0, 0x01, + 0x00, 0x04, 0x68, 0xeb, 0xec, 0xb2 +}; + +/* keyframes all around */ +static guint8 h264_idrframe[] = { + 0x00, 0x00, 0x00, 0x01, 0x65, 0x88, 0x84, 0x00, + 0x10, 0xff, 0xfe, 0xf6, 0xf0, 0xfe, 0x05, 0x36, + 0x56, 0x04, 0x50, 0x96, 0x7b, 0x3f, 0x53, 0xe1 +}; + +/* truncated nal */ +static guint8 garbage_frame[] = { + 0x00, 0x00, 0x00, 0x01, 0x05 +}; + +/* context to tweak tests */ +static const gchar *ctx_suite; +static gboolean ctx_codec_data; + +static gboolean +verify_buffer (buffer_verify_data_s * vdata, GstBuffer * buffer) +{ + if (vdata->discard) { + /* check separate header NALs */ + gint i = vdata->buffer_counter; + + fail_unless (i <= 1); + fail_unless (gst_buffer_get_size (buffer) == ctx_headers[i].size); + fail_unless (gst_buffer_memcmp (buffer, 0, ctx_headers[i].data, + gst_buffer_get_size (buffer)) == 0); + } else { + GstMapInfo map; + + gst_buffer_map (buffer, &map, GST_MAP_READ); + fail_unless (map.size > 4); + /* only need to check avc output case */ + if (GST_READ_UINT32_BE (map.data) == 0x01) { + gst_buffer_unmap (buffer, &map); + return FALSE; + } + /* header is merged in initial frame */ + if (vdata->buffer_counter == 0) { + guint8 *data = map.data; + + fail_unless (map.size == vdata->data_to_verify_size + + ctx_headers[0].size + ctx_headers[1].size); + fail_unless (GST_READ_UINT32_BE (data) == ctx_headers[0].size - 4); + fail_unless (memcmp (data + 4, ctx_headers[0].data + 4, + ctx_headers[0].size - 4) == 0); + data += ctx_headers[0].size; + fail_unless (GST_READ_UINT32_BE (data) == ctx_headers[1].size - 4); + fail_unless (memcmp (data + 4, ctx_headers[1].data + 4, + ctx_headers[1].size - 4) == 0); + data += ctx_headers[1].size; + fail_unless (GST_READ_UINT32_BE (data) == vdata->data_to_verify_size - 4); + fail_unless (memcmp (data + 4, vdata->data_to_verify + 4, + vdata->data_to_verify_size - 4) == 0); + } else { + fail_unless (GST_READ_UINT32_BE (map.data) == map.size - 4); + fail_unless (map.size == vdata->data_to_verify_size); + fail_unless (memcmp (map.data + 4, vdata->data_to_verify + 4, + map.size - 4) == 0); + } + gst_buffer_unmap (buffer, &map); + return TRUE; + } + + return FALSE; +} + +GST_START_TEST (test_parse_normal) +{ + gst_parser_test_normal (h264_idrframe, sizeof (h264_idrframe)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_drain_single) +{ + gst_parser_test_drain_single (h264_idrframe, sizeof (h264_idrframe)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_drain_garbage) +{ + gst_parser_test_drain_garbage (h264_idrframe, sizeof (h264_idrframe), + garbage_frame, sizeof (garbage_frame)); +} + +GST_END_TEST +GST_START_TEST (test_parse_split) +{ + gst_parser_test_split (h264_idrframe, sizeof (h264_idrframe)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_skip_garbage) +{ + gst_parser_test_skip_garbage (h264_idrframe, sizeof (h264_idrframe), + garbage_frame, sizeof (garbage_frame)); +} + +GST_END_TEST; + +#define structure_get_int(s,f) \ + (g_value_get_int(gst_structure_get_value(s,f))) +#define fail_unless_structure_field_int_equals(s,field,num) \ + fail_unless_equals_int (structure_get_int(s,field), num) + + +GST_START_TEST (test_parse_detect_stream) +{ + GstCaps *caps; + GstStructure *s; + GstBuffer *buf; + const GValue *val; + + /* parser does not really care that mpeg1 and mpeg2 frame data + * should be a bit different */ + caps = gst_parser_test_get_output_caps (h264_idrframe, sizeof (h264_idrframe), + NULL); + fail_unless (caps != NULL); + + /* Check that the negotiated caps are as expected */ + /* When codec_data is present, parser assumes that data is version 4 */ + GST_LOG ("h264 output caps: %" GST_PTR_FORMAT, caps); + s = gst_caps_get_structure (caps, 0); + fail_unless (gst_structure_has_name (s, "video/x-h264")); + fail_unless_structure_field_int_equals (s, "width", 32); + fail_unless_structure_field_int_equals (s, "height", 24); + + if (ctx_codec_data) { + fail_unless (gst_structure_has_field (s, "codec_data")); + + /* check codec-data in more detail */ + val = gst_structure_get_value (s, "codec_data"); + fail_unless (val != NULL); + buf = gst_value_get_buffer (val); + fail_unless (buf != NULL); + fail_unless (gst_buffer_get_size (buf) == sizeof (h264_codec_data)); + fail_unless (gst_buffer_memcmp (buf, 0, h264_codec_data, + gst_buffer_get_size (buf)) == 0); + } + + gst_caps_unref (caps); +} + +GST_END_TEST; + + +static Suite * +h264parse_suite (void) +{ + Suite *s = suite_create (ctx_suite); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_parse_normal); + tcase_add_test (tc_chain, test_parse_drain_single); + tcase_add_test (tc_chain, test_parse_drain_garbage); + tcase_add_test (tc_chain, test_parse_split); + tcase_add_test (tc_chain, test_parse_skip_garbage); + tcase_add_test (tc_chain, test_parse_detect_stream); + + return s; +} + +static gboolean +verify_buffer_packetized (buffer_verify_data_s * vdata, GstBuffer * buffer) +{ + GstMapInfo map; + + gst_buffer_map (buffer, &map, GST_MAP_READ); + + fail_unless (map.size > 4); + fail_unless (GST_READ_UINT32_BE (map.data) == 0x01); + if (vdata->discard) { + /* check separate header NALs */ + guint8 *data; + gint size; + + if (vdata->buffer_counter == 0) { + data = h264_sps; + size = sizeof (h264_sps); + } else { + data = h264_pps; + size = sizeof (h264_pps); + } + + fail_unless (map.size == size); + fail_unless (memcmp (map.data + 4, data + 4, size - 4) == 0); + } else { + fail_unless (map.size == vdata->data_to_verify_size); + fail_unless (memcmp (map.data + 4, + vdata->data_to_verify + 4, map.size - 4) == 0); + } + gst_buffer_unmap (buffer, &map); + + return TRUE; +} + +GST_START_TEST (test_parse_packetized) +{ + guint8 *frame; + GstCaps *caps; + GstBuffer *cdata; + GstStructure *s; + gchar *desc; + + /* make AVC frame */ + frame = g_malloc (sizeof (h264_idrframe)); + GST_WRITE_UINT32_BE (frame, sizeof (h264_idrframe) - 4); + memcpy (frame + 4, h264_idrframe + 4, sizeof (h264_idrframe) - 4); + + /* some caps messing */ + caps = gst_caps_from_string (SRC_CAPS_TMPL); + cdata = + gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, h264_codec_data, + sizeof (h264_codec_data), 0, sizeof (h264_codec_data), NULL, NULL); + gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, cdata, NULL); + gst_buffer_unref (cdata); + desc = gst_caps_to_string (caps); + gst_caps_unref (caps); + + caps = gst_parser_test_get_output_caps (frame, sizeof (h264_idrframe), desc); + g_free (desc); + g_free (frame); + + /* minor caps checks */ + GST_LOG ("h264 output caps: %" GST_PTR_FORMAT, caps); + s = gst_caps_get_structure (caps, 0); + fail_unless (gst_structure_has_name (s, "video/x-h264")); + fail_unless_structure_field_int_equals (s, "width", 32); + fail_unless_structure_field_int_equals (s, "height", 24); + + gst_caps_unref (caps); +} + +GST_END_TEST; + +static Suite * +h264parse_packetized_suite (void) +{ + Suite *s = suite_create (ctx_suite); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_parse_packetized); + + return s; +} + + +/* + * TODO: + * - Both push- and pull-modes need to be tested + * * Pull-mode & EOS + */ + +int +main (int argc, char **argv) +{ + int nf = 0; + + Suite *s; + SRunner *sr; + + gst_check_init (&argc, &argv); + + /* globabl init test context */ + ctx_factory = "h264parse"; + ctx_sink_template = &sinktemplate_bs_nal; + ctx_src_template = &srctemplate; + ctx_headers[0].data = h264_sps; + ctx_headers[0].size = sizeof (h264_sps); + ctx_headers[1].data = h264_pps; + ctx_headers[1].size = sizeof (h264_pps); + ctx_verify_buffer = verify_buffer; + /* discard initial sps/pps buffers */ + ctx_discard = 2; + /* no timing info to parse */ + ctx_no_metadata = TRUE; + ctx_codec_data = FALSE; + + ctx_suite = "h264parse_to_bs_nal"; + s = h264parse_suite (); + sr = srunner_create (s); + srunner_run_all (sr, CK_NORMAL); + nf += srunner_ntests_failed (sr); + srunner_free (sr); + + /* setup and tweak to handle avc au output */ + ctx_suite = "h264parse_to_avc_au"; + ctx_sink_template = &sinktemplate_avc_au; + ctx_discard = 0; + ctx_codec_data = TRUE; + + s = h264parse_suite (); + sr = srunner_create (s); + srunner_run_all (sr, CK_NORMAL); + nf += srunner_ntests_failed (sr); + srunner_free (sr); + + /* setup and tweak to handle avc packetized input */ + ctx_suite = "h264parse_packetized"; + /* turn into separate byte stream NALs */ + ctx_sink_template = &sinktemplate_bs_nal; + /* and ignore inserted codec-data NALs */ + ctx_discard = 2; + /* no more config headers */ + ctx_headers[0].data = NULL; + ctx_headers[1].data = NULL; + ctx_headers[0].size = 0; + ctx_headers[1].size = 0; + /* and need adapter buffer check */ + ctx_verify_buffer = verify_buffer_packetized; + + s = h264parse_packetized_suite (); + sr = srunner_create (s); + srunner_run_all (sr, CK_NORMAL); + nf += srunner_ntests_failed (sr); + srunner_free (sr); + + return nf; +} diff --git a/tests/check/elements/id3mux.c b/tests/check/elements/id3mux.c new file mode 100644 index 00000000..b494c2ea --- /dev/null +++ b/tests/check/elements/id3mux.c @@ -0,0 +1,557 @@ +/* GStreamer + * + * unit test for the id3tag element + * + * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net> + * + * 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. + */ + +#include <gst/check/gstcheck.h> + +#include <gst/gst.h> +#include <string.h> + +#define TEST_ARTIST "Ar T\303\255st" +#define TEST_TITLE "M\303\274llermilch!" +#define TEST_ALBUM "Boom" +#define TEST_DATE g_date_new_dmy(1,1,2006) +#define TEST_TRACK_NUMBER 7 +#define TEST_TRACK_COUNT 19 +#define TEST_VOLUME_NUMBER 2 +#define TEST_VOLUME_COUNT 3 +#define TEST_TRACK_GAIN 1.45 +#define TEST_ALBUM_GAIN 0.78 +#define TEST_TRACK_PEAK 0.83 +#define TEST_ALBUM_PEAK 0.18 +#define TEST_BPM 113.0 + +/* for dummy mp3 frame sized MP3_FRAME_SIZE bytes, + * start: ff fb b0 44 00 00 08 00 00 4b 00 00 00 00 00 00 */ +static const guint8 mp3_dummyhdr[] = { 0xff, 0xfb, 0xb0, 0x44, 0x00, 0x00, + 0x08, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00 +}; + +#define MP3_FRAME_SIZE 626 + +/* the peak and gain values are stored pretty roughly, so check that they're + * within 2% of the expected value. + */ +#define fail_unless_sorta_equals_float(a, b) \ +G_STMT_START { \ + double first = a; \ + double second = b; \ + fail_unless(fabs (first - second) < (0.02 * fabs (first)), \ + "'" #a "' (%g) is not equal to '" #b "' (%g)", first, second); \ +} G_STMT_END; + + +static GstTagList * +test_taglib_id3mux_create_tags (guint32 mask) +{ + GstTagList *tags; + + tags = gst_tag_list_new_empty (); + + if (mask & (1 << 0)) { + gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, + GST_TAG_ARTIST, TEST_ARTIST, NULL); + } + if (mask & (1 << 1)) { + gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, + GST_TAG_TITLE, TEST_TITLE, NULL); + } + if (mask & (1 << 2)) { + gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, + GST_TAG_ALBUM, TEST_ALBUM, NULL); + } + if (mask & (1 << 3)) { + GDate *date; + + date = TEST_DATE; + gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, GST_TAG_DATE, date, NULL); + g_date_free (date); + } + if (mask & (1 << 4)) { + gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, + GST_TAG_TRACK_NUMBER, TEST_TRACK_NUMBER, NULL); + } + if (mask & (1 << 5)) { + gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, + GST_TAG_TRACK_COUNT, TEST_TRACK_COUNT, NULL); + } + if (mask & (1 << 6)) { + gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, + GST_TAG_ALBUM_VOLUME_NUMBER, TEST_VOLUME_NUMBER, NULL); + } + if (mask & (1 << 7)) { + gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, + GST_TAG_ALBUM_VOLUME_COUNT, TEST_VOLUME_COUNT, NULL); + } + if (mask & (1 << 8)) { + gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, + GST_TAG_TRACK_GAIN, TEST_TRACK_GAIN, NULL); + } + if (mask & (1 << 9)) { + gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, + GST_TAG_ALBUM_GAIN, TEST_ALBUM_GAIN, NULL); + } + if (mask & (1 << 10)) { + gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, + GST_TAG_TRACK_PEAK, TEST_TRACK_PEAK, NULL); + } + if (mask & (1 << 11)) { + gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, + GST_TAG_ALBUM_PEAK, TEST_ALBUM_PEAK, NULL); + } + if (mask & (1 << 12)) { + gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, + GST_TAG_BEATS_PER_MINUTE, TEST_BPM, NULL); + } + if (mask & (1 << 13)) { + } + return tags; +} + +static gboolean +utf_string_in_buf (GstBuffer * buf, const gchar * s, int v2version) +{ + gint i, len; + gchar *free_str = NULL; + GstMapInfo map; + + if (v2version == 3) { + free_str = g_convert (s, -1, "UTF-16LE", "UTF-8", NULL, NULL, NULL); + s = free_str; + } + + len = strlen (s); + gst_buffer_map (buf, &map, GST_MAP_READ); + for (i = 0; i < (map.size - len); ++i) { + if (memcmp (map.data + i, s, len) == 0) { + gst_buffer_unmap (buf, &map); + g_free (free_str); + return TRUE; + } + } + gst_buffer_unmap (buf, &map); + + g_free (free_str); + return FALSE; +} + +static void +test_taglib_id3mux_check_tag_buffer (GstBuffer * buf, guint32 mask, + int v2version) +{ + /* make sure our UTF-8 string hasn't been put into the tag as ISO-8859-1 */ + if (mask & (1 << 0)) { + fail_unless (utf_string_in_buf (buf, TEST_ARTIST, v2version)); + } + /* make sure our UTF-8 string hasn't been put into the tag as ISO-8859-1 */ + if (mask & (1 << 1)) { + fail_unless (utf_string_in_buf (buf, TEST_TITLE, v2version)); + } + /* make sure our UTF-8 string hasn't been put into the tag as ISO-8859-1 */ + if (mask & (1 << 2)) { + fail_unless (utf_string_in_buf (buf, TEST_ALBUM, v2version)); + } +} + +static void +test_taglib_id3mux_check_tags (GstTagList * tags, guint32 mask, int v2version) +{ + if (mask & (1 << 0)) { + gchar *s = NULL; + + fail_unless (gst_tag_list_get_string (tags, GST_TAG_ARTIST, &s)); + fail_unless (g_str_equal (s, TEST_ARTIST)); + g_free (s); + } + if (mask & (1 << 1)) { + gchar *s = NULL; + + fail_unless (gst_tag_list_get_string (tags, GST_TAG_TITLE, &s)); + fail_unless (g_str_equal (s, TEST_TITLE)); + g_free (s); + } + if (mask & (1 << 2)) { + gchar *s = NULL; + + fail_unless (gst_tag_list_get_string (tags, GST_TAG_ALBUM, &s)); + fail_unless (g_str_equal (s, TEST_ALBUM)); + g_free (s); + } + if (mask & (1 << 3)) { + GDate *shouldbe, *date = NULL; + + shouldbe = TEST_DATE; + fail_unless (gst_tag_list_get_date (tags, GST_TAG_DATE, &date)); + fail_unless (g_date_compare (shouldbe, date) == 0); + g_date_free (shouldbe); + g_date_free (date); + } + if (mask & (1 << 4)) { + guint num; + + fail_unless (gst_tag_list_get_uint (tags, GST_TAG_TRACK_NUMBER, &num)); + fail_unless (num == TEST_TRACK_NUMBER); + } + if (mask & (1 << 5)) { + guint count; + + fail_unless (gst_tag_list_get_uint (tags, GST_TAG_TRACK_COUNT, &count)); + fail_unless (count == TEST_TRACK_COUNT); + } + if (mask & (1 << 6)) { + guint num; + + fail_unless (gst_tag_list_get_uint (tags, GST_TAG_ALBUM_VOLUME_NUMBER, + &num)); + fail_unless (num == TEST_VOLUME_NUMBER); + } + if (mask & (1 << 7)) { + guint count; + + fail_unless (gst_tag_list_get_uint (tags, GST_TAG_ALBUM_VOLUME_COUNT, + &count)); + fail_unless (count == TEST_VOLUME_COUNT); + } + if (mask & (1 << 8)) { + gdouble gain; + + if (v2version == 4) { + fail_unless (gst_tag_list_get_double (tags, GST_TAG_TRACK_GAIN, &gain)); + fail_unless_sorta_equals_float (gain, TEST_TRACK_GAIN); + } + } + if (mask & (1 << 9)) { + gdouble gain; + + if (v2version == 4) { + fail_unless (gst_tag_list_get_double (tags, GST_TAG_ALBUM_GAIN, &gain)); + fail_unless_sorta_equals_float (gain, TEST_ALBUM_GAIN); + } + } + if (mask & (1 << 10)) { + gdouble peak; + + if (v2version == 4) { + fail_unless (gst_tag_list_get_double (tags, GST_TAG_TRACK_PEAK, &peak)); + fail_unless_sorta_equals_float (peak, TEST_TRACK_PEAK); + } + } + if (mask & (1 << 11)) { + gdouble peak; + + if (v2version == 4) { + fail_unless (gst_tag_list_get_double (tags, GST_TAG_ALBUM_PEAK, &peak)); + fail_unless_sorta_equals_float (peak, TEST_ALBUM_PEAK); + } + } + if (mask & (1 << 12)) { + gdouble bpm; + + fail_unless (gst_tag_list_get_double (tags, GST_TAG_BEATS_PER_MINUTE, + &bpm)); + fail_unless_sorta_equals_float (bpm, TEST_BPM); + } + if (mask & (1 << 13)) { + } +} + +static void +fill_mp3_buffer (GstElement * fakesrc, GstBuffer * buf, GstPad * pad, + guint64 * p_offset) +{ + fail_unless (gst_buffer_get_size (buf) == MP3_FRAME_SIZE); + + GST_LOG ("filling buffer with fake mp3 data, offset = %" G_GUINT64_FORMAT, + *p_offset); + + gst_buffer_fill (buf, 0, mp3_dummyhdr, sizeof (mp3_dummyhdr)); + +#if 0 + /* can't use gst_buffer_set_caps() here because the metadata isn't writable + * because of the extra refcounts taken by the signal emission mechanism; + * we know it's fine to use GST_BUFFER_CAPS() here though */ + GST_BUFFER_CAPS (buf) = gst_caps_new_simple ("audio/mpeg", "mpegversion", + G_TYPE_INT, 1, "layer", G_TYPE_INT, 3, NULL); +#endif + + GST_BUFFER_OFFSET (buf) = *p_offset; + *p_offset += gst_buffer_get_size (buf); +} + +static void +got_buffer (GstElement * fakesink, GstBuffer * buf, GstPad * pad, + GstBuffer ** p_buf) +{ + GstMapInfo map; + gint64 off; + guint size; + + off = GST_BUFFER_OFFSET (buf); + gst_buffer_map (buf, &map, GST_MAP_READ); + size = map.size; + + GST_LOG ("got buffer, size=%u, offset=%" G_GINT64_FORMAT, size, off); + + fail_unless (GST_BUFFER_OFFSET_IS_VALID (buf)); + + if (*p_buf == NULL || (off + size) > gst_buffer_get_size (*p_buf)) { + GstBuffer *newbuf; + + /* not very elegant, but who cares */ + newbuf = gst_buffer_new_and_alloc (off + size); + if (*p_buf) { + GstMapInfo pmap; + + gst_buffer_map (*p_buf, &pmap, GST_MAP_READ); + gst_buffer_fill (newbuf, 0, pmap.data, pmap.size); + gst_buffer_unmap (*p_buf, &pmap); + } + gst_buffer_fill (newbuf, off, map.data, size); + + if (*p_buf) + gst_buffer_unref (*p_buf); + *p_buf = newbuf; + } else { + gst_buffer_fill (*p_buf, off, map.data, size); + } + gst_buffer_unmap (buf, &map); +} + +static void +test_taglib_id3mux_check_output_buffer (GstBuffer * buf) +{ + GstMapInfo map; + guint off; + + gst_buffer_map (buf, &map, GST_MAP_READ); + + g_assert (map.size % MP3_FRAME_SIZE == 0); + + for (off = 0; off < map.size; off += MP3_FRAME_SIZE) { + fail_unless (memcmp (map.data + off, mp3_dummyhdr, + sizeof (mp3_dummyhdr)) == 0); + } + gst_buffer_unmap (buf, &map); +} + +static void +identity_cb (GstElement * identity, GstBuffer * buf, GstBuffer ** p_tagbuf) +{ + if (*p_tagbuf == NULL) { + *p_tagbuf = gst_buffer_ref (buf); + } +} + +static void +test_taglib_id3mux_with_tags (GstTagList * tags, guint32 mask, int v2version) +{ + GstMessage *msg; + GstTagList *tags_read = NULL; + GstElement *pipeline, *id3mux, *id3demux, *fakesrc, *identity, *fakesink; + GstBus *bus; + guint64 offset; + GstBuffer *outbuf = NULL; + GstBuffer *tagbuf = NULL; + GstStateChangeReturn state_result; + + pipeline = gst_pipeline_new ("pipeline"); + g_assert (pipeline != NULL); + + fakesrc = gst_element_factory_make ("fakesrc", "fakesrc"); + g_assert (fakesrc != NULL); + + id3mux = gst_element_factory_make ("id3mux", "id3mux"); + g_assert (id3mux != NULL); + g_object_set (id3mux, "v2-version", v2version, NULL); + + identity = gst_element_factory_make ("identity", "identity"); + g_assert (identity != NULL); + + id3demux = gst_element_factory_make ("id3demux", "id3demux"); + g_assert (id3demux != NULL); + + fakesink = gst_element_factory_make ("fakesink", "fakesink"); + g_assert (fakesink != NULL); + + /* set up sink */ + outbuf = NULL; + g_object_set (fakesink, "signal-handoffs", TRUE, NULL); + g_signal_connect (fakesink, "handoff", G_CALLBACK (got_buffer), &outbuf); + + gst_bin_add (GST_BIN (pipeline), fakesrc); + gst_bin_add (GST_BIN (pipeline), id3mux); + gst_bin_add (GST_BIN (pipeline), identity); + gst_bin_add (GST_BIN (pipeline), id3demux); + gst_bin_add (GST_BIN (pipeline), fakesink); + + gst_tag_setter_merge_tags (GST_TAG_SETTER (id3mux), tags, + GST_TAG_MERGE_APPEND); + + gst_element_link_many (fakesrc, id3mux, identity, id3demux, fakesink, NULL); + + /* set up source */ + g_object_set (fakesrc, "signal-handoffs", TRUE, "can-activate-pull", FALSE, + "filltype", 2, "sizetype", 2, "sizemax", MP3_FRAME_SIZE, + "num-buffers", 16, NULL); + + offset = 0; + g_signal_connect (fakesrc, "handoff", G_CALLBACK (fill_mp3_buffer), &offset); + + /* set up identity to catch tag buffer */ + g_signal_connect (identity, "handoff", G_CALLBACK (identity_cb), &tagbuf); + + GST_LOG ("setting and getting state ..."); + gst_element_set_state (pipeline, GST_STATE_PLAYING); + state_result = gst_element_get_state (pipeline, NULL, NULL, -1); + fail_unless (state_result == GST_STATE_CHANGE_SUCCESS, + "Unexpected result from get_state(). Expected success, got %d", + state_result); + + bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); + + GST_LOG ("Waiting for tag ..."); + msg = + gst_bus_poll (bus, GST_MESSAGE_TAG | GST_MESSAGE_EOS | GST_MESSAGE_ERROR, + -1); + if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) { + GError *err; + gchar *dbg; + + gst_message_parse_error (msg, &err, &dbg); + g_printerr ("ERROR from element %s: %s\n%s\n", + GST_OBJECT_NAME (msg->src), err->message, GST_STR_NULL (dbg)); + g_error_free (err); + g_free (dbg); + } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS) { + g_printerr ("EOS message, but were waiting for TAGS!\n"); + } + fail_unless (msg->type == GST_MESSAGE_TAG); + + gst_message_parse_tag (msg, &tags_read); + gst_message_unref (msg); + + GST_LOG ("Got tags: %" GST_PTR_FORMAT, tags_read); + test_taglib_id3mux_check_tags (tags_read, mask, v2version); + gst_tag_list_free (tags_read); + + fail_unless (tagbuf != NULL); + test_taglib_id3mux_check_tag_buffer (tagbuf, mask, v2version); + gst_buffer_unref (tagbuf); + + GST_LOG ("Waiting for EOS ..."); + msg = gst_bus_poll (bus, GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1); + if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) { + GError *err; + gchar *dbg; + + gst_message_parse_error (msg, &err, &dbg); + g_printerr ("ERROR from element %s: %s\n%s\n", + GST_OBJECT_NAME (msg->src), err->message, GST_STR_NULL (dbg)); + g_error_free (err); + g_free (dbg); + } + fail_unless (msg->type == GST_MESSAGE_EOS); + gst_message_unref (msg); + + gst_object_unref (bus); + + GST_LOG ("Got EOS, shutting down ..."); + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (pipeline); + + test_taglib_id3mux_check_output_buffer (outbuf); + gst_buffer_unref (outbuf); + + GST_LOG ("Done"); +} + +static void +run_id3mux_test (int v2version) +{ + GstTagList *tags; + gint i; + + g_random_set_seed (247166295); + + /* internal consistency check */ + tags = test_taglib_id3mux_create_tags (0xFFFFFFFF); + test_taglib_id3mux_check_tags (tags, 0xFFFFFFFF, v2version); + gst_tag_list_free (tags); + + /* now the real tests */ + for (i = 0; i < 50; ++i) { + guint32 mask; + + mask = g_random_int (); + GST_LOG ("tag mask = %08x (i=%d)", mask, i); + + if (mask == 0) + continue; + + /* create tags */ + tags = test_taglib_id3mux_create_tags (mask); + GST_LOG ("tags for mask %08x = %" GST_PTR_FORMAT, mask, tags); + + /* double-check for internal consistency */ + test_taglib_id3mux_check_tags (tags, mask, v2version); + + /* test with pipeline */ + test_taglib_id3mux_with_tags (tags, mask, v2version); + + /* free tags */ + gst_tag_list_free (tags); + } +} + +GST_START_TEST (test_id3mux_v2_3) +{ + run_id3mux_test (3); +} + +GST_END_TEST; + +GST_START_TEST (test_id3mux_v2_4) +{ + run_id3mux_test (4); +} + +GST_END_TEST; + +static Suite * +id3mux_suite (void) +{ + Suite *s = suite_create ("id3mux"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + + if (gst_registry_check_feature_version (gst_registry_get (), "id3demux", + GST_VERSION_MAJOR, GST_VERSION_MINOR, 0)) { + tcase_add_test (tc_chain, test_id3mux_v2_3); + tcase_add_test (tc_chain, test_id3mux_v2_4); + } else { + GST_WARNING ("id3demux element not available, skipping tests"); + } + + return s; +} + +GST_CHECK_MAIN (id3mux); diff --git a/tests/check/elements/jifmux.c b/tests/check/elements/jifmux.c new file mode 100644 index 00000000..680e0122 --- /dev/null +++ b/tests/check/elements/jifmux.c @@ -0,0 +1,1239 @@ +/* GStreamer + * + * unit test for jifmux + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <unistd.h> + +#include <glib/gstdio.h> + +#include <gst/check/gstcheck.h> +#include <gst/tag/tag.h> + +#include <libexif/exif-data.h> +#include <libexif/exif-loader.h> + +typedef struct +{ + gboolean result; + const GstTagList *taglist; + gint map_index; +} ExifTagCheckData; + +/* taken from the exif helper lib in -base */ +/* Exif tag types */ +#define EXIF_TYPE_BYTE 1 +#define EXIF_TYPE_ASCII 2 +#define EXIF_TYPE_SHORT 3 +#define EXIF_TYPE_LONG 4 +#define EXIF_TYPE_RATIONAL 5 +#define EXIF_TYPE_UNDEFINED 7 +#define EXIF_TYPE_SLONG 9 +#define EXIF_TYPE_SRATIONAL 10 + +typedef struct _GstExifTagMatch GstExifTagMatch; +typedef void (*CompareFunc) (ExifEntry * entry, ExifTagCheckData * testdata); + +struct _GstExifTagMatch +{ + const gchar *gst_tag; + guint16 exif_tag; + guint16 exif_type; + CompareFunc compare_func; +}; + +/* compare funcs */ + +/* Copied over from gst-libs/gst/tag/gsttagedittingprivate.c from -base */ +static gint +__exif_tag_image_orientation_to_exif_value (const gchar * str) +{ + if (str == NULL) + goto end; + + if (strcmp (str, "rotate-0") == 0) + return 1; + else if (strcmp (str, "flip-rotate-0") == 0) + return 2; + else if (strcmp (str, "rotate-180") == 0) + return 3; + else if (strcmp (str, "flip-rotate-180") == 0) + return 4; + else if (strcmp (str, "flip-rotate-270") == 0) + return 5; + else if (strcmp (str, "rotate-90") == 0) + return 6; + else if (strcmp (str, "flip-rotate-90") == 0) + return 7; + else if (strcmp (str, "rotate-270") == 0) + return 8; + +end: + GST_WARNING ("Invalid image orientation tag: %s", str); + return -1; +} + +static gint +__exif_tag_capture_exposure_program_to_exif_value (const gchar * str) +{ + if (str == NULL) + goto end; + + if (strcmp (str, "undefined") == 0) + return 0; + else if (strcmp (str, "manual") == 0) + return 1; + else if (strcmp (str, "normal") == 0) + return 2; + else if (strcmp (str, "aperture-priority") == 0) + return 3; + else if (strcmp (str, "shutter-priority") == 0) + return 4; + else if (strcmp (str, "creative") == 0) + return 5; + else if (strcmp (str, "action") == 0) + return 6; + else if (strcmp (str, "portrait") == 0) + return 7; + else if (strcmp (str, "landscape") == 0) + return 8; + +end: + GST_WARNING ("Invalid capture exposure program tag: %s", str); + return -1; +} + +static gint +__exif_tag_capture_exposure_mode_to_exif_value (const gchar * str) +{ + if (str == NULL) + goto end; + + if (strcmp (str, "auto-exposure") == 0) + return 0; + else if (strcmp (str, "manual-exposure") == 0) + return 1; + else if (strcmp (str, "auto-bracket") == 0) + return 2; + +end: + GST_WARNING ("Invalid capture exposure mode tag: %s", str); + return -1; +} + +static gint +__exif_tag_capture_scene_capture_type_to_exif_value (const gchar * str) +{ + if (str == NULL) + goto end; + + if (strcmp (str, "standard") == 0) + return 0; + else if (strcmp (str, "landscape") == 0) + return 1; + else if (strcmp (str, "portrait") == 0) + return 2; + else if (strcmp (str, "night-scene") == 0) + return 3; + +end: + GST_WARNING ("Invalid capture scene capture type: %s", str); + return -1; +} + +static gint +__exif_tag_capture_gain_adjustment_to_exif_value (const gchar * str) +{ + if (str == NULL) + goto end; + + if (strcmp (str, "none") == 0) + return 0; + else if (strcmp (str, "low-gain-up") == 0) + return 1; + else if (strcmp (str, "high-gain-up") == 0) + return 2; + else if (strcmp (str, "low-gain-down") == 0) + return 3; + else if (strcmp (str, "high-gain-down") == 0) + return 4; + +end: + GST_WARNING ("Invalid capture gain adjustment type: %s", str); + return -1; +} + +static gint +__exif_tag_capture_white_balance_to_exif_value (const gchar * str) +{ + if (str == NULL) + goto end; + + if (strcmp (str, "auto") == 0) + return 0; + else /* everything else is just manual */ + return 1; + +end: + GST_WARNING ("Invalid white balance: %s", str); + return -1; +} + +static gint +__exif_tag_capture_contrast_to_exif_value (const gchar * str) +{ + if (str == NULL) + goto end; + + if (strcmp (str, "normal") == 0) + return 0; + else if (strcmp (str, "soft") == 0) + return 1; + else if (strcmp (str, "hard") == 0) + return 2; + +end: + GST_WARNING ("Invalid contrast type: %s", str); + return -1; +} + +static gint +__exif_tag_capture_sharpness_to_exif_value (const gchar * str) +{ + if (str == NULL) + goto end; + + if (strcmp (str, "normal") == 0) + return 0; + else if (strcmp (str, "soft") == 0) + return 1; + else if (strcmp (str, "hard") == 0) + return 2; + +end: + GST_WARNING ("Invalid sharpness type: %s", str); + return -1; +} + +static gint +__exif_tag_capture_saturation_to_exif_value (const gchar * str) +{ + if (str == NULL) + goto end; + + if (strcmp (str, "normal") == 0) + return 0; + else if (strcmp (str, "low-saturation") == 0) + return 1; + else if (strcmp (str, "high-saturation") == 0) + return 2; + +end: + GST_WARNING ("Invalid saturation type: %s", str); + return -1; +} + +static gint +__exif_tag_capture_metering_mode_to_exif_value (const gchar * str) +{ + if (str == NULL) + goto end; + + if (strcmp (str, "unknown") == 0) + return 0; + else if (strcmp (str, "average") == 0) + return 1; + else if (strcmp (str, "center-weighted-average") == 0) + return 2; + else if (strcmp (str, "spot") == 0) + return 3; + else if (strcmp (str, "multi-spot") == 0) + return 4; + else if (strcmp (str, "pattern") == 0) + return 5; + else if (strcmp (str, "partial") == 0) + return 6; + else if (strcmp (str, "other") == 0) + return 255; + +end: + GST_WARNING ("Invalid metering mode type: %s", str); + return -1; +} + +static gint +__exif_tag_capture_source_to_exif_value (const gchar * str) +{ + if (str == NULL) + goto end; + + if (strcmp (str, "dsc") == 0) + return 3; + else if (strcmp (str, "other") == 0) + return 0; + else if (strcmp (str, "transparent-scanner") == 0) + return 1; + else if (strcmp (str, "reflex-scanner") == 0) + return 2; + +end: + GST_WARNING ("Invalid capturing source type: %s", str); + return -1; +} + +#define GST_COMPARE_GST_STRING_TAG_TO_EXIF_SHORT_FUNC(gst_tag,name) \ +static void \ +compare_ ## name (ExifEntry * entry, ExifTagCheckData * testdata) \ +{ \ + gchar *str_tag = NULL; \ + gint exif_value = -1; \ + gint value = -1; \ + \ + if (!gst_tag_list_get_string_index (testdata->taglist, \ + gst_tag, 0, &str_tag)) { \ + /* fail the test if we can't get the tag */ \ + GST_WARNING ("Failed to get %s from taglist", gst_tag); \ + fail (); \ + } \ + \ + value = __exif_tag_ ## name ## _to_exif_value (str_tag); \ + \ + if (value == -1) { \ + GST_WARNING ("Invalid %s tag value: %s", gst_tag, str_tag); \ + fail (); \ + } \ + \ + if (entry->format == EXIF_TYPE_SHORT) \ + exif_value = (gint) exif_get_short (entry->data, \ + exif_data_get_byte_order (entry->parent->parent)); \ + else if (entry->format == EXIF_TYPE_UNDEFINED) \ + exif_value = (gint) entry->data[0]; \ + \ + if (value != exif_value) { \ + GST_WARNING ("Gstreamer tag value (%d) is different from libexif (%d)", \ + value, exif_value); \ + fail (); \ + } \ + \ + testdata->result = TRUE; \ + \ + g_free (str_tag); \ +} + +GST_COMPARE_GST_STRING_TAG_TO_EXIF_SHORT_FUNC (GST_TAG_IMAGE_ORIENTATION, + image_orientation); +GST_COMPARE_GST_STRING_TAG_TO_EXIF_SHORT_FUNC + (GST_TAG_CAPTURING_EXPOSURE_PROGRAM, capture_exposure_program); +GST_COMPARE_GST_STRING_TAG_TO_EXIF_SHORT_FUNC (GST_TAG_CAPTURING_EXPOSURE_MODE, + capture_exposure_mode); +GST_COMPARE_GST_STRING_TAG_TO_EXIF_SHORT_FUNC (GST_TAG_CAPTURING_WHITE_BALANCE, + capture_white_balance); +GST_COMPARE_GST_STRING_TAG_TO_EXIF_SHORT_FUNC (GST_TAG_CAPTURING_CONTRAST, + capture_contrast); +GST_COMPARE_GST_STRING_TAG_TO_EXIF_SHORT_FUNC + (GST_TAG_CAPTURING_GAIN_ADJUSTMENT, capture_gain_adjustment); +GST_COMPARE_GST_STRING_TAG_TO_EXIF_SHORT_FUNC (GST_TAG_CAPTURING_SATURATION, + capture_saturation); +GST_COMPARE_GST_STRING_TAG_TO_EXIF_SHORT_FUNC + (GST_TAG_CAPTURING_SHARPNESS, capture_sharpness); +GST_COMPARE_GST_STRING_TAG_TO_EXIF_SHORT_FUNC + (GST_TAG_CAPTURING_SCENE_CAPTURE_TYPE, capture_scene_capture_type); +GST_COMPARE_GST_STRING_TAG_TO_EXIF_SHORT_FUNC + (GST_TAG_CAPTURING_METERING_MODE, capture_metering_mode); +GST_COMPARE_GST_STRING_TAG_TO_EXIF_SHORT_FUNC + (GST_TAG_CAPTURING_SOURCE, capture_source); + +static void +compare_date_time (ExifEntry * entry, ExifTagCheckData * testdata) +{ + gint year = 0, month = 1, day = 1, hour = 0, minute = 0, second = 0; + GstDateTime *exif_datetime; + GstDateTime *datetime; + const gchar *str; + + if (!gst_tag_list_get_date_time_index (testdata->taglist, GST_TAG_DATE_TIME, + 0, &datetime)) { + GST_WARNING ("Failed to get datetime from taglist"); + return; + } + + str = (gchar *) entry->data; + + sscanf (str, "%04d:%02d:%02d %02d:%02d:%02d", &year, &month, &day, + &hour, &minute, &second); + exif_datetime = gst_date_time_new_local_time (year, month, day, hour, minute, + second); + fail_if (exif_datetime == NULL); + + fail_unless (gst_date_time_get_year (datetime) == + gst_date_time_get_year (exif_datetime) + && gst_date_time_get_month (datetime) == + gst_date_time_get_month (exif_datetime) + && gst_date_time_get_day (datetime) == + gst_date_time_get_day (exif_datetime) + && gst_date_time_get_hour (datetime) == + gst_date_time_get_hour (exif_datetime) + && gst_date_time_get_minute (datetime) == + gst_date_time_get_minute (exif_datetime) + && gst_date_time_get_second (datetime) == + gst_date_time_get_second (exif_datetime)); + + gst_date_time_unref (exif_datetime); + gst_date_time_unref (datetime); + + testdata->result = TRUE; +} + +static void +compare_shutter_speed (ExifEntry * entry, ExifTagCheckData * testdata) +{ + gdouble gst_num, exif_num; + ExifSRational rational; + GValue exif_value = { 0 }; + const GValue *gst_value = NULL; + + gst_value = gst_tag_list_get_value_index (testdata->taglist, + GST_TAG_CAPTURING_SHUTTER_SPEED, 0); + if (gst_value == NULL) { + GST_WARNING ("Failed to get shutter-speed from taglist"); + return; + } + + rational = exif_get_srational (entry->data, + exif_data_get_byte_order (entry->parent->parent)); + + g_value_init (&exif_value, GST_TYPE_FRACTION); + gst_value_set_fraction (&exif_value, rational.numerator, + rational.denominator); + gst_util_fraction_to_double (gst_value_get_fraction_numerator (&exif_value), + gst_value_get_fraction_denominator (&exif_value), &exif_num); + g_value_unset (&exif_value); + + gst_util_fraction_to_double (gst_value_get_fraction_numerator (gst_value), + gst_value_get_fraction_denominator (gst_value), &gst_num); + + exif_num = pow (2, -exif_num); + + GST_LOG ("Shutter speed in gst=%lf and in exif=%lf", gst_num, exif_num); + fail_unless (ABS (gst_num - exif_num) < 0.001); + testdata->result = TRUE; +} + +static void +compare_aperture_value (ExifEntry * entry, ExifTagCheckData * testdata) +{ + gdouble gst_value, exif_value; + ExifSRational rational; + GValue value = { 0 }; + + if (!gst_tag_list_get_double_index (testdata->taglist, + GST_TAG_CAPTURING_FOCAL_RATIO, 0, &gst_value)) { + GST_WARNING ("Failed to get focal ratio from taglist"); + return; + } + + rational = exif_get_srational (entry->data, + exif_data_get_byte_order (entry->parent->parent)); + + g_value_init (&value, GST_TYPE_FRACTION); + gst_value_set_fraction (&value, rational.numerator, rational.denominator); + gst_util_fraction_to_double (gst_value_get_fraction_numerator (&value), + gst_value_get_fraction_denominator (&value), &exif_value); + g_value_unset (&value); + + exif_value = pow (2, exif_value / 2); + + GST_LOG ("Aperture value in gst=%lf and in exif=%lf", gst_value, exif_value); + fail_unless (ABS (gst_value - exif_value) < 0.001); + testdata->result = TRUE; +} + +static void +compare_flash (ExifEntry * entry, ExifTagCheckData * testdata) +{ + guint16 flags; + gboolean flash_fired; + const gchar *flash_mode; + + flags = (gint) exif_get_short (entry->data, + exif_data_get_byte_order (entry->parent->parent)); + + if (!gst_tag_list_get_boolean_index (testdata->taglist, + GST_TAG_CAPTURING_FLASH_FIRED, 0, &flash_fired)) { + GST_WARNING ("Failed to get %s tag", GST_TAG_CAPTURING_FLASH_FIRED); + return; + } + if (!gst_tag_list_peek_string_index (testdata->taglist, + GST_TAG_CAPTURING_FLASH_MODE, 0, &flash_mode)) { + GST_WARNING ("Failed to get %s tag", GST_TAG_CAPTURING_FLASH_MODE); + return; + } + + if (flash_fired) + fail_unless ((flags & 1) == 1); + else + fail_unless ((flags & 1) == 0); + + if (strcmp (flash_mode, "auto") == 0) { + fail_unless (((flags >> 3) & 0x3) == 3); + } else if (strcmp (flash_mode, "always") == 0) { + fail_unless (((flags >> 3) & 0x3) == 1); + } else if (strcmp (flash_mode, "never") == 0) { + fail_unless (((flags >> 3) & 0x3) == 2); + } else { + fail (); + } + testdata->result = TRUE; +} + +static void +compare_geo_elevation (ExifEntry * entry, ExifTagCheckData * testdata) +{ + gdouble altitude = 0, gst_value; + ExifRational rational; + + fail_unless (gst_tag_list_get_double_index (testdata->taglist, + GST_TAG_GEO_LOCATION_ELEVATION, 0, &gst_value)); + + fail_unless (entry->components == 1); + + rational = exif_get_rational (entry->data, + exif_data_get_byte_order (entry->parent->parent)); + gst_util_fraction_to_double (rational.numerator, rational.denominator, + &altitude); + + gst_value = ABS (gst_value); + fail_unless (ABS (gst_value - altitude) < 0.001); + testdata->result = TRUE; +} + +static void +compare_geo_elevation_ref (ExifEntry * entry, ExifTagCheckData * testdata) +{ + gdouble gst_value; + + fail_unless (gst_tag_list_get_double_index (testdata->taglist, + GST_TAG_GEO_LOCATION_ELEVATION, 0, &gst_value)); + + fail_unless (entry->components == 1); + + if (gst_value >= 0) { + fail_unless (entry->data[0] == 0); + } else { + fail_unless (entry->data[0] == 1); + } + testdata->result = TRUE; +} + +static void +compare_speed (ExifEntry * entry, ExifTagCheckData * testdata) +{ + gdouble speed = 0, gst_value; + ExifRational rational; + + fail_unless (gst_tag_list_get_double_index (testdata->taglist, + GST_TAG_GEO_LOCATION_MOVEMENT_SPEED, 0, &gst_value)); + + fail_unless (entry->components == 1); + + rational = exif_get_rational (entry->data, + exif_data_get_byte_order (entry->parent->parent)); + gst_util_fraction_to_double (rational.numerator, rational.denominator, + &speed); + + speed = speed / 3.6; + + fail_unless (ABS (gst_value - speed) < 0.001); + testdata->result = TRUE; +} + +static void +compare_speed_ref (ExifEntry * entry, ExifTagCheckData * testdata) +{ + fail_unless (entry->components == 2); + fail_unless (entry->data[0] == 'K'); + testdata->result = TRUE; +} + +static void +compare_geo_coordinate (ExifEntry * entry, ExifTagCheckData * testdata); + +static void +compare_geo_coordinate_ref (ExifEntry * entry, ExifTagCheckData * testdata); + +static void +compare_geo_direction (ExifEntry * entry, ExifTagCheckData * testdata); + +static void +compare_geo_direction_ref (ExifEntry * entry, ExifTagCheckData * testdata); + +static const GstExifTagMatch tag_map[] = { + {GST_TAG_DESCRIPTION, EXIF_TAG_IMAGE_DESCRIPTION, EXIF_TYPE_ASCII, + NULL}, + {GST_TAG_DEVICE_MANUFACTURER, EXIF_TAG_MAKE, EXIF_TYPE_ASCII, + NULL}, + {GST_TAG_DEVICE_MODEL, EXIF_TAG_MODEL, EXIF_TYPE_ASCII, NULL}, + {GST_TAG_IMAGE_ORIENTATION, EXIF_TAG_ORIENTATION, EXIF_TYPE_SHORT, + compare_image_orientation}, + {GST_TAG_IMAGE_HORIZONTAL_PPI, EXIF_TAG_X_RESOLUTION, EXIF_TYPE_RATIONAL, + NULL}, + {GST_TAG_IMAGE_VERTICAL_PPI, EXIF_TAG_Y_RESOLUTION, EXIF_TYPE_RATIONAL, NULL}, + {GST_TAG_APPLICATION_NAME, EXIF_TAG_SOFTWARE, EXIF_TYPE_ASCII, + NULL}, + {GST_TAG_DATE_TIME, EXIF_TAG_DATE_TIME, EXIF_TYPE_ASCII, + compare_date_time}, + {GST_TAG_ARTIST, EXIF_TAG_ARTIST, EXIF_TYPE_ASCII, NULL}, + {GST_TAG_COPYRIGHT, EXIF_TAG_COPYRIGHT, EXIF_TYPE_ASCII, NULL}, + {GST_TAG_CAPTURING_SHUTTER_SPEED, EXIF_TAG_EXPOSURE_TIME, + EXIF_TYPE_RATIONAL, NULL}, + {GST_TAG_CAPTURING_FOCAL_RATIO, EXIF_TAG_FNUMBER, EXIF_TYPE_RATIONAL, + NULL}, + {GST_TAG_CAPTURING_EXPOSURE_PROGRAM, EXIF_TAG_EXPOSURE_PROGRAM, + EXIF_TYPE_SHORT, compare_capture_exposure_program}, + + /* This is called PhotographicSensitivity in 2.3 */ + {GST_TAG_CAPTURING_ISO_SPEED, EXIF_TAG_ISO_SPEED_RATINGS, + EXIF_TYPE_SHORT, NULL}, + + {GST_TAG_CAPTURING_SHUTTER_SPEED, EXIF_TAG_SHUTTER_SPEED_VALUE, + EXIF_TYPE_SRATIONAL, compare_shutter_speed}, + {GST_TAG_CAPTURING_FOCAL_RATIO, EXIF_TAG_APERTURE_VALUE, EXIF_TYPE_RATIONAL, + compare_aperture_value}, + {GST_TAG_CAPTURING_EXPOSURE_COMPENSATION, EXIF_TAG_EXPOSURE_BIAS_VALUE, + EXIF_TYPE_SRATIONAL}, + {GST_TAG_CAPTURING_FLASH_FIRED, EXIF_TAG_FLASH, EXIF_TYPE_SHORT, + compare_flash}, + {GST_TAG_CAPTURING_FLASH_MODE, EXIF_TAG_FLASH, EXIF_TYPE_SHORT, + compare_flash}, + {GST_TAG_CAPTURING_FOCAL_LENGTH, EXIF_TAG_FOCAL_LENGTH, EXIF_TYPE_RATIONAL, + NULL}, + {GST_TAG_APPLICATION_DATA, EXIF_TAG_MAKER_NOTE, EXIF_TYPE_UNDEFINED, NULL}, + {GST_TAG_CAPTURING_EXPOSURE_MODE, EXIF_TAG_EXPOSURE_MODE, EXIF_TYPE_SHORT, + compare_capture_exposure_mode}, + {GST_TAG_CAPTURING_WHITE_BALANCE, EXIF_TAG_WHITE_BALANCE, EXIF_TYPE_SHORT, + compare_capture_white_balance}, + {GST_TAG_CAPTURING_DIGITAL_ZOOM_RATIO, EXIF_TAG_DIGITAL_ZOOM_RATIO, + EXIF_TYPE_RATIONAL, NULL}, + {GST_TAG_CAPTURING_SCENE_CAPTURE_TYPE, EXIF_TAG_SCENE_CAPTURE_TYPE, + EXIF_TYPE_SHORT, compare_capture_scene_capture_type}, + {GST_TAG_CAPTURING_GAIN_ADJUSTMENT, EXIF_TAG_GAIN_CONTROL, + EXIF_TYPE_SHORT, compare_capture_gain_adjustment}, + {GST_TAG_CAPTURING_CONTRAST, EXIF_TAG_CONTRAST, EXIF_TYPE_SHORT, + compare_capture_contrast}, + {GST_TAG_CAPTURING_SATURATION, EXIF_TAG_SATURATION, EXIF_TYPE_SHORT, + compare_capture_saturation}, + {GST_TAG_CAPTURING_SHARPNESS, EXIF_TAG_SHARPNESS, EXIF_TYPE_SHORT, + compare_capture_sharpness}, + {GST_TAG_CAPTURING_METERING_MODE, EXIF_TAG_METERING_MODE, EXIF_TYPE_SHORT, + compare_capture_metering_mode}, + {GST_TAG_CAPTURING_SOURCE, EXIF_TAG_FILE_SOURCE, EXIF_TYPE_UNDEFINED, + compare_capture_source}, + + /* gps tags */ + {GST_TAG_GEO_LOCATION_LATITUDE, EXIF_TAG_GPS_LATITUDE, EXIF_TYPE_RATIONAL, + compare_geo_coordinate}, + {GST_TAG_GEO_LOCATION_LATITUDE, EXIF_TAG_GPS_LATITUDE_REF, EXIF_TYPE_ASCII, + compare_geo_coordinate_ref}, + {GST_TAG_GEO_LOCATION_LONGITUDE, EXIF_TAG_GPS_LONGITUDE, EXIF_TYPE_RATIONAL, + compare_geo_coordinate}, + {GST_TAG_GEO_LOCATION_LONGITUDE, EXIF_TAG_GPS_LONGITUDE_REF, EXIF_TYPE_ASCII, + compare_geo_coordinate_ref}, + {GST_TAG_GEO_LOCATION_ELEVATION, EXIF_TAG_GPS_ALTITUDE, EXIF_TYPE_RATIONAL, + compare_geo_elevation}, + {GST_TAG_GEO_LOCATION_ELEVATION, EXIF_TAG_GPS_ALTITUDE_REF, EXIF_TYPE_BYTE, + compare_geo_elevation_ref}, + {GST_TAG_GEO_LOCATION_MOVEMENT_SPEED, EXIF_TAG_GPS_SPEED, EXIF_TYPE_RATIONAL, + compare_speed}, + {GST_TAG_GEO_LOCATION_MOVEMENT_SPEED, EXIF_TAG_GPS_SPEED_REF, EXIF_TYPE_ASCII, + compare_speed_ref}, + {GST_TAG_GEO_LOCATION_MOVEMENT_DIRECTION, EXIF_TAG_GPS_TRACK, + EXIF_TYPE_RATIONAL, compare_geo_direction}, + {GST_TAG_GEO_LOCATION_MOVEMENT_DIRECTION, EXIF_TAG_GPS_TRACK_REF, + EXIF_TYPE_ASCII, compare_geo_direction_ref}, + {GST_TAG_GEO_LOCATION_CAPTURE_DIRECTION, EXIF_TAG_GPS_IMG_DIRECTION, + EXIF_TYPE_RATIONAL, compare_geo_direction}, + {GST_TAG_GEO_LOCATION_CAPTURE_DIRECTION, EXIF_TAG_GPS_IMG_DIRECTION_REF, + EXIF_TYPE_ASCII, compare_geo_direction_ref} + +/* + * libexif doesn't have these tags + * {GST_TAG_CAPTURING_ISO_SPEED, EXIF_TAG_ISO_SPEED, EXIF_TYPE_LONG, NULL}, + * {GST_TAG_CAPTURING_ISO_SPEED, EXIF_TAG_SENSITIVITY_TYPE, + * EXIF_TYPE_SHORT, compare_sensitivity_type}, + */ +}; + +static void +compare_geo_coordinate (ExifEntry * entry, ExifTagCheckData * testdata) +{ + gdouble coordinate = 0, aux, gst_value; + ExifRational rational; + + fail_unless (gst_tag_list_get_double_index (testdata->taglist, + tag_map[testdata->map_index].gst_tag, 0, &gst_value)); + + fail_unless (entry->components == 3); + + rational = exif_get_rational (entry->data, + exif_data_get_byte_order (entry->parent->parent)); + gst_util_fraction_to_double (rational.numerator, rational.denominator, &aux); + coordinate += aux; + + rational = exif_get_rational (entry->data + 8, + exif_data_get_byte_order (entry->parent->parent)); + gst_util_fraction_to_double (rational.numerator, rational.denominator, &aux); + coordinate += aux / 60.0; + + rational = exif_get_rational (entry->data + 16, + exif_data_get_byte_order (entry->parent->parent)); + gst_util_fraction_to_double (rational.numerator, rational.denominator, &aux); + coordinate += aux / 3600.0; + + gst_value = ABS (gst_value); + fail_unless (ABS (gst_value - coordinate) < 0.001); + testdata->result = TRUE; +} + +static void +compare_geo_coordinate_ref (ExifEntry * entry, ExifTagCheckData * testdata) +{ + gdouble gst_value; + const gchar *tag; + + tag = tag_map[testdata->map_index].gst_tag; + + fail_unless (gst_tag_list_get_double_index (testdata->taglist, tag, 0, + &gst_value)); + + fail_unless (entry->components == 2); + + if (strcmp (tag, GST_TAG_GEO_LOCATION_LATITUDE) == 0) { + if (gst_value >= 0) { + fail_unless (entry->data[0] == 'N'); + } else { + fail_unless (entry->data[0] == 'S'); + } + } else { + if (gst_value >= 0) { + fail_unless (entry->data[0] == 'E'); + } else { + fail_unless (entry->data[0] == 'W'); + } + } + testdata->result = TRUE; +} + +static void +compare_geo_direction (ExifEntry * entry, ExifTagCheckData * testdata) +{ + gdouble direction = 0, gst_value; + ExifRational rational; + + fail_unless (gst_tag_list_get_double_index (testdata->taglist, + tag_map[testdata->map_index].gst_tag, 0, &gst_value)); + + fail_unless (entry->components == 1); + + rational = exif_get_rational (entry->data, + exif_data_get_byte_order (entry->parent->parent)); + gst_util_fraction_to_double (rational.numerator, rational.denominator, + &direction); + + fail_unless (ABS (gst_value - direction) < 0.001); + testdata->result = TRUE; +} + +static void +compare_geo_direction_ref (ExifEntry * entry, ExifTagCheckData * testdata) +{ + fail_unless (entry->components == 2); + fail_unless (entry->data[0] == 'T'); + testdata->result = TRUE; +} + +static void +check_content (ExifContent * content, void *user_data) +{ + ExifTagCheckData *test_data = (ExifTagCheckData *) user_data; + guint16 tagindex; + ExifEntry *entry; + GType gst_tag_type; + + tagindex = test_data->map_index; + gst_tag_type = gst_tag_get_type (tag_map[tagindex].gst_tag); + + GST_DEBUG ("Got tagindex %u for gsttag %s with type %s", tagindex, + tag_map[tagindex].gst_tag, g_type_name (gst_tag_type)); + + /* search for the entry */ + entry = exif_content_get_entry (content, tag_map[tagindex].exif_tag); + GST_DEBUG ("Entry found at %p", entry); + if (entry == NULL) + return; + + fail_unless (entry->format == tag_map[tagindex].exif_type); + + if (tag_map[tagindex].compare_func) { + tag_map[tagindex].compare_func (entry, test_data); + return; + } + + switch (entry->format) { + case EXIF_TYPE_ASCII:{ + const gchar *str; + gchar *taglist_str; + + str = (gchar *) entry->data; + fail_unless (gst_tag_list_get_string (test_data->taglist, + tag_map[tagindex].gst_tag, &taglist_str)); + + fail_unless (strcmp (str, taglist_str) == 0); + test_data->result = TRUE; + g_free (taglist_str); + } + break; + case EXIF_TYPE_SRATIONAL: + case EXIF_TYPE_RATIONAL:{ + GValue exif_value = { 0 }; + + g_value_init (&exif_value, GST_TYPE_FRACTION); + if (entry->format == EXIF_TYPE_RATIONAL) { + ExifRational exif_rational = exif_get_rational (entry->data, + exif_data_get_byte_order (entry->parent->parent)); + + gst_value_set_fraction (&exif_value, exif_rational.numerator, + exif_rational.denominator); + } else { + ExifSRational exif_rational = exif_get_srational (entry->data, + exif_data_get_byte_order (entry->parent->parent)); + + gst_value_set_fraction (&exif_value, exif_rational.numerator, + exif_rational.denominator); + } + + if (gst_tag_type == GST_TYPE_FRACTION) { + const GValue *value = gst_tag_list_get_value_index (test_data->taglist, + tag_map[tagindex].gst_tag, 0); + + fail_unless (value != NULL); + fail_unless (G_VALUE_TYPE (value) == GST_TYPE_FRACTION); + + fail_unless (gst_value_get_fraction_numerator (value) == + gst_value_get_fraction_numerator (&exif_value) && + gst_value_get_fraction_denominator (value) == + gst_value_get_fraction_denominator (&exif_value)); + + test_data->result = TRUE; + } else if (gst_tag_type == G_TYPE_DOUBLE) { + gdouble gst_num; + gdouble exif_num; + + gst_util_fraction_to_double (gst_value_get_fraction_numerator + (&exif_value), gst_value_get_fraction_denominator (&exif_value), + &exif_num); + + fail_unless (gst_tag_list_get_double_index (test_data->taglist, + tag_map[tagindex].gst_tag, 0, &gst_num)); + + fail_unless (gst_num == exif_num); + test_data->result = TRUE; + } else { + GST_WARNING ("Unhandled type for rational tag(%X): %s", + entry->tag, g_type_name (gst_tag_type)); + } + g_value_unset (&exif_value); + } + break; + case EXIF_TYPE_SHORT: + case EXIF_TYPE_LONG:{ + gint gst_num; + gint exif_num = -1; + + if (entry->format == EXIF_TYPE_LONG) { + exif_num = (gint) exif_get_long (entry->data, + exif_data_get_byte_order (entry->parent->parent)); + } else if (entry->format == EXIF_TYPE_SHORT) { + exif_num = (gint) exif_get_short (entry->data, + exif_data_get_byte_order (entry->parent->parent)); + } + + fail_unless (gst_tag_list_get_int_index (test_data->taglist, + tag_map[tagindex].gst_tag, 0, &gst_num)); + + fail_unless (exif_num == gst_num); + test_data->result = TRUE; + } + break; + case EXIF_TYPE_UNDEFINED:{ + GstMapInfo map; + GstBuffer *buf; + gint i; + + if (!gst_tag_list_get_buffer_index (test_data->taglist, + tag_map[tagindex].gst_tag, 0, &buf)) { + return; + } + + gst_buffer_map (buf, &map, GST_MAP_READ); + fail_unless (entry->size, map.size); + for (i = 0; i < map.size; i++) { + fail_unless (map.data[i] == (guint8) entry->data[i]); + } + gst_buffer_unmap (buf, &map); + + test_data->result = TRUE; + gst_buffer_unref (buf); + } + break; + default: + fail (); + } +} + +/* + * Iterates over the exif data searching for the mapping pointed by index + */ +static void +libexif_check_tag_exists (const GstTagList * taglist, gint index, gpointer data) +{ + ExifData *exif_data = (ExifData *) data; + ExifTagCheckData test_data; + + test_data.result = FALSE; + test_data.taglist = taglist; + test_data.map_index = index; + + exif_data_foreach_content (exif_data, check_content, &test_data); + + fail_unless (test_data.result); +} + +static void +generate_jif_file_with_tags_from_taglist (GstTagList * taglist, + const gchar * filepath) +{ + GstElement *pipeline; + GstBus *bus; + GstMessage *msg; + gchar *launchline; + GstElement *jifmux; + GstTagSetter *setter; + + launchline = g_strdup_printf ("videotestsrc num-buffers=1 ! jpegenc ! " + "jifmux name=jifmux0 ! filesink location=%s", filepath); + + pipeline = gst_parse_launch (launchline, NULL); + fail_unless (pipeline != NULL); + g_free (launchline); + + jifmux = gst_bin_get_by_name (GST_BIN (pipeline), "jifmux0"); + fail_unless (jifmux != NULL); + setter = GST_TAG_SETTER (jifmux); + gst_tag_setter_merge_tags (setter, taglist, GST_TAG_MERGE_REPLACE); + gst_object_unref (jifmux); + + bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); + + fail_if (gst_element_set_state (pipeline, GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE); + + msg = gst_bus_timed_pop_filtered (bus, GST_SECOND * 10, GST_MESSAGE_EOS | + GST_MESSAGE_ERROR); + fail_if (!msg); + fail_if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR); + + gst_message_unref (msg); + gst_object_unref (bus); + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (pipeline); +} + +static void +generate_jif_file_with_tags (const gchar * tags, const gchar * filepath) +{ + GstTagList *taglist; + + taglist = gst_tag_list_new_from_string (tags); + generate_jif_file_with_tags_from_taglist (taglist, filepath); + + gst_tag_list_free (taglist); +} + +static void +libexif_check_tags_from_taglist (GstTagList * taglist, const gchar * filepath) +{ + ExifData *exif_data; + gint i; + + fail_unless (taglist != NULL); + exif_data = exif_data_new_from_file (filepath); + + /* iterate over our tag mapping */ + for (i = 0; i < G_N_ELEMENTS (tag_map); i++) { + if (gst_structure_has_field ((GstStructure *) taglist, tag_map[i].gst_tag)) { + /* we have added this field to the taglist, check if it was writen in + * exif */ + libexif_check_tag_exists (taglist, i, exif_data); + } + } + + exif_data_unref (exif_data); +} + +static void +libexif_check_tags (const gchar * tags, const gchar * filepath) +{ + GstTagList *taglist; + + taglist = gst_tag_list_new_from_string (tags); + fail_unless (taglist != NULL); + + libexif_check_tags_from_taglist (taglist, filepath); + + gst_tag_list_free (taglist); +} + +GST_START_TEST (test_jifmux_tags) +{ + gchar *tmpfile; + gchar *tmp; + GstTagList *taglist; + GstDateTime *datetime; + GstBuffer *buffer; + GstMapInfo map; + gint i; + + gst_tag_register_musicbrainz_tags (); + + tmp = g_strdup_printf ("%s%d", "gst-check-xmp-test-", g_random_int ()); + tmpfile = g_build_filename (g_get_tmp_dir (), tmp, NULL); + g_free (tmp); + + datetime = gst_date_time_new_local_time (2000, 10, 5, 8, 45, 13); + buffer = gst_buffer_new_and_alloc (100); + gst_buffer_map (buffer, &map, GST_MAP_WRITE); + for (i = 0; i < 100; i++) { + map.data[i] = i; + } + gst_buffer_unmap (buffer, &map); + + taglist = gst_tag_list_new (GST_TAG_ARTIST, "some artist", + GST_TAG_COPYRIGHT, "My copyright notice", + GST_TAG_DEVICE_MANUFACTURER, "MyFavoriteBrand", + GST_TAG_DEVICE_MODEL, "123v42.1", + GST_TAG_DESCRIPTION, "some description", + GST_TAG_APPLICATION_NAME, "jifmux-test v1.2b", + GST_TAG_CAPTURING_SHUTTER_SPEED, 1, 30, + GST_TAG_CAPTURING_FOCAL_RATIO, 2.0, + GST_TAG_CAPTURING_ISO_SPEED, 800, GST_TAG_DATE_TIME, datetime, + GST_TAG_CAPTURING_FOCAL_LENGTH, 22.5, + GST_TAG_CAPTURING_DIGITAL_ZOOM_RATIO, 5.25, + GST_TAG_CAPTURING_EXPOSURE_COMPENSATION, -2.5, + GST_TAG_APPLICATION_DATA, buffer, + GST_TAG_CAPTURING_FLASH_FIRED, TRUE, + GST_TAG_CAPTURING_FLASH_MODE, "auto", + GST_TAG_CAPTURING_SOURCE, "dsc", + GST_TAG_CAPTURING_METERING_MODE, "multi-spot", + GST_TAG_CAPTURING_SHARPNESS, "normal", + GST_TAG_CAPTURING_SATURATION, "normal", + GST_TAG_CAPTURING_CONTRAST, "normal", + GST_TAG_GEO_LOCATION_LATITUDE, -32.375, + GST_TAG_GEO_LOCATION_LONGITUDE, 76.0125, + GST_TAG_GEO_LOCATION_ELEVATION, 300.85, + GST_TAG_GEO_LOCATION_MOVEMENT_SPEED, 3.6, + GST_TAG_GEO_LOCATION_MOVEMENT_DIRECTION, 35.4, + GST_TAG_GEO_LOCATION_CAPTURE_DIRECTION, 12.345, + GST_TAG_IMAGE_HORIZONTAL_PPI, 300.0, + GST_TAG_IMAGE_VERTICAL_PPI, 96.0, NULL); + gst_date_time_unref (datetime); + gst_buffer_unref (buffer); + generate_jif_file_with_tags_from_taglist (taglist, tmpfile); + libexif_check_tags_from_taglist (taglist, tmpfile); + gst_tag_list_free (taglist); + +#define IMAGE_ORIENTATION_TAG(t) "taglist," GST_TAG_IMAGE_ORIENTATION "=" t + generate_jif_file_with_tags (IMAGE_ORIENTATION_TAG ("rotate-0"), tmpfile); + libexif_check_tags (IMAGE_ORIENTATION_TAG ("rotate-0"), tmpfile); + generate_jif_file_with_tags (IMAGE_ORIENTATION_TAG ("flip-rotate-0"), + tmpfile); + libexif_check_tags (IMAGE_ORIENTATION_TAG ("flip-rotate-0"), tmpfile); + generate_jif_file_with_tags (IMAGE_ORIENTATION_TAG ("rotate-180"), tmpfile); + libexif_check_tags (IMAGE_ORIENTATION_TAG ("rotate-180"), tmpfile); + generate_jif_file_with_tags (IMAGE_ORIENTATION_TAG ("flip-rotate-180"), + tmpfile); + libexif_check_tags (IMAGE_ORIENTATION_TAG ("flip-rotate-180"), tmpfile); + generate_jif_file_with_tags (IMAGE_ORIENTATION_TAG + ("flip-rotate-270"), tmpfile); + libexif_check_tags (IMAGE_ORIENTATION_TAG ("flip-rotate-270"), tmpfile); + generate_jif_file_with_tags (IMAGE_ORIENTATION_TAG ("rotate-90"), tmpfile); + libexif_check_tags (IMAGE_ORIENTATION_TAG ("rotate-90"), tmpfile); + generate_jif_file_with_tags (IMAGE_ORIENTATION_TAG + ("flip-rotate-90"), tmpfile); + libexif_check_tags (IMAGE_ORIENTATION_TAG ("flip-rotate-90"), tmpfile); + generate_jif_file_with_tags (IMAGE_ORIENTATION_TAG ("rotate-270"), tmpfile); + libexif_check_tags (IMAGE_ORIENTATION_TAG ("rotate-270"), tmpfile); + +#define EXPOSURE_PROGRAM_TAG(t) "taglist," GST_TAG_CAPTURING_EXPOSURE_PROGRAM \ + "=" t + generate_jif_file_with_tags (EXPOSURE_PROGRAM_TAG ("undefined"), tmpfile); + libexif_check_tags (EXPOSURE_PROGRAM_TAG ("undefined"), tmpfile); + generate_jif_file_with_tags (EXPOSURE_PROGRAM_TAG ("manual"), tmpfile); + libexif_check_tags (EXPOSURE_PROGRAM_TAG ("manual"), tmpfile); + generate_jif_file_with_tags (EXPOSURE_PROGRAM_TAG ("normal"), tmpfile); + libexif_check_tags (EXPOSURE_PROGRAM_TAG ("normal"), tmpfile); + generate_jif_file_with_tags (EXPOSURE_PROGRAM_TAG ("aperture-priority"), + tmpfile); + libexif_check_tags (EXPOSURE_PROGRAM_TAG ("aperture-priority"), tmpfile); + generate_jif_file_with_tags (EXPOSURE_PROGRAM_TAG ("shutter-priority"), + tmpfile); + libexif_check_tags (EXPOSURE_PROGRAM_TAG ("shutter-priority"), tmpfile); + generate_jif_file_with_tags (EXPOSURE_PROGRAM_TAG ("creative"), tmpfile); + libexif_check_tags (EXPOSURE_PROGRAM_TAG ("creative"), tmpfile); + generate_jif_file_with_tags (EXPOSURE_PROGRAM_TAG ("action"), tmpfile); + libexif_check_tags (EXPOSURE_PROGRAM_TAG ("action"), tmpfile); + generate_jif_file_with_tags (EXPOSURE_PROGRAM_TAG ("portrait"), tmpfile); + libexif_check_tags (EXPOSURE_PROGRAM_TAG ("portrait"), tmpfile); + generate_jif_file_with_tags (EXPOSURE_PROGRAM_TAG ("landscape"), tmpfile); + libexif_check_tags (EXPOSURE_PROGRAM_TAG ("landscape"), tmpfile); + +#define EXPOSURE_MODE_TAG(t) "taglist," GST_TAG_CAPTURING_EXPOSURE_MODE "=" t + generate_jif_file_with_tags (EXPOSURE_MODE_TAG ("auto-exposure"), tmpfile); + libexif_check_tags (EXPOSURE_MODE_TAG ("auto-exposure"), tmpfile); + generate_jif_file_with_tags (EXPOSURE_MODE_TAG ("manual-exposure"), tmpfile); + libexif_check_tags (EXPOSURE_MODE_TAG ("manual-exposure"), tmpfile); + generate_jif_file_with_tags (EXPOSURE_MODE_TAG ("auto-bracket"), tmpfile); + libexif_check_tags (EXPOSURE_MODE_TAG ("auto-bracket"), tmpfile); + +#define SCENE_CAPTURE_TYPE_TAG(t) "taglist," GST_TAG_CAPTURING_SCENE_CAPTURE_TYPE\ + "=" t + generate_jif_file_with_tags (SCENE_CAPTURE_TYPE_TAG ("standard"), tmpfile); + libexif_check_tags (SCENE_CAPTURE_TYPE_TAG ("standard"), tmpfile); + generate_jif_file_with_tags (SCENE_CAPTURE_TYPE_TAG ("landscape"), tmpfile); + libexif_check_tags (SCENE_CAPTURE_TYPE_TAG ("landscape"), tmpfile); + generate_jif_file_with_tags (SCENE_CAPTURE_TYPE_TAG ("portrait"), tmpfile); + libexif_check_tags (SCENE_CAPTURE_TYPE_TAG ("portrait"), tmpfile); + generate_jif_file_with_tags (SCENE_CAPTURE_TYPE_TAG ("night-scene"), tmpfile); + libexif_check_tags (SCENE_CAPTURE_TYPE_TAG ("night-scene"), tmpfile); + +#define WHITE_BALANCE_TAG(t) "taglist," GST_TAG_CAPTURING_WHITE_BALANCE "=" t + generate_jif_file_with_tags (WHITE_BALANCE_TAG ("auto"), tmpfile); + libexif_check_tags (WHITE_BALANCE_TAG ("auto"), tmpfile); + generate_jif_file_with_tags (WHITE_BALANCE_TAG ("manual"), tmpfile); + libexif_check_tags (WHITE_BALANCE_TAG ("manual"), tmpfile); + +#define GAIN_ADJUSTMENT_TAG(t) "taglist," GST_TAG_CAPTURING_GAIN_ADJUSTMENT "=" t + generate_jif_file_with_tags (GAIN_ADJUSTMENT_TAG ("none"), tmpfile); + libexif_check_tags (GAIN_ADJUSTMENT_TAG ("none"), tmpfile); + generate_jif_file_with_tags (GAIN_ADJUSTMENT_TAG ("high-gain-up"), tmpfile); + libexif_check_tags (GAIN_ADJUSTMENT_TAG ("high-gain-up"), tmpfile); + generate_jif_file_with_tags (GAIN_ADJUSTMENT_TAG ("low-gain-up"), tmpfile); + libexif_check_tags (GAIN_ADJUSTMENT_TAG ("low-gain-up"), tmpfile); + generate_jif_file_with_tags (GAIN_ADJUSTMENT_TAG ("high-gain-down"), tmpfile); + libexif_check_tags (GAIN_ADJUSTMENT_TAG ("high-gain-down"), tmpfile); + generate_jif_file_with_tags (GAIN_ADJUSTMENT_TAG ("low-gain-down"), tmpfile); + libexif_check_tags (GAIN_ADJUSTMENT_TAG ("low-gain-down"), tmpfile); + +#define CONTRAST_TAG(t) "taglist," GST_TAG_CAPTURING_CONTRAST "=" t + generate_jif_file_with_tags (CONTRAST_TAG ("normal"), tmpfile); + libexif_check_tags (CONTRAST_TAG ("normal"), tmpfile); + generate_jif_file_with_tags (CONTRAST_TAG ("soft"), tmpfile); + libexif_check_tags (CONTRAST_TAG ("soft"), tmpfile); + generate_jif_file_with_tags (CONTRAST_TAG ("hard"), tmpfile); + libexif_check_tags (CONTRAST_TAG ("hard"), tmpfile); + +#define SATURATION_TAG(t) "taglist," GST_TAG_CAPTURING_SATURATION "=" t + generate_jif_file_with_tags (SATURATION_TAG ("normal"), tmpfile); + libexif_check_tags (SATURATION_TAG ("normal"), tmpfile); + generate_jif_file_with_tags (SATURATION_TAG ("low-saturation"), tmpfile); + libexif_check_tags (SATURATION_TAG ("low-saturation"), tmpfile); + generate_jif_file_with_tags (SATURATION_TAG ("high-saturation"), tmpfile); + libexif_check_tags (SATURATION_TAG ("high-saturation"), tmpfile); + +#define SHARPNESS_TAG(t) "taglist," GST_TAG_CAPTURING_SHARPNESS "=" t + generate_jif_file_with_tags (SHARPNESS_TAG ("normal"), tmpfile); + libexif_check_tags (SHARPNESS_TAG ("normal"), tmpfile); + generate_jif_file_with_tags (SHARPNESS_TAG ("soft"), tmpfile); + libexif_check_tags (SHARPNESS_TAG ("soft"), tmpfile); + generate_jif_file_with_tags (SHARPNESS_TAG ("hard"), tmpfile); + libexif_check_tags (SHARPNESS_TAG ("hard"), tmpfile); + +#define METERING_MODE_TAG(t) "taglist," GST_TAG_CAPTURING_METERING_MODE "=" t + generate_jif_file_with_tags (METERING_MODE_TAG ("unknown"), tmpfile); + libexif_check_tags (METERING_MODE_TAG ("unknown"), tmpfile); + generate_jif_file_with_tags (METERING_MODE_TAG ("average"), tmpfile); + libexif_check_tags (METERING_MODE_TAG ("average"), tmpfile); + generate_jif_file_with_tags (METERING_MODE_TAG ("center-weighted-average"), + tmpfile); + libexif_check_tags (METERING_MODE_TAG ("center-weighted-average"), tmpfile); + generate_jif_file_with_tags (METERING_MODE_TAG ("spot"), tmpfile); + libexif_check_tags (METERING_MODE_TAG ("spot"), tmpfile); + generate_jif_file_with_tags (METERING_MODE_TAG ("multi-spot"), tmpfile); + libexif_check_tags (METERING_MODE_TAG ("multi-spot"), tmpfile); + generate_jif_file_with_tags (METERING_MODE_TAG ("pattern"), tmpfile); + libexif_check_tags (METERING_MODE_TAG ("pattern"), tmpfile); + generate_jif_file_with_tags (METERING_MODE_TAG ("partial"), tmpfile); + libexif_check_tags (METERING_MODE_TAG ("partial"), tmpfile); + generate_jif_file_with_tags (METERING_MODE_TAG ("other"), tmpfile); + libexif_check_tags (METERING_MODE_TAG ("other"), tmpfile); + +#define FILE_SOURCE_TAG(t) "taglist," GST_TAG_CAPTURING_SOURCE "=" t + generate_jif_file_with_tags (FILE_SOURCE_TAG ("dsc"), tmpfile); + libexif_check_tags (FILE_SOURCE_TAG ("dsc"), tmpfile); + generate_jif_file_with_tags (FILE_SOURCE_TAG ("other"), tmpfile); + libexif_check_tags (FILE_SOURCE_TAG ("other"), tmpfile); + generate_jif_file_with_tags (FILE_SOURCE_TAG ("reflex-scanner"), tmpfile); + libexif_check_tags (FILE_SOURCE_TAG ("reflex-scanner"), tmpfile); + generate_jif_file_with_tags (FILE_SOURCE_TAG ("transparent-scanner"), + tmpfile); + libexif_check_tags (FILE_SOURCE_TAG ("transparent-scanner"), tmpfile); + + g_unlink (tmpfile); + g_free (tmpfile); +} + +GST_END_TEST; + +#define HAVE_ELEMENT(name) \ + gst_registry_check_feature_version (gst_registry_get (), name,\ + GST_VERSION_MAJOR, GST_VERSION_MINOR, 0) + +static Suite * +jifmux_suite (void) +{ + Suite *s = suite_create ("jifmux"); + TCase *tc_chain = tcase_create ("general"); + + if (HAVE_ELEMENT ("taginject") && HAVE_ELEMENT ("jpegenc")) { + tcase_add_test (tc_chain, test_jifmux_tags); + } else { + GST_WARNING ("jpegenc or taginject element not available, skipping tests"); + } + + suite_add_tcase (s, tc_chain); + + return s; +} + +GST_CHECK_MAIN (jifmux); diff --git a/tests/check/elements/jpegparse.c b/tests/check/elements/jpegparse.c new file mode 100644 index 00000000..fa8c63ac --- /dev/null +++ b/tests/check/elements/jpegparse.c @@ -0,0 +1,402 @@ +/* GStreamer + * + * unit test for jpegparse + * + * Copyright (C) <2009> Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser 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. + */ + +#include <unistd.h> + +#include <gst/check/gstcheck.h> + +/* This test doesn't use actual JPEG data, but some fake data that we know + will trigger certain paths in jpegparse. */ + +guint8 test_data_garbage[] = { 0x00, 0x01, 0xff, 0x32, 0x00, 0xff }; +guint8 test_data_short_frame[] = { 0xff, 0xd8, 0xff, 0xd9 }; + +guint8 test_data_normal_frame[] = { 0xff, 0xd8, 0xff, 0x12, 0x00, 0x03, 0x33, + 0xff, 0xd9 +}; + +guint8 test_data_entropy[] = { 0xff, 0xd8, 0xff, 0xda, 0x00, 0x04, 0x22, 0x33, + 0x44, 0xff, 0x00, 0x55, 0xff, 0x04, 0x00, 0x04, 0x22, 0x33, 0xff, 0xd9 +}; +guint8 test_data_ff[] = { 0xff, 0xff }; + +guint8 test_data_extra_ff[] = { 0xff, 0xd8, 0xff, 0xff, 0xff, 0x12, 0x00, 0x03, + 0x33, 0xff, 0xff, 0xff, 0xd9 +}; + +guint8 test_data_soi[] = { 0xff, 0xd8 }; + +guint8 test_data_app1_exif[] = { + 0xff, 0xe1, + 0x00, 0xd2, /* length = 210 */ + 0x45, 0x78, 0x69, 0x66, 0x00, /* Exif */ + 0x00, + 0x49, 0x49, + 0x2a, 0x00, + 0x08, + 0x00, 0x00, 0x00, + 0x09, /* number of entries */ + 0x00, + 0x0e, 0x01, /* tag 0x10e */ + 0x02, 0x00, /* type 2 */ + 0x0b, 0x00, /* count 11 */ + 0x00, 0x00, + 0x7a, /* offset 122 (0x7a) */ + 0x00, 0x00, 0x00, + 0x0f, 0x01, /* tag 0x10f */ + 0x02, 0x00, /* type 2 */ + 0x06, 0x00, /* count 6 */ + 0x00, 0x00, + 0x85, /* offset 133 (0x85) */ + 0x00, 0x00, 0x00, + 0x10, 0x01, /* tag 0x110 */ + 0x02, 0x00, /* type 2 */ + 0x05, 0x00, /* count 5 */ + 0x00, 0x00, + 0x8b, /* offset 139 (0x8b) */ + 0x00, 0x00, 0x00, + 0x12, 0x01, /* tag 0x112 */ + 0x03, 0x00, /* type 3 */ + 0x01, 0x00, /* count 1 */ + 0x00, 0x00, + 0x01, 0x00, 0x30, 0x2c, /* offset (0x2c300001) */ + 0x1a, 0x01, /* tag 0x11a */ + 0x05, 0x00, /* type 5 */ + 0x01, 0x00, /* count 1 */ + 0x00, 0x00, + 0x90, /* offset 144 (0x90) */ + 0x00, 0x00, 0x00, + 0x1b, 0x01, /* tag 0x11b */ + 0x05, 0x00, /* type 5 */ + 0x01, 0x00, /* count 1 */ + 0x00, 0x00, + 0x98, /* offset 152 (0x98) */ + 0x00, 0x00, 0x00, + 0x28, 0x01, /* tag 0x128 */ + 0x03, 0x00, /* type 3 */ + 0x01, 0x00, /* count 1 */ + 0x00, 0x00, + 0x02, 0x00, 0x31, 0x2f, /* offset (0x2f310002) */ + 0x31, 0x01, /* tag 0x131 */ + 0x02, 0x00, /* type 2 */ + 0x08, 0x00, /* count 8 */ + 0x00, 0x00, + 0xa0, /* offset 160 (0xa0) */ + 0x00, 0x00, 0x00, + 0x32, 0x01, /* tag 0x132 */ + 0x02, 0x00, /* type 2 */ + 0x14, 0x00, /* count 20 */ + 0x00, 0x00, + 0xa8, /* offset 168 (0xa8) */ + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, + /* string */ + /* 122: */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, + /* string (NIKON) */ + /* 133: */ 0x4e, 0x49, 0x4b, 0x4f, 0x4e, 0x00, + /* string (E800) */ + /* 139: */ 0x45, 0x38, 0x30, 0x30, 0x00, + /* 144: */ 0x00, 0x00, 0x80, 0x25, /* / */ 0x00, 0x00, 0x20, 0x00, + /* 152: */ 0x00, 0x00, 0x80, 0x25, /* / */ 0x00, 0x00, 0x20, 0x00, + /* string (v984-75) */ + /* 160: */ 0x76, 0x39, 0x38, 0x34, 0x2d, 0x37, 0x35, 0x00, + /* string (2001:08:18 21:44:21) */ + /* 168: */ 0x32, 0x30, 0x30, 0x31, 0x3a, 0x30, 0x38, 0x3a, + 0x31, 0x38, 0x20, 0x32, 0x31, 0x3a, 0x34, 0x34, + 0x3a, 0x32, 0x31, 0x00, + + 0x1e, 0x21, 0x1f, 0x1e, 0x21, 0x1c, 0x20, 0x21, 0x22, 0x24, 0x24, 0x27, + 0x22, 0x20, +}; + +guint8 test_data_comment[] = { + 0xff, 0xfe, + 0x00, 0x08, /* size */ + /* xxxxx */ + 0x78, 0x78, 0x78, 0x78, 0x78, 0x00, +}; + +guint8 test_data_sof0[] = { + 0xff, 0xc0, + 0x00, 0x11, /* size */ + 0x08, /* precision */ + 0x00, 0x3c, /* width */ + 0x00, 0x50, /* height */ + 0x03, /* number of components */ + 0x01, 0x22, 0x00, /* component 1 */ + 0x02, 0x11, 0x01, /* component 2 */ + 0x03, 0x11, 0x01, /* component 3 */ +}; + +guint8 test_data_eoi[] = { 0xff, 0xd9 }; + +static GList * +_make_buffers_in (GList * buffer_in, guint8 * test_data, gsize test_data_size) +{ + GstBuffer *buffer; + gsize i; + + for (i = 0; i < test_data_size; i++) { + buffer = + gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, test_data + i, 1, + 0, 1, NULL, NULL); + buffer_in = g_list_append (buffer_in, buffer); + } + return buffer_in; +} + +#define make_buffers_in(buffer_in, test_data) \ + _make_buffers_in(buffer_in, test_data, sizeof(test_data)) + +static GList * +_make_buffers_out (GList * buffer_out, guint8 * test_data, gsize test_data_size) +{ + GstBuffer *buffer; + + buffer = + gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, test_data, + test_data_size, 0, test_data_size, NULL, NULL); + buffer_out = g_list_append (buffer_out, buffer); + + return buffer_out; +} + +#define make_buffers_out(buffer_out, test_data) \ + _make_buffers_out(buffer_out, test_data, sizeof(test_data)) + +GST_START_TEST (test_parse_single_byte) +{ + GList *buffer_in = NULL, *buffer_out = NULL; + GstCaps *caps_in, *caps_out; + + caps_in = gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, FALSE, + NULL); + caps_out = gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE, + "framerate", GST_TYPE_FRACTION, 1, 1, NULL); + + /* Push the data byte by byte, injecting some garbage. */ + buffer_in = make_buffers_in (buffer_in, test_data_garbage); + buffer_in = make_buffers_in (buffer_in, test_data_short_frame); + buffer_in = make_buffers_in (buffer_in, test_data_garbage); + buffer_in = make_buffers_in (buffer_in, test_data_normal_frame); + buffer_in = make_buffers_in (buffer_in, test_data_ff); + buffer_in = make_buffers_in (buffer_in, test_data_entropy); + buffer_in = make_buffers_in (buffer_in, test_data_extra_ff); + + buffer_out = make_buffers_out (buffer_out, test_data_short_frame); + buffer_out = make_buffers_out (buffer_out, test_data_normal_frame); + buffer_out = make_buffers_out (buffer_out, test_data_entropy); + buffer_out = make_buffers_out (buffer_out, test_data_extra_ff); + gst_check_element_push_buffer_list ("jpegparse", buffer_in, caps_in, + buffer_out, caps_out, GST_FLOW_OK); + + gst_caps_unref (caps_in); + gst_caps_unref (caps_out); +} + +GST_END_TEST; + + + +GST_START_TEST (test_parse_all_in_one_buf) +{ + GList *buffer_in = NULL, *buffer_out = NULL; + GstBuffer *buffer = NULL; + gsize total_size = 0; + gsize offset = 0; + GstCaps *caps_in, *caps_out; + + /* Push the data in a single buffer, injecting some garbage. */ + total_size += sizeof (test_data_garbage); + total_size += sizeof (test_data_short_frame); + total_size += sizeof (test_data_garbage); + total_size += sizeof (test_data_normal_frame); + total_size += sizeof (test_data_ff); + total_size += sizeof (test_data_entropy); + total_size += sizeof (test_data_extra_ff); + buffer = gst_buffer_new_and_alloc (total_size); + gst_buffer_fill (buffer, offset, test_data_garbage, + sizeof (test_data_garbage)); + offset += sizeof (test_data_garbage); + gst_buffer_fill (buffer, offset, test_data_short_frame, + sizeof (test_data_short_frame)); + offset += sizeof (test_data_short_frame); + gst_buffer_fill (buffer, offset, test_data_garbage, + sizeof (test_data_garbage)); + offset += sizeof (test_data_garbage); + gst_buffer_fill (buffer, offset, test_data_normal_frame, + sizeof (test_data_normal_frame)); + offset += sizeof (test_data_normal_frame); + gst_buffer_fill (buffer, offset, test_data_ff, sizeof (test_data_ff)); + offset += sizeof (test_data_ff); + gst_buffer_fill (buffer, offset, test_data_entropy, + sizeof (test_data_entropy)); + offset += sizeof (test_data_entropy); + gst_buffer_fill (buffer, offset, test_data_extra_ff, + sizeof (test_data_extra_ff)); + offset += sizeof (test_data_extra_ff); + + caps_in = gst_caps_new_simple ("image/jpeg", "parsed", + G_TYPE_BOOLEAN, FALSE, NULL); + GST_LOG ("Pushing single buffer of %u bytes.", (guint) total_size); + buffer_in = g_list_append (buffer_in, buffer); + + caps_out = gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE, + "framerate", GST_TYPE_FRACTION, 1, 1, NULL); + buffer_out = make_buffers_out (buffer_out, test_data_short_frame); + buffer_out = make_buffers_out (buffer_out, test_data_normal_frame); + buffer_out = make_buffers_out (buffer_out, test_data_entropy); + buffer_out = make_buffers_out (buffer_out, test_data_extra_ff); + + gst_check_element_push_buffer_list ("jpegparse", buffer_in, caps_in, + buffer_out, caps_out, GST_FLOW_OK); + + gst_caps_unref (caps_in); + gst_caps_unref (caps_out); +} + +GST_END_TEST; + +static inline GstBuffer * +make_my_input_buffer (guint8 * test_data_header, gsize test_data_size) +{ + GstBuffer *buffer; + gsize total_size = 0, offset = 0; + + total_size += sizeof (test_data_soi); + total_size += test_data_size; + total_size += sizeof (test_data_sof0); + total_size += sizeof (test_data_eoi); + + buffer = gst_buffer_new_and_alloc (total_size); + + gst_buffer_fill (buffer, offset, test_data_soi, sizeof (test_data_soi)); + offset += sizeof (test_data_soi); + gst_buffer_fill (buffer, offset, test_data_header, test_data_size); + offset += test_data_size; + gst_buffer_fill (buffer, offset, test_data_sof0, sizeof (test_data_sof0)); + offset += sizeof (test_data_sof0); + gst_buffer_fill (buffer, offset, test_data_eoi, sizeof (test_data_eoi)); + offset += sizeof (test_data_eoi); + + return buffer; +} + +static inline GstBuffer * +make_my_output_buffer (GstBuffer * buffer_in) +{ + GstBuffer *buffer; + GstMapInfo map; + + buffer = gst_buffer_new (); + gst_buffer_map (buffer_in, &map, GST_MAP_READ); + gst_buffer_fill (buffer, 0, map.data, map.size); + gst_buffer_unmap (buffer_in, &map); + + return buffer; +} + + +GST_START_TEST (test_parse_app1_exif) +{ + GstBuffer *buffer_in, *buffer_out; + GstCaps *caps_in, *caps_out; + + caps_in = gst_caps_new_simple ("image/jpeg", "parsed", + G_TYPE_BOOLEAN, FALSE, NULL); + + caps_out = gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE, + "framerate", GST_TYPE_FRACTION, 1, 1, "format", G_TYPE_STRING, + "I420", "interlaced", G_TYPE_BOOLEAN, FALSE, + "width", G_TYPE_INT, 80, "height", G_TYPE_INT, 60, NULL); + + buffer_in = make_my_input_buffer (test_data_app1_exif, + sizeof (test_data_app1_exif)); + buffer_out = make_my_output_buffer (buffer_in); + + gst_check_element_push_buffer ("jpegparse", buffer_in, caps_in, buffer_out, + caps_out); + + gst_caps_unref (caps_in); + gst_caps_unref (caps_out); +} + +GST_END_TEST; + +GST_START_TEST (test_parse_comment) +{ + GstBuffer *buffer_in, *buffer_out; + GstCaps *caps_in, *caps_out; + + caps_in = gst_caps_new_simple ("image/jpeg", "parsed", + G_TYPE_BOOLEAN, FALSE, NULL); + + caps_out = gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE, + "framerate", GST_TYPE_FRACTION, 1, 1, "format", G_TYPE_STRING, + "I420", "interlaced", G_TYPE_BOOLEAN, FALSE, + "width", G_TYPE_INT, 80, "height", G_TYPE_INT, 60, NULL); + + buffer_in = make_my_input_buffer (test_data_comment, + sizeof (test_data_comment)); + buffer_out = make_my_output_buffer (buffer_in); + + gst_check_element_push_buffer ("jpegparse", buffer_in, caps_in, buffer_out, + caps_out); + + gst_caps_unref (caps_in); + gst_caps_unref (caps_out); +} + +GST_END_TEST; + +static Suite * +jpegparse_suite (void) +{ + Suite *s = suite_create ("jpegparse"); + TCase *tc_chain = tcase_create ("jpegparse"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_parse_single_byte); + tcase_add_test (tc_chain, test_parse_all_in_one_buf); + tcase_add_test (tc_chain, test_parse_app1_exif); + tcase_add_test (tc_chain, test_parse_comment); + + return s; +} + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = jpegparse_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; +} diff --git a/tests/check/elements/kate.c b/tests/check/elements/kate.c new file mode 100644 index 00000000..d1d9218b --- /dev/null +++ b/tests/check/elements/kate.c @@ -0,0 +1,858 @@ +/* GStreamer + * + * unit test for kate + * + * Copyright (C) <2007> Stefan Kost <ensonic@users.sf.net> + * Copyright (C) <2008> ogg.k.ogg.k <ogg.k.ogg.k@googlemail.com> + * + * 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. + */ + +#include <unistd.h> + +#include <gst/check/gstcheck.h> +#include <gst/base/gsttypefindhelper.h> + + +static const guint8 kate_header_0x80[64] = { + 0x80, 0x6b, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x09, 0x00, 0x00, 0x00, 0x20, /* .kate...... ... */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* ................ */ + 0x65, 0x6e, 0x5f, 0x47, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* en_GB........... */ + 0x6e, 0x6f, 0x6e, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* none............ */ +}; + +static const guint8 kate_header_0x81[53] = { + 0x81, 0x6b, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x6c, 0x69, 0x62, /* .kate........lib */ + 0x6b, 0x61, 0x74, 0x65, 0x20, 0x30, 0x2e, 0x31, 0x2e, 0x30, 0x20, 0x28, 0x54, 0x69, 0x67, 0x65, /* kate 0.1.0 (Tige */ + 0x72, 0x29, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x54, 0x49, 0x54, 0x4c, 0x45, 0x3d, /* r)........TITLE= */ + 0x54, 0x69, 0x67, 0x65, 0x72, /* Tiger */ +}; + +static const guint8 kate_header_0x8x[10] = { + 0x80, 0x6b, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, 0x00 +}; + +static const guint8 kate_header_0x88[11] = { + 0x88, 0x6b, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const guint8 kate_header_0x00[45] = { + 0x00, 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, /* ................ */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x70, 0x6c, 0x61, /* .............pla */ + 0x69, 0x6e, 0x20, 0x6f, 0x6c, 0x64, 0x20, 0x74, 0x65, 0x78, 0x74, 0x08, 0x00 /* in old text.. */ +}; + +static const guint8 kate_header_0x01[1] = { + 0x01 +}; + +static const guint8 kate_header_0x7f[1] = { + 0x7f +}; + +static const unsigned char kate_spu[] = { + 0x00, 0x1b, /* size */ + 0x00, 0x06, /* commands at offset 6 */ + 0x45, /* first line data - 2 pixels of colors 0 and 1 */ + 0x76, /* first line data - 2 pixels of colors 3 and 2 */ + 0x00, 0x00, /* timestamp */ + 0x00, 0x06, /* link to next command sequence - points back to the current one to mark no more */ + 0x06, 0x00, 0x04, 0x00, 0x05, /* pointers to data */ + 0x05, 0x00, 0x30, 0x04, 0x00, 0x10, 0x02, /* area: 3x1 -> 4x2 */ + 0x04, 0x0f, 0xff, /* alpha: color 0 transparent, all others opaque */ + 0x01, /* show */ + 0xff /* end */ +}; + +/* A lot of these taken from the vorbisdec test */ + +/* For ease of programming we use globals to keep refs for our floating + * src and sink pads we create; otherwise we always have to do get_pad, + * get_peer, and then remove references in every test function */ +static GstPad *mydecsrcpad, *mydecsinkpad; +static GstPad *myencsrcpad, *myencsinkpad; +static GstPad *myparsesrcpad, *myparsesinkpad; +static GstPad *mytagsrcpad, *mytagsinkpad; + +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +static GstElement * +setup_katedec (void) +{ + GstElement *katedec; + + GST_DEBUG ("setup_katedec"); + katedec = gst_check_setup_element ("katedec"); + mydecsrcpad = gst_check_setup_src_pad (katedec, &srctemplate, NULL); + mydecsinkpad = gst_check_setup_sink_pad (katedec, &sinktemplate, NULL); + gst_pad_set_active (mydecsrcpad, TRUE); + gst_pad_set_active (mydecsinkpad, TRUE); + + return katedec; +} + +static void +cleanup_katedec (GstElement * katedec) +{ + GST_DEBUG ("cleanup_katedec"); + gst_element_set_state (katedec, GST_STATE_NULL); + + gst_pad_set_active (mydecsrcpad, FALSE); + gst_pad_set_active (mydecsinkpad, FALSE); + gst_check_teardown_src_pad (katedec); + gst_check_teardown_sink_pad (katedec); + gst_check_teardown_element (katedec); +} + +static GstElement * +setup_kateenc (void) +{ + GstElement *kateenc; + + GST_DEBUG ("setup_kateenc"); + kateenc = gst_check_setup_element ("kateenc"); + myencsrcpad = gst_check_setup_src_pad (kateenc, &srctemplate, NULL); + myencsinkpad = gst_check_setup_sink_pad (kateenc, &sinktemplate, NULL); + gst_pad_set_active (myencsrcpad, TRUE); + gst_pad_set_active (myencsinkpad, TRUE); + + return kateenc; +} + +static void +cleanup_kateenc (GstElement * kateenc) +{ + GST_DEBUG ("cleanup_kateenc"); + gst_element_set_state (kateenc, GST_STATE_NULL); + + gst_pad_set_active (myencsrcpad, FALSE); + gst_pad_set_active (myencsinkpad, FALSE); + gst_check_teardown_src_pad (kateenc); + gst_check_teardown_sink_pad (kateenc); + gst_check_teardown_element (kateenc); +} + +static GstElement * +setup_kateparse (void) +{ + GstElement *kateparse; + + GST_DEBUG ("setup_kateparse"); + kateparse = gst_check_setup_element ("kateparse"); + myparsesrcpad = gst_check_setup_src_pad (kateparse, &srctemplate, NULL); + myparsesinkpad = gst_check_setup_sink_pad (kateparse, &sinktemplate, NULL); + gst_pad_set_active (myparsesrcpad, TRUE); + gst_pad_set_active (myparsesinkpad, TRUE); + + return kateparse; +} + +static void +cleanup_kateparse (GstElement * kateparse) +{ + GST_DEBUG ("cleanup_kateparse"); + gst_element_set_state (kateparse, GST_STATE_NULL); + + gst_pad_set_active (myparsesrcpad, FALSE); + gst_pad_set_active (myparsesinkpad, FALSE); + gst_check_teardown_src_pad (kateparse); + gst_check_teardown_sink_pad (kateparse); + gst_check_teardown_element (kateparse); +} + +static GstElement * +setup_katetag (void) +{ + GstElement *katetag; + + GST_DEBUG ("setup_katetag"); + katetag = gst_check_setup_element ("katetag"); + mytagsrcpad = gst_check_setup_src_pad (katetag, &srctemplate, NULL); + mytagsinkpad = gst_check_setup_sink_pad (katetag, &sinktemplate, NULL); + gst_pad_set_active (mytagsrcpad, TRUE); + gst_pad_set_active (mytagsinkpad, TRUE); + + return katetag; +} + +static void +cleanup_katetag (GstElement * katetag) +{ + GST_DEBUG ("cleanup_katetag"); + gst_element_set_state (katetag, GST_STATE_NULL); + + gst_pad_set_active (mytagsrcpad, FALSE); + gst_pad_set_active (mytagsinkpad, FALSE); + gst_check_teardown_src_pad (katetag); + gst_check_teardown_sink_pad (katetag); + gst_check_teardown_element (katetag); +} + +static void +check_buffers (guint expected, gboolean headers_in_caps) +{ + GstBuffer *outbuffer; + guint i, num_buffers; + const int num_headers = 9; + unsigned char packet_type; + + /* check buffers are the type we expect */ + num_buffers = g_list_length (buffers); + fail_unless (num_buffers >= num_headers + expected); /* at least 9 headers, plus a variable number of data packets */ + for (i = 0; i < num_buffers; ++i) { + outbuffer = GST_BUFFER (buffers->data); + fail_if (outbuffer == NULL); + fail_if (GST_BUFFER_SIZE (outbuffer) == 0); + + if (i < num_headers) { + /* different headers packets */ + packet_type = (0x80 | i); + fail_unless (GST_BUFFER_DATA (outbuffer)[0] == packet_type); + /* headers could be in caps, so would have an extra ref */ + } else if (i == num_buffers - 1) { + /* eos data packet */ + packet_type = 0x7f; + fail_unless (GST_BUFFER_DATA (outbuffer)[0] == packet_type); + } else { + /* data packet */ + packet_type = 0; + fail_unless (GST_BUFFER_DATA (outbuffer)[0] >= 0 + && GST_BUFFER_DATA (outbuffer)[0] < 0x7f); + } + + buffers = g_list_remove (buffers, outbuffer); + + ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1); + gst_buffer_unref (outbuffer); + outbuffer = NULL; + } +} + +GST_START_TEST (test_kate_typefind) +{ + GstTypeFindProbability prob; + const gchar *type; + GstBuffer *buf; + GstCaps *caps = NULL; + + buf = gst_buffer_new (); + GST_BUFFER_DATA (buf) = (guint8 *) kate_header_0x80; + GST_BUFFER_SIZE (buf) = sizeof (kate_header_0x80); + GST_BUFFER_OFFSET (buf) = 0; + + caps = gst_type_find_helper_for_buffer (NULL, buf, &prob); + fail_unless (caps != NULL); + GST_LOG ("Found type: %" GST_PTR_FORMAT, caps); + + type = gst_structure_get_name (gst_caps_get_structure (caps, 0)); + fail_unless_equals_string (type, "application/x-kate"); + fail_unless (prob > GST_TYPE_FIND_MINIMUM && prob <= GST_TYPE_FIND_MAXIMUM); + + gst_buffer_unref (buf); + gst_caps_unref (caps); +} + +GST_END_TEST; + +GST_START_TEST (test_kate_empty_identification_header) +{ + GstElement *katedec; + GstBuffer *inbuffer; + GstBus *bus; + + katedec = setup_katedec (); + bus = gst_bus_new (); + + fail_unless (gst_element_set_state (katedec, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (0); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + + /* set a bus here so we avoid getting state change messages */ + gst_element_set_bus (katedec, bus); + + fail_unless_equals_int (gst_pad_push (mydecsrcpad, inbuffer), GST_FLOW_ERROR); + /* ... but it ends up being collected on the global buffer list */ + fail_unless_equals_int (g_list_length (buffers), 0); + + gst_element_set_bus (katedec, NULL); + + /* cleanup */ + gst_object_unref (GST_OBJECT (bus)); + cleanup_katedec (katedec); +} + +GST_END_TEST; + +/* FIXME: also tests comment header */ +GST_START_TEST (test_kate_identification_header) +{ + GstElement *katedec; + GstBuffer *inbuffer; + GstBus *bus; + GstMessage *message; + GstTagList *tag_list; + gchar *language; + gchar *title; + + katedec = setup_katedec (); + fail_unless (gst_element_set_state (katedec, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + bus = gst_bus_new (); + + inbuffer = gst_buffer_new_and_alloc (sizeof (kate_header_0x80)); + memcpy (GST_BUFFER_DATA (inbuffer), kate_header_0x80, + sizeof (kate_header_0x80)); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + gst_buffer_ref (inbuffer); + + gst_element_set_bus (katedec, bus); + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mydecsrcpad, inbuffer) == GST_FLOW_OK); + /* ... and nothing ends up on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + gst_buffer_unref (inbuffer); + fail_unless (g_list_length (buffers) == 0); + + inbuffer = gst_buffer_new_and_alloc (sizeof (kate_header_0x81)); + memcpy (GST_BUFFER_DATA (inbuffer), kate_header_0x81, + sizeof (kate_header_0x81)); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + gst_buffer_ref (inbuffer); + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mydecsrcpad, inbuffer) == GST_FLOW_OK); + /* ... and nothing ends up on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + gst_buffer_unref (inbuffer); + fail_unless (g_list_length (buffers) == 0); + /* there's a tag message waiting */ + fail_if ((message = gst_bus_pop (bus)) == NULL); + gst_message_parse_tag (message, &tag_list); + fail_unless_equals_int (gst_tag_list_get_tag_size (tag_list, + GST_TAG_LANGUAGE_CODE), 1); + fail_unless (gst_tag_list_get_string (tag_list, GST_TAG_LANGUAGE_CODE, + &language)); + fail_unless_equals_string (language, "en"); + g_free (language); + fail_unless_equals_int (gst_tag_list_get_tag_size (tag_list, "title"), 1); + fail_unless (gst_tag_list_get_string (tag_list, GST_TAG_TITLE, &title)); + fail_unless_equals_string (title, "Tiger"); + g_free (title); + gst_tag_list_free (tag_list); + gst_message_unref (message); + + /* cleanup */ + gst_bus_set_flushing (bus, TRUE); + gst_element_set_bus (katedec, NULL); + gst_object_unref (GST_OBJECT (bus)); + cleanup_katedec (katedec); +} + +GST_END_TEST; + +GST_START_TEST (test_kate_encode_nothing) +{ + GstElement *kateenc; + + kateenc = setup_kateenc (); + fail_unless (gst_element_set_state (kateenc, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + fail_unless (gst_pad_push_event (myencsrcpad, gst_event_new_eos ()) == TRUE); + + fail_unless (gst_element_set_state (kateenc, + GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS, + "could not set to ready"); + + /* cleanup */ + cleanup_kateenc (kateenc); +} + +GST_END_TEST; + +GST_START_TEST (test_kate_encode_empty) +{ + GstElement *kateenc; + GstBuffer *inbuffer; + GstBus *bus; + GstCaps *caps; + + kateenc = setup_kateenc (); + fail_unless (gst_element_set_state (kateenc, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + bus = gst_bus_new (); + + inbuffer = gst_buffer_new_and_alloc (0); + GST_BUFFER_TIMESTAMP (inbuffer) = GST_BUFFER_OFFSET (inbuffer) = + 1 * GST_SECOND; + GST_BUFFER_DURATION (inbuffer) = 5 * GST_SECOND; + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + + caps = gst_caps_from_string ("text/plain"); + fail_unless (caps != NULL); + gst_buffer_set_caps (inbuffer, caps); + gst_caps_unref (caps); + + gst_element_set_bus (kateenc, bus); + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (myencsrcpad, inbuffer) == GST_FLOW_ERROR); + + fail_unless (gst_pad_push_event (myencsrcpad, gst_event_new_eos ()) == TRUE); + + fail_unless (gst_element_set_state (kateenc, + GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS, + "could not set to ready"); + + gst_element_set_bus (kateenc, NULL); + + /* cleanup */ + gst_object_unref (GST_OBJECT (bus)); + cleanup_kateenc (kateenc); +} + +GST_END_TEST; + +GST_START_TEST (test_kate_encode_simple) +{ + GstElement *kateenc; + GstBuffer *inbuffer; + GstBus *bus; + const gchar *test_string = ""; + GstCaps *caps; + + kateenc = setup_kateenc (); + g_object_set (kateenc, "category", "subtitles", NULL); + + fail_unless (gst_element_set_state (kateenc, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + bus = gst_bus_new (); + + inbuffer = gst_buffer_new_and_alloc (strlen (test_string) + 1); + memcpy (GST_BUFFER_DATA (inbuffer), test_string, strlen (test_string) + 1); + GST_BUFFER_TIMESTAMP (inbuffer) = GST_BUFFER_OFFSET (inbuffer) = + 1 * GST_SECOND; + GST_BUFFER_DURATION (inbuffer) = 5 * GST_SECOND; + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + + caps = gst_caps_from_string ("text/plain"); + fail_unless (caps != NULL); + gst_buffer_set_caps (inbuffer, caps); + gst_caps_unref (caps); + gst_buffer_ref (inbuffer); + + gst_element_set_bus (kateenc, bus); + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (myencsrcpad, inbuffer) == GST_FLOW_OK); + /* ... and nothing ends up on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + gst_buffer_unref (inbuffer); + fail_unless (gst_pad_push_event (myencsrcpad, gst_event_new_eos ()) == TRUE); + + fail_unless (gst_element_set_state (kateenc, + GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS, + "could not set to ready"); + + /* at least one data packet and one EOS packet should have been emitted */ + check_buffers (1 + 1, FALSE); + + /* cleanup */ + gst_bus_set_flushing (bus, TRUE); + gst_element_set_bus (kateenc, NULL); + gst_object_unref (GST_OBJECT (bus)); + cleanup_kateenc (kateenc); + g_list_free (buffers); +} + +GST_END_TEST; + +GST_START_TEST (test_kate_encode_spu) +{ + GstElement *kateenc; + GstBuffer *inbuffer; + GstBus *bus; + GstCaps *caps; + + kateenc = setup_kateenc (); + g_object_set (kateenc, "category", "spu-subtitles", NULL); + + fail_unless (gst_element_set_state (kateenc, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + bus = gst_bus_new (); + + inbuffer = gst_buffer_new_and_alloc (sizeof (kate_spu)); + memcpy (GST_BUFFER_DATA (inbuffer), kate_spu, sizeof (kate_spu)); + GST_BUFFER_TIMESTAMP (inbuffer) = GST_BUFFER_OFFSET (inbuffer) = + 1 * GST_SECOND; + GST_BUFFER_DURATION (inbuffer) = 5 * GST_SECOND; + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + + caps = gst_caps_from_string ("video/x-dvd-subpicture"); + fail_unless (caps != NULL); + gst_buffer_set_caps (inbuffer, caps); + gst_caps_unref (caps); + gst_buffer_ref (inbuffer); + + gst_element_set_bus (kateenc, bus); + /* pushing gives away my reference ... */ + fail_unless_equals_int (gst_pad_push (myencsrcpad, inbuffer), GST_FLOW_OK); + /* ... and nothing ends up on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + gst_buffer_unref (inbuffer); + fail_unless (gst_pad_push_event (myencsrcpad, gst_event_new_eos ()) == TRUE); + + fail_unless (gst_element_set_state (kateenc, + GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS, + "could not set to ready"); + + /* at least one data packet and one EOS packet should have been emitted */ + check_buffers (2, FALSE); + + /* cleanup */ + gst_bus_set_flushing (bus, TRUE); + gst_element_set_bus (kateenc, NULL); + gst_object_unref (GST_OBJECT (bus)); + cleanup_kateenc (kateenc); + g_list_free (buffers); +} + +GST_END_TEST; + +GST_START_TEST (test_kate_encode_keepalives) +{ + GstElement *kateenc; + GstBus *bus; + guint i, round; + enum + { n_keepalives = 1000 }; + static const struct + { + gdouble keepalive_min_time; + gint packets; + } cfg[3] = { + { + 0.5, n_keepalives}, { + 2.0, n_keepalives / 2}, { + 5.0, n_keepalives / 5},}; + + for (round = 0; round < 3; ++round) { + kateenc = setup_kateenc (); + /* doesn't matter here, since we never send a packet */ + g_object_set (kateenc, "category", "subtitles", NULL); + fail_unless (gst_element_set_state (kateenc, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + bus = gst_bus_new (); + + gst_element_set_bus (kateenc, bus); + + g_object_set (kateenc, "keepalive-min-time", cfg[round].keepalive_min_time, + NULL); + + /* the second one here should not emit a keepalive since the time since last packet + is less than the keepalive delay */ + for (i = 1; i <= n_keepalives; ++i) { + gint64 t = i * GST_SECOND; + fail_unless (gst_pad_push_event (myencsrcpad, + gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, t, -1, + 0)) == TRUE); + } + + fail_unless (gst_pad_push_event (myencsrcpad, + gst_event_new_eos ()) == TRUE); + + fail_unless (gst_element_set_state (kateenc, + GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS, + "could not set to ready"); + + /* at least a number data packet and an EOS packet should have been emitted */ + check_buffers (cfg[round].packets + 1, FALSE); + + /* cleanup */ + gst_bus_set_flushing (bus, TRUE); + gst_element_set_bus (kateenc, NULL); + gst_object_unref (GST_OBJECT (bus)); + cleanup_kateenc (kateenc); + g_list_free (buffers); + } +} + +GST_END_TEST; + +static void +test_kate_send_headers (GstPad * pad) +{ + GstBuffer *inbuffer; + GstCaps *caps; + int i; + + caps = gst_caps_new_simple ("subtitle/x-kate", NULL); + + /* push headers */ + inbuffer = gst_buffer_new (); + gst_buffer_set_caps (inbuffer, caps); + GST_BUFFER_DATA (inbuffer) = (guint8 *) kate_header_0x80; + GST_BUFFER_SIZE (inbuffer) = sizeof (kate_header_0x80); + GST_BUFFER_OFFSET (inbuffer) = GST_BUFFER_OFFSET_END (inbuffer) = 0; + fail_unless_equals_int (gst_pad_push (pad, inbuffer), GST_FLOW_OK); + + inbuffer = gst_buffer_new (); + gst_buffer_set_caps (inbuffer, caps); + GST_BUFFER_DATA (inbuffer) = (guint8 *) kate_header_0x81; + GST_BUFFER_SIZE (inbuffer) = sizeof (kate_header_0x81); + GST_BUFFER_OFFSET (inbuffer) = GST_BUFFER_OFFSET_END (inbuffer) = 0; + fail_unless_equals_int (gst_pad_push (pad, inbuffer), GST_FLOW_OK); + + for (i = 2; i < 8; ++i) { + inbuffer = gst_buffer_new_and_alloc (sizeof (kate_header_0x8x)); + gst_buffer_set_caps (inbuffer, caps); + memcpy (GST_BUFFER_DATA (inbuffer), (guint8 *) kate_header_0x8x, + sizeof (kate_header_0x8x)); + GST_BUFFER_DATA (inbuffer)[0] = 0x80 | i; + GST_BUFFER_OFFSET (inbuffer) = GST_BUFFER_OFFSET_END (inbuffer) = 0; + fail_unless_equals_int (gst_pad_push (pad, inbuffer), GST_FLOW_OK); + } + + inbuffer = gst_buffer_new (); + gst_buffer_set_caps (inbuffer, caps); + GST_BUFFER_DATA (inbuffer) = (guint8 *) kate_header_0x88; + GST_BUFFER_SIZE (inbuffer) = sizeof (kate_header_0x88); + GST_BUFFER_OFFSET (inbuffer) = GST_BUFFER_OFFSET_END (inbuffer) = 0; + fail_unless_equals_int (gst_pad_push (pad, inbuffer), GST_FLOW_OK); + + gst_caps_unref (caps); +} + +GST_START_TEST (test_kate_parse) +{ + GstElement *kateparse; + GstBuffer *inbuffer; + GstBus *bus; + + kateparse = setup_kateparse (); + fail_unless (gst_element_set_state (kateparse, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + bus = gst_bus_new (); + + gst_element_set_bus (kateparse, bus); + + test_kate_send_headers (myparsesrcpad); + + /* push a text packet */ + inbuffer = gst_buffer_new (); + GST_BUFFER_DATA (inbuffer) = (guint8 *) kate_header_0x00; + GST_BUFFER_SIZE (inbuffer) = sizeof (kate_header_0x00); + GST_BUFFER_TIMESTAMP (inbuffer) = GST_BUFFER_OFFSET (inbuffer) = + 1 * GST_SECOND; + GST_BUFFER_DURATION (inbuffer) = 5 * GST_SECOND; + GST_BUFFER_OFFSET_END (inbuffer) = (GST_BUFFER_TIMESTAMP (inbuffer) << 32); /* granpos */ + fail_unless_equals_int (gst_pad_push (myparsesrcpad, inbuffer), GST_FLOW_OK); + + /* push a eos packet */ + inbuffer = gst_buffer_new (); + GST_BUFFER_DATA (inbuffer) = (guint8 *) kate_header_0x7f; + GST_BUFFER_SIZE (inbuffer) = sizeof (kate_header_0x7f); + GST_BUFFER_TIMESTAMP (inbuffer) = GST_BUFFER_OFFSET (inbuffer) = + 6 * GST_SECOND; + GST_BUFFER_DURATION (inbuffer) = 0; + GST_BUFFER_OFFSET_END (inbuffer) = (GST_BUFFER_TIMESTAMP (inbuffer) << 32); /* granpos */ + fail_unless_equals_int (gst_pad_push (myparsesrcpad, inbuffer), GST_FLOW_OK); + + /* signal eos */ + fail_unless (gst_pad_push_event (myparsesrcpad, + gst_event_new_eos ()) == TRUE); + + fail_unless (gst_element_set_state (kateparse, + GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS, + "could not set to ready"); + + /* at least one data packet and one EOS packet should have been emitted */ + check_buffers (2, TRUE); + + /* cleanup */ + gst_bus_set_flushing (bus, TRUE); + gst_element_set_bus (kateparse, NULL); + gst_object_unref (GST_OBJECT (bus)); + cleanup_kateparse (kateparse); + g_list_free (buffers); +} + +GST_END_TEST; + +GST_START_TEST (test_kate_tag_passthrough) +{ + GstElement *katetag; + GstBus *bus; + GstBuffer *outbuffer; + GList *list; + + katetag = setup_katetag (); + fail_unless (gst_element_set_state (katetag, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + bus = gst_bus_new (); + + gst_element_set_bus (katetag, bus); + + test_kate_send_headers (mytagsrcpad); + + /* signal eos */ + fail_unless (gst_pad_push_event (mytagsrcpad, gst_event_new_eos ()) == TRUE); + + fail_unless (gst_element_set_state (katetag, + GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS, + "could not set to ready"); + + /* get the first buffer and check language/category */ + fail_unless (g_list_length (buffers) >= 2); /* ID header, Vorbis comments header */ + outbuffer = GST_BUFFER (buffers->data); + fail_if (outbuffer == NULL); + + /* check identification header is unchanged */ + list = g_list_nth (buffers, 0); + fail_unless (list != NULL); + outbuffer = list->data; + fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), + sizeof (kate_header_0x80)); + fail_unless_equals_int (memcmp (GST_BUFFER_DATA (outbuffer), kate_header_0x80, + sizeof (kate_header_0x80)), 0); + + /* check comment header is unchanged */ + list = g_list_nth (buffers, 1); + fail_unless (list != NULL); + outbuffer = list->data; + fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), + sizeof (kate_header_0x81)); + fail_unless_equals_int (memcmp (GST_BUFFER_DATA (outbuffer), kate_header_0x81, + sizeof (kate_header_0x81)), 0); + + /* all headers should have been emitted, but no particular packets */ + check_buffers (0, TRUE); + + /* cleanup */ + gst_bus_set_flushing (bus, TRUE); + gst_element_set_bus (katetag, NULL); + gst_object_unref (GST_OBJECT (bus)); + cleanup_katetag (katetag); + g_list_free (buffers); +} + +GST_END_TEST; + +GST_START_TEST (test_kate_tag) +{ + GstElement *katetag; + GstBus *bus; + GstBuffer *outbuffer; + + katetag = setup_katetag (); + fail_unless (gst_element_set_state (katetag, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + bus = gst_bus_new (); + + gst_element_set_bus (katetag, bus); + + g_object_set (katetag, "language", "cy", NULL); + g_object_set (katetag, "category", "subtitles", NULL); + + test_kate_send_headers (mytagsrcpad); + + /* signal eos */ + fail_unless (gst_pad_push_event (mytagsrcpad, gst_event_new_eos ()) == TRUE); + + fail_unless (gst_element_set_state (katetag, + GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS, + "could not set to ready"); + + /* get the first buffer and check language/category */ + fail_unless (g_list_length (buffers) >= 1); + outbuffer = GST_BUFFER (buffers->data); + fail_if (outbuffer == NULL); + fail_if (GST_BUFFER_SIZE (outbuffer) != 64); + fail_if (strcmp ((const char *) GST_BUFFER_DATA (outbuffer) + 32, "cy")); + fail_if (strcmp ((const char *) GST_BUFFER_DATA (outbuffer) + 48, + "subtitles")); + + /* all headers should have been emitted, but no particular packets */ + check_buffers (0, TRUE); + + /* cleanup */ + gst_bus_set_flushing (bus, TRUE); + gst_element_set_bus (katetag, NULL); + gst_object_unref (GST_OBJECT (bus)); + cleanup_katetag (katetag); + g_list_free (buffers); +} + +GST_END_TEST; + +static Suite * +kate_suite (void) +{ + Suite *s = suite_create ("kate"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + +#define X if (0) + tcase_add_test (tc_chain, test_kate_typefind); + tcase_add_test (tc_chain, test_kate_empty_identification_header); + tcase_add_test (tc_chain, test_kate_identification_header); + tcase_add_test (tc_chain, test_kate_encode_nothing); + tcase_add_test (tc_chain, test_kate_encode_empty); + tcase_add_test (tc_chain, test_kate_encode_simple); + tcase_add_test (tc_chain, test_kate_encode_spu); + tcase_add_test (tc_chain, test_kate_encode_keepalives); + tcase_add_test (tc_chain, test_kate_parse); + tcase_add_test (tc_chain, test_kate_tag_passthrough); + tcase_add_test (tc_chain, test_kate_tag); +#undef X + + return s; +} + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = kate_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; +} diff --git a/tests/check/elements/legacyresample.c b/tests/check/elements/legacyresample.c new file mode 100644 index 00000000..3c1bda3d --- /dev/null +++ b/tests/check/elements/legacyresample.c @@ -0,0 +1,574 @@ +/* GStreamer + * + * unit test for legacyresample + * + * Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org> + * Copyright (C) <2006> Tim-Philipp Müller <tim at centricular net> + * + * 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. + */ + +#include <unistd.h> + +#include <gst/check/gstcheck.h> +#include <gst/audio/audio.h> + +/* For ease of programming we use globals to keep refs for our floating + * src and sink pads we create; otherwise we always have to do get_pad, + * get_peer, and then remove references in every test function */ +static GstPad *mysrcpad, *mysinkpad; + + +#define RESAMPLE_CAPS_TEMPLATE_STRING \ + "audio/x-raw, " \ + "format = (string) " GST_AUDIO_NE (S16) ", " \ + "channels = (int) [ 1, MAX ], " \ + "rate = (int) [ 1, MAX ]" + +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (RESAMPLE_CAPS_TEMPLATE_STRING) + ); +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (RESAMPLE_CAPS_TEMPLATE_STRING) + ); + +static GstElement * +setup_legacyresample (int channels, int inrate, int outrate) +{ + GstElement *legacyresample; + GstCaps *caps; + GstStructure *structure; + + GST_DEBUG ("setup_legacyresample"); + legacyresample = gst_check_setup_element ("legacyresample"); + + caps = gst_caps_from_string (RESAMPLE_CAPS_TEMPLATE_STRING); + structure = gst_caps_get_structure (caps, 0); + gst_structure_set (structure, "channels", G_TYPE_INT, channels, + "rate", G_TYPE_INT, inrate, NULL); + fail_unless (gst_caps_is_fixed (caps)); + + fail_unless (gst_element_set_state (legacyresample, + GST_STATE_PAUSED) == GST_STATE_CHANGE_SUCCESS, + "could not set to paused"); + + mysrcpad = gst_check_setup_src_pad (legacyresample, &srctemplate); + gst_pad_set_active (mysrcpad, TRUE); + fail_unless (gst_pad_set_caps (mysrcpad, caps)); + gst_caps_unref (caps); + + caps = gst_caps_from_string (RESAMPLE_CAPS_TEMPLATE_STRING); + structure = gst_caps_get_structure (caps, 0); + gst_structure_set (structure, "channels", G_TYPE_INT, channels, + "rate", G_TYPE_INT, outrate, NULL); + fail_unless (gst_caps_is_fixed (caps)); + + mysinkpad = gst_check_setup_sink_pad (legacyresample, &sinktemplate); + gst_pad_set_active (mysinkpad, TRUE); + /* this installs a getcaps func that will always return the caps we set + * later */ + fail_unless (gst_pad_set_caps (mysinkpad, caps)); + gst_pad_use_fixed_caps (mysinkpad); + gst_caps_unref (caps); + + return legacyresample; +} + +static void +cleanup_legacyresample (GstElement * legacyresample) +{ + GST_DEBUG ("cleanup_legacyresample"); + + fail_unless (gst_element_set_state (legacyresample, + GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to NULL"); + + gst_pad_set_active (mysrcpad, FALSE); + gst_pad_set_active (mysinkpad, FALSE); + gst_check_teardown_src_pad (legacyresample); + gst_check_teardown_sink_pad (legacyresample); + gst_check_teardown_element (legacyresample); +} + +static void +fail_unless_perfect_stream (void) +{ + guint64 timestamp = 0L, duration = 0L; + guint64 offset = 0L, offset_end = 0L; + + GList *l; + GstBuffer *buffer; + + for (l = buffers; l; l = l->next) { + buffer = GST_BUFFER (l->data); + ASSERT_BUFFER_REFCOUNT (buffer, "buffer", 1); + GST_DEBUG ("buffer timestamp %" G_GUINT64_FORMAT ", duration %" + G_GUINT64_FORMAT " offset %" G_GUINT64_FORMAT " offset_end %" + G_GUINT64_FORMAT, + GST_BUFFER_TIMESTAMP (buffer), + GST_BUFFER_DURATION (buffer), + GST_BUFFER_OFFSET (buffer), GST_BUFFER_OFFSET_END (buffer)); + + fail_unless_equals_uint64 (timestamp, GST_BUFFER_TIMESTAMP (buffer)); + fail_unless_equals_uint64 (offset, GST_BUFFER_OFFSET (buffer)); + duration = GST_BUFFER_DURATION (buffer); + offset_end = GST_BUFFER_OFFSET_END (buffer); + + timestamp += duration; + offset = offset_end; + gst_buffer_unref (buffer); + } + g_list_free (buffers); + buffers = NULL; +} + +/* this tests that the output is a perfect stream if the input is */ +static void +test_perfect_stream_instance (int inrate, int outrate, int samples, + int numbuffers) +{ + GstElement *legacyresample; + GstBuffer *inbuffer, *outbuffer; + GstCaps *caps; + guint64 offset = 0; + + int i, j; + gint16 *p; + + legacyresample = setup_legacyresample (2, inrate, outrate); + caps = gst_pad_get_current_caps (mysrcpad); + fail_unless (gst_caps_is_fixed (caps)); + + fail_unless (gst_element_set_state (legacyresample, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + for (j = 1; j <= numbuffers; ++j) { + GstMapInfo map; + + inbuffer = gst_buffer_new_and_alloc (samples * 4); + GST_BUFFER_DURATION (inbuffer) = samples * GST_SECOND / inrate; + GST_BUFFER_TIMESTAMP (inbuffer) = GST_BUFFER_DURATION (inbuffer) * (j - 1); + GST_BUFFER_OFFSET (inbuffer) = offset; + offset += samples; + GST_BUFFER_OFFSET_END (inbuffer) = offset; + + gst_buffer_map (inbuffer, &map, GST_MAP_WRITE); + p = (gint16 *) map.data; + + /* create a 16 bit signed ramp */ + for (i = 0; i < samples; ++i) { + *p = -32767 + i * (65535 / samples); + ++p; + *p = -32767 + i * (65535 / samples); + ++p; + } + gst_buffer_unmap (inbuffer, &map); + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + /* ... but it ends up being collected on the global buffer list */ + fail_unless_equals_int (g_list_length (buffers), j); + } + + /* FIXME: we should make legacyresample handle eos by flushing out the last + * samples, which will give us one more, small, buffer */ + fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL); + ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1); + + fail_unless_perfect_stream (); + + /* cleanup */ + gst_caps_unref (caps); + cleanup_legacyresample (legacyresample); +} + + +/* make sure that outgoing buffers are contiguous in timestamp/duration and + * offset/offsetend + */ +GST_START_TEST (test_perfect_stream) +{ + /* integral scalings */ + test_perfect_stream_instance (48000, 24000, 500, 20); + test_perfect_stream_instance (48000, 12000, 500, 20); + test_perfect_stream_instance (12000, 24000, 500, 20); + test_perfect_stream_instance (12000, 48000, 500, 20); + + /* non-integral scalings */ + test_perfect_stream_instance (44100, 8000, 500, 20); + test_perfect_stream_instance (8000, 44100, 500, 20); + + /* wacky scalings */ + test_perfect_stream_instance (12345, 54321, 500, 20); + test_perfect_stream_instance (101, 99, 500, 20); +} + +GST_END_TEST; + +/* this tests that the output is a correct discontinuous stream + * if the input is; ie input drops in time come out the same way */ +static void +test_discont_stream_instance (int inrate, int outrate, int samples, + int numbuffers) +{ + GstElement *legacyresample; + GstBuffer *inbuffer, *outbuffer; + GstCaps *caps; + GstClockTime ints; + + int i, j; + gint16 *p; + + GST_DEBUG ("inrate:%d outrate:%d samples:%d numbuffers:%d", + inrate, outrate, samples, numbuffers); + + legacyresample = setup_legacyresample (2, inrate, outrate); + caps = gst_pad_get_current_caps (mysrcpad); + fail_unless (gst_caps_is_fixed (caps)); + + fail_unless (gst_element_set_state (legacyresample, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + for (j = 1; j <= numbuffers; ++j) { + GstMapInfo map; + + inbuffer = gst_buffer_new_and_alloc (samples * 4); + GST_BUFFER_DURATION (inbuffer) = samples * GST_SECOND / inrate; + /* "drop" half the buffers */ + ints = GST_BUFFER_DURATION (inbuffer) * 2 * (j - 1); + GST_BUFFER_TIMESTAMP (inbuffer) = ints; + GST_BUFFER_OFFSET (inbuffer) = (j - 1) * 2 * samples; + GST_BUFFER_OFFSET_END (inbuffer) = j * 2 * samples + samples; + + gst_buffer_map (inbuffer, &map, GST_MAP_WRITE); + p = (gint16 *) map.data; + + /* create a 16 bit signed ramp */ + for (i = 0; i < samples; ++i) { + *p = -32767 + i * (65535 / samples); + ++p; + *p = -32767 + i * (65535 / samples); + ++p; + } + gst_buffer_unmap (inbuffer, &map); + + GST_DEBUG ("Sending Buffer time:%" G_GUINT64_FORMAT " duration:%" + G_GINT64_FORMAT " discont:%d offset:%" G_GUINT64_FORMAT " offset_end:%" + G_GUINT64_FORMAT, GST_BUFFER_TIMESTAMP (inbuffer), + GST_BUFFER_DURATION (inbuffer), GST_BUFFER_IS_DISCONT (inbuffer), + GST_BUFFER_OFFSET (inbuffer), GST_BUFFER_OFFSET_END (inbuffer)); + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + + /* check if the timestamp of the pushed buffer matches the incoming one */ + outbuffer = g_list_nth_data (buffers, g_list_length (buffers) - 1); + fail_if (outbuffer == NULL); + fail_unless_equals_uint64 (ints, GST_BUFFER_TIMESTAMP (outbuffer)); + GST_DEBUG ("Got Buffer time:%" G_GUINT64_FORMAT " duration:%" + G_GINT64_FORMAT " discont:%d offset:%" G_GUINT64_FORMAT " offset_end:%" + G_GUINT64_FORMAT, GST_BUFFER_TIMESTAMP (outbuffer), + GST_BUFFER_DURATION (outbuffer), GST_BUFFER_IS_DISCONT (outbuffer), + GST_BUFFER_OFFSET (outbuffer), GST_BUFFER_OFFSET_END (outbuffer)); + if (j > 1) { + fail_unless (GST_BUFFER_IS_DISCONT (outbuffer), + "expected discont for buffer #%d", j); + } + } + + /* cleanup */ + gst_caps_unref (caps); + cleanup_legacyresample (legacyresample); +} + +GST_START_TEST (test_discont_stream) +{ + /* integral scalings */ + test_discont_stream_instance (48000, 24000, 500, 20); + test_discont_stream_instance (48000, 12000, 500, 20); + test_discont_stream_instance (12000, 24000, 500, 20); + test_discont_stream_instance (12000, 48000, 500, 20); + + /* non-integral scalings */ + test_discont_stream_instance (44100, 8000, 500, 20); + test_discont_stream_instance (8000, 44100, 500, 20); + + /* wacky scalings */ + test_discont_stream_instance (12345, 54321, 500, 20); + test_discont_stream_instance (101, 99, 500, 20); +} + +GST_END_TEST; + + + +GST_START_TEST (test_reuse) +{ + GstElement *legacyresample; + GstEvent *newseg; + GstBuffer *inbuffer; + GstCaps *caps; + GstSegment seg; + + legacyresample = setup_legacyresample (1, 9343, 48000); + caps = gst_pad_get_current_caps (mysrcpad); + fail_unless (gst_caps_is_fixed (caps)); + + fail_unless (gst_element_set_state (legacyresample, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + gst_segment_init (&seg, GST_FORMAT_TIME); + newseg = gst_event_new_segment (&seg); + fail_unless (gst_pad_push_event (mysrcpad, newseg) != FALSE); + + inbuffer = gst_buffer_new_and_alloc (9343 * 4); + gst_buffer_memset (inbuffer, 0, 0, -1); + GST_BUFFER_DURATION (inbuffer) = GST_SECOND; + GST_BUFFER_TIMESTAMP (inbuffer) = 0; + GST_BUFFER_OFFSET (inbuffer) = 0; + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + + /* ... but it ends up being collected on the global buffer list */ + fail_unless_equals_int (g_list_length (buffers), 1); + + /* now reset and try again ... */ + fail_unless (gst_element_set_state (legacyresample, + GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to NULL"); + + fail_unless (gst_element_set_state (legacyresample, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + gst_segment_init (&seg, GST_FORMAT_TIME); + newseg = gst_event_new_segment (&seg); + fail_unless (gst_pad_push_event (mysrcpad, newseg) != FALSE); + + inbuffer = gst_buffer_new_and_alloc (9343 * 4); + gst_buffer_memset (inbuffer, 0, 0, -1); + GST_BUFFER_DURATION (inbuffer) = GST_SECOND; + GST_BUFFER_TIMESTAMP (inbuffer) = 0; + GST_BUFFER_OFFSET (inbuffer) = 0; + + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + + /* ... it also ends up being collected on the global buffer list. If we + * now have more than 2 buffers, then legacyresample probably didn't clean + * up its internal buffer properly and tried to push the remaining samples + * when it got the second NEWSEGMENT event */ + fail_unless_equals_int (g_list_length (buffers), 2); + + cleanup_legacyresample (legacyresample); + gst_caps_unref (caps); +} + +GST_END_TEST; + +GST_START_TEST (test_shutdown) +{ + GstElement *pipeline, *src, *cf1, *ar, *cf2, *sink; + GstCaps *caps; + guint i; + + /* create pipeline, force legacyresample to actually resample */ + pipeline = gst_pipeline_new (NULL); + + src = gst_check_setup_element ("audiotestsrc"); + cf1 = gst_check_setup_element ("capsfilter"); + ar = gst_check_setup_element ("legacyresample"); + cf2 = gst_check_setup_element ("capsfilter"); + g_object_set (cf2, "name", "capsfilter2", NULL); + sink = gst_check_setup_element ("fakesink"); + + caps = + gst_caps_new_simple ("audio/x-raw-int", "rate", G_TYPE_INT, 11025, NULL); + g_object_set (cf1, "caps", caps, NULL); + gst_caps_unref (caps); + + caps = + gst_caps_new_simple ("audio/x-raw-int", "rate", G_TYPE_INT, 48000, NULL); + g_object_set (cf2, "caps", caps, NULL); + gst_caps_unref (caps); + + /* don't want to sync against the clock, the more throughput the better */ + g_object_set (src, "is-live", FALSE, NULL); + g_object_set (sink, "sync", FALSE, NULL); + + gst_bin_add_many (GST_BIN (pipeline), src, cf1, ar, cf2, sink, NULL); + fail_if (!gst_element_link_many (src, cf1, ar, cf2, sink, NULL)); + + /* now, wait until pipeline is running and then shut it down again; repeat */ + for (i = 0; i < 20; ++i) { + gst_element_set_state (pipeline, GST_STATE_PAUSED); + gst_element_get_state (pipeline, NULL, NULL, -1); + gst_element_set_state (pipeline, GST_STATE_PLAYING); + g_usleep (100); + gst_element_set_state (pipeline, GST_STATE_NULL); + } + + gst_object_unref (pipeline); +} + +GST_END_TEST; + +#if 0 +static GstFlowReturn +live_switch_alloc_only_48000 (GstPad * pad, guint64 offset, + guint size, GstCaps * caps, GstBuffer ** buf) +{ + GstStructure *structure; + gint rate; + gint channels; + GstCaps *desired; + + structure = gst_caps_get_structure (caps, 0); + fail_unless (gst_structure_get_int (structure, "rate", &rate)); + fail_unless (gst_structure_get_int (structure, "channels", &channels)); + + if (rate < 48000) + return GST_FLOW_NOT_NEGOTIATED; + + desired = gst_caps_copy (caps); + gst_caps_set_simple (desired, "rate", G_TYPE_INT, 48000, NULL); + + *buf = gst_buffer_new_and_alloc (channels * 48000); + gst_buffer_set_caps (*buf, desired); + gst_caps_unref (desired); + + return GST_FLOW_OK; +} + +static GstCaps * +live_switch_get_sink_caps (GstPad * pad) +{ + GstCaps *result; + + result = gst_caps_copy (GST_PAD_CAPS (pad)); + + gst_caps_set_simple (result, + "rate", GST_TYPE_INT_RANGE, 48000, G_MAXINT, NULL); + + return result; +} + +static void +live_switch_push (int rate, GstCaps * caps) +{ + GstBuffer *inbuffer; + GstCaps *desired; + GList *l; + + desired = gst_caps_copy (caps); + gst_caps_set_simple (desired, "rate", G_TYPE_INT, rate, NULL); + + fail_unless (gst_pad_alloc_buffer_and_set_caps (mysrcpad, + GST_BUFFER_OFFSET_NONE, rate * 4, desired, &inbuffer) == GST_FLOW_OK); + + /* When the basetransform hits the non-configured case it always + * returns a buffer with exactly the same caps as we requested so the actual + * renegotiation (if needed) will be done in the _chain*/ + fail_unless (inbuffer != NULL); + fail_unless (gst_caps_is_equal (desired, GST_BUFFER_CAPS (inbuffer))); + + gst_buffer_memset (inbuffer, 0, 0, -1); + GST_BUFFER_DURATION (inbuffer) = GST_SECOND; + GST_BUFFER_TIMESTAMP (inbuffer) = 0; + GST_BUFFER_OFFSET (inbuffer) = 0; + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + + /* ... but it ends up being collected on the global buffer list */ + fail_unless_equals_int (g_list_length (buffers), 1); + + for (l = buffers; l; l = l->next) { + GstBuffer *buffer = GST_BUFFER (l->data); + + gst_buffer_unref (buffer); + } + + g_list_free (buffers); + buffers = NULL; + + gst_caps_unref (desired); +} + +GST_START_TEST (test_live_switch) +{ + GstElement *legacyresample; + GstEvent *newseg; + GstCaps *caps; + + legacyresample = setup_legacyresample (4, 48000, 48000); + + /* Let the sinkpad act like something that can only handle things of + * rate 48000- and can only allocate buffers for that rate, but if someone + * tries to get a buffer with a rate higher then 48000 tries to renegotiate + * */ + gst_pad_set_bufferalloc_function (mysinkpad, live_switch_alloc_only_48000); + gst_pad_set_getcaps_function (mysinkpad, live_switch_get_sink_caps); + + caps = gst_pad_get_negotiated_caps (mysrcpad); + fail_unless (gst_caps_is_fixed (caps)); + + fail_unless (gst_element_set_state (legacyresample, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + newseg = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0); + fail_unless (gst_pad_push_event (mysrcpad, newseg) != FALSE); + + /* downstream can provide the requested rate, a buffer alloc will be passed + * on */ + live_switch_push (48000, caps); + + /* Downstream can never accept this rate, buffer alloc isn't passed on */ + live_switch_push (40000, caps); + + /* Downstream can provide the requested rate but will re-negotiate */ + live_switch_push (50000, caps); + + cleanup_legacyresample (legacyresample); + gst_caps_unref (caps); +} + +GST_END_TEST +#endif +static Suite * +legacyresample_suite (void) +{ + Suite *s = suite_create ("legacyresample"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_perfect_stream); + tcase_add_test (tc_chain, test_discont_stream); + tcase_add_test (tc_chain, test_reuse); + tcase_add_test (tc_chain, test_shutdown); +#if 0 + tcase_add_test (tc_chain, test_live_switch); +#endif + + return s; +} + +GST_CHECK_MAIN (legacyresample); diff --git a/tests/check/elements/logoinsert.c b/tests/check/elements/logoinsert.c new file mode 100644 index 00000000..08f19d2a --- /dev/null +++ b/tests/check/elements/logoinsert.c @@ -0,0 +1,252 @@ +/* GStreamer + * + * unit test for logoinsert + * + * Copyright (C) 2011 David Schleef <ds@schleef.org> + * + * 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. + */ + +#include <gst/check/gstcheck.h> +#include <string.h> + +static guint8 image_data[]; +/* sizeof on a forward declaration? not so fast */ +#define SIZEOF_IMAGE_DATA 1428 + +typedef struct +{ + GMainLoop *loop; + gboolean eos; +} OnMessageUserData; + +static void +on_message_cb (GstBus * bus, GstMessage * message, gpointer user_data) +{ + OnMessageUserData *d = user_data; + + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_ERROR: + case GST_MESSAGE_WARNING: + g_assert_not_reached (); + break; + case GST_MESSAGE_EOS: + g_main_loop_quit (d->loop); + d->eos = TRUE; + break; + default: + break; + } +} + +static void +run_test (const gchar * pipeline_string) +{ + GstElement *pipeline; + GstBus *bus; + GMainLoop *loop; + OnMessageUserData omud = { NULL, }; + GstStateChangeReturn ret; + GstElement *e; + GstBuffer *buffer; + + GST_DEBUG ("Testing pipeline '%s'", pipeline_string); + + pipeline = gst_parse_launch (pipeline_string, NULL); + fail_unless (pipeline != NULL); + g_object_set (G_OBJECT (pipeline), "async-handling", TRUE, NULL); + + e = gst_bin_get_by_name (GST_BIN (pipeline), "e"); + fail_unless (e != NULL); + buffer = gst_buffer_new (); + GST_BUFFER_DATA (buffer) = image_data; + GST_BUFFER_SIZE (buffer) = SIZEOF_IMAGE_DATA; + g_object_set (e, "data", buffer, NULL); + g_object_unref (e); + + loop = g_main_loop_new (NULL, FALSE); + + bus = gst_element_get_bus (pipeline); + fail_unless (bus != NULL); + gst_bus_add_signal_watch (bus); + + omud.loop = loop; + omud.eos = FALSE; + + g_signal_connect (bus, "message", (GCallback) on_message_cb, &omud); + + gst_object_unref (bus); + + ret = gst_element_set_state (pipeline, GST_STATE_PLAYING); + fail_unless (ret == GST_STATE_CHANGE_SUCCESS + || ret == GST_STATE_CHANGE_ASYNC); + + g_main_loop_run (loop); + + fail_unless (gst_element_set_state (pipeline, + GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS); + + fail_unless (omud.eos == TRUE); + + gst_object_unref (pipeline); + g_main_loop_unref (loop); +} + +GST_START_TEST (test_logoinsert) +{ + + run_test ("videotestsrc num-buffers=250 ! coglogoinsert name=e ! fakesink"); +} + +GST_END_TEST; + +static Suite * +logoinsert_suite (void) +{ + Suite *s = suite_create ("logoinsert"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_set_timeout (tc_chain, 180); + + tcase_add_test (tc_chain, test_logoinsert); + + return s; +} + +GST_CHECK_MAIN (logoinsert); + +static guint8 image_data[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, + 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x64, 0x08, + 0x06, 0x00, 0x00, 0x00, 0x70, 0xe2, 0x95, 0x54, 0x00, 0x00, 0x00, 0x01, + 0x73, 0x52, 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 0x00, + 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xa0, + 0xbd, 0xa7, 0x93, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, + 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, + 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xdb, 0x03, 0x12, + 0x01, 0x3b, 0x19, 0x50, 0x86, 0x8e, 0x47, 0x00, 0x00, 0x00, 0x19, 0x74, + 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, + 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0x0e, 0x17, 0x00, 0x00, 0x04, 0xef, + 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xed, 0x9d, 0xcf, 0x6b, 0x1d, 0x55, + 0x14, 0xc7, 0x3f, 0xf7, 0xa1, 0x89, 0x81, 0x16, 0xa3, 0x82, 0x9a, 0x57, + 0xc4, 0x59, 0x68, 0x05, 0x05, 0x13, 0x28, 0x08, 0xba, 0x49, 0x16, 0xa2, + 0xb8, 0x90, 0x06, 0xd4, 0x45, 0x75, 0x61, 0x17, 0xfe, 0x07, 0xe2, 0xca, + 0x85, 0x8a, 0x9b, 0x82, 0x14, 0x04, 0x37, 0x5d, 0x5a, 0xfc, 0x51, 0x10, + 0xd4, 0xd6, 0xba, 0x69, 0x11, 0xac, 0x22, 0x55, 0xb0, 0xd1, 0x44, 0xd0, + 0x62, 0x57, 0x53, 0x82, 0x81, 0x46, 0x6b, 0x5f, 0xd3, 0x17, 0x34, 0x21, + 0xf5, 0xb8, 0x98, 0x33, 0xed, 0x04, 0x5e, 0x9a, 0xbe, 0xf7, 0x66, 0xee, + 0xdc, 0x99, 0x39, 0x5f, 0xb8, 0x0c, 0x59, 0xcd, 0xdc, 0xf3, 0xc9, 0xf7, + 0xdc, 0x3b, 0x77, 0xde, 0x3d, 0xd7, 0x89, 0x08, 0xa6, 0x70, 0xd4, 0xb2, + 0x10, 0x18, 0x10, 0x93, 0x01, 0x31, 0x20, 0x26, 0x03, 0x62, 0x40, 0x4c, + 0x06, 0xa4, 0xfe, 0xba, 0xa5, 0xea, 0x1d, 0x70, 0xce, 0x8d, 0x03, 0xd9, + 0x96, 0x55, 0x27, 0x6d, 0x22, 0xd2, 0xa9, 0x44, 0x7f, 0x42, 0x7f, 0x31, + 0x74, 0xce, 0x8d, 0x00, 0x6d, 0x20, 0xbd, 0x02, 0xec, 0x00, 0x1e, 0x00, + 0x22, 0x60, 0xa7, 0xfe, 0x3d, 0x72, 0x23, 0x20, 0x40, 0x0c, 0x2c, 0x00, + 0xf3, 0x21, 0xc3, 0x09, 0x12, 0x88, 0x42, 0xd8, 0x0d, 0x3c, 0xa1, 0x41, + 0x9f, 0xd0, 0xc0, 0xdf, 0xaf, 0xc1, 0xcf, 0xb6, 0x9b, 0x75, 0x79, 0x07, + 0x98, 0xd7, 0xb6, 0xa0, 0xd7, 0x38, 0x34, 0x38, 0xc1, 0x00, 0x51, 0x08, + 0x51, 0x06, 0xc4, 0x6e, 0xe0, 0xf1, 0x8c, 0x2b, 0xf2, 0xd4, 0x45, 0x60, + 0x11, 0x38, 0x03, 0x7c, 0x01, 0xcc, 0x89, 0xc8, 0x92, 0x01, 0xb9, 0x0e, + 0x63, 0x07, 0xf0, 0x34, 0xf0, 0x9c, 0x82, 0xd8, 0xe3, 0xe9, 0xd6, 0x1b, + 0x40, 0x17, 0xb8, 0x04, 0x9c, 0x03, 0x3e, 0x07, 0x8e, 0x97, 0x09, 0xa7, + 0x54, 0x20, 0x99, 0xd4, 0xf4, 0x14, 0xf0, 0xa2, 0x47, 0x10, 0xbd, 0x74, + 0x55, 0x9d, 0xb3, 0x0c, 0x7c, 0x0f, 0x1c, 0x2f, 0xc3, 0x39, 0xa5, 0x01, + 0xc9, 0xb8, 0x62, 0x5f, 0x81, 0xa9, 0x69, 0x50, 0x75, 0x15, 0xce, 0x29, + 0xe0, 0x3d, 0x11, 0x99, 0xab, 0x35, 0x10, 0x85, 0xf1, 0x2c, 0xf0, 0x6a, + 0xc9, 0xae, 0xd8, 0x4e, 0xab, 0x3a, 0xce, 0x1c, 0xf1, 0x96, 0xca, 0x44, + 0xc4, 0x6b, 0xd3, 0x99, 0xd1, 0x3e, 0xed, 0xa8, 0x54, 0xa0, 0x6d, 0x00, + 0x7f, 0x01, 0x1f, 0x03, 0x7b, 0x0a, 0x8f, 0x4f, 0x49, 0x30, 0x7e, 0xae, + 0x08, 0x8c, 0x6c, 0x5b, 0x07, 0x7e, 0xd0, 0xe7, 0x1f, 0xaf, 0x3c, 0x10, + 0x7d, 0x71, 0x9b, 0x06, 0x7e, 0xa9, 0x20, 0x8c, 0xb4, 0x5d, 0xd5, 0xe9, + 0xf2, 0x41, 0x20, 0xaa, 0x3a, 0x90, 0x87, 0x74, 0xce, 0x2f, 0x35, 0x68, + 0x5d, 0xe0, 0x23, 0x60, 0x26, 0x6f, 0xb7, 0x78, 0x19, 0xd4, 0x9d, 0x73, + 0x0f, 0x03, 0xaf, 0xeb, 0x7b, 0xc6, 0x68, 0x4d, 0xd6, 0x01, 0xd7, 0x80, + 0x9f, 0x80, 0x4f, 0x80, 0xa3, 0x22, 0x12, 0x57, 0x62, 0x71, 0xd1, 0x39, + 0xf7, 0x20, 0xf0, 0x1a, 0xf0, 0xbc, 0xa6, 0xad, 0xba, 0x68, 0x54, 0xa7, + 0xeb, 0x13, 0xc0, 0xb8, 0x73, 0xee, 0xfd, 0x3c, 0xa0, 0xb4, 0x0a, 0x86, + 0x11, 0x01, 0xaf, 0x00, 0xb3, 0x35, 0x83, 0x91, 0x55, 0x04, 0xbc, 0x0c, + 0xec, 0xd7, 0xfe, 0x86, 0x09, 0x44, 0x1f, 0x6e, 0x3f, 0xf0, 0x52, 0x8f, + 0x55, 0x58, 0x83, 0xe2, 0x13, 0x88, 0x7e, 0xa3, 0x98, 0x55, 0x20, 0xbb, + 0x68, 0x86, 0x52, 0x28, 0xb3, 0xda, 0xff, 0xa0, 0x1c, 0x32, 0x05, 0xec, + 0x25, 0x59, 0x2e, 0x6f, 0x92, 0x22, 0xed, 0xf7, 0x54, 0x30, 0x40, 0xd4, + 0xb2, 0x43, 0x3d, 0x54, 0xc5, 0x35, 0x05, 0xec, 0x1d, 0x34, 0x75, 0xb5, + 0x72, 0x86, 0x91, 0xa6, 0xaa, 0xd9, 0x06, 0x8c, 0x1b, 0x5b, 0xe9, 0x5a, + 0x0c, 0x06, 0x49, 0x5d, 0xad, 0x02, 0x2c, 0x3b, 0xad, 0xd7, 0x26, 0x6b, + 0xe0, 0x38, 0xb4, 0x0a, 0xb0, 0xeb, 0x14, 0xa6, 0x81, 0x63, 0x91, 0x1b, + 0x10, 0xb5, 0xe7, 0xa4, 0xb9, 0x63, 0x93, 0x4b, 0x26, 0xfb, 0x4d, 0x5b, + 0x2d, 0x73, 0x47, 0x58, 0x2e, 0xc9, 0x13, 0xc8, 0xa4, 0x01, 0xe9, 0x09, + 0x64, 0xd2, 0x3b, 0x10, 0xb5, 0x65, 0xd4, 0xe0, 0x99, 0xd5, 0x8d, 0x66, + 0x5c, 0x51, 0x3f, 0x69, 0xab, 0x95, 0xe3, 0x8d, 0xdb, 0x16, 0xff, 0x2d, + 0x63, 0x53, 0x0a, 0x90, 0x7b, 0x2d, 0xf6, 0x61, 0x01, 0xd9, 0x65, 0xb1, + 0x0f, 0x07, 0xc8, 0x5d, 0xc0, 0x98, 0xc5, 0x7e, 0x78, 0xe5, 0x05, 0xe4, + 0x11, 0xe0, 0x76, 0x0b, 0x67, 0x38, 0x40, 0xee, 0x33, 0x87, 0x04, 0x02, + 0xc4, 0x39, 0xd7, 0x06, 0xee, 0xc0, 0x36, 0xff, 0x6c, 0xa5, 0x74, 0x3b, + 0x84, 0x37, 0x87, 0x8c, 0x90, 0xfc, 0x12, 0xc3, 0x14, 0x08, 0x90, 0x36, + 0x70, 0xa7, 0xc5, 0x3d, 0x2c, 0x87, 0x58, 0xba, 0xea, 0xad, 0x35, 0xe0, + 0x42, 0x3f, 0x9b, 0x82, 0x2c, 0x90, 0xc5, 0xea, 0x1f, 0xe0, 0xdf, 0x32, + 0x66, 0x59, 0xa6, 0xde, 0x1a, 0x03, 0x6e, 0x33, 0x20, 0xe1, 0x68, 0x14, + 0xb8, 0xc7, 0xf7, 0xe2, 0xe2, 0x52, 0x3f, 0x83, 0x56, 0x03, 0xe5, 0x7d, + 0xe9, 0x64, 0x9d, 0x64, 0x0f, 0x85, 0x29, 0x10, 0x20, 0x4b, 0x3a, 0x78, + 0x99, 0x42, 0x00, 0x22, 0x22, 0xeb, 0x24, 0x1b, 0x25, 0xd7, 0x2c, 0xf6, + 0xc3, 0x2b, 0xaf, 0x41, 0xfd, 0x57, 0x60, 0xc5, 0xc2, 0x19, 0x0e, 0x90, + 0x45, 0x4b, 0x5b, 0x61, 0x01, 0xd9, 0x00, 0x2e, 0x5b, 0x38, 0x7b, 0xca, + 0xfb, 0xd2, 0x49, 0x3a, 0xb0, 0x9f, 0xb7, 0xd8, 0x87, 0x03, 0x64, 0x1d, + 0xf8, 0xdb, 0x62, 0x1f, 0x96, 0x43, 0xfe, 0xb0, 0xd8, 0xf7, 0x84, 0x11, + 0x7b, 0x5f, 0x5c, 0xd4, 0xa9, 0x6f, 0xac, 0x60, 0x4c, 0xd7, 0x95, 0x96, + 0x82, 0xf2, 0x3e, 0xa8, 0x03, 0x9c, 0x26, 0x29, 0xda, 0x62, 0xda, 0x0c, + 0x64, 0xbe, 0x2c, 0x20, 0xe7, 0xb4, 0x99, 0x12, 0xc5, 0xc0, 0x42, 0xbf, + 0x05, 0xd2, 0x72, 0x03, 0xa2, 0x69, 0xeb, 0x34, 0x30, 0x67, 0x2c, 0x06, + 0x73, 0x47, 0xde, 0x0e, 0x31, 0x97, 0x6c, 0x76, 0xc7, 0x37, 0x7a, 0x2d, + 0x15, 0x48, 0x0c, 0x7c, 0xda, 0x70, 0x97, 0x74, 0x80, 0xa3, 0x24, 0xd5, + 0x1d, 0xfa, 0xfe, 0x2c, 0x91, 0x6b, 0x25, 0x07, 0x11, 0x59, 0x77, 0xce, + 0x9d, 0x20, 0xd9, 0x7d, 0x3b, 0x41, 0x33, 0x7f, 0x80, 0x3d, 0x0f, 0x1c, + 0x1b, 0xb4, 0xaa, 0x43, 0xee, 0x5f, 0x0c, 0x45, 0xa4, 0x0b, 0x9c, 0x6c, + 0xe8, 0x8c, 0x2b, 0x06, 0x8e, 0x0d, 0x32, 0x76, 0x14, 0x06, 0x24, 0x33, + 0x96, 0x1c, 0x69, 0x58, 0xea, 0x5a, 0x04, 0x0e, 0x0f, 0x9a, 0xaa, 0x0a, + 0x05, 0xa2, 0x33, 0xae, 0x13, 0x24, 0x75, 0xa5, 0x9a, 0x00, 0xe5, 0x4f, + 0xe0, 0x03, 0x60, 0xf8, 0x02, 0x34, 0x9e, 0x2a, 0xc8, 0x55, 0xb9, 0x68, + 0xd9, 0x76, 0xed, 0x12, 0xf0, 0x0e, 0x39, 0x15, 0x34, 0xf3, 0x59, 0xd6, + 0xef, 0xf7, 0x1a, 0xc2, 0xb8, 0x08, 0xbc, 0x4d, 0x8e, 0xd5, 0xe5, 0x7c, + 0xd6, 0x5a, 0x9c, 0x06, 0x7e, 0xac, 0x11, 0x8c, 0x55, 0xe0, 0x2d, 0xa0, + 0x5d, 0xe5, 0x9a, 0x8b, 0x8f, 0x01, 0x67, 0x6b, 0x00, 0xe3, 0x0a, 0xf0, + 0x2e, 0x70, 0x77, 0xa5, 0xab, 0x92, 0x2a, 0x98, 0x67, 0xa8, 0x66, 0x55, + 0xd2, 0x6c, 0x9a, 0x3a, 0x50, 0x04, 0x8c, 0x52, 0x80, 0x28, 0x94, 0x27, + 0x81, 0xef, 0x2a, 0x08, 0xe3, 0x02, 0xf0, 0x66, 0x51, 0x30, 0xbc, 0x15, + 0xc1, 0xec, 0x25, 0xe7, 0xdc, 0x0c, 0xf0, 0x06, 0x49, 0x65, 0xcf, 0xd0, + 0xb5, 0xaa, 0x30, 0x0e, 0x03, 0x87, 0x44, 0x64, 0xb9, 0xa8, 0x1b, 0x95, + 0x76, 0xc2, 0x8e, 0x88, 0x9c, 0x72, 0xce, 0xa5, 0x6f, 0xb7, 0x33, 0x84, + 0x5b, 0x23, 0x65, 0x19, 0xf8, 0x5a, 0x61, 0x7c, 0x2b, 0x22, 0xab, 0x85, + 0xfe, 0xa3, 0x96, 0x7d, 0x5c, 0x85, 0x16, 0xfa, 0x9a, 0x26, 0x29, 0x07, + 0x38, 0x13, 0x18, 0x88, 0x15, 0x7d, 0xe1, 0x2b, 0xd4, 0x15, 0x41, 0x38, + 0x24, 0xe3, 0x94, 0x18, 0x88, 0x9d, 0x73, 0xe7, 0xd5, 0x2d, 0x51, 0x89, + 0x60, 0xd2, 0xd4, 0xb4, 0x02, 0x7c, 0xa6, 0x4b, 0xe8, 0x73, 0x45, 0xbb, + 0x22, 0x28, 0x87, 0xf4, 0x70, 0x4b, 0xea, 0x98, 0xc8, 0x43, 0x2a, 0xfb, + 0x4f, 0x67, 0x4d, 0x1d, 0x85, 0xf1, 0x1b, 0xf0, 0xa1, 0x8f, 0xd4, 0x54, + 0x09, 0x20, 0x5b, 0xa4, 0xb2, 0x14, 0xd2, 0xad, 0xc0, 0xa3, 0x24, 0x45, + 0x0a, 0x86, 0x5d, 0xd6, 0xbf, 0x0c, 0x7c, 0xa5, 0xab, 0x07, 0x27, 0x15, + 0xc6, 0xd9, 0xb2, 0x20, 0x54, 0x02, 0x48, 0x0f, 0x38, 0x64, 0xdc, 0x32, + 0x46, 0x72, 0x4e, 0xd5, 0x0b, 0x24, 0x35, 0xe5, 0x6f, 0x46, 0x57, 0x80, + 0x2f, 0x81, 0x83, 0x3e, 0x0f, 0x68, 0xa9, 0x25, 0x90, 0x6d, 0x60, 0xed, + 0x24, 0x39, 0x14, 0x26, 0xbd, 0x66, 0xd5, 0x25, 0x39, 0xa7, 0xa4, 0x2b, + 0x22, 0x67, 0x2a, 0xd1, 0x1f, 0x3b, 0xe0, 0x3e, 0x2c, 0xd9, 0x1e, 0x43, + 0x03, 0x62, 0x32, 0x20, 0x06, 0xc4, 0x64, 0x40, 0x0c, 0x88, 0xc9, 0x80, + 0x18, 0x10, 0x93, 0x01, 0x31, 0x20, 0x26, 0x03, 0x62, 0x32, 0x20, 0x06, + 0xc4, 0x64, 0x40, 0x0c, 0x88, 0xc9, 0x80, 0x18, 0x10, 0x93, 0x01, 0x69, + 0xb2, 0xfe, 0x07, 0xb0, 0x6d, 0xc6, 0x8c, 0x41, 0x92, 0x78, 0x97, 0x00, + 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; diff --git a/tests/check/elements/mpeg2enc.c b/tests/check/elements/mpeg2enc.c new file mode 100644 index 00000000..41dc7e07 --- /dev/null +++ b/tests/check/elements/mpeg2enc.c @@ -0,0 +1,208 @@ +/* GStreamer + * + * unit test for mpeg2enc + * + * Copyright (C) <2006> Mark Nauwelaerts <manauw@skynet.be> + * + * 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. + */ + +#include <unistd.h> + +#include <gst/check/gstcheck.h> + +/* For ease of programming we use globals to keep refs for our floating + * src and sink pads we create; otherwise we always have to do get_pad, + * get_peer, and then remove references in every test function */ +static GstPad *mysrcpad, *mysinkpad; + +#define VIDEO_CAPS_STRING "video/x-raw, " \ + "format = (string) I420, " \ + "width = (int) 384, " \ + "height = (int) 288, " \ + "framerate = (fraction) 25/1" + +#define MPEG_CAPS_STRING "video/mpeg, " \ + "mpegversion = (int) { 1, 2 }, " \ + "systemstream = (bool) false, " \ + "height = (int) 288, " \ + "framerate = (fraction) 25/1" + +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (MPEG_CAPS_STRING)); + +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (VIDEO_CAPS_STRING)); + + +/* some global vars, makes it easy as for the ones above */ +static GMutex *mpeg2enc_mutex; +static GCond *mpeg2enc_cond; +static gboolean arrived_eos; + +static gboolean +test_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) +{ + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_EOS: + g_mutex_lock (mpeg2enc_mutex); + arrived_eos = TRUE; + g_cond_signal (mpeg2enc_cond); + g_mutex_unlock (mpeg2enc_mutex); + break; + default: + break; + } + + return gst_pad_event_default (pad, parent, event); +} + +static GstElement * +setup_mpeg2enc (void) +{ + GstElement *mpeg2enc; + + GST_DEBUG ("setup_mpeg2enc"); + mpeg2enc = gst_check_setup_element ("mpeg2enc"); + mysrcpad = gst_check_setup_src_pad (mpeg2enc, &srctemplate); + mysinkpad = gst_check_setup_sink_pad (mpeg2enc, &sinktemplate); + gst_pad_set_active (mysrcpad, TRUE); + gst_pad_set_active (mysinkpad, TRUE); + + /* need to know when we are eos */ + gst_pad_set_event_function (mysinkpad, test_sink_event); + + /* and notify the test run */ + mpeg2enc_mutex = g_mutex_new (); + mpeg2enc_cond = g_cond_new (); + + return mpeg2enc; +} + +static void +cleanup_mpeg2enc (GstElement * mpeg2enc) +{ + GST_DEBUG ("cleanup_mpeg2enc"); + gst_element_set_state (mpeg2enc, GST_STATE_NULL); + + gst_pad_set_active (mysrcpad, FALSE); + gst_pad_set_active (mysinkpad, FALSE); + gst_check_teardown_src_pad (mpeg2enc); + gst_check_teardown_sink_pad (mpeg2enc); + gst_check_teardown_element (mpeg2enc); + + g_mutex_free (mpeg2enc_mutex); + g_cond_free (mpeg2enc_cond); +} + +GST_START_TEST (test_video_pad) +{ + GstElement *mpeg2enc; + GstBuffer *inbuffer, *outbuffer; + GstCaps *caps; + int i, num_buffers; + guint8 data0[] = { 0x00, 0x00, 0x01, 0xb3 }; + + + mpeg2enc = setup_mpeg2enc (); + fail_unless (gst_element_set_state (mpeg2enc, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + /* corresponds to I420 buffer for the size mentioned in the caps */ + inbuffer = gst_buffer_new_and_alloc (384 * 288 * 3 / 2); + /* makes valgrind's memcheck happier */ + gst_buffer_memset (inbuffer, 0, 0, -1); + caps = gst_caps_from_string (VIDEO_CAPS_STRING); + gst_pad_set_caps (mysrcpad, caps); + gst_caps_unref (caps); + GST_BUFFER_TIMESTAMP (inbuffer) = 0; + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + + /* need to force eos and state change to make sure the encoding task ends */ + fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()) == TRUE); + /* need to wait a bit to make sure mpeg2enc task digested all this */ + g_mutex_lock (mpeg2enc_mutex); + while (!arrived_eos) + g_cond_wait (mpeg2enc_cond, mpeg2enc_mutex); + g_mutex_unlock (mpeg2enc_mutex); + + num_buffers = g_list_length (buffers); + /* well, we do not really know much with mpeg, but at least something ... */ + fail_unless (num_buffers >= 1); + + /* clean up buffers */ + for (i = 0; i < num_buffers; ++i) { + outbuffer = GST_BUFFER (buffers->data); + fail_if (outbuffer == NULL); + + switch (i) { + case 0: + fail_unless (gst_buffer_get_size (outbuffer) >= sizeof (data0)); + fail_unless (gst_buffer_memcmp (outbuffer, 0, data0, + sizeof (data0)) == 0); + break; + default: + break; + } + buffers = g_list_remove (buffers, outbuffer); + + ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1); + gst_buffer_unref (outbuffer); + outbuffer = NULL; + } + + cleanup_mpeg2enc (mpeg2enc); + g_list_free (buffers); + buffers = NULL; +} + +GST_END_TEST; + +static Suite * +mpeg2enc_suite (void) +{ + Suite *s = suite_create ("mpeg2enc"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_video_pad); + + return s; +} + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = mpeg2enc_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; +} diff --git a/tests/check/elements/mpeg4videoparse.c b/tests/check/elements/mpeg4videoparse.c new file mode 100644 index 00000000..ccddf7f3 --- /dev/null +++ b/tests/check/elements/mpeg4videoparse.c @@ -0,0 +1,200 @@ +/* + * GStreamer + * + * unit test for mpeg4videoparse + * + * Copyright (C) 2011 Nokia Corporation. All rights reserved. + * + * Contact: Stefan Kost <stefan.kost@nokia.com> + * + * 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. + */ + +#include <gst/check/gstcheck.h> +#include "parser.h" + +#define SRC_CAPS_TMPL "video/mpeg, framed=(boolean)false" +#define SINK_CAPS_TMPL "video/mpeg, framed=(boolean)true" + +GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (SINK_CAPS_TMPL) + ); + +GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (SRC_CAPS_TMPL) + ); + +/* some data */ + +/* codec data; VOS up to and including GOP */ +static guint8 mpeg4_config[] = { + 0x00, 0x00, 0x01, 0xb0, 0x01, 0x00, 0x00, 0x01, + 0xb5, 0x89, 0x13, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x20, 0x00, 0xc4, 0x8d, 0x88, 0x00, + 0xf5, 0x01, 0x04, 0x03, 0x14, 0x63, 0x00, 0x00, + 0x01, 0xb3, 0x00, 0x10, 0x07 +}; + +/* keyframes all around */ +static guint8 mpeg4_iframe[] = { + 0x00, 0x00, 0x01, 0xb6, 0x10, 0x60, 0x91, 0x82, + 0x3d, 0xb7, 0xf1, 0xb6, 0xdf, 0xc6, 0xdb, 0x7f, + 0x1b, 0x6d, 0xfb +}; + +static gboolean +verify_buffer (buffer_verify_data_s * vdata, GstBuffer * buffer) +{ + GstMapInfo map; + + gst_buffer_map (buffer, &map, GST_MAP_READ); + + /* header is merged in initial frame */ + if (vdata->buffer_counter == 0) { + /* the whole sequence header is included */ + fail_unless (map.size == ctx_headers[0].size + vdata->data_to_verify_size); + fail_unless (memcmp (map.data, ctx_headers[0].data, + ctx_headers[0].size) == 0); + fail_unless (memcmp (map.data + ctx_headers[0].size, + vdata->data_to_verify, vdata->data_to_verify_size) == 0); + gst_buffer_unmap (buffer, &map); + return TRUE; + } + gst_buffer_unmap (buffer, &map); + + return FALSE; +} + +GST_START_TEST (test_parse_normal) +{ + gst_parser_test_normal (mpeg4_iframe, sizeof (mpeg4_iframe)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_drain_single) +{ + gst_parser_test_drain_single (mpeg4_iframe, sizeof (mpeg4_iframe)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_split) +{ + gst_parser_test_split (mpeg4_iframe, sizeof (mpeg4_iframe)); +} + +GST_END_TEST; + + +#define structure_get_int(s,f) \ + (g_value_get_int(gst_structure_get_value(s,f))) +#define fail_unless_structure_field_int_equals(s,field,num) \ + fail_unless_equals_int (structure_get_int(s,field), num) + +GST_START_TEST (test_parse_detect_stream) +{ + GstCaps *caps; + GstStructure *s; + GstBuffer *buf; + const GValue *val; + GstMapInfo map; + + caps = gst_parser_test_get_output_caps (mpeg4_iframe, sizeof (mpeg4_iframe), + NULL); + fail_unless (caps != NULL); + + /* Check that the negotiated caps are as expected */ + /* When codec_data is present, parser assumes that data is version 4 */ + GST_LOG ("mpeg4video output caps: %" GST_PTR_FORMAT, caps); + s = gst_caps_get_structure (caps, 0); + fail_unless (gst_structure_has_name (s, "video/mpeg")); + fail_unless_structure_field_int_equals (s, "mpegversion", 4); + fail_unless_structure_field_int_equals (s, "width", 32); + fail_unless_structure_field_int_equals (s, "height", 24); + fail_unless (gst_structure_has_field (s, "codec_data")); + + /* check codec-data in more detail */ + val = gst_structure_get_value (s, "codec_data"); + fail_unless (val != NULL); + buf = gst_value_get_buffer (val); + fail_unless (buf != NULL); + /* codec-data == config header - GOP */ + gst_buffer_map (buf, &map, GST_MAP_READ); + fail_unless (map.size == sizeof (mpeg4_config) - 7); + fail_unless (memcmp (map.data, mpeg4_config, map.size) == 0); + gst_buffer_unmap (buf, &map); + + gst_caps_unref (caps); +} + +GST_END_TEST; + + +static Suite * +mpeg4videoparse_suite (void) +{ + Suite *s = suite_create ("mpeg4videoparse"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_parse_normal); + tcase_add_test (tc_chain, test_parse_drain_single); + tcase_add_test (tc_chain, test_parse_split); + tcase_add_test (tc_chain, test_parse_detect_stream); + + return s; +} + + +/* + * TODO: + * - Both push- and pull-modes need to be tested + * * Pull-mode & EOS + */ + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = mpeg4videoparse_suite (); + SRunner *sr = srunner_create (s); + + gst_check_init (&argc, &argv); + + /* init test context */ + ctx_factory = "mpeg4videoparse"; + ctx_sink_template = &sinktemplate; + ctx_src_template = &srctemplate; + ctx_headers[0].data = mpeg4_config; + ctx_headers[0].size = sizeof (mpeg4_config); + ctx_verify_buffer = verify_buffer; + /* no timing info to parse */ + ctx_no_metadata = TRUE; + + srunner_run_all (sr, CK_NORMAL); + nf = srunner_ntests_failed (sr); + srunner_free (sr); + + return nf; +} diff --git a/tests/check/elements/mpegtsmux.c b/tests/check/elements/mpegtsmux.c new file mode 100644 index 00000000..a95cee1a --- /dev/null +++ b/tests/check/elements/mpegtsmux.c @@ -0,0 +1,323 @@ +/* GStreamer + * + * Copyright (C) 2011 Alessandro Decina <alessandro.d@gmail.com> + * + * 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. + */ + +#include <gst/check/gstcheck.h> +#include <string.h> +#include <gst/video/video.h> + +static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +static GstStaticPadTemplate video_src_template = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-h264") + ); + +static GstStaticPadTemplate audio_src_template = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/mpeg") + ); + +typedef struct _TestData +{ + GstEvent *sink_event; + GstEvent *src_event1; + GstEvent *src_event2; + gint src_events; +} TestData; + +typedef struct _ThreadData +{ + GstPad *pad; + GstBuffer *buffer; + GstFlowReturn flow_return; + GThread *thread; +} ThreadData; + +static gboolean +src_event (GstPad * pad, GstObject * parent, GstEvent * event) +{ + TestData *data = (TestData *) gst_pad_get_element_private (pad); + + if (event->type == GST_EVENT_CUSTOM_UPSTREAM) { + data->src_events += 1; + if (data->src_event1 != NULL) + data->src_event2 = event; + else + data->src_event1 = event; + } + + return TRUE; +} + +static gboolean +sink_event (GstPad * pad, GstObject * parent, GstEvent * event) +{ + TestData *data = (TestData *) gst_pad_get_element_private (pad); + + if (event->type == GST_EVENT_CUSTOM_DOWNSTREAM) + data->sink_event = event; + + return TRUE; +} + +static void +link_sinks (GstElement * mpegtsmux, + GstPad ** src1, GstPad ** src2, GstPad ** src3, TestData * test_data) +{ + GstPad *mux_sink1, *mux_sink2, *mux_sink3; + GstCaps *caps; + + /* link 3 sink pads, 2 video 1 audio */ + *src1 = gst_pad_new_from_static_template (&video_src_template, "src1"); + gst_pad_set_active (*src1, TRUE); + gst_pad_set_element_private (*src1, test_data); + gst_pad_set_event_function (*src1, src_event); + mux_sink1 = gst_element_get_request_pad (mpegtsmux, "sink_1"); + fail_unless (gst_pad_link (*src1, mux_sink1) == GST_PAD_LINK_OK); + + *src2 = gst_pad_new_from_static_template (&video_src_template, "src2"); + gst_pad_set_active (*src2, TRUE); + gst_pad_set_element_private (*src2, test_data); + gst_pad_set_event_function (*src2, src_event); + mux_sink2 = gst_element_get_request_pad (mpegtsmux, "sink_2"); + fail_unless (gst_pad_link (*src2, mux_sink2) == GST_PAD_LINK_OK); + + *src3 = gst_pad_new_from_static_template (&audio_src_template, "src3"); + gst_pad_set_active (*src3, TRUE); + gst_pad_set_element_private (*src3, test_data); + gst_pad_set_event_function (*src3, src_event); + mux_sink3 = gst_element_get_request_pad (mpegtsmux, "sink_3"); + fail_unless (gst_pad_link (*src3, mux_sink3) == GST_PAD_LINK_OK); + + caps = gst_caps_new_empty_simple ("video/x-h264"); + gst_pad_set_caps (mux_sink1, caps); + gst_pad_set_caps (mux_sink2, caps); + gst_caps_unref (caps); + caps = gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT, 4, NULL); + gst_pad_set_caps (mux_sink3, caps); + gst_caps_unref (caps); + + gst_object_unref (mux_sink1); + gst_object_unref (mux_sink2); + gst_object_unref (mux_sink3); +} + +static void +link_src (GstElement * mpegtsmux, GstPad ** sink, TestData * test_data) +{ + GstPad *mux_src; + + mux_src = gst_element_get_static_pad (mpegtsmux, "src"); + *sink = gst_pad_new_from_static_template (&sink_template, "sink"); + gst_pad_set_active (*sink, TRUE); + gst_pad_set_event_function (*sink, sink_event); + gst_pad_set_element_private (*sink, test_data); + fail_unless (gst_pad_link (mux_src, *sink) == GST_PAD_LINK_OK); + + gst_object_unref (mux_src); +} + +static gpointer +pad_push_thread (gpointer user_data) +{ + ThreadData *data = (ThreadData *) user_data; + + data->flow_return = gst_pad_push (data->pad, data->buffer); + + return NULL; +} + +static ThreadData * +pad_push (GstPad * pad, GstBuffer * buffer, GstClockTime timestamp) +{ + ThreadData *data; + + data = g_new0 (ThreadData, 1); + data->pad = pad; + data->buffer = buffer; + GST_BUFFER_TIMESTAMP (buffer) = timestamp; + data->thread = g_thread_create (pad_push_thread, data, TRUE, NULL); + + return data; +} + +GST_START_TEST (test_force_key_unit_event_downstream) +{ + GstElement *mpegtsmux; + GstPad *sink; + GstPad *src1; + GstPad *src2; + GstPad *src3; + GstEvent *sink_event; + GstClockTime timestamp, stream_time, running_time; + gboolean all_headers = TRUE; + gint count = 0; + ThreadData *thread_data_1, *thread_data_2, *thread_data_3, *thread_data_4; + TestData test_data = { 0, }; + + mpegtsmux = gst_check_setup_element ("mpegtsmux"); + gst_element_set_state (mpegtsmux, GST_STATE_PLAYING); + + link_src (mpegtsmux, &sink, &test_data); + link_sinks (mpegtsmux, &src1, &src2, &src3, &test_data); + + /* hack: make sure collectpads builds collect->data */ + gst_pad_push_event (src1, gst_event_new_flush_start ()); + gst_pad_push_event (src1, gst_event_new_flush_stop (FALSE)); + + /* send a force-key-unit event with running_time=2s */ + timestamp = stream_time = running_time = 2 * GST_SECOND; + sink_event = gst_video_event_new_downstream_force_key_unit (timestamp, + stream_time, running_time, all_headers, count); + + fail_unless (gst_pad_push_event (src1, sink_event)); + fail_unless (test_data.sink_event == NULL); + + /* push 4 buffers, make sure mpegtsmux handles the force-key-unit event when + * the buffer with the requested running time is collected */ + thread_data_1 = pad_push (src1, gst_buffer_new (), 1 * GST_SECOND); + thread_data_2 = pad_push (src2, gst_buffer_new (), 2 * GST_SECOND); + thread_data_3 = pad_push (src3, gst_buffer_new (), 3 * GST_SECOND); + + g_thread_join (thread_data_1->thread); + fail_unless (test_data.sink_event == NULL); + + /* push again on src1 so that the buffer on src2 is collected */ + thread_data_4 = pad_push (src1, gst_buffer_new (), 4 * GST_SECOND); + + g_thread_join (thread_data_2->thread); + fail_unless (test_data.sink_event != NULL); + + gst_element_set_state (mpegtsmux, GST_STATE_NULL); + + g_thread_join (thread_data_3->thread); + g_thread_join (thread_data_4->thread); + + g_free (thread_data_1); + g_free (thread_data_2); + g_free (thread_data_3); + g_free (thread_data_4); + gst_object_unref (src1); + gst_object_unref (src2); + gst_object_unref (src3); + gst_object_unref (sink); + gst_object_unref (mpegtsmux); +} + +GST_END_TEST; + +GST_START_TEST (test_force_key_unit_event_upstream) +{ + GstElement *mpegtsmux; + GstPad *sink; + GstPad *src1; + GstPad *src2; + GstPad *src3; + GstEvent *event; + GstClockTime timestamp, stream_time, running_time; + gboolean all_headers = TRUE; + gint count = 0; + TestData test_data = { 0, }; + ThreadData *thread_data_1, *thread_data_2, *thread_data_3, *thread_data_4; + + mpegtsmux = gst_check_setup_element ("mpegtsmux"); + gst_element_set_state (mpegtsmux, GST_STATE_PLAYING); + + link_src (mpegtsmux, &sink, &test_data); + link_sinks (mpegtsmux, &src1, &src2, &src3, &test_data); + + /* hack: make sure collectpads builds collect->data */ + gst_pad_push_event (src1, gst_event_new_flush_start ()); + gst_pad_push_event (src1, gst_event_new_flush_stop (FALSE)); + + /* send an upstream force-key-unit event with running_time=2s */ + timestamp = stream_time = running_time = 2 * GST_SECOND; + event = + gst_video_event_new_upstream_force_key_unit (running_time, TRUE, count); + fail_unless (gst_pad_push_event (sink, event)); + + fail_unless (test_data.sink_event == NULL); + fail_unless_equals_int (test_data.src_events, 3); + + /* send downstream events with unrelated seqnums */ + event = gst_video_event_new_downstream_force_key_unit (timestamp, + stream_time, running_time, all_headers, count); + fail_unless (gst_pad_push_event (src1, event)); + event = gst_video_event_new_downstream_force_key_unit (timestamp, + stream_time, running_time, all_headers, count); + fail_unless (gst_pad_push_event (src2, event)); + + /* events should be skipped */ + fail_unless (test_data.sink_event == NULL); + + /* push 4 buffers, make sure mpegtsmux handles the force-key-unit event when + * the buffer with the requested running time is collected */ + thread_data_1 = pad_push (src1, gst_buffer_new (), 1 * GST_SECOND); + thread_data_2 = pad_push (src2, gst_buffer_new (), 2 * GST_SECOND); + thread_data_3 = pad_push (src3, gst_buffer_new (), 3 * GST_SECOND); + + g_thread_join (thread_data_1->thread); + fail_unless (test_data.sink_event == NULL); + + /* push again on src1 so that the buffer on src2 is collected */ + thread_data_4 = pad_push (src1, gst_buffer_new (), 4 * GST_SECOND); + + g_thread_join (thread_data_2->thread); + fail_unless (test_data.sink_event != NULL); + + gst_element_set_state (mpegtsmux, GST_STATE_NULL); + + g_thread_join (thread_data_3->thread); + g_thread_join (thread_data_4->thread); + + g_free (thread_data_1); + g_free (thread_data_2); + g_free (thread_data_3); + g_free (thread_data_4); + + gst_object_unref (src1); + gst_object_unref (src2); + gst_object_unref (src3); + gst_object_unref (sink); + gst_object_unref (mpegtsmux); +} + +GST_END_TEST; + +static Suite * +mpegtsmux_suite (void) +{ + Suite *s = suite_create ("mpegtsmux"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + + tcase_add_test (tc_chain, test_force_key_unit_event_downstream); + tcase_add_test (tc_chain, test_force_key_unit_event_upstream); + + return s; +} + +GST_CHECK_MAIN (mpegtsmux); diff --git a/tests/check/elements/mpegvideoparse.c b/tests/check/elements/mpegvideoparse.c new file mode 100644 index 00000000..fd7a170c --- /dev/null +++ b/tests/check/elements/mpegvideoparse.c @@ -0,0 +1,275 @@ +/* + * GStreamer + * + * unit test for mpegvideoparse + * + * Copyright (C) 2011 Nokia Corporation. All rights reserved. + * + * Contact: Stefan Kost <stefan.kost@nokia.com> + * + * 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. + */ + +#include <gst/check/gstcheck.h> +#include "parser.h" + +#define SRC_CAPS_TMPL "video/mpeg, framed=(boolean)false" +#define SINK_CAPS_TMPL "video/mpeg, framed=(boolean)true" + +GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (SINK_CAPS_TMPL) + ); + +GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (SRC_CAPS_TMPL) + ); + +/* some data */ + +/* actually seq + gop */ +static guint8 mpeg2_seq[] = { + 0x00, 0x00, 0x01, 0xb3, 0x02, 0x00, 0x18, 0x15, + 0xff, 0xff, 0xe0, 0x28, 0x00, 0x00, 0x01, 0xb5, + 0x14, 0x8a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xb8, 0x00, 0x08, 0x00, 0x00 +}; + +/* actually seq + gop */ +static guint8 mpeg1_seq[] = { + 0x00, 0x00, 0x01, 0xb3, 0x02, 0x00, 0x18, 0x15, + 0xff, 0xff, 0xe0, 0x28, 0x00, 0x00, 0x01, 0xb8, + 0x00, 0x08, 00, 00 +}; + +/* keyframes all around */ +static guint8 mpeg2_iframe[] = { + 0x00, 0x00, 0x01, 0x00, 0x00, 0x0f, 0xff, 0xf8, + 0x00, 0x00, 0x01, 0xb5, 0x8f, 0xff, 0xf3, 0x41, + 0x80, 0x00, 0x00, 0x01, 0x01, 0x23, 0xf8, 0x7d, + 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x20, 0x00, + 0x00, 0x01, 0x02, 0x23, 0xf8, 0x7d, 0x29, 0x48, + 0x8b, 0x94, 0xa5, 0x22, 0x20 +}; + +static gboolean +verify_buffer (buffer_verify_data_s * vdata, GstBuffer * buffer) +{ + GstMapInfo map; + + gst_buffer_map (buffer, &map, GST_MAP_READ); + + /* check initial header special case, otherwise delegate to default */ + if (vdata->discard) { + /* header is separate */ + fail_unless (map.size == ctx_headers[0].size - 8); + fail_unless (memcmp (map.data, ctx_headers[0].data, map.size) == 0); + } else { + /* header is merged in initial frame */ + if (vdata->buffer_counter == 0) { + fail_unless (map.size > 4); + if (GST_READ_UINT32_BE (map.data) == 0x1b3) { + /* the whole sequence header is included */ + fail_unless (map.size == + ctx_headers[0].size + vdata->data_to_verify_size); + fail_unless (memcmp (map.data, ctx_headers[0].data, + ctx_headers[0].size) == 0); + fail_unless (memcmp (map.data + ctx_headers[0].size, + vdata->data_to_verify, vdata->data_to_verify_size) == 0); + } else { + /* sequence was separate, only gop here */ + fail_unless (map.size == 8 + vdata->data_to_verify_size); + fail_unless (memcmp (map.data, + ctx_headers[0].data + ctx_headers[0].size - 8, 8) == 0); + fail_unless (memcmp (map.data + 8, + vdata->data_to_verify, vdata->data_to_verify_size) == 0); + } + gst_buffer_unmap (buffer, &map); + return TRUE; + } + } + gst_buffer_unmap (buffer, &map); + + return FALSE; +} + +#define GOP_SPLIT "gop-split" + +static GstElement * +setup_element (const gchar * desc) +{ + GstElement *element; + + if (strcmp (desc, GOP_SPLIT) == 0) { + element = gst_check_setup_element ("mpegvideoparse"); + g_object_set (G_OBJECT (element), "gop-split", TRUE, NULL); + } else { + element = gst_check_setup_element ("mpegvideoparse"); + } + + return element; +} + +GST_START_TEST (test_parse_normal) +{ + gst_parser_test_normal (mpeg2_iframe, sizeof (mpeg2_iframe)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_drain_single) +{ + gst_parser_test_drain_single (mpeg2_iframe, sizeof (mpeg2_iframe)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_split) +{ + gst_parser_test_split (mpeg2_iframe, sizeof (mpeg2_iframe)); +} + +GST_END_TEST; + + +#define structure_get_int(s,f) \ + (g_value_get_int(gst_structure_get_value(s,f))) +#define fail_unless_structure_field_int_equals(s,field,num) \ + fail_unless_equals_int (structure_get_int(s,field), num) + +static void +mpeg_video_parse_check_caps (guint version, guint8 * seq, gint size) +{ + GstCaps *caps; + GstStructure *s; + GstBuffer *buf; + const GValue *val; + GstMapInfo map; + + ctx_headers[0].data = seq; + ctx_headers[0].size = size; + /* parser does not really care that mpeg1 and mpeg2 frame data + * should be a bit different */ + caps = gst_parser_test_get_output_caps (mpeg2_iframe, sizeof (mpeg2_iframe), + NULL); + fail_unless (caps != NULL); + + /* Check that the negotiated caps are as expected */ + /* When codec_data is present, parser assumes that data is version 4 */ + GST_LOG ("mpegvideo output caps: %" GST_PTR_FORMAT, caps); + s = gst_caps_get_structure (caps, 0); + fail_unless (gst_structure_has_name (s, "video/mpeg")); + fail_unless_structure_field_int_equals (s, "mpegversion", version); + fail_unless_structure_field_int_equals (s, "width", 32); + fail_unless_structure_field_int_equals (s, "height", 24); + fail_unless (gst_structure_has_field (s, "codec_data")); + + /* check codec-data in more detail */ + val = gst_structure_get_value (s, "codec_data"); + fail_unless (val != NULL); + buf = gst_value_get_buffer (val); + fail_unless (buf != NULL); + gst_buffer_map (buf, &map, GST_MAP_READ); + /* codec-data = header - GOP */ + assert_equals_int (map.size, size - 8); + fail_unless (memcmp (map.data, seq + 4, map.size) == 0); + gst_buffer_unmap (buf, &map); + + gst_caps_unref (caps); +} + +GST_START_TEST (test_parse_detect_stream_mpeg2) +{ + mpeg_video_parse_check_caps (2, mpeg2_seq, sizeof (mpeg2_seq)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_detect_stream_mpeg1) +{ + mpeg_video_parse_check_caps (1, mpeg1_seq, sizeof (mpeg1_seq)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_gop_split) +{ + ctx_factory = GOP_SPLIT; + ctx_discard = 1; + gst_parser_test_normal (mpeg2_iframe, sizeof (mpeg2_iframe)); + ctx_factory = "mpegvideoparse"; + ctx_discard = 0; +} + +GST_END_TEST; + + +static Suite * +mpegvideoparse_suite (void) +{ + Suite *s = suite_create ("mpegvideoparse"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_parse_normal); + tcase_add_test (tc_chain, test_parse_drain_single); + tcase_add_test (tc_chain, test_parse_split); + tcase_add_test (tc_chain, test_parse_detect_stream_mpeg1); + tcase_add_test (tc_chain, test_parse_detect_stream_mpeg2); + tcase_add_test (tc_chain, test_parse_gop_split); + + return s; +} + + +/* + * TODO: + * - Both push- and pull-modes need to be tested + * * Pull-mode & EOS + */ + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = mpegvideoparse_suite (); + SRunner *sr = srunner_create (s); + + gst_check_init (&argc, &argv); + + /* init test context */ + ctx_factory = "mpegvideoparse"; + ctx_sink_template = &sinktemplate; + ctx_src_template = &srctemplate; + ctx_headers[0].data = mpeg2_seq; + ctx_headers[0].size = sizeof (mpeg2_seq); + ctx_verify_buffer = verify_buffer; + ctx_setup = setup_element; + + srunner_run_all (sr, CK_NORMAL); + nf = srunner_ntests_failed (sr); + srunner_free (sr); + + return nf; +} diff --git a/tests/check/elements/mplex.c b/tests/check/elements/mplex.c new file mode 100644 index 00000000..13a2c277 --- /dev/null +++ b/tests/check/elements/mplex.c @@ -0,0 +1,314 @@ +/* GStreamer + * + * unit test for mplex + * + * Copyright (C) <2008> Mark Nauwelaerts <mnauw@users.sourceforge.net> + * + * 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. + */ + +#include <unistd.h> + +#include <gst/check/gstcheck.h> + +/* For ease of programming we use globals to keep refs for our floating + * src and sink pads we create; otherwise we always have to do get_pad, + * get_peer, and then remove references in every test function */ +static GstPad *mysrcpad, *mysinkpad; + +#define AUDIO_CAPS_STRING "audio/mpeg, " \ + "mpegversion = (int) 1, " \ + "layer = (int) 2, " \ + "rate = (int) 48000, " \ + "channels = (int) 1, " \ + "framerate = (fraction) 25/1" + +#define MPEG_CAPS_STRING "video/mpeg, " \ + "systemstream = (bool) true" + +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (MPEG_CAPS_STRING)); + +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (AUDIO_CAPS_STRING)); + + +/* some global vars, makes it easy as for the ones above */ +static GMutex *mplex_mutex; +static GCond *mplex_cond; +static gboolean arrived_eos; + +/* another easy hack, some mp2 audio data that should please mplex + * perhaps less would also do, but anyway ... + */ +/* begin binary data: */ +guint8 mp2_data[] = /* 384 */ +{ + 0xFF, 0xFD, 0x84, 0xC4, 0x75, 0x56, 0x46, 0x54, 0x54, 0x5B, 0x2E, 0xB0, + 0x80, 0x00, 0x00, 0xAB, 0xAA, 0xAE, 0x8A, 0xAC, 0xB4, 0xD7, 0x9D, 0xB6, + 0xDB, 0x5D, 0xB3, 0xDB, 0x8C, 0xF5, 0xCF, 0x8D, 0x38, 0xD2, 0xFB, 0xF3, + 0x66, 0x59, 0x6C, 0x62, 0x49, 0x16, 0x59, 0x65, 0xAC, 0xE8, 0x8C, 0x6F, + 0x18, 0x48, 0x6B, 0x96, 0xD0, 0xD2, 0x68, 0xA6, 0xC5, 0x42, 0x45, 0xA1, + 0x28, 0x42, 0xBC, 0xA3, 0x99, 0x39, 0x53, 0x20, 0xBA, 0x4A, 0x56, 0x30, + 0xC5, 0x81, 0xE6, 0x16, 0x6B, 0x77, 0x67, 0x24, 0x29, 0xA9, 0x11, 0x7E, + 0xA9, 0xA8, 0x41, 0xE1, 0x11, 0x48, 0x79, 0xB1, 0xC2, 0x30, 0x39, 0x2D, + 0x40, 0x9A, 0xEC, 0x12, 0x65, 0xC5, 0xDD, 0x68, 0x8D, 0x6A, 0xF4, 0x63, + 0x02, 0xAE, 0xE5, 0x1B, 0xAA, 0xA3, 0x87, 0x1B, 0xDE, 0xB8, 0x6B, 0x7A, + 0x9B, 0xAF, 0xF7, 0x1A, 0x39, 0x33, 0x9A, 0x17, 0x56, 0x64, 0x0D, 0xDC, + 0xE2, 0x15, 0xEF, 0x93, 0x24, 0x9A, 0x8E, 0x59, 0x49, 0x7D, 0x45, 0x68, + 0x2D, 0x9F, 0x85, 0x71, 0xA8, 0x99, 0xC4, 0x6D, 0x26, 0x46, 0x40, 0xBA, + 0x9A, 0xD6, 0x3D, 0xCF, 0x45, 0xB2, 0xC6, 0xF3, 0x16, 0x21, 0x8B, 0xA8, + 0xD5, 0x59, 0x78, 0x87, 0xB7, 0x42, 0x9A, 0x65, 0x59, 0x9A, 0x99, 0x58, + 0x71, 0x26, 0x20, 0x33, 0x76, 0xEE, 0x96, 0x70, 0xF2, 0xBC, 0xB3, 0x7D, + 0x6B, 0x35, 0x48, 0x37, 0x59, 0x21, 0xC4, 0x87, 0x8A, 0xD8, 0x05, 0x36, + 0xA5, 0x1A, 0x5C, 0x0A, 0x4F, 0x4B, 0x39, 0x40, 0x39, 0x9A, 0x17, 0xD9, + 0xAD, 0x21, 0xBE, 0x64, 0xB4, 0x6B, 0x13, 0x03, 0x20, 0x95, 0xDA, 0x18, + 0x89, 0x88, 0xB5, 0x44, 0xE2, 0x5D, 0x4F, 0x12, 0x19, 0xC4, 0x1A, 0x1A, + 0x07, 0x07, 0x91, 0xA8, 0x4C, 0x66, 0xB4, 0x81, 0x33, 0xDE, 0xDB, 0xD6, + 0x24, 0x17, 0xD2, 0x9A, 0x4E, 0xC9, 0x88, 0xAB, 0x44, 0xAA, 0x25, 0x4A, + 0x79, 0xA9, 0x39, 0x39, 0x0D, 0x2D, 0x20, 0x76, 0x68, 0x5F, 0x65, 0x25, + 0xCF, 0x29, 0x27, 0x67, 0xB3, 0x68, 0x6C, 0xE5, 0xDC, 0xA5, 0x79, 0xC9, + 0xAB, 0x46, 0x9D, 0x21, 0x35, 0x82, 0x98, 0xBA, 0x0E, 0x26, 0x39, 0x20, + 0xAE, 0x1B, 0x92, 0x3D, 0xF7, 0x9F, 0x29, 0xB5, 0xF3, 0xB6, 0x38, 0x68, + 0x65, 0x99, 0xAD, 0xD8, 0x98, 0x56, 0x5A, 0x61, 0x8D, 0xCB, 0x4A, 0x29, + 0x43, 0x0E, 0x2D, 0x33, 0x40, 0x6A, 0xB7, 0x5F, 0x49, 0xC9, 0x81, 0xE4, + 0x0D, 0x6F, 0x15, 0x58, 0x1B, 0x9E, 0x74, 0x20, 0x5D, 0x97, 0x5B, 0x5A, + 0xDF, 0x92, 0x2D, 0x5A, 0x98, 0xCE, 0x50, 0x20, 0x1A, 0x33, 0x6A, 0x67, + 0xE2, 0x18, 0x94, 0xA4, 0x70, 0x8F, 0x5F, 0x11, 0x85, 0xB0, 0xE5, 0xD8, + 0xD4, 0xAA, 0x86, 0xAE, 0x1C, 0x0D, 0xA1, 0x6B, 0x21, 0xB9, 0xC2, 0x17 +}; + +/* end binary data. size = 384 bytes */ + +static gboolean +test_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) +{ + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_EOS: + g_mutex_lock (mplex_mutex); + arrived_eos = TRUE; + g_cond_signal (mplex_cond); + g_mutex_unlock (mplex_mutex); + break; + default: + break; + } + + return gst_pad_event_default (pad, parent, event); +} + +/* setup and teardown needs some special handling for muxer */ +static GstPad * +setup_src_pad (GstElement * element, + GstStaticPadTemplate * template, GstCaps * caps, const gchar * sinkname) +{ + GstPad *srcpad, *sinkpad; + + GST_DEBUG_OBJECT (element, "setting up sending pad"); + /* sending pad */ + srcpad = gst_pad_new_from_static_template (template, "src"); + fail_if (srcpad == NULL, "Could not create a srcpad"); + ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 1); + + sinkpad = gst_element_get_request_pad (element, sinkname); + fail_if (sinkpad == NULL, "Could not get sink pad from %s", + GST_ELEMENT_NAME (element)); + /* references are owned by: 1) us, 2) mplex, 3) mplex list */ + ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 3); + if (caps) + fail_unless (gst_pad_set_caps (srcpad, caps)); + fail_unless (gst_pad_link (srcpad, sinkpad) == GST_PAD_LINK_OK, + "Could not link source and %s sink pads", GST_ELEMENT_NAME (element)); + gst_object_unref (sinkpad); /* because we got it higher up */ + + /* references are owned by: 1) mplex, 2) mplex list */ + ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2); + + return srcpad; +} + +static void +teardown_src_pad (GstElement * element, const gchar * sinkname) +{ + GstPad *srcpad, *sinkpad; + gchar *padname; + + /* clean up floating src pad */ + padname = g_strdup (sinkname); + memcpy (strchr (padname, '%'), "0", 2); + sinkpad = gst_element_get_static_pad (element, padname); + g_free (padname); + /* pad refs held by 1) mplex 2) mplex list and 3) us (through _get) */ + ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 3); + srcpad = gst_pad_get_peer (sinkpad); + + gst_pad_unlink (srcpad, sinkpad); + + /* after unlinking, pad refs still held by + * 1) mplex and 2) mplex list and 3) us (through _get) */ + ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 3); + gst_object_unref (sinkpad); + /* one more ref is held by element itself */ + + /* pad refs held by both creator and this function (through _get_peer) */ + ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 2); + gst_object_unref (srcpad); + gst_object_unref (srcpad); + +} + +static GstElement * +setup_mplex (void) +{ + GstElement *mplex; + + GST_DEBUG ("setup_mplex"); + mplex = gst_check_setup_element ("mplex"); + mysrcpad = setup_src_pad (mplex, &srctemplate, NULL, "audio_%u"); + mysinkpad = gst_check_setup_sink_pad (mplex, &sinktemplate); + gst_pad_set_active (mysrcpad, TRUE); + gst_pad_set_active (mysinkpad, TRUE); + + /* need to know when we are eos */ + gst_pad_set_event_function (mysinkpad, test_sink_event); + + /* and notify the test run */ + mplex_mutex = g_mutex_new (); + mplex_cond = g_cond_new (); + + return mplex; +} + +static void +cleanup_mplex (GstElement * mplex) +{ + GST_DEBUG ("cleanup_mplex"); + gst_element_set_state (mplex, GST_STATE_NULL); + + gst_pad_set_active (mysrcpad, FALSE); + gst_pad_set_active (mysinkpad, FALSE); + teardown_src_pad (mplex, "audio_%u"); + gst_check_teardown_sink_pad (mplex); + gst_check_teardown_element (mplex); + + g_mutex_free (mplex_mutex); + g_cond_free (mplex_cond); + + gst_deinit (); +} + +GST_START_TEST (test_audio_pad) +{ + GstElement *mplex; + GstBuffer *inbuffer, *outbuffer; + GstCaps *caps; + int i, num_buffers; + + /* PES pack_start_code */ + guint8 data0[] = { 0x00, 0x00, 0x01, 0xba }; + /* MPEG_program_end_code */ + guint8 data1[] = { 0x00, 0x00, 0x01, 0xb9 }; + + mplex = setup_mplex (); + fail_unless (gst_element_set_state (mplex, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + /* corresponds to I420 buffer for the size mentioned in the caps */ + inbuffer = gst_buffer_new_and_alloc (sizeof (mp2_data)); + gst_buffer_fill (inbuffer, 0, mp2_data, sizeof (mp2_data)); + caps = gst_caps_from_string (AUDIO_CAPS_STRING); + gst_pad_set_caps (mysrcpad, caps); + gst_caps_unref (caps); + GST_BUFFER_TIMESTAMP (inbuffer) = 0; + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + + /* need to force eos and state change to make sure the encoding task ends */ + fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()) == TRUE); + /* need to wait a bit to make sure mplex task digested all this */ + g_mutex_lock (mplex_mutex); + while (!arrived_eos) + g_cond_wait (mplex_cond, mplex_mutex); + g_mutex_unlock (mplex_mutex); + + num_buffers = g_list_length (buffers); + /* well, we do not really know much with mplex, but at least something ... */ + fail_unless (num_buffers >= 1); + + /* clean up buffers */ + for (i = 0; i < num_buffers; ++i) { + outbuffer = GST_BUFFER (buffers->data); + fail_if (outbuffer == NULL); + + if (i == 0) { + fail_unless (gst_buffer_get_size (outbuffer) >= sizeof (data0)); + fail_unless (gst_buffer_memcmp (outbuffer, 0, data0, + sizeof (data0)) == 0); + } + if (i == num_buffers - 1) { + fail_unless (gst_buffer_get_size (outbuffer) >= sizeof (data1)); + fail_unless (gst_buffer_memcmp (outbuffer, + gst_buffer_get_size (outbuffer) - sizeof (data1), data1, + sizeof (data1)) == 0); + } + buffers = g_list_remove (buffers, outbuffer); + + ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1); + gst_buffer_unref (outbuffer); + outbuffer = NULL; + } + + cleanup_mplex (mplex); + g_list_free (buffers); + buffers = NULL; +} + +GST_END_TEST; + +static Suite * +mplex_suite (void) +{ + Suite *s = suite_create ("mplex"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_audio_pad); + + return s; +} + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = mplex_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; +} diff --git a/tests/check/elements/mxfdemux.c b/tests/check/elements/mxfdemux.c new file mode 100644 index 00000000..d84ae32a --- /dev/null +++ b/tests/check/elements/mxfdemux.c @@ -0,0 +1,280 @@ +/* GStreamer + * + * unit test for mxfdemux + * + * Copyright (C) <2008> Sebastian Dröge <sebastian.droege@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. + */ + +#include <gst/check/gstcheck.h> +#include <string.h> +#include "mxfdemux.h" + +static GstPad *mysrcpad, *mysinkpad; +static GMainLoop *loop = NULL; +static gboolean have_eos = FALSE; +static gboolean have_data = FALSE; + +static GstStaticPadTemplate mysrctemplate = +GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/mxf")); + +static GstStaticPadTemplate mysinktemplate = +GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +static void +_pad_added (GstElement * element, GstPad * pad, gpointer user_data) +{ + gchar *name = gst_pad_get_name (pad); + + fail_unless_equals_string (name, "track_2"); + fail_unless (gst_pad_link (pad, mysinkpad) == GST_PAD_LINK_OK); + + g_free (name); +} + +static void +_sink_check_caps (GstPad * pad, GstCaps * caps) +{ + GstCaps *tcaps = gst_caps_new_simple ("audio/x-raw", + "rate", G_TYPE_INT, 11025, + "channels", G_TYPE_INT, 1, + "format", G_TYPE_STRING, "U8", + "layout", G_TYPE_STRING, "interleaved", + NULL); + + fail_unless (gst_caps_is_always_compatible (caps, tcaps)); + gst_caps_unref (tcaps); +} + +static GstFlowReturn +_sink_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) +{ + fail_unless_equals_int (gst_buffer_get_size (buffer), sizeof (mxf_essence)); + fail_unless (gst_buffer_memcmp (buffer, 0, mxf_essence, + sizeof (mxf_essence)) == 0); + + fail_unless (GST_BUFFER_TIMESTAMP (buffer) == 0); + fail_unless (GST_BUFFER_DURATION (buffer) == 200 * GST_MSECOND); + + gst_buffer_unref (buffer); + + have_data = TRUE; + return GST_FLOW_OK; +} + +static gboolean +_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) +{ + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_EOS: + if (loop) { + while (!g_main_loop_is_running (loop)); + } + + have_eos = TRUE; + if (loop) + g_main_loop_quit (loop); + break; + case GST_EVENT_CAPS: + { + GstCaps *caps; + + gst_event_parse_caps (event, &caps); + _sink_check_caps (pad, caps); + break; + } + default: + break; + } + + gst_event_unref (event); + + return TRUE; +} + +static GstPad * +_create_sink_pad (void) +{ + mysinkpad = gst_pad_new_from_static_template (&mysinktemplate, "sink"); + + gst_pad_set_chain_function (mysinkpad, _sink_chain); + gst_pad_set_event_function (mysinkpad, _sink_event); + + return mysinkpad; +} + +static GstPad * +_create_src_pad_push (void) +{ + mysrcpad = gst_pad_new_from_static_template (&mysrctemplate, "src"); + + return mysrcpad; +} + +static GstFlowReturn +_src_getrange (GstPad * pad, GstObject * parent, guint64 offset, guint length, + GstBuffer ** buffer) +{ + if (offset + length > sizeof (mxf_file)) + return GST_FLOW_EOS; + + *buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, + (guint8 *) (mxf_file + offset), length, 0, length, NULL, NULL); + + return GST_FLOW_OK; +} + +static gboolean +_src_query (GstPad * pad, GstObject * parent, GstQuery * query) +{ + GstFormat fmt; + + if (GST_QUERY_TYPE (query) != GST_QUERY_DURATION) + return FALSE; + + gst_query_parse_duration (query, &fmt, NULL); + + if (fmt != GST_FORMAT_BYTES) + return FALSE; + + gst_query_set_duration (query, fmt, sizeof (mxf_file)); + + return TRUE; +} + +static GstPad * +_create_src_pad_pull (void) +{ + mysrcpad = gst_pad_new_from_static_template (&mysrctemplate, "src"); + gst_pad_set_getrange_function (mysrcpad, _src_getrange); + gst_pad_set_query_function (mysrcpad, _src_query); + + return mysrcpad; +} + +GST_START_TEST (test_pull) +{ + GstElement *mxfdemux; + GstPad *sinkpad; + + have_eos = FALSE; + have_data = FALSE; + loop = g_main_loop_new (NULL, FALSE); + + mxfdemux = gst_element_factory_make ("mxfdemux", NULL); + fail_unless (mxfdemux != NULL); + g_signal_connect (mxfdemux, "pad-added", G_CALLBACK (_pad_added), NULL); + sinkpad = gst_element_get_static_pad (mxfdemux, "sink"); + fail_unless (sinkpad != NULL); + + mysinkpad = _create_sink_pad (); + fail_unless (mysinkpad != NULL); + mysrcpad = _create_src_pad_pull (); + fail_unless (mysrcpad != NULL); + + fail_unless (gst_pad_link (mysrcpad, sinkpad) == GST_PAD_LINK_OK); + gst_object_unref (sinkpad); + + gst_pad_set_active (mysinkpad, TRUE); + gst_pad_set_active (mysrcpad, TRUE); + + gst_element_set_state (mxfdemux, GST_STATE_PLAYING); + + g_main_loop_run (loop); + fail_unless (have_eos == TRUE); + fail_unless (have_data == TRUE); + + gst_element_set_state (mxfdemux, GST_STATE_NULL); + gst_pad_set_active (mysinkpad, FALSE); + gst_pad_set_active (mysrcpad, FALSE); + + gst_object_unref (mxfdemux); + gst_object_unref (mysinkpad); + gst_object_unref (mysrcpad); + g_main_loop_unref (loop); + loop = NULL; +} + +GST_END_TEST; + +GST_START_TEST (test_push) +{ + GstElement *mxfdemux; + GstBuffer *buffer; + GstPad *sinkpad; + + have_data = FALSE; + have_eos = FALSE; + + mxfdemux = gst_element_factory_make ("mxfdemux", NULL); + fail_unless (mxfdemux != NULL); + g_signal_connect (mxfdemux, "pad-added", G_CALLBACK (_pad_added), NULL); + sinkpad = gst_element_get_static_pad (mxfdemux, "sink"); + fail_unless (sinkpad != NULL); + + buffer = + gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, + (guint8 *) mxf_file, sizeof (mxf_file), 0, sizeof (mxf_file), NULL, NULL); + GST_BUFFER_OFFSET (buffer) = 0; + + mysinkpad = _create_sink_pad (); + fail_unless (mysinkpad != NULL); + mysrcpad = _create_src_pad_push (); + fail_unless (mysrcpad != NULL); + + fail_unless (gst_pad_link (mysrcpad, sinkpad) == GST_PAD_LINK_OK); + gst_object_unref (sinkpad); + + gst_pad_set_active (mysinkpad, TRUE); + gst_pad_set_active (mysrcpad, TRUE); + + gst_element_set_state (mxfdemux, GST_STATE_PLAYING); + + fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK); + fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ())); + + fail_unless (have_eos == TRUE); + fail_unless (have_data == TRUE); + + gst_element_set_state (mxfdemux, GST_STATE_NULL); + gst_pad_set_active (mysinkpad, FALSE); + gst_pad_set_active (mysrcpad, FALSE); + + gst_object_unref (mxfdemux); + gst_object_unref (mysinkpad); + gst_object_unref (mysrcpad); +} + +GST_END_TEST; + +static Suite * +mxfdemux_suite (void) +{ + Suite *s = suite_create ("mxfdemux"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_set_timeout (tc_chain, 180); + tcase_add_test (tc_chain, test_pull); + tcase_add_test (tc_chain, test_push); + + return s; +} + +GST_CHECK_MAIN (mxfdemux); diff --git a/tests/check/elements/mxfdemux.h b/tests/check/elements/mxfdemux.h new file mode 100644 index 00000000..3ad0ed30 --- /dev/null +++ b/tests/check/elements/mxfdemux.h @@ -0,0 +1,2552 @@ +/* Very simple MXF file containing BWF audio. Taken + from the Ingex project. + */ +#include <glib.h> + +static const guint8 mxf_essence[] = { + 0x74, 0x5d, 0x8c, 0x69, 0x74, 0x80, 0x69, 0x80, + 0x5d, 0x80, 0x80, 0x74, 0x8c, 0x69, 0x80, 0x74 +}; + +static const guint8 mxf_file[] = { + 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, + 0x0d, 0x01, 0x02, 0x01, 0x01, 0x02, 0x04, 0x00, + 0x83, 0x00, 0x00, 0x78, 0x00, 0x01, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x4e, 0x3f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x4d, 0x8f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x06, 0x0e, 0x2b, 0x34, + 0x04, 0x01, 0x01, 0x01, 0x0d, 0x01, 0x02, 0x01, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x10, 0x06, 0x0e, 0x2b, 0x34, + 0x04, 0x01, 0x01, 0x03, 0x0d, 0x01, 0x03, 0x01, + 0x02, 0x7f, 0x01, 0x00, 0x06, 0x0e, 0x2b, 0x34, + 0x04, 0x01, 0x01, 0x02, 0x0d, 0x01, 0x03, 0x01, + 0x02, 0x06, 0x01, 0x00, 0x06, 0x0e, 0x2b, 0x34, + 0x02, 0x05, 0x01, 0x01, 0x0d, 0x01, 0x02, 0x01, + 0x01, 0x05, 0x01, 0x00, 0x83, 0x00, 0x03, 0xb0, + 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x12, + 0x01, 0x02, 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, + 0x01, 0x02, 0x05, 0x20, 0x07, 0x01, 0x08, 0x00, + 0x00, 0x00, 0x02, 0x01, 0x06, 0x0e, 0x2b, 0x34, + 0x01, 0x01, 0x01, 0x02, 0x04, 0x07, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x06, 0x0e, + 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, 0x07, 0x02, + 0x02, 0x01, 0x01, 0x03, 0x00, 0x00, 0x10, 0x01, + 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, + 0x06, 0x01, 0x01, 0x04, 0x06, 0x09, 0x00, 0x00, + 0x11, 0x01, 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, + 0x01, 0x02, 0x06, 0x01, 0x01, 0x03, 0x01, 0x00, + 0x00, 0x00, 0x11, 0x02, 0x06, 0x0e, 0x2b, 0x34, + 0x01, 0x01, 0x01, 0x02, 0x06, 0x01, 0x01, 0x03, + 0x02, 0x00, 0x00, 0x00, 0x12, 0x01, 0x06, 0x0e, + 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, 0x07, 0x02, + 0x01, 0x03, 0x01, 0x04, 0x00, 0x00, 0x15, 0x01, + 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, + 0x07, 0x02, 0x01, 0x03, 0x01, 0x05, 0x00, 0x00, + 0x15, 0x02, 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, + 0x01, 0x02, 0x04, 0x04, 0x01, 0x01, 0x02, 0x06, + 0x00, 0x00, 0x15, 0x03, 0x06, 0x0e, 0x2b, 0x34, + 0x01, 0x01, 0x01, 0x01, 0x04, 0x04, 0x01, 0x01, + 0x05, 0x00, 0x00, 0x00, 0x19, 0x01, 0x06, 0x0e, + 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, 0x06, 0x01, + 0x01, 0x04, 0x05, 0x01, 0x00, 0x00, 0x19, 0x02, + 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, + 0x06, 0x01, 0x01, 0x04, 0x05, 0x02, 0x00, 0x00, + 0x27, 0x01, 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, + 0x01, 0x02, 0x06, 0x01, 0x01, 0x06, 0x01, 0x00, + 0x00, 0x00, 0x30, 0x01, 0x06, 0x0e, 0x2b, 0x34, + 0x01, 0x01, 0x01, 0x01, 0x04, 0x06, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x30, 0x02, 0x06, 0x0e, + 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, 0x04, 0x06, + 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x30, 0x04, + 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, + 0x06, 0x01, 0x01, 0x04, 0x01, 0x02, 0x00, 0x00, + 0x30, 0x06, 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, + 0x01, 0x05, 0x06, 0x01, 0x01, 0x03, 0x05, 0x00, + 0x00, 0x00, 0x3b, 0x02, 0x06, 0x0e, 0x2b, 0x34, + 0x01, 0x01, 0x01, 0x02, 0x07, 0x02, 0x01, 0x10, + 0x02, 0x04, 0x00, 0x00, 0x3b, 0x03, 0x06, 0x0e, + 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, 0x06, 0x01, + 0x01, 0x04, 0x02, 0x01, 0x00, 0x00, 0x3b, 0x05, + 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, + 0x03, 0x01, 0x02, 0x01, 0x05, 0x00, 0x00, 0x00, + 0x3b, 0x06, 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, + 0x01, 0x02, 0x06, 0x01, 0x01, 0x04, 0x06, 0x04, + 0x00, 0x00, 0x3b, 0x08, 0x06, 0x0e, 0x2b, 0x34, + 0x01, 0x01, 0x01, 0x04, 0x06, 0x01, 0x01, 0x04, + 0x01, 0x08, 0x00, 0x00, 0x3b, 0x09, 0x06, 0x0e, + 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, 0x01, 0x02, + 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x0a, + 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, + 0x01, 0x02, 0x02, 0x10, 0x02, 0x01, 0x00, 0x00, + 0x3b, 0x0b, 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, + 0x01, 0x05, 0x01, 0x02, 0x02, 0x10, 0x02, 0x02, + 0x00, 0x00, 0x3c, 0x01, 0x06, 0x0e, 0x2b, 0x34, + 0x01, 0x01, 0x01, 0x02, 0x05, 0x20, 0x07, 0x01, + 0x02, 0x01, 0x00, 0x00, 0x3c, 0x02, 0x06, 0x0e, + 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, 0x05, 0x20, + 0x07, 0x01, 0x03, 0x01, 0x00, 0x00, 0x3c, 0x04, + 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, + 0x05, 0x20, 0x07, 0x01, 0x05, 0x01, 0x00, 0x00, + 0x3c, 0x05, 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, + 0x01, 0x02, 0x05, 0x20, 0x07, 0x01, 0x07, 0x00, + 0x00, 0x00, 0x3c, 0x06, 0x06, 0x0e, 0x2b, 0x34, + 0x01, 0x01, 0x01, 0x02, 0x07, 0x02, 0x01, 0x10, + 0x02, 0x03, 0x00, 0x00, 0x3c, 0x09, 0x06, 0x0e, + 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, 0x05, 0x20, + 0x07, 0x01, 0x01, 0x00, 0x00, 0x00, 0x3c, 0x0a, + 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x15, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x3d, 0x01, 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, + 0x01, 0x04, 0x04, 0x02, 0x03, 0x03, 0x04, 0x00, + 0x00, 0x00, 0x3d, 0x02, 0x06, 0x0e, 0x2b, 0x34, + 0x01, 0x01, 0x01, 0x04, 0x04, 0x02, 0x03, 0x01, + 0x04, 0x00, 0x00, 0x00, 0x3d, 0x03, 0x06, 0x0e, + 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, 0x04, 0x02, + 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0x3d, 0x07, + 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, + 0x04, 0x02, 0x01, 0x01, 0x04, 0x00, 0x00, 0x00, + 0x3d, 0x09, 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, + 0x01, 0x05, 0x04, 0x02, 0x03, 0x03, 0x05, 0x00, + 0x00, 0x00, 0x3d, 0x0a, 0x06, 0x0e, 0x2b, 0x34, + 0x01, 0x01, 0x01, 0x05, 0x04, 0x02, 0x03, 0x02, + 0x01, 0x00, 0x00, 0x00, 0x3f, 0x06, 0x06, 0x0e, + 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, 0x01, 0x03, + 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x07, + 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, + 0x01, 0x03, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x44, 0x01, 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x15, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x44, 0x02, 0x06, 0x0e, 0x2b, 0x34, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, 0x02, + 0x01, 0x00, 0x00, 0x00, 0x44, 0x03, 0x06, 0x0e, + 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, 0x06, 0x01, + 0x01, 0x04, 0x06, 0x05, 0x00, 0x00, 0x44, 0x04, + 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, + 0x07, 0x02, 0x01, 0x10, 0x02, 0x05, 0x00, 0x00, + 0x44, 0x05, 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, + 0x01, 0x02, 0x07, 0x02, 0x01, 0x10, 0x01, 0x03, + 0x00, 0x00, 0x47, 0x01, 0x06, 0x0e, 0x2b, 0x34, + 0x01, 0x01, 0x01, 0x02, 0x06, 0x01, 0x01, 0x04, + 0x02, 0x03, 0x00, 0x00, 0x48, 0x01, 0x06, 0x0e, + 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, 0x01, 0x07, + 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, 0x02, + 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, + 0x01, 0x07, 0x01, 0x02, 0x01, 0x00, 0x00, 0x00, + 0x48, 0x03, 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, + 0x01, 0x02, 0x06, 0x01, 0x01, 0x04, 0x02, 0x04, + 0x00, 0x00, 0x48, 0x04, 0x06, 0x0e, 0x2b, 0x34, + 0x01, 0x01, 0x01, 0x02, 0x01, 0x04, 0x01, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x4b, 0x01, 0x06, 0x0e, + 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, 0x05, 0x30, + 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x02, + 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, + 0x07, 0x02, 0x01, 0x03, 0x01, 0x03, 0x00, 0x00, + 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x2f, 0x00, + 0x83, 0x00, 0x00, 0xda, 0x3c, 0x0a, 0x00, 0x10, + 0x5d, 0xce, 0xec, 0x07, 0x72, 0xe0, 0x4b, 0xfd, + 0x95, 0xde, 0x33, 0x15, 0x18, 0x9c, 0x0c, 0x38, + 0x3b, 0x02, 0x00, 0x08, 0x07, 0xd4, 0x04, 0x1a, + 0x0e, 0x12, 0x1d, 0x5c, 0x3b, 0x05, 0x00, 0x02, + 0x01, 0x02, 0x3b, 0x06, 0x00, 0x28, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x1b, 0xe6, + 0x28, 0xa1, 0xa1, 0x47, 0x4c, 0x87, 0xad, 0xc6, + 0x6a, 0xce, 0x8a, 0x93, 0x51, 0xb3, 0x2c, 0xf4, + 0xbc, 0x4e, 0x65, 0x7f, 0x4e, 0x05, 0x87, 0xb4, + 0x4c, 0xfd, 0xaa, 0xe3, 0x0a, 0x2b, 0x3b, 0x0a, + 0x00, 0x28, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x10, 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, + 0x01, 0x03, 0x0d, 0x01, 0x03, 0x01, 0x02, 0x7f, + 0x01, 0x00, 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, + 0x01, 0x02, 0x0d, 0x01, 0x03, 0x01, 0x02, 0x06, + 0x01, 0x00, 0x3b, 0x0b, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x3b, 0x03, + 0x00, 0x10, 0x89, 0x8a, 0x44, 0x70, 0x32, 0x7a, + 0x40, 0xaa, 0x9c, 0x41, 0xc6, 0xc6, 0x3a, 0x64, + 0x77, 0x18, 0x3b, 0x09, 0x00, 0x10, 0x06, 0x0e, + 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, 0x0d, 0x01, + 0x02, 0x01, 0x10, 0x00, 0x00, 0x00, 0x3b, 0x08, + 0x00, 0x10, 0x08, 0x7c, 0x01, 0x83, 0xbe, 0xde, + 0x4f, 0x1e, 0x8b, 0x1e, 0x16, 0x33, 0x6e, 0x35, + 0xc4, 0x5e, 0x01, 0x02, 0x00, 0x10, 0x35, 0xac, + 0x10, 0x04, 0x0e, 0xe7, 0x4e, 0x21, 0x94, 0xbf, + 0x0d, 0xf4, 0xe4, 0xe5, 0x24, 0x14, 0x06, 0x0e, + 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, 0x0d, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x30, 0x00, 0x83, 0x00, + 0x00, 0xc4, 0x3c, 0x01, 0x00, 0x16, 0x00, 0x46, + 0x00, 0x72, 0x00, 0x65, 0x00, 0x65, 0x00, 0x4d, + 0x00, 0x58, 0x00, 0x46, 0x00, 0x2e, 0x00, 0x6f, + 0x00, 0x72, 0x00, 0x67, 0x3c, 0x02, 0x00, 0x28, + 0x00, 0x6d, 0x00, 0x78, 0x00, 0x66, 0x00, 0x77, + 0x00, 0x72, 0x00, 0x61, 0x00, 0x70, 0x00, 0x20, + 0x00, 0x66, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x65, + 0x00, 0x20, 0x00, 0x77, 0x00, 0x72, 0x00, 0x61, + 0x00, 0x70, 0x00, 0x70, 0x00, 0x65, 0x00, 0x72, + 0x3c, 0x04, 0x00, 0x32, 0x00, 0x55, 0x00, 0x6e, + 0x00, 0x72, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x65, + 0x00, 0x61, 0x00, 0x73, 0x00, 0x65, 0x00, 0x64, + 0x00, 0x20, 0x00, 0x6d, 0x00, 0x78, 0x00, 0x66, + 0x00, 0x6c, 0x00, 0x69, 0x00, 0x62, 0x00, 0x20, + 0x00, 0x30, 0x00, 0x2e, 0x00, 0x33, 0x00, 0x2e, + 0x00, 0x33, 0x00, 0x2e, 0x00, 0x31, 0x3c, 0x05, + 0x00, 0x10, 0x84, 0x66, 0x14, 0xf3, 0x27, 0xdd, + 0xde, 0x40, 0x86, 0xdc, 0xe0, 0x99, 0xda, 0x7f, + 0xd0, 0x52, 0x3c, 0x06, 0x00, 0x08, 0x07, 0xd4, + 0x04, 0x1a, 0x0e, 0x12, 0x1d, 0x57, 0x3c, 0x0a, + 0x00, 0x10, 0x1b, 0xe6, 0x28, 0xa1, 0xa1, 0x47, + 0x4c, 0x87, 0xad, 0xc6, 0x6a, 0xce, 0x8a, 0x93, + 0x51, 0xb3, 0x3c, 0x09, 0x00, 0x10, 0x3f, 0x12, + 0xad, 0x30, 0x44, 0xea, 0x40, 0xe2, 0xbe, 0x1c, + 0x1a, 0x48, 0xe6, 0x0c, 0xc7, 0x13, 0x06, 0x0e, + 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, 0x0d, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x30, 0x00, 0x83, 0x00, + 0x00, 0xc4, 0x3c, 0x01, 0x00, 0x16, 0x00, 0x46, + 0x00, 0x72, 0x00, 0x65, 0x00, 0x65, 0x00, 0x4d, + 0x00, 0x58, 0x00, 0x46, 0x00, 0x2e, 0x00, 0x6f, + 0x00, 0x72, 0x00, 0x67, 0x3c, 0x02, 0x00, 0x28, + 0x00, 0x6d, 0x00, 0x78, 0x00, 0x66, 0x00, 0x77, + 0x00, 0x72, 0x00, 0x61, 0x00, 0x70, 0x00, 0x20, + 0x00, 0x66, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x65, + 0x00, 0x20, 0x00, 0x77, 0x00, 0x72, 0x00, 0x61, + 0x00, 0x70, 0x00, 0x70, 0x00, 0x65, 0x00, 0x72, + 0x3c, 0x04, 0x00, 0x32, 0x00, 0x55, 0x00, 0x6e, + 0x00, 0x72, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x65, + 0x00, 0x61, 0x00, 0x73, 0x00, 0x65, 0x00, 0x64, + 0x00, 0x20, 0x00, 0x6d, 0x00, 0x78, 0x00, 0x66, + 0x00, 0x6c, 0x00, 0x69, 0x00, 0x62, 0x00, 0x20, + 0x00, 0x30, 0x00, 0x2e, 0x00, 0x33, 0x00, 0x2e, + 0x00, 0x33, 0x00, 0x2e, 0x00, 0x31, 0x3c, 0x05, + 0x00, 0x10, 0x84, 0x66, 0x14, 0xf3, 0x27, 0xdd, + 0xde, 0x40, 0x86, 0xdc, 0xe0, 0x99, 0xda, 0x7f, + 0xd0, 0x52, 0x3c, 0x06, 0x00, 0x08, 0x07, 0xd4, + 0x04, 0x1a, 0x0e, 0x12, 0x1d, 0x5c, 0x3c, 0x0a, + 0x00, 0x10, 0x2c, 0xf4, 0xbc, 0x4e, 0x65, 0x7f, + 0x4e, 0x05, 0x87, 0xb4, 0x4c, 0xfd, 0xaa, 0xe3, + 0x0a, 0x2b, 0x3c, 0x09, 0x00, 0x10, 0x35, 0xac, + 0x10, 0x04, 0x0e, 0xe7, 0x4e, 0x21, 0x94, 0xbf, + 0x0d, 0xf4, 0xe4, 0xe5, 0x24, 0x14, 0x06, 0x0e, + 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, 0x0d, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x18, 0x00, 0x83, 0x00, + 0x00, 0x5c, 0x19, 0x01, 0x00, 0x28, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0xc0, 0x7c, + 0x8b, 0x06, 0x0e, 0xe3, 0x4b, 0x75, 0x9f, 0xfb, + 0x89, 0x05, 0xa4, 0x6f, 0xda, 0x18, 0x08, 0x7c, + 0x01, 0x83, 0xbe, 0xde, 0x4f, 0x1e, 0x8b, 0x1e, + 0x16, 0x33, 0x6e, 0x35, 0xc4, 0x5e, 0x19, 0x02, + 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x10, 0x0f, 0x46, 0xb4, 0x10, 0x8b, 0xa9, + 0x45, 0xa2, 0xa4, 0x0a, 0x17, 0x5b, 0x0b, 0x62, + 0x50, 0xf3, 0x3c, 0x0a, 0x00, 0x10, 0x89, 0x8a, + 0x44, 0x70, 0x32, 0x7a, 0x40, 0xaa, 0x9c, 0x41, + 0xc6, 0xc6, 0x3a, 0x64, 0x77, 0x18, 0x06, 0x0e, + 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, 0x0d, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x36, 0x00, 0x83, 0x00, + 0x00, 0xa4, 0x44, 0x02, 0x00, 0x24, 0x00, 0x41, + 0x00, 0x20, 0x00, 0x4d, 0x00, 0x61, 0x00, 0x74, + 0x00, 0x65, 0x00, 0x72, 0x00, 0x69, 0x00, 0x61, + 0x00, 0x6c, 0x00, 0x20, 0x00, 0x50, 0x00, 0x61, + 0x00, 0x63, 0x00, 0x6b, 0x00, 0x61, 0x00, 0x67, + 0x00, 0x65, 0x44, 0x01, 0x00, 0x20, 0x06, 0x0a, + 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, 0x01, 0x01, + 0x0d, 0x20, 0x13, 0x00, 0x00, 0x00, 0x9a, 0xb6, + 0x5c, 0xc0, 0xf9, 0x54, 0x41, 0x20, 0xa4, 0x2d, + 0xa5, 0xf3, 0x4b, 0x6c, 0x3d, 0xd7, 0x44, 0x05, + 0x00, 0x08, 0x07, 0xd4, 0x04, 0x1a, 0x0e, 0x12, + 0x1d, 0x57, 0x44, 0x04, 0x00, 0x08, 0x07, 0xd4, + 0x04, 0x1a, 0x0e, 0x12, 0x1d, 0x57, 0x44, 0x03, + 0x00, 0x28, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x10, 0x9e, 0x69, 0xd9, 0x47, 0x1a, 0x63, + 0x45, 0xd7, 0xa3, 0x85, 0xc5, 0x79, 0xfa, 0x48, + 0x3f, 0xcf, 0x3a, 0x21, 0x3b, 0xc8, 0x7b, 0xb9, + 0x40, 0xbd, 0xa0, 0x54, 0x14, 0x4f, 0x38, 0x34, + 0xe8, 0x08, 0x3c, 0x0a, 0x00, 0x10, 0xc0, 0x7c, + 0x8b, 0x06, 0x0e, 0xe3, 0x4b, 0x75, 0x9f, 0xfb, + 0x89, 0x05, 0xa4, 0x6f, 0xda, 0x18, 0x06, 0x0e, + 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, 0x0d, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x3b, 0x00, 0x83, 0x00, + 0x00, 0x70, 0x48, 0x02, 0x00, 0x1c, 0x00, 0x54, + 0x00, 0x69, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x63, + 0x00, 0x6f, 0x00, 0x64, 0x00, 0x65, 0x00, 0x20, + 0x00, 0x54, 0x00, 0x72, 0x00, 0x61, 0x00, 0x63, + 0x00, 0x6b, 0x48, 0x04, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x4b, 0x02, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x01, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x01, 0x48, 0x01, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x01, 0x48, 0x03, 0x00, 0x10, 0xb1, 0x5d, + 0x1a, 0xad, 0x9e, 0x13, 0x4f, 0x9d, 0x89, 0xa6, + 0x28, 0x00, 0x6f, 0x0b, 0x23, 0xd7, 0x3c, 0x0a, + 0x00, 0x10, 0x9e, 0x69, 0xd9, 0x47, 0x1a, 0x63, + 0x45, 0xd7, 0xa3, 0x85, 0xc5, 0x79, 0xfa, 0x48, + 0x3f, 0xcf, 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, + 0x01, 0x01, 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x0f, 0x00, 0x83, 0x00, 0x00, 0x64, 0x02, 0x01, + 0x00, 0x10, 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, + 0x01, 0x01, 0x01, 0x03, 0x02, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x02, 0x02, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x01, + 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x10, 0xa4, 0x5f, 0x10, 0x3a, 0x63, 0x79, + 0x45, 0x56, 0xb6, 0x65, 0x17, 0x2d, 0xf2, 0xf0, + 0x0e, 0x6e, 0x3c, 0x0a, 0x00, 0x10, 0xb1, 0x5d, + 0x1a, 0xad, 0x9e, 0x13, 0x4f, 0x9d, 0x89, 0xa6, + 0x28, 0x00, 0x6f, 0x0b, 0x23, 0xd7, 0x01, 0x02, + 0x00, 0x10, 0x35, 0xac, 0x10, 0x04, 0x0e, 0xe7, + 0x4e, 0x21, 0x94, 0xbf, 0x0d, 0xf4, 0xe4, 0xe5, + 0x24, 0x14, 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, + 0x01, 0x01, 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x14, 0x00, 0x83, 0x00, 0x00, 0x5f, 0x15, 0x02, + 0x00, 0x02, 0x00, 0x05, 0x15, 0x03, 0x00, 0x01, + 0x00, 0x15, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x3c, 0x0a, 0x00, 0x10, 0xa4, 0x5f, 0x10, + 0x3a, 0x63, 0x79, 0x45, 0x56, 0xb6, 0x65, 0x17, + 0x2d, 0xf2, 0xf0, 0x0e, 0x6e, 0x02, 0x01, 0x00, + 0x10, 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, + 0x01, 0x01, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x00, 0x10, 0x35, 0xac, 0x10, + 0x04, 0x0e, 0xe7, 0x4e, 0x21, 0x94, 0xbf, 0x0d, + 0xf4, 0xe4, 0xe5, 0x24, 0x14, 0x06, 0x0e, 0x2b, + 0x34, 0x02, 0x53, 0x01, 0x01, 0x0d, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x3b, 0x00, 0x83, 0x00, 0x00, + 0x6a, 0x48, 0x02, 0x00, 0x16, 0x00, 0x53, 0x00, + 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, + 0x20, 0x00, 0x54, 0x00, 0x72, 0x00, 0x61, 0x00, + 0x63, 0x00, 0x6b, 0x48, 0x04, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x4b, 0x02, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, + 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x00, 0x00, 0x01, 0x48, 0x01, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x02, 0x48, 0x03, 0x00, 0x10, 0xbf, + 0x20, 0x73, 0x31, 0xe2, 0xc5, 0x45, 0x47, 0x9b, + 0xe1, 0x1a, 0x07, 0x89, 0x94, 0x97, 0xef, 0x3c, + 0x0a, 0x00, 0x10, 0x3a, 0x21, 0x3b, 0xc8, 0x7b, + 0xb9, 0x40, 0xbd, 0xa0, 0x54, 0x14, 0x4f, 0x38, + 0x34, 0xe8, 0x08, 0x06, 0x0e, 0x2b, 0x34, 0x02, + 0x53, 0x01, 0x01, 0x0d, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x0f, 0x00, 0x83, 0x00, 0x00, 0x64, 0x02, + 0x01, 0x00, 0x10, 0x06, 0x0e, 0x2b, 0x34, 0x04, + 0x01, 0x01, 0x01, 0x01, 0x03, 0x02, 0x02, 0x02, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, + 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x10, 0x9b, 0x27, 0xfe, 0xda, 0x8d, + 0x2f, 0x45, 0x72, 0xaf, 0x06, 0xf6, 0x99, 0xb8, + 0xc8, 0x9e, 0xb5, 0x3c, 0x0a, 0x00, 0x10, 0xbf, + 0x20, 0x73, 0x31, 0xe2, 0xc5, 0x45, 0x47, 0x9b, + 0xe1, 0x1a, 0x07, 0x89, 0x94, 0x97, 0xef, 0x01, + 0x02, 0x00, 0x10, 0x35, 0xac, 0x10, 0x04, 0x0e, + 0xe7, 0x4e, 0x21, 0x94, 0xbf, 0x0d, 0xf4, 0xe4, + 0xe5, 0x24, 0x14, 0x06, 0x0e, 0x2b, 0x34, 0x02, + 0x53, 0x01, 0x01, 0x0d, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x11, 0x00, 0x83, 0x00, 0x00, 0x80, 0x02, + 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x11, 0x01, 0x00, 0x20, 0x06, + 0x0a, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x02, 0x20, 0x13, 0x00, 0x00, 0x00, 0x14, + 0x5d, 0x1e, 0x9f, 0x7a, 0x3f, 0x41, 0x03, 0xad, + 0xb6, 0x24, 0x9c, 0x87, 0x0d, 0x7e, 0xc3, 0x11, + 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x12, + 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3c, 0x0a, 0x00, 0x10, 0x9b, + 0x27, 0xfe, 0xda, 0x8d, 0x2f, 0x45, 0x72, 0xaf, + 0x06, 0xf6, 0x99, 0xb8, 0xc8, 0x9e, 0xb5, 0x02, + 0x01, 0x00, 0x10, 0x06, 0x0e, 0x2b, 0x34, 0x04, + 0x01, 0x01, 0x01, 0x01, 0x03, 0x02, 0x02, 0x02, + 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x10, 0x35, + 0xac, 0x10, 0x04, 0x0e, 0xe7, 0x4e, 0x21, 0x94, + 0xbf, 0x0d, 0xf4, 0xe4, 0xe5, 0x24, 0x14, 0x06, + 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, 0x0d, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x37, 0x00, 0x83, + 0x00, 0x00, 0xfe, 0x44, 0x02, 0x00, 0x6a, 0x00, + 0x46, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x65, 0x00, + 0x20, 0x00, 0x50, 0x00, 0x61, 0x00, 0x63, 0x00, + 0x6b, 0x00, 0x61, 0x00, 0x67, 0x00, 0x65, 0x00, + 0x3a, 0x00, 0x20, 0x00, 0x53, 0x00, 0x4d, 0x00, + 0x50, 0x00, 0x54, 0x00, 0x45, 0x00, 0x20, 0x00, + 0x33, 0x00, 0x38, 0x00, 0x32, 0x00, 0x4d, 0x00, + 0x20, 0x00, 0x66, 0x00, 0x72, 0x00, 0x61, 0x00, + 0x6d, 0x00, 0x65, 0x00, 0x20, 0x00, 0x77, 0x00, + 0x72, 0x00, 0x61, 0x00, 0x70, 0x00, 0x70, 0x00, + 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x20, 0x00, + 0x6f, 0x00, 0x66, 0x00, 0x20, 0x00, 0x77, 0x00, + 0x61, 0x00, 0x76, 0x00, 0x65, 0x00, 0x20, 0x00, + 0x61, 0x00, 0x75, 0x00, 0x64, 0x00, 0x69, 0x00, + 0x6f, 0x44, 0x01, 0x00, 0x20, 0x06, 0x0a, 0x2b, + 0x34, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, + 0x20, 0x13, 0x00, 0x00, 0x00, 0x14, 0x5d, 0x1e, + 0x9f, 0x7a, 0x3f, 0x41, 0x03, 0xad, 0xb6, 0x24, + 0x9c, 0x87, 0x0d, 0x7e, 0xc3, 0x44, 0x05, 0x00, + 0x08, 0x07, 0xd4, 0x04, 0x1a, 0x0e, 0x12, 0x1d, + 0x57, 0x44, 0x04, 0x00, 0x08, 0x07, 0xd4, 0x04, + 0x1a, 0x0e, 0x12, 0x1d, 0x57, 0x44, 0x03, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x10, 0xf2, 0xbf, 0xb3, 0x60, 0x10, 0xb7, 0x49, + 0xa7, 0xaf, 0x2e, 0xc4, 0xfa, 0x62, 0x19, 0xbc, + 0x01, 0x2a, 0xae, 0x1e, 0xb3, 0xc5, 0xa0, 0x4d, + 0xa5, 0xb1, 0x78, 0xf1, 0xeb, 0x9a, 0x68, 0xf0, + 0x8c, 0x3c, 0x0a, 0x00, 0x10, 0x08, 0x7c, 0x01, + 0x83, 0xbe, 0xde, 0x4f, 0x1e, 0x8b, 0x1e, 0x16, + 0x33, 0x6e, 0x35, 0xc4, 0x5e, 0x47, 0x01, 0x00, + 0x10, 0xc4, 0xe1, 0xba, 0xb5, 0x66, 0x8d, 0x4f, + 0x3c, 0xb4, 0x16, 0x78, 0x06, 0x26, 0x4d, 0xc6, + 0xe8, 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, + 0x01, 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x3b, + 0x00, 0x83, 0x00, 0x00, 0x70, 0x48, 0x02, 0x00, + 0x1c, 0x00, 0x54, 0x00, 0x69, 0x00, 0x6d, 0x00, + 0x65, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x64, 0x00, + 0x65, 0x00, 0x20, 0x00, 0x54, 0x00, 0x72, 0x00, + 0x61, 0x00, 0x63, 0x00, 0x6b, 0x48, 0x04, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x02, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x4b, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x01, 0x48, 0x01, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x48, 0x03, 0x00, + 0x10, 0x77, 0xb2, 0x7d, 0x53, 0xcb, 0xef, 0x43, + 0x1c, 0x84, 0xbd, 0xe6, 0x42, 0x59, 0x0e, 0x92, + 0xcc, 0x3c, 0x0a, 0x00, 0x10, 0xf2, 0xbf, 0xb3, + 0x60, 0x10, 0xb7, 0x49, 0xa7, 0xaf, 0x2e, 0xc4, + 0xfa, 0x62, 0x19, 0xbc, 0x01, 0x06, 0x0e, 0x2b, + 0x34, 0x02, 0x53, 0x01, 0x01, 0x0d, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x0f, 0x00, 0x83, 0x00, 0x00, + 0x64, 0x02, 0x01, 0x00, 0x10, 0x06, 0x0e, 0x2b, + 0x34, 0x04, 0x01, 0x01, 0x01, 0x01, 0x03, 0x02, + 0x01, 0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x10, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x10, 0x6d, 0x85, 0x87, + 0x23, 0xb9, 0x0e, 0x4d, 0x67, 0x8d, 0xd8, 0xe1, + 0x28, 0xf2, 0x4b, 0xbc, 0xf5, 0x3c, 0x0a, 0x00, + 0x10, 0x77, 0xb2, 0x7d, 0x53, 0xcb, 0xef, 0x43, + 0x1c, 0x84, 0xbd, 0xe6, 0x42, 0x59, 0x0e, 0x92, + 0xcc, 0x01, 0x02, 0x00, 0x10, 0x35, 0xac, 0x10, + 0x04, 0x0e, 0xe7, 0x4e, 0x21, 0x94, 0xbf, 0x0d, + 0xf4, 0xe4, 0xe5, 0x24, 0x14, 0x06, 0x0e, 0x2b, + 0x34, 0x02, 0x53, 0x01, 0x01, 0x0d, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x14, 0x00, 0x83, 0x00, 0x00, + 0x5f, 0x15, 0x02, 0x00, 0x02, 0x00, 0x05, 0x15, + 0x03, 0x00, 0x01, 0x00, 0x15, 0x01, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x50, + 0x02, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x3c, 0x0a, 0x00, 0x10, + 0x6d, 0x85, 0x87, 0x23, 0xb9, 0x0e, 0x4d, 0x67, + 0x8d, 0xd8, 0xe1, 0x28, 0xf2, 0x4b, 0xbc, 0xf5, + 0x02, 0x01, 0x00, 0x10, 0x06, 0x0e, 0x2b, 0x34, + 0x04, 0x01, 0x01, 0x01, 0x01, 0x03, 0x02, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x10, + 0x35, 0xac, 0x10, 0x04, 0x0e, 0xe7, 0x4e, 0x21, + 0x94, 0xbf, 0x0d, 0xf4, 0xe4, 0xe5, 0x24, 0x14, + 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x3b, 0x00, + 0x83, 0x00, 0x00, 0x6a, 0x48, 0x02, 0x00, 0x16, + 0x00, 0x53, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, + 0x00, 0x64, 0x00, 0x20, 0x00, 0x54, 0x00, 0x72, + 0x00, 0x61, 0x00, 0x63, 0x00, 0x6b, 0x48, 0x04, + 0x00, 0x04, 0x16, 0x01, 0x01, 0x01, 0x4b, 0x02, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x4b, 0x01, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x48, 0x01, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x48, 0x03, + 0x00, 0x10, 0xf2, 0x67, 0xd5, 0x27, 0x0f, 0xbd, + 0x45, 0x55, 0xa0, 0x3e, 0x35, 0x52, 0xae, 0x31, + 0x7c, 0x4a, 0x3c, 0x0a, 0x00, 0x10, 0x2a, 0xae, + 0x1e, 0xb3, 0xc5, 0xa0, 0x4d, 0xa5, 0xb1, 0x78, + 0xf1, 0xeb, 0x9a, 0x68, 0xf0, 0x8c, 0x06, 0x0e, + 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, 0x0d, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x0f, 0x00, 0x83, 0x00, + 0x00, 0x64, 0x02, 0x01, 0x00, 0x10, 0x06, 0x0e, + 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, 0x01, 0x03, + 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x10, 0x01, 0x00, 0x18, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0xdf, 0x85, + 0x49, 0x8b, 0x72, 0x43, 0x4b, 0xa4, 0xa2, 0x4e, + 0xfa, 0xed, 0xd8, 0x7a, 0xa0, 0x0d, 0x3c, 0x0a, + 0x00, 0x10, 0xf2, 0x67, 0xd5, 0x27, 0x0f, 0xbd, + 0x45, 0x55, 0xa0, 0x3e, 0x35, 0x52, 0xae, 0x31, + 0x7c, 0x4a, 0x01, 0x02, 0x00, 0x10, 0x35, 0xac, + 0x10, 0x04, 0x0e, 0xe7, 0x4e, 0x21, 0x94, 0xbf, + 0x0d, 0xf4, 0xe4, 0xe5, 0x24, 0x14, 0x06, 0x0e, + 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, 0x0d, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x11, 0x00, 0x83, 0x00, + 0x00, 0x80, 0x02, 0x02, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x01, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x11, 0x02, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x12, 0x01, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x0a, + 0x00, 0x10, 0xdf, 0x85, 0x49, 0x8b, 0x72, 0x43, + 0x4b, 0xa4, 0xa2, 0x4e, 0xfa, 0xed, 0xd8, 0x7a, + 0xa0, 0x0d, 0x02, 0x01, 0x00, 0x10, 0x06, 0x0e, + 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, 0x01, 0x03, + 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x00, 0x10, 0x35, 0xac, 0x10, 0x04, 0x0e, 0xe7, + 0x4e, 0x21, 0x94, 0xbf, 0x0d, 0xf4, 0xe4, 0xe5, + 0x24, 0x14, 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, + 0x01, 0x01, 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x48, 0x00, 0x83, 0x00, 0x00, 0x8b, 0x30, 0x01, + 0x00, 0x08, 0x00, 0x00, 0x2b, 0x11, 0x00, 0x00, + 0x00, 0x01, 0x3d, 0x03, 0x00, 0x08, 0x00, 0x00, + 0x2b, 0x11, 0x00, 0x00, 0x00, 0x01, 0x3d, 0x02, + 0x00, 0x01, 0x00, 0x3d, 0x07, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x01, 0x3d, 0x01, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x08, 0x3d, 0x0a, 0x00, 0x02, 0x00, + 0x01, 0x3d, 0x09, 0x00, 0x04, 0x00, 0x00, 0x2b, + 0x11, 0x30, 0x04, 0x00, 0x10, 0x06, 0x0e, 0x2b, + 0x34, 0x04, 0x01, 0x01, 0x02, 0x0d, 0x01, 0x03, + 0x01, 0x02, 0x06, 0x01, 0x00, 0x30, 0x06, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x02, 0x3c, 0x0a, 0x00, + 0x10, 0xc4, 0xe1, 0xba, 0xb5, 0x66, 0x8d, 0x4f, + 0x3c, 0xb4, 0x16, 0x78, 0x06, 0x26, 0x4d, 0xc6, + 0xe8, 0x30, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, + 0x10, 0x35, 0xac, 0x10, 0x04, 0x0e, 0xe7, 0x4e, + 0x21, 0x94, 0xbf, 0x0d, 0xf4, 0xe4, 0xe5, 0x24, + 0x14, 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, + 0x01, 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x23, + 0x00, 0x83, 0x00, 0x00, 0x5c, 0x27, 0x01, 0x00, + 0x20, 0x06, 0x0a, 0x2b, 0x34, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x02, 0x20, 0x13, 0x00, 0x00, + 0x00, 0x14, 0x5d, 0x1e, 0x9f, 0x7a, 0x3f, 0x41, + 0x03, 0xad, 0xb6, 0x24, 0x9c, 0x87, 0x0d, 0x7e, + 0xc3, 0x3f, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x3c, 0x0a, 0x00, 0x10, 0x0f, 0x46, 0xb4, + 0x10, 0x8b, 0xa9, 0x45, 0xa2, 0xa4, 0x0a, 0x17, + 0x5b, 0x0b, 0x62, 0x50, 0xf3, 0x3f, 0x06, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x81, 0x01, 0x02, 0x00, + 0x10, 0x35, 0xac, 0x10, 0x04, 0x0e, 0xe7, 0x4e, + 0x21, 0x94, 0xbf, 0x0d, 0xf4, 0xe4, 0xe5, 0x24, + 0x14, 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, + 0x01, 0x03, 0x01, 0x02, 0x10, 0x01, 0x00, 0x00, + 0x00, 0x83, 0x00, 0x3d, 0xde, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x0e, 0x2b, 0x34, 0x01, + 0x02, 0x01, 0x01, 0x0d, 0x01, 0x03, 0x01, 0x16, + 0x01, 0x01, 0x01, 0x83, 0x00, 0x00, 0x10, 0x74, + 0x5d, 0x8c, 0x69, 0x74, 0x80, 0x69, 0x80, 0x5d, + 0x80, 0x80, 0x74, 0x8c, 0x69, 0x80, 0x74, 0x06, + 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, 0x0d, + 0x01, 0x02, 0x01, 0x01, 0x04, 0x04, 0x00, 0x83, + 0x00, 0x00, 0x78, 0x00, 0x01, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x4e, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x4e, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x81, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x0e, 0x2b, 0x34, 0x04, + 0x01, 0x01, 0x01, 0x0d, 0x01, 0x02, 0x01, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x10, 0x06, 0x0e, 0x2b, 0x34, 0x04, + 0x01, 0x01, 0x03, 0x0d, 0x01, 0x03, 0x01, 0x02, + 0x7f, 0x01, 0x00, 0x06, 0x0e, 0x2b, 0x34, 0x04, + 0x01, 0x01, 0x02, 0x0d, 0x01, 0x03, 0x01, 0x02, + 0x06, 0x01, 0x00, 0x06, 0x0e, 0x2b, 0x34, 0x02, + 0x53, 0x01, 0x01, 0x0d, 0x01, 0x02, 0x01, 0x01, + 0x10, 0x01, 0x00, 0x83, 0x00, 0x00, 0x50, 0x3c, + 0x0a, 0x00, 0x10, 0xba, 0xc8, 0x72, 0x86, 0xb4, + 0xc4, 0x43, 0x30, 0x95, 0x5c, 0x3d, 0x89, 0x2a, + 0x7a, 0xfc, 0x01, 0x3f, 0x0b, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x3f, + 0x0c, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3f, 0x0d, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, + 0x05, 0x00, 0x04, 0x00, 0x00, 0x08, 0x9d, 0x3f, + 0x06, 0x00, 0x04, 0x00, 0x00, 0x00, 0x81, 0x3f, + 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x06, + 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, 0x0d, + 0x01, 0x02, 0x01, 0x01, 0x11, 0x01, 0x00, 0x83, + 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x4e, 0x3f, 0x00, 0x00, 0x00, 0x30, +}; diff --git a/tests/check/elements/mxfmux.c b/tests/check/elements/mxfmux.c new file mode 100644 index 00000000..f8c931e2 --- /dev/null +++ b/tests/check/elements/mxfmux.c @@ -0,0 +1,261 @@ +/* GStreamer + * + * unit test for mxfmux + * + * Copyright (C) <2009> Sebastian Dröge <sebastian.droege@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. + */ + +#include <gst/check/gstcheck.h> +#include <string.h> + +static const gchar * +get_mpeg2enc_element_name (void) +{ + GstElementFactory *factory = NULL; + + if ((factory = gst_element_factory_find ("mpeg2enc"))) { + gst_object_unref (factory); + return "mpeg2enc"; + } else if ((factory = gst_element_factory_find ("ffenc_mpeg2video"))) { + gst_object_unref (factory); + return "ffenc_mpeg2video"; + } else { + return NULL; + } +} + +typedef struct +{ + GMainLoop *loop; + gboolean eos; +} OnMessageUserData; + +static void +on_message_cb (GstBus * bus, GstMessage * message, gpointer user_data) +{ + OnMessageUserData *d = user_data; + + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_ERROR: + case GST_MESSAGE_WARNING: + g_assert_not_reached (); + break; + case GST_MESSAGE_EOS: + g_main_loop_quit (d->loop); + d->eos = TRUE; + break; + default: + break; + } +} + +static void +run_test (const gchar * pipeline_string) +{ + GstElement *pipeline; + GstBus *bus; + GMainLoop *loop; + OnMessageUserData omud = { NULL, }; + GstStateChangeReturn ret; + + GST_DEBUG ("Testing pipeline '%s'", pipeline_string); + + pipeline = gst_parse_launch (pipeline_string, NULL); + fail_unless (pipeline != NULL); + g_object_set (G_OBJECT (pipeline), "async-handling", TRUE, NULL); + + loop = g_main_loop_new (NULL, FALSE); + + bus = gst_element_get_bus (pipeline); + fail_unless (bus != NULL); + gst_bus_add_signal_watch (bus); + + omud.loop = loop; + omud.eos = FALSE; + + g_signal_connect (bus, "message", (GCallback) on_message_cb, &omud); + + ret = gst_element_set_state (pipeline, GST_STATE_PLAYING); + fail_unless (ret == GST_STATE_CHANGE_SUCCESS + || ret == GST_STATE_CHANGE_ASYNC); + + g_main_loop_run (loop); + + fail_unless (gst_element_set_state (pipeline, + GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS); + + fail_unless (omud.eos == TRUE); + + gst_object_unref (pipeline); + g_main_loop_unref (loop); + gst_bus_remove_signal_watch (bus); + gst_object_unref (bus); +} + +GST_START_TEST (test_mpeg2) +{ + const gchar *mpeg2enc_name = get_mpeg2enc_element_name (); + gchar *pipeline; + + if (!mpeg2enc_name) + return; + + pipeline = g_strdup_printf ("videotestsrc num-buffers=250 ! " + "video/x-raw,framerate=25/1 ! " + "%s ! " "mxfmux name=mux ! " "fakesink", mpeg2enc_name); + + run_test (pipeline); + g_free (pipeline); +} + +GST_END_TEST; + +GST_START_TEST (test_raw_video_raw_audio) +{ + gchar *pipeline; + + pipeline = g_strdup_printf ("videotestsrc num-buffers=250 ! " + "video/x-raw,format=(string)v308,width=1920,height=1080,framerate=25/1 ! " + "mxfmux name=mux ! " + "fakesink " + "audiotestsrc num-buffers=250 ! " + "audioconvert ! " "audio/x-raw,rate=48000,channels=2 ! " "mux. "); + + run_test (pipeline); + g_free (pipeline); +} + +GST_END_TEST; + +GST_START_TEST (test_raw_video_stride_transform) +{ + gchar *pipeline; + + pipeline = g_strdup_printf ("videotestsrc num-buffers=250 ! " + "video/x-raw,format=(string)v308,width=1001,height=501,framerate=25/1 ! " + "mxfmux name=mux ! " "fakesink"); + + run_test (pipeline); + g_free (pipeline); +} + +GST_END_TEST; + +GST_START_TEST (test_jpeg2000_alaw) +{ + gchar *pipeline; + GstElementFactory *factory = NULL; + + if ((factory = gst_element_factory_find ("jp2kenc")) == NULL) + return; + gst_object_unref (factory); + if ((factory = gst_element_factory_find ("alawenc")) == NULL) + return; + gst_object_unref (factory); + + pipeline = g_strdup_printf ("videotestsrc num-buffers=250 ! " + "video/x-raw,framerate=25/1 ! " + "jp2kenc ! " + "mxfmux name=mux ! " + "fakesink " + "audiotestsrc num-buffers=250 ! " "audioconvert ! " "alawenc ! " "mux. "); + + run_test (pipeline); + g_free (pipeline); +} + +GST_END_TEST; + +GST_START_TEST (test_dnxhd_mp3) +{ + gchar *pipeline; + GstElementFactory *factory = NULL; + + if ((factory = gst_element_factory_find ("ffenc_dnxhd")) == NULL) + return; + gst_object_unref (factory); + if ((factory = gst_element_factory_find ("lame")) == NULL) + return; + gst_object_unref (factory); + if ((factory = gst_element_factory_find ("mp3parse")) == NULL) + return; + gst_object_unref (factory); + + pipeline = g_strdup_printf ("videotestsrc num-buffers=250 ! " + "video/x-raw,format=(string)Y42B,width=1920,height=1080,framerate=25/1 ! " + "ffenc_dnxhd bitrate=36000000 ! " + "mxfmux name=mux ! " + "fakesink " + "audiotestsrc num-buffers=250 ! " + "audioconvert ! " + "audio/x-raw,channels=2 ! " "lame ! " "mp3parse ! " "mux. "); + + run_test (pipeline); + g_free (pipeline); +} + +GST_END_TEST; + +GST_START_TEST (test_multiple_av_streams) +{ + gchar *pipeline; + + pipeline = g_strdup_printf ("videotestsrc num-buffers=250 ! " + "video/x-raw,format=(string)v308,width=1920,height=1080,framerate=25/1 ! " + "mxfmux name=mux ! " + "fakesink " + "audiotestsrc num-buffers=250 ! " + "audioconvert ! " + "audio/x-raw,rate=48000,channels=2 ! " + "mux. " + "videotestsrc num-buffers=100 ! " + "video/x-raw,format=(string)v308,width=1920,height=1080,framerate=25/1 ! " + "mux. " + "audiotestsrc num-buffers=100 ! " + "audioconvert ! " + "audio/x-raw,rate=48000,channels=2 ! " + "mux. " + "audiotestsrc num-buffers=250 ! " + "audioconvert ! " "audio/x-raw,rate=48000,channels=2 ! " "mux. "); + + run_test (pipeline); + g_free (pipeline); +} + +GST_END_TEST; + +static Suite * +mxfmux_suite (void) +{ + Suite *s = suite_create ("mxfmux"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_set_timeout (tc_chain, 180); + + tcase_add_test (tc_chain, test_mpeg2); + tcase_add_test (tc_chain, test_raw_video_raw_audio); + tcase_add_test (tc_chain, test_raw_video_stride_transform); + tcase_add_test (tc_chain, test_jpeg2000_alaw); + tcase_add_test (tc_chain, test_dnxhd_mp3); + tcase_add_test (tc_chain, test_multiple_av_streams); + + return s; +} + +GST_CHECK_MAIN (mxfmux); diff --git a/tests/check/elements/neonhttpsrc.c b/tests/check/elements/neonhttpsrc.c new file mode 100644 index 00000000..49e36525 --- /dev/null +++ b/tests/check/elements/neonhttpsrc.c @@ -0,0 +1,190 @@ +/* GStreamer unit tests for the neonhttpsrc element + * Copyright (C) 2006-2007 Tim-Philipp Müller <tim centricular net> + * + * 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> + +static void +handoff_cb (GstElement * fakesink, GstBuffer * buf, GstPad * pad, + GstBuffer ** p_outbuf) +{ + GST_LOG ("handoff, buf = %p", buf); + if (*p_outbuf == NULL) + *p_outbuf = gst_buffer_ref (buf); +} + +GST_START_TEST (test_first_buffer_has_offset) +{ + GstStateChangeReturn ret; + GstElement *pipe, *src, *sink; + GstBuffer *buf = NULL; + gchar **cookies; + + pipe = gst_pipeline_new (NULL); + + src = gst_element_factory_make ("neonhttpsrc", NULL); + fail_unless (src != NULL); + + sink = gst_element_factory_make ("fakesink", NULL); + fail_unless (sink != NULL); + + gst_bin_add (GST_BIN (pipe), src); + gst_bin_add (GST_BIN (pipe), sink); + fail_unless (gst_element_link (src, sink)); + + g_object_set (src, "location", "http://gstreamer.freedesktop.org/", NULL); + g_object_set (src, "automatic-redirect", TRUE, NULL); + + /* set some cookies (shouldn't hurt) */ + cookies = g_strsplit ("foo=1234,bar=9871615348162523726337x99FB", ",", -1); + g_object_set (src, "cookies", cookies, NULL); + g_strfreev (cookies); + + g_object_set (sink, "signal-handoffs", TRUE, NULL); + g_signal_connect (sink, "preroll-handoff", G_CALLBACK (handoff_cb), &buf); + + ret = gst_element_set_state (pipe, GST_STATE_PAUSED); + if (ret != GST_STATE_CHANGE_ASYNC) { + GST_DEBUG ("failed to start up neon http src, ret = %d", ret); + goto done; + } + + /* don't wait for more than 10 seconds */ + ret = gst_element_get_state (pipe, NULL, NULL, 10 * GST_SECOND); + GST_LOG ("ret = %u", ret); + + if (buf == NULL) { + /* we want to test the buffer offset, nothing else; if there's a failure + * it might be for lots of reasons (no network connection, whatever), we're + * not interested in those */ + GST_DEBUG ("didn't manage to get data within 10 seconds, skipping test"); + goto done; + } + + GST_DEBUG ("buffer offset = %" G_GUINT64_FORMAT, GST_BUFFER_OFFSET (buf)); + + /* first buffer should have a 0 offset */ + fail_unless (GST_BUFFER_OFFSET (buf) == 0); + gst_buffer_unref (buf); + +done: + + gst_element_set_state (pipe, GST_STATE_NULL); + gst_object_unref (pipe); +} + +GST_END_TEST; + +GST_START_TEST (test_icy_stream) +{ + GstElement *pipe, *src, *sink; + GstMessage *msg; + + pipe = gst_pipeline_new (NULL); + + src = gst_element_factory_make ("neonhttpsrc", NULL); + fail_unless (src != NULL); + + sink = gst_element_factory_make ("fakesink", NULL); + fail_unless (sink != NULL); + + gst_bin_add (GST_BIN (pipe), src); + gst_bin_add (GST_BIN (pipe), sink); + fail_unless (gst_element_link (src, sink)); + + /* First try Virgin Radio Ogg stream, to see if there's connectivity and all + * (which is an attempt to work around the completely horrid error reporting + * and that we can't distinguish different types of failures here). + * Note that neonhttpsrc does the whole connect + session initiation all in + * the state change function. */ + + g_object_set (src, "location", "http://ogg2.smgradio.com/vr32.ogg", NULL); + g_object_set (src, "automatic-redirect", FALSE, NULL); + g_object_set (src, "num-buffers", 1, NULL); + gst_element_set_state (pipe, GST_STATE_PLAYING); + + msg = gst_bus_poll (GST_ELEMENT_BUS (pipe), + GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1); + if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) { + GST_INFO ("looks like there's no net connectivity or sgmradio.com is " + "down. In any case, let's just skip this test"); + gst_message_unref (msg); + goto done; + } + gst_message_unref (msg); + msg = NULL; + gst_element_set_state (pipe, GST_STATE_NULL); + + /* Now, if the ogg stream works, the mp3 shoutcast stream should work as + * well (time will tell if that's true) */ + + /* Virgin Radio 32kbps mp3 shoutcast stream */ + g_object_set (src, "location", "http://mp3-vr-32.smgradio.com:80/", NULL); + g_object_set (src, "automatic-redirect", FALSE, NULL); + + /* g_object_set (src, "neon-http-debug", TRUE, NULL); */ + + /* EOS after the first buffer */ + g_object_set (src, "num-buffers", 1, NULL); + + gst_element_set_state (pipe, GST_STATE_PLAYING); + msg = gst_bus_poll (GST_ELEMENT_BUS (pipe), + GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1); + + if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS) { + GST_DEBUG ("success, we're done here"); + gst_message_unref (msg); + goto done; + } + + { + GError *err = NULL; + + gst_message_parse_error (msg, &err, NULL); + gst_message_unref (msg); + g_error ("Error with ICY mp3 shoutcast stream: %s", err->message); + g_error_free (err); + } + +done: + + gst_element_set_state (pipe, GST_STATE_NULL); + gst_object_unref (pipe); +} + +GST_END_TEST; + +static Suite * +neonhttpsrc_suite (void) +{ + Suite *s = suite_create ("neonhttpsrc"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_set_timeout (tc_chain, 5); + tcase_add_test (tc_chain, test_first_buffer_has_offset); + tcase_add_test (tc_chain, test_icy_stream); + + return s; +} + +GST_CHECK_MAIN (neonhttpsrc); diff --git a/tests/check/elements/ofa.c b/tests/check/elements/ofa.c new file mode 100644 index 00000000..d1d61be5 --- /dev/null +++ b/tests/check/elements/ofa.c @@ -0,0 +1,396 @@ +/* GStreamer + * Copyright (C) 2008 Sebastian Dröge <slomo@circular-chaos.org> + * + * 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. + */ + +#include <gst/check/gstcheck.h> + +static gboolean found_fingerprint = FALSE; + +static gboolean +bus_handler (GstBus * bus, GstMessage * message, gpointer data) +{ + GMainLoop *loop = (GMainLoop *) data; + + switch (message->type) { + case GST_MESSAGE_EOS: + g_main_loop_quit (loop); + break; + case GST_MESSAGE_WARNING: + case GST_MESSAGE_ERROR:{ + GError *gerror; + gchar *debug; + + if (message->type == GST_MESSAGE_WARNING) + gst_message_parse_warning (message, &gerror, &debug); + else + gst_message_parse_error (message, &gerror, &debug); + gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug); + gst_message_unref (message); + g_error_free (gerror); + g_free (debug); + g_main_loop_quit (loop); + break; + } + case GST_MESSAGE_TAG: + { + GstTagList *tag_list; + gchar *fpr, *p; + + gst_message_parse_tag (message, &tag_list); + + fail_unless (gst_tag_list_get_string (tag_list, "ofa-fingerprint", &fpr)); + + p = fpr; + while (*p) { + fail_unless (g_ascii_isalnum (*p) || *p == '=' || *p == '+' + || *p == '/'); + p++; + } + + g_free (fpr); + gst_tag_list_free (tag_list); + + found_fingerprint = TRUE; + + g_main_loop_quit (loop); + break; + } + default: + break; + } + + return TRUE; +} + +GST_START_TEST (test_ofa_le_1ch) +{ + GstElement *pipeline; + GstElement *audiotestsrc, *audioconvert, *capsfilter, *ofa, *fakesink; + + GstBus *bus; + GMainLoop *loop; + GstCaps *caps; + gint64 position; + GstFormat fmt = GST_FORMAT_TIME; + guint bus_watch = 0; + + pipeline = gst_pipeline_new ("pipeline"); + fail_unless (pipeline != NULL); + + audiotestsrc = gst_element_factory_make ("audiotestsrc", "src"); + fail_unless (audiotestsrc != NULL); + g_object_set (G_OBJECT (audiotestsrc), "wave", 0, "freq", 440.0, NULL); + + audioconvert = gst_element_factory_make ("audioconvert", "audioconvert"); + fail_unless (audioconvert != NULL); + g_object_set (G_OBJECT (audioconvert), "dithering", 0, NULL); + + capsfilter = gst_element_factory_make ("capsfilter", "capsfilter"); + fail_unless (capsfilter != NULL); + caps = gst_caps_new_simple ("audio/x-raw-int", + "rate", G_TYPE_INT, 44100, + "channels", G_TYPE_INT, 1, + "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, + "width", G_TYPE_INT, 16, + "depth", G_TYPE_INT, 16, "signed", G_TYPE_BOOLEAN, TRUE, NULL); + g_object_set (G_OBJECT (capsfilter), "caps", caps, NULL); + gst_caps_unref (caps); + + ofa = gst_element_factory_make ("ofa", "ofa"); + fail_unless (ofa != NULL); + + fakesink = gst_element_factory_make ("fakesink", "sink"); + fail_unless (fakesink != NULL); + + gst_bin_add_many (GST_BIN (pipeline), audiotestsrc, audioconvert, capsfilter, + ofa, fakesink, NULL); + + fail_unless (gst_element_link_many (audiotestsrc, audioconvert, capsfilter, + ofa, fakesink, NULL)); + + loop = g_main_loop_new (NULL, TRUE); + fail_unless (loop != NULL); + + bus = gst_element_get_bus (pipeline); + fail_unless (bus != NULL); + bus_watch = gst_bus_add_watch (bus, bus_handler, loop); + gst_object_unref (bus); + + found_fingerprint = FALSE; + gst_element_set_state (pipeline, GST_STATE_PLAYING); + g_main_loop_run (loop); + + fail_unless (gst_element_query_position (audiotestsrc, &fmt, &position)); + fail_unless (position >= 135 * GST_SECOND); + + gst_element_set_state (pipeline, GST_STATE_NULL); + + fail_unless (found_fingerprint == TRUE); + g_object_unref (pipeline); + g_main_loop_unref (loop); + g_source_remove (bus_watch); +} + +GST_END_TEST; + + +GST_START_TEST (test_ofa_be_1ch) +{ + GstElement *pipeline; + GstElement *audiotestsrc, *audioconvert, *capsfilter, *ofa, *fakesink; + GstBus *bus; + GMainLoop *loop; + GstCaps *caps; + gint64 position; + GstFormat fmt = GST_FORMAT_TIME; + guint bus_watch = 0; + + pipeline = gst_pipeline_new ("pipeline"); + fail_unless (pipeline != NULL); + + audiotestsrc = gst_element_factory_make ("audiotestsrc", "src"); + fail_unless (audiotestsrc != NULL); + g_object_set (G_OBJECT (audiotestsrc), "wave", 0, "freq", 440.0, NULL); + + audioconvert = gst_element_factory_make ("audioconvert", "audioconvert"); + fail_unless (audioconvert != NULL); + g_object_set (G_OBJECT (audioconvert), "dithering", 0, NULL); + + capsfilter = gst_element_factory_make ("capsfilter", "capsfilter"); + fail_unless (capsfilter != NULL); + caps = gst_caps_new_simple ("audio/x-raw-int", + "rate", G_TYPE_INT, 44100, + "channels", G_TYPE_INT, 1, + "endianness", G_TYPE_INT, G_BIG_ENDIAN, + "width", G_TYPE_INT, 16, + "depth", G_TYPE_INT, 16, "signed", G_TYPE_BOOLEAN, TRUE, NULL); + g_object_set (G_OBJECT (capsfilter), "caps", caps, NULL); + gst_caps_unref (caps); + + ofa = gst_element_factory_make ("ofa", "ofa"); + fail_unless (ofa != NULL); + + fakesink = gst_element_factory_make ("fakesink", "sink"); + fail_unless (fakesink != NULL); + + gst_bin_add_many (GST_BIN (pipeline), audiotestsrc, audioconvert, capsfilter, + ofa, fakesink, NULL); + + fail_unless (gst_element_link_many (audiotestsrc, audioconvert, capsfilter, + ofa, fakesink, NULL)); + + loop = g_main_loop_new (NULL, TRUE); + fail_unless (loop != NULL); + + bus = gst_element_get_bus (pipeline); + fail_unless (bus != NULL); + bus_watch = gst_bus_add_watch (bus, bus_handler, loop); + gst_object_unref (bus); + + found_fingerprint = FALSE; + gst_element_set_state (pipeline, GST_STATE_PLAYING); + g_main_loop_run (loop); + + fail_unless (gst_element_query_position (audiotestsrc, &fmt, &position)); + fail_unless (position >= 135 * GST_SECOND); + + gst_element_set_state (pipeline, GST_STATE_NULL); + + fail_unless (found_fingerprint == TRUE); + g_object_unref (pipeline); + g_main_loop_unref (loop); + g_source_remove (bus_watch); +} + +GST_END_TEST; + +GST_START_TEST (test_ofa_le_2ch) +{ + GstElement *pipeline; + GstElement *audiotestsrc, *audioconvert, *capsfilter, *ofa, *fakesink; + GstBus *bus; + GMainLoop *loop; + GstCaps *caps; + gint64 position; + GstFormat fmt = GST_FORMAT_TIME; + guint bus_watch = 0; + + pipeline = gst_pipeline_new ("pipeline"); + fail_unless (pipeline != NULL); + + audiotestsrc = gst_element_factory_make ("audiotestsrc", "src"); + fail_unless (audiotestsrc != NULL); + g_object_set (G_OBJECT (audiotestsrc), "wave", 0, "freq", 440.0, NULL); + + audioconvert = gst_element_factory_make ("audioconvert", "audioconvert"); + fail_unless (audioconvert != NULL); + g_object_set (G_OBJECT (audioconvert), "dithering", 0, NULL); + + capsfilter = gst_element_factory_make ("capsfilter", "capsfilter"); + fail_unless (capsfilter != NULL); + caps = gst_caps_new_simple ("audio/x-raw-int", + "rate", G_TYPE_INT, 44100, + "channels", G_TYPE_INT, 2, + "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, + "width", G_TYPE_INT, 16, + "depth", G_TYPE_INT, 16, "signed", G_TYPE_BOOLEAN, TRUE, NULL); + g_object_set (G_OBJECT (capsfilter), "caps", caps, NULL); + gst_caps_unref (caps); + + ofa = gst_element_factory_make ("ofa", "ofa"); + fail_unless (ofa != NULL); + + fakesink = gst_element_factory_make ("fakesink", "sink"); + fail_unless (fakesink != NULL); + + gst_bin_add_many (GST_BIN (pipeline), audiotestsrc, audioconvert, capsfilter, + ofa, fakesink, NULL); + + fail_unless (gst_element_link_many (audiotestsrc, audioconvert, capsfilter, + ofa, fakesink, NULL)); + + loop = g_main_loop_new (NULL, TRUE); + fail_unless (loop != NULL); + + bus = gst_element_get_bus (pipeline); + fail_unless (bus != NULL); + bus_watch = gst_bus_add_watch (bus, bus_handler, loop); + gst_object_unref (bus); + + found_fingerprint = FALSE; + gst_element_set_state (pipeline, GST_STATE_PLAYING); + g_main_loop_run (loop); + + fail_unless (gst_element_query_position (audiotestsrc, &fmt, &position)); + fail_unless (position >= 135 * GST_SECOND); + + gst_element_set_state (pipeline, GST_STATE_NULL); + + fail_unless (found_fingerprint == TRUE); + g_object_unref (pipeline); + g_main_loop_unref (loop); + g_source_remove (bus_watch); +} + +GST_END_TEST; + + +GST_START_TEST (test_ofa_be_2ch) +{ + GstElement *pipeline; + GstElement *audiotestsrc, *audioconvert, *capsfilter, *ofa, *fakesink; + GstBus *bus; + GMainLoop *loop; + GstCaps *caps; + gint64 position; + GstFormat fmt = GST_FORMAT_TIME; + guint bus_watch = 0; + + pipeline = gst_pipeline_new ("pipeline"); + fail_unless (pipeline != NULL); + + audiotestsrc = gst_element_factory_make ("audiotestsrc", "src"); + fail_unless (audiotestsrc != NULL); + g_object_set (G_OBJECT (audiotestsrc), "wave", 0, "freq", 440.0, NULL); + + audioconvert = gst_element_factory_make ("audioconvert", "audioconvert"); + fail_unless (audioconvert != NULL); + g_object_set (G_OBJECT (audioconvert), "dithering", 0, NULL); + + capsfilter = gst_element_factory_make ("capsfilter", "capsfilter"); + fail_unless (capsfilter != NULL); + caps = gst_caps_new_simple ("audio/x-raw-int", + "rate", G_TYPE_INT, 44100, + "channels", G_TYPE_INT, 2, + "endianness", G_TYPE_INT, G_BIG_ENDIAN, + "width", G_TYPE_INT, 16, + "depth", G_TYPE_INT, 16, "signed", G_TYPE_BOOLEAN, TRUE, NULL); + g_object_set (G_OBJECT (capsfilter), "caps", caps, NULL); + gst_caps_unref (caps); + + ofa = gst_element_factory_make ("ofa", "ofa"); + fail_unless (ofa != NULL); + + fakesink = gst_element_factory_make ("fakesink", "sink"); + fail_unless (fakesink != NULL); + + gst_bin_add_many (GST_BIN (pipeline), audiotestsrc, audioconvert, capsfilter, + ofa, fakesink, NULL); + + fail_unless (gst_element_link_many (audiotestsrc, audioconvert, capsfilter, + ofa, fakesink, NULL)); + + loop = g_main_loop_new (NULL, TRUE); + fail_unless (loop != NULL); + + bus = gst_element_get_bus (pipeline); + fail_unless (bus != NULL); + bus_watch = gst_bus_add_watch (bus, bus_handler, loop); + gst_object_unref (bus); + + found_fingerprint = FALSE; + gst_element_set_state (pipeline, GST_STATE_PLAYING); + g_main_loop_run (loop); + + fail_unless (gst_element_query_position (audiotestsrc, &fmt, &position)); + fail_unless (position >= 135 * GST_SECOND); + + gst_element_set_state (pipeline, GST_STATE_NULL); + + fail_unless (found_fingerprint == TRUE); + g_object_unref (pipeline); + g_main_loop_unref (loop); + g_source_remove (bus_watch); +} + +GST_END_TEST; + +static Suite * +ofa_suite (void) +{ + Suite *s = suite_create ("OFA"); + TCase *tc_chain = tcase_create ("linear"); + + /* time out after 120s, not the default 3 */ + tcase_set_timeout (tc_chain, 120); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_ofa_le_1ch); + tcase_add_test (tc_chain, test_ofa_be_1ch); + tcase_add_test (tc_chain, test_ofa_le_2ch); + tcase_add_test (tc_chain, test_ofa_be_2ch); + + return s; +} + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = ofa_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; +} diff --git a/tests/check/elements/opus.c b/tests/check/elements/opus.c new file mode 100644 index 00000000..be5b2cf6 --- /dev/null +++ b/tests/check/elements/opus.c @@ -0,0 +1,385 @@ +/* GStreamer + * + * unit test for opus + * + * Copyright (C) <2011> Vincent Penquerc'h <vincent.penquerch@collbaora.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. + */ + +#include <unistd.h> + +#include <gst/check/gstcheck.h> + +#if G_BYTE_ORDER == G_BIG_ENDIAN +#define AFORMAT "S16BE" +#else +#define AFORMAT "S16LE" +#endif + +#define AUDIO_CAPS_STRING "audio/x-raw, " \ + "format = (string) " AFORMAT ", "\ + "layout = (string) interleaved, " \ + "rate = (int) 48000, " \ + "channels = (int) 1 " + +static const guint8 opus_ogg_id_header[19] = { + 0x4f, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const guint8 opus_ogg_comments_header[] = { + 0x4f, 0x70, 0x75, 0x73, 0x54, 0x61, 0x67, 0x73, 0x1e, 0x00, 0x00, 0x00, 0x45, + 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, + 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x65, 0x72, 0x20, 0x4f, 0x70, 0x75, 0x73, + 0x65, 0x6e, 0x63, 0x00, 0x00, 0x00, 0x00 +}; + +/* A lot of these taken from the vorbisdec test */ + +/* For ease of programming we use globals to keep refs for our floating + * src and sink pads we create; otherwise we always have to do get_pad, + * get_peer, and then remove references in every test function */ +static GstPad *mydecsrcpad, *mydecsinkpad; +static GstPad *myencsrcpad, *myencsinkpad; + +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +static GstElement * +setup_opusdec (void) +{ + GstElement *opusdec; + + GST_DEBUG ("setup_opusdec"); + opusdec = gst_check_setup_element ("opusdec"); + mydecsrcpad = gst_check_setup_src_pad (opusdec, &srctemplate); + mydecsinkpad = gst_check_setup_sink_pad (opusdec, &sinktemplate); + gst_pad_set_active (mydecsrcpad, TRUE); + gst_pad_set_active (mydecsinkpad, TRUE); + + return opusdec; +} + +static void +cleanup_opusdec (GstElement * opusdec) +{ + GST_DEBUG ("cleanup_opusdec"); + gst_element_set_state (opusdec, GST_STATE_NULL); + + gst_pad_set_active (mydecsrcpad, FALSE); + gst_pad_set_active (mydecsinkpad, FALSE); + gst_check_teardown_src_pad (opusdec); + gst_check_teardown_sink_pad (opusdec); + gst_check_teardown_element (opusdec); +} + +static GstElement * +setup_opusenc (void) +{ + GstElement *opusenc; + + GST_DEBUG ("setup_opusenc"); + opusenc = gst_check_setup_element ("opusenc"); + myencsrcpad = gst_check_setup_src_pad (opusenc, &srctemplate); + myencsinkpad = gst_check_setup_sink_pad (opusenc, &sinktemplate); + gst_pad_set_active (myencsrcpad, TRUE); + gst_pad_set_active (myencsinkpad, TRUE); + + return opusenc; +} + +static void +cleanup_opusenc (GstElement * opusenc) +{ + GST_DEBUG ("cleanup_opusenc"); + gst_element_set_state (opusenc, GST_STATE_NULL); + + gst_pad_set_active (myencsrcpad, FALSE); + gst_pad_set_active (myencsinkpad, FALSE); + gst_check_teardown_src_pad (opusenc); + gst_check_teardown_sink_pad (opusenc); + gst_check_teardown_element (opusenc); +} + +static void +check_buffers (guint expected) +{ + GstBuffer *outbuffer; + guint i, num_buffers; + + /* check buffers are the type we expect */ + num_buffers = g_list_length (buffers); + fail_unless (num_buffers >= expected); + for (i = 0; i < num_buffers; ++i) { + outbuffer = GST_BUFFER (buffers->data); + fail_if (outbuffer == NULL); + fail_if (gst_buffer_get_size (outbuffer) == 0); + + buffers = g_list_remove (buffers, outbuffer); + + ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1); + gst_buffer_unref (outbuffer); + outbuffer = NULL; + } +} + +GST_START_TEST (test_opus_id_header) +{ + GstElement *opusdec; + GstBuffer *inbuffer; + + opusdec = setup_opusdec (); + fail_unless (gst_element_set_state (opusdec, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (sizeof (opus_ogg_id_header)); + gst_buffer_fill (inbuffer, 0, opus_ogg_id_header, + sizeof (opus_ogg_id_header)); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + gst_buffer_ref (inbuffer); + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mydecsrcpad, inbuffer) == GST_FLOW_OK); + /* ... and nothing ends up on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + gst_buffer_unref (inbuffer); + check_buffers (0); + + /* cleanup */ + cleanup_opusdec (opusdec); +} + +GST_END_TEST; + +GST_START_TEST (test_opus_encode_nothing) +{ + GstElement *opusenc; + + opusenc = setup_opusenc (); + fail_unless (gst_element_set_state (opusenc, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + fail_unless (gst_pad_push_event (myencsrcpad, gst_event_new_eos ()) == TRUE); + + fail_unless (gst_element_set_state (opusenc, + GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS, + "could not set to ready"); + + /* cleanup */ + cleanup_opusenc (opusenc); +} + +GST_END_TEST; + +GST_START_TEST (test_opus_decode_nothing) +{ + GstElement *opusdec; + + opusdec = setup_opusdec (); + fail_unless (gst_element_set_state (opusdec, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + fail_unless (gst_pad_push_event (mydecsrcpad, gst_event_new_eos ()) == TRUE); + + fail_unless (gst_element_set_state (opusdec, + GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS, + "could not set to ready"); + + /* cleanup */ + cleanup_opusdec (opusdec); +} + +GST_END_TEST; + +GST_START_TEST (test_opus_encode_samples) +{ + const unsigned int nsamples = 4096; + GstElement *opusenc; + GstBuffer *inbuffer; + GstCaps *caps; + + opusenc = setup_opusenc (); + + fail_unless (gst_element_set_state (opusenc, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (nsamples * 2); + gst_buffer_memset (inbuffer, 0, 0, nsamples * 2); + + GST_BUFFER_TIMESTAMP (inbuffer) = GST_BUFFER_OFFSET (inbuffer) = 0; + GST_BUFFER_DURATION (inbuffer) = GST_CLOCK_TIME_NONE; + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + + caps = gst_caps_from_string (AUDIO_CAPS_STRING); + fail_unless (caps != NULL); + gst_pad_set_caps (myencsrcpad, caps); + gst_caps_unref (caps); + gst_buffer_ref (inbuffer); + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (myencsrcpad, inbuffer) == GST_FLOW_OK); + /* ... and nothing ends up on the global buffer list */ + fail_unless (gst_pad_push_event (myencsrcpad, gst_event_new_eos ()) == TRUE); + + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + gst_buffer_unref (inbuffer); + + fail_unless (gst_element_set_state (opusenc, + GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS, + "could not set to ready"); + + /* default frame size is 20 ms, at 48000 Hz that's 960 samples */ + check_buffers ((nsamples + 959) / 960); + + /* cleanup */ + cleanup_opusenc (opusenc); + g_list_free (buffers); +} + +GST_END_TEST; + +GST_START_TEST (test_opus_encode_properties) +{ + const unsigned int nsamples = 4096; + enum + { steps = 20 }; + GstElement *opusenc; + GstBuffer *inbuffer; + GstCaps *caps; + unsigned int step; + static const struct + { + const char *param; + int value; + } param_changes[steps] = { + { + "frame-size", 40}, { + "inband-fec", 1}, { + "complexity", 5}, { + "bandwidth", 1104}, { + "frame-size", 2}, { + "max-payload-size", 80}, { + "frame-size", 60}, { + "max-payload-size", 900}, { + "complexity", 1}, { + "bitrate", 30000}, { + "frame-size", 10}, { + "bitrate", 300000}, { + "inband-fec", 0}, { + "frame-size", 5}, { + "bandwidth", 1101}, { + "frame-size", 10}, { + "bitrate", 500000}, { + "frame-size", 5}, { + "bitrate", 80000}, { + "complexity", 8},}; + + opusenc = setup_opusenc (); + + fail_unless (gst_element_set_state (opusenc, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + caps = gst_caps_from_string (AUDIO_CAPS_STRING); + fail_unless (caps != NULL); + + gst_pad_set_caps (myencsrcpad, caps); + + for (step = 0; step < steps; ++step) { + inbuffer = gst_buffer_new_and_alloc (nsamples * 2); + gst_buffer_memset (inbuffer, 0, 0, nsamples * 2); + + GST_BUFFER_TIMESTAMP (inbuffer) = GST_BUFFER_OFFSET (inbuffer) = 0; + GST_BUFFER_DURATION (inbuffer) = GST_CLOCK_TIME_NONE; + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + + gst_buffer_ref (inbuffer); + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (myencsrcpad, inbuffer) == GST_FLOW_OK); + /* ... and nothing ends up on the global buffer list */ + fail_unless (gst_pad_push_event (myencsrcpad, + gst_event_new_eos ()) == TRUE); + + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + gst_buffer_unref (inbuffer); + + /* change random parameters */ + g_object_set (opusenc, param_changes[step].param, param_changes[step].value, + NULL); + + check_buffers (1); + } + + gst_caps_unref (caps); + + fail_unless (gst_element_set_state (opusenc, + GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS, + "could not set to ready"); + + /* cleanup */ + cleanup_opusenc (opusenc); + g_list_free (buffers); +} + +GST_END_TEST; + +static Suite * +opus_suite (void) +{ + Suite *s = suite_create ("opus"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + +#define X if (0) + tcase_add_test (tc_chain, test_opus_id_header); + tcase_add_test (tc_chain, test_opus_encode_nothing); + tcase_add_test (tc_chain, test_opus_decode_nothing); + tcase_add_test (tc_chain, test_opus_encode_samples); + tcase_add_test (tc_chain, test_opus_encode_properties); +#undef X + + return s; +} + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = opus_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; +} diff --git a/tests/check/elements/parser.c b/tests/check/elements/parser.c new file mode 100644 index 00000000..356b7738 --- /dev/null +++ b/tests/check/elements/parser.c @@ -0,0 +1,428 @@ +/* + * GStreamer + * + * unit test for (audio) parser + * + * Copyright (C) 2008 Nokia Corporation. All rights reserved. + * + * Contact: Stefan Kost <stefan.kost@nokia.com> + * + * 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. + */ + +#include <gst/check/gstcheck.h> +#include "elements/parser.h" + + +/* context state variables */ +const gchar *ctx_factory; +GstStaticPadTemplate *ctx_sink_template; +GstStaticPadTemplate *ctx_src_template; +GstCaps *ctx_input_caps; +GstCaps *ctx_output_caps; +guint ctx_discard = 0; +datablob ctx_headers[MAX_HEADERS] = { {NULL, 0}, }; + +VerifyBuffer ctx_verify_buffer = NULL; +ElementSetup ctx_setup = NULL; + +gboolean ctx_no_metadata = FALSE; + +/* helper variables */ +GList *current_buf = NULL; + +GstPad *srcpad, *sinkpad; +guint dataoffset = 0; + +/* takes a copy of the passed buffer data */ +static GstBuffer * +buffer_new (const unsigned char *buffer_data, guint size) +{ + GstBuffer *buffer; + + buffer = gst_buffer_new_and_alloc (size); + if (buffer_data) { + gst_buffer_fill (buffer, 0, buffer_data, size); + } else { + guint i; + GstMapInfo map; + + /* Create a recognizable pattern (loop 0x00 -> 0xff) in the data block */ + gst_buffer_map (buffer, &map, GST_MAP_WRITE); + for (i = 0; i < size; i++) { + map.data[i] = i % 0x100; + } + gst_buffer_unmap (buffer, &map); + } + + GST_BUFFER_OFFSET (buffer) = dataoffset; + dataoffset += size; + return buffer; +} + +/* + * Adds buffer sizes together. + */ +static void +buffer_count_size (void *buffer, void *user_data) +{ + guint *sum = (guint *) user_data; + *sum += gst_buffer_get_size (buffer); +} + +/* + * Verify that given buffer contains predefined ADTS frame. + */ +static void +buffer_verify_data (void *buffer, void *user_data) +{ + buffer_verify_data_s *vdata; + + if (!user_data) { + return; + } + + vdata = (buffer_verify_data_s *) user_data; + + GST_DEBUG ("discard: %d", vdata->discard); + if (vdata->discard) { + if (ctx_verify_buffer) + ctx_verify_buffer (vdata, buffer); + vdata->buffer_counter++; + vdata->offset_counter += gst_buffer_get_size (buffer); + if (vdata->buffer_counter == vdata->discard) { + vdata->buffer_counter = 0; + vdata->discard = 0; + } + return; + } + + if (!ctx_verify_buffer || !ctx_verify_buffer (vdata, buffer)) { + fail_unless (gst_buffer_get_size (buffer) == vdata->data_to_verify_size); + fail_unless (gst_buffer_memcmp (buffer, 0, vdata->data_to_verify, + vdata->data_to_verify_size) == 0); + } + + if (vdata->buffers_before_offset_skip) { + /* This is for skipping the garbage in some test cases */ + if (vdata->buffer_counter == vdata->buffers_before_offset_skip) { + vdata->offset_counter += vdata->offset_skip_amount; + } + } + if (!vdata->no_metadata) { + fail_unless (GST_BUFFER_TIMESTAMP (buffer) == vdata->ts_counter); + fail_unless (GST_BUFFER_DURATION (buffer) != 0); + fail_unless (GST_BUFFER_OFFSET (buffer) == vdata->offset_counter); + } + + vdata->ts_counter += GST_BUFFER_DURATION (buffer); + vdata->offset_counter += gst_buffer_get_size (buffer); + vdata->buffer_counter++; +} + +static GstElement * +setup_element (const gchar * factory, ElementSetup setup, + GstStaticPadTemplate * sink_template, + GstCaps * sink_caps, GstStaticPadTemplate * src_template, + GstCaps * src_caps) +{ + GstElement *element; + GstBus *bus; + + if (setup) { + element = setup (factory); + } else { + element = gst_check_setup_element (factory); + } + srcpad = gst_check_setup_src_pad (element, src_template); + sinkpad = gst_check_setup_sink_pad (element, sink_template); + gst_pad_set_active (srcpad, TRUE); + gst_pad_set_active (sinkpad, TRUE); + if (src_caps) + fail_unless (gst_pad_set_caps (srcpad, src_caps)); + if (sink_caps) + fail_unless (gst_pad_set_caps (sinkpad, sink_caps)); + + bus = gst_bus_new (); + gst_element_set_bus (element, bus); + + fail_unless (gst_element_set_state (element, + GST_STATE_PLAYING) != GST_STATE_CHANGE_FAILURE, + "could not set to playing"); + + buffers = NULL; + return element; +} + +static void +cleanup_element (GstElement * element) +{ + GstBus *bus; + + /* Free parsed buffers */ + gst_check_drop_buffers (); + + bus = GST_ELEMENT_BUS (element); + gst_bus_set_flushing (bus, TRUE); + gst_object_unref (bus); + + gst_pad_set_active (srcpad, FALSE); + gst_pad_set_active (sinkpad, FALSE); + gst_check_teardown_src_pad (element); + gst_check_teardown_sink_pad (element); + gst_check_teardown_element (element); +} + +/* inits a standard test */ +void +gst_parser_test_init (GstParserTest * ptest, guint8 * data, guint size, + guint num) +{ + /* need these */ + fail_unless (ctx_factory != NULL); + fail_unless (ctx_src_template != NULL); + fail_unless (ctx_sink_template != NULL); + + /* basics */ + memset (ptest, 0, sizeof (*ptest)); + ptest->factory = ctx_factory; + ptest->factory_setup = ctx_setup; + ptest->sink_template = ctx_sink_template; + ptest->src_template = ctx_src_template; + ptest->framed = TRUE; + /* could be NULL if not relevant/needed */ + ptest->src_caps = ctx_input_caps; + ptest->sink_caps = ctx_output_caps; + memcpy (ptest->headers, ctx_headers, sizeof (ptest->headers)); + ptest->discard = ctx_discard; + /* some data that pleases caller */ + ptest->series[0].data = data; + ptest->series[0].size = size; + ptest->series[0].num = num; + ptest->series[0].fpb = 1; + ptest->series[1].fpb = 1; + ptest->series[2].fpb = 1; + ptest->no_metadata = ctx_no_metadata; +} + +/* + * Test if the parser pushes clean data properly. + */ +void +gst_parser_test_run (GstParserTest * test, GstCaps ** out_caps) +{ + buffer_verify_data_s vdata = { 0, 0, 0, NULL, 0, NULL, FALSE, 0, 0, 0 }; + GstElement *element; + GstBuffer *buffer = NULL; + GstCaps *src_caps; + guint i, j, k; + guint frames = 0, size = 0; + + element = setup_element (test->factory, test->factory_setup, + test->sink_template, NULL, test->src_template, test->src_caps); + + /* push some setup headers */ + for (j = 0; j < G_N_ELEMENTS (test->headers) && test->headers[j].data; j++) { + buffer = buffer_new (test->headers[j].data, test->headers[j].size); + fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK); + } + + for (j = 0; j < 3; j++) { + for (i = 0; i < test->series[j].num; i++) { + /* sanity enforcing */ + for (k = 0; k < MAX (1, test->series[j].fpb); k++) { + if (!k) + buffer = buffer_new (test->series[j].data, test->series[j].size); + else { + buffer = gst_buffer_append (buffer, + buffer_new (test->series[j].data, test->series[j].size)); + } + } + fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK); + if (j == 0) + vdata.buffers_before_offset_skip++; + else if (j == 1) + vdata.offset_skip_amount += test->series[j].size * test->series[j].fpb; + if (j != 1) { + frames += test->series[j].fpb; + size += test->series[j].size * test->series[j].fpb; + } + } + } + gst_pad_push_event (srcpad, gst_event_new_eos ()); + + if (G_LIKELY (test->framed)) + fail_unless_equals_int (g_list_length (buffers) - test->discard, frames); + + /* if all frames are identical, do extended test, + * otherwise only verify total data size */ + if (test->series[0].data && (!test->series[2].size || + (test->series[0].size == test->series[2].size && test->series[2].data + && !memcmp (test->series[0].data, test->series[2].data, + test->series[0].size)))) { + vdata.data_to_verify = test->series[0].data; + vdata.data_to_verify_size = test->series[0].size; + vdata.caps = test->sink_caps; + vdata.discard = test->discard; + vdata.no_metadata = test->no_metadata; + g_list_foreach (buffers, buffer_verify_data, &vdata); + } else { + guint datasum = 0; + + g_list_foreach (buffers, buffer_count_size, &datasum); + size -= test->dropped; + fail_unless_equals_int (datasum, size); + } + + src_caps = gst_pad_get_current_caps (sinkpad); + GST_LOG ("output caps: %" GST_PTR_FORMAT, src_caps); + + if (test->sink_caps) { + GST_LOG ("%" GST_PTR_FORMAT " = %" GST_PTR_FORMAT " ?", src_caps, + test->sink_caps); + fail_unless (gst_caps_is_equal (src_caps, test->sink_caps)); + } + + if (out_caps) + *out_caps = src_caps; + else + gst_caps_unref (src_caps); + + cleanup_element (element); +} + +/* + * Test if the parser pushes clean data properly. + */ +void +gst_parser_test_normal (guint8 * data, guint size) +{ + GstParserTest ptest; + + gst_parser_test_init (&ptest, data, size, 10); + gst_parser_test_run (&ptest, NULL); +} + +/* + * Test if parser drains its buffers properly. Even one single frame + * should be drained and pushed forward when EOS occurs. This single frame + * case is special, since normally the parser needs more data to be sure + * about stream format. But it should still push the frame forward in EOS. + */ +void +gst_parser_test_drain_single (guint8 * data, guint size) +{ + GstParserTest ptest; + + gst_parser_test_init (&ptest, data, size, 1); + gst_parser_test_run (&ptest, NULL); +} + +/* + * Make sure that parser does not drain garbage when EOS occurs. + */ +void +gst_parser_test_drain_garbage (guint8 * data, guint size, guint8 * garbage, + guint gsize) +{ + GstParserTest ptest; + + gst_parser_test_init (&ptest, data, size, 1); + ptest.series[1].data = garbage; + ptest.series[1].size = gsize; + ptest.series[1].num = 1; + gst_parser_test_run (&ptest, NULL); +} + +/* + * Test if parser splits a buffer that contains two frames into two + * separate buffers properly. + */ +void +gst_parser_test_split (guint8 * data, guint size) +{ + GstParserTest ptest; + + gst_parser_test_init (&ptest, data, size, 10); + ptest.series[0].fpb = 2; + gst_parser_test_run (&ptest, NULL); +} + +/* + * Test if the parser skips garbage between frames properly. + */ +void +gst_parser_test_skip_garbage (guint8 * data, guint size, guint8 * garbage, + guint gsize) +{ + GstParserTest ptest; + + gst_parser_test_init (&ptest, data, size, 10); + ptest.series[1].data = garbage; + ptest.series[1].size = gsize; + ptest.series[1].num = 1; + ptest.series[2].data = data; + ptest.series[2].size = size; + ptest.series[2].num = 10; + gst_parser_test_run (&ptest, NULL); +} + +/* + * Test if the src caps are set according to stream format. + */ +void +gst_parser_test_output_caps (guint8 * data, guint size, + const gchar * input_caps, const gchar * output_caps) +{ + GstParserTest ptest; + + gst_parser_test_init (&ptest, data, size, 10); + if (input_caps) { + ptest.src_caps = gst_caps_from_string (input_caps); + fail_unless (ptest.src_caps != NULL); + } + if (output_caps) { + ptest.sink_caps = gst_caps_from_string (output_caps); + fail_unless (ptest.sink_caps != NULL); + } + gst_parser_test_run (&ptest, NULL); + if (ptest.sink_caps) + gst_caps_unref (ptest.sink_caps); + if (ptest.src_caps) + gst_caps_unref (ptest.src_caps); +} + +/* + * Test if the src caps are set according to stream format. + */ +GstCaps * +gst_parser_test_get_output_caps (guint8 * data, guint size, + const gchar * input_caps) +{ + GstParserTest ptest; + GstCaps *out_caps; + + gst_parser_test_init (&ptest, data, size, 10); + if (input_caps) { + ptest.src_caps = gst_caps_from_string (input_caps); + fail_unless (ptest.src_caps != NULL); + } + gst_parser_test_run (&ptest, &out_caps); + if (ptest.src_caps) + gst_caps_unref (ptest.src_caps); + + return out_caps; +} diff --git a/tests/check/elements/parser.h b/tests/check/elements/parser.h new file mode 100644 index 00000000..7ae85c51 --- /dev/null +++ b/tests/check/elements/parser.h @@ -0,0 +1,117 @@ +/* + * GStreamer + * + * unit test for (audio) parser + * + * Copyright (C) 2008 Nokia Corporation. All rights reserved. + * + * Contact: Stefan Kost <stefan.kost@nokia.com> + * + * 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. + */ + +#include <gst/check/gstcheck.h> + +#define MAX_HEADERS 10 + +typedef struct +{ + guint discard; + guint buffers_before_offset_skip; + guint offset_skip_amount; + const guint8 *data_to_verify; + guint data_to_verify_size; + GstCaps *caps; + gboolean no_metadata; + + GstClockTime ts_counter; + gint64 offset_counter; + guint buffer_counter; +} buffer_verify_data_s; + +typedef struct { + guint8 *data; + guint size; +} datablob; + +typedef gboolean (*VerifyBuffer) (buffer_verify_data_s * vdata, GstBuffer * buf); +typedef GstElement* (*ElementSetup) (const gchar * desc); + +/* context state variables; to be set by test using this helper */ +/* mandatory */ +extern const gchar *ctx_factory; +extern GstStaticPadTemplate *ctx_sink_template; +extern GstStaticPadTemplate *ctx_src_template; +/* optional */ +extern GstCaps *ctx_input_caps; +extern GstCaps *ctx_output_caps; +extern guint ctx_discard; +extern datablob ctx_headers[MAX_HEADERS]; +extern gboolean ctx_no_metadata; + +extern VerifyBuffer ctx_verify_buffer; +extern ElementSetup ctx_setup; + +/* no refs taken/kept, all up to caller */ +typedef struct +{ + const gchar *factory; + ElementSetup factory_setup; + GstStaticPadTemplate *sink_template; + GstStaticPadTemplate *src_template; + /* caps that go into element */ + GstCaps *src_caps; + /* optional: output caps to verify */ + GstCaps *sink_caps; + /* initial headers */ + datablob headers[MAX_HEADERS]; + /* initial (header) output to forego checking */ + guint discard; + /* series of buffers; middle series considered garbage */ + struct { + /* data and size */ + guint8 *data; + guint size; + /* num of frames with above data per buffer */ + guint fpb; + /* num of buffers */ + guint num; + } series[3]; + /* sigh, weird cases */ + gboolean framed; + guint dropped; + gboolean no_metadata; +} GstParserTest; + +void gst_parser_test_init (GstParserTest * ptest, guint8 * data, guint size, guint num); + +void gst_parser_test_run (GstParserTest * test, GstCaps ** out_caps); + +void gst_parser_test_normal (guint8 *data, guint size); + +void gst_parser_test_drain_single (guint8 *data, guint size); + +void gst_parser_test_drain_garbage (guint8 *data, guint size, guint8 *garbage, guint gsize); + +void gst_parser_test_split (guint8 *data, guint size); + +void gst_parser_test_skip_garbage (guint8 *data, guint size, guint8 *garbage, guint gsize); + +void gst_parser_test_output_caps (guint8 *data, guint size, const gchar * input_caps, + const gchar * output_caps); + +GstCaps *gst_parser_test_get_output_caps (guint8 *data, guint size, const gchar * input_caps); + diff --git a/tests/check/elements/rtpmux.c b/tests/check/elements/rtpmux.c new file mode 100644 index 00000000..1228e5b8 --- /dev/null +++ b/tests/check/elements/rtpmux.c @@ -0,0 +1,305 @@ +/* GStreamer + * + * unit test for rtpmux elements + * + * Copyright 2009 Collabora Ltd. + * @author: Olivier Crete <olivier.crete@collabora.co.uk> + * Copyright 2009 Nokia Corp. + * + * 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. + */ + +#include <gst/check/gstcheck.h> +#include <gst/rtp/gstrtpbuffer.h> +#include <gst/gst.h> + +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-rtp")); + +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-rtp")); + +typedef void (*check_cb) (GstPad * pad, int i); + +static gboolean +query_func (GstPad * pad, GstObject * noparent, GstQuery * query) +{ + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_CAPS: + { + GstCaps **caps = g_object_get_data (G_OBJECT (pad), "caps"); + + fail_unless (caps != NULL && *caps != NULL); + gst_query_set_caps_result (query, *caps); + break; + } + default: + break; + } + + return TRUE; +} + +static gboolean +event_func (GstPad * pad, GstObject * noparent, GstEvent * event) +{ + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_CAPS: + { + GstCaps *caps; + GstCaps **caps2 = g_object_get_data (G_OBJECT (pad), "caps"); + + gst_event_parse_caps (event, &caps); + fail_unless (caps2 != NULL && *caps2 != NULL); + fail_unless (gst_caps_is_equal (caps, *caps2)); + break; + } + default: + gst_event_unref (event); + break; + } + + return TRUE; +} + +static void +test_basic (const gchar * elem_name, const gchar * sink2, int count, + check_cb cb) +{ + GstElement *rtpmux = NULL; + GstPad *reqpad1 = NULL; + GstPad *reqpad2 = NULL; + GstPad *src1 = NULL; + GstPad *src2 = NULL; + GstPad *sink = NULL; + GstBuffer *inbuf = NULL; + GstCaps *src1caps = NULL; + GstCaps *src2caps = NULL; + GstCaps *sinkcaps = NULL; + GstCaps *caps; + GstSegment segment; + int i; + + rtpmux = gst_check_setup_element (elem_name); + + reqpad1 = gst_element_get_request_pad (rtpmux, "sink_1"); + fail_unless (reqpad1 != NULL); + reqpad2 = gst_element_get_request_pad (rtpmux, sink2); + fail_unless (reqpad2 != NULL); + sink = gst_check_setup_sink_pad_by_name (rtpmux, &sinktemplate, "src"); + + src1 = gst_pad_new_from_static_template (&srctemplate, "src"); + src2 = gst_pad_new_from_static_template (&srctemplate, "src"); + fail_unless (gst_pad_link (src1, reqpad1) == GST_PAD_LINK_OK); + fail_unless (gst_pad_link (src2, reqpad2) == GST_PAD_LINK_OK); + gst_pad_set_query_function (src1, query_func); + gst_pad_set_query_function (src2, query_func); + gst_pad_set_query_function (sink, query_func); + gst_pad_set_event_function (sink, event_func); + g_object_set_data (G_OBJECT (src1), "caps", &src1caps); + g_object_set_data (G_OBJECT (src2), "caps", &src2caps); + g_object_set_data (G_OBJECT (sink), "caps", &sinkcaps); + + src1caps = gst_caps_new_simple ("application/x-rtp", + "clock-rate", G_TYPE_INT, 1, "ssrc", G_TYPE_UINT, 11, NULL); + src2caps = gst_caps_new_simple ("application/x-rtp", + "clock-rate", G_TYPE_INT, 2, "ssrc", G_TYPE_UINT, 12, NULL); + sinkcaps = gst_caps_new_simple ("application/x-rtp", + "clock-rate", G_TYPE_INT, 3, "ssrc", G_TYPE_UINT, 13, NULL); + + caps = gst_pad_peer_query_caps (src1, NULL); + fail_unless (gst_caps_is_empty (caps)); + gst_caps_unref (caps); + + gst_caps_set_simple (src2caps, "clock-rate", G_TYPE_INT, 3, NULL); + caps = gst_pad_peer_query_caps (src1, NULL); + fail_unless (gst_caps_is_equal (caps, sinkcaps)); + gst_caps_unref (caps); + + g_object_set (rtpmux, "seqnum-offset", 100, "timestamp-offset", 1000, + "ssrc", 55, NULL); + + fail_unless (gst_element_set_state (rtpmux, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS); + gst_pad_set_active (sink, TRUE); + gst_pad_set_active (src1, TRUE); + gst_pad_set_active (src2, TRUE); + + gst_caps_set_simple (sinkcaps, + "payload", G_TYPE_INT, 98, "seqnum-base", G_TYPE_UINT, 100, + "clock-base", G_TYPE_UINT, 1000, "ssrc", G_TYPE_UINT, 66, NULL); + caps = gst_caps_new_simple ("application/x-rtp", + "payload", G_TYPE_INT, 98, "clock-rate", G_TYPE_INT, 3, + "seqnum-base", G_TYPE_UINT, 56, "clock-base", G_TYPE_UINT, 57, + "ssrc", G_TYPE_UINT, 66, NULL); + fail_unless (gst_pad_set_caps (src1, caps)); + + gst_segment_init (&segment, GST_FORMAT_TIME); + segment.start = 100000; + fail_unless (gst_pad_push_event (src1, gst_event_new_segment (&segment))); + segment.start = 0; + fail_unless (gst_pad_push_event (src2, gst_event_new_segment (&segment))); + + + for (i = 0; i < count; i++) { + GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT; + + inbuf = gst_rtp_buffer_new_allocate (10, 0, 0); + GST_BUFFER_PTS (inbuf) = i * 1000 + 100000; + GST_BUFFER_DURATION (inbuf) = 1000; + + gst_rtp_buffer_map (inbuf, GST_MAP_WRITE, &rtpbuffer); + + gst_rtp_buffer_set_version (&rtpbuffer, 2); + gst_rtp_buffer_set_payload_type (&rtpbuffer, 98); + gst_rtp_buffer_set_ssrc (&rtpbuffer, 44); + gst_rtp_buffer_set_timestamp (&rtpbuffer, 200 + i); + gst_rtp_buffer_set_seq (&rtpbuffer, 2000 + i); + gst_rtp_buffer_unmap (&rtpbuffer); + fail_unless (gst_pad_push (src1, inbuf) == GST_FLOW_OK); + + if (buffers) + fail_unless (GST_BUFFER_PTS (buffers->data) == i * 1000, "%lld", + GST_BUFFER_PTS (buffers->data)); + + cb (src2, i); + + g_list_foreach (buffers, (GFunc) gst_buffer_unref, NULL); + g_list_free (buffers); + buffers = NULL; + } + + + gst_pad_set_active (sink, FALSE); + gst_pad_set_active (src1, FALSE); + gst_pad_set_active (src2, FALSE); + fail_unless (gst_element_set_state (rtpmux, + GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS); + gst_check_teardown_pad_by_name (rtpmux, "src"); + gst_object_unref (reqpad1); + gst_object_unref (reqpad2); + gst_check_teardown_pad_by_name (rtpmux, "sink_1"); + gst_check_teardown_pad_by_name (rtpmux, sink2); + gst_element_release_request_pad (rtpmux, reqpad1); + gst_element_release_request_pad (rtpmux, reqpad2); + + gst_caps_unref (caps); + gst_caps_replace (&src1caps, NULL); + gst_caps_replace (&src2caps, NULL); + gst_caps_replace (&sinkcaps, NULL); + + gst_check_teardown_element (rtpmux); +} + +static void +basic_check_cb (GstPad * pad, int i) +{ + GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT; + fail_unless (buffers && g_list_length (buffers) == 1); + + gst_rtp_buffer_map (buffers->data, GST_MAP_READ, &rtpbuffer); + fail_unless (gst_rtp_buffer_get_ssrc (&rtpbuffer) == 55); + fail_unless (gst_rtp_buffer_get_timestamp (&rtpbuffer) == + 200 - 57 + 1000 + i); + fail_unless (gst_rtp_buffer_get_seq (&rtpbuffer) == 100 + 1 + i); + gst_rtp_buffer_unmap (&rtpbuffer); +} + + +GST_START_TEST (test_rtpmux_basic) +{ + test_basic ("rtpmux", "sink_2", 10, basic_check_cb); +} + +GST_END_TEST; + +GST_START_TEST (test_rtpdtmfmux_basic) +{ + test_basic ("rtpdtmfmux", "sink_2", 10, basic_check_cb); +} + +GST_END_TEST; + +static void +lock_check_cb (GstPad * pad, int i) +{ + GstBuffer *inbuf; + + if (i % 2) { + fail_unless (buffers == NULL); + } else { + GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT; + + fail_unless (buffers && g_list_length (buffers) == 1); + gst_rtp_buffer_map (buffers->data, GST_MAP_READ, &rtpbuffer); + fail_unless (gst_rtp_buffer_get_ssrc (&rtpbuffer) == 55); + fail_unless (gst_rtp_buffer_get_timestamp (&rtpbuffer) == + 200 - 57 + 1000 + i); + fail_unless (gst_rtp_buffer_get_seq (&rtpbuffer) == 100 + 1 + i); + gst_rtp_buffer_unmap (&rtpbuffer); + + inbuf = gst_rtp_buffer_new_allocate (10, 0, 0); + GST_BUFFER_PTS (inbuf) = i * 1000 + 500; + GST_BUFFER_DURATION (inbuf) = 1000; + gst_rtp_buffer_map (inbuf, GST_MAP_WRITE, &rtpbuffer); + gst_rtp_buffer_set_version (&rtpbuffer, 2); + gst_rtp_buffer_set_payload_type (&rtpbuffer, 98); + gst_rtp_buffer_set_ssrc (&rtpbuffer, 44); + gst_rtp_buffer_set_timestamp (&rtpbuffer, 200 + i); + gst_rtp_buffer_set_seq (&rtpbuffer, 2000 + i); + gst_rtp_buffer_unmap (&rtpbuffer); + fail_unless (gst_pad_push (pad, inbuf) == GST_FLOW_OK); + + + g_list_foreach (buffers, (GFunc) gst_buffer_unref, NULL); + g_list_free (buffers); + buffers = NULL; + } +} + +GST_START_TEST (test_rtpdtmfmux_lock) +{ + test_basic ("rtpdtmfmux", "priority_sink_2", 10, lock_check_cb); +} + +GST_END_TEST; + +static Suite * +rtpmux_suite (void) +{ + Suite *s = suite_create ("rtpmux"); + TCase *tc_chain; + + tc_chain = tcase_create ("rtpmux_basic"); + tcase_add_test (tc_chain, test_rtpmux_basic); + suite_add_tcase (s, tc_chain); + + tc_chain = tcase_create ("rtpdtmfmux_basic"); + tcase_add_test (tc_chain, test_rtpdtmfmux_basic); + suite_add_tcase (s, tc_chain); + + tc_chain = tcase_create ("rtpdtmfmux_lock"); + tcase_add_test (tc_chain, test_rtpdtmfmux_lock); + suite_add_tcase (s, tc_chain); + + return s; +} + +GST_CHECK_MAIN (rtpmux) diff --git a/tests/check/elements/schroenc.c b/tests/check/elements/schroenc.c new file mode 100644 index 00000000..00afa183 --- /dev/null +++ b/tests/check/elements/schroenc.c @@ -0,0 +1,177 @@ +/* GStreamer + * + * Copyright (c) 2010 Sebastian Dröge <sebastian.droege@collabora.co.uk> + * Copyright (c) 2010 David Schleef <ds@schleef.org> + * + * 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. + */ + +#include <gst/check/gstcheck.h> + +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-dirac, " + "width = (int) [1, MAX], " + "height = (int) [1, MAX], " "framerate = (fraction) [0, MAX]")); + +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-raw, " + "format = (string) I420, " + "width = (int) [1, MAX], " + "height = (int) [1, MAX], " "framerate = (fraction) [0, MAX]")); + +static GstPad *sinkpad, *srcpad; + +static GstElement * +setup_schroenc (const gchar * src_caps_str) +{ + GstElement *schroenc; + GstCaps *srccaps = NULL; + GstBus *bus; + + if (src_caps_str) { + srccaps = gst_caps_from_string (src_caps_str); + fail_unless (srccaps != NULL); + } + + schroenc = gst_check_setup_element ("schroenc"); + fail_unless (schroenc != NULL); + srcpad = gst_check_setup_src_pad (schroenc, &srctemplate); + sinkpad = gst_check_setup_sink_pad (schroenc, &sinktemplate); + gst_pad_set_active (srcpad, TRUE); + gst_pad_set_active (sinkpad, TRUE); + + gst_pad_set_caps (srcpad, srccaps); + + bus = gst_bus_new (); + gst_element_set_bus (schroenc, bus); + + fail_unless (gst_element_set_state (schroenc, + GST_STATE_PLAYING) != GST_STATE_CHANGE_FAILURE, + "could not set to playing"); + + if (srccaps) + gst_caps_unref (srccaps); + + buffers = NULL; + return schroenc; +} + +static void +cleanup_schroenc (GstElement * schroenc) +{ + GstBus *bus; + + /* Free parsed buffers */ + gst_check_drop_buffers (); + + bus = GST_ELEMENT_BUS (schroenc); + gst_bus_set_flushing (bus, TRUE); + gst_object_unref (bus); + + gst_pad_set_active (srcpad, FALSE); + gst_pad_set_active (sinkpad, FALSE); + gst_check_teardown_src_pad (schroenc); + gst_check_teardown_sink_pad (schroenc); + gst_check_teardown_element (schroenc); +} + +GST_START_TEST (test_encode_simple) +{ + GstElement *schroenc; + GstBuffer *buffer; + gint i; + GList *l; + GstCaps *outcaps, *sinkcaps; + GstSegment seg; + + schroenc = + setup_schroenc + ("video/x-raw,format=(string)I420,width=(int)320,height=(int)240,framerate=(fraction)25/1"); + + g_object_set (schroenc, "queue-depth", 10, NULL); + + gst_segment_init (&seg, GST_FORMAT_TIME); + seg.stop = gst_util_uint64_scale (20, GST_SECOND, 25); + + fail_unless (gst_pad_push_event (srcpad, gst_event_new_segment (&seg))); + + buffer = gst_buffer_new_allocate (NULL, 320 * 240 + 2 * 160 * 120, NULL); + gst_buffer_memset (buffer, 0, 0, -1); + + for (i = 0; i < 20; i++) { + GST_BUFFER_TIMESTAMP (buffer) = gst_util_uint64_scale (i, GST_SECOND, 25); + GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale (1, GST_SECOND, 25); + fail_unless (gst_pad_push (srcpad, gst_buffer_ref (buffer)) == GST_FLOW_OK); + } + + gst_buffer_unref (buffer); + + /* Only 5 buffers are allowed to be queued now */ + fail_unless (g_list_length (buffers) > 10); + + fail_unless (gst_pad_push_event (srcpad, gst_event_new_eos ())); + + + /* All buffers must be there now */ + fail_unless_equals_int (g_list_length (buffers), 20); + + outcaps = + gst_caps_from_string + ("video/x-dirac,width=(int)320,height=(int)240,framerate=(fraction)25/1"); + + for (l = buffers, i = 0; l; l = l->next, i++) { + buffer = l->data; + + if (i == 0) + fail_if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)); + +#if 0 + fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (buffer), + gst_util_uint64_scale (i, GST_SECOND, 25)); +#endif + fail_unless_equals_uint64 (GST_BUFFER_DURATION (buffer), + gst_util_uint64_scale (1, GST_SECOND, 25)); + + sinkcaps = gst_pad_get_current_caps (sinkpad); + fail_unless (gst_caps_can_intersect (sinkcaps, outcaps)); + gst_caps_unref (sinkcaps); + } + + gst_caps_unref (outcaps); + + cleanup_schroenc (schroenc); +} + +GST_END_TEST; + +static Suite * +schroenc_suite (void) +{ + Suite *s = suite_create ("schroenc"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + + tcase_add_test (tc_chain, test_encode_simple); + + return s; +} + +GST_CHECK_MAIN (schroenc); diff --git a/tests/check/elements/timidity.c b/tests/check/elements/timidity.c new file mode 100644 index 00000000..b30de314 --- /dev/null +++ b/tests/check/elements/timidity.c @@ -0,0 +1,89 @@ +/* GStreamer + * + * unit test for timidity/wildmidi + * + * Copyright (C) <2007> Stefan Kost <ensonic@users.sf.net> + * + * 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. + */ + +#include <unistd.h> + +#include <gst/check/gstcheck.h> +#include <gst/base/gsttypefindhelper.h> + + +GST_START_TEST (test_midi_typefind) +{ + const guint8 midi_header[] = { + 0x4d, 0x54, 0x68, 0x64, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x60, 0x4d, 0x54, + 0x72, 0x6b, 0x00, 0x00 + }; + GstTypeFindProbability prob; + const gchar *type; + GstBuffer *buf; + GstCaps *caps = NULL; + + buf = gst_buffer_new (); + GST_BUFFER_DATA (buf) = (guint8 *) midi_header; + GST_BUFFER_SIZE (buf) = sizeof (midi_header); + GST_BUFFER_OFFSET (buf) = 0; + + caps = gst_type_find_helper_for_buffer (NULL, buf, &prob); + fail_unless (caps != NULL); + GST_LOG ("Found type: %" GST_PTR_FORMAT, caps); + + type = gst_structure_get_name (gst_caps_get_structure (caps, 0)); + fail_unless_equals_string (type, "audio/midi"); + fail_unless (prob > GST_TYPE_FIND_MINIMUM && prob <= GST_TYPE_FIND_MAXIMUM); + + gst_buffer_unref (buf); + gst_caps_unref (caps); + +} + +GST_END_TEST; + + +static Suite * +timidity_suite (void) +{ + Suite *s = suite_create ("timidity"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_midi_typefind); + + return s; +} + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = timidity_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; +} diff --git a/tests/check/elements/viewfinderbin.c b/tests/check/elements/viewfinderbin.c new file mode 100644 index 00000000..c5766052 --- /dev/null +++ b/tests/check/elements/viewfinderbin.c @@ -0,0 +1,103 @@ +/* GStreamer unit test for the viewfinderbin element + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#include <gst/check/gstcheck.h> + +typedef struct +{ + GstElement *pipe; + GstElement *src; + GstElement *vfbin; +} GstViewFinderBinTestContext; + +static void +gstviewfinderbin_init_test_context (GstViewFinderBinTestContext * ctx, + gint num_buffers) +{ + GstElement *sink; + fail_unless (ctx != NULL); + + ctx->pipe = gst_pipeline_new ("pipeline"); + fail_unless (ctx->pipe != NULL); + ctx->src = gst_element_factory_make ("videotestsrc", "src"); + fail_unless (ctx->src != NULL, "Failed to create videotestsrc element"); + sink = gst_element_factory_make ("fakesink", NULL); + ctx->vfbin = gst_element_factory_make ("viewfinderbin", "vfbin"); + fail_unless (ctx->vfbin != NULL, "Failed to create viewfinderbin element"); + g_object_set (ctx->vfbin, "video-sink", sink, NULL); + gst_object_unref (sink); + + if (num_buffers > 0) + g_object_set (ctx->src, "num-buffers", num_buffers, NULL); + + fail_unless (gst_bin_add (GST_BIN (ctx->pipe), ctx->src)); + fail_unless (gst_bin_add (GST_BIN (ctx->pipe), ctx->vfbin)); + fail_unless (gst_element_link (ctx->src, ctx->vfbin)); +} + +static void +gstviewfinderbin_unset_test_context (GstViewFinderBinTestContext * ctx) +{ + gst_element_set_state (ctx->pipe, GST_STATE_NULL); + gst_object_unref (ctx->pipe); + memset (ctx, 0, sizeof (GstViewFinderBinTestContext)); +} + +GST_START_TEST (test_simple_run) +{ + GstViewFinderBinTestContext ctx; + GstBus *bus; + GstMessage *msg; + + gstviewfinderbin_init_test_context (&ctx, 10); + bus = gst_element_get_bus (ctx.pipe); + + fail_if (gst_element_set_state (ctx.pipe, GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE); + + msg = gst_bus_timed_pop_filtered (bus, GST_SECOND * 30, + GST_MESSAGE_EOS | GST_MESSAGE_ERROR); + fail_unless (msg != NULL); + fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS); + gst_message_unref (msg); + + gstviewfinderbin_unset_test_context (&ctx); + gst_object_unref (bus); +} + +GST_END_TEST; + +static Suite * +viewfinderbin_suite (void) +{ + Suite *s = suite_create ("viewfinderbin"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_simple_run); + + return s; +} + +GST_CHECK_MAIN (viewfinderbin); diff --git a/tests/check/elements/voaacenc.c b/tests/check/elements/voaacenc.c new file mode 100644 index 00000000..d12849b7 --- /dev/null +++ b/tests/check/elements/voaacenc.c @@ -0,0 +1,263 @@ +/* GStreamer + * + * unit test for voaacenc + * + * Copyright (C) <2009> Mark Nauwelaerts <mnauw@users.sf.net> + * + * 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. + */ + +#include <unistd.h> + +#include <gst/check/gstcheck.h> +#include <gst/audio/audio.h> + +/* For ease of programming we use globals to keep refs for our floating + * src and sink pads we create; otherwise we always have to do get_pad, + * get_peer, and then remove references in every test function */ +static GstPad *mysrcpad, *mysinkpad; + +#define AUDIO_CAPS_STRING "audio/x-raw, " \ + "format = (string) " GST_AUDIO_NE (S16) ", "\ + "layout = (string) interleaved, " \ + "rate = (int) 48000, " \ + "channels = (int) 2, " \ + "channel-mask = (bitmask) 3" + +#define AAC_RAW_CAPS_STRING "audio/mpeg, " \ + "mpegversion = (int) 4, " \ + "rate = (int) 48000, " \ + "channels = (int) 2, " \ + "stream-format = \"raw\"" + +#define AAC_ADTS_CAPS_STRING "audio/mpeg, " \ + "mpegversion = (int) 4, " \ + "rate = (int) 48000, " \ + "channels = (int) 2, " \ + "stream-format = \"adts\"" + + +static GstStaticPadTemplate sinktemplate_adts = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (AAC_ADTS_CAPS_STRING)); + +static GstStaticPadTemplate sinktemplate_raw = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (AAC_RAW_CAPS_STRING)); + + +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (AUDIO_CAPS_STRING)); + + +static GstElement * +setup_voaacenc (gboolean adts) +{ + GstElement *voaacenc; + + GST_DEBUG ("setup_voaacenc"); + voaacenc = gst_check_setup_element ("voaacenc"); + mysrcpad = gst_check_setup_src_pad (voaacenc, &srctemplate); + + if (adts) + mysinkpad = gst_check_setup_sink_pad (voaacenc, &sinktemplate_adts); + else + mysinkpad = gst_check_setup_sink_pad (voaacenc, &sinktemplate_raw); + + gst_pad_set_active (mysrcpad, TRUE); + gst_pad_set_active (mysinkpad, TRUE); + + return voaacenc; +} + +static void +cleanup_voaacenc (GstElement * voaacenc) +{ + GST_DEBUG ("cleanup_aacenc"); + gst_element_set_state (voaacenc, GST_STATE_NULL); + + gst_pad_set_active (mysrcpad, FALSE); + gst_pad_set_active (mysinkpad, FALSE); + gst_check_teardown_src_pad (voaacenc); + gst_check_teardown_sink_pad (voaacenc); + gst_check_teardown_element (voaacenc); +} + +static void +do_test (gboolean adts) +{ + GstElement *voaacenc; + GstBuffer *inbuffer, *outbuffer; + GstCaps *caps; + gint i, num_buffers; + const gint nbuffers = 10; + + voaacenc = setup_voaacenc (adts); + fail_unless (gst_element_set_state (voaacenc, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + /* corresponds to audio buffer mentioned in the caps */ + inbuffer = gst_buffer_new_and_alloc (1024 * nbuffers * 2 * 2); + /* makes valgrind's memcheck happier */ + gst_buffer_memset (inbuffer, 0, 0, 1024 * nbuffers * 2 * 2); + caps = gst_caps_from_string (AUDIO_CAPS_STRING); + + gst_pad_set_caps (mysrcpad, caps); + gst_caps_unref (caps); + GST_BUFFER_TIMESTAMP (inbuffer) = 0; + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + + /* send eos to have all flushed if needed */ + fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()) == TRUE); + + num_buffers = g_list_length (buffers); + fail_unless_equals_int (num_buffers, nbuffers); + + /* clean up buffers */ + for (i = 0; i < num_buffers; ++i) { + gint header = 0, id; + GstMapInfo map; + gsize size; + guint8 *data; + + outbuffer = GST_BUFFER (buffers->data); + fail_if (outbuffer == NULL); + + gst_buffer_map (outbuffer, &map, GST_MAP_READ); + data = map.data; + size = map.size; + + if (adts) { + gboolean protection; + gint k; + + fail_if (size < 7); + protection = !(data[1] & 0x1); + /* expect only 1 raw data block */ + k = (data[6] & 0x3) + 1; + fail_if (k != 1); + + header = 7; + if (protection) + header += (k - 1) * 2 + 2; + + /* check header */ + k = GST_READ_UINT16_BE (data) & 0xFFF6; + /* sync */ + fail_unless (k == 0xFFF0); + k = data[2]; + /* profile */ + fail_unless ((k >> 6) == 0x1); + /* rate */ + fail_unless (((k >> 2) & 0xF) == 0x3); + /* channels */ + fail_unless ((k & 0x1) == 0); + k = data[3]; + fail_unless ((k >> 6) == 0x2); + + } else { + GstCaps *caps; + GstStructure *s; + const GValue *value; + GstBuffer *buf; + gint k; + GstMapInfo cmap; + + caps = gst_pad_get_current_caps (mysinkpad); + fail_if (caps == NULL); + s = gst_caps_get_structure (caps, 0); + fail_if (s == NULL); + value = gst_structure_get_value (s, "codec_data"); + fail_if (value == NULL); + buf = gst_value_get_buffer (value); + fail_if (buf == NULL); + gst_buffer_map (buf, &cmap, GST_MAP_READ); + fail_if (cmap.size < 2); + k = GST_READ_UINT16_BE (cmap.data); + gst_buffer_unmap (buf, &cmap); + /* profile, rate, channels */ + fail_unless ((k & 0xFFF8) == ((0x02 << 11) | (0x3 << 7) | (0x02 << 3))); + gst_caps_unref (caps); + + } + + fail_if (size <= header); + id = data[header] & (0x7 << 5); + /* allow all but ID_END or ID_LFE */ + fail_if (id == 7 || id == 3); + gst_buffer_unmap (outbuffer, &map); + + buffers = g_list_remove (buffers, outbuffer); + + ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1); + gst_buffer_unref (outbuffer); + outbuffer = NULL; + } + + cleanup_voaacenc (voaacenc); + g_list_free (buffers); + buffers = NULL; +} + +GST_START_TEST (test_adts) +{ + do_test (TRUE); +} + +GST_END_TEST; + +GST_START_TEST (test_raw) +{ + do_test (FALSE); +} + +GST_END_TEST; + +static Suite * +voaacenc_suite (void) +{ + Suite *s = suite_create ("voaacenc"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_adts); + tcase_add_test (tc_chain, test_raw); + + return s; +} + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = voaacenc_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; +} diff --git a/tests/check/elements/voamrwbenc.c b/tests/check/elements/voamrwbenc.c new file mode 100644 index 00000000..b3e674ce --- /dev/null +++ b/tests/check/elements/voamrwbenc.c @@ -0,0 +1,194 @@ +/* GStreamer + * + * unit test for voamrwbenc + * + * Copyright (C) <2011> Mark Nauwelaerts <mark.nauwelaerts@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. + */ + +#include <unistd.h> + +#include <gst/check/gstcheck.h> + +/* For ease of programming we use globals to keep refs for our floating + * src and sink pads we create; otherwise we always have to do get_pad, + * get_peer, and then remove references in every test function */ +static GstPad *mysrcpad, *mysinkpad; + +#if G_BYTE_ORDER == G_BIG_ENDIAN +#define AFORMAT "S16BE" +#else +#define AFORMAT "S16LE" +#endif + +#define AUDIO_CAPS_STRING "audio/x-raw, " \ + "format = (string) " AFORMAT ", "\ + "layout = (string) interleaved, " \ + "rate = (int) 16000, " \ + "channels = (int) 1 " + + +#define AMRWB_CAPS_STRING "audio/AMR-WB" + + +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (AMRWB_CAPS_STRING)); + + +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (AUDIO_CAPS_STRING)); + + +static GstElement * +setup_voamrwbenc (void) +{ + GstElement *voamrwbenc; + + GST_DEBUG ("setup_voamrwbenc"); + voamrwbenc = gst_check_setup_element ("voamrwbenc"); + /* ensure mode as expected */ + g_object_set (voamrwbenc, "band-mode", 0, NULL); + mysrcpad = gst_check_setup_src_pad (voamrwbenc, &srctemplate); + mysinkpad = gst_check_setup_sink_pad (voamrwbenc, &sinktemplate); + gst_pad_set_active (mysrcpad, TRUE); + gst_pad_set_active (mysinkpad, TRUE); + + return voamrwbenc; +} + +static void +cleanup_voamrwbenc (GstElement * voamrwbenc) +{ + GST_DEBUG ("cleanup_aacenc"); + gst_element_set_state (voamrwbenc, GST_STATE_NULL); + + gst_pad_set_active (mysrcpad, FALSE); + gst_pad_set_active (mysinkpad, FALSE); + gst_check_teardown_src_pad (voamrwbenc); + gst_check_teardown_sink_pad (voamrwbenc); + gst_check_teardown_element (voamrwbenc); +} + +static void +do_test (void) +{ + GstElement *voamrwbenc; + GstBuffer *inbuffer, *outbuffer; + GstCaps *caps; + gint i, num_buffers; + const gint nbuffers = 10; + + voamrwbenc = setup_voamrwbenc (); + fail_unless (gst_element_set_state (voamrwbenc, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + /* corresponds to audio buffer mentioned in the caps */ + inbuffer = gst_buffer_new_and_alloc (320 * nbuffers * 2); + /* makes valgrind's memcheck happier */ + gst_buffer_memset (inbuffer, 0, 0, 1024 * nbuffers * 2 * 2); + caps = gst_caps_from_string (AUDIO_CAPS_STRING); + + gst_pad_set_caps (mysrcpad, caps); + gst_caps_unref (caps); + GST_BUFFER_TIMESTAMP (inbuffer) = 0; + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + + /* send eos to have all flushed if needed */ + fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()) == TRUE); + + num_buffers = g_list_length (buffers); + fail_unless_equals_int (num_buffers, nbuffers); + + /* clean up buffers */ + for (i = 0; i < num_buffers; ++i) { + GstMapInfo map; + gsize size; + guint8 *data; + GstClockTime time, dur; + + outbuffer = GST_BUFFER (buffers->data); + fail_if (outbuffer == NULL); + + gst_buffer_map (outbuffer, &map, GST_MAP_READ); + data = map.data; + size = map.size; + + /* at least for mode 0 */ + fail_unless (size == 18); + fail_unless ((data[0] & 0x83) == 0); + fail_unless (((data[0] >> 3) & 0xF) == 0); + + time = GST_BUFFER_TIMESTAMP (outbuffer); + dur = GST_BUFFER_DURATION (outbuffer); + fail_unless (time == 20 * GST_MSECOND * i); + fail_unless (dur == 20 * GST_MSECOND); + gst_buffer_unmap (outbuffer, &map); + + buffers = g_list_remove (buffers, outbuffer); + + ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1); + gst_buffer_unref (outbuffer); + outbuffer = NULL; + } + + cleanup_voamrwbenc (voamrwbenc); + g_list_free (buffers); + buffers = NULL; +} + +GST_START_TEST (test_enc) +{ + do_test (); +} + +GST_END_TEST; + + +static Suite * +voamrwbenc_suite (void) +{ + Suite *s = suite_create ("voamrwbenc"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_enc); + + return s; +} + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = voamrwbenc_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; +} diff --git a/tests/check/elements/vp8dec.c b/tests/check/elements/vp8dec.c new file mode 100644 index 00000000..25648401 --- /dev/null +++ b/tests/check/elements/vp8dec.c @@ -0,0 +1,178 @@ +/* GStreamer + * + * Copyright (c) 2010 Sebastian Dröge <sebastian.droege@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. + */ + +#include <gst/check/gstcheck.h> + +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-raw, " + "format = (string) I420, " + "width = (int) [1, MAX], " + "height = (int) [1, MAX], " "framerate = (fraction) [0, MAX]")); + +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-raw, " + "format = (string) I420, " + "width = (int) [1, MAX], " + "height = (int) [1, MAX], " "framerate = (fraction) [0, MAX]")); + +static GstPad *sinkpad, *srcpad; + +static GstElement * +setup_vp8dec (const gchar * src_caps_str) +{ + GstElement *bin; + GstElement *vp8enc, *vp8dec; + GstCaps *srccaps = NULL; + GstBus *bus; + GstPad *ghostpad, *targetpad; + + if (src_caps_str) { + srccaps = gst_caps_from_string (src_caps_str); + fail_unless (srccaps != NULL); + } + + bin = gst_bin_new ("bin"); + + vp8enc = gst_check_setup_element ("vp8enc"); + fail_unless (vp8enc != NULL); + vp8dec = gst_check_setup_element ("vp8dec"); + fail_unless (vp8dec != NULL); + + gst_bin_add_many (GST_BIN (bin), vp8enc, vp8dec, NULL); + fail_unless (gst_element_link_pads (vp8enc, "src", vp8dec, "sink")); + + targetpad = gst_element_get_static_pad (vp8enc, "sink"); + fail_unless (targetpad != NULL); + ghostpad = gst_ghost_pad_new ("sink", targetpad); + fail_unless (ghostpad != NULL); + gst_element_add_pad (bin, ghostpad); + gst_object_unref (targetpad); + + targetpad = gst_element_get_static_pad (vp8dec, "src"); + fail_unless (targetpad != NULL); + ghostpad = gst_ghost_pad_new ("src", targetpad); + fail_unless (ghostpad != NULL); + gst_element_add_pad (bin, ghostpad); + gst_object_unref (targetpad); + + srcpad = gst_check_setup_src_pad (bin, &srctemplate); + sinkpad = gst_check_setup_sink_pad (bin, &sinktemplate); + gst_pad_set_active (srcpad, TRUE); + gst_pad_set_active (sinkpad, TRUE); + fail_unless (gst_pad_set_caps (srcpad, srccaps)); + + bus = gst_bus_new (); + gst_element_set_bus (bin, bus); + + fail_unless (gst_element_set_state (bin, + GST_STATE_PLAYING) != GST_STATE_CHANGE_FAILURE, + "could not set to playing"); + + if (srccaps) + gst_caps_unref (srccaps); + + buffers = NULL; + return bin; +} + +static void +cleanup_vp8dec (GstElement * bin) +{ + GstBus *bus; + + /* Free parsed buffers */ + gst_check_drop_buffers (); + + bus = GST_ELEMENT_BUS (bin); + gst_bus_set_flushing (bus, TRUE); + gst_object_unref (bus); + + gst_pad_set_active (srcpad, FALSE); + gst_pad_set_active (sinkpad, FALSE); + + gst_check_teardown_src_pad (bin); + gst_check_teardown_sink_pad (bin); + gst_check_teardown_element (bin); +} + +GST_START_TEST (test_decode_simple) +{ + GstElement *bin; + GstBuffer *buffer; + gint i; + GList *l; + GstSegment seg; + + bin = + setup_vp8dec + ("video/x-raw,format=(string)I420,width=(int)320,height=(int)240,framerate=(fraction)25/1"); + + gst_segment_init (&seg, GST_FORMAT_TIME); + seg.stop = gst_util_uint64_scale (20, GST_SECOND, 25); + fail_unless (gst_pad_push_event (srcpad, gst_event_new_segment (&seg))); + + buffer = gst_buffer_new_and_alloc (320 * 240 + 2 * 160 * 120); + gst_buffer_memset (buffer, 0, 0, -1); + + for (i = 0; i < 20; i++) { + GST_BUFFER_TIMESTAMP (buffer) = gst_util_uint64_scale (i, GST_SECOND, 25); + GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale (1, GST_SECOND, 25); + fail_unless (gst_pad_push (srcpad, gst_buffer_ref (buffer)) == GST_FLOW_OK); + } + + gst_buffer_unref (buffer); + + fail_unless (gst_pad_push_event (srcpad, gst_event_new_eos ())); + + /* All buffers must be there now */ + fail_unless_equals_int (g_list_length (buffers), 20); + + for (l = buffers, i = 0; l; l = l->next, i++) { + buffer = l->data; + + fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (buffer), + gst_util_uint64_scale (i, GST_SECOND, 25)); + fail_unless_equals_uint64 (GST_BUFFER_DURATION (buffer), + gst_util_uint64_scale (1, GST_SECOND, 25)); + } + + cleanup_vp8dec (bin); +} + +GST_END_TEST; + +static Suite * +vp8dec_suite (void) +{ + Suite *s = suite_create ("vp8dec"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + + tcase_add_test (tc_chain, test_decode_simple); + + return s; +} + +GST_CHECK_MAIN (vp8dec); diff --git a/tests/check/elements/vp8enc.c b/tests/check/elements/vp8enc.c new file mode 100644 index 00000000..19be2479 --- /dev/null +++ b/tests/check/elements/vp8enc.c @@ -0,0 +1,168 @@ +/* GStreamer + * + * Copyright (c) 2010 Sebastian Dröge <sebastian.droege@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. + */ + +#include <gst/check/gstcheck.h> + +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-vp8, " + "width = (int) [1, MAX], " + "height = (int) [1, MAX], " "framerate = (fraction) [0, MAX]")); + +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-raw, " + "format = (string) I420, " + "width = (int) [1, MAX], " + "height = (int) [1, MAX], " "framerate = (fraction) [0, MAX]")); + +static GstPad *sinkpad, *srcpad; + +static GstElement * +setup_vp8enc (const gchar * src_caps_str) +{ + GstElement *vp8enc; + GstCaps *srccaps = NULL; + GstBus *bus; + + if (src_caps_str) { + srccaps = gst_caps_from_string (src_caps_str); + fail_unless (srccaps != NULL); + } + + vp8enc = gst_check_setup_element ("vp8enc"); + fail_unless (vp8enc != NULL); + srcpad = gst_check_setup_src_pad (vp8enc, &srctemplate); + sinkpad = gst_check_setup_sink_pad (vp8enc, &sinktemplate); + gst_pad_set_active (srcpad, TRUE); + gst_pad_set_active (sinkpad, TRUE); + fail_unless (gst_pad_set_caps (srcpad, srccaps)); + + bus = gst_bus_new (); + gst_element_set_bus (vp8enc, bus); + + fail_unless (gst_element_set_state (vp8enc, + GST_STATE_PLAYING) != GST_STATE_CHANGE_FAILURE, + "could not set to playing"); + + if (srccaps) + gst_caps_unref (srccaps); + + buffers = NULL; + return vp8enc; +} + +static void +cleanup_vp8enc (GstElement * vp8enc) +{ + GstBus *bus; + + /* Free parsed buffers */ + gst_check_drop_buffers (); + + bus = GST_ELEMENT_BUS (vp8enc); + gst_bus_set_flushing (bus, TRUE); + gst_object_unref (bus); + + gst_pad_set_active (srcpad, FALSE); + gst_pad_set_active (sinkpad, FALSE); + gst_check_teardown_src_pad (vp8enc); + gst_check_teardown_sink_pad (vp8enc); + gst_check_teardown_element (vp8enc); +} + +GST_START_TEST (test_encode_simple) +{ + GstElement *vp8enc; + GstBuffer *buffer; + gint i; + GList *l; + GstCaps *outcaps; + GstSegment seg; + + vp8enc = + setup_vp8enc + ("video/x-raw,format=(string)I420,width=(int)320,height=(int)240,framerate=(fraction)25/1"); + + g_object_set (vp8enc, "max-latency", 5, NULL); + + gst_segment_init (&seg, GST_FORMAT_TIME); + seg.stop = gst_util_uint64_scale (20, GST_SECOND, 25); + fail_unless (gst_pad_push_event (srcpad, gst_event_new_segment (&seg))); + + buffer = gst_buffer_new_and_alloc (320 * 240 + 2 * 160 * 120); + gst_buffer_memset (buffer, 0, 0, -1); + + for (i = 0; i < 20; i++) { + GST_BUFFER_TIMESTAMP (buffer) = gst_util_uint64_scale (i, GST_SECOND, 25); + GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale (1, GST_SECOND, 25); + fail_unless (gst_pad_push (srcpad, gst_buffer_ref (buffer)) == GST_FLOW_OK); + } + + gst_buffer_unref (buffer); + + /* Only 5 buffers are allowed to be queued now */ + fail_unless (g_list_length (buffers) > 15); + + fail_unless (gst_pad_push_event (srcpad, gst_event_new_eos ())); + + + /* All buffers must be there now */ + fail_unless_equals_int (g_list_length (buffers), 20); + + outcaps = + gst_caps_from_string + ("video/x-vp8,width=(int)320,height=(int)240,framerate=(fraction)25/1"); + + for (l = buffers, i = 0; l; l = l->next, i++) { + buffer = l->data; + + if (i == 0) + fail_if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)); + + fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (buffer), + gst_util_uint64_scale (i, GST_SECOND, 25)); + fail_unless_equals_uint64 (GST_BUFFER_DURATION (buffer), + gst_util_uint64_scale (1, GST_SECOND, 25)); + } + + gst_caps_unref (outcaps); + + cleanup_vp8enc (vp8enc); +} + +GST_END_TEST; + +static Suite * +vp8enc_suite (void) +{ + Suite *s = suite_create ("vp8enc"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + + tcase_add_test (tc_chain, test_encode_simple); + + return s; +} + +GST_CHECK_MAIN (vp8enc); diff --git a/tests/check/elements/zbar.c b/tests/check/elements/zbar.c new file mode 100644 index 00000000..38f4961e --- /dev/null +++ b/tests/check/elements/zbar.c @@ -0,0 +1,116 @@ +/* GStreamer zbar element unit test + * + * Copyright (C) 2010 Tim-Philipp Müller <tim centricular net> + * + * 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. + */ + +#include <gst/check/gstcheck.h> + +GST_START_TEST (test_still_image) +{ + GstMessage *zbar_msg = NULL; + const GstStructure *s; + GstElement *pipeline, *src, *dec, *csp, *zbar, *sink; + const gchar *type, *symbol; + gchar *path; + int qual; + + pipeline = gst_pipeline_new ("pipeline"); + + src = gst_element_factory_make ("filesrc", NULL); + dec = gst_element_factory_make ("pngdec", NULL); + csp = gst_element_factory_make ("ffmpegcolorspace", NULL); + zbar = gst_element_factory_make ("zbar", NULL); + sink = gst_element_factory_make ("fakesink", NULL); + + path = g_build_filename (GST_TEST_FILES_PATH, "barcode.png", NULL); + GST_LOG ("reading file '%s'", path); + g_object_set (src, "location", path, NULL); + g_free (path); + + gst_bin_add_many (GST_BIN (pipeline), src, dec, csp, zbar, sink, NULL); + fail_unless (gst_element_link_many (src, dec, csp, zbar, sink, NULL)); + + fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_PLAYING), + GST_STATE_CHANGE_ASYNC); + + do { + GstMessage *msg; + + msg = gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (pipeline), -1, + GST_MESSAGE_ELEMENT | GST_MESSAGE_EOS | GST_MESSAGE_ERROR); + + GST_INFO ("message: %" GST_PTR_FORMAT, msg); + + fail_if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR); + + if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS) { + gst_message_unref (msg); + break; + } + + if (GST_MESSAGE_SRC (msg) == GST_OBJECT_CAST (zbar) && zbar_msg == NULL) { + zbar_msg = msg; + } else { + gst_message_unref (msg); + } + } while (1); + + fail_unless (zbar_msg != NULL); + s = gst_message_get_structure (zbar_msg); + fail_unless (s != NULL); + + fail_unless (gst_structure_has_name (s, "barcode")); + fail_unless (gst_structure_has_field (s, "timestamp")); + fail_unless (gst_structure_has_field (s, "type")); + fail_unless (gst_structure_has_field (s, "symbol")); + fail_unless (gst_structure_has_field (s, "quality")); + fail_unless (gst_structure_get_int (s, "quality", &qual)); + fail_unless (qual >= 90); + type = gst_structure_get_string (s, "type"); + fail_unless_equals_string (type, "EAN-13"); + symbol = gst_structure_get_string (s, "symbol"); + fail_unless_equals_string (symbol, "9876543210128"); + + fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_NULL), + GST_STATE_CHANGE_SUCCESS); + + gst_object_unref (pipeline); + gst_message_unref (zbar_msg); +} + +GST_END_TEST; + +static Suite * +zbar_suite (void) +{ + Suite *s = suite_create ("zbar"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + + if (!gst_registry_check_feature_version (gst_registry_get (), "pngdec", 0, 10, + 25)) { + GST_INFO ("Skipping test, pngdec either not available or too old"); + } else { + tcase_add_test (tc_chain, test_still_image); + } + + return s; +} + +GST_CHECK_MAIN (zbar); |