1 /* GStreamer
2  *
3  * unit test for mxfdemux
4  *
5  * Copyright (C) <2008> Sebastian Dröge <sebastian.droege@collabora.co.uk>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 #include <gst/check/gstcheck.h>
24 #include <string.h>
25 #include "mxfdemux.h"
26 
27 static GstPad *mysrcpad, *mysinkpad;
28 static GMainLoop *loop = NULL;
29 static gboolean have_eos = FALSE;
30 static gboolean have_data = FALSE;
31 
32 static GstStaticPadTemplate mysrctemplate =
33 GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
34     GST_STATIC_CAPS ("application/mxf"));
35 
36 static GstStaticPadTemplate mysinktemplate =
37 GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
38     GST_STATIC_CAPS_ANY);
39 
40 static void
_pad_added(GstElement * element,GstPad * pad,gpointer user_data)41 _pad_added (GstElement * element, GstPad * pad, gpointer user_data)
42 {
43   gchar *name = gst_pad_get_name (pad);
44 
45   fail_unless_equals_string (name, "track_2");
46   fail_unless (gst_pad_link (pad, mysinkpad) == GST_PAD_LINK_OK);
47 
48   g_free (name);
49 }
50 
51 static void
_sink_check_caps(GstPad * pad,GstCaps * caps)52 _sink_check_caps (GstPad * pad, GstCaps * caps)
53 {
54   GstCaps *tcaps = gst_caps_new_simple ("audio/x-raw",
55       "rate", G_TYPE_INT, 11025,
56       "channels", G_TYPE_INT, 1,
57       "format", G_TYPE_STRING, "U8",
58       "layout", G_TYPE_STRING, "interleaved",
59       NULL);
60 
61   fail_unless (gst_caps_is_always_compatible (caps, tcaps));
62   gst_caps_unref (tcaps);
63 }
64 
65 static GstFlowReturn
_sink_chain(GstPad * pad,GstObject * parent,GstBuffer * buffer)66 _sink_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
67 {
68   fail_unless_equals_int (gst_buffer_get_size (buffer), sizeof (mxf_essence));
69   fail_unless (gst_buffer_memcmp (buffer, 0, mxf_essence,
70           sizeof (mxf_essence)) == 0);
71 
72   fail_unless (GST_BUFFER_TIMESTAMP (buffer) == 0);
73   fail_unless (GST_BUFFER_DURATION (buffer) == 200 * GST_MSECOND);
74 
75   gst_buffer_unref (buffer);
76 
77   have_data = TRUE;
78   return GST_FLOW_OK;
79 }
80 
81 static gboolean
_sink_event(GstPad * pad,GstObject * parent,GstEvent * event)82 _sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
83 {
84   GST_INFO_OBJECT (pad, "got %s event %p: %" GST_PTR_FORMAT,
85       GST_EVENT_TYPE_NAME (event), event, event);
86 
87   switch (GST_EVENT_TYPE (event)) {
88     case GST_EVENT_EOS:
89       if (loop) {
90         while (!g_main_loop_is_running (loop));
91       }
92 
93       have_eos = TRUE;
94       if (loop)
95         g_main_loop_quit (loop);
96       break;
97     case GST_EVENT_CAPS:
98     {
99       GstCaps *caps;
100 
101       gst_event_parse_caps (event, &caps);
102       _sink_check_caps (pad, caps);
103       break;
104     }
105     default:
106       break;
107   }
108 
109   gst_event_unref (event);
110 
111   return TRUE;
112 }
113 
114 static GstPad *
_create_sink_pad(void)115 _create_sink_pad (void)
116 {
117   mysinkpad = gst_pad_new_from_static_template (&mysinktemplate, "sink");
118 
119   gst_pad_set_chain_function (mysinkpad, _sink_chain);
120   gst_pad_set_event_function (mysinkpad, _sink_event);
121 
122   return mysinkpad;
123 }
124 
125 static GstPad *
_create_src_pad_push(void)126 _create_src_pad_push (void)
127 {
128   mysrcpad = gst_pad_new_from_static_template (&mysrctemplate, "src");
129 
130   return mysrcpad;
131 }
132 
133 static GstFlowReturn
_src_getrange(GstPad * pad,GstObject * parent,guint64 offset,guint length,GstBuffer ** buffer)134 _src_getrange (GstPad * pad, GstObject * parent, guint64 offset, guint length,
135     GstBuffer ** buffer)
136 {
137   if (offset + length > sizeof (mxf_file))
138     return GST_FLOW_EOS;
139 
140   *buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
141       (guint8 *) (mxf_file + offset), length, 0, length, NULL, NULL);
142 
143   return GST_FLOW_OK;
144 }
145 
146 static gboolean
_src_query(GstPad * pad,GstObject * parent,GstQuery * query)147 _src_query (GstPad * pad, GstObject * parent, GstQuery * query)
148 {
149   gboolean res = FALSE;
150 
151   switch (GST_QUERY_TYPE (query)) {
152     case GST_QUERY_DURATION:{
153       GstFormat fmt;
154 
155       gst_query_parse_duration (query, &fmt, NULL);
156       if (fmt != GST_FORMAT_BYTES)
157         break;
158 
159       gst_query_set_duration (query, fmt, sizeof (mxf_file));
160       res = TRUE;
161       break;
162     }
163     case GST_QUERY_SCHEDULING:{
164       gst_query_set_scheduling (query, GST_SCHEDULING_FLAG_SEEKABLE, 1, -1, 0);
165       gst_query_add_scheduling_mode (query, GST_PAD_MODE_PULL);
166       res = TRUE;
167       break;
168     }
169     default:
170       GST_DEBUG_OBJECT (pad, "unhandled %s query", GST_QUERY_TYPE_NAME (query));
171       break;
172   }
173 
174   return res;
175 }
176 
177 static GstPad *
_create_src_pad_pull(void)178 _create_src_pad_pull (void)
179 {
180   mysrcpad = gst_pad_new_from_static_template (&mysrctemplate, "src");
181   gst_pad_set_getrange_function (mysrcpad, _src_getrange);
182   gst_pad_set_query_function (mysrcpad, _src_query);
183 
184   return mysrcpad;
185 }
186 
GST_START_TEST(test_pull)187 GST_START_TEST (test_pull)
188 {
189   GstStateChangeReturn sret;
190   GstElement *mxfdemux;
191   GstPad *sinkpad;
192 
193   have_eos = FALSE;
194   have_data = FALSE;
195   loop = g_main_loop_new (NULL, FALSE);
196 
197   mxfdemux = gst_element_factory_make ("mxfdemux", NULL);
198   fail_unless (mxfdemux != NULL);
199   g_signal_connect (mxfdemux, "pad-added", G_CALLBACK (_pad_added), NULL);
200   sinkpad = gst_element_get_static_pad (mxfdemux, "sink");
201   fail_unless (sinkpad != NULL);
202 
203   mysinkpad = _create_sink_pad ();
204   fail_unless (mysinkpad != NULL);
205   mysrcpad = _create_src_pad_pull ();
206   fail_unless (mysrcpad != NULL);
207 
208   fail_unless (gst_pad_link (mysrcpad, sinkpad) == GST_PAD_LINK_OK);
209   gst_object_unref (sinkpad);
210 
211   gst_pad_set_active (mysinkpad, TRUE);
212   gst_pad_set_active (mysrcpad, TRUE);
213 
214   GST_INFO ("Setting to PLAYING");
215   sret = gst_element_set_state (mxfdemux, GST_STATE_PLAYING);
216   fail_unless_equals_int (sret, GST_STATE_CHANGE_SUCCESS);
217 
218   g_main_loop_run (loop);
219   fail_unless (have_eos == TRUE);
220   fail_unless (have_data == TRUE);
221 
222   gst_element_set_state (mxfdemux, GST_STATE_NULL);
223   gst_pad_set_active (mysinkpad, FALSE);
224   gst_pad_set_active (mysrcpad, FALSE);
225 
226   gst_object_unref (mxfdemux);
227   gst_object_unref (mysinkpad);
228   gst_object_unref (mysrcpad);
229   g_main_loop_unref (loop);
230   loop = NULL;
231 }
232 
233 GST_END_TEST;
234 
GST_START_TEST(test_push)235 GST_START_TEST (test_push)
236 {
237   GstElement *mxfdemux;
238   GstBuffer *buffer;
239   GstPad *sinkpad;
240   GstCaps *caps;
241 
242   have_data = FALSE;
243   have_eos = FALSE;
244 
245   mxfdemux = gst_element_factory_make ("mxfdemux", NULL);
246   fail_unless (mxfdemux != NULL);
247   g_signal_connect (mxfdemux, "pad-added", G_CALLBACK (_pad_added), NULL);
248   sinkpad = gst_element_get_static_pad (mxfdemux, "sink");
249   fail_unless (sinkpad != NULL);
250 
251   buffer =
252       gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
253       (guint8 *) mxf_file, sizeof (mxf_file), 0, sizeof (mxf_file), NULL, NULL);
254   GST_BUFFER_OFFSET (buffer) = 0;
255 
256   mysinkpad = _create_sink_pad ();
257   fail_unless (mysinkpad != NULL);
258   mysrcpad = _create_src_pad_push ();
259   fail_unless (mysrcpad != NULL);
260 
261   fail_unless (gst_pad_link (mysrcpad, sinkpad) == GST_PAD_LINK_OK);
262   gst_object_unref (sinkpad);
263 
264   gst_pad_set_active (mysinkpad, TRUE);
265   gst_pad_set_active (mysrcpad, TRUE);
266 
267   caps = gst_caps_new_empty_simple ("application/mxf");
268   gst_check_setup_events (mysrcpad, mxfdemux, caps, GST_FORMAT_BYTES);
269   gst_caps_unref (caps);
270 
271   gst_element_set_state (mxfdemux, GST_STATE_PLAYING);
272 
273   fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
274   fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
275 
276   fail_unless (have_eos == TRUE);
277   fail_unless (have_data == TRUE);
278 
279   gst_element_set_state (mxfdemux, GST_STATE_NULL);
280   gst_pad_set_active (mysinkpad, FALSE);
281   gst_pad_set_active (mysrcpad, FALSE);
282 
283   gst_object_unref (mxfdemux);
284   gst_object_unref (mysinkpad);
285   gst_object_unref (mysrcpad);
286 }
287 
288 GST_END_TEST;
289 
290 static Suite *
mxfdemux_suite(void)291 mxfdemux_suite (void)
292 {
293   Suite *s = suite_create ("mxfdemux");
294   TCase *tc_chain = tcase_create ("general");
295 
296   /* FIXME: remove again once ported */
297   if (!gst_registry_check_feature_version (gst_registry_get (), "mxfdemux", 1,
298           0, 0))
299     return s;
300 
301   suite_add_tcase (s, tc_chain);
302   tcase_set_timeout (tc_chain, 180);
303   tcase_add_test (tc_chain, test_pull);
304   tcase_add_test (tc_chain, test_push);
305 
306   return s;
307 }
308 
309 GST_CHECK_MAIN (mxfdemux);
310