mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-28 04:31:06 +00:00
validate: Add a media-descriptor parser and writer
This commit is contained in:
parent
f6c6043317
commit
d280d0dbc9
11 changed files with 1830 additions and 52 deletions
|
@ -11,6 +11,9 @@ libgstvalidate_@GST_API_VERSION@_la_SOURCES = \
|
|||
gst-validate-override.c \
|
||||
gst-validate-utils.c \
|
||||
gst-validate-override-registry.c \
|
||||
media-descriptor.c \
|
||||
media-descriptor-writer.c \
|
||||
media-descriptor-parser.c \
|
||||
gst-validate-media-info.c \
|
||||
validate.c
|
||||
|
||||
|
@ -31,6 +34,9 @@ libgstvalidate_@GST_API_VERSION@include_HEADERS = \
|
|||
gst-validate-runner.h \
|
||||
gst-validate-scenario.h \
|
||||
gst-validate-utils.h \
|
||||
media-descriptor.h \
|
||||
media-descriptor-writer.h \
|
||||
media-descriptor-parser.h \
|
||||
gst-validate-media-info.h
|
||||
|
||||
|
||||
|
|
|
@ -202,6 +202,8 @@ gst_validate_report_load_issues (void)
|
|||
_("an error occured while starting playback of the test file"), NULL);
|
||||
REGISTER_VALIDATE_ISSUE (CRITICAL, FILE_PLAYBACK_ERROR,
|
||||
_("an error during playback of the file"), NULL);
|
||||
REGISTER_VALIDATE_ISSUE (WARNING, FILE_NO_STREAM_ID,
|
||||
_("the discoverer found a stream that had no stream ID"), NULL);
|
||||
|
||||
REGISTER_VALIDATE_ISSUE (CRITICAL, ALLOCATION_FAILURE,
|
||||
_("a memory allocation failed during Validate run"), NULL);
|
||||
|
|
|
@ -103,6 +103,7 @@ typedef enum {
|
|||
#define GST_VALIDATE_ISSUE_ID_FILE_CHECK_FAILURE (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 7)
|
||||
#define GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_START_FAILURE (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 8)
|
||||
#define GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_ERROR (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 9)
|
||||
#define GST_VALIDATE_ISSUE_ID_FILE_NO_STREAM_ID (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 10)
|
||||
|
||||
#define GST_VALIDATE_ISSUE_ID_ALLOCATION_FAILURE (((GstValidateIssueId) GST_VALIDATE_AREA_RUN_ERROR) << GST_VALIDATE_ISSUE_ID_SHIFT | 1)
|
||||
#define GST_VALIDATE_ISSUE_ID_MISSING_PLUGIN (((GstValidateIssueId) GST_VALIDATE_AREA_RUN_ERROR) << GST_VALIDATE_ISSUE_ID_SHIFT | 2)
|
||||
|
|
|
@ -69,8 +69,9 @@ _free_priv (GstValidateReporterPrivate * priv)
|
|||
static GstValidateReporterPrivate *
|
||||
gst_validate_reporter_get_priv (GstValidateReporter * reporter)
|
||||
{
|
||||
GstValidateReporterPrivate *priv =
|
||||
g_object_get_data (G_OBJECT (reporter), REPORTER_PRIVATE);
|
||||
GstValidateReporterPrivate *priv;
|
||||
|
||||
priv = g_object_get_data (G_OBJECT (reporter), REPORTER_PRIVATE);
|
||||
|
||||
if (priv == NULL) {
|
||||
priv = g_slice_new0 (GstValidateReporterPrivate);
|
||||
|
|
591
validate/gst/validate/media-descriptor-parser.c
Normal file
591
validate/gst/validate/media-descriptor-parser.c
Normal file
|
@ -0,0 +1,591 @@
|
|||
/**
|
||||
* Gstreamer
|
||||
*
|
||||
* Copyright (c) 2012, Collabora Ltd.
|
||||
* Author: Thibault Saunier <thibault.saunier@collabora.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "media-descriptor-parser.h"
|
||||
|
||||
G_DEFINE_TYPE (GstMediaDescriptorParser, gst_media_descriptor_parser,
|
||||
GST_TYPE_MEDIA_DESCRIPTOR);
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_PATH,
|
||||
N_PROPERTIES
|
||||
};
|
||||
|
||||
struct _GstMediaDescriptorParserPrivate
|
||||
{
|
||||
gchar *xmlpath;
|
||||
|
||||
gboolean in_stream;
|
||||
gchar *xmlcontent;
|
||||
GMarkupParseContext *parsecontext;
|
||||
};
|
||||
|
||||
/* Private methods and callbacks */
|
||||
static gint
|
||||
compare_frames (FrameNode * frm, FrameNode * frm1)
|
||||
{
|
||||
if (frm->id < frm1->id)
|
||||
return -1;
|
||||
|
||||
else if (frm->id == frm1->id)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
deserialize_filenode (FileNode *filenode,
|
||||
const gchar ** names, const gchar ** values)
|
||||
{
|
||||
gint i;
|
||||
for (i = 0; names[i] != NULL; i++) {
|
||||
if (g_strcmp0 (names[i], "uri") == 0)
|
||||
filenode->uri = g_strdup (values[i]);
|
||||
else if (g_strcmp0 (names[i], "id") == 0)
|
||||
filenode->id = g_ascii_strtoull (values[i], NULL, 0);
|
||||
else if (g_strcmp0 (names[i], "frame-detection") == 0)
|
||||
filenode->frame_detection = g_ascii_strtoull (values[i], NULL, 0);
|
||||
else if (g_strcmp0 (names[i], "duration") == 0)
|
||||
filenode->duration = g_ascii_strtoull (values[i], NULL, 0);
|
||||
else if (g_strcmp0 (names[i], "seekable") == 0)
|
||||
filenode->seekable = (gboolean) g_strcmp0 (values[i], "false");
|
||||
}
|
||||
}
|
||||
|
||||
static StreamNode *
|
||||
deserialize_streamnode (const gchar ** names, const gchar ** values)
|
||||
{
|
||||
gint i;
|
||||
StreamNode *streamnode = g_slice_new0 (StreamNode);
|
||||
|
||||
for (i = 0; names[i] != NULL; i++) {
|
||||
if (g_strcmp0 (names[i], "id") == 0)
|
||||
streamnode->id = g_strdup (values[i]);
|
||||
else if (g_strcmp0 (names[i], "caps") == 0)
|
||||
streamnode->caps = gst_caps_from_string (values[i]);
|
||||
else if (g_strcmp0 (names[i], "padname") == 0)
|
||||
streamnode->padname = g_strdup (values[i]);
|
||||
}
|
||||
|
||||
|
||||
return streamnode;
|
||||
}
|
||||
|
||||
static TagsNode *
|
||||
deserialize_tagsnode (const gchar ** names, const gchar ** values)
|
||||
{
|
||||
TagsNode *tagsnode = g_slice_new0 (TagsNode);
|
||||
|
||||
return tagsnode;
|
||||
}
|
||||
|
||||
static TagNode *
|
||||
deserialize_tagnode (const gchar ** names, const gchar ** values)
|
||||
{
|
||||
gint i;
|
||||
TagNode *tagnode = g_slice_new0 (TagNode);
|
||||
|
||||
for (i = 0; names[i] != NULL; i++) {
|
||||
if (g_strcmp0 (names[i], "content") == 0)
|
||||
tagnode->taglist = gst_tag_list_new_from_string (values[i]);
|
||||
}
|
||||
|
||||
return tagnode;
|
||||
}
|
||||
|
||||
static FrameNode *
|
||||
deserialize_framenode (const gchar ** names, const gchar ** values)
|
||||
{
|
||||
gint i;
|
||||
|
||||
FrameNode *framenode = g_slice_new0 (FrameNode);
|
||||
|
||||
for (i = 0; names[i] != NULL; i++) {
|
||||
if (g_strcmp0 (names[i], "id") == 0)
|
||||
framenode->id = g_ascii_strtoull (values[i], NULL, 0);
|
||||
else if (g_strcmp0 (names[i], "offset") == 0)
|
||||
framenode->offset = g_ascii_strtoull (values[i], NULL, 0);
|
||||
else if (g_strcmp0 (names[i], "offset-end") == 0)
|
||||
framenode->offset_end = g_ascii_strtoull (values[i], NULL, 0);
|
||||
else if (g_strcmp0 (names[i], "duration") == 0)
|
||||
framenode->duration = g_ascii_strtoull (values[i], NULL, 0);
|
||||
else if (g_strcmp0 (names[i], "pts") == 0)
|
||||
framenode->pts = g_ascii_strtoull (values[i], NULL, 0);
|
||||
else if (g_strcmp0 (names[i], "dts") == 0)
|
||||
framenode->dts = g_ascii_strtoull (values[i], NULL, 0);
|
||||
else if (g_strcmp0 (names[i], "is-keyframe") == 0)
|
||||
framenode->is_keyframe = g_ascii_strtoull (values[i], NULL, 0);
|
||||
}
|
||||
|
||||
framenode->buf = gst_buffer_new ();
|
||||
|
||||
GST_BUFFER_OFFSET (framenode->buf) = framenode->offset;
|
||||
GST_BUFFER_OFFSET_END (framenode->buf) = framenode->offset_end;
|
||||
GST_BUFFER_DURATION (framenode->buf) = framenode->duration;
|
||||
GST_BUFFER_PTS (framenode->buf) = framenode->pts;
|
||||
GST_BUFFER_DTS (framenode->buf) = framenode->dts;
|
||||
|
||||
if (framenode->is_keyframe == FALSE)
|
||||
GST_BUFFER_FLAG_SET (framenode->buf, GST_BUFFER_FLAG_DELTA_UNIT);
|
||||
|
||||
return framenode;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
frame_node_compare (FrameNode * fnode, GstBuffer * buf, GstBuffer * expected)
|
||||
{
|
||||
if (expected != NULL) {
|
||||
GST_BUFFER_OFFSET (expected) = fnode->offset;
|
||||
GST_BUFFER_OFFSET_END (expected) = fnode->offset_end;
|
||||
GST_BUFFER_DURATION (expected) = fnode->duration;
|
||||
GST_BUFFER_PTS (expected) = fnode->pts;
|
||||
GST_BUFFER_DTS (expected) = fnode->dts;
|
||||
if (fnode->is_keyframe)
|
||||
GST_BUFFER_FLAG_SET (expected, GST_BUFFER_FLAG_DELTA_UNIT);
|
||||
}
|
||||
|
||||
if ((fnode->offset == GST_BUFFER_OFFSET (buf) &&
|
||||
fnode->offset_end == GST_BUFFER_OFFSET_END (buf) &&
|
||||
fnode->duration == GST_BUFFER_DURATION (buf) &&
|
||||
fnode->pts == GST_BUFFER_PTS (buf) &&
|
||||
fnode->dts == GST_BUFFER_DTS (buf) &&
|
||||
fnode->is_keyframe == GST_BUFFER_FLAG_IS_SET (buf,
|
||||
GST_BUFFER_FLAG_DELTA_UNIT)) == FALSE) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
on_end_element_cb (GMarkupParseContext * context,
|
||||
const gchar * element_name, gpointer user_data, GError ** error)
|
||||
{
|
||||
GstMediaDescriptorParserPrivate *priv =
|
||||
GST_MEDIA_DESCRIPTOR_PARSER (user_data)->priv;
|
||||
|
||||
if (g_strcmp0 (element_name, "stream") == 0) {
|
||||
priv->in_stream = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_start_element_cb (GMarkupParseContext * context,
|
||||
const gchar * element_name, const gchar ** attribute_names,
|
||||
const gchar ** attribute_values, gpointer user_data, GError ** error)
|
||||
{
|
||||
FileNode *filenode = GST_MEDIA_DESCRIPTOR (user_data)->filenode;
|
||||
|
||||
GstMediaDescriptorParserPrivate *priv =
|
||||
GST_MEDIA_DESCRIPTOR_PARSER (user_data)->priv;
|
||||
|
||||
if (g_strcmp0 (element_name, "file") == 0) {
|
||||
deserialize_filenode (filenode, attribute_names, attribute_values);
|
||||
} else if (g_strcmp0 (element_name, "stream") == 0) {
|
||||
StreamNode *node =
|
||||
deserialize_streamnode (attribute_names, attribute_values);
|
||||
priv->in_stream = TRUE;
|
||||
filenode->streams = g_list_prepend (filenode->streams, node);
|
||||
} else if (g_strcmp0 (element_name, "frame") == 0) {
|
||||
StreamNode *streamnode = filenode->streams->data;
|
||||
|
||||
streamnode->cframe = streamnode->frames =
|
||||
g_list_insert_sorted (streamnode->frames,
|
||||
deserialize_framenode (attribute_names, attribute_values),
|
||||
(GCompareFunc) compare_frames);
|
||||
} else if (g_strcmp0 (element_name, "tags") == 0) {
|
||||
if (priv->in_stream) {
|
||||
StreamNode *snode = (StreamNode *) filenode->streams->data;
|
||||
|
||||
snode->tags = deserialize_tagsnode (attribute_names, attribute_values);
|
||||
} else {
|
||||
filenode->tags = deserialize_tagsnode (attribute_names, attribute_values);
|
||||
}
|
||||
} else if (g_strcmp0 (element_name, "tag") == 0) {
|
||||
TagsNode *tagsnode;
|
||||
|
||||
if (priv->in_stream) {
|
||||
StreamNode *snode = (StreamNode *) filenode->streams->data;
|
||||
tagsnode = snode->tags;
|
||||
} else {
|
||||
tagsnode = filenode->tags;
|
||||
}
|
||||
|
||||
tagsnode->tags = g_list_prepend (tagsnode->tags,
|
||||
deserialize_tagnode (attribute_names, attribute_values));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_error_cb (GMarkupParseContext * context, GError * error, gpointer user_data)
|
||||
{
|
||||
GST_ERROR ("Error parsing file: %s", error->message);
|
||||
}
|
||||
|
||||
static const GMarkupParser content_parser = {
|
||||
on_start_element_cb,
|
||||
on_end_element_cb,
|
||||
NULL,
|
||||
NULL,
|
||||
&on_error_cb
|
||||
};
|
||||
|
||||
static gboolean
|
||||
set_xml_path (GstMediaDescriptorParser * parser, const gchar * path,
|
||||
GError ** error)
|
||||
{
|
||||
gsize xmlsize;
|
||||
GError *err = NULL;
|
||||
GstMediaDescriptorParserPrivate *priv = parser->priv;
|
||||
|
||||
if (!g_file_get_contents (path, &priv->xmlcontent, &xmlsize, &err))
|
||||
goto failed;
|
||||
|
||||
priv->xmlpath = g_strdup (path);
|
||||
priv->parsecontext = g_markup_parse_context_new (&content_parser,
|
||||
G_MARKUP_TREAT_CDATA_AS_TEXT, parser, NULL);
|
||||
|
||||
if (g_markup_parse_context_parse (priv->parsecontext, priv->xmlcontent,
|
||||
xmlsize, &err) == FALSE)
|
||||
goto failed;
|
||||
|
||||
return TRUE;
|
||||
|
||||
failed:
|
||||
g_propagate_error (error, err);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* GObject standard vmethods */
|
||||
static void
|
||||
dispose (GstMediaDescriptorParser * parser)
|
||||
{
|
||||
G_OBJECT_CLASS (gst_media_descriptor_parser_parent_class)->dispose (G_OBJECT
|
||||
(parser));
|
||||
}
|
||||
|
||||
static void
|
||||
finalize (GstMediaDescriptorParser * parser)
|
||||
{
|
||||
GstMediaDescriptorParserPrivate *priv;
|
||||
|
||||
priv = parser->priv;
|
||||
|
||||
g_free (priv->xmlpath);
|
||||
g_free (priv->xmlcontent);
|
||||
|
||||
if (priv->parsecontext != NULL)
|
||||
g_markup_parse_context_free (priv->parsecontext);
|
||||
|
||||
G_OBJECT_CLASS (gst_media_descriptor_parser_parent_class)->finalize (G_OBJECT
|
||||
(parser));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
get_property (GObject * gobject, guint prop_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
switch (prop_id) {
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
set_property (GObject * gobject, guint prop_id, const GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
switch (prop_id) {
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_media_descriptor_parser_init (GstMediaDescriptorParser * parser)
|
||||
{
|
||||
GstMediaDescriptorParserPrivate *priv;
|
||||
|
||||
parser->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (parser,
|
||||
GST_TYPE_MEDIA_DESCRIPTOR_PARSER, GstMediaDescriptorParserPrivate);
|
||||
|
||||
priv->xmlpath = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_media_descriptor_parser_class_init (GstMediaDescriptorParserClass *
|
||||
self_class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (self_class);
|
||||
|
||||
g_type_class_add_private (self_class,
|
||||
sizeof (GstMediaDescriptorParserPrivate));
|
||||
object_class->dispose = (void (*)(GObject * object)) dispose;
|
||||
object_class->finalize = (void (*)(GObject * object)) finalize;
|
||||
object_class->get_property = get_property;
|
||||
object_class->set_property = set_property;
|
||||
}
|
||||
|
||||
/* Public methods */
|
||||
GstMediaDescriptorParser *
|
||||
gst_media_descriptor_parser_new (GstValidateRunner * runner,
|
||||
const gchar * xmlpath, GError ** error)
|
||||
{
|
||||
GstMediaDescriptorParser *parser;
|
||||
|
||||
parser = g_object_new (GST_TYPE_MEDIA_DESCRIPTOR_PARSER, "validate-runner",
|
||||
runner, NULL);
|
||||
|
||||
if (set_xml_path (parser, xmlpath, error) == FALSE) {
|
||||
g_object_unref (parser);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
return parser;
|
||||
}
|
||||
|
||||
gchar *
|
||||
gst_media_descriptor_parser_get_xml_path (GstMediaDescriptorParser * parser)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), NULL);
|
||||
|
||||
return g_strdup (parser->priv->xmlpath);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_media_descriptor_parser_add_stream (GstMediaDescriptorParser * parser,
|
||||
GstPad * pad)
|
||||
{
|
||||
GList *tmp;
|
||||
gboolean ret = FALSE;
|
||||
GstCaps *caps;
|
||||
|
||||
g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), FALSE);
|
||||
g_return_val_if_fail (((GstMediaDescriptor *) parser)->filenode, FALSE);
|
||||
|
||||
caps = gst_pad_query_caps (pad, NULL);
|
||||
for (tmp = ((GstMediaDescriptor *) parser)->filenode->streams; tmp;
|
||||
tmp = tmp->next) {
|
||||
StreamNode *streamnode = (StreamNode *) tmp->data;
|
||||
|
||||
if (streamnode->pad == NULL && gst_caps_is_equal (streamnode->caps, caps)) {
|
||||
ret = TRUE;
|
||||
streamnode->pad = gst_object_ref (pad);
|
||||
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (caps != NULL)
|
||||
gst_caps_unref (caps);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_media_descriptor_parser_all_stream_found (GstMediaDescriptorParser * parser)
|
||||
{
|
||||
GList *tmp;
|
||||
|
||||
g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), FALSE);
|
||||
g_return_val_if_fail (((GstMediaDescriptor *) parser)->filenode, FALSE);
|
||||
|
||||
for (tmp = ((GstMediaDescriptor *) parser)->filenode->streams; tmp;
|
||||
tmp = tmp->next) {
|
||||
StreamNode *streamnode = (StreamNode *) tmp->data;
|
||||
|
||||
if (streamnode->pad == NULL)
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_media_descriptor_parser_add_frame (GstMediaDescriptorParser * parser,
|
||||
GstPad * pad, GstBuffer * buf, GstBuffer * expected)
|
||||
{
|
||||
GList *tmp;
|
||||
|
||||
g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), FALSE);
|
||||
g_return_val_if_fail (((GstMediaDescriptor *) parser)->filenode, FALSE);
|
||||
|
||||
for (tmp = ((GstMediaDescriptor *) parser)->filenode->streams; tmp;
|
||||
tmp = tmp->next) {
|
||||
StreamNode *streamnode = (StreamNode *) tmp->data;
|
||||
|
||||
if (streamnode->pad == pad && streamnode->cframe) {
|
||||
FrameNode *fnode = streamnode->cframe->data;
|
||||
|
||||
streamnode->cframe = streamnode->cframe->next;
|
||||
return frame_node_compare (fnode, buf, expected);
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_media_descriptor_parser_add_taglist (GstMediaDescriptorParser * parser,
|
||||
GstTagList * taglist)
|
||||
{
|
||||
GList *tmptag;
|
||||
TagsNode *tagsnode;
|
||||
|
||||
g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), FALSE);
|
||||
g_return_val_if_fail (((GstMediaDescriptor *) parser)->filenode, FALSE);
|
||||
g_return_val_if_fail (GST_IS_STRUCTURE (taglist), FALSE);
|
||||
|
||||
tagsnode = ((GstMediaDescriptor *) parser)->filenode->tags;
|
||||
|
||||
for (tmptag = tagsnode->tags; tmptag; tmptag = tmptag->next) {
|
||||
if (tag_node_compare ((TagNode *) tmptag->data, taglist)) {
|
||||
GST_DEBUG ("Adding tag %" GST_PTR_FORMAT, taglist);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_media_descriptor_parser_all_tags_found (GstMediaDescriptorParser * parser)
|
||||
{
|
||||
GList *tmptag;
|
||||
TagsNode *tagsnode;
|
||||
gboolean ret = TRUE;
|
||||
|
||||
g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), FALSE);
|
||||
g_return_val_if_fail (((GstMediaDescriptor *) parser)->filenode, FALSE);
|
||||
|
||||
tagsnode = ((GstMediaDescriptor *) parser)->filenode->tags;
|
||||
for (tmptag = tagsnode->tags; tmptag; tmptag = tmptag->next) {
|
||||
gchar *tag = NULL;
|
||||
|
||||
tag = gst_tag_list_to_string (((TagNode *) tmptag->data)->taglist);
|
||||
if (((TagNode *) tmptag->data)->found == FALSE) {
|
||||
|
||||
if (((TagNode *) tmptag->data)->taglist != NULL) {
|
||||
GST_DEBUG ("Tag not found %s", tag);
|
||||
} else {
|
||||
GST_DEBUG ("Tag not not properly deserialized");
|
||||
}
|
||||
|
||||
ret = FALSE;
|
||||
}
|
||||
|
||||
GST_DEBUG ("Tag properly found found %s", tag);
|
||||
g_free (tag);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_media_descriptor_parser_detects_frames (GstMediaDescriptorParser * parser)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), FALSE);
|
||||
g_return_val_if_fail (((GstMediaDescriptor *) parser)->filenode, FALSE);
|
||||
|
||||
return ((GstMediaDescriptor *) parser)->filenode->frame_detection;
|
||||
}
|
||||
|
||||
GstClockTime
|
||||
gst_media_descriptor_parser_get_duration (GstMediaDescriptorParser * parser)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), FALSE);
|
||||
g_return_val_if_fail (((GstMediaDescriptor *) parser)->filenode, FALSE);
|
||||
|
||||
return ((GstMediaDescriptor *) parser)->filenode->duration;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_media_descriptor_parser_get_seekable (GstMediaDescriptorParser * parser)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), FALSE);
|
||||
g_return_val_if_fail (((GstMediaDescriptor *) parser)->filenode, FALSE);
|
||||
|
||||
return ((GstMediaDescriptor *) parser)->filenode->seekable;
|
||||
}
|
||||
|
||||
GList *
|
||||
gst_media_descriptor_parser_get_buffers (GstMediaDescriptorParser * parser,
|
||||
GstPad * pad, GCompareFunc compare_func)
|
||||
{
|
||||
GList *ret = NULL, *tmpstream, *tmpframe;
|
||||
gboolean check = (pad == NULL);
|
||||
|
||||
g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), FALSE);
|
||||
g_return_val_if_fail (((GstMediaDescriptor *) parser)->filenode, FALSE);
|
||||
|
||||
for (tmpstream = ((GstMediaDescriptor *) parser)->filenode->streams;
|
||||
tmpstream; tmpstream = tmpstream->next) {
|
||||
StreamNode *streamnode = (StreamNode *) tmpstream->data;
|
||||
|
||||
if (pad && streamnode->pad == pad)
|
||||
check = TRUE;
|
||||
|
||||
if (check) {
|
||||
for (tmpframe = streamnode->frames; tmpframe; tmpframe = tmpframe->next) {
|
||||
if (compare_func)
|
||||
ret =
|
||||
g_list_insert_sorted (ret,
|
||||
gst_buffer_ref (((FrameNode *) tmpframe->data)->buf),
|
||||
compare_func);
|
||||
else
|
||||
ret =
|
||||
g_list_prepend (ret,
|
||||
gst_buffer_ref (((FrameNode *) tmpframe->data)->buf));
|
||||
}
|
||||
|
||||
if (pad != NULL)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
GList *
|
||||
gst_media_descriptor_parser_get_pads (GstMediaDescriptorParser * parser)
|
||||
{
|
||||
GList *ret = NULL, *tmp;
|
||||
|
||||
for (tmp = ((GstMediaDescriptor *) parser)->filenode->streams; tmp;
|
||||
tmp = tmp->next) {
|
||||
StreamNode *snode = (StreamNode *) tmp->data;
|
||||
ret = g_list_append (ret, gst_pad_new (snode->padname, GST_PAD_UNKNOWN));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
82
validate/gst/validate/media-descriptor-parser.h
Normal file
82
validate/gst/validate/media-descriptor-parser.h
Normal file
|
@ -0,0 +1,82 @@
|
|||
/**
|
||||
* Insanity QA system
|
||||
*
|
||||
* Copyright (c) 2012, Collabora Ltd
|
||||
* Author: Thibault Saunier <thibault.saunier@collabora.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef GST_MEDIA_DESCRIPTOR_PARSER_h
|
||||
#define GST_MEDIA_DESCRIPTOR_PARSER_h
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
#include <gst/gst.h>
|
||||
#include "media-descriptor.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GType gst_media_descriptor_parser_get_type (void);
|
||||
|
||||
#define GST_TYPE_MEDIA_DESCRIPTOR_PARSER (gst_media_descriptor_parser_get_type ())
|
||||
#define GST_MEDIA_DESCRIPTOR_PARSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MEDIA_DESCRIPTOR_PARSER, GstMediaDescriptorParser))
|
||||
#define GST_MEDIA_DESCRIPTOR_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MEDIA_DESCRIPTOR_PARSER, GstMediaDescriptorParserClass))
|
||||
#define GST_IS_MEDIA_DESCRIPTOR_PARSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MEDIA_DESCRIPTOR_PARSER))
|
||||
#define GST_IS_MEDIA_DESCRIPTOR_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MEDIA_DESCRIPTOR_PARSER))
|
||||
#define GST_MEDIA_DESCRIPTOR_PARSER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_MEDIA_DESCRIPTOR_PARSER, GstMediaDescriptorParserClass))
|
||||
|
||||
typedef struct _GstMediaDescriptorParserPrivate GstMediaDescriptorParserPrivate;
|
||||
|
||||
|
||||
typedef struct {
|
||||
GstMediaDescriptor parent;
|
||||
|
||||
GstMediaDescriptorParserPrivate *priv;
|
||||
|
||||
} GstMediaDescriptorParser;
|
||||
|
||||
typedef struct {
|
||||
|
||||
GstMediaDescriptorClass parent;
|
||||
|
||||
} GstMediaDescriptorParserClass;
|
||||
|
||||
GstMediaDescriptorParser * gst_media_descriptor_parser_new (GstValidateRunner *runner,
|
||||
const gchar * xmlpath,
|
||||
GError **error);
|
||||
gchar * gst_media_descriptor_parser_get_xml_path (GstMediaDescriptorParser *parser);
|
||||
gboolean gst_media_descriptor_parser_detects_frames (GstMediaDescriptorParser *parser);
|
||||
GstClockTime gst_media_descriptor_parser_get_duration (GstMediaDescriptorParser *parser);
|
||||
gboolean gst_media_descriptor_parser_get_seekable (GstMediaDescriptorParser * parser);
|
||||
gboolean gst_media_descriptor_parser_add_stream (GstMediaDescriptorParser *parser,
|
||||
GstPad *pad);
|
||||
gboolean gst_media_descriptor_parser_add_taglist (GstMediaDescriptorParser *parser,
|
||||
GstTagList *taglist);
|
||||
gboolean gst_media_descriptor_parser_all_stream_found (GstMediaDescriptorParser *parser);
|
||||
gboolean gst_media_descriptor_parser_all_tags_found (GstMediaDescriptorParser *parser);
|
||||
gboolean gst_media_descriptor_parser_add_frame (GstMediaDescriptorParser *parser,
|
||||
GstPad *pad,
|
||||
GstBuffer *buf,
|
||||
GstBuffer *expected);
|
||||
GList * gst_media_descriptor_parser_get_buffers (GstMediaDescriptorParser * parser,
|
||||
GstPad *pad,
|
||||
GCompareFunc compare_func);
|
||||
GList * gst_media_descriptor_parser_get_pads (GstMediaDescriptorParser * parser);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* GST_MEDIA_DESCRIPTOR_PARSER_h */
|
534
validate/gst/validate/media-descriptor-writer.c
Normal file
534
validate/gst/validate/media-descriptor-writer.c
Normal file
|
@ -0,0 +1,534 @@
|
|||
/**
|
||||
* Gstreamer
|
||||
*
|
||||
* Copyright (c) 2012, Collabora Ltd.
|
||||
* Author: Thibault Saunier <thibault.saunier@collabora.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "media-descriptor-writer.h"
|
||||
#include <string.h>
|
||||
|
||||
G_DEFINE_TYPE (GstMediaDescriptorWriter,
|
||||
gst_media_descriptor_writer, GST_TYPE_MEDIA_DESCRIPTOR);
|
||||
|
||||
#define STR_APPEND(arg, nb_white) \
|
||||
tmpstr = res; \
|
||||
res = g_strdup_printf ("%s%*s%s%s", res, (nb_white), " ", (arg), "\n"); \
|
||||
g_free (tmpstr);
|
||||
|
||||
#define STR_APPEND0(arg) STR_APPEND((arg), 0)
|
||||
#define STR_APPEND1(arg) STR_APPEND((arg), 2)
|
||||
#define STR_APPEND2(arg) STR_APPEND((arg), 4)
|
||||
#define STR_APPEND3(arg) STR_APPEND((arg), 6)
|
||||
#define STR_APPEND4(arg) STR_APPEND((arg), 8)
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_PATH,
|
||||
N_PROPERTIES
|
||||
};
|
||||
|
||||
struct _GstMediaDescriptorWriterPrivate
|
||||
{
|
||||
GList *serialized_string;
|
||||
guint stream_id;
|
||||
};
|
||||
|
||||
static void
|
||||
finalize (GstMediaDescriptorWriter * writer)
|
||||
{
|
||||
G_OBJECT_CLASS (gst_media_descriptor_writer_parent_class)->
|
||||
finalize (G_OBJECT (writer));
|
||||
}
|
||||
|
||||
static void
|
||||
get_property (GObject * gobject, guint prop_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
switch (prop_id) {
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
set_property (GObject * gobject, guint prop_id, const GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
switch (prop_id) {
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_media_descriptor_writer_init (GstMediaDescriptorWriter * writer)
|
||||
{
|
||||
GstMediaDescriptorWriterPrivate *priv;
|
||||
|
||||
writer->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (writer,
|
||||
GST_TYPE_MEDIA_DESCRIPTOR_WRITER, GstMediaDescriptorWriterPrivate);
|
||||
|
||||
priv->serialized_string = NULL;
|
||||
priv->stream_id = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_media_descriptor_writer_class_init
|
||||
(GstMediaDescriptorWriterClass * self_class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (self_class);
|
||||
|
||||
g_type_class_add_private (self_class,
|
||||
sizeof (GstMediaDescriptorWriterPrivate));
|
||||
object_class->finalize = (void (*)(GObject * object)) finalize;
|
||||
object_class->get_property = get_property;
|
||||
object_class->set_property = set_property;
|
||||
}
|
||||
|
||||
/* Private methods */
|
||||
static gchar *
|
||||
serialize_filenode (GstMediaDescriptorWriter * writer)
|
||||
{
|
||||
gchar *res, *tmpstr, *caps_str, *tmpnode;
|
||||
GList *tmp, *tmp2;
|
||||
TagsNode *tagsnode;
|
||||
FileNode *filenode = ((GstMediaDescriptor *) writer)->filenode;
|
||||
|
||||
res = g_markup_printf_escaped ("<file duration=\"%" G_GUINT64_FORMAT
|
||||
"\" frame-detection=\"%i\" uri=\"%s\" seekable=\"%s\">\n",
|
||||
filenode->duration, filenode->frame_detection, filenode->uri,
|
||||
filenode->seekable ? "true" : "false");
|
||||
|
||||
if (filenode->caps)
|
||||
caps_str = gst_caps_to_string (filenode->caps);
|
||||
else
|
||||
caps_str = g_strdup ("");
|
||||
|
||||
tmpnode = g_strdup_printf ("<streams caps=\"%s\">", caps_str);
|
||||
STR_APPEND1 (tmpnode);
|
||||
g_free (caps_str);
|
||||
g_free (tmpnode);
|
||||
|
||||
for (tmp = filenode->streams; tmp; tmp = tmp->next) {
|
||||
GList *tmp3;
|
||||
StreamNode *snode = ((StreamNode *) tmp->data);
|
||||
|
||||
STR_APPEND2 (snode->str_open);
|
||||
|
||||
for (tmp2 = snode->frames; tmp2; tmp2 = tmp2->next) {
|
||||
STR_APPEND3 (((FrameNode *) tmp2->data)->str_open);
|
||||
}
|
||||
|
||||
tagsnode = snode->tags;
|
||||
STR_APPEND3 (tagsnode->str_open);
|
||||
for (tmp3 = tagsnode->tags; tmp3; tmp3 = tmp3->next) {
|
||||
STR_APPEND4 (((TagNode *) tmp3->data)->str_open);
|
||||
}
|
||||
STR_APPEND3 (tagsnode->str_close);
|
||||
|
||||
STR_APPEND2 (snode->str_close);
|
||||
}
|
||||
STR_APPEND1 ("</streams>");
|
||||
|
||||
tagsnode = filenode->tags;
|
||||
STR_APPEND1 (tagsnode->str_open);
|
||||
for (tmp2 = tagsnode->tags; tmp2; tmp2 = tmp2->next) {
|
||||
STR_APPEND2 (((TagNode *) tmp2->data)->str_open);
|
||||
}
|
||||
STR_APPEND1 (tagsnode->str_close);
|
||||
|
||||
tmpstr = res;
|
||||
res = g_strdup_printf ("%s%s", res, filenode->str_close);
|
||||
g_free (tmpstr);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Public methods */
|
||||
GstMediaDescriptorWriter *
|
||||
gst_media_descriptor_writer_new (GstValidateRunner * runner,
|
||||
const gchar * uri, GstClockTime duration, gboolean seekable)
|
||||
{
|
||||
GstMediaDescriptorWriter *writer;
|
||||
FileNode *fnode;
|
||||
|
||||
writer =
|
||||
g_object_new (GST_TYPE_MEDIA_DESCRIPTOR_WRITER, "validate-runner", runner,
|
||||
NULL);
|
||||
|
||||
fnode = ((GstMediaDescriptor *) writer)->filenode;
|
||||
fnode->uri = g_strdup (uri);
|
||||
fnode->duration = duration;
|
||||
fnode->seekable = seekable;
|
||||
fnode->str_open = NULL;
|
||||
|
||||
fnode->str_close = g_markup_printf_escaped ("</file>");
|
||||
|
||||
return writer;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_media_descriptor_writer_add_stream (GstMediaDescriptorWriter * writer,
|
||||
GstDiscovererStreamInfo * info)
|
||||
{
|
||||
const gchar *stype;
|
||||
gboolean ret = FALSE;
|
||||
GstCaps *caps;
|
||||
gchar *capsstr = NULL;
|
||||
StreamNode *snode = NULL;
|
||||
|
||||
g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_WRITER (writer), FALSE);
|
||||
g_return_val_if_fail (((GstMediaDescriptor *) writer)->filenode, FALSE);
|
||||
|
||||
snode = g_slice_new0 (StreamNode);
|
||||
snode->frames = NULL;
|
||||
snode->cframe = NULL;
|
||||
|
||||
snode->id = g_strdup (gst_discoverer_stream_info_get_stream_id (info));
|
||||
if (snode->id == NULL) {
|
||||
caps = gst_discoverer_stream_info_get_caps (info);
|
||||
capsstr = gst_caps_to_string (caps);
|
||||
|
||||
g_slice_free (StreamNode, snode);
|
||||
GST_VALIDATE_REPORT (writer, FILE_NO_STREAM_ID,
|
||||
"Stream with caps: %s has no stream ID",
|
||||
capsstr);
|
||||
gst_caps_unref (caps);
|
||||
g_free (capsstr);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
caps = gst_discoverer_stream_info_get_caps (info);
|
||||
snode->caps = caps;
|
||||
capsstr = gst_caps_to_string (caps);
|
||||
if (GST_IS_DISCOVERER_AUDIO_INFO (info)) {
|
||||
stype = "audio";
|
||||
} else if (GST_IS_DISCOVERER_VIDEO_INFO (info)) {
|
||||
if (gst_discoverer_video_info_is_image (GST_DISCOVERER_VIDEO_INFO (info)))
|
||||
stype = "image";
|
||||
else
|
||||
stype = "video";
|
||||
} else if (GST_IS_DISCOVERER_SUBTITLE_INFO (info)) {
|
||||
stype = "subtitle";
|
||||
} else {
|
||||
stype = "Unknown";
|
||||
}
|
||||
|
||||
snode->str_open =
|
||||
g_markup_printf_escaped
|
||||
("<stream type=\"%s\" caps=\"%s\" id=\"%s\">", stype, capsstr, snode->id);
|
||||
|
||||
snode->str_close = g_markup_printf_escaped ("</stream>");
|
||||
|
||||
((GstMediaDescriptor *) writer)->filenode->streams =
|
||||
g_list_prepend (((GstMediaDescriptor *) writer)->filenode->streams,
|
||||
snode);
|
||||
|
||||
if (gst_discoverer_stream_info_get_tags (info)) {
|
||||
gst_media_descriptor_writer_add_tags (writer, snode->id,
|
||||
gst_discoverer_stream_info_get_tags (info));
|
||||
}
|
||||
|
||||
if (caps != NULL)
|
||||
gst_caps_unref (caps);
|
||||
g_free (capsstr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
GstMediaDescriptorWriter *
|
||||
gst_media_descriptor_writer_new_discover (GstValidateRunner * runner,
|
||||
const gchar * uri, GError ** err)
|
||||
{
|
||||
GList *tmp, *streams;
|
||||
GstDiscovererInfo *info;
|
||||
GstDiscoverer *discoverer;
|
||||
GstDiscovererStreamInfo *streaminfo;
|
||||
GstMediaDescriptorWriter *writer;
|
||||
|
||||
discoverer = gst_discoverer_new (GST_SECOND * 60, err);
|
||||
|
||||
if (discoverer == NULL) {
|
||||
GST_ERROR ("Could not create discoverer");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
info = gst_discoverer_discover_uri (discoverer, uri, err);
|
||||
if (info == NULL
|
||||
|| gst_discoverer_info_get_result (info) != GST_DISCOVERER_OK) {
|
||||
|
||||
GST_ERROR ("Could not discover URI: %s", uri);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
writer =
|
||||
gst_media_descriptor_writer_new (runner,
|
||||
gst_discoverer_info_get_uri (info),
|
||||
gst_discoverer_info_get_duration (info),
|
||||
gst_discoverer_info_get_seekable (info));
|
||||
|
||||
if (gst_discoverer_info_get_tags (info))
|
||||
gst_media_descriptor_writer_add_taglist (writer,
|
||||
gst_discoverer_info_get_tags (info));
|
||||
|
||||
streaminfo = gst_discoverer_info_get_stream_info (info);
|
||||
((GstMediaDescriptor *) writer)->filenode->caps =
|
||||
gst_discoverer_stream_info_get_caps (GST_DISCOVERER_STREAM_INFO
|
||||
(streaminfo));
|
||||
|
||||
streams = gst_discoverer_info_get_stream_list (info);
|
||||
for (tmp = streams; tmp; tmp = tmp->next)
|
||||
gst_media_descriptor_writer_add_stream (writer, tmp->data);
|
||||
gst_discoverer_stream_info_list_free(streams);
|
||||
|
||||
|
||||
return writer;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_media_descriptor_writer_add_tags (GstMediaDescriptorWriter
|
||||
* writer, const gchar * stream_id, const GstTagList * taglist)
|
||||
{
|
||||
TagsNode *tagsnode;
|
||||
TagNode *tagnode;
|
||||
GList *tmp, *tmptag;
|
||||
|
||||
gchar *str_str = NULL;
|
||||
StreamNode *snode = NULL;
|
||||
|
||||
g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_WRITER (writer), FALSE);
|
||||
g_return_val_if_fail (((GstMediaDescriptor *) writer)->filenode, FALSE);
|
||||
|
||||
for (tmp = ((GstMediaDescriptor *) writer)->filenode->streams; tmp;
|
||||
tmp = tmp->next) {
|
||||
if (g_strcmp0 (((StreamNode *) tmp->data)->id, stream_id) == 0) {
|
||||
snode = tmp->data;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (snode == NULL) {
|
||||
GST_WARNING ("Could not find stream with id: %s", stream_id);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (snode->tags == NULL) {
|
||||
tagsnode = g_slice_new0 (TagsNode);
|
||||
tagsnode->str_open = g_markup_printf_escaped ("<tags>");
|
||||
tagsnode->str_close = g_markup_printf_escaped ("</tags>");
|
||||
snode->tags = tagsnode;
|
||||
} else {
|
||||
tagsnode = snode->tags;
|
||||
|
||||
for (tmptag = tagsnode->tags; tmptag; tmptag = tmptag->next) {
|
||||
if (tag_node_compare ((TagNode *) tmptag->data, taglist)) {
|
||||
GST_DEBUG ("Tag already in... not adding again %" GST_PTR_FORMAT,
|
||||
taglist);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tagnode = g_slice_new0 (TagNode);
|
||||
tagnode->taglist = gst_tag_list_copy (taglist);
|
||||
str_str = gst_tag_list_to_string (tagnode->taglist);
|
||||
tagnode->str_open =
|
||||
g_markup_printf_escaped ("<tag content=\"%s\"/>", str_str);
|
||||
tagsnode->tags = g_list_prepend (tagsnode->tags, tagnode);
|
||||
|
||||
g_free (str_str);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_media_descriptor_writer_add_pad (GstMediaDescriptorWriter *
|
||||
writer, GstPad * pad)
|
||||
{
|
||||
GList *tmp;
|
||||
gboolean ret = FALSE;
|
||||
GstCaps *caps;
|
||||
gchar *capsstr = NULL, *padname = NULL;
|
||||
StreamNode *snode = NULL;
|
||||
|
||||
g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_WRITER (writer), FALSE);
|
||||
g_return_val_if_fail (((GstMediaDescriptor *) writer)->filenode, FALSE);
|
||||
|
||||
caps = gst_pad_get_current_caps (pad);
|
||||
for (tmp = ((GstMediaDescriptor *) writer)->filenode->streams; tmp;
|
||||
tmp = tmp->next) {
|
||||
StreamNode *streamnode = (StreamNode *) tmp->data;
|
||||
|
||||
if (streamnode->pad == pad) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
snode = g_slice_new0 (StreamNode);
|
||||
snode->frames = NULL;
|
||||
snode->cframe = NULL;
|
||||
|
||||
snode->caps = gst_caps_ref (caps);
|
||||
snode->pad = gst_object_ref (pad);
|
||||
|
||||
capsstr = gst_caps_to_string (caps);
|
||||
padname = gst_pad_get_name (pad);
|
||||
snode->str_open =
|
||||
g_markup_printf_escaped
|
||||
("<stream padname=\"%s\" caps=\"%s\" id=\"%i\">", padname, capsstr, 0);
|
||||
|
||||
snode->str_close = g_markup_printf_escaped ("</stream>");
|
||||
|
||||
((GstMediaDescriptor *) writer)->filenode->streams =
|
||||
g_list_prepend (((GstMediaDescriptor *) writer)->filenode->streams,
|
||||
snode);
|
||||
|
||||
done:
|
||||
if (caps != NULL)
|
||||
gst_caps_unref (caps);
|
||||
g_free (capsstr);
|
||||
g_free (padname);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_media_descriptor_writer_add_taglist (GstMediaDescriptorWriter * writer,
|
||||
const GstTagList * taglist)
|
||||
{
|
||||
gchar *str_str = NULL;
|
||||
TagsNode *tagsnode;
|
||||
TagNode *tagnode;
|
||||
GList *tmptag;
|
||||
|
||||
g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_WRITER (writer), FALSE);
|
||||
g_return_val_if_fail (((GstMediaDescriptor *) writer)->filenode, FALSE);
|
||||
|
||||
if (((GstMediaDescriptor *) writer)->filenode->tags == NULL) {
|
||||
tagsnode = g_slice_new0 (TagsNode);
|
||||
tagsnode->str_open = g_markup_printf_escaped ("<tags>");
|
||||
tagsnode->str_close = g_markup_printf_escaped ("</tags>");
|
||||
((GstMediaDescriptor *) writer)->filenode->tags = tagsnode;
|
||||
} else {
|
||||
tagsnode = ((GstMediaDescriptor *) writer)->filenode->tags;
|
||||
for (tmptag = tagsnode->tags; tmptag; tmptag = tmptag->next) {
|
||||
if (tag_node_compare ((TagNode *) tmptag->data, taglist)) {
|
||||
GST_DEBUG ("Tag already in... not adding again %" GST_PTR_FORMAT,
|
||||
taglist);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tagnode = g_slice_new0 (TagNode);
|
||||
tagnode->taglist = gst_tag_list_copy (taglist);
|
||||
str_str = gst_tag_list_to_string (tagnode->taglist);
|
||||
tagnode->str_open =
|
||||
g_markup_printf_escaped ("<tag content=\"%s\"/>", str_str);
|
||||
tagsnode->tags = g_list_prepend (tagsnode->tags, tagnode);
|
||||
|
||||
g_free (str_str);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_media_descriptor_writer_add_frame (GstMediaDescriptorWriter
|
||||
* writer, GstPad * pad, GstBuffer * buf)
|
||||
{
|
||||
GList *tmp;
|
||||
|
||||
g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_WRITER (writer), FALSE);
|
||||
g_return_val_if_fail (((GstMediaDescriptor *) writer)->filenode, FALSE);
|
||||
|
||||
((GstMediaDescriptor *) writer)->filenode->frame_detection = TRUE;
|
||||
|
||||
for (tmp = ((GstMediaDescriptor *) writer)->filenode->streams; tmp;
|
||||
tmp = tmp->next) {
|
||||
StreamNode *streamnode = (StreamNode *) tmp->data;
|
||||
|
||||
if (streamnode->pad == pad) {
|
||||
guint id = g_list_length (streamnode->frames);
|
||||
FrameNode *fnode = g_slice_new0 (FrameNode);
|
||||
|
||||
fnode->id = id;
|
||||
fnode->offset = GST_BUFFER_OFFSET (buf);
|
||||
fnode->offset_end = GST_BUFFER_OFFSET_END (buf);
|
||||
fnode->duration = GST_BUFFER_DURATION (buf);
|
||||
fnode->pts = GST_BUFFER_PTS (buf);
|
||||
fnode->dts = GST_BUFFER_DTS (buf);
|
||||
fnode->is_keyframe = (GST_BUFFER_FLAG_IS_SET (buf,
|
||||
GST_BUFFER_FLAG_DELTA_UNIT) == FALSE);
|
||||
|
||||
fnode->str_open =
|
||||
g_markup_printf_escaped (" <frame duration=\"%" G_GUINT64_FORMAT
|
||||
"\" id=\"%i\" is-keyframe=\"%i\" offset=\"%" G_GUINT64_FORMAT
|
||||
"\" offset-end=\"%" G_GUINT64_FORMAT "\" pts=\"%"
|
||||
G_GUINT64_FORMAT "\" dts=\"%" G_GUINT64_FORMAT "\" />",
|
||||
fnode->duration, id, fnode->is_keyframe,
|
||||
fnode->offset, fnode->offset_end, fnode->pts, fnode->dts);
|
||||
|
||||
fnode->str_close = NULL;
|
||||
|
||||
streamnode->frames = g_list_append (streamnode->frames, fnode);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_media_descriptor_writer_write (GstMediaDescriptorWriter *
|
||||
writer, const gchar * filename)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
gchar *serialized;
|
||||
|
||||
g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_WRITER (writer), FALSE);
|
||||
g_return_val_if_fail (((GstMediaDescriptor *) writer)->filenode, FALSE);
|
||||
|
||||
serialized = serialize_filenode (writer);
|
||||
|
||||
|
||||
if (g_file_set_contents (filename, serialized, -1, NULL) == TRUE)
|
||||
ret = TRUE;
|
||||
|
||||
|
||||
g_free (serialized);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
gchar *
|
||||
gst_media_descriptor_writer_serialize (GstMediaDescriptorWriter * writer)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_WRITER (writer), FALSE);
|
||||
g_return_val_if_fail (((GstMediaDescriptor *) writer)->filenode, FALSE);
|
||||
|
||||
return serialize_filenode (writer);
|
||||
}
|
91
validate/gst/validate/media-descriptor-writer.h
Normal file
91
validate/gst/validate/media-descriptor-writer.h
Normal file
|
@ -0,0 +1,91 @@
|
|||
/**
|
||||
* Insanity QA system
|
||||
*
|
||||
* Copyright (c) 2012, Collabora Ltd
|
||||
* Author: Thibault Saunier <thibault.saunier@collabora.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef GST_MEDIA_DESCRIPTOR_WRITER_h
|
||||
#define GST_MEDIA_DESCRIPTOR_WRITER_h
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
#include <gst/gst.h>
|
||||
#include <gst/pbutils/pbutils.h>
|
||||
#include "media-descriptor.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GType gst_media_descriptor_writer_get_type (void);
|
||||
|
||||
#define GST_TYPE_MEDIA_DESCRIPTOR_WRITER (gst_media_descriptor_writer_get_type ())
|
||||
#define GST_MEDIA_DESCRIPTOR_WRITER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MEDIA_DESCRIPTOR_WRITER, GstMediaDescriptorWriter))
|
||||
#define GST_MEDIA_DESCRIPTOR_WRITER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MEDIA_DESCRIPTOR_WRITER, GstMediaDescriptorWriterClass))
|
||||
#define GST_IS_MEDIA_DESCRIPTOR_WRITER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MEDIA_DESCRIPTOR_WRITER))
|
||||
#define GST_IS_MEDIA_DESCRIPTOR_WRITER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MEDIA_DESCRIPTOR_WRITER))
|
||||
#define GST_MEDIA_DESCRIPTOR_WRITER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_MEDIA_DESCRIPTOR_WRITER, GstMediaDescriptorWriterClass))
|
||||
|
||||
typedef struct _GstMediaDescriptorWriterPrivate GstMediaDescriptorWriterPrivate;
|
||||
|
||||
|
||||
typedef struct {
|
||||
GstMediaDescriptor parent;
|
||||
|
||||
GstMediaDescriptorWriterPrivate *priv;
|
||||
|
||||
} GstMediaDescriptorWriter;
|
||||
|
||||
typedef struct {
|
||||
|
||||
GstMediaDescriptorClass parent;
|
||||
|
||||
} GstMediaDescriptorWriterClass;
|
||||
|
||||
GstMediaDescriptorWriter * gst_media_descriptor_writer_new_discover (GstValidateRunner *runner,
|
||||
const gchar *uri,
|
||||
GError **err);
|
||||
|
||||
GstMediaDescriptorWriter * gst_media_descriptor_writer_new (GstValidateRunner *runner,
|
||||
const gchar *location,
|
||||
GstClockTime duration,
|
||||
gboolean seekable);
|
||||
|
||||
gchar * gst_media_descriptor_writer_get_xml_path (GstMediaDescriptorWriter *writer);
|
||||
|
||||
gboolean gst_media_descriptor_writer_detects_frames (GstMediaDescriptorWriter *writer);
|
||||
GstClockTime gst_media_descriptor_writer_get_duration (GstMediaDescriptorWriter *writer);
|
||||
gboolean gst_media_descriptor_writer_get_seekable (GstMediaDescriptorWriter * writer);
|
||||
|
||||
gboolean gst_media_descriptor_writer_add_pad (GstMediaDescriptorWriter *writer,
|
||||
GstPad *pad);
|
||||
gboolean gst_media_descriptor_writer_add_taglist (GstMediaDescriptorWriter *writer,
|
||||
const GstTagList *taglist);
|
||||
gboolean gst_media_descriptor_writer_add_frame (GstMediaDescriptorWriter *writer,
|
||||
GstPad *pad,
|
||||
GstBuffer *buf);
|
||||
gboolean gst_media_descriptor_writer_add_tags (GstMediaDescriptorWriter *writer,
|
||||
const gchar *stream_id,
|
||||
const GstTagList *taglist);
|
||||
gboolean gst_media_descriptor_writer_write (GstMediaDescriptorWriter * writer,
|
||||
const gchar * filename);
|
||||
gchar * gst_media_descriptor_writer_serialize (GstMediaDescriptorWriter *writer);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* GST_MEDIA_DESCRIPTOR_WRITER_h */
|
326
validate/gst/validate/media-descriptor.c
Normal file
326
validate/gst/validate/media-descriptor.c
Normal file
|
@ -0,0 +1,326 @@
|
|||
/**
|
||||
* Gstreamer
|
||||
*
|
||||
* Copyright (c) 2012, Collabora Ltd.
|
||||
* Author: Thibault Saunier <thibault.saunier@collabora.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "media-descriptor.h"
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstMediaDescriptor, gst_media_descriptor,
|
||||
G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, NULL));
|
||||
|
||||
#define GST_MEDIA_DESCRIPTOR_GET_PRIVATE(o)\
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_MEDIA_DESCRIPTOR, GstMediaDescriptorPrivate))
|
||||
|
||||
static inline void
|
||||
free_tagnode (TagNode * tagnode)
|
||||
{
|
||||
g_free (tagnode->str_open);
|
||||
g_free (tagnode->str_close);
|
||||
if (tagnode->taglist)
|
||||
gst_tag_list_unref (tagnode->taglist);
|
||||
|
||||
g_slice_free (TagNode, tagnode);
|
||||
}
|
||||
|
||||
static inline void
|
||||
free_tagsnode (TagsNode * tagsnode)
|
||||
{
|
||||
g_free (tagsnode->str_open);
|
||||
g_free (tagsnode->str_close);
|
||||
g_list_free_full (tagsnode->tags, (GDestroyNotify) free_tagnode);
|
||||
g_slice_free (TagsNode, tagsnode);
|
||||
}
|
||||
|
||||
static inline void
|
||||
free_framenode (FrameNode * framenode)
|
||||
{
|
||||
g_free (framenode->str_open);
|
||||
g_free (framenode->str_close);
|
||||
|
||||
if (framenode->buf)
|
||||
gst_buffer_unref (framenode->buf);
|
||||
|
||||
g_slice_free (FrameNode, framenode);
|
||||
}
|
||||
|
||||
static inline void
|
||||
free_streamnode (StreamNode * streamnode)
|
||||
{
|
||||
if (streamnode->caps)
|
||||
gst_caps_unref (streamnode->caps);
|
||||
|
||||
g_list_free_full (streamnode->frames, (GDestroyNotify) free_framenode);
|
||||
|
||||
if (streamnode->pad)
|
||||
gst_object_unref (streamnode->pad);
|
||||
|
||||
if (streamnode->tags)
|
||||
free_tagsnode (streamnode->tags);
|
||||
|
||||
if (streamnode->padname)
|
||||
g_free (streamnode->padname);
|
||||
|
||||
if (streamnode->id)
|
||||
g_free (streamnode->id);
|
||||
|
||||
g_free (streamnode->str_open);
|
||||
g_free (streamnode->str_close);
|
||||
g_slice_free (StreamNode, streamnode);
|
||||
}
|
||||
|
||||
void
|
||||
free_filenode (FileNode * filenode)
|
||||
{
|
||||
g_list_free_full (filenode->streams, (GDestroyNotify) free_streamnode);
|
||||
if (filenode->tags)
|
||||
free_tagsnode (filenode->tags);
|
||||
|
||||
if (filenode->uri)
|
||||
g_free (filenode->uri);
|
||||
|
||||
g_free (filenode->str_open);
|
||||
g_free (filenode->str_close);
|
||||
|
||||
g_slice_free (FileNode, filenode);
|
||||
}
|
||||
|
||||
gboolean
|
||||
tag_node_compare (TagNode * tnode, const GstTagList * tlist)
|
||||
{
|
||||
if (gst_structure_is_equal (GST_STRUCTURE (tlist),
|
||||
GST_STRUCTURE (tnode->taglist)) == FALSE) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
tnode->found = TRUE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
struct _GstMediaDescriptorPrivate
|
||||
{
|
||||
gpointer dummy;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_RUNNER,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
gst_media_descriptor_dispose (GstMediaDescriptor * self)
|
||||
{
|
||||
G_OBJECT_CLASS (gst_media_descriptor_parent_class)->dispose (G_OBJECT (self));
|
||||
}
|
||||
|
||||
static void
|
||||
gst_media_descriptor_finalize (GstMediaDescriptor * self)
|
||||
{
|
||||
if (self->filenode)
|
||||
free_filenode (self->filenode);
|
||||
|
||||
G_OBJECT_CLASS (gst_media_descriptor_parent_class)->
|
||||
finalize (G_OBJECT (self));
|
||||
}
|
||||
|
||||
static void
|
||||
gst_media_descriptor_init (GstMediaDescriptor * self)
|
||||
{
|
||||
self->filenode = g_slice_new0 (FileNode);
|
||||
}
|
||||
|
||||
static void
|
||||
_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
switch (prop_id) {
|
||||
case PROP_RUNNER:
|
||||
/* we assume the runner is valid as long as this scenario is,
|
||||
* no ref taken */
|
||||
gst_validate_reporter_set_runner (GST_VALIDATE_REPORTER (object),
|
||||
g_value_get_object (value));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
switch (prop_id) {
|
||||
case PROP_RUNNER:
|
||||
/* we assume the runner is valid as long as this scenario is,
|
||||
* no ref taken */
|
||||
g_value_set_object (value,
|
||||
gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (object)));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_media_descriptor_class_init (GstMediaDescriptorClass * self_class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (self_class);
|
||||
|
||||
g_type_class_add_private (self_class, sizeof (GstMediaDescriptorPrivate));
|
||||
object_class->dispose =
|
||||
(void (*)(GObject * object)) gst_media_descriptor_dispose;
|
||||
object_class->finalize =
|
||||
(void (*)(GObject * object)) gst_media_descriptor_finalize;
|
||||
|
||||
object_class->get_property = _get_property;
|
||||
object_class->set_property = _set_property;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_RUNNER,
|
||||
g_param_spec_object ("validate-runner", "VALIDATE Runner",
|
||||
"The Validate runner to " "report errors to",
|
||||
GST_TYPE_VALIDATE_RUNNER,
|
||||
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static gint
|
||||
compare_tags (GstMediaDescriptor *ref, StreamNode *rstream, StreamNode *cstream)
|
||||
{
|
||||
gboolean found;
|
||||
TagNode *rtag, *ctag;
|
||||
GList *rtag_list, *ctag_list;
|
||||
TagsNode *rtags, *ctags;
|
||||
|
||||
rtags = rstream->tags;
|
||||
if (rtags == NULL)
|
||||
return 1;
|
||||
|
||||
ctags = cstream->tags;
|
||||
for (rtag_list = rtags->tags; rtag_list; rtag_list = rtag_list->next) {
|
||||
rtag = rtag_list->data;
|
||||
found = FALSE;
|
||||
for (ctag_list = ctags->tags; ctag_list; ctag_list = ctag_list->next) {
|
||||
ctag = ctag_list->data;
|
||||
if (gst_tag_list_is_equal (rtag->taglist, ctag->taglist)) {
|
||||
found = TRUE;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found == FALSE) {
|
||||
gchar *rtaglist = gst_tag_list_to_string (rtag->taglist);
|
||||
|
||||
GST_VALIDATE_REPORT (ref, FILE_PROFILE_INCORRECT,
|
||||
"Reference descriptor for stream %s has tags %s"
|
||||
" but no equivalent taglist was found on the compared stream",
|
||||
rstream->id, rtaglist);
|
||||
g_free (rtaglist);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Return -1 if not found 1 if OK 0 if an error occured */
|
||||
static gint
|
||||
comparse_stream (GstMediaDescriptor *ref, StreamNode *rstream, StreamNode *cstream)
|
||||
{
|
||||
if (g_strcmp0 (rstream->id, cstream->id) == 0) {
|
||||
if (!gst_caps_is_equal (rstream->caps, cstream->caps)) {
|
||||
gchar *rcaps = gst_caps_to_string (rstream->caps),
|
||||
*ccaps = gst_caps_to_string (cstream->caps);
|
||||
GST_VALIDATE_REPORT (ref, FILE_PROFILE_INCORRECT,
|
||||
"Reference descriptor for stream %s has caps: %s"
|
||||
" but compared stream %s has caps: %s",
|
||||
rstream->id, rcaps,
|
||||
cstream->id, ccaps);
|
||||
g_free (rcaps);
|
||||
g_free (ccaps);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return compare_tags (ref, rstream, cstream);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_media_descriptors_compare (GstMediaDescriptor * ref,
|
||||
GstMediaDescriptor * compared)
|
||||
{
|
||||
GList *rstream_list;
|
||||
FileNode *rfilenode = ref->filenode, *cfilenode = compared->filenode;
|
||||
|
||||
if (rfilenode->duration != cfilenode->duration) {
|
||||
GST_VALIDATE_REPORT (ref, FILE_DURATION_INCORRECT,
|
||||
"Duration %" GST_TIME_FORMAT " is different from the reference %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (cfilenode->duration),
|
||||
GST_TIME_ARGS (rfilenode->duration));
|
||||
}
|
||||
|
||||
if (rfilenode->seekable != cfilenode->seekable) {
|
||||
GST_VALIDATE_REPORT (ref, FILE_SEEKABLE_INCORRECT,
|
||||
"File known as %s but is reported %s now",
|
||||
rfilenode->seekable ? "seekable" : "not seekable",
|
||||
cfilenode->seekable ? "seekable" : "not seekable");
|
||||
}
|
||||
|
||||
if (g_list_length (rfilenode->streams) != g_list_length (cfilenode->streams)) {
|
||||
GST_VALIDATE_REPORT (ref, FILE_PROFILE_INCORRECT,
|
||||
"Reference descriptor has %i streams != compared which has %i streams",
|
||||
g_list_length (rfilenode->streams), g_list_length (cfilenode->streams));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
for (rstream_list = rfilenode->streams; rstream_list;
|
||||
rstream_list = rstream_list->next) {
|
||||
GList *cstream_list;
|
||||
gint sfound = -1;
|
||||
|
||||
for (cstream_list = cfilenode->streams; cstream_list;
|
||||
cstream_list = cstream_list->next) {
|
||||
|
||||
sfound = comparse_stream (ref, rstream_list->data, cstream_list->data);
|
||||
if (sfound == 0) {
|
||||
return FALSE;
|
||||
} else if (sfound == 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sfound == FALSE) {
|
||||
GST_VALIDATE_REPORT (ref, FILE_PROFILE_INCORRECT,
|
||||
"Could not find stream %s in the compared descriptor",
|
||||
((StreamNode*) rstream_list->data)->id);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
147
validate/gst/validate/media-descriptor.h
Normal file
147
validate/gst/validate/media-descriptor.h
Normal file
|
@ -0,0 +1,147 @@
|
|||
/**
|
||||
* Gstreamer
|
||||
*
|
||||
* Copyright (c) 2012, Collabora Ltd.
|
||||
* Author: Thibault Saunier <thibault.saunier@collabora.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_MEDIA_DESCRIPTOR_H__
|
||||
#define __GST_MEDIA_DESCRIPTOR_H__
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
#include <gst/gst.h>
|
||||
#include "gst-validate-report.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* Children */
|
||||
/* TagNode */
|
||||
GList *tags;
|
||||
|
||||
gchar *str_open;
|
||||
gchar *str_close;
|
||||
} TagsNode;
|
||||
|
||||
/* Parsing structures */
|
||||
typedef struct
|
||||
{
|
||||
/* Children */
|
||||
/* StreamNode */
|
||||
GList *streams;
|
||||
/* TagsNode */
|
||||
TagsNode *tags;
|
||||
|
||||
/* attributes */
|
||||
guint64 id;
|
||||
gchar *uri;
|
||||
GstClockTime duration;
|
||||
gboolean frame_detection;
|
||||
gboolean seekable;
|
||||
|
||||
GstCaps *caps;
|
||||
|
||||
gchar *str_open;
|
||||
gchar *str_close;
|
||||
} FileNode;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* Children */
|
||||
GstTagList *taglist;
|
||||
|
||||
/* Testing infos */
|
||||
gboolean found;
|
||||
|
||||
gchar *str_open;
|
||||
gchar *str_close;
|
||||
} TagNode;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* Children */
|
||||
/* FrameNode */
|
||||
GList *frames;
|
||||
|
||||
/* TagsNode */
|
||||
TagsNode *tags;
|
||||
|
||||
/* Attributes */
|
||||
GstCaps *caps;
|
||||
gchar *id;
|
||||
gchar *padname;
|
||||
|
||||
/* Testing infos */
|
||||
GstPad *pad;
|
||||
GList *cframe;
|
||||
|
||||
gchar *str_open;
|
||||
gchar *str_close;
|
||||
} StreamNode;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* Attributes */
|
||||
guint64 id;
|
||||
guint64 offset;
|
||||
guint64 offset_end;
|
||||
GstClockTime duration;
|
||||
GstClockTime pts, dts;
|
||||
gboolean is_keyframe;
|
||||
|
||||
GstBuffer *buf;
|
||||
|
||||
gchar *str_open;
|
||||
gchar *str_close;
|
||||
} FrameNode;
|
||||
|
||||
void free_filenode (FileNode * filenode);
|
||||
gboolean tag_node_compare (TagNode * tnode, const GstTagList * tlist);
|
||||
|
||||
GType gst_media_descriptor_get_type (void);
|
||||
|
||||
#define GST_TYPE_MEDIA_DESCRIPTOR (gst_media_descriptor_get_type ())
|
||||
#define GST_MEDIA_DESCRIPTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MEDIA_DESCRIPTOR, GstMediaDescriptor))
|
||||
#define GST_MEDIA_DESCRIPTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MEDIA_DESCRIPTOR, GstMediaDescriptorClass))
|
||||
#define GST_IS_MEDIA_DESCRIPTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MEDIA_DESCRIPTOR))
|
||||
#define GST_IS_MEDIA_DESCRIPTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MEDIA_DESCRIPTOR))
|
||||
#define GST_MEDIA_DESCRIPTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_MEDIA_DESCRIPTOR, GstMediaDescriptorClass))
|
||||
|
||||
typedef struct _GstMediaDescriptorPrivate GstMediaDescriptorPrivate;
|
||||
|
||||
typedef struct {
|
||||
GObject parent;
|
||||
|
||||
FileNode *filenode;
|
||||
|
||||
GstMediaDescriptorPrivate *priv;
|
||||
} GstMediaDescriptor;
|
||||
|
||||
typedef struct {
|
||||
GObjectClass parent;
|
||||
|
||||
} GstMediaDescriptorClass;
|
||||
|
||||
gboolean gst_media_descriptors_compare (GstMediaDescriptor *ref,
|
||||
GstMediaDescriptor *compared);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
|
@ -30,6 +30,9 @@
|
|||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/validate/validate.h>
|
||||
#include <gst/validate/media-descriptor-writer.h>
|
||||
#include <gst/validate/media-descriptor-parser.h>
|
||||
#include <gst/validate/media-descriptor.h>
|
||||
#include <gst/pbutils/encoding-profile.h>
|
||||
|
||||
/* move this into some utils file */
|
||||
|
@ -164,14 +167,15 @@ int
|
|||
main (int argc, gchar ** argv)
|
||||
{
|
||||
GOptionContext *ctx;
|
||||
GstValidateMediaInfo mi;
|
||||
|
||||
GError *err = NULL;
|
||||
guint ret = 0;
|
||||
gchar *output_file = NULL;
|
||||
gchar *expected_file = NULL;
|
||||
gchar *output = NULL;
|
||||
gsize outputlength;
|
||||
gboolean ret, discover_only;
|
||||
GstMediaDescriptorWriter *writer;
|
||||
GstValidateRunner *runner;
|
||||
GstMediaDescriptorParser * reference = NULL;
|
||||
|
||||
GOptionEntry options[] = {
|
||||
{"output-file", 'o', 0, G_OPTION_ARG_FILENAME,
|
||||
|
@ -181,9 +185,6 @@ main (int argc, gchar ** argv)
|
|||
&expected_file, "Path to file containing the expected results "
|
||||
"(or the last results found) for comparison with new results",
|
||||
NULL},
|
||||
{"discover-only", 'e', 0, G_OPTION_ARG_NONE,
|
||||
&discover_only, "Only discover files, no other playback tests",
|
||||
NULL},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
@ -215,50 +216,46 @@ main (int argc, gchar ** argv)
|
|||
}
|
||||
g_option_context_free (ctx);
|
||||
|
||||
gst_validate_media_info_init (&mi);
|
||||
ret = gst_validate_media_info_inspect_uri (&mi, argv[1], discover_only, NULL);
|
||||
output = gst_validate_media_info_to_string (&mi, &outputlength);
|
||||
runner = gst_validate_runner_new ();
|
||||
writer = gst_media_descriptor_writer_new_discover (runner, argv[1], NULL);
|
||||
if (writer == NULL) {
|
||||
g_print ("Could not discover file: %s", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (output_file)
|
||||
gst_validate_media_info_save (&mi, output_file, NULL);
|
||||
gst_media_descriptor_writer_write (writer, output_file);
|
||||
|
||||
if (expected_file) {
|
||||
GstValidateMediaInfo *expected_mi;
|
||||
GError *err = NULL;
|
||||
reference = gst_media_descriptor_parser_new (runner,
|
||||
expected_file, NULL);
|
||||
|
||||
ret = TRUE;
|
||||
if (!g_path_is_absolute (expected_file)) {
|
||||
gchar *cdir = g_get_current_dir ();
|
||||
gchar *absolute = g_build_filename (cdir, expected_file, NULL);
|
||||
if (reference == NULL) {
|
||||
g_print ("Could not parse file: %s", expected_file);
|
||||
gst_object_unref (writer);
|
||||
|
||||
g_free (expected_file);
|
||||
g_free (cdir);
|
||||
|
||||
expected_file = absolute;
|
||||
return 1;
|
||||
}
|
||||
|
||||
expected_mi = gst_validate_media_info_load (expected_file, &err);
|
||||
if (err) {
|
||||
g_print ("Error loading %s: %s", expected_file, err->message);
|
||||
ret = FALSE;
|
||||
} else if (expected_mi) {
|
||||
if (!gst_validate_media_info_compare (expected_mi, &mi)) {
|
||||
g_print ("Expected results didn't match\n");
|
||||
ret = FALSE;
|
||||
}
|
||||
gst_validate_media_info_free (expected_mi);
|
||||
gst_media_descriptors_compare (GST_MEDIA_DESCRIPTOR (reference),
|
||||
GST_MEDIA_DESCRIPTOR (writer));
|
||||
} else {
|
||||
g_print ("Failed to load expected results file: %s\n", err->message);
|
||||
g_error_free (err);
|
||||
ret = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
gst_validate_media_info_clear (&mi);
|
||||
|
||||
output = gst_media_descriptor_writer_serialize (writer);
|
||||
g_print ("Media info:\n%s\n", output);
|
||||
g_free (output);
|
||||
if (!ret)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = gst_validate_runner_printf (runner);
|
||||
if (ret && expected_file) {
|
||||
output = gst_media_descriptor_writer_serialize (writer);
|
||||
g_print ("Media info:\n%s\n", output);
|
||||
g_free (output);
|
||||
}
|
||||
|
||||
if (reference)
|
||||
gst_object_unref (reference);
|
||||
gst_object_unref (writer);
|
||||
gst_object_unref (runner);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue