validate: cleanup the use of GST_VALIDATE_API on Windows
[platform/upstream/gstreamer.git] / subprojects / gst-devtools / validate / gst / validate / media-descriptor-parser.c
1 /* Gstreamer
2  *
3  * Copyright (c) 2012, Collabora Ltd.
4  * Author: Thibault Saunier <thibault.saunier@collabora.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 #ifdef HAVE_CONFIG_H
22 #  include "config.h"
23 #endif
24
25 #include "media-descriptor-parser.h"
26 #include <string.h>
27
28 #include "gst-validate-internal.h"
29
30 struct _GstValidateMediaDescriptorParserPrivate
31 {
32   gchar *xmlpath;
33
34   gboolean in_stream;
35   gchar *xmlcontent;
36   GMarkupParseContext *parsecontext;
37 };
38
39 G_DEFINE_TYPE_WITH_PRIVATE (GstValidateMediaDescriptorParser,
40     gst_validate_media_descriptor_parser, GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR);
41
42 enum
43 {
44   PROP_0,
45   PROP_PATH,
46   N_PROPERTIES
47 };
48
49 /* Private methods  and callbacks */
50 static gint
51 compare_frames (GstValidateMediaFrameNode * frm,
52     GstValidateMediaFrameNode * frm1)
53 {
54   if (frm->id < frm1->id)
55     return -1;
56
57   else if (frm->id == frm1->id)
58     return 0;
59
60   return 1;
61 }
62
63 static void
64     deserialize_filenode
65     (GstValidateMediaFileNode *
66     filenode, const gchar ** names, const gchar ** values)
67 {
68   gint i;
69   for (i = 0; names[i] != NULL; i++) {
70     if (g_strcmp0 (names[i], "uri") == 0)
71       filenode->uri = g_strdup (values[i]);
72     else if (g_strcmp0 (names[i], "id") == 0)
73       filenode->id = g_ascii_strtoull (values[i], NULL, 0);
74     else if (g_strcmp0 (names[i], "frame-detection") == 0)
75       filenode->frame_detection = g_ascii_strtoull (values[i], NULL, 0);
76     else if (g_strcmp0 (names[i], "duration") == 0)
77       filenode->duration = g_ascii_strtoull (values[i], NULL, 0);
78     else if (g_strcmp0 (names[i], "seekable") == 0)
79       filenode->seekable = (g_strcmp0 (values[i], "true") == 0);
80   }
81 }
82
83 static GstValidateMediaStreamNode *
84 deserialize_streamnode (const gchar ** names, const gchar ** values)
85 {
86   gint i;
87   GstValidateMediaStreamNode
88       * streamnode = g_slice_new0 (GstValidateMediaStreamNode);
89
90   for (i = 0; names[i] != NULL; i++) {
91     if (g_strcmp0 (names[i], "id") == 0)
92       streamnode->id = g_strdup (values[i]);
93     else if (g_strcmp0 (names[i], "caps") == 0)
94       streamnode->caps = gst_caps_from_string (values[i]);
95     else if (g_strcmp0 (names[i], "padname") == 0)
96       streamnode->padname = g_strdup (values[i]);
97   }
98
99
100   return streamnode;
101 }
102
103 static GstValidateSegmentNode *
104 deserialize_segmentnode (const gchar ** names, const gchar ** values)
105 {
106   gint i;
107   GstValidateSegmentNode *node = g_slice_new0 (GstValidateSegmentNode);
108
109   for (i = 0; names[i] != NULL; i++) {
110     if (!g_strcmp0 (names[i], "next-frame-id"))
111       node->next_frame_id = g_ascii_strtoull (values[i], NULL, 0);
112     else if (!g_strcmp0 (names[i], "flags"))
113       node->segment.flags = g_ascii_strtoull (values[i], NULL, 0);
114     else if (!g_strcmp0 (names[i], "rate"))
115       node->segment.rate = g_ascii_strtod (values[i], NULL);
116     else if (!g_strcmp0 (names[i], "applied-rate"))
117       node->segment.applied_rate = g_ascii_strtod (values[i], NULL);
118     else if (!g_strcmp0 (names[i], "format"))
119       node->segment.format = g_ascii_strtoull (values[i], NULL, 0);
120     else if (!g_strcmp0 (names[i], "base"))
121       node->segment.base = g_ascii_strtoull (values[i], NULL, 0);
122     else if (!g_strcmp0 (names[i], "offset"))
123       node->segment.offset = g_ascii_strtoull (values[i], NULL, 0);
124     else if (!g_strcmp0 (names[i], "start"))
125       node->segment.start = g_ascii_strtoull (values[i], NULL, 0);
126     else if (!g_strcmp0 (names[i], "stop"))
127       node->segment.stop = g_ascii_strtoull (values[i], NULL, 0);
128     else if (!g_strcmp0 (names[i], "time"))
129       node->segment.time = g_ascii_strtoull (values[i], NULL, 0);
130     else if (!g_strcmp0 (names[i], "position"))
131       node->segment.position = g_ascii_strtoull (values[i], NULL, 0);
132     else if (!g_strcmp0 (names[i], "duration"))
133       node->segment.duration = g_ascii_strtoull (values[i], NULL, 0);
134   }
135
136   return node;
137 }
138
139 static GstValidateMediaTagsNode *
140 deserialize_tagsnode (const gchar ** names, const gchar ** values)
141 {
142   GstValidateMediaTagsNode *tagsnode = g_slice_new0 (GstValidateMediaTagsNode);
143
144   return tagsnode;
145 }
146
147 static GstValidateMediaTagNode *
148 deserialize_tagnode (const gchar ** names, const gchar ** values)
149 {
150   gint i;
151   GstValidateMediaTagNode *tagnode = g_slice_new0 (GstValidateMediaTagNode);
152
153   for (i = 0; names[i] != NULL; i++) {
154     if (g_strcmp0 (names[i], "content") == 0)
155       tagnode->taglist = gst_tag_list_new_from_string (values[i]);
156   }
157
158   return tagnode;
159 }
160
161 static GstValidateMediaFrameNode *
162 deserialize_framenode (const gchar ** names, const gchar ** values)
163 {
164   gint i;
165
166   GstValidateMediaFrameNode *framenode =
167       g_slice_new0 (GstValidateMediaFrameNode);
168
169 /* *INDENT-OFF* */
170 #define IF_SET_UINT64_FIELD(name,fieldname) \
171     if (g_strcmp0 (names[i], name) == 0) { \
172       if (g_strcmp0 (values[i], "unknown") == 0)  \
173         framenode->fieldname = GST_VALIDATE_UNKNOWN_UINT64; \
174       else\
175         framenode->fieldname = g_ascii_strtoull (values[i], NULL, 0); \
176     }
177
178   for (i = 0; names[i] != NULL; i++) {
179     IF_SET_UINT64_FIELD ("id", id)
180     else IF_SET_UINT64_FIELD ("offset", offset)
181     else IF_SET_UINT64_FIELD ("offset-end", offset_end)
182     else IF_SET_UINT64_FIELD ("duration", duration)
183     else IF_SET_UINT64_FIELD ("pts", pts)
184     else IF_SET_UINT64_FIELD ("dts", dts)
185     else IF_SET_UINT64_FIELD ("running-time", running_time)
186     else if (g_strcmp0 (names[i], "checksum") == 0)
187       framenode->checksum = g_strdup (values[i]);
188     else if (g_strcmp0 (names[i], "is-keyframe") == 0) {
189       if (!g_ascii_strcasecmp (values[i], "true"))
190         framenode->is_keyframe = TRUE;
191       else if (!g_ascii_strcasecmp (values[i], "unknown"))
192         framenode->is_keyframe = GST_VALIDATE_UNKNOWN_BOOL;
193       else
194         framenode->is_keyframe = FALSE;
195     }
196   }
197 /* *INDENT-ON* */
198
199   framenode->buf = gst_buffer_new_wrapped (framenode->checksum,
200       strlen (framenode->checksum) + 1);
201
202   GST_BUFFER_OFFSET (framenode->buf) = framenode->offset;
203   GST_BUFFER_OFFSET_END (framenode->buf) = framenode->offset_end;
204   GST_BUFFER_DURATION (framenode->buf) = framenode->duration;
205   GST_BUFFER_PTS (framenode->buf) = framenode->pts;
206   GST_BUFFER_DTS (framenode->buf) = framenode->dts;
207
208   if (framenode->is_keyframe) {
209     GST_BUFFER_FLAG_UNSET (framenode->buf, GST_BUFFER_FLAG_DELTA_UNIT);
210   } else {
211     GST_BUFFER_FLAG_SET (framenode->buf, GST_BUFFER_FLAG_DELTA_UNIT);
212   }
213
214   return framenode;
215 }
216
217
218 static void
219 on_end_element_cb (GMarkupParseContext * context,
220     const gchar * element_name, gpointer user_data, GError ** error)
221 {
222   GstValidateMediaDescriptorParserPrivate *priv =
223       GST_VALIDATE_MEDIA_DESCRIPTOR_PARSER (user_data)->priv;
224
225   if (g_strcmp0 (element_name, "stream") == 0) {
226     priv->in_stream = FALSE;
227   }
228 }
229
230 static void
231 on_start_element_cb (GMarkupParseContext * context,
232     const gchar * element_name, const gchar ** attribute_names,
233     const gchar ** attribute_values, gpointer user_data, GError ** error)
234 {
235   GstValidateMediaFileNode
236       * filenode =
237       gst_validate_media_descriptor_get_file_node (GST_VALIDATE_MEDIA_DESCRIPTOR
238       (user_data));
239
240   GstValidateMediaDescriptorParserPrivate *priv =
241       GST_VALIDATE_MEDIA_DESCRIPTOR_PARSER (user_data)->priv;
242
243   if (g_strcmp0 (element_name, "file") == 0) {
244     deserialize_filenode (filenode, attribute_names, attribute_values);
245   } else if (g_strcmp0 (element_name, "stream") == 0) {
246     GstValidateMediaStreamNode
247         * node = deserialize_streamnode (attribute_names, attribute_values);
248     priv->in_stream = TRUE;
249     filenode->streams = g_list_prepend (filenode->streams, node);
250   } else if (g_strcmp0 (element_name, "segment") == 0) {
251     GstValidateMediaStreamNode *streamnode = filenode->streams->data;
252     GstValidateSegmentNode *node =
253         deserialize_segmentnode (attribute_names, attribute_values);
254
255     streamnode->segments = g_list_append (streamnode->segments, node);
256
257   } else if (g_strcmp0 (element_name, "frame") == 0) {
258     GstValidateMediaStreamNode *streamnode = filenode->streams->data;
259
260     streamnode->cframe = streamnode->frames =
261         g_list_insert_sorted (streamnode->frames,
262         deserialize_framenode (attribute_names, attribute_values),
263         (GCompareFunc) compare_frames);
264   } else if (g_strcmp0 (element_name, "tags") == 0) {
265     if (priv->in_stream) {
266       GstValidateMediaStreamNode *snode = (GstValidateMediaStreamNode *)
267           filenode->streams->data;
268
269       snode->tags = deserialize_tagsnode (attribute_names, attribute_values);
270     } else {
271       filenode->tags = deserialize_tagsnode (attribute_names, attribute_values);
272     }
273   } else if (g_strcmp0 (element_name, "tag") == 0) {
274     GstValidateMediaTagsNode *tagsnode;
275
276     if (priv->in_stream) {
277       GstValidateMediaStreamNode *snode = (GstValidateMediaStreamNode *)
278           filenode->streams->data;
279       tagsnode = snode->tags;
280     } else {
281       tagsnode = filenode->tags;
282     }
283
284     tagsnode->tags = g_list_prepend (tagsnode->tags,
285         deserialize_tagnode (attribute_names, attribute_values));
286   }
287 }
288
289 static void
290 on_error_cb (GMarkupParseContext * context, GError * error, gpointer user_data)
291 {
292   GST_ERROR ("Error parsing file: %s", error->message);
293 }
294
295 static const GMarkupParser content_parser = {
296   on_start_element_cb,
297   on_end_element_cb,
298   NULL,
299   NULL,
300   &on_error_cb
301 };
302
303 static gboolean
304 _set_content (GstValidateMediaDescriptorParser * parser,
305     const gchar * content, gsize size, GError ** error)
306 {
307   GError *err = NULL;
308   GstValidateMediaDescriptorParserPrivate *priv = parser->priv;
309
310   priv->parsecontext = g_markup_parse_context_new (&content_parser,
311       G_MARKUP_TREAT_CDATA_AS_TEXT, parser, NULL);
312
313   if (g_markup_parse_context_parse (priv->parsecontext, content,
314           size, &err) == FALSE)
315     goto failed;
316
317   return TRUE;
318
319 failed:
320   g_propagate_error (error, err);
321   return FALSE;
322 }
323
324 static gboolean
325 set_xml_path (GstValidateMediaDescriptorParser * parser, const gchar * path,
326     GError ** error)
327 {
328   gsize xmlsize;
329   gchar *content;
330   GError *err = NULL;
331   GstValidateMediaDescriptorParserPrivate *priv = parser->priv;
332   gboolean result;
333
334   if (!g_file_get_contents (path, &content, &xmlsize, &err))
335     goto failed;
336
337   priv->xmlpath = g_strdup (path);
338
339   result = _set_content (parser, content, xmlsize, error);
340   g_free (content);
341   return result;
342
343 failed:
344   g_propagate_error (error, err);
345   return FALSE;
346 }
347
348 /* GObject standard vmethods */
349 static void
350 dispose (GstValidateMediaDescriptorParser * parser)
351 {
352   G_OBJECT_CLASS (gst_validate_media_descriptor_parser_parent_class)->dispose
353       (G_OBJECT (parser));
354 }
355
356 static void
357 finalize (GstValidateMediaDescriptorParser * parser)
358 {
359   GstValidateMediaDescriptorParserPrivate *priv;
360
361   priv = parser->priv;
362
363   g_free (priv->xmlpath);
364   g_free (priv->xmlcontent);
365
366   if (priv->parsecontext != NULL)
367     g_markup_parse_context_free (priv->parsecontext);
368
369   G_OBJECT_CLASS (gst_validate_media_descriptor_parser_parent_class)->finalize
370       (G_OBJECT (parser));
371 }
372
373
374 static void
375 get_property (GObject * gobject, guint prop_id, GValue * value,
376     GParamSpec * pspec)
377 {
378   switch (prop_id) {
379     default:
380       g_assert_not_reached ();
381   }
382
383 }
384
385 static void
386 set_property (GObject * gobject, guint prop_id, const GValue * value,
387     GParamSpec * pspec)
388 {
389   switch (prop_id) {
390     default:
391       g_assert_not_reached ();
392   }
393 }
394
395 static void
396 gst_validate_media_descriptor_parser_init (GstValidateMediaDescriptorParser *
397     parser)
398 {
399   GstValidateMediaDescriptorParserPrivate *priv;
400
401   parser->priv = priv =
402       gst_validate_media_descriptor_parser_get_instance_private (parser);
403
404   priv->xmlpath = NULL;
405 }
406
407 static void
408     gst_validate_media_descriptor_parser_class_init
409     (GstValidateMediaDescriptorParserClass * self_class)
410 {
411   GObjectClass *object_class = G_OBJECT_CLASS (self_class);
412
413   object_class->dispose = (void (*)(GObject * object)) dispose;
414   object_class->finalize = (void (*)(GObject * object)) finalize;
415   object_class->get_property = get_property;
416   object_class->set_property = set_property;
417 }
418
419 /* Public methods */
420 GstValidateMediaDescriptorParser *
421 gst_validate_media_descriptor_parser_new (GstValidateRunner * runner,
422     const gchar * xmlpath, GError ** error)
423 {
424   GstValidateMediaDescriptorParser *parser;
425
426   parser =
427       g_object_new (GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_PARSER,
428       "validate-runner", runner, NULL);
429
430   if (set_xml_path (parser, xmlpath, error) == FALSE) {
431     g_object_unref (parser);
432
433     return NULL;
434   }
435
436
437   return parser;
438 }
439
440 GstValidateMediaDescriptorParser *
441 gst_validate_media_descriptor_parser_new_from_xml (GstValidateRunner * runner,
442     const gchar * xml, GError ** error)
443 {
444   GstValidateMediaDescriptorParser *parser;
445
446   parser =
447       g_object_new (GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_PARSER,
448       "validate-runner", runner, NULL);
449   if (_set_content (parser, xml, strlen (xml) * sizeof (gchar), error) == FALSE) {
450     g_object_unref (parser);
451
452     return NULL;
453   }
454
455
456   return parser;
457 }
458
459 gchar *gst_validate_media_descriptor_parser_get_xml_path
460     (GstValidateMediaDescriptorParser * parser)
461 {
462   g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_PARSER (parser), NULL);
463
464   return g_strdup (parser->priv->xmlpath);
465 }
466
467 gboolean
468     gst_validate_media_descriptor_parser_add_stream
469     (GstValidateMediaDescriptorParser * parser, GstPad * pad) {
470   GList *tmp;
471   gboolean ret = FALSE;
472   GstCaps *caps;
473
474   g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_PARSER (parser),
475       FALSE);
476   g_return_val_if_fail (gst_validate_media_descriptor_get_file_node (
477           (GstValidateMediaDescriptor *) parser), FALSE);
478
479   caps = gst_pad_query_caps (pad, NULL);
480   for (tmp =
481       gst_validate_media_descriptor_get_file_node ((GstValidateMediaDescriptor
482               *) parser)->streams; tmp; tmp = tmp->next) {
483     GstValidateMediaStreamNode *streamnode = (GstValidateMediaStreamNode *)
484         tmp->data;
485
486     if (streamnode->pad == NULL && gst_caps_is_equal (streamnode->caps, caps)) {
487       ret = TRUE;
488       streamnode->pad = gst_object_ref (pad);
489
490       goto done;
491     }
492   }
493
494 done:
495   if (caps != NULL)
496     gst_caps_unref (caps);
497
498   return ret;
499 }
500
501 gboolean
502     gst_validate_media_descriptor_parser_all_stream_found
503     (GstValidateMediaDescriptorParser * parser) {
504   GList *tmp;
505
506   g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_PARSER (parser),
507       FALSE);
508   g_return_val_if_fail (gst_validate_media_descriptor_get_file_node (
509           (GstValidateMediaDescriptor *) parser), FALSE);
510
511   for (tmp =
512       gst_validate_media_descriptor_get_file_node ((GstValidateMediaDescriptor
513               *) parser)->streams; tmp; tmp = tmp->next) {
514     GstValidateMediaStreamNode *streamnode = (GstValidateMediaStreamNode *)
515         tmp->data;
516
517     if (streamnode->pad == NULL)
518       return FALSE;
519
520   }
521
522   return TRUE;
523 }
524
525 gboolean
526     gst_validate_media_descriptor_parser_add_taglist
527     (GstValidateMediaDescriptorParser * parser, GstTagList * taglist) {
528   GList *tmptag;
529   GstValidateMediaTagsNode *tagsnode;
530
531   g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_PARSER (parser),
532       FALSE);
533   g_return_val_if_fail (gst_validate_media_descriptor_get_file_node (
534           (GstValidateMediaDescriptor *) parser), FALSE);
535   g_return_val_if_fail (GST_IS_STRUCTURE (taglist), FALSE);
536
537   tagsnode =
538       gst_validate_media_descriptor_get_file_node ((GstValidateMediaDescriptor
539           *) parser)->tags;
540
541   for (tmptag = tagsnode->tags; tmptag; tmptag = tmptag->next) {
542     if (gst_validate_tag_node_compare ((GstValidateMediaTagNode *)
543             tmptag->data, taglist)) {
544       GST_DEBUG ("Adding tag %" GST_PTR_FORMAT, taglist);
545       return TRUE;
546     }
547   }
548
549   return FALSE;
550 }
551
552 gboolean
553     gst_validate_media_descriptor_parser_all_tags_found
554     (GstValidateMediaDescriptorParser * parser) {
555   GList *tmptag;
556   GstValidateMediaTagsNode *tagsnode;
557   gboolean ret = TRUE;
558
559   g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_PARSER (parser),
560       FALSE);
561   g_return_val_if_fail (gst_validate_media_descriptor_get_file_node (
562           (GstValidateMediaDescriptor *) parser), FALSE);
563
564   tagsnode =
565       gst_validate_media_descriptor_get_file_node ((GstValidateMediaDescriptor
566           *) parser)->tags;
567   for (tmptag = tagsnode->tags; tmptag; tmptag = tmptag->next) {
568     gchar *tag = NULL;
569
570     tag = gst_tag_list_to_string (((GstValidateMediaTagNode *)
571             tmptag->data)->taglist);
572     if (((GstValidateMediaTagNode *)
573             tmptag->data)->found == FALSE) {
574
575       if (((GstValidateMediaTagNode *)
576               tmptag->data)->taglist != NULL) {
577         GST_DEBUG ("Tag not found %s", tag);
578       } else {
579         GST_DEBUG ("Tag not properly deserialized");
580       }
581
582       ret = FALSE;
583     }
584
585     GST_DEBUG ("Tag properly found %s", tag);
586     g_free (tag);
587   }
588
589   return ret;
590 }