3 * Copyright (C) 2013 Collabora Ltd.
4 * Author: Thiago Sousa Santos <thiago.sousa.santos@collabora.com>
6 * gst-validate-media-info.c
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
29 #include "gst-validate-media-info.h"
32 #include <glib/gstdio.h>
35 struct _GstValidateStreamInfo
42 static GstValidateStreamInfo *
43 gst_validate_stream_info_from_discoverer_info (GstDiscovererStreamInfo * info)
45 GstValidateStreamInfo *ret = g_new0 (GstValidateStreamInfo, 1);
47 ret->caps = gst_discoverer_stream_info_get_caps (info);
48 if (GST_IS_DISCOVERER_CONTAINER_INFO (info)) {
50 gst_discoverer_container_info_get_streams (GST_DISCOVERER_CONTAINER_INFO
54 for (iter = streams; iter; iter = g_list_next (iter)) {
55 ret->children = g_list_append (ret->children,
56 gst_validate_stream_info_from_discoverer_info (iter->data));
58 gst_discoverer_stream_info_list_free (streams);
64 static GstValidateStreamInfo *
65 gst_validate_stream_info_from_caps_string (gchar * capsstr)
67 GstValidateStreamInfo *ret = g_new0 (GstValidateStreamInfo, 1);
69 ret->caps = gst_caps_from_string (capsstr);
75 gst_validate_stream_info_free (GstValidateStreamInfo * si)
78 gst_caps_unref (si->caps);
79 g_list_free_full (si->children,
80 (GDestroyNotify) gst_validate_stream_info_free);
85 gst_validate_media_info_init (GstValidateMediaInfo * mi)
89 mi->duration = GST_CLOCK_TIME_NONE;
91 mi->stream_info = NULL;
92 mi->playback_error = NULL;
93 mi->reverse_playback_error = NULL;
94 mi->track_switch_error = NULL;
96 mi->discover_only = FALSE;
100 gst_validate_media_info_clear (GstValidateMediaInfo * mi)
103 g_free (mi->playback_error);
104 g_free (mi->reverse_playback_error);
105 g_free (mi->track_switch_error);
107 gst_validate_stream_info_free (mi->stream_info);
111 gst_validate_media_info_free (GstValidateMediaInfo * mi)
113 gst_validate_media_info_clear (mi);
118 gst_validate_media_info_to_string (GstValidateMediaInfo * mi, gsize * length)
120 GKeyFile *kf = g_key_file_new ();
125 g_key_file_set_string (kf, "file-info", "uri", mi->uri);
126 g_key_file_set_uint64 (kf, "file-info", "file-size", mi->file_size);
129 g_key_file_set_uint64 (kf, "media-info", "file-duration", mi->duration);
130 g_key_file_set_boolean (kf, "media-info", "seekable", mi->seekable);
131 g_key_file_set_boolean (kf, "media-info", "is-image", mi->is_image);
133 if (mi->stream_info && mi->stream_info->caps) {
134 str = gst_caps_to_string (mi->stream_info->caps);
135 g_key_file_set_string (kf, "media-info", "caps", str);
140 g_key_file_set_string (kf, "playback-tests", "playback-error",
141 mi->playback_error ? mi->playback_error : "");
142 g_key_file_set_string (kf, "playback-tests", "reverse-playback-error",
143 mi->reverse_playback_error ? mi->reverse_playback_error : "");
144 g_key_file_set_string (kf, "playback-tests", "track-switch-error",
145 mi->track_switch_error ? mi->track_switch_error : "");
147 data = g_key_file_to_data (kf, length, NULL);
148 g_key_file_free (kf);
154 gst_validate_media_info_save (GstValidateMediaInfo * mi, const gchar * path,
158 gsize datalength = 0;
160 data = gst_validate_media_info_to_string (mi, &datalength);
162 if (!g_file_set_contents (path, data, datalength, err))
168 * gst_validate_media_info_load: (skip):
170 GstValidateMediaInfo *
171 gst_validate_media_info_load (const gchar * path, GError ** err)
173 GKeyFile *kf = g_key_file_new ();
174 GstValidateMediaInfo *mi;
177 if (!g_key_file_load_from_file (kf, path, G_KEY_FILE_NONE, err)) {
178 g_key_file_free (kf);
182 mi = g_new (GstValidateMediaInfo, 1);
183 gst_validate_media_info_init (mi);
185 mi->uri = g_key_file_get_string (kf, "file-info", "uri", err);
188 mi->file_size = g_key_file_get_uint64 (kf, "file-info", "file-size", err);
193 g_key_file_get_uint64 (kf, "media-info", "file-duration", NULL);
194 mi->seekable = g_key_file_get_boolean (kf, "media-info", "seekable", NULL);
195 mi->is_image = g_key_file_get_boolean (kf, "media-info", "is-image", NULL);
197 str = g_key_file_get_string (kf, "media-info", "caps", NULL);
199 mi->stream_info = gst_validate_stream_info_from_caps_string (str);
204 g_key_file_get_string (kf, "playback-tests", "playback-error", NULL);
205 mi->reverse_playback_error =
206 g_key_file_get_string (kf, "playback-tests", "reverse-playback-error",
208 mi->track_switch_error =
209 g_key_file_get_string (kf, "playback-tests", "track-switch-error", NULL);
210 if (mi->playback_error && strlen (mi->playback_error) == 0) {
211 g_free (mi->playback_error);
212 mi->playback_error = NULL;
214 if (mi->reverse_playback_error && strlen (mi->reverse_playback_error) == 0) {
215 g_free (mi->reverse_playback_error);
216 mi->reverse_playback_error = NULL;
218 if (mi->track_switch_error && strlen (mi->track_switch_error) == 0) {
219 g_free (mi->track_switch_error);
220 mi->track_switch_error = NULL;
224 g_key_file_free (kf);
229 check_file_size (GstValidateMediaInfo * mi)
237 filepath = g_filename_from_uri (mi->uri, NULL, &err);
243 if (g_stat (filepath, &statbuf) == 0) {
244 size = statbuf.st_size;
250 mi->file_size = size;
258 check_file_duration (GstValidateMediaInfo * mi, GstDiscovererInfo * info)
260 mi->duration = gst_discoverer_info_get_duration (info);
265 check_seekable (GstValidateMediaInfo * mi, GstDiscovererInfo * info)
267 mi->seekable = gst_discoverer_info_get_seekable (info);
272 static inline gboolean
273 _gst_caps_can_intersect_safe (const GstCaps * a, const GstCaps * b)
277 if ((a == NULL) || (b == NULL))
279 return gst_caps_can_intersect (a, b);
285 GstEncodingProfile *profile;
289 #define SET_MESSAGE(placeholder, msg) \
292 *placeholder = msg; \
297 compare_encoding_profile_with_discoverer_stream (GstValidateFileChecker * fc,
298 GstEncodingProfile * prof, GstDiscovererStreamInfo * stream, gchar ** msg);
301 compare_container_profile_with_container_discoverer_stream
302 (GstValidateFileChecker * fc, GstEncodingContainerProfile * prof,
303 GstDiscovererContainerInfo * stream, gchar ** msg)
305 ExpectedStream *expected_streams = NULL;
306 GList *container_streams;
307 const GList *profile_iter;
308 const GList *streams_iter;
310 gint expected_count = g_list_length ((GList *)
311 gst_encoding_container_profile_get_profiles (prof));
314 container_streams = gst_discoverer_container_info_get_streams (stream);
316 if (expected_count == 0) {
317 if (g_list_length (container_streams) != 0) {
320 ("No streams expected on this container, but found %u",
321 g_list_length (container_streams)));
327 /* initialize expected streams data */
328 expected_streams = g_malloc0 (sizeof (ExpectedStream) * expected_count);
329 for (i = 0, profile_iter = gst_encoding_container_profile_get_profiles (prof);
330 profile_iter; profile_iter = g_list_next (profile_iter), i++) {
331 GstEncodingProfile *prof = profile_iter->data;
332 ExpectedStream *expected = &(expected_streams[i]);
334 expected->profile = prof;
337 /* look for the streams on discoverer info */
338 for (streams_iter = container_streams; streams_iter;
339 streams_iter = g_list_next (streams_iter)) {
340 GstDiscovererStreamInfo *info = streams_iter->data;
341 gboolean found = FALSE;
342 for (i = 0; i < expected_count; i++) {
343 ExpectedStream *expected = &(expected_streams[i]);
345 if (compare_encoding_profile_with_discoverer_stream (fc,
346 expected->profile, info, NULL)) {
353 GstCaps *caps = gst_discoverer_stream_info_get_caps (info);
354 gchar *caps_str = gst_caps_to_string (caps);
356 g_strdup_printf ("Stream with caps '%s' wasn't found on file",
359 gst_caps_unref (caps);
365 /* check if all expected streams are present */
366 for (i = 0; i < expected_count; i++) {
367 ExpectedStream *expected = &(expected_streams[i]);
368 guint presence = gst_encoding_profile_get_presence (expected->profile);
373 if (presence != expected->count) {
375 gst_caps_to_string (gst_encoding_profile_get_format
376 (expected->profile));
378 g_strdup_printf ("Stream from profile %s (with caps '%s"
379 "' has presence %u but the number of streams found was %d",
380 gst_encoding_profile_get_name (expected->profile), caps_str,
381 presence, expected->count));
389 g_free (expected_streams);
390 gst_discoverer_stream_info_list_free (container_streams);
395 compare_encoding_profile_with_discoverer_stream (GstValidateFileChecker * fc,
396 GstEncodingProfile * prof, GstDiscovererStreamInfo * stream, gchar ** msg)
399 GstCaps *caps = NULL;
400 const GstCaps *profile_caps;
401 const GstCaps *restriction_caps;
403 caps = gst_discoverer_stream_info_get_caps (stream);
404 profile_caps = gst_encoding_profile_get_format (prof);
405 restriction_caps = gst_encoding_profile_get_restriction (prof);
407 /* TODO need to consider profile caps restrictions */
408 if (!_gst_caps_can_intersect_safe (caps, profile_caps)) {
409 gchar *caps_str = gst_caps_to_string (caps);
410 gchar *profile_caps_str = gst_caps_to_string (profile_caps);
411 SET_MESSAGE (msg, g_strdup_printf ("Caps '%s' didn't match profile '%s'",
412 profile_caps_str, caps_str));
414 g_free (profile_caps_str);
419 if (restriction_caps) {
420 GstStructure *structure;
422 gboolean found = FALSE;
424 for (i = 0; i < gst_caps_get_size (restriction_caps); i++) {
425 structure = gst_caps_get_structure (restriction_caps, i);
426 structure = gst_structure_copy (structure);
427 gst_structure_set_name (structure,
428 gst_structure_get_name (gst_caps_get_structure (caps, 0)));
429 if (gst_structure_can_intersect (structure, gst_caps_get_structure (caps,
431 gst_structure_free (structure);
435 gst_structure_free (structure);
438 gchar *caps_str = gst_caps_to_string (caps);
439 gchar *restriction_caps_str = gst_caps_to_string (restriction_caps);
441 g_strdup_printf ("Caps restriction '%s' wasn't respected on file "
442 "with caps '%s'", restriction_caps_str, caps_str));
444 g_free (restriction_caps_str);
450 if (GST_IS_ENCODING_CONTAINER_PROFILE (prof)) {
451 if (GST_IS_DISCOVERER_CONTAINER_INFO (stream)) {
453 ret & compare_container_profile_with_container_discoverer_stream (fc,
454 (GstEncodingContainerProfile *) prof,
455 (GstDiscovererContainerInfo *) stream, msg);
458 g_strdup_printf ("Expected container profile but found stream of %s",
459 gst_discoverer_stream_info_get_stream_type_nick (stream)));
464 } else if (GST_IS_ENCODING_VIDEO_PROFILE (prof)) {
465 if (!GST_IS_DISCOVERER_VIDEO_INFO (stream)) {
467 g_strdup_printf ("Expected video profile but found stream of %s",
468 gst_discoverer_stream_info_get_stream_type_nick (stream)));
473 } else if (GST_IS_ENCODING_AUDIO_PROFILE (prof)) {
474 if (!GST_IS_DISCOVERER_AUDIO_INFO (stream)) {
476 g_strdup_printf ("Expected audio profile but found stream of %s",
477 gst_discoverer_stream_info_get_stream_type_nick (stream)));
482 g_assert_not_reached ();
489 gst_caps_unref (caps);
497 check_encoding_profile (GstValidateMediaInfo * mi, GstDiscovererInfo * info)
500 GstDiscovererStreamInfo *streaminfo;
502 streaminfo = gst_discoverer_info_get_stream_info (info);
503 mi->stream_info = gst_validate_stream_info_from_discoverer_info (streaminfo);
505 gst_discoverer_info_unref (streaminfo);
510 typedef gboolean (*GstElementConfigureFunc) (GstValidateMediaInfo *,
511 GstElement *, gchar ** msg);
513 check_playback_scenario (GstValidateMediaInfo * mi,
514 GstElementConfigureFunc configure_function, gchar ** error_message)
517 GstElement *videosink, *audiosink;
521 GstStateChangeReturn state_ret;
523 playbin = gst_element_factory_make ("playbin", "fc-playbin");
524 videosink = gst_element_factory_make ("fakesink", "fc-videosink");
525 audiosink = gst_element_factory_make ("fakesink", "fc-audiosink");
527 if (!playbin || !videosink || !audiosink) {
528 *error_message = g_strdup ("Playbin and/or fakesink not available");
531 g_object_set (playbin, "video-sink", videosink, "audio-sink", audiosink,
532 "uri", mi->uri, NULL);
534 bus = gst_pipeline_get_bus (GST_PIPELINE (playbin));
536 state_ret = gst_element_set_state (playbin, GST_STATE_PAUSED);
537 if (state_ret == GST_STATE_CHANGE_FAILURE) {
538 *error_message = g_strdup ("Failed to change pipeline to paused");
541 } else if (state_ret == GST_STATE_CHANGE_ASYNC) {
543 gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
544 GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_EOS | GST_MESSAGE_ERROR);
545 if (msg && GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_DONE) {
546 gst_message_unref (msg);
549 *error_message = g_strdup ("Playback finihshed unexpectedly");
554 if (configure_function) {
555 if (!configure_function (mi, playbin, error_message)) {
556 gst_object_unref (bus);
557 gst_object_unref (playbin);
562 if (gst_element_set_state (playbin,
563 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
564 *error_message = g_strdup ("Failed to set pipeline to playing");
570 gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
571 GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
573 if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS) {
576 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
577 GError *error = NULL;
580 gst_message_parse_error (msg, &error, &debug);
581 *error_message = g_strdup_printf ("Playback error: %s : %s",
582 error->message, debug);
583 g_error_free (error);
588 g_assert_not_reached ();
590 gst_message_unref (msg);
593 *error_message = g_strdup ("Playback finihshed unexpectedly");
597 gst_object_unref (bus);
598 gst_element_set_state (playbin, GST_STATE_NULL);
599 gst_object_unref (playbin);
605 check_playback (GstValidateMediaInfo * mi, gchar ** msg)
607 return check_playback_scenario (mi, NULL, msg);
611 send_reverse_seek (GstValidateMediaInfo * mi, GstElement * pipeline,
616 ret = gst_element_seek (pipeline, -1.0, GST_FORMAT_TIME,
617 GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, -1);
620 *msg = g_strdup ("Reverse playback seek failed");
626 check_reverse_playback (GstValidateMediaInfo * mi, gchar ** msg)
628 return check_playback_scenario (mi, send_reverse_seek, msg);
639 static GstPadProbeReturn
640 input_selector_pad_probe (GstPad * pad, GstPadProbeInfo * info,
643 GstPad *sink_pad = NULL;
645 if (info->type == GST_PAD_PROBE_TYPE_BUFFER) {
646 BufferCountData *bcd =
647 g_object_get_data (G_OBJECT (pad), "buffer-count-data");
649 GST_ERROR_OBJECT (pad, "No buffer-count-data found");
650 return GST_PAD_PROBE_OK;
654 if (GST_PAD_IS_SRC (pad)) {
655 g_object_get (GST_PAD_PARENT (pad), "active-pad", &sink_pad, NULL);
657 bcd = g_object_get_data (G_OBJECT (sink_pad), "buffer-count-data");
659 gst_object_unref (sink_pad);
660 GST_ERROR_OBJECT (pad, "No buffer-count-data found");
661 return GST_PAD_PROBE_OK;
664 gst_object_unref (sink_pad);
668 return GST_PAD_PROBE_OK;
672 setup_input_selector_counters (GstElement * element)
674 GstIterator *iterator;
675 gboolean done = FALSE;
676 GValue value = { 0, };
678 BufferCountData *bcd;
680 iterator = gst_element_iterate_pads (element);
682 switch (gst_iterator_next (iterator, &value)) {
683 case GST_ITERATOR_OK:
684 pad = g_value_dup_object (&value);
685 bcd = g_slice_new0 (BufferCountData);
686 g_object_set_data (G_OBJECT (pad), "buffer-count-data", bcd);
687 bcd->probe_id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER,
688 (GstPadProbeCallback) input_selector_pad_probe, NULL, NULL);
690 g_value_reset (&value);
692 case GST_ITERATOR_RESYNC:
693 gst_iterator_resync (iterator);
695 case GST_ITERATOR_ERROR:
698 case GST_ITERATOR_DONE:
703 gst_iterator_free (iterator);
707 check_and_remove_input_selector_counters (GstElement * element,
708 gchar ** error_message)
710 GstIterator *iterator;
711 gboolean done = FALSE;
713 GValue value = { 0, };
714 guint id, ncounters = 0, total_sink_count = 0;
715 BufferCountData *bcd, **bcds =
716 g_malloc0 (sizeof (BufferCountData *) * element->numpads);
719 /* First gather all counts, and free memory, etc */
720 iterator = gst_element_iterate_pads (element);
722 switch (gst_iterator_next (iterator, &value)) {
723 case GST_ITERATOR_OK:
724 pad = g_value_get_object (&value);
725 bcd = g_object_get_data (G_OBJECT (pad), "buffer-count-data");
726 if (GST_PAD_IS_SINK (pad)) {
727 bcds[++ncounters] = bcd;
728 total_sink_count += bcd->counter;
732 gst_pad_remove_probe (pad, bcd->probe_id);
733 g_value_reset (&value);
735 case GST_ITERATOR_RESYNC:
736 gst_iterator_resync (iterator);
738 case GST_ITERATOR_ERROR:
740 *error_message = g_strdup ("Failed to iterate through pads");
743 case GST_ITERATOR_DONE:
748 gst_iterator_free (iterator);
755 /* Now bcd[0] contains the total number of buffers received,
756 and subsequent bcd slots contain the total number of buffers sent
757 by each source pad. Check that the totals match, and that every
758 source pad got at least one buffer.
759 Or that's the theory. It doesn't work in practice, the number of
760 raw buffers flowing is non deterministic. */
762 if (bcds[0]->counter != total_sink_count) {
763 *error_message = g_strdup_printf ("%u buffers received, %u buffers sent",
764 total_sink_count, bcds[0]->counter);
767 for (id = 1; id < element->numpads; ++id) {
768 if (bcds[id]->counter == 0) {
770 g_strdup_printf ("Sink pad %s got no buffers",
771 GST_PAD_NAME (bcds[id]->pad));
776 /* We at least check that at least one buffer was sent while the
777 selected sink was a given sink, for all sinks */
778 for (id = 1; id < element->numpads; ++id) {
779 if (bcds[id]->back_counter == 0) {
781 g_strdup_printf ("No buffer was sent while sink pad %s was active",
782 GST_PAD_NAME (bcds[id]->pad));
787 for (id = 0; id < element->numpads; ++id) {
788 gst_object_unref (bcds[id]->pad);
789 g_slice_free (BufferCountData, bcds[id]);
796 find_next_pad (GstElement * element, GstPad * pad)
798 GstIterator *iterator;
799 gboolean done = FALSE, pick = FALSE;
800 GstPad *tmp, *next = NULL, *first = NULL;
801 GValue value = { 0, };
803 iterator = gst_element_iterate_sink_pads (element);
806 switch (gst_iterator_next (iterator, &value)) {
807 case GST_ITERATOR_OK:
808 tmp = g_value_dup_object (&value);
810 first = gst_object_ref (tmp);
816 gst_object_unref (tmp);
818 g_value_reset (&value);
820 case GST_ITERATOR_RESYNC:
821 gst_iterator_resync (iterator);
823 case GST_ITERATOR_ERROR:
826 case GST_ITERATOR_DONE:
827 /* When we reach the end, we may be in the case where the pad
828 to search from was the last one in the list, in which case
829 we want to return the first pad. */
838 gst_iterator_free (iterator);
840 gst_object_unref (first);
845 find_input_selector (GValue * value, void *userdata)
847 GstElement *element = g_value_get_object (value);
848 g_assert (GST_IS_ELEMENT (element));
849 if (g_str_has_prefix (GST_ELEMENT_NAME (element), "inputselector")) {
851 g_object_get (element, "n-pads", &npads, NULL);
858 /* This function looks for an input-selector, and, if one is found,
859 cycle through its sink pads */
861 check_track_selection (GstValidateMediaInfo * mi, gchar ** error_message)
864 GstElement *videosink, *audiosink;
865 GstElement *input_selector = NULL;
869 GstStateChangeReturn state_ret;
870 GstIterator *iterator;
871 GstPad *original_pad;
872 static const GstClockTime switch_delay = GST_SECOND * 5;
873 GValue value = { 0, };
875 playbin = gst_element_factory_make ("playbin", "fc-playbin");
876 videosink = gst_element_factory_make ("fakesink", "fc-videosink");
877 audiosink = gst_element_factory_make ("fakesink", "fc-audiosink");
879 if (!playbin || !videosink || !audiosink) {
880 *error_message = g_strdup ("Playbin and/or fakesink not available");
883 g_object_set (playbin, "video-sink", videosink, "audio-sink", audiosink,
884 "uri", mi->uri, NULL);
885 g_object_set (videosink, "sync", TRUE, NULL);
886 g_object_set (audiosink, "sync", TRUE, NULL);
888 bus = gst_pipeline_get_bus (GST_PIPELINE (playbin));
890 state_ret = gst_element_set_state (playbin, GST_STATE_PAUSED);
891 if (state_ret == GST_STATE_CHANGE_FAILURE) {
892 *error_message = g_strdup ("Failed to change pipeline to paused");
895 } else if (state_ret == GST_STATE_CHANGE_ASYNC) {
897 gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
898 GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_EOS | GST_MESSAGE_ERROR);
899 if (msg && GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_DONE) {
900 gst_message_unref (msg);
903 *error_message = g_strdup ("Playback finihshed unexpectedly");
908 if (gst_element_set_state (playbin,
909 GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
910 *error_message = g_strdup ("Failed to set pipeline to playing");
915 iterator = gst_bin_iterate_recurse (GST_BIN (playbin));
916 if (!gst_iterator_find_custom (iterator,
917 (GCompareFunc) find_input_selector, &value, NULL)) {
918 /* It's fine, there's only one if several tracks of the same type */
919 gst_iterator_free (iterator);
920 input_selector = NULL;
923 input_selector = g_value_dup_object (&value);
924 g_value_reset (&value);
925 gst_iterator_free (iterator);
926 g_object_get (input_selector, "active-pad", &original_pad, NULL);
928 /* Unexpected, log an error somehow ? */
930 gst_object_unref (input_selector);
931 input_selector = NULL;
935 /* Attach a buffer counter to each pad */
936 setup_input_selector_counters (input_selector);
940 gst_bus_timed_pop_filtered (bus, switch_delay,
941 GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
943 if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS) {
946 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
947 GError *error = NULL;
950 gst_message_parse_error (msg, &error, &debug);
951 *error_message = g_strdup_printf ("Playback error: %s : %s",
952 error->message, debug);
953 g_error_free (error);
958 g_assert_not_reached ();
960 gst_message_unref (msg);
962 /* Timeout, switch track if we have more, or stop */
963 GstPad *active_pad, *next_pad;
965 g_object_get (input_selector, "active-pad", &active_pad, NULL);
968 g_strdup ("Failed to get active-pad from input-selector");
972 next_pad = find_next_pad (input_selector, active_pad);
973 gst_object_unref (active_pad);
978 if (next_pad == original_pad) {
981 g_object_set (input_selector, "active-pad", next_pad, NULL);
982 gst_object_unref (next_pad);
987 if (input_selector) {
988 if (!check_and_remove_input_selector_counters (input_selector,
991 gst_object_unref (input_selector);
993 gst_object_unref (bus);
994 gst_element_set_state (playbin, GST_STATE_NULL);
995 gst_object_unref (playbin);
1001 check_is_image (GstDiscovererInfo * info)
1003 gboolean ret = FALSE;
1004 GList *video_streams = gst_discoverer_info_get_video_streams (info);
1006 if (g_list_length (video_streams) == 1) {
1007 if (gst_discoverer_video_info_is_image (video_streams->data)) {
1008 GList *audio_streams = gst_discoverer_info_get_audio_streams (info);
1010 if (audio_streams == NULL)
1013 gst_discoverer_stream_info_list_free (audio_streams);
1017 gst_discoverer_stream_info_list_free (video_streams);
1023 gst_validate_media_info_inspect_uri (GstValidateMediaInfo * mi,
1024 const gchar * uri, gboolean discover_only, GError ** err)
1026 GstDiscovererInfo *info;
1027 GstDiscoverer *discoverer = gst_discoverer_new (GST_SECOND * 60, err);
1028 gboolean ret = TRUE;
1030 g_return_val_if_fail (uri != NULL, FALSE);
1033 mi->uri = g_strdup (uri);
1039 info = gst_discoverer_discover_uri (discoverer, uri, err);
1041 if (gst_discoverer_info_get_result (info) != GST_DISCOVERER_OK) {
1042 gst_object_unref (discoverer);
1046 mi->is_image = check_is_image (info);
1047 ret = check_file_size (mi) & ret;
1048 ret = check_encoding_profile (mi, info) & ret;
1049 ret = check_file_duration (mi, info) & ret;
1054 check_seekable (mi, info);
1058 ret = check_playback (mi, &mi->playback_error) & ret;
1059 ret = check_reverse_playback (mi, &mi->reverse_playback_error) & ret;
1060 ret = check_track_selection (mi, &mi->track_switch_error) & ret;
1063 gst_object_unref (discoverer);
1069 gst_validate_media_info_compare (GstValidateMediaInfo * expected,
1070 GstValidateMediaInfo * extracted)
1072 gboolean ret = TRUE;
1073 if (expected->duration != extracted->duration) {
1074 gst_validate_printf (NULL,
1075 "Duration changed: %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "\n",
1076 GST_TIME_ARGS (expected->duration),
1077 GST_TIME_ARGS (extracted->duration));
1080 if (expected->file_size != extracted->file_size) {
1081 gst_validate_printf (NULL,
1082 "File size changed: %" G_GUINT64_FORMAT " -> %" G_GUINT64_FORMAT "\n",
1083 expected->file_size, extracted->file_size);
1086 if (expected->seekable && !extracted->seekable) {
1087 gst_validate_printf (NULL, "File isn't seekable anymore\n");
1091 if (extracted->discover_only == FALSE) {
1092 if (expected->playback_error == NULL && extracted->playback_error) {
1093 gst_validate_printf (NULL, "Playback is now failing with: %s\n",
1094 extracted->playback_error);
1097 if (expected->reverse_playback_error == NULL
1098 && extracted->reverse_playback_error) {
1099 gst_validate_printf (NULL, "Reverse playback is now failing with: %s\n",
1100 extracted->reverse_playback_error);
1103 if (expected->track_switch_error == NULL && extracted->track_switch_error) {
1104 gst_validate_printf (NULL, "Track switching is now failing with: %s\n",
1105 extracted->track_switch_error);
1110 if (extracted->stream_info == NULL || expected->stream_info == NULL) {
1111 gst_validate_printf (NULL,
1112 "Stream infos could not be retrieved, an error occured\n");
1114 } else if (expected->stream_info
1115 && !gst_caps_is_equal_fixed (expected->stream_info->caps,
1116 extracted->stream_info->caps)) {
1117 gchar *caps1 = gst_caps_to_string (expected->stream_info->caps);
1118 gchar *caps2 = gst_caps_to_string (extracted->stream_info->caps);
1120 gst_validate_printf (NULL, "Media caps changed: '%s' -> '%s'\n", caps1,