From 808a51dc0e2011c24eee9c1a691473ec2886aa49 Mon Sep 17 00:00:00 2001 From: Florin Apostol Date: Tue, 16 Feb 2016 11:37:44 +0000 Subject: [PATCH] dashdemux: tests: added content protection test Test content protection Configure 3 content protection sources: - a uuid scheme/value pair - a non uuid scheme/value pair (dash recognises only uuid schemes) - a complex uuid scheme, with trailing spaces and capital letters in scheme uri Only the uuid scheme should be recognised. We expect to receive 2 content protection events https://bugzilla.gnome.org/show_bug.cgi?id=758064 --- tests/check/elements/adaptive_demux_engine.c | 26 ++++ tests/check/elements/adaptive_demux_engine.h | 11 ++ tests/check/elements/dash_demux.c | 191 ++++++++++++++++++++++++++- 3 files changed, 227 insertions(+), 1 deletion(-) diff --git a/tests/check/elements/adaptive_demux_engine.c b/tests/check/elements/adaptive_demux_engine.c index 70f94cd..4662a00 100644 --- a/tests/check/elements/adaptive_demux_engine.c +++ b/tests/check/elements/adaptive_demux_engine.c @@ -195,6 +195,29 @@ on_demux_sent_data (GstPad * pad, GstPadProbeInfo * info, gpointer data) return GST_PAD_PROBE_OK; } +/* callback called when dash sends event to AppSink */ +static GstPadProbeReturn +on_demux_sent_event (GstPad * pad, GstPadProbeInfo * info, gpointer data) +{ + GstAdaptiveDemuxTestEnginePrivate *priv = + (GstAdaptiveDemuxTestEnginePrivate *) data; + GstAdaptiveDemuxTestOutputStream *stream = NULL; + GstEvent *event; + + event = GST_PAD_PROBE_INFO_EVENT (info); + + GST_TEST_LOCK (&priv->engine); + + if (priv->callbacks->demux_sent_event) { + stream = getTestOutputDataByPad (priv, pad, TRUE); + (*priv->callbacks->demux_sent_event) (&priv->engine, + stream, event, priv->user_data); + } + + GST_TEST_UNLOCK (&priv->engine); + return GST_PAD_PROBE_OK; +} + /* callback called when demux receives events from GstFakeSoupHTTPSrc */ static GstPadProbeReturn on_demuxReceivesEvent (GstPad * pad, GstPadProbeInfo * info, gpointer data) @@ -310,6 +333,9 @@ on_demuxNewPad (GstElement * demux, GstPad * pad, gpointer user_data) gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, (GstPadProbeCallback) on_demux_sent_data, priv, NULL); + gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM | + GST_PAD_PROBE_TYPE_EVENT_FLUSH, + (GstPadProbeCallback) on_demux_sent_event, priv, NULL); gobject_class = G_OBJECT_GET_CLASS (sink); if (g_object_class_find_property (gobject_class, "sync")) { GST_DEBUG ("Setting sync=FALSE on AppSink"); diff --git a/tests/check/elements/adaptive_demux_engine.h b/tests/check/elements/adaptive_demux_engine.h index 3eb553d..372431e 100644 --- a/tests/check/elements/adaptive_demux_engine.h +++ b/tests/check/elements/adaptive_demux_engine.h @@ -136,6 +136,17 @@ typedef struct _GstAdaptiveDemuxTestCallbacks GstBuffer * buffer, gpointer user_data); /** + * demux_sent_event: called each time the demux sends event to AppSink + * @engine: #GstAdaptiveDemuxTestEngine + * @stream: #GstAdaptiveDemuxTestOutputStream + * @event: the #GstEvent that was sent by demux + * @user_data: the user_data passed to gst_adaptive_demux_test_run() + */ + gboolean (*demux_sent_event) (GstAdaptiveDemuxTestEngine *engine, + GstAdaptiveDemuxTestOutputStream * stream, + GstEvent * event, gpointer user_data); + + /** * bus_error_message: called if an error is posted to the bus * @engine: #GstAdaptiveDemuxTestEngine * @msg: the #GstMessage that contains the error diff --git a/tests/check/elements/dash_demux.c b/tests/check/elements/dash_demux.c index 8e99538..7733044 100644 --- a/tests/check/elements/dash_demux.c +++ b/tests/check/elements/dash_demux.c @@ -46,6 +46,9 @@ typedef struct _GstTestHTTPSrcTestData typedef struct _GstDashDemuxTestCase { GstAdaptiveDemuxTestCase parent; + + /* the number of Protection Events sent to each pad */ + GstStructure *countContentProtectionEvents; } GstDashDemuxTestCase; GType gst_dash_demux_test_case_get_type (void); @@ -97,12 +100,17 @@ gst_dash_demux_test_case_class_init (GstDashDemuxTestCaseClass * klass) static void gst_dash_demux_test_case_init (GstDashDemuxTestCase * test_case) { + test_case->countContentProtectionEvents = NULL; gst_dash_demux_test_case_clear (test_case); } static void gst_dash_demux_test_case_clear (GstDashDemuxTestCase * test_case) { + if (test_case->countContentProtectionEvents) { + gst_structure_free (test_case->countContentProtectionEvents); + test_case->countContentProtectionEvents = NULL; + } } static void @@ -686,7 +694,8 @@ run_seek_position_test (gdouble rate, GstSeekType start_type, * first chunk of at least one byte has already arrived in AppSink */ if (seek_threshold_bytes) - GST_ADAPTIVE_DEMUX_TEST_CASE (testData)->threshold_for_seek = seek_threshold_bytes; + GST_ADAPTIVE_DEMUX_TEST_CASE (testData)->threshold_for_seek = + seek_threshold_bytes; else GST_ADAPTIVE_DEMUX_TEST_CASE (testData)->threshold_for_seek = 4687 + 1; @@ -1318,6 +1327,185 @@ GST_START_TEST (testQuery) GST_END_TEST; +static gboolean +testContentProtectionDashdemuxSendsEvent (GstAdaptiveDemuxTestEngine * engine, + GstAdaptiveDemuxTestOutputStream * stream, + GstEvent * event, gpointer user_data) +{ + GstDashDemuxTestCase *test_case = GST_DASH_DEMUX_TEST_CASE (user_data); + const gchar *system_id; + GstBuffer *data; + const gchar *origin; + GstMapInfo info; + gchar *value; + gchar *name; + guint event_count = 0; + + GST_DEBUG ("received event %s", GST_EVENT_TYPE_NAME (event)); + + if (GST_EVENT_TYPE (event) != GST_EVENT_PROTECTION) { + return TRUE; + } + + /* we expect content protection events only on video pad */ + name = gst_pad_get_name (stream->pad); + fail_unless (g_strcmp0 (name, "video_00") == 0); + gst_event_parse_protection (event, &system_id, &data, &origin); + + gst_buffer_map (data, &info, GST_MAP_READ); + + value = g_malloc (info.size + 1); + strncpy (value, (gchar *) info.data, info.size); + value[info.size] = 0; + gst_buffer_unmap (data, &info); + + if (g_strcmp0 (system_id, "11111111-AAAA-BBBB-CCCC-123456789ABC") == 0) { + fail_unless (g_strcmp0 (origin, "dash/mpd") == 0); + fail_unless (g_strcmp0 (value, "test value") == 0); + } else if (g_strcmp0 (system_id, "5e629af5-38da-4063-8977-97ffbd9902d4") == 0) { + const gchar *str; + + fail_unless (g_strcmp0 (origin, "dash/mpd") == 0); + + /* We can't do a simple compare of value (which should be an XML dump + of the ContentProtection element), because the whitespace + formatting from xmlDump might differ between versions of libxml */ + str = strstr (value, ""); + fail_if (str == NULL); + str = strstr (value, ""); + fail_if (str == NULL); + str = strstr (value, "urn:marlin:kid:02020202020202020202020202020202"); + fail_if (str == NULL); + str = strstr (value, ""); + fail_if (str == NULL); + } else { + fail ("unexpected content protection event '%s'", system_id); + } + + g_free (value); + + fail_if (test_case->countContentProtectionEvents == NULL); + gst_structure_get_uint (test_case->countContentProtectionEvents, name, + &event_count); + event_count++; + gst_structure_set (test_case->countContentProtectionEvents, name, G_TYPE_UINT, + event_count, NULL); + + g_free (name); + return TRUE; +} + +/* + * Test content protection + * Configure 3 content protection sources: + * - a uuid scheme/value pair + * - a non uuid scheme/value pair (dash recognises only uuid schemes) + * - a complex uuid scheme, with trailing spaces and capital letters in scheme uri + * Only the uuid scheme will be recognised. We expect to receive 2 content + * protection events + */ +GST_START_TEST (testContentProtection) +{ + const gchar *mpd = + "" + "" + " " + " " + " " + " " + " audio.webm" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " urn:marlin:kid:02020202020202020202020202020202" + " " + " " + " " + " video.webm" + " " + " " + " " + " "; + + GstDashDemuxTestInputData inputTestData[] = { + {"http://unit.test/test.mpd", (guint8 *) mpd, 0}, + {"http://unit.test/audio.webm", NULL, 5000}, + {"http://unit.test/video.webm", NULL, 9000}, + {NULL, NULL, 0}, + }; + GstAdaptiveDemuxTestExpectedOutput outputTestData[] = { + {"audio_00", 5000, NULL}, + {"video_00", 9000, NULL}, + }; + GstTestHTTPSrcCallbacks http_src_callbacks = { 0 }; + GstTestHTTPSrcTestData http_src_test_data = { 0 }; + GstAdaptiveDemuxTestCallbacks test_callbacks = { 0 }; + GstDashDemuxTestCase *testData; + guint event_count = 0; + + http_src_callbacks.src_start = gst_dashdemux_http_src_start; + http_src_callbacks.src_create = gst_dashdemux_http_src_create; + http_src_test_data.input = inputTestData; + gst_test_http_src_install_callbacks (&http_src_callbacks, + &http_src_test_data); + + test_callbacks.appsink_received_data = + gst_adaptive_demux_test_check_received_data; + test_callbacks.appsink_eos = + gst_adaptive_demux_test_check_size_of_received_data; + test_callbacks.demux_sent_event = testContentProtectionDashdemuxSendsEvent; + + testData = gst_dash_demux_test_case_new (); + COPY_OUTPUT_TEST_DATA (outputTestData, testData); + testData->countContentProtectionEvents = + gst_structure_new_empty ("countContentProtectionEvents"); + gst_adaptive_demux_test_run (DEMUX_ELEMENT_NAME, "http://unit.test/test.mpd", + &test_callbacks, testData); + + fail_unless (gst_structure_has_field_typed + (testData->countContentProtectionEvents, "video_00", G_TYPE_UINT)); + + gst_structure_get_uint (testData->countContentProtectionEvents, "video_00", + &event_count); + fail_unless (event_count == 2); + + g_object_unref (testData); + if (http_src_test_data.data) + gst_structure_free (http_src_test_data.data); +} + +GST_END_TEST; + static Suite * dash_demux_suite (void) { @@ -1342,6 +1530,7 @@ dash_demux_suite (void) tcase_add_test (tc_basicTest, testMediaDownloadErrorLastFragment); tcase_add_test (tc_basicTest, testMediaDownloadErrorMiddleFragment); tcase_add_test (tc_basicTest, testQuery); + tcase_add_test (tc_basicTest, testContentProtection); tcase_add_unchecked_fixture (tc_basicTest, gst_adaptive_demux_test_setup, gst_adaptive_demux_test_teardown); -- 2.7.4