1 /* GStreamer unit test for gstprofile
2  *
3  * Copyright (C) <2009> Edward Hervey <edward.hervey@collabora.co.uk>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <gst/pbutils/encoding-profile.h>
26 #include <gst/pbutils/missing-plugins.h>
27 #include <gst/check/gstcheck.h>
28 
29 /* Helper functions to create profiles */
30 
31 static GstEncodingProfile *
create_ogg_profile()32 create_ogg_profile ()
33 {
34   GstEncodingContainerProfile *prof;
35   GstCaps *ogg;
36 
37   ogg = gst_caps_new_empty_simple ("application/ogg");
38   prof = gst_encoding_container_profile_new ((gchar *) "myprofile", NULL, ogg,
39       NULL);
40   gst_caps_unref (ogg);
41   return (GstEncodingProfile *) prof;
42 }
43 
44 static GstEncodingProfile *
create_ogg_vorbis_profile(guint presence,gchar * preset)45 create_ogg_vorbis_profile (guint presence, gchar * preset)
46 {
47   GstEncodingContainerProfile *cprof;
48   GstCaps *ogg, *vorbis;
49 
50   ogg = gst_caps_new_empty_simple ("application/ogg");
51   cprof =
52       gst_encoding_container_profile_new ((gchar *) "myprofile", NULL, ogg,
53       NULL);
54   gst_caps_unref (ogg);
55 
56   vorbis = gst_caps_new_empty_simple ("audio/x-vorbis");
57   fail_unless (gst_encoding_container_profile_add_profile (cprof,
58           (GstEncodingProfile *) gst_encoding_audio_profile_new (vorbis, preset,
59               NULL, presence)));
60   gst_caps_unref (vorbis);
61 
62   return (GstEncodingProfile *) cprof;
63 }
64 
65 static GstEncodingProfile *
create_ogg_theora_vorbis_profile(guint theorapresence,guint vorbispresence)66 create_ogg_theora_vorbis_profile (guint theorapresence, guint vorbispresence)
67 {
68   GstEncodingContainerProfile *prof;
69   GstCaps *ogg, *vorbis, *theora;
70 
71   ogg = gst_caps_new_empty_simple ("application/ogg");
72   prof =
73       gst_encoding_container_profile_new ((gchar *) "myprofile", NULL, ogg,
74       NULL);
75   gst_caps_unref (ogg);
76 
77   vorbis = gst_caps_new_empty_simple ("audio/x-vorbis");
78   fail_unless (gst_encoding_container_profile_add_profile (prof,
79           (GstEncodingProfile *) gst_encoding_audio_profile_new (vorbis, NULL,
80               NULL, vorbispresence)));
81   gst_caps_unref (vorbis);
82 
83   theora = gst_caps_new_empty_simple ("video/x-theora");
84   fail_unless (gst_encoding_container_profile_add_profile (prof,
85           (GstEncodingProfile *) gst_encoding_video_profile_new (theora, NULL,
86               NULL, theorapresence)));
87   gst_caps_unref (theora);
88 
89   return (GstEncodingProfile *) prof;
90 }
91 
92 static GstEncodingProfile *
create_vorbis_only_profile(void)93 create_vorbis_only_profile (void)
94 {
95   GstEncodingProfile *prof;
96   GstCaps *vorbis;
97 
98   vorbis = gst_caps_new_empty_simple ("audio/x-vorbis");
99   prof =
100       (GstEncodingProfile *) gst_encoding_audio_profile_new (vorbis, NULL, NULL,
101       0);
102   gst_caps_unref (vorbis);
103 
104   return prof;
105 }
106 
107 static GstCaps *
create_unsupported_caps(void)108 create_unsupported_caps (void)
109 {
110   return gst_caps_new_empty_simple ("audio/x-bogus");
111 }
112 
113 static GstEncodingProfile *
create_unsupported_profile(void)114 create_unsupported_profile (void)
115 {
116   GstEncodingProfile *prof;
117   GstCaps *caps;
118 
119   caps = create_unsupported_caps ();
120   prof =
121       (GstEncodingProfile *) gst_encoding_audio_profile_new (caps, NULL, NULL,
122       0);
123   gst_caps_unref (caps);
124 
125   return prof;
126 }
127 
128 static void
_caps_match(GstPad * sinkpad,const gchar * capsname)129 _caps_match (GstPad * sinkpad, const gchar * capsname)
130 {
131   GstCaps *caps, *sinkcaps;
132   gchar *name;
133 
134   caps = gst_caps_from_string (capsname);
135   sinkcaps = gst_pad_query_caps (sinkpad, NULL);
136   fail_unless (sinkcaps != NULL);
137   name = gst_caps_to_string (sinkcaps);
138   fail_unless (gst_caps_is_subset (sinkcaps, caps),
139       "caps ('%s') are not a subset of ('%s')", name, capsname);
140   g_free (name);
141   gst_caps_unref (sinkcaps);
142   gst_caps_unref (caps);
143 }
144 
145 static void
set_profile(GstElement * ebin,GstEncodingProfile * prof)146 set_profile (GstElement * ebin, GstEncodingProfile * prof)
147 {
148   g_object_set (ebin, "profile", prof, NULL);
149   gst_encoding_profile_unref (prof);
150 }
151 
152 /* Tests */
153 
GST_START_TEST(test_encodebin_set_profile)154 GST_START_TEST (test_encodebin_set_profile)
155 {
156   GstElement *ebin;
157   GstEncodingProfile *prof, *prof2;
158 
159   /* Create an encodebin and check that it correctly changes states
160    * according to whether a profile is set or not */
161 
162   ebin = gst_element_factory_make ("encodebin", NULL);
163 
164   /* Set a profile on encodebin... */
165   prof = create_ogg_profile ();
166   g_object_set (ebin, "profile", prof, NULL);
167 
168   /* ... and check the profile has been properly set */
169   g_object_get (ebin, "profile", &prof2, NULL);
170 
171   fail_unless (gst_encoding_profile_is_equal (prof, prof2));
172 
173   gst_encoding_profile_unref (prof);
174   gst_encoding_profile_unref (prof2);
175 
176   gst_object_unref (ebin);
177 };
178 
179 GST_END_TEST;
180 
181 
GST_START_TEST(test_encodebin_can_go_to_ready_without_profile)182 GST_START_TEST (test_encodebin_can_go_to_ready_without_profile)
183 {
184   GstElement *ebin;
185   GstPad *srcpad;
186   GstPad *target;
187 
188   /* Create an encodebin and check that it correctly changes states
189    * according to whether a profile is set or not */
190 
191   ebin = gst_element_factory_make ("encodebin", NULL);
192 
193   /* Check if the source pad was properly created */
194   srcpad = gst_element_get_static_pad (ebin, "src");
195   fail_unless (srcpad != NULL);
196 
197   /* At this point, the ghostpad has *NO* target */
198   target = gst_ghost_pad_get_target (GST_GHOST_PAD (srcpad));
199   fail_unless (target == NULL);
200   gst_object_unref (srcpad);
201 
202   /* No profile,
203    * switching to READY should succeed,
204    * but switching to PAUSED should fail
205    */
206   fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_READY),
207       GST_STATE_CHANGE_SUCCESS);
208   fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_PAUSED),
209       GST_STATE_CHANGE_FAILURE);
210 
211   /* Set back to NULL */
212   fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_NULL),
213       GST_STATE_CHANGE_SUCCESS);
214 
215   gst_object_unref (ebin);
216 };
217 
218 GST_END_TEST;
219 
GST_START_TEST(test_encodebin_can_go_to_paused_with_profile)220 GST_START_TEST (test_encodebin_can_go_to_paused_with_profile)
221 {
222   GstElement *ebin;
223   GstPad *srcpad;
224   GstPad *target;
225 
226   /* Create an encodebin and check that it correctly changes states
227    * according to whether a profile is set or not */
228 
229   ebin = gst_element_factory_make ("encodebin", NULL);
230 
231   /* Set a profile on encodebin... */
232   set_profile (ebin, create_ogg_profile ());
233 
234   /* Make sure we can go to PAUSED */
235   fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_PAUSED),
236       GST_STATE_CHANGE_SUCCESS);
237 
238   /* At this point, the source pad *HAS* a target */
239   srcpad = gst_element_get_static_pad (ebin, "src");
240   fail_unless (srcpad != NULL);
241   target = gst_ghost_pad_get_target (GST_GHOST_PAD (srcpad));
242   fail_unless (target != NULL);
243   gst_object_unref (target);
244   gst_object_unref (srcpad);
245 
246 
247   /* Set back to NULL */
248   fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_NULL),
249       GST_STATE_CHANGE_SUCCESS);
250 
251   gst_object_unref (ebin);
252 };
253 
254 GST_END_TEST;
255 
256 
GST_START_TEST(test_encodebin_sink_pads_static)257 GST_START_TEST (test_encodebin_sink_pads_static)
258 {
259   GstElement *ebin;
260   GstPad *srcpad, *sinkpad;
261 
262   /* Create an encodebin and check that it properly creates the sink pads
263    * for a single-stream profile with fixed presence */
264 
265   ebin = gst_element_factory_make ("encodebin", NULL);
266 
267   /* streamprofile that has a forced presence of 1 */
268   set_profile (ebin, create_ogg_vorbis_profile (1, NULL));
269 
270   fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_PAUSED),
271       GST_STATE_CHANGE_SUCCESS);
272 
273   /* Check if the source pad was properly created */
274   srcpad = gst_element_get_static_pad (ebin, "src");
275   fail_unless (srcpad != NULL);
276   gst_object_unref (srcpad);
277 
278   /* Check if the audio sink pad was properly created */
279   sinkpad = gst_element_get_static_pad (ebin, "audio_0");
280   fail_unless (sinkpad != NULL);
281   /* Check caps match */
282   _caps_match (sinkpad, "audio/x-raw;audio/x-vorbis");
283   gst_object_unref (sinkpad);
284 
285   /* Set back to NULL */
286   fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_NULL),
287       GST_STATE_CHANGE_SUCCESS);
288 
289   gst_object_unref (ebin);
290 };
291 
292 GST_END_TEST;
293 
GST_START_TEST(test_encodebin_preset)294 GST_START_TEST (test_encodebin_preset)
295 {
296   GstElement *ebin;
297   GstEncodingProfile *prof;
298   guint64 max_delay = 0;
299   GstPreset *oggmuxpreset;
300 
301   /* Create an encodebin with a bogus preset and check it fails switching states */
302 
303   ebin = gst_element_factory_make ("encodebin", NULL);
304   oggmuxpreset = GST_PRESET (gst_element_factory_make ("oggmux", NULL));
305 
306   /* We also set the name as the load_preset call will reset the element name to
307    * what is described in the preset... which might not be very smart tbh */
308   g_object_set (oggmuxpreset, "max-delay", (guint64) 12, "name",
309       "testingoggmux", NULL);
310 
311   /* Give a name someone should never use outside of that test */
312   gst_preset_save_preset (oggmuxpreset, "test_encodebin_preset");
313 
314   /* streamprofile that has a forced presence of 1 */
315   prof = create_ogg_vorbis_profile (1, NULL);
316 
317   gst_encoding_profile_set_preset (prof, "test_encodebin_preset");
318   gst_encoding_profile_set_preset_name (prof, "oggmux");
319 
320   set_profile (ebin, prof);
321 
322   /* It will go to READY... */
323   fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_READY),
324       GST_STATE_CHANGE_SUCCESS);
325   /* ... and to PAUSED */
326   fail_unless (gst_element_set_state (ebin, GST_STATE_PAUSED) !=
327       GST_STATE_CHANGE_FAILURE);
328 
329   gst_child_proxy_get (GST_CHILD_PROXY (ebin), "testingoggmux::max-delay",
330       &max_delay, NULL);
331   fail_unless_equals_uint64 (max_delay, 12);
332 
333   gst_element_set_state (ebin, GST_STATE_NULL);
334   gst_preset_delete_preset (oggmuxpreset, "test_encodebin_preset");
335 
336   gst_object_unref (oggmuxpreset);
337   gst_object_unref (ebin);
338 };
339 
340 GST_END_TEST;
341 
GST_START_TEST(test_encodebin_sink_pads_nopreset_static)342 GST_START_TEST (test_encodebin_sink_pads_nopreset_static)
343 {
344   GstElement *ebin;
345 
346   /* Create an encodebin with a bogus preset and check it fails switching states */
347 
348   ebin = gst_element_factory_make ("encodebin", NULL);
349 
350   /* streamprofile that has a forced presence of 1 */
351   set_profile (ebin,
352       create_ogg_vorbis_profile (1, (gchar *) "nowaythispresetexists"));
353 
354   /* It will go to READY... */
355   fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_READY),
356       GST_STATE_CHANGE_SUCCESS);
357   /* ... but to not PAUSED */
358   fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_PAUSED),
359       GST_STATE_CHANGE_FAILURE);
360 
361   gst_element_set_state (ebin, GST_STATE_NULL);
362 
363   gst_object_unref (ebin);
364 };
365 
366 GST_END_TEST;
367 
GST_START_TEST(test_encodebin_sink_pads_dynamic)368 GST_START_TEST (test_encodebin_sink_pads_dynamic)
369 {
370   GstElement *ebin;
371   GstPad *srcpad, *sinkpad;
372   GstCaps *sinkcaps;
373 
374   /* Create an encodebin and check that it properly creates the sink pads
375    * for a single-stream profile with a unfixed presence */
376 
377   ebin = gst_element_factory_make ("encodebin", NULL);
378 
379   /* streamprofile that has non-forced presence */
380   set_profile (ebin, create_ogg_vorbis_profile (0, NULL));
381 
382   /* Check if the source pad was properly created */
383   srcpad = gst_element_get_static_pad (ebin, "src");
384   fail_unless (srcpad != NULL);
385   gst_object_unref (srcpad);
386 
387   /* Check if the audio sink pad can be requested */
388   sinkpad = gst_element_get_request_pad (ebin, "audio_0");
389   fail_unless (sinkpad != NULL);
390   _caps_match (sinkpad, "audio/x-raw;audio/x-vorbis");
391   gst_element_release_request_pad (ebin, sinkpad);
392   gst_object_unref (sinkpad);
393   sinkpad = NULL;
394 
395   /* Check again with the 'request-pad' signal */
396   sinkcaps = gst_caps_new_empty_simple ("audio/x-raw");
397   g_signal_emit_by_name (ebin, "request-pad", sinkcaps, &sinkpad);
398   gst_caps_unref (sinkcaps);
399   fail_unless (sinkpad != NULL);
400   _caps_match (sinkpad, "audio/x-raw;audio/x-vorbis");
401   gst_element_release_request_pad (ebin, sinkpad);
402   gst_object_unref (sinkpad);
403   sinkpad = NULL;
404 
405   fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_PAUSED),
406       GST_STATE_CHANGE_SUCCESS);
407 
408   /* Set back to NULL */
409   fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_NULL),
410       GST_STATE_CHANGE_SUCCESS);
411 
412   gst_object_unref (ebin);
413 };
414 
415 GST_END_TEST;
416 
GST_START_TEST(test_encodebin_sink_pads_multiple_static)417 GST_START_TEST (test_encodebin_sink_pads_multiple_static)
418 {
419   GstElement *ebin;
420   GstPad *srcpad, *sinkpadvorbis, *sinkpadtheora;
421 
422   /* Create an encodebin and check that it properly creates the sink pads */
423 
424   ebin = gst_element_factory_make ("encodebin", NULL);
425 
426   /* First try is with a streamprofile that has a forced presence of 1 */
427   set_profile (ebin, create_ogg_theora_vorbis_profile (1, 1));
428 
429   fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_PAUSED),
430       GST_STATE_CHANGE_SUCCESS);
431 
432   /* Check if the source pad was properly created */
433   srcpad = gst_element_get_static_pad (ebin, "src");
434   fail_unless (srcpad != NULL);
435   gst_object_unref (srcpad);
436 
437   /* Check if the audio sink pad was properly created */
438   sinkpadvorbis = gst_element_get_static_pad (ebin, "audio_0");
439   fail_unless (sinkpadvorbis != NULL);
440   _caps_match (sinkpadvorbis, "audio/x-raw;audio/x-vorbis");
441   gst_object_unref (sinkpadvorbis);
442 
443   /* Check if the video sink pad was properly created */
444   sinkpadtheora = gst_element_get_static_pad (ebin, "video_1");
445   fail_unless (sinkpadtheora != NULL);
446   _caps_match (sinkpadtheora, "video/x-raw;video/x-theora");
447   gst_object_unref (sinkpadtheora);
448 
449   /* Set back to NULL */
450   fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_NULL),
451       GST_STATE_CHANGE_SUCCESS);
452 
453   gst_object_unref (ebin);
454 };
455 
456 GST_END_TEST;
457 
GST_START_TEST(test_encodebin_sink_pads_multiple_dynamic)458 GST_START_TEST (test_encodebin_sink_pads_multiple_dynamic)
459 {
460   GstElement *ebin;
461   GstPad *srcpad, *sinkpadvorbis, *sinkpadtheora;
462 
463   /* Create an encodebin and check that it properly creates the sink pads
464    * for a multiple-stream with unfixed presence */
465 
466   ebin = gst_element_factory_make ("encodebin", NULL);
467 
468   /* multi-stream profile that has non-forced presence */
469   set_profile (ebin, create_ogg_theora_vorbis_profile (0, 0));
470 
471   /* Check if the source pad was properly created */
472   srcpad = gst_element_get_static_pad (ebin, "src");
473   fail_unless (srcpad != NULL);
474   gst_object_unref (srcpad);
475 
476   /* Check if the audio sink pad was properly created */
477   sinkpadvorbis = gst_element_get_request_pad (ebin, "audio_0");
478   _caps_match (sinkpadvorbis, "audio/x-raw;audio/x-vorbis");
479   fail_unless (sinkpadvorbis != NULL);
480 
481   /* Check if the video sink pad was properly created */
482   sinkpadtheora = gst_element_get_request_pad (ebin, "video_1");
483   _caps_match (sinkpadtheora, "video/x-raw;video/x-theora");
484   fail_unless (sinkpadtheora != NULL);
485 
486   fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_PAUSED),
487       GST_STATE_CHANGE_SUCCESS);
488 
489   /* Set back to NULL */
490   fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_NULL),
491       GST_STATE_CHANGE_SUCCESS);
492 
493   gst_element_release_request_pad (GST_ELEMENT (ebin), sinkpadvorbis);
494   gst_object_unref (sinkpadvorbis);
495   gst_element_release_request_pad (GST_ELEMENT (ebin), sinkpadtheora);
496   gst_object_unref (sinkpadtheora);
497 
498   gst_object_unref (ebin);
499 };
500 
501 GST_END_TEST;
502 
GST_START_TEST(test_encodebin_sink_pads_dynamic_encoder)503 GST_START_TEST (test_encodebin_sink_pads_dynamic_encoder)
504 {
505   GstElement *ebin;
506   GstPad *srcpad, *sinkpad = NULL;
507   GstCaps *vorbiscaps;
508 
509   /* Create an encodebin and check that it properly creates the sink pads
510    * for a single-stream profile with a unfixed presence */
511 
512   ebin = gst_element_factory_make ("encodebin", NULL);
513 
514   /* streamprofile that has non-forced presence */
515   set_profile (ebin, create_ogg_vorbis_profile (0, NULL));
516 
517   /* Check if the source pad was properly created */
518   srcpad = gst_element_get_static_pad (ebin, "src");
519   fail_unless (srcpad != NULL);
520   gst_object_unref (srcpad);
521 
522   /* Check if the audio sink pad was properly created */
523   vorbiscaps = gst_caps_from_string ("audio/x-vorbis,channels=2,rate=44100");
524   g_signal_emit_by_name (ebin, "request-pad", vorbiscaps, &sinkpad);
525   gst_caps_unref (vorbiscaps);
526   fail_unless (sinkpad != NULL);
527   _caps_match (sinkpad, "audio/x-raw;audio/x-vorbis");
528   gst_element_release_request_pad (ebin, sinkpad);
529   gst_object_unref (sinkpad);
530 
531   fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_PAUSED),
532       GST_STATE_CHANGE_SUCCESS);
533 
534   /* Set back to NULL */
535   fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_NULL),
536       GST_STATE_CHANGE_SUCCESS);
537 
538   gst_object_unref (ebin);
539 };
540 
541 GST_END_TEST;
542 
GST_START_TEST(test_encodebin_render_audio_static)543 GST_START_TEST (test_encodebin_render_audio_static)
544 {
545   GstElement *ebin, *pipeline, *audiotestsrc, *fakesink;
546   GstBus *bus;
547   gboolean done = FALSE;
548 
549   /* Create an encodebin and render 5s of vorbis/ogg */
550 
551   pipeline = gst_pipeline_new ("encodebin-pipeline");
552   bus = gst_pipeline_get_bus ((GstPipeline *) pipeline);
553   audiotestsrc = gst_element_factory_make ("audiotestsrc", NULL);
554   g_object_set (audiotestsrc, "num-buffers", 10, NULL);
555   fakesink = gst_element_factory_make ("fakesink", NULL);
556 
557   ebin = gst_element_factory_make ("encodebin", NULL);
558   set_profile (ebin, create_ogg_vorbis_profile (1, NULL));
559 
560   gst_bin_add_many ((GstBin *) pipeline, audiotestsrc, ebin, fakesink, NULL);
561 
562   fail_unless (gst_element_link_many (audiotestsrc, ebin, fakesink, NULL));
563 
564   fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_PLAYING),
565       GST_STATE_CHANGE_ASYNC);
566 
567   while (!done) {
568     GstMessage *msg;
569 
570     /* poll the bus until we get EOS without any errors */
571     msg = gst_bus_timed_pop (bus, GST_SECOND / 10);
572     if (msg) {
573       switch (GST_MESSAGE_TYPE (msg)) {
574         case GST_MESSAGE_ERROR:
575           fail ("GST_MESSAGE_ERROR");
576           break;
577         case GST_MESSAGE_EOS:
578           done = TRUE;
579           break;
580         default:
581           break;
582       }
583       gst_message_unref (msg);
584     }
585   }
586 
587   /* Set back to NULL */
588   fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_NULL),
589       GST_STATE_CHANGE_SUCCESS);
590 
591   gst_object_unref (bus);
592 
593   gst_object_unref (pipeline);
594 }
595 
596 GST_END_TEST;
597 
GST_START_TEST(test_encodebin_render_audio_only_static)598 GST_START_TEST (test_encodebin_render_audio_only_static)
599 {
600   GstElement *ebin, *pipeline, *audiotestsrc, *fakesink;
601   GstBus *bus;
602   gboolean done = FALSE;
603   GstPad *sinkpad;
604   GstCaps *sinkcaps;
605 
606   /* Create an encodebin and render 5s of vorbis only */
607   pipeline = gst_pipeline_new ("encodebin-pipeline");
608   bus = gst_pipeline_get_bus ((GstPipeline *) pipeline);
609   audiotestsrc = gst_element_factory_make ("audiotestsrc", NULL);
610   g_object_set (audiotestsrc, "num-buffers", 10, NULL);
611   fakesink = gst_element_factory_make ("fakesink", NULL);
612 
613   ebin = gst_element_factory_make ("encodebin", NULL);
614   set_profile (ebin, create_vorbis_only_profile ());
615 
616   gst_bin_add_many (GST_BIN (pipeline), audiotestsrc, ebin, fakesink, NULL);
617 
618   GST_DEBUG ("linking encodebin");
619   fail_unless (gst_element_link_many (audiotestsrc, ebin, fakesink, NULL));
620 
621   /* Requesting a new pad should fail */
622   ASSERT_CRITICAL (gst_element_get_request_pad (ebin, "audio_0"));
623 
624   sinkcaps = gst_caps_new_empty_simple ("audio/x-raw");
625   g_signal_emit_by_name (ebin, "request-pad", sinkcaps, &sinkpad);
626   gst_caps_unref (sinkcaps);
627   fail_if (sinkpad != NULL);
628 
629   fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_PLAYING),
630       GST_STATE_CHANGE_ASYNC);
631 
632   while (!done) {
633     GstMessage *msg;
634 
635     /* poll the bus until we get EOS without any errors */
636     msg = gst_bus_timed_pop (bus, GST_SECOND / 10);
637     if (msg) {
638       switch (GST_MESSAGE_TYPE (msg)) {
639         case GST_MESSAGE_ERROR:
640           fail ("GST_MESSAGE_ERROR");
641           break;
642         case GST_MESSAGE_EOS:
643           done = TRUE;
644           break;
645         default:
646           break;
647       }
648       gst_message_unref (msg);
649     }
650   }
651 
652   /* Set back to NULL */
653   fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_NULL),
654       GST_STATE_CHANGE_SUCCESS);
655 
656   gst_object_unref (bus);
657 
658   gst_object_unref (pipeline);
659 }
660 
661 GST_END_TEST;
662 
GST_START_TEST(test_encodebin_render_audio_dynamic)663 GST_START_TEST (test_encodebin_render_audio_dynamic)
664 {
665   GstElement *ebin, *pipeline, *audiotestsrc, *fakesink;
666   GstBus *bus;
667   GstPad *sinkpad, *srcpad;
668   gboolean done = FALSE;
669 
670   /* Create an encodebin and render 5s of vorbis/ogg */
671 
672   pipeline = gst_pipeline_new ("encodebin-pipeline");
673   bus = gst_pipeline_get_bus ((GstPipeline *) pipeline);
674   audiotestsrc = gst_element_factory_make ("audiotestsrc", NULL);
675   g_object_set (audiotestsrc, "num-buffers", 10, NULL);
676   fakesink = gst_element_factory_make ("fakesink", NULL);
677 
678   ebin = gst_element_factory_make ("encodebin", NULL);
679   set_profile (ebin, create_ogg_vorbis_profile (0, NULL));
680 
681   gst_bin_add_many ((GstBin *) pipeline, audiotestsrc, ebin, fakesink, NULL);
682 
683   srcpad = gst_element_get_static_pad (audiotestsrc, "src");
684   fail_unless (srcpad != NULL);
685 
686   sinkpad = gst_element_get_request_pad (ebin, "audio_0");
687   fail_unless (sinkpad != NULL);
688   _caps_match (sinkpad, "audio/x-raw;audio/x-vorbis");
689 
690   fail_unless_equals_int (gst_pad_link (srcpad, sinkpad), GST_PAD_LINK_OK);
691 
692   gst_object_unref (srcpad);
693 
694   fail_unless (gst_element_link (ebin, fakesink));
695 
696   fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_PLAYING),
697       GST_STATE_CHANGE_ASYNC);
698 
699   while (!done) {
700     GstMessage *msg;
701 
702     /* poll the bus until we get EOS without any errors */
703     msg = gst_bus_timed_pop (bus, GST_SECOND / 10);
704     if (msg) {
705       switch (GST_MESSAGE_TYPE (msg)) {
706         case GST_MESSAGE_ERROR:
707           fail ("GST_MESSAGE_ERROR");
708           break;
709         case GST_MESSAGE_EOS:
710           done = TRUE;
711           break;
712         default:
713           break;
714       }
715       gst_message_unref (msg);
716     }
717   }
718 
719   /* Set back to NULL */
720   fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_NULL),
721       GST_STATE_CHANGE_SUCCESS);
722 
723   gst_element_release_request_pad (GST_ELEMENT (ebin), sinkpad);
724   gst_object_unref (sinkpad);
725 
726   gst_object_unref (bus);
727 
728   gst_object_unref (pipeline);
729 }
730 
731 GST_END_TEST;
732 
GST_START_TEST(test_encodebin_render_audio_video_static)733 GST_START_TEST (test_encodebin_render_audio_video_static)
734 {
735   GstElement *ebin, *pipeline, *audiotestsrc, *videotestsrc, *fakesink;
736   GstBus *bus;
737   gboolean done = FALSE;
738 
739   /* Create an encodebin and render 5s of vorbis/ogg */
740 
741   pipeline = gst_pipeline_new ("encodebin-pipeline");
742   bus = gst_pipeline_get_bus ((GstPipeline *) pipeline);
743   audiotestsrc = gst_element_factory_make ("audiotestsrc", NULL);
744   g_object_set (audiotestsrc, "num-buffers", 10, NULL);
745   videotestsrc = gst_element_factory_make ("videotestsrc", NULL);
746   g_object_set (videotestsrc, "num-buffers", 5, NULL);
747   fakesink = gst_element_factory_make ("fakesink", NULL);
748 
749   ebin = gst_element_factory_make ("encodebin", NULL);
750   set_profile (ebin, create_ogg_theora_vorbis_profile (1, 1));
751 
752   gst_bin_add_many ((GstBin *) pipeline, audiotestsrc, videotestsrc, ebin,
753       fakesink, NULL);
754 
755   fail_unless (gst_element_link (videotestsrc, ebin));
756   fail_unless (gst_element_link_many (audiotestsrc, ebin, fakesink, NULL));
757 
758   fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_PLAYING),
759       GST_STATE_CHANGE_ASYNC);
760 
761   while (!done) {
762     GstMessage *msg;
763 
764     /* poll the bus until we get EOS without any errors */
765     msg = gst_bus_timed_pop (bus, GST_SECOND / 10);
766     if (msg) {
767       switch (GST_MESSAGE_TYPE (msg)) {
768         case GST_MESSAGE_ERROR:
769           fail ("GST_MESSAGE_ERROR");
770           break;
771         case GST_MESSAGE_EOS:
772           done = TRUE;
773           break;
774         default:
775           break;
776       }
777       gst_message_unref (msg);
778     }
779   }
780 
781   /* Set back to NULL */
782   fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_NULL),
783       GST_STATE_CHANGE_SUCCESS);
784 
785   gst_object_unref (bus);
786 
787   gst_object_unref (pipeline);
788 }
789 
790 GST_END_TEST;
791 
GST_START_TEST(test_encodebin_render_audio_video_dynamic)792 GST_START_TEST (test_encodebin_render_audio_video_dynamic)
793 {
794   GstElement *ebin, *pipeline, *audiotestsrc, *videotestsrc, *fakesink;
795   GstBus *bus;
796   gboolean done = FALSE;
797   GstPad *sinkpad1, *sinkpad2, *srcpad;
798 
799   /* Create an encodebin and render 5s of vorbis/ogg */
800 
801   pipeline = gst_pipeline_new ("encodebin-pipeline");
802   bus = gst_pipeline_get_bus ((GstPipeline *) pipeline);
803   audiotestsrc = gst_element_factory_make ("audiotestsrc", NULL);
804   g_object_set (audiotestsrc, "num-buffers", 10, NULL);
805   videotestsrc = gst_element_factory_make ("videotestsrc", NULL);
806   g_object_set (videotestsrc, "num-buffers", 5, NULL);
807   fakesink = gst_element_factory_make ("fakesink", NULL);
808 
809   ebin = gst_element_factory_make ("encodebin", NULL);
810   set_profile (ebin, create_ogg_theora_vorbis_profile (0, 0));
811 
812   gst_bin_add_many ((GstBin *) pipeline, audiotestsrc, videotestsrc, ebin,
813       fakesink, NULL);
814 
815   fail_unless (gst_element_link (ebin, fakesink));
816 
817   srcpad = gst_element_get_static_pad (audiotestsrc, "src");
818   sinkpad1 = gst_element_get_request_pad (ebin, "audio_0");
819   fail_unless (srcpad != NULL);
820   fail_unless (sinkpad1 != NULL);
821   _caps_match (sinkpad1, "audio/x-raw;audio/x-vorbis");
822   fail_unless_equals_int (gst_pad_link (srcpad, sinkpad1), GST_PAD_LINK_OK);
823   gst_object_unref (srcpad);
824 
825   srcpad = gst_element_get_static_pad (videotestsrc, "src");
826   sinkpad2 = gst_element_get_request_pad (ebin, "video_1");
827   _caps_match (sinkpad2, "video/x-raw;video/x-theora");
828   fail_unless_equals_int (gst_pad_link (srcpad, sinkpad2), GST_PAD_LINK_OK);
829   gst_object_unref (srcpad);
830 
831   fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_PLAYING),
832       GST_STATE_CHANGE_ASYNC);
833 
834   while (!done) {
835     GstMessage *msg;
836 
837     /* poll the bus until we get EOS without any errors */
838     msg = gst_bus_timed_pop (bus, GST_SECOND / 10);
839     if (msg) {
840       switch (GST_MESSAGE_TYPE (msg)) {
841         case GST_MESSAGE_ERROR:
842           fail ("GST_MESSAGE_ERROR");
843           break;
844         case GST_MESSAGE_EOS:
845           done = TRUE;
846           break;
847         default:
848           break;
849       }
850       gst_message_unref (msg);
851     }
852   }
853 
854   /* Set back to NULL */
855   fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_NULL),
856       GST_STATE_CHANGE_SUCCESS);
857 
858   gst_element_release_request_pad (GST_ELEMENT (ebin), sinkpad1);
859   gst_object_unref (sinkpad1);
860   gst_element_release_request_pad (GST_ELEMENT (ebin), sinkpad2);
861   gst_object_unref (sinkpad2);
862 
863   gst_object_unref (bus);
864 
865   gst_object_unref (pipeline);
866 }
867 
868 GST_END_TEST;
869 
GST_START_TEST(test_encodebin_impossible_element_combination)870 GST_START_TEST (test_encodebin_impossible_element_combination)
871 {
872   GstElement *ebin;
873   GstEncodingProfile *prof;
874   GstCaps *ogg, *x264;
875 
876   ebin = gst_element_factory_make ("x264enc", NULL);
877   if (ebin == NULL) {
878     GST_DEBUG ("No available h264 encoder, skipping test");
879     return;
880   }
881   gst_object_unref (ebin);
882 
883   /* Make sure that impossible combinations of encoders and muxer
884    * properly fail. In this case we try putting h264 in ogg.
885    *
886    * To properly test we abort early, we use a presence of zero for the
887    * h264 stream profile. */
888 
889   ebin = gst_element_factory_make ("encodebin", NULL);
890 
891   ogg = gst_caps_new_empty_simple ("application/ogg");
892   prof = (GstEncodingProfile *) gst_encoding_container_profile_new ((gchar *)
893       "myprofile", NULL, ogg, NULL);
894   gst_caps_unref (ogg);
895 
896   x264 = gst_caps_new_empty_simple ("video/x-h264");
897   fail_unless (gst_encoding_container_profile_add_profile
898       (GST_ENCODING_CONTAINER_PROFILE (prof),
899           (GstEncodingProfile *) gst_encoding_video_profile_new (x264, NULL,
900               NULL, 0)));
901   gst_caps_unref (x264);
902 
903   g_object_set (ebin, "profile", prof, NULL);
904   gst_encoding_profile_unref (prof);
905 
906   /* It will go to READY... */
907   fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_READY),
908       GST_STATE_CHANGE_SUCCESS);
909   /* ... but to not PAUSED */
910   fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_PAUSED),
911       GST_STATE_CHANGE_FAILURE);
912 
913   gst_element_set_state (ebin, GST_STATE_NULL);
914 
915   gst_object_unref (ebin);
916 };
917 
918 GST_END_TEST;
919 
920 static void
_test_encodebin_reuse(GstEncodingProfile * prof1,GstEncodingProfile * prof2)921 _test_encodebin_reuse (GstEncodingProfile * prof1, GstEncodingProfile * prof2)
922 {
923   GstElement *ebin;
924 
925   ebin = gst_element_factory_make ("encodebin", NULL);
926 
927   /* Set a profile on encodebin... */
928   if (prof1)
929     g_object_set (ebin, "profile", prof1, NULL);
930 
931   /* Make sure we can go to PAUSED */
932   fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_PAUSED),
933       GST_STATE_CHANGE_SUCCESS);
934 
935   /* Set back to NULL */
936   fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_NULL),
937       GST_STATE_CHANGE_SUCCESS);
938 
939   if (prof2)
940     g_object_set (ebin, "profile", prof2, NULL);
941 
942   /* Make sure we can go to PLAYING */
943   fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_PAUSED),
944       GST_STATE_CHANGE_SUCCESS);
945 
946   /* Set back to NULL */
947   fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_NULL),
948       GST_STATE_CHANGE_SUCCESS);
949 
950   gst_object_unref (ebin);
951 }
952 
GST_START_TEST(test_encodebin_reuse)953 GST_START_TEST (test_encodebin_reuse)
954 {
955   GstEncodingProfile *prof1;
956   GstEncodingProfile *prof2;
957   GstEncodingProfile *prof3;
958 
959   prof1 = create_ogg_profile ();
960   prof2 = create_ogg_theora_vorbis_profile (1, 1);
961   prof3 = create_vorbis_only_profile ();
962 
963   _test_encodebin_reuse (prof1, NULL);
964   _test_encodebin_reuse (prof1, prof1);
965   _test_encodebin_reuse (prof1, prof2);
966   _test_encodebin_reuse (prof2, prof3);
967 
968   gst_encoding_profile_unref (prof1);
969   gst_encoding_profile_unref (prof2);
970   gst_encoding_profile_unref (prof3);
971 };
972 
973 GST_END_TEST;
974 
GST_START_TEST(test_encodebin_named_requests)975 GST_START_TEST (test_encodebin_named_requests)
976 {
977   GstElement *ebin;
978   GstEncodingContainerProfile *cprof;
979   GstCaps *ogg, *vorbis, *theora;
980   GstEncodingProfile *vorbisprof, *theoraprof;
981   GstPad *srcpad, *sinkpadvorbis, *sinkpadtheora;
982 
983   /* Create a profile with vorbis/theora named profile */
984   ogg = gst_caps_new_empty_simple ("application/ogg");
985   cprof =
986       gst_encoding_container_profile_new ((gchar *) "myprofile", NULL, ogg,
987       NULL);
988   gst_caps_unref (ogg);
989 
990   vorbis = gst_caps_new_empty_simple ("audio/x-vorbis");
991   vorbisprof =
992       (GstEncodingProfile *) gst_encoding_audio_profile_new (vorbis, NULL, NULL,
993       0);
994   gst_encoding_profile_set_name (vorbisprof, "vorbisprofile");
995   fail_unless (gst_encoding_container_profile_add_profile (cprof, vorbisprof));
996   gst_caps_unref (vorbis);
997 
998   theora = gst_caps_new_empty_simple ("video/x-theora");
999   theoraprof =
1000       (GstEncodingProfile *) gst_encoding_video_profile_new (theora, NULL, NULL,
1001       0);
1002   gst_encoding_profile_set_name (theoraprof, "theoraprofile");
1003   fail_unless (gst_encoding_container_profile_add_profile (cprof, theoraprof));
1004   gst_caps_unref (theora);
1005 
1006   ebin = gst_element_factory_make ("encodebin", NULL);
1007 
1008   /* First try is with a streamprofile that has a forced presence of 1 */
1009   g_object_set (ebin, "profile", cprof, NULL);
1010 
1011   gst_encoding_profile_unref (cprof);
1012 
1013   /* Check if the source pad was properly created */
1014   srcpad = gst_element_get_static_pad (ebin, "src");
1015   fail_unless (srcpad != NULL);
1016   gst_object_unref (srcpad);
1017 
1018   /* Request a vorbis profile pad */
1019   g_signal_emit_by_name (ebin, "request-profile-pad", "vorbisprofile",
1020       &sinkpadvorbis);
1021   fail_unless (sinkpadvorbis != NULL);
1022   _caps_match (sinkpadvorbis, "audio/x-raw;audio/x-vorbis");
1023   gst_object_unref (sinkpadvorbis);
1024 
1025   /* Request a theora profile pad */
1026   g_signal_emit_by_name (ebin, "request-profile-pad", "theoraprofile",
1027       &sinkpadtheora);
1028   fail_unless (sinkpadtheora != NULL);
1029   _caps_match (sinkpadtheora, "video/x-raw;video/x-theora");
1030   gst_object_unref (sinkpadtheora);
1031 
1032   fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_PAUSED),
1033       GST_STATE_CHANGE_SUCCESS);
1034 
1035   /* Set back to NULL */
1036   fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_NULL),
1037       GST_STATE_CHANGE_SUCCESS);
1038 
1039   gst_object_unref (ebin);
1040 
1041 }
1042 
1043 GST_END_TEST;
1044 
GST_START_TEST(test_encodebin_missing_plugin_messages)1045 GST_START_TEST (test_encodebin_missing_plugin_messages)
1046 {
1047   GstElement *pipeline = gst_pipeline_new ("test");
1048   GstBus *bus = gst_pipeline_get_bus ((GstPipeline *) pipeline);
1049   GstElement *ebin = gst_element_factory_make ("encodebin", NULL);
1050   GstMessage *message;
1051   GstElement *audiotestsrc;
1052   GstPad *sinkpad, *srcpad;
1053 
1054   audiotestsrc = gst_element_factory_make ("audiotestsrc", NULL);
1055   g_object_set (audiotestsrc, "num-buffers", 1, NULL);
1056   gst_bin_add ((GstBin *) pipeline, audiotestsrc);
1057 
1058   /* first add to bin, then set profile */
1059   gst_bin_add ((GstBin *) pipeline, ebin);
1060   set_profile (ebin, create_unsupported_profile ());
1061 
1062   srcpad = gst_element_get_static_pad (audiotestsrc, "src");
1063   sinkpad = gst_element_get_static_pad (ebin, "audio_0");
1064   fail_unless (gst_pad_link (srcpad, sinkpad) == GST_PAD_LINK_OK);
1065   gst_object_unref (srcpad);
1066   gst_object_unref (sinkpad);
1067 
1068   gst_element_set_state (pipeline, GST_STATE_PLAYING);
1069 
1070   message =
1071       gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
1072       GST_MESSAGE_ELEMENT);
1073   fail_if (message == NULL);
1074   fail_if (!gst_is_missing_plugin_message (message));
1075   gst_message_unref (message);
1076 
1077   gst_element_set_state (pipeline, GST_STATE_NULL);
1078   gst_object_unref (bus);
1079   gst_object_unref (pipeline);
1080 }
1081 
1082 GST_END_TEST;
1083 
GST_START_TEST(test_encodebin_fallback_profiles_on_failure)1084 GST_START_TEST (test_encodebin_fallback_profiles_on_failure)
1085 {
1086   GstElement *ebin;
1087   GstPad *sinkpad = NULL;
1088   GstCaps *vorbiscaps;
1089   GstEncodingProfile *profile, *vorbis_profile;
1090 
1091   ebin = gst_element_factory_make ("encodebin", NULL);
1092 
1093   /* Create a ogg profile with a vorbis sub profile
1094    * that can't be 'instanciated' because its preset is set
1095    * to nowaythispresetexists. */
1096   profile = create_ogg_vorbis_profile (0, (gchar *) "nowaythispresetexists");
1097   vorbis_profile = create_vorbis_only_profile ();
1098   gst_encoding_container_profile_add_profile (GST_ENCODING_CONTAINER_PROFILE
1099       (profile), vorbis_profile);
1100   set_profile (ebin, profile);
1101 
1102   /* Check if the audio sink pad can be created, meaning
1103    * that the first profile with a 'nowaythispresetexists'
1104    * preset has been skipped. */
1105   vorbiscaps = gst_caps_from_string ("audio/x-vorbis");
1106   g_signal_emit_by_name (ebin, "request-pad", vorbiscaps, &sinkpad);
1107   _caps_match (sinkpad, "audio/x-raw;audio/x-vorbis");
1108   gst_element_release_request_pad (ebin, sinkpad);
1109   gst_object_unref (sinkpad);
1110   gst_caps_unref (vorbiscaps);
1111 
1112   gst_object_unref (ebin);
1113 };
1114 
1115 GST_END_TEST;
1116 
1117 static Suite *
encodebin_suite(void)1118 encodebin_suite (void)
1119 {
1120   Suite *s = suite_create ("encodebin element");
1121   TCase *tc_chain = tcase_create ("general");
1122 
1123   suite_add_tcase (s, tc_chain);
1124   tcase_add_test (tc_chain, test_encodebin_set_profile);
1125   tcase_add_test (tc_chain, test_encodebin_can_go_to_ready_without_profile);
1126   tcase_add_test (tc_chain, test_encodebin_can_go_to_paused_with_profile);
1127   tcase_add_test (tc_chain, test_encodebin_sink_pads_static);
1128   tcase_add_test (tc_chain, test_encodebin_sink_pads_nopreset_static);
1129   tcase_add_test (tc_chain, test_encodebin_preset);
1130   tcase_add_test (tc_chain, test_encodebin_sink_pads_dynamic);
1131   tcase_add_test (tc_chain, test_encodebin_sink_pads_multiple_static);
1132   tcase_add_test (tc_chain, test_encodebin_sink_pads_multiple_dynamic);
1133   tcase_add_test (tc_chain, test_encodebin_sink_pads_dynamic_encoder);
1134   tcase_add_test (tc_chain, test_encodebin_render_audio_static);
1135   tcase_add_test (tc_chain, test_encodebin_render_audio_only_static);
1136   tcase_add_test (tc_chain, test_encodebin_render_audio_dynamic);
1137   tcase_add_test (tc_chain, test_encodebin_render_audio_video_static);
1138   tcase_add_test (tc_chain, test_encodebin_render_audio_video_dynamic);
1139   tcase_add_test (tc_chain, test_encodebin_impossible_element_combination);
1140   tcase_add_test (tc_chain, test_encodebin_reuse);
1141   tcase_add_test (tc_chain, test_encodebin_named_requests);
1142   tcase_add_test (tc_chain, test_encodebin_missing_plugin_messages);
1143   tcase_add_test (tc_chain, test_encodebin_fallback_profiles_on_failure);
1144 
1145   return s;
1146 }
1147 
1148 GST_CHECK_MAIN (encodebin);
1149