3 * Copyright (c) 2012, Collabora Ltd.
4 * Author: Thibault Saunier <thibault.saunier@collabora.com>
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.
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.
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.
25 #include "media-descriptor-parser.h"
28 #include "gst-validate-internal.h"
30 struct _GstValidateMediaDescriptorParserPrivate
36 GMarkupParseContext *parsecontext;
39 G_DEFINE_TYPE_WITH_PRIVATE (GstValidateMediaDescriptorParser,
40 gst_validate_media_descriptor_parser, GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR);
49 /* Private methods and callbacks */
51 compare_frames (GstValidateMediaFrameNode * frm,
52 GstValidateMediaFrameNode * frm1)
54 if (frm->id < frm1->id)
57 else if (frm->id == frm1->id)
65 (GstValidateMediaFileNode *
66 filenode, const gchar ** names, const gchar ** values)
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);
83 static GstValidateMediaStreamNode *
84 deserialize_streamnode (const gchar ** names, const gchar ** values)
87 GstValidateMediaStreamNode
88 * streamnode = g_slice_new0 (GstValidateMediaStreamNode);
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]);
103 static GstValidateSegmentNode *
104 deserialize_segmentnode (const gchar ** names, const gchar ** values)
107 GstValidateSegmentNode *node = g_slice_new0 (GstValidateSegmentNode);
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);
139 static GstValidateMediaTagsNode *
140 deserialize_tagsnode (const gchar ** names, const gchar ** values)
142 GstValidateMediaTagsNode *tagsnode = g_slice_new0 (GstValidateMediaTagsNode);
147 static GstValidateMediaTagNode *
148 deserialize_tagnode (const gchar ** names, const gchar ** values)
151 GstValidateMediaTagNode *tagnode = g_slice_new0 (GstValidateMediaTagNode);
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]);
161 static GstValidateMediaFrameNode *
162 deserialize_framenode (const gchar ** names, const gchar ** values)
166 GstValidateMediaFrameNode *framenode =
167 g_slice_new0 (GstValidateMediaFrameNode);
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; \
175 framenode->fieldname = g_ascii_strtoull (values[i], NULL, 0); \
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;
194 framenode->is_keyframe = FALSE;
199 framenode->buf = gst_buffer_new_wrapped (framenode->checksum,
200 strlen (framenode->checksum) + 1);
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;
208 if (framenode->is_keyframe) {
209 GST_BUFFER_FLAG_UNSET (framenode->buf, GST_BUFFER_FLAG_DELTA_UNIT);
211 GST_BUFFER_FLAG_SET (framenode->buf, GST_BUFFER_FLAG_DELTA_UNIT);
219 on_end_element_cb (GMarkupParseContext * context,
220 const gchar * element_name, gpointer user_data, GError ** error)
222 GstValidateMediaDescriptorParserPrivate *priv =
223 GST_VALIDATE_MEDIA_DESCRIPTOR_PARSER (user_data)->priv;
225 if (g_strcmp0 (element_name, "stream") == 0) {
226 priv->in_stream = FALSE;
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)
235 GstValidateMediaFileNode
237 gst_validate_media_descriptor_get_file_node (GST_VALIDATE_MEDIA_DESCRIPTOR
240 GstValidateMediaDescriptorParserPrivate *priv =
241 GST_VALIDATE_MEDIA_DESCRIPTOR_PARSER (user_data)->priv;
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);
255 streamnode->segments = g_list_append (streamnode->segments, node);
257 } else if (g_strcmp0 (element_name, "frame") == 0) {
258 GstValidateMediaStreamNode *streamnode = filenode->streams->data;
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;
269 snode->tags = deserialize_tagsnode (attribute_names, attribute_values);
271 filenode->tags = deserialize_tagsnode (attribute_names, attribute_values);
273 } else if (g_strcmp0 (element_name, "tag") == 0) {
274 GstValidateMediaTagsNode *tagsnode;
276 if (priv->in_stream) {
277 GstValidateMediaStreamNode *snode = (GstValidateMediaStreamNode *)
278 filenode->streams->data;
279 tagsnode = snode->tags;
281 tagsnode = filenode->tags;
284 tagsnode->tags = g_list_prepend (tagsnode->tags,
285 deserialize_tagnode (attribute_names, attribute_values));
290 on_error_cb (GMarkupParseContext * context, GError * error, gpointer user_data)
292 GST_ERROR ("Error parsing file: %s", error->message);
295 static const GMarkupParser content_parser = {
304 _set_content (GstValidateMediaDescriptorParser * parser,
305 const gchar * content, gsize size, GError ** error)
308 GstValidateMediaDescriptorParserPrivate *priv = parser->priv;
310 priv->parsecontext = g_markup_parse_context_new (&content_parser,
311 G_MARKUP_TREAT_CDATA_AS_TEXT, parser, NULL);
313 if (g_markup_parse_context_parse (priv->parsecontext, content,
314 size, &err) == FALSE)
320 g_propagate_error (error, err);
325 set_xml_path (GstValidateMediaDescriptorParser * parser, const gchar * path,
331 GstValidateMediaDescriptorParserPrivate *priv = parser->priv;
334 if (!g_file_get_contents (path, &content, &xmlsize, &err))
337 priv->xmlpath = g_strdup (path);
339 result = _set_content (parser, content, xmlsize, error);
344 g_propagate_error (error, err);
348 /* GObject standard vmethods */
350 dispose (GstValidateMediaDescriptorParser * parser)
352 G_OBJECT_CLASS (gst_validate_media_descriptor_parser_parent_class)->dispose
357 finalize (GstValidateMediaDescriptorParser * parser)
359 GstValidateMediaDescriptorParserPrivate *priv;
363 g_free (priv->xmlpath);
364 g_free (priv->xmlcontent);
366 if (priv->parsecontext != NULL)
367 g_markup_parse_context_free (priv->parsecontext);
369 G_OBJECT_CLASS (gst_validate_media_descriptor_parser_parent_class)->finalize
375 get_property (GObject * gobject, guint prop_id, GValue * value,
380 g_assert_not_reached ();
386 set_property (GObject * gobject, guint prop_id, const GValue * value,
391 g_assert_not_reached ();
396 gst_validate_media_descriptor_parser_init (GstValidateMediaDescriptorParser *
399 GstValidateMediaDescriptorParserPrivate *priv;
401 parser->priv = priv =
402 gst_validate_media_descriptor_parser_get_instance_private (parser);
404 priv->xmlpath = NULL;
408 gst_validate_media_descriptor_parser_class_init
409 (GstValidateMediaDescriptorParserClass * self_class)
411 GObjectClass *object_class = G_OBJECT_CLASS (self_class);
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;
420 GstValidateMediaDescriptorParser *
421 gst_validate_media_descriptor_parser_new (GstValidateRunner * runner,
422 const gchar * xmlpath, GError ** error)
424 GstValidateMediaDescriptorParser *parser;
427 g_object_new (GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_PARSER,
428 "validate-runner", runner, NULL);
430 if (set_xml_path (parser, xmlpath, error) == FALSE) {
431 g_object_unref (parser);
440 GstValidateMediaDescriptorParser *
441 gst_validate_media_descriptor_parser_new_from_xml (GstValidateRunner * runner,
442 const gchar * xml, GError ** error)
444 GstValidateMediaDescriptorParser *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);
459 gchar *gst_validate_media_descriptor_parser_get_xml_path
460 (GstValidateMediaDescriptorParser * parser)
462 g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_PARSER (parser), NULL);
464 return g_strdup (parser->priv->xmlpath);
468 gst_validate_media_descriptor_parser_add_stream
469 (GstValidateMediaDescriptorParser * parser, GstPad * pad) {
471 gboolean ret = FALSE;
474 g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_PARSER (parser),
476 g_return_val_if_fail (gst_validate_media_descriptor_get_file_node (
477 (GstValidateMediaDescriptor *) parser), FALSE);
479 caps = gst_pad_query_caps (pad, NULL);
481 gst_validate_media_descriptor_get_file_node ((GstValidateMediaDescriptor
482 *) parser)->streams; tmp; tmp = tmp->next) {
483 GstValidateMediaStreamNode *streamnode = (GstValidateMediaStreamNode *)
486 if (streamnode->pad == NULL && gst_caps_is_equal (streamnode->caps, caps)) {
488 streamnode->pad = gst_object_ref (pad);
496 gst_caps_unref (caps);
502 gst_validate_media_descriptor_parser_all_stream_found
503 (GstValidateMediaDescriptorParser * parser) {
506 g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_PARSER (parser),
508 g_return_val_if_fail (gst_validate_media_descriptor_get_file_node (
509 (GstValidateMediaDescriptor *) parser), FALSE);
512 gst_validate_media_descriptor_get_file_node ((GstValidateMediaDescriptor
513 *) parser)->streams; tmp; tmp = tmp->next) {
514 GstValidateMediaStreamNode *streamnode = (GstValidateMediaStreamNode *)
517 if (streamnode->pad == NULL)
526 gst_validate_media_descriptor_parser_add_taglist
527 (GstValidateMediaDescriptorParser * parser, GstTagList * taglist) {
529 GstValidateMediaTagsNode *tagsnode;
531 g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_PARSER (parser),
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);
538 gst_validate_media_descriptor_get_file_node ((GstValidateMediaDescriptor
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);
553 gst_validate_media_descriptor_parser_all_tags_found
554 (GstValidateMediaDescriptorParser * parser) {
556 GstValidateMediaTagsNode *tagsnode;
559 g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_PARSER (parser),
561 g_return_val_if_fail (gst_validate_media_descriptor_get_file_node (
562 (GstValidateMediaDescriptor *) parser), FALSE);
565 gst_validate_media_descriptor_get_file_node ((GstValidateMediaDescriptor
567 for (tmptag = tagsnode->tags; tmptag; tmptag = tmptag->next) {
570 tag = gst_tag_list_to_string (((GstValidateMediaTagNode *)
571 tmptag->data)->taglist);
572 if (((GstValidateMediaTagNode *)
573 tmptag->data)->found == FALSE) {
575 if (((GstValidateMediaTagNode *)
576 tmptag->data)->taglist != NULL) {
577 GST_DEBUG ("Tag not found %s", tag);
579 GST_DEBUG ("Tag not properly deserialized");
585 GST_DEBUG ("Tag properly found %s", tag);