validate: cleanup the use of GST_VALIDATE_API on Windows
[platform/upstream/gstreamer.git] / subprojects / gst-devtools / validate / gst / validate / media-descriptor.c
1 /**
2  * Gstreamer
3  *
4  * Copyright (c) 2012, Collabora Ltd.
5  * Author: Thibault Saunier <thibault.saunier@collabora.com>
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 #ifdef HAVE_CONFIG_H
23 #  include "config.h"
24 #endif
25
26 #include <string.h>
27 #include "media-descriptor.h"
28
29 #include "gst-validate-internal.h"
30
31 struct _GstValidateMediaDescriptorPrivate
32 {
33   GstValidateMediaFileNode *filenode;
34 };
35
36 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstValidateMediaDescriptor,
37     gst_validate_media_descriptor, GST_TYPE_OBJECT,
38     G_ADD_PRIVATE (GstValidateMediaDescriptor)
39     G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, NULL));
40
41 static inline void
42 free_tagnode (GstValidateMediaTagNode * tagnode)
43 {
44   g_free (tagnode->str_open);
45   g_free (tagnode->str_close);
46   if (tagnode->taglist)
47     gst_tag_list_unref (tagnode->taglist);
48
49   g_slice_free (GstValidateMediaTagNode, tagnode);
50 }
51
52 static inline void
53 free_tagsnode (GstValidateMediaTagsNode * tagsnode)
54 {
55   g_free (tagsnode->str_open);
56   g_free (tagsnode->str_close);
57   g_list_free_full (tagsnode->tags, (GDestroyNotify) free_tagnode);
58   g_slice_free (GstValidateMediaTagsNode, tagsnode);
59 }
60
61 static inline void
62 free_framenode (GstValidateMediaFrameNode * framenode)
63 {
64   g_free (framenode->str_open);
65   g_free (framenode->str_close);
66
67   if (framenode->buf)
68     gst_buffer_unref (framenode->buf);
69
70   g_slice_free (GstValidateMediaFrameNode, framenode);
71 }
72
73 static inline void
74 free_segmentnode (GstValidateSegmentNode * segmentnode)
75 {
76   g_free (segmentnode->str_open);
77   g_free (segmentnode->str_close);
78
79   g_slice_free (GstValidateSegmentNode, segmentnode);
80 }
81
82 static inline void
83 free_streamnode (GstValidateMediaStreamNode * streamnode)
84 {
85   if (streamnode->caps)
86     gst_caps_unref (streamnode->caps);
87
88   g_list_free_full (streamnode->frames, (GDestroyNotify) free_framenode);
89   g_list_free_full (streamnode->segments, (GDestroyNotify) free_segmentnode);
90
91   if (streamnode->pad)
92     gst_object_unref (streamnode->pad);
93
94   if (streamnode->tags)
95     free_tagsnode (streamnode->tags);
96
97   g_free (streamnode->padname);
98   g_free (streamnode->id);
99   g_free (streamnode->str_open);
100   g_free (streamnode->str_close);
101   g_slice_free (GstValidateMediaStreamNode, streamnode);
102 }
103
104 void
105 gst_validate_filenode_free (GstValidateMediaFileNode * filenode)
106 {
107   g_list_free_full (filenode->streams, (GDestroyNotify) free_streamnode);
108   if (filenode->tags)
109     free_tagsnode (filenode->tags);
110
111   g_free (filenode->uri);
112
113   if (filenode->caps)
114     gst_caps_unref (filenode->caps);
115
116   g_free (filenode->str_open);
117   g_free (filenode->str_close);
118
119   g_slice_free (GstValidateMediaFileNode, filenode);
120 }
121
122 gboolean
123     gst_validate_tag_node_compare
124     (GstValidateMediaTagNode * tnode, const GstTagList * tlist)
125 {
126   if (gst_structure_is_equal (GST_STRUCTURE (tlist),
127           GST_STRUCTURE (tnode->taglist)) == FALSE) {
128     return FALSE;
129   }
130
131   tnode->found = TRUE;
132
133   return TRUE;
134 }
135
136 enum
137 {
138   PROP_0,
139   PROP_RUNNER,
140   PROP_LAST
141 };
142
143
144 static void
145 gst_validate_media_descriptor_dispose (GstValidateMediaDescriptor * self)
146 {
147   G_OBJECT_CLASS (gst_validate_media_descriptor_parent_class)->dispose (G_OBJECT
148       (self));
149 }
150
151 static void
152 gst_validate_media_descriptor_finalize (GstValidateMediaDescriptor * self)
153 {
154   if (self->priv->filenode)
155     gst_validate_filenode_free (self->priv->filenode);
156
157   G_OBJECT_CLASS (gst_validate_media_descriptor_parent_class)->finalize
158       (G_OBJECT (self));
159 }
160
161 static void
162 gst_validate_media_descriptor_init (GstValidateMediaDescriptor * self)
163 {
164   self->priv = gst_validate_media_descriptor_get_instance_private (self);
165   self->priv->filenode = g_slice_new0 (GstValidateMediaFileNode);
166 }
167
168 static void
169 _set_property (GObject * object, guint prop_id,
170     const GValue * value, GParamSpec * pspec)
171 {
172   switch (prop_id) {
173     case PROP_RUNNER:
174       /* we assume the runner is valid as long as this scenario is,
175        * no ref taken */
176       gst_validate_reporter_set_runner (GST_VALIDATE_REPORTER (object),
177           g_value_get_object (value));
178       break;
179     default:
180       break;
181   }
182 }
183
184 static void
185 _get_property (GObject * object, guint prop_id,
186     GValue * value, GParamSpec * pspec)
187 {
188   switch (prop_id) {
189     case PROP_RUNNER:
190       /* we assume the runner is valid as long as this scenario is,
191        * no ref taken */
192       g_value_take_object (value,
193           gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (object)));
194       break;
195     default:
196       break;
197   }
198 }
199
200 static void
201 gst_validate_media_descriptor_class_init (GstValidateMediaDescriptorClass *
202     self_class)
203 {
204   GObjectClass *object_class = G_OBJECT_CLASS (self_class);
205
206   object_class->dispose =
207       (void (*)(GObject * object)) gst_validate_media_descriptor_dispose;
208   object_class->finalize =
209       (void (*)(GObject * object)) gst_validate_media_descriptor_finalize;
210
211   object_class->get_property = _get_property;
212   object_class->set_property = _set_property;
213
214   g_object_class_install_property (object_class, PROP_RUNNER,
215       g_param_spec_object ("validate-runner", "VALIDATE Runner",
216           "The Validate runner to report errors to",
217           GST_TYPE_VALIDATE_RUNNER,
218           G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
219 }
220
221 static gint
222 compare_tags (GstValidateMediaDescriptor * ref,
223     GstValidateMediaStreamNode * rstream, GstValidateMediaStreamNode * cstream)
224 {
225   gboolean found;
226   GstValidateMediaTagNode *rtag, *ctag;
227   GList *rtag_list, *ctag_list;
228   GstValidateMediaTagsNode *rtags, *ctags;
229
230   rtags = rstream->tags;
231   ctags = cstream->tags;
232   if (!rtags && !ctags)
233     return 1;
234   else if (!rtags && ctags) {
235     GList *taglist;
236     GString *all_tags = g_string_new (NULL);
237
238     for (taglist = ctags->tags; taglist; taglist = taglist->next) {
239       gchar *stags = gst_tag_list_to_string (((GstValidateMediaTagNode *)
240               taglist->data)->taglist);
241
242       g_string_append_printf (all_tags, "%s\n", stags);
243       g_free (stags);
244     }
245
246     GST_VALIDATE_REPORT (ref, FILE_TAG_DETECTION_INCORRECT,
247         "Reference descriptor for stream %s has NO tags"
248         " but tags found: %s", rstream->id, all_tags->str);
249
250     g_string_free (all_tags, TRUE);
251
252     return 0;
253   } else if (rtags && !ctags) {
254     GList *taglist;
255     GString *all_tags = g_string_new (NULL);
256
257     for (taglist = rtags->tags; taglist; taglist = taglist->next) {
258       gchar *stags = gst_tag_list_to_string (((GstValidateMediaTagNode *)
259               taglist->data)->taglist);
260
261       g_string_append_printf (all_tags, "%s\n", stags);
262       g_free (stags);
263     }
264
265     GST_VALIDATE_REPORT (ref, FILE_TAG_DETECTION_INCORRECT,
266         "Reference descriptor for stream %s has tags:\n %s\n"
267         " but NO tags found on the stream", rstream->id, all_tags->str);
268
269     g_string_free (all_tags, TRUE);
270     return 0;
271   }
272
273   for (rtag_list = rtags->tags; rtag_list; rtag_list = rtag_list->next) {
274     rtag = rtag_list->data;
275     found = FALSE;
276     for (ctag_list = ctags->tags; ctag_list; ctag_list = ctag_list->next) {
277       ctag = ctag_list->data;
278       if (gst_tag_list_is_equal (rtag->taglist, ctag->taglist)) {
279         found = TRUE;
280
281         break;
282       }
283     }
284
285     if (found == FALSE) {
286       gchar *rtaglist = gst_tag_list_to_string (rtag->taglist);
287
288       GST_VALIDATE_REPORT (ref, FILE_TAG_DETECTION_INCORRECT,
289           "Reference descriptor for stream %s has tags %s"
290           " but no equivalent taglist was found on the compared stream",
291           rstream->id, rtaglist);
292       g_free (rtaglist);
293
294       return 0;
295     }
296   }
297
298   return 1;
299 }
300
301 /* Workaround false warning caused by differnet file path */
302 static gboolean
303 stream_id_is_equal (const gchar * uri, const gchar * rid, const gchar * cid)
304 {
305   GChecksum *cs;
306   const gchar *stream_id;
307
308   /* Simple case it's the same */
309   if (g_strcmp0 (rid, cid) == 0)
310     return TRUE;
311
312   /* If it's not from file or from our local http server, it should have been the same */
313   if (!g_str_has_prefix (uri, "file://")
314       && !g_str_has_prefix (uri, "imagesequence:/")
315       && !g_str_has_prefix (uri, "http://127.0.0.1"))
316     return FALSE;
317
318   /* taken from basesrc, compute the reference stream-id */
319   cs = g_checksum_new (G_CHECKSUM_SHA256);
320   g_checksum_update (cs, (const guchar *) uri, strlen (uri));
321
322   stream_id = g_checksum_get_string (cs);
323
324   /* If the reference stream_id is the URI SHA256, that means we have a single
325    * stream file (no demuxing), just assume it's the same id */
326   if (g_strcmp0 (rid, stream_id) == 0) {
327     g_checksum_free (cs);
328     return TRUE;
329   }
330
331   /* It should always be prefixed with the SHA256, otherwise it likely means
332    * that basesrc is no longer using a SHA256 checksum on the URI, and this
333    * workaround will need to be fixed */
334   if (!g_str_has_prefix (rid, stream_id)) {
335     g_checksum_free (cs);
336     return FALSE;
337   }
338   g_checksum_free (cs);
339
340   /* we strip the IDS to the delimitor, and then compare */
341   rid = strchr (rid, '/');
342   cid = strchr (cid, '/');
343
344   if (rid == NULL || cid == NULL)
345     return FALSE;
346
347   if (g_strcmp0 (rid, cid) == 0)
348     return TRUE;
349
350   return FALSE;
351 }
352
353 static gboolean
354 compare_segments (GstValidateMediaDescriptor * ref,
355     gint i,
356     GstValidateMediaStreamNode * rstream,
357     GstValidateSegmentNode * rsegment, GstValidateSegmentNode * csegment)
358 {
359   if (rsegment->next_frame_id != csegment->next_frame_id) {
360     GST_VALIDATE_REPORT (ref, FILE_SEGMENT_INCORRECT,
361         "Segment %" GST_SEGMENT_FORMAT
362         " didn't come before the same frame ID, expected to come before %d, came before %d",
363         &rsegment->segment, rsegment->next_frame_id, csegment->next_frame_id);
364     return FALSE;
365   }
366 #define CHECK_SEGMENT_FIELD(fieldname, format) \
367   if (rsegment->segment.fieldname != csegment->segment.fieldname) { \
368     GST_ERROR ("Expected: %" GST_SEGMENT_FORMAT " got: %" GST_SEGMENT_FORMAT, \
369       &rsegment->segment, &csegment->segment); \
370     GST_VALIDATE_REPORT (ref, FILE_SEGMENT_INCORRECT, \
371         "Stream %s segment %d has " #fieldname \
372         " mismatch, Expected " format " got: " format , \
373         rstream->id, i, rsegment->segment.fieldname, \
374         csegment->segment.fieldname); \
375       return FALSE; \
376   }
377
378   CHECK_SEGMENT_FIELD (flags, "%d");
379   CHECK_SEGMENT_FIELD (rate, "%f");
380   CHECK_SEGMENT_FIELD (applied_rate, "%f");
381   CHECK_SEGMENT_FIELD (base, "%" G_GUINT64_FORMAT);
382   CHECK_SEGMENT_FIELD (offset, "%" G_GUINT64_FORMAT);
383   CHECK_SEGMENT_FIELD (start, "%" G_GUINT64_FORMAT);
384   CHECK_SEGMENT_FIELD (stop, "%" G_GUINT64_FORMAT);
385   CHECK_SEGMENT_FIELD (time, "%" G_GUINT64_FORMAT);
386   /* We do not compare segment position since it's a field for usage only within the element */
387   /* CHECK_SEGMENT_FIELD (position, "%" G_GUINT64_FORMAT); */
388   CHECK_SEGMENT_FIELD (duration, "%" G_GUINT64_FORMAT);
389
390   return TRUE;
391 }
392
393 static void
394 append_segment_diff (GString * diff, char diffsign, GList * segments)
395 {
396   GList *tmp;
397
398   for (tmp = segments; tmp; tmp = tmp->next) {
399     gchar *ssegment =
400         gst_info_strdup_printf ("%c %" GST_SEGMENT_FORMAT "\n", diffsign,
401         &((GstValidateSegmentNode *) tmp->data)->segment);
402     g_string_append (diff, ssegment);
403     g_free (ssegment);
404
405   }
406 }
407
408 static gboolean
409 compare_segment_list (GstValidateMediaDescriptor * ref,
410     GstValidateMediaStreamNode * rstream, GstValidateMediaStreamNode * cstream)
411 {
412   gint i;
413   GList *rsegments, *csegments;
414
415   /* Keep compatibility with media stream files that do not have segments */
416   if (rstream->segments
417       && g_list_length (rstream->segments) !=
418       g_list_length (cstream->segments)) {
419     GString *diff = g_string_new (NULL);
420
421     append_segment_diff (diff, '-', rstream->segments);
422     append_segment_diff (diff, '+', cstream->segments);
423     GST_VALIDATE_REPORT (ref, FILE_SEGMENT_INCORRECT,
424         "Stream reference has %i segments, compared one has %i segments\n%s",
425         g_list_length (rstream->segments), g_list_length (cstream->segments),
426         diff->str);
427     g_string_free (diff, TRUE);
428   }
429
430   for (i = 0, rsegments = rstream->segments, csegments = cstream->segments;
431       rsegments;
432       rsegments = rsegments->next, csegments = csegments->next, i++) {
433     GstValidateSegmentNode *rsegment, *csegment;
434
435     if (csegments == NULL) {
436       /* The list was checked to be of the same size */
437       g_assert_not_reached ();
438       return FALSE;
439     }
440
441     rsegment = rsegments->data;
442     csegment = csegments->data;
443
444     if (!compare_segments (ref, i, rstream, rsegment, csegment))
445       return FALSE;
446   }
447
448   return TRUE;
449 }
450
451 static gboolean
452 compare_frames (GstValidateMediaDescriptor * ref,
453     GstValidateMediaStreamNode *
454     rstream, GstValidateMediaFrameNode * rframe,
455     GstValidateMediaFrameNode * cframe)
456 {
457   if (rframe->id != cframe->id) {
458     GST_VALIDATE_REPORT (ref, FILE_FRAMES_INCORRECT,
459         "Stream frame %s ids mismatch: %" G_GUINT64_FORMAT " != %"
460         G_GUINT64_FORMAT, rstream->id, rframe->id, cframe->id);
461     return FALSE;
462   }
463 #define CHECK_FRAME_FIELD(fieldname, format, unknown_value) \
464   if (rframe->fieldname != unknown_value && rframe->fieldname != cframe->fieldname) { \
465     GST_VALIDATE_REPORT (ref, FILE_FRAMES_INCORRECT, \
466         "Stream %s frames with id %" G_GUINT64_FORMAT " have " #fieldname \
467         " mismatch. Expected " format ", got " format, rstream->id, \
468         rframe->id, rframe->fieldname, cframe->fieldname); \
469     return FALSE; \
470   }
471
472   CHECK_FRAME_FIELD (pts, "%" G_GUINT64_FORMAT, GST_VALIDATE_UNKNOWN_UINT64);
473   CHECK_FRAME_FIELD (dts, "%" G_GUINT64_FORMAT, GST_VALIDATE_UNKNOWN_UINT64);
474   CHECK_FRAME_FIELD (duration, "%" G_GUINT64_FORMAT,
475       GST_VALIDATE_UNKNOWN_UINT64);
476   CHECK_FRAME_FIELD (running_time, "%" G_GUINT64_FORMAT,
477       GST_VALIDATE_UNKNOWN_UINT64);
478   CHECK_FRAME_FIELD (is_keyframe, "%d", GST_VALIDATE_UNKNOWN_BOOL);
479
480   return TRUE;
481 }
482
483 static gboolean
484 compare_frames_list (GstValidateMediaDescriptor * ref,
485     GstValidateMediaStreamNode * rstream, GstValidateMediaStreamNode * cstream)
486 {
487   GList *rframes, *cframes;
488
489   if (g_list_length (rstream->frames) != g_list_length (cstream->frames)) {
490     GST_VALIDATE_REPORT (ref, FILE_FRAMES_INCORRECT,
491         "Stream reference has %i frames, compared one has %i frames",
492         g_list_length (rstream->frames), g_list_length (cstream->frames));
493     return FALSE;
494   }
495
496   for (rframes = rstream->frames, cframes = cstream->frames; rframes;
497       rframes = g_list_next (rframes), cframes = g_list_next (cframes)) {
498     GstValidateMediaFrameNode *rframe, *cframe;
499
500     if (cframes == NULL) {
501       /* The list was checked to be of the same size */
502       g_assert_not_reached ();
503       return FALSE;
504     }
505
506     rframe = rframes->data;
507     cframe = cframes->data;
508
509     if (!compare_frames (ref, rstream, rframe, cframe)) {
510       return FALSE;
511     }
512   }
513
514   return TRUE;
515 }
516
517 static GstCaps *
518 caps_cleanup_parsing_fields (GstCaps * caps)
519 {
520   gint i;
521   GstCaps *res = gst_caps_copy (caps);
522
523   for (i = 0; i < gst_caps_get_size (res); i++) {
524     GstStructure *s = gst_caps_get_structure (res, i);
525
526     gst_structure_remove_fields (s, "stream-format", "codec_data", "parsed",
527         "frames", "alignment", NULL);
528   }
529
530   return res;
531 }
532
533 /*  Return TRUE if found FALSE otherwise */
534 static gboolean
535 compare_streams (GstValidateMediaDescriptor * ref,
536     GstValidateMediaStreamNode * rstream, GstValidateMediaStreamNode * cstream)
537 {
538   GstCaps *rcaps, *ccaps;
539
540   if (!stream_id_is_equal (ref->priv->filenode->uri, rstream->id, cstream->id))
541     return FALSE;
542
543   rcaps = caps_cleanup_parsing_fields (rstream->caps);
544   ccaps = caps_cleanup_parsing_fields (cstream->caps);
545
546   if (!gst_caps_is_equal (rcaps, ccaps)) {
547     gchar *rcaps_str = gst_caps_to_string (rcaps),
548         *ccaps_str = gst_caps_to_string (ccaps);
549     GST_VALIDATE_REPORT (ref, FILE_PROFILE_INCORRECT,
550         "Reference descriptor for stream %s has caps: %s"
551         " but compared stream %s has caps: %s",
552         rstream->id, rcaps_str, cstream->id, ccaps_str);
553     g_free (rcaps_str);
554     g_free (ccaps_str);
555   }
556
557   gst_caps_unref (rcaps);
558   gst_caps_unref (ccaps);
559   /* We ignore the return value on purpose as this is not critical */
560   compare_tags (ref, rstream, cstream);
561
562   compare_segment_list (ref, rstream, cstream);
563   compare_frames_list (ref, rstream, cstream);
564
565   return TRUE;
566 }
567
568 gboolean
569 gst_validate_media_descriptors_compare (GstValidateMediaDescriptor * ref,
570     GstValidateMediaDescriptor * compared)
571 {
572   GList *rstream_list;
573   GstValidateMediaFileNode
574       * rfilenode = ref->priv->filenode, *cfilenode = compared->priv->filenode;
575
576   if (rfilenode->duration != cfilenode->duration) {
577     GST_VALIDATE_REPORT (ref, FILE_DURATION_INCORRECT,
578         "Duration %" GST_TIME_FORMAT " is different from the reference %"
579         GST_TIME_FORMAT, GST_TIME_ARGS (cfilenode->duration),
580         GST_TIME_ARGS (rfilenode->duration));
581   }
582
583   if (rfilenode->seekable != cfilenode->seekable) {
584     GST_VALIDATE_REPORT (ref, FILE_SEEKABLE_INCORRECT,
585         "File known as %s but is reported %s now",
586         rfilenode->seekable ? "seekable" : "not seekable",
587         cfilenode->seekable ? "seekable" : "not seekable");
588   }
589
590   if (g_list_length (rfilenode->streams) != g_list_length (cfilenode->streams)) {
591     GST_VALIDATE_REPORT (ref, FILE_PROFILE_INCORRECT,
592         "Reference descriptor has %i streams != compared which has %i streams",
593         g_list_length (rfilenode->streams), g_list_length (cfilenode->streams));
594
595     return FALSE;
596   }
597
598
599   for (rstream_list = rfilenode->streams; rstream_list;
600       rstream_list = rstream_list->next) {
601     GList *cstream_list;
602     gboolean sfound = FALSE;
603
604     for (cstream_list = cfilenode->streams; cstream_list;
605         cstream_list = cstream_list->next) {
606
607       sfound = compare_streams (ref, rstream_list->data, cstream_list->data);
608       if (sfound)
609         break;
610     }
611
612     if (!sfound) {
613       GST_VALIDATE_REPORT (ref, FILE_PROFILE_INCORRECT,
614           "Could not find stream %s in the compared descriptor",
615           ((GstValidateMediaStreamNode *) rstream_list->data)->id);
616     }
617   }
618
619   return TRUE;
620 }
621
622 gboolean
623 gst_validate_media_descriptor_detects_frames (GstValidateMediaDescriptor * self)
624 {
625   g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR (self), FALSE);
626   g_return_val_if_fail (self->priv->filenode, FALSE);
627
628   return self->priv->filenode->frame_detection;
629 }
630
631 /**
632  * gst_validate_media_descriptor_get_buffers: (skip):
633  */
634 gboolean
635 gst_validate_media_descriptor_get_buffers (GstValidateMediaDescriptor * self,
636     GstPad * pad, GCompareFunc compare_func, GList ** bufs)
637 {
638   GList *tmpstream, *tmpframe;
639   gboolean check = (pad == NULL), ret = FALSE;
640   GstCaps *pad_caps = gst_pad_get_current_caps (pad);
641
642   g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR (self), FALSE);
643   g_return_val_if_fail (self->priv->filenode, FALSE);
644
645   for (tmpstream = self->priv->filenode->streams;
646       tmpstream; tmpstream = tmpstream->next) {
647     GstValidateMediaStreamNode
648         * streamnode = (GstValidateMediaStreamNode *) tmpstream->data;
649
650     if (pad && streamnode->pad == pad)
651       check = TRUE;
652
653     if (!streamnode->pad && gst_caps_is_subset (pad_caps, streamnode->caps)) {
654       check = TRUE;
655     }
656
657     if (check) {
658       ret = TRUE;
659       for (tmpframe = streamnode->frames; tmpframe; tmpframe = tmpframe->next) {
660         if (compare_func)
661           *bufs =
662               g_list_insert_sorted (*bufs,
663               gst_buffer_ref ((
664                       (GstValidateMediaFrameNode
665                           *) tmpframe->data)->buf), compare_func);
666         else
667           *bufs =
668               g_list_prepend (*bufs,
669               gst_buffer_ref ((
670                       (GstValidateMediaFrameNode *) tmpframe->data)->buf));
671       }
672
673       if (pad != NULL)
674         goto done;
675     }
676   }
677
678
679 done:
680
681   if (compare_func == NULL)
682     *bufs = g_list_reverse (*bufs);
683
684   gst_caps_unref (pad_caps);
685   return ret;
686 }
687
688 gboolean
689 gst_validate_media_descriptor_has_frame_info (GstValidateMediaDescriptor * self)
690 {
691   GList *tmpstream;
692
693   for (tmpstream = self->priv->filenode->streams;
694       tmpstream; tmpstream = tmpstream->next) {
695     GstValidateMediaStreamNode
696         * streamnode = (GstValidateMediaStreamNode *) tmpstream->data;
697
698     if (g_list_length (streamnode->frames))
699       return TRUE;
700   }
701
702   return FALSE;
703 }
704
705 GstClockTime
706 gst_validate_media_descriptor_get_duration (GstValidateMediaDescriptor * self)
707 {
708   g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR (self), FALSE);
709   g_return_val_if_fail (self->priv->filenode, FALSE);
710
711   return self->priv->filenode->duration;
712 }
713
714 gboolean
715 gst_validate_media_descriptor_get_seekable (GstValidateMediaDescriptor * self)
716 {
717   g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR (self), FALSE);
718   g_return_val_if_fail (self->priv->filenode, FALSE);
719
720   return self->priv->filenode->seekable;
721 }
722
723 /**
724  * gst_validate_media_descriptor_get_pads: (skip):
725  */
726 GList *
727 gst_validate_media_descriptor_get_pads (GstValidateMediaDescriptor * self)
728 {
729   GList *ret = NULL, *tmp;
730
731   for (tmp = self->priv->filenode->streams; tmp; tmp = tmp->next) {
732     GstValidateMediaStreamNode
733         * snode = (GstValidateMediaStreamNode *) tmp->data;
734     ret = g_list_append (ret, gst_pad_new (snode->padname, GST_PAD_UNKNOWN));
735   }
736
737   return ret;
738 }
739
740
741 GstValidateMediaFileNode *
742 gst_validate_media_descriptor_get_file_node (GstValidateMediaDescriptor * self)
743 {
744   return self->priv->filenode;
745 }