Skip to content

Commit

Permalink
Merge remote-tracking branch 'main/master' into rename_api
Browse files Browse the repository at this point in the history
  • Loading branch information
hyades committed Jan 7, 2015
2 parents 471a59c + a2f1edd commit 0a36c73
Show file tree
Hide file tree
Showing 6 changed files with 243 additions and 45 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*.txt
imgurbash.sh.*
.coverage
.gdb_history
.idea
/INSTALL
/Makefile
Expand Down
12 changes: 9 additions & 3 deletions tests/unit/Makefile.am
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
include $(top_srcdir)/build/glib-tap.mk

LDADD = \
$(GLIB_LIBS) $(GST_LIBS)
LDADD = $(GTK_LIBS) $(GLIB_LIBS) $(GST_LIBS)

CFLAGS += $(GST_CFLAGS)
test_gstswitchopts_SOURCES = test_gstswitchopts.c
test_gstswitchopts_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS) \
$(GCOV_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) -DLOG_PREFIX="\"./tests\""
test_gstrecorder_filename_SOURCES = test_gstrecorder_filename.c ../../tools/gstworker.c
test_gstrecorder_filename_CFLAGS = -fprofile-arcs $(GST_CFLAGS) $(GST_BASE_CFLAGS) \
$(GCOV_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) -DLOG_PREFIX="\"./tests\""
test_gstrecorder_filename_LDFLAGS = $(GCOV_LFLAGS)

dist_test_data = \
$(NULL)

test_programs = \
test_gstswitchopts \
test_gstrecorder_filename \
test_gstcomposite \
$(NULL)

Expand Down
91 changes: 91 additions & 0 deletions tests/unit/test_gstrecorder_filename.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@

#include "tools/gstrecorder.c"
#include <fcntl.h>

#define BASEDIR "/tmp/unittests/"

// fake options struct, not used in these tests
GstSwitchServerOpts opts;
gboolean verbose = FALSE;



static char *
filepath (char *buf, size_t len, char const *fn)
{
snprintf (buf, len, BASEDIR "%d/%s", getpid (), fn);
return buf;
}


static gboolean
exists (const char *filepath, gboolean dir)
{
struct stat s;

if (stat (filepath, &s) == 0) {
if (!dir || S_ISDIR (s.st_mode))
return TRUE;
}
return FALSE;
}

static gboolean
touch (const char *filepath)
{
int fd =
open (filepath, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (fd != -1) {
close (fd);
return TRUE;
}
return FALSE;
}


static int
create_new_directory (const char *name)
{
char buf[256];

gst_recorder_mkdirs (filepath (buf, sizeof buf, name));
return exists (buf, TRUE);
}


static gboolean
create_capture_file (const char *name)
{
char buf[256];
char const *capfilename =
gst_recorder_new_filename (filepath (buf, sizeof buf, name));
return touch (capfilename);
}

static void
test_mkdirs ()
{
g_assert_cmpint (create_new_directory ("testdir1"), !=, 0);
g_assert_cmpint (create_new_directory ("testdir2"), !=, 0);
g_assert_cmpint (create_new_directory ("testdir1/testdir3"), !=, 0);
g_assert_cmpint (create_new_directory ("testdir3/testdir1"), !=, 0);
}

static void
test_new_filename ()
{
g_assert_true (create_capture_file ("%Y%m%d_%T"));
g_assert_true (create_capture_file ("%Y%m/%d_%T"));
g_assert_true (create_capture_file ("%Y/%m/%d/%T"));
}

int
main (int argc, char *argv[])
{
g_test_init (&argc, &argv, NULL);
gst_init (&argc, &argv);
g_test_set_nonfatal_assertions ();
g_test_add_func ("/gstswitch/options/mkdirs", test_mkdirs);
g_test_add_func ("/gstswitch/options/filename", test_new_filename);
return g_test_run ();
}
10 changes: 0 additions & 10 deletions tests/unit/test_gstswitchopts.c
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@

#include "tools/gstswitchopts.c"

static char const *test_bad_strings[] = {
"video/x-raw,height=[400,800],width=500,framerate=25/1",
"720p@75", "sadfasf",
"video/x-raw,height=10,width=500,framerate=25/1",
"video/x-raw,height=400,width=10,framerate=25/1",
"video/x-raw,height=400,width=10,framerate=1001/1",
"pal@75",
NULL
};

static void
test_strings_good (void)
{
Expand Down
114 changes: 86 additions & 28 deletions tools/gstrecorder.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/stat.h>
#include "gstswitchserver.h"
#include "gstcomposite.h"
#include "gstrecorder.h"
Expand Down Expand Up @@ -170,45 +171,102 @@ gst_recorder_set_property (GstRecorder * rec, guint property_id,
}
}

/*
* @param dir - directory to create
* @return nothing
* Create a directory and all intermediary directories
* if necessary. Note that errors are ignored here, if
* the resulting path is in fact unusable having early
* warning here is not necessary
*/
static void
gst_recorder_mkdirs (const char *dir)
{
char tmp[256];
strncpy (tmp, dir, sizeof (tmp));
size_t len = strlen (tmp);
if (len > 0) {
if (tmp[len - 1] == '/')
tmp[len--] = 0;
if (len > 0) {
size_t at = 1; // skip leading slash
while (at < len) {
char *p = strchr (tmp + at, '/');
if (p != NULL && *p == '/') {
*p = '\0';
mkdir (tmp, S_IRWXU);
*p = '/';
at = p - tmp + 1;
} else
at = len;
}
mkdir (tmp, S_IRWXU);
}
}
}

/**
* @param rec The GstRecorder instance.
* @memberof GstRecorder
* @param filepath - file file/path of a unix file
* @return length of the path potion of the file, excluding the separator
*/
static size_t
gst_recorder_pathlen (const char *filepath)
{
if (filepath != NULL && strlen (filepath) > 0) {
char const *sep = strrchr (filepath + 1, '/');
if (sep != NULL)
return sep - filepath;
}
return 0;
}


/**
* @param filename Template name of the file to save
* @return the file name string, need to be freed after used
*
* This is used to generate a new recording file name for the recorder.
*/
static const gchar *
gst_recorder_new_filename (GstRecorder * rec)
gst_recorder_new_filename (const gchar * filename)
{
time_t t;
struct tm *tm;
gchar stamp[128];
const gchar *dot = NULL;
const gchar *filename = opts.record_filename;
if (!filename) {
if (!filename)
return NULL;
}

t = time (NULL);
tm = localtime (&t);

if (tm == NULL) {
static gint num = 0;
num += 1;
snprintf (stamp, sizeof (stamp), "%d", num);
} else {
strftime (stamp, sizeof (stamp), "%F %H%M%S", tm);
gchar fnbuf[256];
time_t t = time (NULL);
struct tm *tm = localtime (&t);
// Note: reserve some space for collision suffix
strftime (fnbuf, sizeof (fnbuf) - 5, filename, tm);
// We now have a fully built name in our buffer
// If there is at least one directory present, make sure they exist
size_t pathlen = gst_recorder_pathlen (fnbuf);
if (pathlen > 0) {
fnbuf[pathlen] = '\0';
gst_recorder_mkdirs (fnbuf);
fnbuf[pathlen] = '/';
}

if ((dot = g_strrstr (filename, "."))) {
const gchar *s = g_strndup (filename, dot - filename);
filename = g_strdup_printf ("%s %s%s", s, stamp, dot);
g_free ((gpointer) s);
} else {
filename = g_strdup_printf ("%s %s.dat", filename, stamp);
pathlen = strlen (fnbuf); // reuse for length of file/path

// handle name collisions by adding a suffix/extension
size_t suffix = 0;
while (1) {
struct stat s;
if (-1 == stat (fnbuf, &s)) {
if (ENOENT == errno)
break;
else {
perror (fnbuf);
return NULL; // can't record
}
}
snprintf (fnbuf + pathlen, 256 - pathlen, ".%03d", (int) suffix++);
// can't record if we've used up our additions
if (suffix > 999)
return NULL;
}

return filename;
return g_strdup (fnbuf);
}

/**
Expand All @@ -221,7 +279,7 @@ gst_recorder_new_filename (GstRecorder * rec)
static GString *
gst_recorder_get_pipeline_string (GstRecorder * rec)
{
const gchar *filename = gst_recorder_new_filename (rec);
const gchar *filename = gst_recorder_new_filename (opts.record_filename);
GString *desc;

//INFO ("Recording to %s and port %d", filename, rec->sink_port);
Expand Down
60 changes: 56 additions & 4 deletions tools/gstswitchserver.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,19 @@
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>

#define GST_SWITCH_SERVER_DEFAULT_HOST "localhost"
#define GST_SWITCH_SERVER_DEFAULT_VIDEO_ACCEPTOR_PORT 3000
#define GST_SWITCH_SERVER_DEFAULT_AUDIO_ACCEPTOR_PORT 4000
#define GST_SWITCH_SERVER_DEFAULT_CONTROLLER_PORT 5000
#define GST_SWITCH_SERVER_LISTEN_BACKLOG 8 /* client connection queue */

#define GST_SWITCH_SERVER_HOST_SPEC "%q"
#define GST_SWITCH_SERVER_DEFAULT_RECORD_FILE GST_SWITCH_SERVER_HOST_SPEC "_record_%Y%m%d%T"
#define GST_SWITCH_SERVER_DEFAULT_RECORD_EXT ".avi"

#define GST_SWITCH_SERVER_LOCK_MAIN_LOOP(srv) (g_mutex_lock (&(srv)->main_loop_lock))
#define GST_SWITCH_SERVER_UNLOCK_MAIN_LOOP(srv) (g_mutex_unlock (&(srv)->main_loop_lock))
#define GST_SWITCH_SERVER_LOCK_VIDEO_ACCEPTOR(srv) (g_mutex_lock (&(srv)->video_acceptor_lock))
Expand Down Expand Up @@ -80,14 +86,59 @@ GstSwitchServerOpts opts = {

gboolean verbose = FALSE;

static gboolean gparse_record_filename(gchar *name, gchar *value, gpointer data, GError **error)
{
size_t maxpathlen = 256;
gchar fnbuf[maxpathlen+1];
size_t fnlen = 0;

if (value == NULL || (fnlen = strlen(value)) == 0) {
// file not specified, use the default filename.ext
strncpy(fnbuf, GST_SWITCH_SERVER_DEFAULT_RECORD_FILE, sizeof(fnbuf) - 5);
strcat(fnbuf, GST_SWITCH_SERVER_DEFAULT_RECORD_EXT);
} else if (fnlen < maxpathlen) {
strncpy(fnbuf, value, sizeof(fnbuf));
if ((fnlen < 5 || strchr(value + fnlen - 5, '.') == NULL) && fnlen + 4 < maxpathlen)
strcat(fnbuf, GST_SWITCH_SERVER_DEFAULT_RECORD_EXT);
} else {
GError *err = g_error_new(G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "%s path/filename too long: %s\n", name, value);
g_propagate_error(error, err);
return FALSE;
}

// Do manual substitution of %q => hostname up front since this is static
// Time and date tokens are substituted within the recorder as the recording
// is started or cut to accurately reflect the date/time of recording
char *h = strstr(fnbuf, GST_SWITCH_SERVER_HOST_SPEC);
if (h != NULL) {
int mnlen = maxpathlen - fnlen; // limit size to what is available
char hostname[mnlen + 1];
if (gethostname(hostname, mnlen) != 0)
strcpy(hostname, GST_SWITCH_SERVER_DEFAULT_HOST);
else hostname[mnlen] = '\0';
int hnlen = strlen(hostname);
hostname[hnlen] = '\0'; // guarantee nul termination
fnlen = strlen(fnbuf);
do {
size_t over = fnlen - (h - fnbuf) + 1;
memmove(h + hnlen, h + 2, over);
memcpy(h, hostname, hnlen);
fnlen += (hnlen - 2); // adjust the result length
} while ((h = strstr(fnbuf, GST_SWITCH_SERVER_HOST_SPEC)) != NULL);
}

opts.record_filename = g_strdup(fnbuf);
return TRUE;
}

static GOptionEntry entries[] = {
{"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
"Prompt more messages", NULL},
{"test-switch", 't', 0, G_OPTION_ARG_STRING, &opts.test_switch,
"Perform switch test", "OUTPUT"},
{"record", 'r', 0, G_OPTION_ARG_STRING, &opts.record_filename,
"Enable recorder and record into the specified FILENAME",
"FILENAME"},
{"record", 'r', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK,
(gpointer)gparse_record_filename,
"Enable recorder and record into the specified FILENAME"},
{"video-input-port", 'p', 0, G_OPTION_ARG_INT, &opts.video_input_port,
"Specify the video input listen port.", "NUM"},
{"audio-input-port", 'a', 0, G_OPTION_ARG_INT, &opts.audio_input_port,
Expand Down Expand Up @@ -1750,6 +1801,7 @@ static unsigned long long i = 0;
void
my_handler (int signum)
{
extern void __gcov_flush();
printf ("received signal\n");
printf ("%llu\n", i);
__gcov_flush (); /* dump coverage data on receiving SIGUSR1 */
Expand All @@ -1761,7 +1813,7 @@ main (int argc, char *argv[])
{

struct sigaction new_action, old_action;
int n;

/* setup signal hander */
new_action.sa_handler = my_handler;
sigemptyset (&new_action.sa_mask);
Expand Down

0 comments on commit 0a36c73

Please sign in to comment.