tizen 2.3 release
[framework/multimedia/gst-plugins-base0.10.git] / tests / check / elements / decodebin.c
1 /* GStreamer unit tests for decodebin
2  *
3  * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
4  * Copyright (C) 2011 Hewlett-Packard Development Company, L.P.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 # include <config.h>
24 #endif
25
26 #include <gst/check/gstcheck.h>
27 #include <gst/base/gstbaseparse.h>
28 #include <unistd.h>
29
30 static const gchar dummytext[] =
31     "Quick Brown Fox Jumps over a Lazy Frog Quick Brown "
32     "Fox Jumps over a Lazy Frog Quick Brown Fox Jumps over a Lazy Frog Quick "
33     "Brown Fox Jumps over a Lazy Frog Quick Brown Fox Jumps over a Lazy Frog "
34     "Quick Brown Fox Jumps over a Lazy Frog Quick Brown Fox Jumps over a Lazy "
35     "Frog Quick Brown Fox Jumps over a Lazy Frog Quick Brown Fox Jumps over a "
36     "Lazy Frog Quick Brown Fox Jumps over a Lazy Frog Quick Brown Fox Jumps "
37     "over a Lazy Frog Quick Brown Fox Jumps over a Lazy Frog Quick Brown Fox "
38     "jumps over a Lazy Frog Quick Brown Fox Jumps over a Lazy Frog Quick Brown "
39     "Fox Jumps over a Lazy Frog Quick Brown Fox Jumps over a Lazy Frog Quick "
40     "Brown Fox Jumps over a Lazy Frog Quick Brown Fox Jumps over a Lazy Frog "
41     "Quick Brown Fox Jumps over a Lazy Frog Quick Brown Fox Jumps over a Lazy "
42     "Frog Quick Brown Fox Jumps over a Lazy Frog Quick Brown Fox Jumps over a "
43     "Lazy Frog Quick Brown Fox Jumps over a Lazy Frog Quick Brown Fox Jumps "
44     "over a Lazy Frog Quick Brown Fox Jumps over a Lazy Frog Quick Brown Fox ";
45
46 static void
47 src_handoff_cb (GstElement * src, GstBuffer * buf, GstPad * pad, gpointer data)
48 {
49   GST_BUFFER_DATA (buf) = (guint8 *) dummytext;
50   GST_BUFFER_SIZE (buf) = sizeof (dummytext);
51   GST_BUFFER_OFFSET (buf) = 0;
52   GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_READONLY);
53 }
54
55 static void
56 decodebin_new_decoded_pad_cb (GstElement * decodebin, GstPad * pad,
57     gboolean last, gboolean * p_flag)
58 {
59   /* we should not be reached */
60   fail_unless (decodebin == NULL, "new-decoded-pad should not be emitted");
61 }
62
63 /* make sure that decodebin errors out instead of creating a new decoded pad
64  * if the entire stream is a plain text file */
65 GST_START_TEST (test_text_plain_streams)
66 {
67   GstElement *pipe, *src, *decodebin;
68   GstMessage *msg;
69
70   pipe = gst_pipeline_new (NULL);
71   fail_unless (pipe != NULL, "failed to create pipeline");
72
73   src = gst_element_factory_make ("fakesrc", "src");
74   fail_unless (src != NULL, "Failed to create fakesrc element");
75
76   g_object_set (src, "signal-handoffs", TRUE, NULL);
77   g_object_set (src, "num-buffers", 1, NULL);
78   g_object_set (src, "can-activate-pull", FALSE, NULL);
79   g_signal_connect (src, "handoff", G_CALLBACK (src_handoff_cb), NULL);
80
81   decodebin = gst_element_factory_make ("decodebin", "decodebin");
82   fail_unless (decodebin != NULL, "Failed to create decodebin element");
83
84   g_signal_connect (decodebin, "new-decoded-pad",
85       G_CALLBACK (decodebin_new_decoded_pad_cb), NULL);
86
87   fail_unless (gst_bin_add (GST_BIN (pipe), src));
88   fail_unless (gst_bin_add (GST_BIN (pipe), decodebin));
89   fail_unless (gst_element_link (src, decodebin), "can't link src<->decodebin");
90
91   fail_unless_equals_int (gst_element_set_state (pipe, GST_STATE_READY),
92       GST_STATE_CHANGE_SUCCESS);
93   /* it's push-based, so should be async */
94   fail_unless_equals_int (gst_element_set_state (pipe, GST_STATE_PAUSED),
95       GST_STATE_CHANGE_ASYNC);
96
97   /* it should error out at some point */
98   msg = gst_bus_poll (GST_ELEMENT_BUS (pipe), GST_MESSAGE_ERROR, -1);
99   fail_unless (msg != NULL);
100   fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR);
101   gst_message_unref (msg);
102
103   gst_element_set_state (pipe, GST_STATE_NULL);
104   gst_object_unref (pipe);
105 }
106
107 GST_END_TEST;
108
109 static void
110 new_decoded_pad_plug_fakesink_cb (GstElement * decodebin, GstPad * srcpad,
111     gboolean last, GstElement * pipeline)
112 {
113   GstElement *sink;
114   GstPad *sinkpad;
115
116   sink = gst_element_factory_make ("fakesink", "sink");
117   fail_unless (sink != NULL, "Failed to create fakesink element");
118
119   gst_bin_add (GST_BIN (pipeline), sink);
120
121   sinkpad = gst_element_get_static_pad (sink, "sink");
122   fail_unless_equals_int (gst_pad_link (srcpad, sinkpad), GST_PAD_LINK_OK);
123   gst_object_unref (sinkpad);
124
125   gst_element_set_state (sink, GST_STATE_PLAYING);
126 }
127
128 GST_START_TEST (test_reuse_without_decoders)
129 {
130   GstElement *pipe, *src, *decodebin, *sink;
131
132   pipe = gst_pipeline_new (NULL);
133   fail_unless (pipe != NULL, "failed to create pipeline");
134
135   src = gst_element_factory_make ("audiotestsrc", "src");
136   fail_unless (src != NULL, "Failed to create audiotestsrc element");
137
138   decodebin = gst_element_factory_make ("decodebin", "decodebin");
139   fail_unless (decodebin != NULL, "Failed to create decodebin element");
140
141   g_signal_connect (decodebin, "new-decoded-pad",
142       G_CALLBACK (new_decoded_pad_plug_fakesink_cb), pipe);
143
144   fail_unless (gst_bin_add (GST_BIN (pipe), src));
145   fail_unless (gst_bin_add (GST_BIN (pipe), decodebin));
146   fail_unless (gst_element_link (src, decodebin), "can't link src<->decodebin");
147
148   fail_unless_equals_int (gst_element_set_state (pipe, GST_STATE_READY),
149       GST_STATE_CHANGE_SUCCESS);
150   /* it's push-based, so should be async */
151   fail_unless_equals_int (gst_element_set_state (pipe, GST_STATE_PAUSED),
152       GST_STATE_CHANGE_ASYNC);
153
154   /* wait for state change to complete */
155   fail_unless_equals_int (gst_element_get_state (pipe, NULL, NULL, -1),
156       GST_STATE_CHANGE_SUCCESS);
157
158   /* there shouldn't be any errors */
159   fail_if (gst_bus_poll (GST_ELEMENT_BUS (pipe), GST_MESSAGE_ERROR, 0) != NULL);
160
161   /* reset */
162   gst_element_set_state (pipe, GST_STATE_NULL);
163
164   sink = gst_bin_get_by_name (GST_BIN (pipe), "sink");
165   gst_bin_remove (GST_BIN (pipe), sink);
166   gst_object_unref (sink);
167
168   GST_LOG ("second try");
169
170   fail_unless_equals_int (gst_element_set_state (pipe, GST_STATE_READY),
171       GST_STATE_CHANGE_SUCCESS);
172   /* it's push-based, so should be async */
173   fail_unless_equals_int (gst_element_set_state (pipe, GST_STATE_PAUSED),
174       GST_STATE_CHANGE_ASYNC);
175
176   /* wait for state change to complete */
177   fail_unless_equals_int (gst_element_get_state (pipe, NULL, NULL, -1),
178       GST_STATE_CHANGE_SUCCESS);
179
180   /* there shouldn't be any errors */
181   fail_if (gst_bus_poll (GST_ELEMENT_BUS (pipe), GST_MESSAGE_ERROR, 0) != NULL);
182
183   gst_element_set_state (pipe, GST_STATE_NULL);
184   gst_object_unref (pipe);
185 }
186
187 GST_END_TEST;
188
189 /* Fake mp3 parser for test */
190 typedef GstBaseParse TestMpegAudioParse;
191 typedef GstBaseParseClass TestMpegAudioParseClass;
192
193 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
194     GST_PAD_SRC,
195     GST_PAD_ALWAYS,
196     GST_STATIC_CAPS ("audio/mpeg, mpegversion=1, layer=[1,3], parsed=(b)true")
197     );
198
199 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
200     GST_PAD_SINK,
201     GST_PAD_ALWAYS,
202     GST_STATIC_CAPS ("audio/mpeg, mpegversion=1, parsed=(bool) { false, true }")
203     );
204
205 static GType test_mpeg_audio_parse_get_type (void);
206 static gboolean test_mpeg_audio_parse_start (GstBaseParse * parse);
207 static gboolean test_mpeg_audio_parse_stop (GstBaseParse * parse);
208 static gboolean test_mpeg_audio_parse_check_valid_frame (GstBaseParse * parse,
209     GstBaseParseFrame * frame, guint * size, gint * skipsize);
210 static GstFlowReturn test_mpeg_audio_parse_parse_frame (GstBaseParse * parse,
211     GstBaseParseFrame * frame);
212
213 GST_BOILERPLATE (TestMpegAudioParse, test_mpeg_audio_parse, GstBaseParse,
214     GST_TYPE_BASE_PARSE);
215
216 static void
217 test_mpeg_audio_parse_base_init (gpointer klass)
218 {
219   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
220
221   gst_element_class_add_static_pad_template (element_class,
222       &sink_template);
223   gst_element_class_add_static_pad_template (element_class, &src_template);
224
225   gst_element_class_set_details_simple (element_class, "MPEG1 Audio Parser",
226       "Codec/Parser/Audio", "Pretends to parse mpeg1 audio stream",
227       "Foo Bar <foo@bar.com>");
228 }
229
230 static void
231 test_mpeg_audio_parse_class_init (TestMpegAudioParseClass * klass)
232 {
233   GstBaseParseClass *parse_class = GST_BASE_PARSE_CLASS (klass);
234
235   parse_class->start = test_mpeg_audio_parse_start;
236   parse_class->stop = test_mpeg_audio_parse_stop;
237   parse_class->check_valid_frame = test_mpeg_audio_parse_check_valid_frame;
238   parse_class->parse_frame = test_mpeg_audio_parse_parse_frame;
239 }
240
241 static gint num_parse_instances = 0;
242
243 static void
244 test_mpeg_audio_parse_init (TestMpegAudioParse * mp3parse,
245     TestMpegAudioParseClass * klass)
246 {
247   /* catch decodebin plugging parsers in a loop early */
248   fail_unless (++num_parse_instances < 10);
249 }
250
251 static gboolean
252 test_mpeg_audio_parse_start (GstBaseParse * parse)
253 {
254   gst_base_parse_set_min_frame_size (parse, 6);
255   return TRUE;
256 }
257
258 static gboolean
259 test_mpeg_audio_parse_stop (GstBaseParse * parse)
260 {
261   return TRUE;
262 }
263
264 static gboolean
265 test_mpeg_audio_parse_check_valid_frame (GstBaseParse * parse,
266     GstBaseParseFrame * frame, guint * framesize, gint * skipsize)
267 {
268   const guint8 *data = GST_BUFFER_DATA (frame->buffer);
269
270   if ((GST_READ_UINT16_BE (data) & 0xffe0) == 0xffe0) {
271     /* this framesize is hard-coded for ../test.mp3 */
272     *framesize = 1045;
273     return TRUE;
274   } else {
275     *skipsize = 1;
276     return FALSE;
277   }
278 }
279
280 static GstFlowReturn
281 test_mpeg_audio_parse_parse_frame (GstBaseParse * parse,
282     GstBaseParseFrame * frame)
283 {
284   if (GST_BUFFER_OFFSET (frame->buffer) == 0) {
285     GstCaps *caps;
286
287     caps = gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT, 1,
288         "mpegaudioversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3,
289         "rate", G_TYPE_INT, 44100, "channels", G_TYPE_INT, 2, NULL);
290     gst_buffer_set_caps (frame->buffer, caps);
291     gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps);
292     gst_caps_unref (caps);
293   }
294   return GST_FLOW_OK;
295 }
296
297 static gboolean
298 plugin_init (GstPlugin * plugin)
299 {
300   return gst_element_register (plugin, "testmpegaudioparse", GST_RANK_NONE,
301       test_mpeg_audio_parse_get_type ());
302 }
303
304 GST_START_TEST (test_mp3_parser_loop)
305 {
306   GstStateChangeReturn sret;
307   GstPluginFeature *feature;
308   GstMessage *msg;
309   GstElement *pipe, *src, *dec;
310   gchar *path;
311
312   num_parse_instances = 0;
313
314   gst_plugin_register_static (GST_VERSION_MAJOR, GST_VERSION_MINOR,
315       "fakemp3parse", "fakemp3parse", plugin_init, VERSION, "LGPL",
316       "gst-plugins-base", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
317
318   feature = gst_default_registry_find_feature ("testmpegaudioparse",
319       GST_TYPE_ELEMENT_FACTORY);
320
321   gst_plugin_feature_set_rank (feature, GST_RANK_PRIMARY + 100);
322
323   pipe = gst_pipeline_new (NULL);
324
325   src = gst_element_factory_make ("filesrc", NULL);
326   fail_unless (src != NULL);
327
328   path = g_build_filename (GST_TEST_FILES_PATH, "test.mp3", NULL);
329   g_object_set (src, "location", path, NULL);
330   g_free (path);
331
332   dec = gst_element_factory_make ("decodebin", NULL);
333   fail_unless (dec != NULL);
334
335   gst_bin_add_many (GST_BIN (pipe), src, dec, NULL);
336   gst_element_link_many (src, dec, NULL);
337
338   sret = gst_element_set_state (pipe, GST_STATE_PLAYING);
339   fail_unless_equals_int (sret, GST_STATE_CHANGE_ASYNC);
340
341   /* wait for unlinked error */
342   msg = gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (pipe),
343       GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR);
344   gst_message_unref (msg);
345
346   gst_element_set_state (pipe, GST_STATE_NULL);
347   gst_object_unref (pipe);
348
349   /* make sure out parser got plugged at all though */
350   fail_unless_equals_int (num_parse_instances, 1);
351
352   /* don't want to interfere with any other of the other tests */
353   gst_plugin_feature_set_rank (feature, GST_RANK_NONE);
354   gst_object_unref (feature);
355 }
356
357 GST_END_TEST;
358
359 static Suite *
360 decodebin_suite (void)
361 {
362   Suite *s = suite_create ("decodebin");
363   TCase *tc_chain = tcase_create ("general");
364
365   suite_add_tcase (s, tc_chain);
366   tcase_add_test (tc_chain, test_text_plain_streams);
367   tcase_add_test (tc_chain, test_reuse_without_decoders);
368   tcase_add_test (tc_chain, test_mp3_parser_loop);
369
370   return s;
371 }
372
373 GST_CHECK_MAIN (decodebin);