This commit is contained in:
Akkariin Meiko
2022-03-12 03:16:09 +08:00
Unverified
parent 12b76e0c7a
commit 27c4ec74a1
10075 changed files with 5122287 additions and 1 deletions
@@ -0,0 +1,153 @@
#!/usr/bin/env python3
#
# Copyright (c) 2015, Edward Hervey <edward@centricular.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This program 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the
# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
# Boston, MA 02110-1301, USA.
import os
import sys
import xml.etree.cElementTree
def extract_info(xmlfile):
e = xml.etree.cElementTree.parse(xmlfile).getroot()
r = {}
for i in e:
r[(i.get("classname"), i.get("name"))] = i
return r
if "__main__" == __name__:
if len(sys.argv) < 2:
print("Usage : %s [<old run xml>] <new run xml>" % sys.argv[0])
if len(sys.argv) == 3:
oldfile = extract_info(sys.argv[1])
newfile = extract_info(sys.argv[2])
else:
oldfile = []
newfile = extract_info(sys.argv[1])
# new failures (pass in old run, fail in new run)
newfail = []
# new fixes (fail in old run, pass in new run)
newfix = []
# tests that are still failing
stillfail = []
# tests that are still failling but for a different reason
failchange = []
# failed tests sorted by reason
reasons = {}
# all files
allfiles = []
# failed tests sorted by file
failedfiles = {}
if oldfile:
# tests that weren't present in old run
newtests = [x for x in newfile.keys() if x not in oldfile]
# tests that are no longer present in new run
gonetests = [x for x in oldfile.keys() if x not in newfile]
# go over new tests
for k, v in newfile.iteritems():
tn, fn = k
if not fn in allfiles:
allfiles.append(fn)
newf = v.findall("error")
if newf:
# extract the failure reason
r = newf[0].get("message")
if "Application returned 18" in r or "Application returned -5" in r:
rs = r.split('[')[1].split(']')[0].split(',')
for la in rs:
la = la.strip()
if la not in reasons:
reasons[la] = []
reasons[la].append(k)
if fn not in failedfiles:
failedfiles[fn] = []
failedfiles[fn].append((tn, r))
if k in oldfile:
oldone = oldfile.get(k)
# compare failures
oldf = oldone.findall("error")
if newf and not oldf:
newfail.append(k)
if oldf and not newf:
newfix.append(k)
if oldf and newf:
stillfail.append(k)
a = oldf[0]
b = newf[0]
print a, b
# check if the failure reasons are the same
if a.get("type") != b.get("type"):
failchange.append(k)
elif a.get("message") != b.get("message"):
failchange.append(k)
if newfail:
print("New failures", len(newfail))
newfail.sort()
for i in newfail:
print " %s : %s" % (i[0], i[1])
f = newfile[i].find("error")
print " ", f.get("type"), f.get("message")
print
if newfix:
print "New fixes", len(newfix)
newfix.sort()
for i in newfix:
print " %s : %s" % (i[0], i[1])
print
if failchange:
print "Failure changes", len(failchange)
failchange.sort()
for i in failchange:
print " %s : %s" % (i[0], i[1])
oldt = oldfile[i].find("error").get("type")
newt = newfile[i].find("error").get("type")
if oldt != newt:
print " Went from '%s' to '%s'" % (oldt, newt)
print " Previous message :", oldfile[i].find("error").get("message")
print " New message :", newfile[i].find("error").get("message")
print
for k, v in reasons.iteritems():
print "Failure type : ", k, len(v)
v.sort()
for i in v:
print " %s : %s" % (i[0], i[1])
print
nofailfiles = sorted([fn for fn in allfiles if fn not in failedfiles])
if nofailfiles:
print "Files without failures", len(nofailfiles)
for f in nofailfiles:
print " ", f
print
for k, v in failedfiles.iteritems():
print "Failed File :", k
for i in v:
print " %s : %s" % (i[0], i[1])
@@ -0,0 +1,122 @@
/* GStreamer
*
* Copyright (C) 2014 Mathieu Duponchelle <mathieu.duponchelle@opencreed.com>
* Copyright (C) 2015 Raspberry Pi Foundation
* 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 Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "../gst-libs/gst/video/gstvalidatessim.h"
#include <gst/gst.h>
#include <gst/validate/validate.h>
#include <gst/video/video.h>
#include <locale.h> /* for LC_ALL */
int
main (int argc, char **argv)
{
GstValidateSsim *ssim;
gint rep_err, ret = 0;
GError *err = NULL;
GstValidateRunner *runner = NULL;
GOptionContext *ctx;
gchar *outfolder = NULL;
gfloat mssim = 0, lowest = 1, highest = -1;
gdouble min_avg_similarity = 0.95, min_lowest_similarity = -1.0;
GOptionEntry options[] = {
{"min-avg-similarity", 'a', 0, G_OPTION_ARG_DOUBLE,
&min_avg_similarity,
"The minimum average similarity under which we consider"
" the test as failing",
NULL},
{"min-lowest-similarity", 'l', 0, G_OPTION_ARG_DOUBLE,
&min_lowest_similarity,
"The minimum 'lowest' similarity under which we consider"
" the test as failing",
NULL},
{"result-output-folder", 'r', 0, G_OPTION_ARG_FILENAME,
&outfolder,
"The folder in which to store resulting grey scale images"
" when the test failed. In that folder you will find"
" images with the structural difference between"
" the reference frame and the failed one",
NULL},
{NULL}
};
setlocale (LC_ALL, "");
g_set_prgname ("gst-validate-images-check-" GST_API_VERSION);
ctx = g_option_context_new ("/reference/file/path /compared/file/path");
g_option_context_set_summary (ctx,
"The gst-validate-images-check calculates SSIM (Structural SIMilarity)"
" index for the images. And according to min-lowest-similarity and"
" min-avg-similarity, it will consider the images similar enough"
" or report critical issues in the GstValidate reporting system");
g_option_context_add_main_entries (ctx, options, NULL);
if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
g_printerr ("Error initializing: %s\n", err->message);
g_option_context_free (ctx);
g_clear_error (&err);
return -1;
}
if (argc != 3) {
gchar *help = g_option_context_get_help (ctx, FALSE, NULL);
g_printerr ("%s", help);
g_free (help);
g_option_context_free (ctx);
return -1;
}
gst_init (&argc, &argv);
gst_validate_init ();
runner = gst_validate_runner_new ();
ssim =
gst_validate_ssim_new (runner, min_avg_similarity, min_lowest_similarity,
0, 1);
gst_validate_ssim_compare_image_files (ssim, argv[1], argv[2], &mssim,
&lowest, &highest, outfolder);
if (!g_file_test (argv[1], G_FILE_TEST_IS_DIR)) {
gst_validate_printf (ssim, "Compared %s with %s, average: %f, Min %f\n",
argv[1], argv[2], mssim, lowest);
}
rep_err = gst_validate_runner_exit (runner, TRUE);
if (ret == 0) {
ret = rep_err;
if (rep_err != 0)
gst_validate_printf (NULL, "Returning %d as error where found", rep_err);
}
g_object_unref (ssim);
g_object_unref (runner);
gst_validate_deinit ();
gst_validate_printf (NULL, "\n=======> Test %s (Return value: %i)\n\n",
ret == 0 ? "PASSED" : "FAILED", ret);
return ret;
}
@@ -0,0 +1,55 @@
#!/usr/bin/env python3
#
# Copyright (c) 2014,Thibault Saunier <thibault.saunier@collabora.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This program 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the
# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
# Boston, MA 02110-1301, USA.
import os
import subprocess
import sys
LIBDIR = r'@LIBDIR@'
BUILDDIR = r'@BUILDDIR@'
SRCDIR = r'@SRCDIR@'
def _add_gst_launcher_path():
f = os.path.abspath(__file__)
if f.startswith(BUILDDIR):
# Make sure to have the configured config.py in the python path
sys.path.insert(0, os.path.abspath(os.path.join(BUILDDIR, "..")))
root = os.path.abspath(os.path.join(SRCDIR, "../"))
else:
root = os.path.join(LIBDIR, 'gst-validate-launcher', 'python')
sys.path.insert(0, root)
return os.path.join(root, "launcher")
if "__main__" == __name__:
libsdir = _add_gst_launcher_path()
from launcher.main import main
run_profile = os.environ.get('GST_VALIDATE_LAUNCHER_PROFILING', False)
if run_profile:
import cProfile
prof = cProfile.Profile()
try:
res = prof.runcall(main, libsdir)
finally:
prof.dump_stats('gst-validate-launcher-runstats')
exit(res)
exit(main(libsdir))
@@ -0,0 +1,187 @@
/* GStreamer
*
* Copyright (C) 2013 Collabora Ltd.
* Author: Thiago Sousa Santos <thiago.sousa.santos@collabora.com>
*
* gst-validate-media-check.c - Media Check CLI tool
*
* 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.1 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#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/validate/gst-validate-utils.h>
#include <gst/pbutils/encoding-profile.h>
#include <locale.h> /* for LC_ALL */
int
main (int argc, gchar ** argv)
{
GOptionContext *ctx;
guint ret = 0;
GError *err = NULL;
gboolean full = FALSE;
gboolean skip_parsers = FALSE;
gchar *output_file = NULL;
gchar *expected_file = NULL;
gchar *output = NULL;
GstValidateMediaDescriptorWriterFlags writer_flags =
GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER_FLAGS_HANDLE_GLOGS;
GstValidateMediaDescriptorWriter *writer = NULL;
GstValidateRunner *runner = NULL;
GstValidateMediaDescriptorParser *reference = NULL;
GOptionEntry options[] = {
{"output-file", 'o', 0, G_OPTION_ARG_FILENAME,
&output_file, "The output file to store the results",
NULL},
{"full", 'f', 0, G_OPTION_ARG_NONE,
&full, "Fully analyze the file frame by frame",
NULL},
{"expected-results", 'e', 0, G_OPTION_ARG_FILENAME,
&expected_file, "Path to file containing the expected results "
"(or the last results found) for comparison with new results",
NULL},
{"skip-parsers", 's', 0, G_OPTION_ARG_NONE,
&skip_parsers, "Do not plug a parser after demuxer.",
NULL},
{NULL}
};
setlocale (LC_ALL, "");
g_set_prgname ("gst-validate-media-check-" GST_API_VERSION);
ctx = g_option_context_new ("[URI]");
g_option_context_set_summary (ctx, "Analyzes a media file and writes "
"the results to stdout or a file. Can also compare the results found "
"with another results file for identifying regressions. The monitoring"
" lib from gst-validate will be enabled during the tests to identify "
"issues with the gstreamer elements involved with the media file's "
"container and codec types");
g_option_context_add_main_entries (ctx, options, NULL);
if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
g_printerr ("Error initializing: %s\n", err->message);
g_option_context_free (ctx);
g_clear_error (&err);
exit (1);
}
gst_init (&argc, &argv);
gst_validate_init ();
if (argc != 2) {
gchar *msg = g_option_context_get_help (ctx, TRUE, NULL);
g_printerr ("%s\n", msg);
g_free (msg);
g_option_context_free (ctx);
ret = 1;
goto out;
}
g_option_context_free (ctx);
gst_validate_spin_on_fault_signals ();
runner = gst_validate_runner_new ();
if (expected_file) {
reference =
gst_validate_media_descriptor_parser_new (runner, expected_file, NULL);
if (reference == NULL) {
gst_validate_printf (NULL, "Could not parse file: %s\n", expected_file);
ret = 1;
goto out;
}
if (!full
&&
gst_validate_media_descriptor_has_frame_info (
(GstValidateMediaDescriptor *)
reference))
full = TRUE; /* Reference has frame info, activate to do comparison */
}
if (full)
writer_flags |= GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER_FLAGS_FULL;
if (skip_parsers)
writer_flags |= GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER_FLAGS_NO_PARSER;
writer =
gst_validate_media_descriptor_writer_new_discover (runner, argv[1],
writer_flags, NULL);
if (writer == NULL) {
gst_validate_printf (NULL, "Could not discover file: %s\n", argv[1]);
ret = 1;
goto out;
}
if (output_file) {
if (!gst_validate_media_descriptor_writer_write (writer, output_file)) {
ret = 1;
goto out;
}
}
if (reference) {
if (!gst_validate_media_descriptors_compare (GST_VALIDATE_MEDIA_DESCRIPTOR
(reference), GST_VALIDATE_MEDIA_DESCRIPTOR (writer))) {
ret = 1;
goto out;
}
} else {
output = gst_validate_media_descriptor_writer_serialize (writer);
gst_validate_printf (NULL, "Media info:\n%s\n", output);
g_free (output);
}
out:
if (runner)
ret += gst_validate_runner_exit (runner, TRUE);
g_free (output_file);
g_free (expected_file);
if (reference) {
gst_validate_reporter_purge_reports (GST_VALIDATE_REPORTER (reference));
gst_object_unref (reference);
}
if (writer) {
gst_validate_reporter_purge_reports (GST_VALIDATE_REPORTER (writer));
gst_object_unref (writer);
}
if (runner)
gst_object_unref (runner);
gst_validate_deinit ();
gst_deinit ();
gst_validate_printf (NULL, "\n=======> Test %s (Return value: %i)\n\n",
ret == 0 ? "PASSED" : "FAILED", ret);
return ret;
}
@@ -0,0 +1,159 @@
/* GStreamer
* Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.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.
*/
/* Cc'd from the test-uri example */
#include <gst/gst.h>
#include <gst/validate/validate.h>
#include <gst/rtsp-server/rtsp-server.h>
#include <gst/rtsp-server/rtsp-media-factory-uri.h>
#define DEFAULT_RTSP_PORT "8554"
static char *port = (char *) DEFAULT_RTSP_PORT;
static GOptionEntry entries[] = {
{"port", 'p', 0, G_OPTION_ARG_STRING, &port,
"Port to listen on (default: " DEFAULT_RTSP_PORT ")", "PORT"},
{NULL}
};
static gboolean
timeout (GstRTSPServer * server)
{
GstRTSPSessionPool *pool;
pool = gst_rtsp_server_get_session_pool (server);
gst_rtsp_session_pool_cleanup (pool);
g_object_unref (pool);
return TRUE;
}
#if 0
static gboolean
remove_map (GstRTSPServer * server)
{
GstRTSPMountPoints *mounts;
gst_validate_printf (NULL, "removing /test mount point\n");
mounts = gst_rtsp_server_get_mount_points (server);
gst_rtsp_mount_points_remove_factory (mounts, "/test");
g_object_unref (mounts);
return FALSE;
}
#endif
int
main (int argc, gchar * argv[])
{
GMainLoop *loop;
GstRTSPServer *server;
GstRTSPMountPoints *mounts;
GstRTSPMediaFactoryURI *factory;
GOptionContext *optctx;
GError *error = NULL;
gchar *uri;
optctx = g_option_context_new ("<uri> - GstValidate RTSP server, URI");
g_option_context_add_main_entries (optctx, entries, NULL);
g_option_context_add_group (optctx, gst_init_get_option_group ());
if (!g_option_context_parse (optctx, &argc, &argv, &error)) {
g_printerr ("Error parsing options: %s\n", error->message);
g_option_context_free (optctx);
g_clear_error (&error);
return -1;
}
g_option_context_free (optctx);
if (argc < 2) {
g_printerr ("Please pass an URI or file as argument!\n");
return -1;
}
loop = g_main_loop_new (NULL, FALSE);
/* create a server instance */
server = gst_rtsp_server_new ();
g_object_set (server, "service", port, NULL);
/* get the mount points for this server, every server has a default object
* that be used to map uri mount points to media factories */
mounts = gst_rtsp_server_get_mount_points (server);
/* make a URI media factory for a test stream. */
factory = gst_rtsp_media_factory_uri_new ();
/* when using GStreamer as a client, one can use the gst payloader, which is
* more efficient when there is no payloader for the compressed format */
/* g_object_set (factory, "use-gstpay", TRUE, NULL); */
/* check if URI is valid, otherwise convert filename to URI if it's a file */
if (gst_uri_is_valid (argv[1])) {
uri = g_strdup (argv[1]);
} else if (g_file_test (argv[1], G_FILE_TEST_EXISTS)) {
uri = gst_filename_to_uri (argv[1], NULL);
} else {
g_printerr ("Unrecognised command line argument '%s'.\n"
"Please pass an URI or file as argument!\n", argv[1]);
return -1;
}
gst_rtsp_media_factory_uri_set_uri (factory, uri);
g_free (uri);
/* if you want multiple clients to see the same video, set the shared property
* to TRUE */
/* gst_rtsp_media_factory_set_shared ( GST_RTSP_MEDIA_FACTORY (factory), TRUE); */
/* attach the test factory to the /test url */
gst_rtsp_mount_points_add_factory (mounts, "/test",
GST_RTSP_MEDIA_FACTORY (factory));
/* don't need the ref to the mapper anymore */
g_object_unref (mounts);
/* attach the server to the default maincontext */
if (gst_rtsp_server_attach (server, NULL) == 0)
goto failed;
/* do session cleanup every 2 seconds */
g_timeout_add_seconds (2, (GSourceFunc) timeout, server);
#if 0
/* remove the mount point after 10 seconds, new clients won't be able to use
* the /test url anymore */
g_timeout_add_seconds (10, (GSourceFunc) remove_map, server);
#endif
/* start serving */
g_print ("stream ready at rtsp://127.0.0.1:%s/test\n", port);
g_main_loop_run (loop);
return 0;
/* ERRORS */
failed:
{
g_print ("failed to attach the server\n");
return -1;
}
}
@@ -0,0 +1,389 @@
/* GStreamer
*
* Copyright (C) 2013 Collabora Ltd.
* Author: Thibault Saunier <thibault.saunier@collabora.com>
*
* gst-validate-transcoding.c - CLI tool to validate transcoding operations
*
* 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.1 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <locale.h> /* for LC_ALL */
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/validate/gst-validate-utils.h>
#include <gst/validate/validate.h>
#include <gst/pbutils/encoding-profile.h>
#include <gst/transcoder/gsttranscoder.h>
#ifdef G_OS_UNIX
#include <glib-unix.h>
#endif
#include <gst/validate/gst-validate-scenario.h>
#include <gst/validate/gst-validate-bin-monitor.h>
static gint ret = 0;
static GstValidateMonitor *monitor = NULL;
static GstValidateRunner *runner = NULL;
static GstTranscoder *transcoder = NULL;
static gboolean eos_on_shutdown = FALSE;
static gint
finish_transcoding (GstElement * pipeline, gint ret)
{
int rep_err;
if (!runner) {
ret = 1;
goto done;
}
rep_err = gst_validate_runner_exit (runner, TRUE);
if (ret == 0)
ret = rep_err;
gst_clear_object (&transcoder);
gst_clear_object (&pipeline);
gst_validate_reporter_purge_reports (GST_VALIDATE_REPORTER (monitor));
g_object_unref (monitor);
g_object_unref (runner);
gst_validate_deinit ();
gst_deinit ();
done:
g_print ("\n=======> Test %s (Return value: %i)\n\n",
ret == 0 ? "PASSED" : "FAILED", ret);
exit (ret);
return ret;
}
#ifdef G_OS_UNIX
static gboolean
intr_handler (GstElement * pipeline)
{
GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline),
GST_DEBUG_GRAPH_SHOW_ALL, "gst-validate.interrupted");
if (eos_on_shutdown) {
eos_on_shutdown = FALSE;
gst_element_send_event (pipeline, gst_event_new_eos ());
return TRUE;
}
finish_transcoding (pipeline, 1);
/* remove signal handler */
return FALSE;
}
#endif /* G_OS_UNIX */
static gboolean
_execute_set_restriction (GstValidateScenario * scenario,
GstValidateAction * action)
{
GstCaps *caps;
GType profile_type = G_TYPE_NONE;
const gchar *restriction_caps, *profile_type_name, *profile_name;
GstElement *pipeline = gst_validate_scenario_get_pipeline (scenario);
GstEncodingProfile *encoding_profile;
g_object_get (pipeline, "profile", &encoding_profile, NULL);
restriction_caps =
gst_structure_get_string (action->structure, "restriction-caps");
profile_type_name =
gst_structure_get_string (action->structure, "profile-type");
profile_name = gst_structure_get_string (action->structure, "profile-name");
if (profile_type_name) {
profile_type = g_type_from_name (profile_type_name);
if (profile_type == G_TYPE_NONE) {
gst_validate_abort ("Profile name %s not known", profile_name);
return FALSE;
} else if (profile_type == GST_TYPE_ENCODING_CONTAINER_PROFILE) {
gst_validate_abort ("Can not set restrictions on container profiles");
return FALSE;
}
} else if (profile_name == NULL) {
if (g_strrstr (restriction_caps, "audio/x-raw") == restriction_caps)
profile_type = GST_TYPE_ENCODING_AUDIO_PROFILE;
else if (g_strrstr (restriction_caps, "video/x-raw") == restriction_caps)
profile_type = GST_TYPE_ENCODING_VIDEO_PROFILE;
else {
g_error
("No information on what profiles to apply action, you should set either "
"profile_name or profile_type_name and the caps %s give us no hint",
restriction_caps);
return FALSE;
}
}
caps = gst_caps_from_string (restriction_caps);
if (caps == NULL) {
gst_validate_abort ("Could not parse caps: %s", restriction_caps);
return FALSE;
}
if (GST_IS_ENCODING_CONTAINER_PROFILE (encoding_profile)) {
gboolean found = FALSE;
const GList *tmp;
for (tmp =
gst_encoding_container_profile_get_profiles
(GST_ENCODING_CONTAINER_PROFILE (encoding_profile)); tmp;
tmp = tmp->next) {
GstEncodingProfile *profile = tmp->data;
if (profile_type != G_TYPE_NONE
&& G_OBJECT_TYPE (profile) == profile_type) {
gst_encoding_profile_set_restriction (profile, gst_caps_copy (caps));
found = TRUE;
} else if (profile_name
&& g_strcmp0 (gst_encoding_profile_get_name (profile),
profile_name) == 0) {
gst_encoding_profile_set_restriction (profile, gst_caps_copy (caps));
found = TRUE;
}
}
if (!found) {
gst_validate_abort ("Could not find profile for %s%s",
profile_type_name ? profile_type_name : "",
profile_name ? profile_name : "");
gst_caps_unref (caps);
return FALSE;
}
}
if (profile_type != G_TYPE_NONE) {
gst_validate_printf (action,
"setting caps to %s on profiles of type %s\n",
restriction_caps, g_type_name (profile_type));
} else {
gst_validate_printf (action, "setting caps to %s on profile %s\n",
restriction_caps, profile_name);
}
gst_caps_unref (caps);
return TRUE;
}
static void
_register_actions (void)
{
/* *INDENT-OFF* */
gst_validate_register_action_type ("set-restriction", "validate-transcoding", _execute_set_restriction,
(GstValidateActionParameter []) {
{
.name = "restriction-caps",
.description = "The restriction caps to set on the encodebin "
"encoding profile.\nSee gst_encoding_profile_set_restriction()",
.mandatory = TRUE,
.types = "GstCaps serialized as a string"
},
{NULL}
},
"Change the restriction caps on the fly",
FALSE);
/* *INDENT-ON* */
}
int
main (int argc, gchar ** argv)
{
guint i;
GOptionContext *ctx;
gchar *output_file = NULL;
const gchar *profile_str;
GError *err = NULL;
gchar *scenario = NULL, *configs = NULL;
gboolean want_help = FALSE;
gboolean list_scenarios = FALSE, inspect_action_type = FALSE;
GstElement *pipeline = NULL;
gboolean force_reencoding = TRUE;
GOptionEntry options[] = {
{"output-format", 'o', 0, G_OPTION_ARG_STRING, &profile_str,
"Set the properties to use for the encoding profile "
"(in case of transcoding.) For example:\n"
"video/mpegts:video/x-raw-yuv,width=1920,height=1080->video/x-h264:audio/x-ac3\n"
"A preset name can be used by adding +presetname, eg:\n"
"video/webm:video/x-vp8+mypreset:audio/x-vorbis\n"
"The presence property of the profile can be specified with |<presence>, eg:\n"
"video/webm:video/x-vp8|<presence>:audio/x-vorbis\n",
"properties-values"},
{"set-scenario", '\0', 0, G_OPTION_ARG_FILENAME, &scenario,
"Let you set a scenario, it can be a full path to a scenario file"
" or the name of the scenario (name of the file without the"
" '.scenario' extension).", NULL},
{"set-configs", '\0', 0, G_OPTION_ARG_STRING, &configs,
"Select a config scenario (one including 'is-config=true' in its"
" description). Specify multiple ones using ':' as separator."
" This option overrides the GST_VALIDATE_SCENARIO environment variable.",
NULL},
{"list-scenarios", 'l', 0, G_OPTION_ARG_NONE, &list_scenarios,
"List the available scenarios that can be run", NULL},
{"inspect-action-type", 't', 0, G_OPTION_ARG_NONE, &inspect_action_type,
"Inspect the available action types with which to write scenarios"
" if no parameter passed, it will list all available action types"
" otherwise will print the full description of the wanted types",
NULL},
{"scenarios-defs-output-file", '\0', 0, G_OPTION_ARG_FILENAME,
&output_file, "The output file to store scenarios details. "
"Implies --list-scenarios",
NULL},
{"force-reencoding", 'r', 0, G_OPTION_ARG_NONE, &force_reencoding,
"Whether to try to force reencoding, meaning trying to only remux "
"if possible(default: TRUE)", NULL},
{"eos-on-shutdown", 'e', 0, G_OPTION_ARG_NONE, &eos_on_shutdown,
"If an EOS event should be sent to the pipeline if an interrupt is "
"received, instead of forcing the pipeline to stop. Sending an EOS "
"will allow the transcoding to finish the files properly before "
"exiting.", NULL},
{NULL}
};
setlocale (LC_ALL, "");
/* There is a bug that make gst_init remove the help param when initializing,
* it is FIXED in 1.0 */
for (i = 1; i < argc; i++) {
if (!g_strcmp0 (argv[i], "--help") || !g_strcmp0 (argv[i], "-h"))
want_help = TRUE;
}
if (!want_help)
gst_init (&argc, &argv);
g_set_prgname ("gst-validate-transcoding-" GST_API_VERSION);
ctx = g_option_context_new ("[input-uri] [output-uri]");
g_option_context_set_summary (ctx, "Transcodes input-uri to output-uri, "
"using the given encoding profile. The pipeline will be monitored for "
"possible issues detection using the gst-validate lib."
"\nCan also perform file conformance "
"tests after transcoding to make sure the result is correct");
g_option_context_add_main_entries (ctx, options, NULL);
if (want_help) {
g_option_context_add_group (ctx, gst_init_get_option_group ());
}
if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
g_printerr ("Error initializing: %s\n", err->message);
g_option_context_free (ctx);
g_clear_error (&err);
exit (1);
}
g_option_context_free (ctx);
if (want_help)
exit (0);
if (scenario || configs) {
gchar *scenarios;
if (scenario)
scenarios = g_strjoin (":", scenario, configs, NULL);
else
scenarios = g_strdup (configs);
g_setenv ("GST_VALIDATE_SCENARIO", scenarios, TRUE);
g_free (scenarios);
}
gst_validate_init ();
if (list_scenarios || output_file) {
if (gst_validate_list_scenarios (argv + 1, argc - 1, output_file))
return 1;
return 0;
}
_register_actions ();
if (inspect_action_type) {
if (gst_validate_print_action_types ((const gchar **) argv + 1, argc - 1))
return 0;
return -1;
}
if (argc != 3) {
g_printerr ("%i arguments received, 2 expected.\n"
"You should run the test using:\n"
" ./gst-validate-transcoding-1.0 <input-uri> <output-uri> [options]\n",
argc - 1);
return 1;
}
if (profile_str == NULL) {
GST_INFO ("Creating default encoding profile");
profile_str = "application/ogg:video/x-theora:audio/x-vorbis";
}
transcoder = gst_transcoder_new (argv[1], argv[2], profile_str);
gst_transcoder_set_avoid_reencoding (transcoder, !force_reencoding);
/* Create the pipeline */
runner = gst_validate_runner_new ();
pipeline = gst_transcoder_get_pipeline (transcoder);
#ifdef G_OS_UNIX
g_unix_signal_add (SIGINT, (GSourceFunc) intr_handler, pipeline);
#endif
gst_validate_spin_on_fault_signals ();
monitor =
gst_validate_monitor_factory_create (GST_OBJECT_CAST (pipeline), runner,
NULL);
gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor));
if (!runner) {
gst_object_unref (pipeline);
gst_object_unref (transcoder);
g_printerr ("Failed to setup Validate Runner\n");
exit (1);
}
if (!gst_transcoder_run (transcoder, &err)) {
ret = -1;
GST_ERROR ("\nFAILURE: %s", err->message);
}
return finish_transcoding (pipeline, ret);
}
@@ -0,0 +1,631 @@
/* GStreamer
*
* Copyright (C) 2013 Collabora Ltd.
* Author: Thiago Sousa Santos <thiago.sousa.santos@collabora.com>
*
* gst-validate.c - Validate CLI launch line tool
*
* 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.1 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <gst/gst.h>
#include <gio/gio.h>
#include <gst/validate/validate.h>
#include <gst/validate/gst-validate-scenario.h>
#include <gst/validate/gst-validate-utils.h>
#include <gst/validate/media-descriptor-parser.h>
#include <gst/validate/gst-validate-bin-monitor.h>
#include <gst/validate/gst-validate-pipeline-monitor.h>
#ifdef G_OS_UNIX
#include <glib-unix.h>
#endif
#include <locale.h> /* for LC_ALL */
static gint ret = 0;
static GMainLoop *mainloop;
static GstElement *pipeline;
static gboolean is_testfile;
static gboolean buffering = FALSE;
static gboolean is_live = FALSE;
#ifdef G_OS_UNIX
static gboolean
intr_handler (gpointer user_data)
{
gst_validate_printf (NULL, "interrupt received.\n");
GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline),
GST_DEBUG_GRAPH_SHOW_ALL, "gst-validate.interrupted");
g_main_loop_quit (mainloop);
ret = SIGINT;
/* Keep signal handler, it will be removed later anyway */
return TRUE;
}
#endif /* G_OS_UNIX */
typedef struct
{
GMainLoop *mainloop;
GstValidateMonitor *monitor;
} BusCallbackData;
static gboolean
bus_callback (GstBus * bus, GstMessage * message, gpointer data)
{
BusCallbackData *bus_callback_data = data;
GMainLoop *loop = bus_callback_data->mainloop;
GstValidateMonitor *monitor = bus_callback_data->monitor;
switch (GST_MESSAGE_TYPE (message)) {
case GST_MESSAGE_ERROR:
{
GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline),
GST_DEBUG_GRAPH_SHOW_ALL, "gst-validate.error");
g_main_loop_quit (loop);
break;
}
case GST_MESSAGE_EOS:
if (!g_getenv ("GST_VALIDATE_SCENARIO") && !is_testfile)
g_main_loop_quit (loop);
break;
case GST_MESSAGE_ASYNC_DONE:
break;
case GST_MESSAGE_LATENCY:
gst_bin_recalculate_latency (GST_BIN (pipeline));
break;
case GST_MESSAGE_STATE_CHANGED:
if (GST_MESSAGE_SRC (message) == GST_OBJECT (pipeline)) {
GstState oldstate, newstate, pending;
gchar *dump_name;
gchar *state_transition_name;
gst_message_parse_state_changed (message, &oldstate, &newstate,
&pending);
GST_DEBUG ("State changed (old: %s, new: %s, pending: %s)",
gst_element_state_get_name (oldstate),
gst_element_state_get_name (newstate),
gst_element_state_get_name (pending));
state_transition_name = g_strdup_printf ("%s_%s",
gst_element_state_get_name (oldstate),
gst_element_state_get_name (newstate));
dump_name = g_strconcat ("gst-validate.", state_transition_name, NULL);
GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline),
GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
g_free (dump_name);
g_free (state_transition_name);
}
break;
case GST_MESSAGE_WARNING:{
GError *gerror;
gchar *debug;
gchar *name = gst_object_get_path_string (GST_MESSAGE_SRC (message));
/* dump graph on warning */
GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline),
GST_DEBUG_GRAPH_SHOW_ALL, "gst-validate.warning");
gst_message_parse_warning (message, &gerror, &debug);
gst_validate_printf (NULL, "WARNING: from element %s: %s\n", name,
gerror->message);
if (debug)
gst_validate_printf (NULL, "Additional debug info:\n%s\n", debug);
g_clear_error (&gerror);
g_free (debug);
g_free (name);
break;
}
case GST_MESSAGE_BUFFERING:{
gint percent;
GstBufferingMode mode;
GstState target_state = GST_STATE_PLAYING;
gboolean monitor_handles_state;
g_object_get (monitor, "handles-states", &monitor_handles_state, NULL);
if (monitor_handles_state && GST_IS_VALIDATE_BIN_MONITOR (monitor)) {
target_state =
gst_validate_scenario_get_target_state (GST_VALIDATE_BIN_MONITOR
(monitor)->scenario);
}
if (!buffering) {
gst_validate_printf (NULL, "\n");
}
gst_message_parse_buffering (message, &percent);
gst_message_parse_buffering_stats (message, &mode, NULL, NULL, NULL);
/* no state management needed for live pipelines */
if (mode == GST_BUFFERING_LIVE) {
is_live = TRUE;
break;
}
if (percent == 100) {
/* a 100% message means buffering is done */
if (buffering) {
buffering = FALSE;
if (target_state == GST_STATE_PLAYING) {
gst_element_set_state (pipeline, GST_STATE_PLAYING);
}
}
} else {
/* buffering... */
if (!buffering) {
gst_element_set_state (pipeline, GST_STATE_PAUSED);
buffering = TRUE;
}
}
break;
}
case GST_MESSAGE_REQUEST_STATE:
{
GstState state;
gst_message_parse_request_state (message, &state);
if (GST_IS_VALIDATE_SCENARIO (GST_MESSAGE_SRC (message))
&& state == GST_STATE_NULL) {
gst_validate_printf (GST_MESSAGE_SRC (message),
"State change request NULL, quitting mainloop\n");
g_main_loop_quit (mainloop);
}
break;
}
default:
break;
}
return TRUE;
}
static gboolean
_is_playbin_pipeline (int argc, gchar ** argv)
{
gint i;
for (i = 0; i < argc; i++) {
if (g_ascii_strncasecmp (argv[i], "playbin", 7) == 0) {
return TRUE;
}
}
return FALSE;
}
static gboolean
_execute_set_subtitles (GstValidateScenario * scenario,
GstValidateAction * action)
{
gchar *uri, *fname;
GFile *tmpfile, *folder;
const gchar *subtitle_file, *subtitle_dir;
GstElement *pipeline = gst_validate_scenario_get_pipeline (scenario);
if (pipeline == NULL) {
GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR,
"Can't execute a '%s' action after the pipeline "
"has been destroyed.", action->type);
return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED;
}
subtitle_file = gst_structure_get_string (action->structure, "subtitle-file");
if (subtitle_file == NULL) {
GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR,
"No 'subtitle-file' specified in 'set-subtile'");
gst_object_unref (pipeline);
return GST_VALIDATE_EXECUTE_ACTION_ERROR;
}
subtitle_dir = gst_structure_get_string (action->structure, "subtitle-dir");
g_object_get (pipeline, "current-uri", &uri, NULL);
tmpfile = g_file_new_for_uri (uri);
g_free (uri);
folder = g_file_get_parent (tmpfile);
fname = g_strdup_printf ("%s%s%s%s",
subtitle_dir ? subtitle_dir : "",
subtitle_dir ? G_DIR_SEPARATOR_S : "",
g_file_get_basename (tmpfile), subtitle_file);
gst_object_unref (tmpfile);
tmpfile = g_file_get_child (folder, fname);
g_free (fname);
gst_object_unref (folder);
uri = g_file_get_uri (tmpfile);
gst_validate_printf (action, "Setting subtitle file to: %s", uri);
g_object_set (pipeline, "suburi", uri, NULL);
g_free (uri);
gst_object_unref (pipeline);
return TRUE;
}
static void
_register_playbin_actions (void)
{
/* *INDENT-OFF* */
gst_validate_register_action_type ("set-subtitle", "validate-launcher", _execute_set_subtitles,
(GstValidateActionParameter []) {
{
.name = "subtitle-file",
.description = "Sets a subtitles file on a playbin pipeline",
.mandatory = TRUE,
.types = "string (A URI)",
NULL
},
{NULL}
},
"Action to set a subtitle file to use on a playbin pipeline.\n"
"The subtitles file that will be used should be specified\n"
"relative to the playbin URI in use thanks to the subtitle-file\n"
"action property. You can also specify a folder with subtitle-dir\n"
"For example if playbin.uri='file://some/uri.mov'\n"
"and action looks like 'set-subtitle, subtitle-file=en.srt'\n"
"the subtitle URI will be set to 'file:///some/uri.mov.en.srt'\n",
FALSE);
/* *INDENT-ON* */
}
int main (int argc, gchar ** argv);
static int
run_test_from_file (gchar * testfile, gboolean use_fakesinks)
{
gint argc, ret;
gchar **args, **argv;
GstStructure *meta = gst_validate_setup_test_file (testfile, use_fakesinks);
args = gst_validate_utils_get_strv (meta, "args");
if (!args)
gst_validate_abort ("No 'args' in .validatetest meta structure: %s",
gst_structure_to_string (meta));
for (argc = 0; args[argc]; argc++);
argc++;
argv = g_new0 (char *, argc + 1);
argv[0] = (gchar *) "gst-validate-" GST_API_VERSION;
memcpy (&argv[1], args, sizeof (char *) * (argc));
ret = main (argc, argv);
g_strfreev (args);
g_free (argv);
g_free (testfile);
return ret;
}
int
main (int argc, gchar ** argv)
{
GError *err = NULL;
gchar *scenario = NULL, *configs = NULL, *media_info = NULL,
*verbosity = NULL, *testfile = NULL;
gboolean list_scenarios = FALSE, monitor_handles_state,
inspect_action_type = FALSE, print_issue_types = FALSE;
GstStateChangeReturn sret;
gchar *output_file = NULL;
BusCallbackData bus_callback_data = { 0, };
gboolean use_fakesinks = FALSE;
#ifdef G_OS_UNIX
guint signal_watch_id;
#endif
int rep_err;
GOptionEntry options[] = {
{"set-test-file", '\0', 0, G_OPTION_ARG_FILENAME, &testfile,
"Let you set a all container testfile", NULL},
{"set-scenario", '\0', 0, G_OPTION_ARG_FILENAME, &scenario,
"Let you set a scenario, it can be a full path to a scenario file"
" or the name of the scenario (name of the file without the"
" '.scenario' extension).", NULL},
{"list-scenarios", 'l', 0, G_OPTION_ARG_NONE, &list_scenarios,
"List the available scenarios that can be run", NULL},
{"use-fakesinks", 'm', 0, G_OPTION_ARG_NONE, &use_fakesinks,
"Use fakesinks when possible. This will have effect when using"
" test files.", NULL},
{"verbosity", 'v', 0, G_OPTION_ARG_STRING, &verbosity,
"Set overall verbosity as defined by GstValidateVerbosityFlags"
" as a string", NULL},
{"scenarios-defs-output-file", '\0', 0, G_OPTION_ARG_FILENAME,
&output_file, "The output file to store scenarios details. "
"Implies --list-scenarios",
NULL},
{"inspect-action-type", 't', 0, G_OPTION_ARG_NONE, &inspect_action_type,
"Inspect the available action types with which to write scenarios."
" Specify an action type if you want its full description."
" If no action type is given the full list of available ones gets printed."
"Note that passing \"all\" as action type name, makes it output the"
" full documentation for all types.",
NULL},
{"print-issue-types", '\0', 0, G_OPTION_ARG_NONE, &print_issue_types,
"List all known issue types and their descriptions.",
NULL},
{"set-media-info", '\0', 0, G_OPTION_ARG_FILENAME, &media_info,
"Set a media_info XML file descriptor to share information about the"
" media file that will be reproduced.",
NULL},
{"set-configs", '\0', 0, G_OPTION_ARG_STRING, &configs,
"Select a config scenario (one including 'is-config=true' in its"
" description). Specify multiple ones using ':' as separator."
" This option overrides the GST_VALIDATE_SCENARIO environment variable.",
NULL},
{NULL}
};
GOptionContext *ctx;
gchar **argvn;
GstValidateRunner *runner;
GstValidateMonitor *monitor;
GstBus *bus;
setlocale (LC_ALL, "");
g_set_prgname ("gst-validate-" GST_API_VERSION);
ctx = g_option_context_new ("PIPELINE-DESCRIPTION");
g_option_context_add_main_entries (ctx, options, NULL);
g_option_context_set_summary (ctx, "Runs a gst launch pipeline, adding "
"monitors to it to identify issues in the used elements. At the end"
" a report will be printed. To view issues as they are created, set"
" the env var GST_DEBUG=validate:2 and it will be printed "
"as gstreamer debugging");
if (argc == 1) {
g_print ("%s", g_option_context_get_help (ctx, FALSE, NULL));
exit (1);
}
if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
g_printerr ("Error initializing: %s\n", err->message);
g_option_context_free (ctx);
g_clear_error (&err);
exit (1);
}
gst_init (&argc, &argv);
gst_validate_init_debug ();
if (testfile) {
is_testfile = TRUE;
if (scenario)
gst_validate_abort
("Can not specify scenario and testfile at the same time");
g_option_context_free (ctx);
return run_test_from_file (testfile, use_fakesinks);
}
if (scenario || configs) {
gchar *scenarios;
if (scenario)
scenarios = g_strjoin (":", scenario, configs, NULL);
else
scenarios = g_strdup (configs);
g_setenv ("GST_VALIDATE_SCENARIO", scenarios, TRUE);
g_free (scenarios);
g_free (scenario);
g_free (configs);
}
gst_validate_init ();
if (list_scenarios || output_file) {
g_option_context_free (ctx);
if (gst_validate_list_scenarios (argv + 1, argc - 1, output_file))
return 1;
return 0;
}
if (inspect_action_type) {
_register_playbin_actions ();
if (!gst_validate_print_action_types ((const gchar **) argv + 1, argc - 1)) {
GST_ERROR ("Could not print all wanted types");
return -1;
}
return 0;
}
if (print_issue_types) {
gst_validate_print_issues ();
return 0;
}
if (argc == 1) {
gst_validate_printf (NULL, "%s", g_option_context_get_help (ctx, FALSE,
NULL));
g_option_context_free (ctx);
exit (1);
}
g_option_context_free (ctx);
runner = gst_validate_runner_new ();
if (!runner) {
g_printerr ("Failed to setup Validate Runner\n");
exit (1);
}
/* Create the pipeline */
argvn = g_new0 (char *, argc);
memcpy (argvn, argv + 1, sizeof (char *) * (argc - 1));
if (argc == 2) {
gst_validate_printf (NULL, "**-> Pipeline: '%s'**\n", argvn[0]);
pipeline = (GstElement *) gst_parse_launch (argvn[0], &err);
} else {
pipeline = (GstElement *) gst_parse_launchv ((const gchar **) argvn, &err);
}
if (!pipeline) {
gst_validate_printf (NULL, "Failed to create pipeline: %s\n",
err ? err->message : "unknown reason");
g_clear_error (&err);
g_object_unref (runner);
g_free (argvn);
exit (1);
} else if (err) {
if (g_error_matches (err, GST_PARSE_ERROR, GST_PARSE_ERROR_NO_SUCH_ELEMENT)) {
if (!gst_validate_fail_on_missing_plugin ())
gst_validate_skip_test ("missing plugin: %s", err->message);
}
g_printerr ("Erroneous pipeline: %s\n",
err->message ? err->message : "unknown reason");
g_clear_error (&err);
g_free (argvn);
return 1;
}
if (!GST_IS_PIPELINE (pipeline)) {
GstElement *new_pipeline = gst_pipeline_new ("");
gst_bin_add (GST_BIN (new_pipeline), pipeline);
pipeline = new_pipeline;
}
gst_pipeline_set_auto_flush_bus (GST_PIPELINE (pipeline), FALSE);
#ifdef G_OS_UNIX
signal_watch_id =
g_unix_signal_add (SIGINT, (GSourceFunc) intr_handler, pipeline);
#endif
gst_validate_spin_on_fault_signals ();
if (_is_playbin_pipeline (argc - 1, argv + 1)) {
_register_playbin_actions ();
}
monitor = gst_validate_monitor_factory_create (GST_OBJECT_CAST (pipeline),
runner, NULL);
if (verbosity)
gst_util_set_object_arg (G_OBJECT (monitor), "verbosity", verbosity);
gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor));
if (media_info) {
GError *err = NULL;
GstValidateMediaDescriptorParser *parser =
gst_validate_media_descriptor_parser_new (runner,
media_info, &err);
if (parser == NULL) {
GST_ERROR ("Could not use %s as a media-info file (error: %s)",
media_info, err ? err->message : "Unknown error");
g_free (media_info);
exit (1);
}
gst_validate_monitor_set_media_descriptor (monitor,
GST_VALIDATE_MEDIA_DESCRIPTOR (parser));
gst_object_unref (parser);
g_free (media_info);
}
mainloop = g_main_loop_new (NULL, FALSE);
bus = gst_element_get_bus (pipeline);
gst_bus_add_signal_watch (bus);
bus_callback_data.mainloop = mainloop;
bus_callback_data.monitor = monitor;
g_signal_connect (bus, "message", (GCallback) bus_callback,
&bus_callback_data);
gst_validate_printf (NULL, "**-> Starting pipeline**\n");
g_free (argvn);
g_object_get (monitor, "handles-states", &monitor_handles_state, NULL);
if (monitor_handles_state == FALSE) {
sret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
switch (sret) {
case GST_STATE_CHANGE_FAILURE:
/* ignore, we should get an error message posted on the bus */
gst_validate_printf (NULL, "Pipeline failed to go to PLAYING state\n");
gst_element_set_state (pipeline, GST_STATE_NULL);
ret = -1;
goto exit;
case GST_STATE_CHANGE_NO_PREROLL:
gst_validate_printf (NULL, "Pipeline is live.\n");
is_live = TRUE;
break;
case GST_STATE_CHANGE_ASYNC:
gst_validate_printf (NULL, "Prerolling...\r");
break;
default:
break;
}
gst_validate_printf (NULL, "**-> Pipeline started**\n");
} else {
gst_validate_printf (NULL, "**-> Letting scenario handle set state**\n");
}
g_main_loop_run (mainloop);
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
/* Clean the bus */
gst_bus_set_flushing (bus, TRUE);
gst_bus_remove_signal_watch (bus);
gst_object_unref (bus);
rep_err = gst_validate_runner_exit (runner, TRUE);
if (ret == 0) {
ret = rep_err;
if (rep_err != 0)
gst_validate_printf (NULL, "Returning %d as errors were found\n",
rep_err);
}
exit:
g_main_loop_unref (mainloop);
g_object_unref (pipeline);
g_object_unref (runner);
gst_validate_reporter_purge_reports (GST_VALIDATE_REPORTER (monitor));
g_object_unref (monitor);
g_clear_error (&err);
#ifdef G_OS_UNIX
g_source_remove (signal_watch_id);
#endif
gst_validate_printf (NULL, "\n=======> Test %s (Return value: %i)\n\n",
ret == 0 ? "PASSED" : "FAILED", ret);
gst_validate_deinit ();
gst_deinit ();
return ret;
}
@@ -0,0 +1,67 @@
executable('gst-validate-' + apiversion,
'gst-validate.c',
install: true,
include_directories : inc_dirs,
dependencies : validate_dep,
c_args : [gst_c_args] + ['-DG_LOG_DOMAIN="gst-validate-@0@"'.format(apiversion)],
)
gst_transcoder_dep = dependency('gstreamer-transcoder-' + apiversion, version : gst_req,
fallback : ['gst-plugins-bad', 'gst_transcoder_dep'], required: false)
if gst_transcoder_dep.found()
executable('gst-validate-transcoding-' + apiversion,
'gst-validate-transcoding.c',
install: true,
include_directories : inc_dirs,
dependencies : [validate_dep, gst_transcoder_dep],
c_args : [gst_c_args] + ['-DG_LOG_DOMAIN="gst-validate-transcoding-@0@"'.format(apiversion)],
)
else
warning('Can not build gst-validate-transcoding-' + apiversion)
endif
executable('gst-validate-media-check-' + apiversion,
'gst-validate-media-check.c',
install: true,
include_directories : inc_dirs,
dependencies : validate_dep,
c_args : [gst_c_args] + ['-DG_LOG_DOMAIN="gst-validate-media-check-@0@"'.format(apiversion)],
)
rtsp_server_dep = dependency('gstreamer-rtsp-server-' + apiversion,
fallback: ['gst-rtsp-server', 'gst_rtsp_server_dep'],
version : gst_req,
required: false)
if rtsp_server_dep.found()
executable('gst-validate-rtsp-server-' + apiversion,
'gst-validate-rtsp-server.c',
install: true,
include_directories: inc_dirs,
dependencies : [rtsp_server_dep, validate_dep],
c_args: [gst_c_args] + ['-DG_LOG_DOMAIN="gst-validate-rtsp-server-@0@"'.format(apiversion)],
)
endif
if validate_video_dep.found()
executable('gst-validate-images-check-' + apiversion,
'gst-validate-images-check.c',
install: true,
include_directories : inc_dirs,
dependencies : [validate_dep, validate_video_dep],
c_args : [gst_c_args] + ['-DG_LOG_DOMAIN="gst-validate-images-check-@0@"'.format(apiversion)]
)
endif
tmpconf = configuration_data()
tmpconf.set('LIBDIR', join_paths(get_option('prefix'), get_option('libdir')))
tmpconf.set('BUILDDIR', meson.current_build_dir())
tmpconf.set('SRCDIR', meson.current_source_dir())
configure_file(input : 'gst-validate-launcher.in',
install_dir: get_option('bindir'),
output : 'gst-validate-launcher',
configuration : tmpconf)
launcher = find_program(meson.current_build_dir() + '/gst-validate-launcher')