| /* GStreamer |
| * |
| * unit test for qtdemux |
| * |
| * Copyright (C) <2016> Edward Hervey <edward@centricular.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., 51 Franklin St, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| */ |
| |
| #include "qtdemux.h" |
| |
| typedef struct |
| { |
| GstPad *srcpad; |
| guint expected_size; |
| GstClockTime expected_time; |
| } CommonTestData; |
| |
| static GstPadProbeReturn |
| qtdemux_probe (GstPad * pad, GstPadProbeInfo * info, CommonTestData * data) |
| { |
| GstBuffer *buf = GST_PAD_PROBE_INFO_BUFFER (info); |
| |
| fail_unless_equals_int (gst_buffer_get_size (buf), data->expected_size); |
| fail_unless_equals_uint64 (GST_BUFFER_PTS (buf), data->expected_time); |
| gst_buffer_unref (buf); |
| return GST_PAD_PROBE_HANDLED; |
| } |
| |
| static void |
| qtdemux_pad_added_cb (GstElement * element, GstPad * pad, CommonTestData * data) |
| { |
| data->srcpad = pad; |
| gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, |
| (GstPadProbeCallback) qtdemux_probe, data, NULL); |
| } |
| |
| GST_START_TEST (test_qtdemux_input_gap) |
| { |
| GstElement *qtdemux; |
| GstPad *sinkpad; |
| CommonTestData data = { 0, }; |
| GstBuffer *inbuf; |
| GstSegment segment; |
| GstEvent *event; |
| guint i, offset; |
| GstClockTime pts; |
| |
| /* The goal of this test is to check that qtdemux can properly handle |
| * fragmented input from dashdemux, with gaps in it. |
| * |
| * Input segment : |
| * - TIME |
| * Input buffers : |
| * - The offset is set on buffers, it corresponds to the offset |
| * within the current fragment. |
| * - Buffer of the beginning of a fragment has the PTS set, others |
| * don't. |
| * - By extension, the beginning of a fragment also has an offset |
| * of 0. |
| */ |
| |
| qtdemux = gst_element_factory_make ("qtdemux", NULL); |
| gst_element_set_state (qtdemux, GST_STATE_PLAYING); |
| sinkpad = gst_element_get_static_pad (qtdemux, "sink"); |
| |
| /* We'll want to know when the source pad is added */ |
| g_signal_connect (qtdemux, "pad-added", (GCallback) qtdemux_pad_added_cb, |
| &data); |
| |
| /* Send the initial STREAM_START and segment (TIME) event */ |
| event = gst_event_new_stream_start ("TEST"); |
| GST_DEBUG ("Pushing stream-start event"); |
| fail_unless (gst_pad_send_event (sinkpad, event) == TRUE); |
| gst_segment_init (&segment, GST_FORMAT_TIME); |
| event = gst_event_new_segment (&segment); |
| GST_DEBUG ("Pushing segment event"); |
| fail_unless (gst_pad_send_event (sinkpad, event) == TRUE); |
| |
| /* Feed the init buffer, should create the source pad */ |
| inbuf = gst_buffer_new_and_alloc (init_mp4_len); |
| gst_buffer_fill (inbuf, 0, init_mp4, init_mp4_len); |
| GST_BUFFER_PTS (inbuf) = 0; |
| GST_BUFFER_OFFSET (inbuf) = 0; |
| GST_DEBUG ("Pushing header buffer"); |
| fail_unless (gst_pad_chain (sinkpad, inbuf) == GST_FLOW_OK); |
| |
| /* Now send the trun of the first fragment */ |
| inbuf = gst_buffer_new_and_alloc (seg_1_moof_size); |
| gst_buffer_fill (inbuf, 0, seg_1_m4f, seg_1_moof_size); |
| GST_BUFFER_PTS (inbuf) = 0; |
| GST_BUFFER_OFFSET (inbuf) = 0; |
| /* We are simulating that this fragment can happen at any point */ |
| GST_BUFFER_FLAG_SET (inbuf, GST_BUFFER_FLAG_DISCONT); |
| GST_DEBUG ("Pushing trun buffer"); |
| fail_unless (gst_pad_chain (sinkpad, inbuf) == GST_FLOW_OK); |
| fail_if (data.srcpad == NULL); |
| |
| /* We are now ready to send some buffers with gaps */ |
| offset = seg_1_sample_0_offset; |
| pts = 0; |
| |
| GST_DEBUG ("Pushing gap'ed buffers"); |
| for (i = 0; i < 129; i++) { |
| /* Let's send one every 3 */ |
| if ((i % 3) == 0) { |
| GST_DEBUG ("Pushing buffer #%d offset:%" G_GUINT32_FORMAT, i, offset); |
| inbuf = gst_buffer_new_and_alloc (seg_1_sample_sizes[i]); |
| gst_buffer_fill (inbuf, 0, seg_1_m4f + offset, seg_1_sample_sizes[i]); |
| GST_BUFFER_OFFSET (inbuf) = offset; |
| GST_BUFFER_FLAG_SET (inbuf, GST_BUFFER_FLAG_DISCONT); |
| data.expected_time = |
| gst_util_uint64_scale (pts, GST_SECOND, seg_1_timescale); |
| data.expected_size = seg_1_sample_sizes[i]; |
| fail_unless (gst_pad_chain (sinkpad, inbuf) == GST_FLOW_OK); |
| } |
| /* Finally move offset forward */ |
| offset += seg_1_sample_sizes[i]; |
| pts += seg_1_sample_duration; |
| } |
| |
| gst_object_unref (sinkpad); |
| gst_element_set_state (qtdemux, GST_STATE_NULL); |
| gst_object_unref (qtdemux); |
| } |
| |
| GST_END_TEST; |
| |
| static Suite * |
| qtdemux_suite (void) |
| { |
| Suite *s = suite_create ("qtdemux"); |
| TCase *tc_chain = tcase_create ("general"); |
| |
| suite_add_tcase (s, tc_chain); |
| tcase_add_test (tc_chain, test_qtdemux_input_gap); |
| |
| return s; |
| } |
| |
| GST_CHECK_MAIN (qtdemux) |