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.
22 #include <gst/validate/validate.h>
23 #include "media-descriptor-writer.h"
26 struct _GstValidateMediaDescriptorWriterPrivate
33 GstValidateMediaDescriptorWriterFlags flags;
36 G_DEFINE_TYPE_WITH_PRIVATE (GstValidateMediaDescriptorWriter,
37 gst_validate_media_descriptor_writer, GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR);
39 #define STR_APPEND(arg, nb_white) \
40 g_string_append_printf (res, "%*s%s%s", (nb_white), " ", (arg), "\n"); \
42 #define STR_APPEND0(arg) STR_APPEND((arg), 0)
43 #define STR_APPEND1(arg) STR_APPEND((arg), 2)
44 #define STR_APPEND2(arg) STR_APPEND((arg), 4)
45 #define STR_APPEND3(arg) STR_APPEND((arg), 6)
46 #define STR_APPEND4(arg) STR_APPEND((arg), 8)
48 #define FLAG_IS_SET(writer,flag) ((writer->priv->flags & (flag)) == (flag))
58 finalize (GstValidateMediaDescriptorWriter * writer)
60 if (writer->priv->raw_caps)
61 gst_caps_unref (writer->priv->raw_caps);
63 if (writer->priv->parsers)
64 gst_plugin_feature_list_free (writer->priv->parsers);
66 G_OBJECT_CLASS (gst_validate_media_descriptor_writer_parent_class)->finalize
71 get_property (GObject * gobject, guint prop_id, GValue * value,
76 g_assert_not_reached ();
82 set_property (GObject * gobject, guint prop_id, const GValue * value,
87 g_assert_not_reached ();
92 gst_validate_media_descriptor_writer_init (GstValidateMediaDescriptorWriter *
95 GstValidateMediaDescriptorWriterPrivate *priv;
99 gst_validate_media_descriptor_writer_get_instance_private (writer);
101 writer->priv->parsers =
102 gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_PARSER,
107 gst_validate_media_descriptor_writer_class_init
108 (GstValidateMediaDescriptorWriterClass * self_class)
110 GObjectClass *object_class = G_OBJECT_CLASS (self_class);
112 object_class->finalize = (void (*)(GObject * object)) finalize;
113 object_class->get_property = get_property;
114 object_class->set_property = set_property;
117 /* Private methods */
119 serialize_filenode (GstValidateMediaDescriptorWriter * writer)
122 gchar *tmpstr, *caps_str;
124 GstValidateMediaTagsNode *tagsnode;
125 GstValidateMediaFileNode
126 * filenode = ((GstValidateMediaDescriptor *) writer)->filenode;
128 tmpstr = g_markup_printf_escaped ("<file duration=\"%" G_GUINT64_FORMAT
129 "\" frame-detection=\"%i\" skip-parsers=\"%i\" uri=\"%s\" seekable=\"%s\">\n",
130 filenode->duration, filenode->frame_detection, filenode->skip_parsers,
131 filenode->uri, filenode->seekable ? "true" : "false");
134 caps_str = gst_caps_to_string (filenode->caps);
136 caps_str = g_strdup ("");
138 res = g_string_new (tmpstr);
140 tmpstr = g_markup_printf_escaped (" <streams caps=\"%s\">\n", caps_str);
141 g_string_append (res, tmpstr);
144 for (tmp = filenode->streams; tmp; tmp = tmp->next) {
146 GstValidateMediaStreamNode
147 * snode = ((GstValidateMediaStreamNode *) tmp->data);
150 STR_APPEND2 (snode->str_open);
152 /* Segment are always prepended, let's bring them back to the right order */
153 STR_APPEND3 ("<segments>");
154 for (tmp2 = snode->segments; tmp2; tmp2 = tmp2->next)
155 STR_APPEND4 (((GstValidateSegmentNode *) tmp2->data)->str_open);
156 STR_APPEND3 ("</segments>");
158 for (tmp2 = snode->frames; tmp2; tmp2 = tmp2->next) {
159 STR_APPEND3 (((GstValidateMediaFrameNode *) tmp2->data)->str_open);
162 tagsnode = snode->tags;
164 STR_APPEND3 (tagsnode->str_open);
165 for (tmp3 = tagsnode->tags; tmp3; tmp3 = tmp3->next) {
166 STR_APPEND4 (((GstValidateMediaTagNode *) tmp3->data)->str_open);
168 STR_APPEND3 (tagsnode->str_close);
171 STR_APPEND2 (snode->str_close);
173 STR_APPEND1 ("</streams>");
175 tagsnode = filenode->tags;
177 STR_APPEND1 (tagsnode->str_open);
178 for (tmp2 = tagsnode->tags; tmp2; tmp2 = tmp2->next) {
179 STR_APPEND2 (((GstValidateMediaTagNode *)
180 tmp2->data)->str_open);
182 STR_APPEND1 (tagsnode->str_close);
185 g_string_append (res, filenode->str_close);
187 return g_string_free (res, FALSE);
190 /* Should be called with GST_VALIDATE_MEDIA_DESCRIPTOR_LOCK */
192 GstValidateMediaStreamNode
193 * gst_validate_media_descriptor_find_stream_node_by_pad
194 (GstValidateMediaDescriptor * md, GstPad * pad)
198 for (tmp = md->filenode->streams; tmp; tmp = tmp->next) {
199 GstValidateMediaStreamNode
200 * streamnode = (GstValidateMediaStreamNode *) tmp->data;
202 if (streamnode->pad == pad) {
211 GstValidateMediaDescriptorWriter *
212 gst_validate_media_descriptor_writer_new (GstValidateRunner * runner,
213 const gchar * uri, GstClockTime duration, gboolean seekable)
215 GstValidateMediaDescriptorWriter *writer;
216 GstValidateMediaFileNode *fnode;
219 g_object_new (GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_WRITER,
220 "validate-runner", runner, NULL);
222 fnode = ((GstValidateMediaDescriptor *) writer)->filenode;
223 fnode->uri = g_strdup (uri);
224 fnode->duration = duration;
225 fnode->seekable = seekable;
226 fnode->str_open = NULL;
228 fnode->str_close = g_markup_printf_escaped ("</file>");
234 strip_caps_to_avoid_parsers (GstValidateMediaDescriptorWriter * writer,
238 GstStructure *structure, *new_struct;
241 /* If parsers are wanted, use exactly the caps reported by the discoverer (which also
243 if (!FLAG_IS_SET (writer,
244 GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER_FLAGS_NO_PARSER))
245 return gst_caps_copy (caps);
247 /* Otherwise use the simplest version of those caps (with the names only),
248 * meaning that decodebin will never plug any parser */
249 stripped = gst_caps_new_empty ();
250 for (i = 0; i < gst_caps_get_size (caps); i++) {
251 structure = gst_caps_get_structure (caps, i);
252 new_struct = gst_structure_new_empty (gst_structure_get_name (structure));
254 gst_caps_append_structure (stripped, new_struct);
261 gst_validate_media_descriptor_writer_add_stream
262 (GstValidateMediaDescriptorWriter * writer, GstDiscovererStreamInfo * info)
265 gboolean ret = FALSE;
267 gchar *capsstr = NULL;
268 GstValidateMediaStreamNode *snode = NULL;
270 g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_WRITER (writer),
272 g_return_val_if_fail (((GstValidateMediaDescriptor *) writer)->filenode,
275 snode = g_slice_new0 (GstValidateMediaStreamNode);
276 snode->frames = NULL;
277 snode->cframe = NULL;
279 snode->id = g_strdup (gst_discoverer_stream_info_get_stream_id (info));
280 if (snode->id == NULL) {
281 caps = gst_discoverer_stream_info_get_caps (info);
282 capsstr = gst_caps_to_string (caps);
284 g_slice_free (GstValidateMediaStreamNode, snode);
285 GST_VALIDATE_REPORT (writer, FILE_NO_STREAM_ID,
286 "Stream with caps: %s has no stream ID", capsstr);
287 gst_caps_unref (caps);
293 caps = gst_discoverer_stream_info_get_caps (info);
294 snode->caps = caps; /* Pass ownership */
295 capsstr = gst_caps_to_string (caps);
296 if (GST_IS_DISCOVERER_AUDIO_INFO (info)) {
298 } else if (GST_IS_DISCOVERER_VIDEO_INFO (info)) {
299 if (gst_discoverer_video_info_is_image (GST_DISCOVERER_VIDEO_INFO (info)))
303 } else if (GST_IS_DISCOVERER_SUBTITLE_INFO (info)) {
310 g_markup_printf_escaped
311 ("<stream type=\"%s\" caps=\"%s\" id=\"%s\">", stype, capsstr, snode->id);
313 snode->str_close = g_markup_printf_escaped ("</stream>");
315 ((GstValidateMediaDescriptor *) writer)->filenode->streams =
316 g_list_prepend (((GstValidateMediaDescriptor *) writer)->
317 filenode->streams, snode);
319 if (gst_discoverer_stream_info_get_tags (info)) {
320 gst_validate_media_descriptor_writer_add_tags (writer, snode->id,
321 gst_discoverer_stream_info_get_tags (info));
324 if (writer->priv->raw_caps == NULL)
325 writer->priv->raw_caps = strip_caps_to_avoid_parsers (writer, caps);
327 writer->priv->raw_caps = gst_caps_merge (writer->priv->raw_caps,
328 strip_caps_to_avoid_parsers (writer, caps));
335 static GstPadProbeReturn
336 _uridecodebin_probe (GstPad * pad, GstPadProbeInfo * info,
337 GstValidateMediaDescriptorWriter * writer)
339 if (GST_PAD_PROBE_INFO_TYPE (info) & GST_PAD_PROBE_TYPE_BUFFER) {
340 gst_validate_media_descriptor_writer_add_frame (writer, pad, info->data);
341 } else if (GST_PAD_PROBE_INFO_TYPE (info) &
342 GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM) {
343 GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info);
344 switch (GST_EVENT_TYPE (event)) {
345 case GST_EVENT_SEGMENT:{
346 const GstSegment *segment;
347 GstValidateMediaStreamNode *streamnode;
350 gst_validate_media_descriptor_find_stream_node_by_pad (
351 (GstValidateMediaDescriptor *)
354 GstValidateSegmentNode *segment_node =
355 g_slice_new0 (GstValidateSegmentNode);
357 gst_event_parse_segment (event, &segment);
358 gst_segment_copy_into (segment, &segment_node->segment);
359 segment_node->next_frame_id = g_list_length (streamnode->frames);
361 segment_node->str_open =
362 g_markup_printf_escaped ("<segment next-frame-id=\"%d\""
363 " flags=\"%d\" rate=\"%f\" applied-rate=\"%f\""
364 " format=\"%d\" base=\"%" G_GUINT64_FORMAT "\" offset=\"%"
365 G_GUINT64_FORMAT "\" start=\"%" G_GUINT64_FORMAT "\""
366 " stop=\"%" G_GUINT64_FORMAT "\" time=\"%" G_GUINT64_FORMAT
367 "\" position=\"%" G_GUINT64_FORMAT "\" duration=\"%"
368 G_GUINT64_FORMAT "\"/>", segment_node->next_frame_id,
369 segment->flags, segment->rate, segment->applied_rate,
370 segment->format, segment->base, segment->offset, segment->start,
371 segment->stop, segment->time, segment->position,
374 streamnode->segments =
375 g_list_prepend (streamnode->segments, segment_node);
383 g_assert_not_reached ();
386 return GST_PAD_PROBE_OK;
390 _find_stream_id (GstPad * pad, GstEvent ** event,
391 GstValidateMediaDescriptorWriter * writer)
393 if (GST_EVENT_TYPE (*event) == GST_EVENT_STREAM_START) {
395 GstValidateMediaStreamNode *snode = NULL;
396 const gchar *stream_id;
398 gst_event_parse_stream_start (*event, &stream_id);
399 for (tmp = ((GstValidateMediaDescriptor *) writer)->filenode->streams; tmp;
401 GstValidateMediaStreamNode *subnode =
402 (GstValidateMediaStreamNode *) tmp->data;
403 if (g_strcmp0 (subnode->id, stream_id) == 0) {
410 if (!snode || snode->pad) {
411 GST_VALIDATE_REPORT (writer, FILE_NO_STREAM_ID,
412 "Got pad %s:%s where Discoverer found no stream ID",
413 GST_DEBUG_PAD_NAME (pad));
418 snode->pad = gst_object_ref (pad);
426 static inline GstElement *
427 _get_parser (GstValidateMediaDescriptorWriter * writer, GstPad * pad)
429 GList *parsers1, *parsers;
430 GstElement *parser = NULL;
431 GstElementFactory *parserfact = NULL;
434 if (FLAG_IS_SET (writer,
435 GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER_FLAGS_NO_PARSER))
438 format = gst_pad_get_current_caps (pad);
440 GST_DEBUG ("Getting list of parsers for format %" GST_PTR_FORMAT, format);
442 gst_element_factory_list_filter (writer->priv->parsers, format,
445 gst_element_factory_list_filter (parsers1, format, GST_PAD_SINK, FALSE);
446 gst_plugin_feature_list_free (parsers1);
448 if (G_UNLIKELY (parsers == NULL)) {
449 GST_DEBUG ("Couldn't find any compatible parsers");
453 /* Just pick the first one */
454 parserfact = parsers->data;
456 parser = gst_element_factory_create (parserfact, NULL);
458 gst_plugin_feature_list_free (parsers);
462 gst_caps_unref (format);
468 pad_added_cb (GstElement * decodebin, GstPad * pad,
469 GstValidateMediaDescriptorWriter * writer)
471 GstValidateMediaStreamNode *snode = NULL;
472 GstPad *sinkpad, *srcpad;
474 /* Try to plug a parser so we have as much info as possible
475 * about the encoded stream. */
476 GstElement *parser = _get_parser (writer, pad);
477 GstElement *fakesink = gst_element_factory_make ("fakesink", NULL);
480 sinkpad = gst_element_get_static_pad (parser, "sink");
481 gst_bin_add (GST_BIN (writer->priv->pipeline), parser);
482 gst_element_sync_state_with_parent (parser);
483 gst_pad_link (pad, sinkpad);
484 gst_object_unref (sinkpad);
486 srcpad = gst_element_get_static_pad (parser, "src");
488 srcpad = gst_object_ref (pad);
491 sinkpad = gst_element_get_static_pad (fakesink, "sink");
492 gst_bin_add (GST_BIN (writer->priv->pipeline), fakesink);
493 gst_element_sync_state_with_parent (fakesink);
494 gst_pad_link (srcpad, sinkpad);
495 gst_object_unref (sinkpad);
496 gst_pad_sticky_events_foreach (pad,
497 (GstPadStickyEventsForeachFunction) _find_stream_id, writer);
501 gst_validate_media_descriptor_find_stream_node_by_pad (
502 (GstValidateMediaDescriptor *)
505 gst_object_unref (snode->pad);
506 snode->pad = gst_object_ref (srcpad);
510 gst_pad_add_probe (srcpad,
511 GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
512 (GstPadProbeCallback) _uridecodebin_probe, writer, NULL);
514 gst_object_unref (srcpad);
518 bus_callback (GstBus * bus, GstMessage * message,
519 GstValidateMediaDescriptorWriter * writer)
521 GMainLoop *loop = writer->priv->loop;
523 switch (GST_MESSAGE_TYPE (message)) {
524 case GST_MESSAGE_ERROR:
526 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (writer->priv->pipeline),
527 GST_DEBUG_GRAPH_SHOW_ALL, "gst-validate-media-check.error");
528 g_main_loop_quit (loop);
531 case GST_MESSAGE_EOS:
532 GST_INFO ("Got EOS!");
533 g_main_loop_quit (loop);
535 case GST_MESSAGE_STATE_CHANGED:
536 if (GST_MESSAGE_SRC (message) == GST_OBJECT (writer->priv->pipeline)) {
537 GstState oldstate, newstate, pending;
539 gst_message_parse_state_changed (message, &oldstate, &newstate,
542 GST_DEBUG ("State changed (old: %s, new: %s, pending: %s)",
543 gst_element_state_get_name (oldstate),
544 gst_element_state_get_name (newstate),
545 gst_element_state_get_name (pending));
547 if (newstate == GST_STATE_PLAYING) {
548 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (writer->priv->pipeline),
549 GST_DEBUG_GRAPH_SHOW_ALL,
550 "gst-validate-media-descriptor-writer.playing");
555 case GST_MESSAGE_BUFFERING:{
558 gst_message_parse_buffering (message, &percent);
560 /* no state management needed for live pipelines */
561 if (percent == 100) {
562 gst_element_set_state (writer->priv->pipeline, GST_STATE_PLAYING);
564 gst_element_set_state (writer->priv->pipeline, GST_STATE_PAUSED);
576 _run_frame_analysis (GstValidateMediaDescriptorWriter * writer,
577 GstValidateRunner * runner, const gchar * uri)
581 GstStateChangeReturn sret;
582 GstValidateMonitor *monitor;
583 GstValidateMediaFileNode *filenode;
585 GstElement *uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
587 writer->priv->pipeline = gst_pipeline_new ("frame-analysis");
590 gst_validate_monitor_factory_create (GST_OBJECT_CAST (writer->
591 priv->pipeline), runner, NULL);
592 gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor));
594 g_object_set (uridecodebin, "uri", uri, "caps", writer->priv->raw_caps, NULL);
595 g_signal_connect (uridecodebin, "pad-added", G_CALLBACK (pad_added_cb),
597 gst_bin_add (GST_BIN (writer->priv->pipeline), uridecodebin);
599 writer->priv->loop = g_main_loop_new (NULL, FALSE);
600 bus = gst_element_get_bus (writer->priv->pipeline);
601 gst_bus_add_signal_watch (bus);
602 g_signal_connect (bus, "message", (GCallback) bus_callback, writer);
603 sret = gst_element_set_state (writer->priv->pipeline, GST_STATE_PLAYING);
605 case GST_STATE_CHANGE_FAILURE:
606 /* ignore, we should get an error message posted on the bus */
607 gst_validate_printf (NULL, "Pipeline failed to go to PLAYING state\n");
613 g_main_loop_run (writer->priv->loop);
615 filenode = ((GstValidateMediaDescriptor *) writer)->filenode;
616 /* Segment are always prepended, let's reorder them. */
617 for (tmp = filenode->streams; tmp; tmp = tmp->next) {
618 GstValidateMediaStreamNode
619 * snode = ((GstValidateMediaStreamNode *) tmp->data);
620 snode->segments = g_list_reverse (snode->segments);
623 gst_element_set_state (writer->priv->pipeline, GST_STATE_NULL);
624 gst_object_unref (writer->priv->pipeline);
625 writer->priv->pipeline = NULL;
626 g_main_loop_unref (writer->priv->loop);
627 writer->priv->loop = NULL;
628 gst_bus_remove_signal_watch (bus);
629 gst_object_unref (bus);
630 gst_validate_reporter_purge_reports (GST_VALIDATE_REPORTER (monitor));
631 g_object_unref (monitor);
636 GstValidateMediaDescriptorWriter *
637 gst_validate_media_descriptor_writer_new_discover (GstValidateRunner * runner,
638 const gchar * uri, GstValidateMediaDescriptorWriterFlags flags,
641 GList *tmp, *streams = NULL;
642 GstDiscovererInfo *info = NULL;
643 GstDiscoverer *discoverer;
644 GstDiscovererStreamInfo *streaminfo = NULL;
645 GstValidateMediaDescriptorWriter *writer = NULL;
646 GstValidateMediaDescriptor *media_descriptor;
647 const GstTagList *tags;
648 GError *error = NULL;
650 discoverer = gst_discoverer_new (GST_SECOND * 60, &error);
652 if (discoverer == NULL) {
653 GST_ERROR ("Could not create discoverer");
654 g_propagate_error (err, error);
658 info = gst_discoverer_discover_uri (discoverer, uri, &error);
661 GST_ERROR ("Could not discover URI: %s (error: %s)", uri, error->message);
662 g_propagate_error (err, error);
665 GstDiscovererResult result = gst_discoverer_info_get_result (info);
667 case GST_DISCOVERER_OK:
669 case GST_DISCOVERER_URI_INVALID:
670 GST_ERROR ("URI is not valid");
672 case GST_DISCOVERER_TIMEOUT:
673 GST_ERROR ("Analyzing URI timed out\n");
675 case GST_DISCOVERER_BUSY:
676 GST_ERROR ("Discoverer was busy\n");
678 case GST_DISCOVERER_MISSING_PLUGINS:
681 const gchar **installer_details =
682 gst_discoverer_info_get_missing_elements_installer_details (info);
683 GST_ERROR ("Missing plugins");
684 while (installer_details[i]) {
685 GST_ERROR ("(%s)", installer_details[i]);
696 streaminfo = gst_discoverer_info_get_stream_info (info);
700 gst_validate_media_descriptor_writer_new (runner,
701 gst_discoverer_info_get_uri (info),
702 gst_discoverer_info_get_duration (info),
703 gst_discoverer_info_get_seekable (info));
705 writer->priv->flags = flags;
706 if (FLAG_IS_SET (writer,
707 GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER_FLAGS_HANDLE_GLOGS))
708 gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (writer));
710 tags = gst_discoverer_info_get_tags (info);
712 gst_validate_media_descriptor_writer_add_taglist (writer, tags);
714 if (GST_IS_DISCOVERER_CONTAINER_INFO (streaminfo)) {
715 ((GstValidateMediaDescriptor *) writer)->filenode->caps =
716 gst_discoverer_stream_info_get_caps (GST_DISCOVERER_STREAM_INFO
719 streams = gst_discoverer_info_get_stream_list (info);
720 for (tmp = streams; tmp; tmp = tmp->next) {
721 GstDiscovererStreamInfo *streaminfo =
722 (GstDiscovererStreamInfo *) tmp->data;
723 gst_validate_media_descriptor_writer_add_stream (writer, streaminfo);
726 if (!GST_IS_DISCOVERER_AUDIO_INFO (info)
727 && !GST_IS_DISCOVERER_AUDIO_INFO (info)
728 && gst_discoverer_stream_info_get_next (streaminfo)) {
729 ((GstValidateMediaDescriptor *) writer)->filenode->caps =
730 gst_discoverer_stream_info_get_caps (streaminfo);
731 streaminfo = gst_discoverer_stream_info_get_next (streaminfo);
734 gst_validate_media_descriptor_writer_add_stream (writer, streaminfo);
735 } while ((streaminfo = gst_discoverer_stream_info_get_next (streaminfo)));
738 GST_VALIDATE_REPORT (writer, FILE_NO_STREAM_INFO,
739 "Discoverer info, does not contain the stream info");
743 media_descriptor = (GstValidateMediaDescriptor *) writer;
744 if (streams == NULL && media_descriptor->filenode->caps)
745 writer->priv->raw_caps = gst_caps_copy (media_descriptor->filenode->caps);
747 gst_discoverer_stream_info_list_free (streams);
750 if (FLAG_IS_SET (writer, GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER_FLAGS_FULL))
751 _run_frame_analysis (writer, runner, uri);
755 gst_discoverer_info_unref (info);
757 gst_discoverer_stream_info_unref (streaminfo);
758 g_object_unref (discoverer);
763 gst_validate_media_descriptor_writer_add_tags (GstValidateMediaDescriptorWriter
764 * writer, const gchar * stream_id, const GstTagList * taglist)
766 GstValidateMediaTagsNode *tagsnode;
767 GstValidateMediaTagNode *tagnode;
770 gchar *str_str = NULL;
771 GstValidateMediaStreamNode *snode = NULL;
773 g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_WRITER (writer),
775 g_return_val_if_fail (((GstValidateMediaDescriptor *) writer)->filenode,
778 for (tmp = ((GstValidateMediaDescriptor *) writer)->filenode->streams; tmp;
780 GstValidateMediaStreamNode *subnode =
781 (GstValidateMediaStreamNode *) tmp->data;
782 if (g_strcmp0 (subnode->id, stream_id) == 0) {
790 GST_WARNING ("Could not find stream with id: %s", stream_id);
795 if (snode->tags == NULL) {
796 tagsnode = g_slice_new0 (GstValidateMediaTagsNode);
797 tagsnode->str_open = g_markup_printf_escaped ("<tags>");
798 tagsnode->str_close = g_markup_printf_escaped ("</tags>");
799 snode->tags = tagsnode;
801 tagsnode = snode->tags;
803 for (tmptag = tagsnode->tags; tmptag; tmptag = tmptag->next) {
804 if (gst_validate_tag_node_compare ((GstValidateMediaTagNode *)
805 tmptag->data, taglist)) {
806 GST_DEBUG ("Tag already in... not adding again %" GST_PTR_FORMAT,
813 tagnode = g_slice_new0 (GstValidateMediaTagNode);
814 tagnode->taglist = gst_tag_list_copy (taglist);
815 str_str = gst_tag_list_to_string (tagnode->taglist);
817 g_markup_printf_escaped ("<tag content=\"%s\"/>", str_str);
818 tagsnode->tags = g_list_prepend (tagsnode->tags, tagnode);
826 gst_validate_media_descriptor_writer_add_pad (GstValidateMediaDescriptorWriter *
827 writer, GstPad * pad)
830 gboolean ret = FALSE;
832 gchar *capsstr = NULL, *padname = NULL;
833 GstValidateMediaStreamNode *snode = NULL;
835 g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_WRITER (writer),
837 g_return_val_if_fail (((GstValidateMediaDescriptor *) writer)->filenode,
840 caps = gst_pad_get_current_caps (pad);
841 for (tmp = ((GstValidateMediaDescriptor *) writer)->filenode->streams; tmp;
843 GstValidateMediaStreamNode
844 * streamnode = (GstValidateMediaStreamNode *) tmp->data;
846 if (streamnode->pad == pad) {
851 snode = g_slice_new0 (GstValidateMediaStreamNode);
852 snode->frames = NULL;
853 snode->cframe = NULL;
855 snode->caps = gst_caps_ref (caps);
856 snode->pad = gst_object_ref (pad);
858 capsstr = gst_caps_to_string (caps);
859 padname = gst_pad_get_name (pad);
861 g_markup_printf_escaped
862 ("<stream padname=\"%s\" caps=\"%s\" id=\"%i\">", padname, capsstr, 0);
864 snode->str_close = g_markup_printf_escaped ("</stream>");
866 ((GstValidateMediaDescriptor *) writer)->filenode->streams =
867 g_list_prepend (((GstValidateMediaDescriptor *) writer)->
868 filenode->streams, snode);
872 gst_caps_unref (caps);
880 gst_validate_media_descriptor_writer_add_taglist
881 (GstValidateMediaDescriptorWriter * writer, const GstTagList * taglist) {
882 gchar *str_str = NULL;
883 GstValidateMediaTagsNode *tagsnode;
884 GstValidateMediaTagNode *tagnode;
887 g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_WRITER (writer),
889 g_return_val_if_fail (((GstValidateMediaDescriptor *) writer)->filenode,
892 if (((GstValidateMediaDescriptor *) writer)->filenode->tags == NULL) {
893 tagsnode = g_slice_new0 (GstValidateMediaTagsNode);
894 tagsnode->str_open = g_markup_printf_escaped ("<tags>");
895 tagsnode->str_close = g_markup_printf_escaped ("</tags>");
896 ((GstValidateMediaDescriptor *) writer)->filenode->tags = tagsnode;
898 tagsnode = ((GstValidateMediaDescriptor *) writer)->filenode->tags;
899 for (tmptag = tagsnode->tags; tmptag; tmptag = tmptag->next) {
900 if (gst_validate_tag_node_compare ((GstValidateMediaTagNode *)
901 tmptag->data, taglist)) {
902 GST_DEBUG ("Tag already in... not adding again %" GST_PTR_FORMAT,
909 tagnode = g_slice_new0 (GstValidateMediaTagNode);
910 tagnode->taglist = gst_tag_list_copy (taglist);
911 str_str = gst_tag_list_to_string (tagnode->taglist);
913 g_markup_printf_escaped ("<tag content=\"%s\"/>", str_str);
914 tagsnode->tags = g_list_prepend (tagsnode->tags, tagnode);
922 gst_validate_media_descriptor_writer_add_frame (GstValidateMediaDescriptorWriter
923 * writer, GstPad * pad, GstBuffer * buf)
925 GstValidateMediaStreamNode *streamnode;
930 GstValidateMediaFrameNode *fnode;
931 GstValidateMediaFileNode *filenode;
933 g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_WRITER (writer),
935 g_return_val_if_fail (((GstValidateMediaDescriptor *) writer)->filenode,
938 filenode = ((GstValidateMediaDescriptor *) writer)->filenode;
939 filenode->frame_detection = TRUE;
940 filenode->skip_parsers =
942 GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER_FLAGS_NO_PARSER);
943 GST_VALIDATE_MEDIA_DESCRIPTOR_LOCK (writer);
945 gst_validate_media_descriptor_find_stream_node_by_pad (
946 (GstValidateMediaDescriptor *)
948 if (streamnode == NULL) {
949 GST_VALIDATE_MEDIA_DESCRIPTOR_UNLOCK (writer);
953 id = g_list_length (streamnode->frames);
954 fnode = g_slice_new0 (GstValidateMediaFrameNode);
956 g_assert (gst_buffer_map (buf, &map, GST_MAP_READ));
957 checksum = g_compute_checksum_for_data (G_CHECKSUM_MD5,
958 (const guchar *) map.data, map.size);
959 gst_buffer_unmap (buf, &map);
962 fnode->offset = GST_BUFFER_OFFSET (buf);
963 fnode->offset_end = GST_BUFFER_OFFSET_END (buf);
964 fnode->duration = GST_BUFFER_DURATION (buf);
965 fnode->pts = GST_BUFFER_PTS (buf);
966 fnode->dts = GST_BUFFER_DTS (buf);
968 g_assert (streamnode->segments);
969 segment = &((GstValidateSegmentNode *) streamnode->segments->data)->segment;
970 fnode->running_time =
971 gst_segment_to_running_time (segment, GST_FORMAT_TIME,
972 GST_BUFFER_PTS (buf));
974 (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT) == FALSE);
977 g_markup_printf_escaped (" <frame duration=\"%" G_GUINT64_FORMAT
978 "\" id=\"%i\" is-keyframe=\"%s\" offset=\"%" G_GUINT64_FORMAT
979 "\" offset-end=\"%" G_GUINT64_FORMAT "\" pts=\"%" G_GUINT64_FORMAT
980 "\" dts=\"%" G_GUINT64_FORMAT "\" running-time=\"%" G_GUINT64_FORMAT
981 "\" checksum=\"%s\"/>",
982 fnode->duration, id, fnode->is_keyframe ? "true" : "false",
983 fnode->offset, fnode->offset_end, fnode->pts, fnode->dts,
984 fnode->running_time, checksum);
986 fnode->str_close = NULL;
988 streamnode->frames = g_list_append (streamnode->frames, fnode);
991 GST_VALIDATE_MEDIA_DESCRIPTOR_UNLOCK (writer);
997 gst_validate_media_descriptor_writer_write (GstValidateMediaDescriptorWriter *
998 writer, const gchar * filename)
1000 gboolean ret = FALSE;
1003 g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_WRITER (writer),
1005 g_return_val_if_fail (((GstValidateMediaDescriptor *) writer)->filenode,
1008 serialized = serialize_filenode (writer);
1011 if (g_file_set_contents (filename, serialized, -1, NULL) == TRUE)
1015 g_free (serialized);
1021 gst_validate_media_descriptor_writer_serialize (GstValidateMediaDescriptorWriter
1024 g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_WRITER (writer),
1026 g_return_val_if_fail (((GstValidateMediaDescriptor *) writer)->filenode,
1029 return serialize_filenode (writer);