Commit f7ea79cc authored by Brendan Long's avatar Brendan Long

Merged in restructure (pull request #1)

Created separate subdirectories for each test program.  Moved general test program from dlnasrc repo to this repo.  Modified so make is performed in individual directories
parents 630ac6c8 e2a490ec
......@@ -14,14 +14,17 @@ config.*
configure
configure.in
depcomp
/general
INSTALL
install-sh
libtool
ltmain.sh
Makefile
Makefile.in
missing
m4/*.m4
/playspeeds
stamp-h1
playspeeds-test
*.mkv
*.ogv
*.mpg
......
CableLabs
Put your license in here!
2013-07-08 CableLabs
* initial creation
playspeeds-test: playspeeds-test.c
gcc playspeeds-test.c -o playspeeds-test `pkg-config --cflags --libs gstreamer-1.0`
.PHONY: clean
clean:
rm -f *.o playspeeds-test *~ core
\ No newline at end of file
ACLOCAL_AMFLAGS = -I m4
bin_PROGRAMS = general playspeeds
general_SOURCES = src/general-test.c
general_CFLAGS = $(GST_CFLAGS)
general_LDADD = $(GST_LIBS) -lm
general_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
general_LIBTOOLFLAGS = --tag=disable-static
playspeeds_SOURCES = src/playspeeds-test.c
playspeeds_CFLAGS = $(GST_CFLAGS)
playspeeds_LDADD = $(GST_LIBS)
playspeeds_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
playspeeds_LIBTOOLFLAGS = --tag=disable-static
Nothing much yet.
WHAT IT IS
----------
This is a collection of C test programs to assist in development of CableLabs supplied GStreamer elements.
HOW TO BUILD IT
---------------
Issue the following commands from the test directory:
./autogen.sh
This will produce a Makefile, initiate the make via:
make
Install the plugin via:
(sudo make install) no longer necessary???
This plugin will be built when entering the same commands from gst-plugins-cl (parent directory) or
individual test subdirectories
TESTING
-------
The "general" test program has a bunch of options to test many different scenarios. It can be used to test GStreamer playbin pipeline or a manually built pipeline. See help for complete listing of options.
The "playspeeds" test program is from a GStreamer tutorial modified to support GStreamer 1.0 and to take command line args for UI. It also is built via the make target and has a script to run the program.
#!/bin/sh
# you can either set the environment variables AUTOCONF, AUTOHEADER, AUTOMAKE,
# ACLOCAL, AUTOPOINT and/or LIBTOOLIZE to the right versions, or leave them
# unset and get the defaults
autoreconf --verbose --force --install || {
echo 'autogen.sh failed';
exit 1;
}
./configure || {
echo 'configure failed';
exit 1;
}
echo
echo "Now type 'make' to compile this module."
echo
dnl required version of autoconf
AC_PREREQ([2.53])
AC_INIT([general-test],[1.0.0])
dnl required versions of gstreamer and plugins-base
GST_REQUIRED=1.0.0
GSTPB_REQUIRED=1.0.0
AC_CONFIG_SRCDIR([src/general-test.c])
AC_CONFIG_HEADERS([config.h])
dnl required version of automake
AM_INIT_AUTOMAKE([1.11 subdir-objects])
AM_SILENT_RULES([yes])
dnl enable mainainer mode by default
AM_MAINTAINER_MODE([enable])
dnl check for tools (compiler etc.)
AC_PROG_CC
AM_PROG_CC_C_O
dnl required version of libtool
LT_PREREQ([2.2.6])
LT_INIT
dnl give error and exit if we don't have pkgconfig
AC_CHECK_PROG(HAVE_PKGCONFIG, pkg-config, [ ], [
AC_MSG_ERROR([You need to have pkg-config installed!])
])
dnl Check for the required version of GStreamer core (and gst-plugins-base)
dnl This will export GST_CFLAGS and GST_LIBS variables for use in Makefile.am
dnl
dnl If you need libraries from gst-plugins-base here, also add:
dnl for libgstaudio-1.0: gstreamer-audio-1.0 >= $GST_REQUIRED
dnl for libgstvideo-1.0: gstreamer-video-1.0 >= $GST_REQUIRED
dnl for libgsttag-1.0: gstreamer-tag-1.0 >= $GST_REQUIRED
dnl for libgstpbutils-1.0: gstreamer-pbutils-1.0 >= $GST_REQUIRED
dnl for libgstfft-1.0: gstreamer-fft-1.0 >= $GST_REQUIRED
dnl for libgstinterfaces-1.0: gstreamer-interfaces-1.0 >= $GST_REQUIRED
dnl for libgstrtp-1.0: gstreamer-rtp-1.0 >= $GST_REQUIRED
dnl for libgstrtsp-1.0: gstreamer-rtsp-1.0 >= $GST_REQUIRED
dnl etc.
PKG_CHECK_MODULES(GST, [
gstreamer-1.0 >= $GST_REQUIRED
gstreamer-base-1.0 >= $GST_REQUIRED
gstreamer-controller-1.0 >= $GST_REQUIRED
], [
AC_SUBST(GST_CFLAGS)
AC_SUBST(GST_LIBS)
], [
AC_MSG_ERROR([
You need to install or upgrade the GStreamer development
packages on your system. On debian-based systems these are
libgstreamer1.0-dev and libgstreamer-plugins-base1.0-dev.
on RPM-based systems gstreamer1.0-devel, libgstreamer1.0-devel
or similar. The minimum version required is $GST_REQUIRED.
])
])
dnl *** soup ***
PKG_CHECK_MODULES(SOUP, [
libsoup-2.4 >= 2.3.2
], [
AC_SUBST(SOUP_CFLAGS)
AC_SUBST(SOUP_LIBS)
], [
AC_MSG_ERROR([
You need to install or upgrade the libsoup on your system.
The minimum version required is 2.3.2.
])
])
dnl check if compiler understands -Wall (if yes, add -Wall to GST_CFLAGS)
AC_MSG_CHECKING([to see if compiler understands -Wall])
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Wall -Werror"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ ], [ ])], [
GST_CFLAGS="$GST_CFLAGS -Wall -Werror"
AC_MSG_RESULT([yes])
], [
AC_MSG_RESULT([no])
])
dnl set the plugindir where plugins should be installed (for src/Makefile.am)
if test "x${prefix}" = "x$HOME"; then
plugindir="$HOME/.gstreamer-1.0/plugins"
else
plugindir="\$(libdir)/gstreamer-1.0"
fi
AC_SUBST(plugindir)
dnl set proper LDFLAGS for plugins
GST_PLUGIN_LDFLAGS='-module -avoid-version -export-symbols-regex [_]*\(gst_\|Gst\|GST_\).*'
AC_SUBST(GST_PLUGIN_LDFLAGS)
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
/* Test program for CableLabs GStreamer plugins
* Copyright (C) 2013 CableLabs, Louisville, CO 80027
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Alternatively, the contents of this file may be used under the
* GNU Lesser General Public License Version 2.1 (the "LGPL"), in
* which case the following provisions apply instead of the ones
* mentioned above:
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <gst/gst.h>
#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
// Global vars for cmd line args
//
static int g_wait_secs = 0;
static int g_state_change_timeout_secs = 45;
static gfloat g_requested_rate = 1;
static int g_rrid = 2;
static int g_rate_change_cnt = 1;
static char g_host[256];
static char g_uri[256];
static gboolean g_use_manual_bin_pipeline = FALSE;
static gboolean g_use_manual_elements_pipeline = FALSE;
static gboolean g_use_simple_pipeline = FALSE;
static gboolean g_use_dtcp = FALSE;
static gboolean g_format_bytes = FALSE;
static gboolean g_do_query = FALSE;
static gboolean g_do_seek = FALSE;
static gboolean g_zero_position = FALSE;
static gboolean g_positions = FALSE;
static gboolean g_test_uri_switch = FALSE;
static int g_eos_max_cnt = 1;
static int g_eos_cnt = 0;
//static const guint64 NANOS_PER_SECOND = 1000000000L;
static const guint64 NANOS_PER_MINUTE = 60000000000L;
static gboolean g_use_file = FALSE;
static char g_file_name[256];
static gchar* g_file_path = NULL;
static gchar* TEST_FILE_URL_PREFIX_ENV = "TEST_FILE_URL_PREFIX";
static gboolean g_create_dot = FALSE;
static GstElement* g_sink = NULL;
static GstElement* g_pipeline = NULL;
static GstElement* g_identity = NULL;
static GstElement* g_tee = NULL;
static GstElement* g_queue = NULL;
static GstElement* g_mpeg2dec = NULL;
static GstElement* g_aparse = NULL;
static GstElement* g_avdec = NULL;
/* Structure to contain all our information, so we can pass it around */
typedef struct _CustomData {
GstElement *pipeline; /* Our pipeline element */
gboolean playing; /* Are we in the PLAYING state? */
gboolean terminate; /* Should we terminate execution? */
gboolean seek_enabled; /* Is seeking enabled for this media? */
gboolean seek_done; /* Have we performed the seek already? */
gint64 duration; /* How long does this media last, in nanoseconds */
gdouble rate; /* current playspeed */
} CustomData;
// Local method declarations
//
static gboolean process_cmd_line_args(int argc, char*argv[]);
static GstElement* create_playbin_pipeline();
static GstElement* create_manual_pipeline(gchar* pipeline_name, gboolean use_bin);
static gboolean create_manual_bin_pipeline(GstElement* pipeline);
static gboolean create_manual_elements_pipeline(GstElement* pipeline);
static void bin_cb_pad_added (GstElement *dec, GstPad *pad, gpointer data);
static void tsdemux_cb_pad_added (GstElement *tsdemux, GstPad *pad, gpointer data);
static gboolean link_video_elements(gchar* name, GstPad* tsdemux_src_pad, GstCaps* caps);
static gboolean link_audio_elements(gchar* name, GstPad* tsdemux_src_pad, GstCaps* caps);
static GstElement* create_simple_pipeline();
static void on_source_changed(GstElement* element, GParamSpec* param, gpointer data);
static void perform_test(CustomData* data);
static gboolean perform_test_rate_change(CustomData* data);
static gboolean perform_test_position(CustomData* data);
static gboolean perform_test_query(CustomData* data, gint64* position, GstFormat format);
static gboolean perform_test_seek(CustomData* data, gint64 position, GstFormat format, gfloat rate);
static gboolean set_pipeline_state(CustomData* data, GstState desired_state, gint timeoutSecs);
static gboolean set_new_uri(CustomData* data);
static void handle_message (CustomData *data, GstMessage *msg);
static void log_bin_elements(GstBin* bin);
static GstElement* log_element_links(GstElement* elem);
/**
* Test program for playspeed testing
*/
int main(int argc, char *argv[])
{
CustomData data;
data.playing = FALSE;
data.terminate = FALSE;
data.seek_enabled = FALSE;
data.seek_done = FALSE;
data.duration = GST_CLOCK_TIME_NONE;
// Assign default values
strcpy(g_host, "192.168.2.2");
g_uri[0] = '\0';
g_file_name[0] = '\0';
if (!process_cmd_line_args(argc, argv))
{
g_printerr("Exit due to problems with cmd line args\n");
return -1;
}
// Build default URI if one was not specified
if (g_uri[0] == '\0')
{
char* line2 = "http://";
char* line3 = ":8008/ocaphn/recording?rrid=";
char* line4 = "&profile=MPEG_TS_SD_NA_ISO&mime=video/mpeg";
if (g_use_dtcp)
{
line4 = "&profile=DTCP_MPEG_TS_SD_NA_ISO&mime=video/mpeg";
}
sprintf(g_uri, "%s%s%s%d%s", line2, g_host, line3, g_rrid, line4);
}
// Initialize GStreamer
gst_init (&argc, &argv);
// Build the pipeline
if (g_use_manual_bin_pipeline)
{
g_print("Creating pipeline by manually linking uri decode bin\n");
data.pipeline = create_manual_pipeline("manual-bin-pipeline", TRUE);
}
else if (g_use_manual_elements_pipeline)
{
g_print("Creating pipeline by manually linking decode elements\n");
data.pipeline = create_manual_pipeline("manual-elements-pipeline", FALSE);
}
else if (g_use_simple_pipeline)
{
g_print("Creating simple pipeline\n");
data.pipeline = create_simple_pipeline();
}
else
{
g_print("Creating pipeline using playbin\n");
data.pipeline = create_playbin_pipeline();
}
// Check that pipeline was properly created
if (data.pipeline == NULL)
{
g_printerr("Problems creating pipeline\n");
return -1;
}
g_pipeline = data.pipeline;
// Start playing
g_print("Pipeline created, start playing\n");
if (!set_pipeline_state(&data, GST_STATE_PLAYING, g_state_change_timeout_secs))
{
g_printerr ("Unable to set the pipeline to the playing state.\n");
return -1;
}
else
{
g_print("Pipeline in playing state\n");
}
// Print out elements in playbin
log_bin_elements(GST_BIN(data.pipeline));
// Create pipeline diagram
if (g_create_dot)
{
g_print("Creating pipeline.dot file\n");
GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(data.pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "pipeline");
}
// Perform requested testing
g_print("Begin pipeline test\n");
perform_test(&data);
return 0;
}
/**
*
*/
static void handle_message (CustomData *data, GstMessage *msg)
{
GError *err;
gchar *debug_info;
GstState old_state, new_state, pending_state;
g_print("Got message type: %s\n", GST_MESSAGE_TYPE_NAME (msg));
switch (GST_MESSAGE_TYPE (msg))
{
case GST_MESSAGE_ERROR:
err = NULL;
debug_info = NULL;
gst_message_parse_error (msg, &err, &debug_info);
g_printerr ("Error received from element %s: %s\n", GST_OBJECT_NAME (msg->src), err->message);
g_printerr ("Debugging information: %s\n", debug_info ? debug_info : "none");
g_clear_error (&err);
g_free (debug_info);
data->terminate = TRUE;
break;
case GST_MESSAGE_EOS:
g_print ("End-Of-Stream reached.\n");
g_eos_cnt++;
if (g_eos_cnt >= g_eos_max_cnt)
{
data->terminate = TRUE;
}
break;
case GST_MESSAGE_DURATION:
// The duration has changed, mark thdata.pipeline,e current one as invalid
data->duration = GST_CLOCK_TIME_NONE;
break;
case GST_MESSAGE_STATE_CHANGED:
gst_message_parse_state_changed (msg, &old_state, &new_state, &pending_state);
if (GST_MESSAGE_SRC (msg) == GST_OBJECT (data->pipeline))
{
g_print ("Pipeline state changed from %s to %s:\n",
gst_element_state_get_name (old_state), gst_element_state_get_name (new_state));
// Remember whether we are in the PLAYING state or not
data->playing = (new_state == GST_STATE_PLAYING);
}
break;
default:
// We should not reach here
g_printerr ("Unexpected message received.\n");
break;
}
gst_message_unref (msg);
}
/**
* Handle command line args
*/
static gboolean process_cmd_line_args(int argc, char *argv[])
{
int i = 0;
for (i = 1; i < argc; i++)
{
if (strstr(argv[i], "rate=") != NULL)
{
if (sscanf(argv[i], "rate=%f", &g_requested_rate) != 1)
{
g_printerr("Invalid rate arg specified: %s\n", argv[i]);
return FALSE;
}
else
{
g_print("Set requested rate change to %4.1f\n", g_requested_rate);
g_do_seek = TRUE;
g_print("Setting do seek flag to TRUE\n");
g_do_query = TRUE;
g_print("Setting do query flag to TRUE\n");
}
}
else if (strstr(argv[i], "wait=") != NULL)
{
if (sscanf(argv[i], "wait=%d", &g_wait_secs) != 1)
{
g_printerr("Invalid wait arg specified: %s\n", argv[i]);
return FALSE;
}
else
{
g_print("Set requested wait secs to %d\n", g_wait_secs);
}
}
else if (strstr(argv[i], "uri=") != NULL)
{
if (sscanf(argv[i], "uri=%s\n", &g_uri[0]) != 1)
{
g_printerr("Invalid uri arg specified: %s\n", argv[i]);
return FALSE;
}
else
{
g_print("Set requested URI to %s\n", g_uri);
}
}
else if (strstr(argv[i], "rrid=") != NULL)
{
if (sscanf(argv[i], "rrid=%d", &g_rrid) != 1)
{
g_printerr("Invalid rrid specified: %s\n", argv[i]);
return FALSE;
}
else
{
g_print("Set requested rrid to %d\n", g_rrid);
}
}
else if (strstr(argv[i], "host=") != NULL)
{
if (sscanf(argv[i], "host=%s\n", &g_host[0]) != 1)
{
g_printerr("Invalid host arg specified: %s\n", argv[i]);
return FALSE;
}
else
{
g_print("Set requested host ip to %s\n", g_host);
}
}
else if (strstr(argv[i], "manual_bin") != NULL)
{
g_use_manual_bin_pipeline = TRUE;
g_print("Set to manually build pipeline using uridecode bin\n");
}
else if (strstr(argv[i], "manual_elements") != NULL)
{
g_use_manual_elements_pipeline = TRUE;
g_print("Set to manually build pipeline using individual elements\n");
}
else if (strstr(argv[i], "simple") != NULL)
{
g_use_simple_pipeline = TRUE;
g_print("Set to build simplest pipeline\n");
}
else if (strstr(argv[i], "switch") != NULL)
{
g_test_uri_switch = TRUE;
g_print("Set to test uri switching\n");
}
else if (strstr(argv[i], "query") != NULL)
{
g_do_query = TRUE;
g_print("Set to query position\n");
}
else if (strstr(argv[i], "zero") != NULL)
{
g_zero_position = TRUE;
g_print("Set to position to zero\n");
}
else if (strstr(argv[i], "file=") != NULL)
{
if (sscanf(argv[i], "file=%s\n", &g_file_name[0]) != 1)
{
g_printerr("Invalid file name specified: %s\n", argv[i]);
return FALSE;
}
else
{
g_use_file = TRUE;
g_print("Test using local file %s rather than URI\n", g_file_name);
}
}
else if (strstr(argv[i], "dtcp") != NULL)
{
g_use_dtcp = TRUE;
g_print("Set to use dtcp URI\n");
}
else if (strstr(argv[i], "byte") != NULL)
{
g_format_bytes = TRUE;
g_print("Set to use byte format for query and seek\n");
}
else if (strstr(argv[i], "dot") != NULL)
{
g_create_dot = TRUE;
g_print("Set to generate dot file for pipeline diagram\n");
}
else if (strstr(argv[i], "changes=") != NULL)
{
if (sscanf(argv[i], "changes=%d", &g_rate_change_cnt) != 1)
{
g_printerr("Invalid rate change count arg specified: %s\n", argv[i]);
return FALSE;
}
else
{
g_print("Set requested rate change count to %d\n", g_rate_change_cnt);
}
}
else if (strstr(argv[i], "position") != NULL)
{
g_positions = TRUE;
g_print("Set to test positioning\n");
}
else
{
g_printerr("Invalid option: %s\n", argv[i]);
g_printerr("Usage:\n");
g_printerr("\t byte \t\t use byte format for query and seek\n");
g_printerr("\t changes=x \t\t where x is number of 2x increase rate changes\n");
g_printerr("\t dot \t\t generate dot file of pipeline diagram\n");
g_printerr("\t dtcp \t\t indicates content is dtcp/ip encrypted\n");
g_printerr("\t file=name \t\twhere name indicates file name using path from env var\n");
g_printerr("\t host=ip \t\t addr of server\n");
g_printerr("\t manual_uri_bin \t\t build manual pipeline using uri decode bin\n");
g_printerr("\t manual_decode_bin \t\t build manual pipeline using decode bin\n");