Added htsstr.[ch], string helper functions, argument splitting and

formatting functions
Added support for post-processing again, now with string formatting
Ticket #33
This commit is contained in:
Mattias Wadman 2008-10-19 15:08:17 +00:00
parent b52656ac5c
commit 539f2e0460
8 changed files with 115 additions and 7 deletions

View file

@ -32,12 +32,12 @@ body {
padding-right: 60px;
}
.hts-doc-text dt {
.hts-doc-text dt,th {
padding-top: 10px;
font-weight: bold;
}
.hts-doc-text dl {
.hts-doc-text dl,td {
padding-bottom: 10px;
}
@ -53,4 +53,4 @@ body {
</style>
<body>
<body>

View file

@ -42,6 +42,27 @@
<dd>If checked, Tvheadend will include the time for the recording in the
event title. This applies to both the titled stored in the file
and to the filename itself.
<dt>Post-processor command
<dd>Command to run after finishing a recording. The command will be
run in background and is executed even if a recording is aborted
or an error occurred. Use the %e error formatting string to check
for errors, the error string is empty if recording finished
successfully.
<br><br>
Support format strings:<br>
<table class="hts-doc-text" border="0">
<tr><th>Format</th><th>Description</th><th>Example value</th></tr>
<tr><td>%f</td><td>Full path to recoding</td><td>/home/user/Videos/News.mkv</td></tr>
<tr><td>%b</td><td>Basename of recoding</td><td>News.mkv</td></tr>
<tr><td>%c</td><td>Channel name</td><td>BBC world</td></tr>
<tr><td>%C</td><td>Who created this recoding</td><td>user</td></tr>
<tr><td>%t</td><td>Program title</td><td>News</td></tr>
<tr><td>%c</td><td>Program description</td><td>News and stories...</td></tr>
<tr><td>%S</td><td>Start timestmap of recoding, UNIX epoch</td><td>1224421200</td></tr>
<tr><td>%E</td><td>Stop timestamp of recoding, UNIX epoch</td><td>1224426600</td></tr>
</table>
<br>
Example usage: /path/to/ffmpeg -i %f -vcodec libx264 -acodec copy "/path/with white space/%b"
</dl>
Changes to any of these settings must be confirmed by pressing the
'Save configuration' button before taking effect.

View file

@ -29,6 +29,7 @@ extern char *dvr_format;
extern char *dvr_file_postfix;
extern uint32_t dvr_retention_days;
extern int dvr_flags;
extern char *dvr_postproc;
#define DVR_DIR_PER_DAY 0x1
#define DVR_DIR_PER_CHANNEL 0x2
@ -144,6 +145,8 @@ void dvr_entry_dec_ref(dvr_entry_t *de);
void dvr_storage_set(const char *storage);
void dvr_postproc_set(const char *postproc);
void dvr_retention_set(int days);
void dvr_flags_set(int flags);

View file

@ -33,7 +33,7 @@ char *dvr_format;
char *dvr_file_postfix;
uint32_t dvr_retention_days;
int dvr_flags;
char *dvr_postproc;
static int de_tally;
@ -488,6 +488,8 @@ dvr_init(void)
if(!htsmsg_get_u32(m, "time-in-title", &u32) && u32)
dvr_flags |= DVR_TIME_IN_TITLE;
tvh_str_set(&dvr_postproc, htsmsg_get_str(m, "postproc"));
htsmsg_destroy(m);
}
@ -538,6 +540,8 @@ dvr_save(void)
htsmsg_add_u32(m, "channel-in-title", !!(dvr_flags & DVR_CHANNEL_IN_TITLE));
htsmsg_add_u32(m, "date-in-title", !!(dvr_flags & DVR_DATE_IN_TITLE));
htsmsg_add_u32(m, "time-in-title", !!(dvr_flags & DVR_TIME_IN_TITLE));
if(dvr_postproc != NULL)
htsmsg_add_str(m, "postproc", dvr_postproc);
hts_settings_save(m, "dvr/config");
htsmsg_destroy(m);
@ -556,6 +560,19 @@ dvr_storage_set(const char *storage)
dvr_save();
}
/**
*
*/
void
dvr_postproc_set(const char *postproc)
{
if(dvr_postproc != NULL && !strcmp(dvr_postproc, postproc))
return;
tvh_str_set(&dvr_postproc, !strcmp(postproc, "") ? NULL : postproc);
dvr_save();
}
/**
*

View file

@ -20,13 +20,17 @@
#include <assert.h>
#include <string.h>
#include <sys/stat.h>
#include <libgen.h> /* basename */
#include <libavutil/avstring.h>
#include <libavcodec/avcodec.h>
#include <libhts/htsstr.h>
#include "tvhead.h"
#include "streaming.h"
#include "dvr.h"
#include "spawn.h"
typedef struct dvr_rec_stream {
LIST_ENTRY(dvr_rec_stream) drs_link;
@ -46,6 +50,7 @@ static void dvr_rec_start(dvr_entry_t *de, streaming_pad_t *sp);
static void dvr_rec_stop(dvr_entry_t *de);
static void *dvr_thread(void *aux);
static void dvr_thread_new_pkt(dvr_entry_t *de, th_pkt_t *pkt);
static void dvr_spawn_postproc(dvr_entry_t *de);
static void dvr_thread_epilog(dvr_entry_t *de);
/**
@ -695,6 +700,57 @@ dvr_thread_new_pkt(dvr_entry_t *de, th_pkt_t *pkt)
}
}
/**
*
*/
static void dvr_spawn_postproc(dvr_entry_t *de)
{
char *fmap[256];
char **args;
char start[16];
char stop[16];
char *fbasename; /* filename dup for basename */
int i;
args = htsstr_argsplit(dvr_postproc);
/* no arguments at all */
if(!args[0]) {
htsstr_argsplit_free(args);
return;
}
fbasename = strdup(de->de_filename);
snprintf(start, sizeof(start), "%ld", de->de_start);
snprintf(stop, sizeof(stop), "%ld", de->de_stop);
memset(fmap, 0, sizeof(fmap));
fmap['f'] = de->de_filename; /* full path to recoding */
fmap['b'] = basename(fbasename); /* basename of recoding */
fmap['c'] = de->de_channel->ch_name; /* channel name */
fmap['C'] = de->de_creator; /* user who created this recording */
fmap['t'] = de->de_title; /* program title */
fmap['d'] = de->de_desc; /* program description */
fmap['e'] = de->de_error; /* error message, empty if no error (FIXME:?) */
fmap['S'] = start; /* start time, unix epoch */
fmap['E'] = stop; /* stop time, unix epoch */
printf("error=%s\n", de->de_error);
/* format arguments */
for(i = 0; args[i]; i++) {
char *s;
s = htsstr_format(args[i], fmap);
free(args[i]);
args[i] = s;
}
spawnv(args[0], (void *)args);
free(fbasename);
htsstr_argsplit_free(args);
}
/**
*
*/
@ -731,4 +787,7 @@ dvr_thread_epilog(dvr_entry_t *de)
LIST_REMOVE(drs, drs_link);
free(drs);
}
if(dvr_postproc)
dvr_spawn_postproc(de);
}

View file

@ -1063,6 +1063,7 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque)
r = htsmsg_create();
htsmsg_add_str(r, "storage", dvr_storage);
htsmsg_add_str(r, "postproc", dvr_postproc);
htsmsg_add_u32(r, "retention", dvr_retention_days);
htsmsg_add_u32(r, "dayDirs", !!(dvr_flags & DVR_DIR_PER_DAY));
htsmsg_add_u32(r, "channelDirs", !!(dvr_flags & DVR_DIR_PER_CHANNEL));
@ -1076,6 +1077,9 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque)
if((s = http_arg_get(&hc->hc_req_args, "storage")) != NULL)
dvr_storage_set(s);
if((s = http_arg_get(&hc->hc_req_args, "postproc")) != NULL)
dvr_postproc_set(s);
if((s = http_arg_get(&hc->hc_req_args, "retention")) != NULL)
dvr_retention_set(atoi(s));

View file

@ -319,7 +319,7 @@ tvheadend.dvrsettings = function() {
var confreader = new Ext.data.JsonReader({
root: 'dvrSettings',
}, ['storage','retention','dayDirs',
}, ['storage','postproc','retention','dayDirs',
'channelDirs','channelInTitle',
'dateInTitle','timeInTitle']);
@ -359,7 +359,11 @@ tvheadend.dvrsettings = function() {
}), new Ext.form.Checkbox({
fieldLabel: 'Include time in title',
name: 'timeInTitle'
})],
}), {
width: 300,
fieldLabel: 'Post-processor command',
name: 'postproc'
}],
tbar: [{
tooltip: 'Save changes made to channel configuration below',
iconCls:'save',

View file

@ -154,4 +154,4 @@
.about-title {
font:normal 24px verdana;
font-weight: bold;
}
}