Commit 9d277ec9 authored by Julian Rother's avatar Julian Rother

Cleanup and restructuring

parent 9a3250d8
......@@ -19,8 +19,10 @@ static char *getxmlattr(xmlAttr *a, char *name, char *err)
char *get_xmpchapters(char *xmp)
{
int i, len, maxlen;
char *out;
int i;
char *ptr;
size_t size;
FILE *stream;
xmlDocPtr doc;
xmlXPathContextPtr xpath;
xmlXPathObjectPtr res;
......@@ -41,51 +43,52 @@ char *get_xmpchapters(char *xmp)
res = xmlXPathEvalExpression("/x:xmpmeta/rdf:RDF/rdf:Description/xmpDM:Tracks/rdf:Bag/rdf:li/rdf:Description/xmpDM:markers/rdf:Seq/rdf:li/rdf:Description", xpath);
if (!res || !res->nodesetval)
return "";
len = 0; maxlen = res->nodesetval->nodeNr*200;
out = malloc(maxlen);
len += xsnprintf(out+len, maxlen-len-1, "[");
ptr = 0;
size = 0;
if (!(stream = open_memstream(&ptr, &size)))
exit(99);
fprintf(stream, "[");
for (i = 0; i < res->nodesetval->nodeNr; i ++)
{
start = atoi(getxmlattr(res->nodesetval->nodeTab[i]->properties, "startTime", "0"))/framerate;
if (i)
len += xsnprintf(out+len, maxlen-len-1, ",");
len += xsnprintf(out+len, maxlen-len-1, "{\"time\": %f, \"text\": \"%s\"}",
start, jescape(getxmlattr(res->nodesetval->nodeTab[i]->properties, "name", "")));
fprintf(stream, ",");
fprintf(stream, "{\"time\": %f, \"text\": \"%s\"}", start,
jescape(getxmlattr(res->nodesetval->nodeTab[i]->properties, "name", "")));
}
len += xsnprintf(out+len, maxlen-len-1, "]");
return out;
fprintf(stream, "]");
fclose(stream);
return ptr;
}
int main(int argc, char *argv[])
{
int jobid;
char path[100], *xmp;
int err;
char *path, *xmp;
AVFormatContext *demux, *mux;
AVDictionaryEntry *tag;
AVDictionary *opts;
if (argc != 5)
return 1;
av_register_all();
av_log_set_callback(avlogbuf_callback);
init_avlogbuf();
jobid = atoi(argv[1]);
xsnprintf(BL(path), "%s/%s", CONFIG_VIDEOS_RAW,
jstr(jlookup(argv[4], "path"), ""));
path = mprintf("%s/%s", CONFIG_VIDEOS_RAW, jstr(jlookup(argv[4], "path"), ""));
ping_job(jobid, "running", 0);
opts = 0;
av_dict_set_int(&opts, "export_xmp", 1, 0);
demux = 0;
if (avformat_open_input(&demux, path, 0, &opts))
goto fail;
if (err = avformat_open_input(&demux, path, 0, &opts))
job_failed("Opening input file failed: %s", av_err2str(err));
avformat_find_stream_info(demux, 0);
if (tag = av_dict_get(demux->metadata, "xmp", 0, 0))
ping_job(jobid, "finished", "{\"xmp_chapters\": %s, \"duration\": %f, \"log\": \"%s\"}", get_xmpchapters(tag->value), demux->duration*av_q2d(AV_TIME_BASE_Q), get_avlogbuf());
ping_job(jobid, "finished", "{\"xmp_chapters\": %s, \"duration\": %f, \"log\": \"%s\"}",
get_xmpchapters(tag->value), demux->duration*av_q2d(AV_TIME_BASE_Q),
jescape(get_avlogbuf()));
else
ping_job(jobid, "finished", "{\"duration\": %f, \"log\": \"%s\"}", demux->duration*av_q2d(AV_TIME_BASE_Q), get_avlogbuf());
ping_job(jobid, "finished", "{\"duration\": %f, \"log\": \"%s\"}",
demux->duration*av_q2d(AV_TIME_BASE_Q), jescape(get_avlogbuf()));
return 0;
fail:
ping_job(jobid, "failed", "{\"log\": \"%s\"}", get_avlogbuf());
return 1;
}
......@@ -42,9 +42,9 @@ void parse_chapters(AVFormatContext *ctx, char *s, int duration)
int main(int argc, char *argv[])
{
int jobid, i;
int i, err;
int *idxmap;
char *p, path[100], tmp[100];
char *p, *path, *tmp;
AVFormatContext *demux, *mux;
AVPacket pkt;
AVStream *stream;
......@@ -52,19 +52,18 @@ int main(int argc, char *argv[])
if (argc != 5)
return 1;
av_register_all();
av_log_set_callback(avlogbuf_callback);
init_avlogbuf();
memset(&pkt, 0, sizeof(pkt));
av_init_packet(&pkt);
jobid = atoi(argv[1]);
xsnprintf(BL(path), "%s/%s", CONFIG_VIDEOS_RELEASED,
jstr(jlookup(argv[4], "path"), ""));
xsnprintf(BL(tmp), "%s/.tmp-%i", CONFIG_VIDEOS_TMP, jobid);
path = mprintf("%s/%s", CONFIG_VIDEOS_RELEASED, jstr(jlookup(argv[4], "path"), ""));
tmp = mprintf("%s/.tmp-%i", CONFIG_VIDEOS_TMP, jobid);
ping_job(jobid, "running", 0);
demux = 0;
if (avformat_open_input(&demux, path, 0, 0))
goto fail;
if (err = avformat_open_input(&demux, path, 0, 0))
job_failed("Opening input file failed: %s", av_err2str(err));
avformat_find_stream_info(demux, 0);
avformat_alloc_output_context2(&mux, 0, jstr(jlookup(argv[4], "format"), 0), path);
av_dict_copy(&mux->metadata, demux->metadata, 0);
......@@ -89,8 +88,8 @@ int main(int argc, char *argv[])
avio_open(&mux->pb, tmp, AVIO_FLAG_WRITE);
muxopts = 0;
parse_dict(&muxopts, jlookup(argv[4], "options"));
if (avformat_write_header(mux, &muxopts) < 0)
goto fail;
if ((err = avformat_write_header(mux, &muxopts)) < 0)
job_failed("Writing temporary file failed: %s", av_err2str(err));
while (!av_read_frame(demux, &pkt))
{
if (pkt.stream_index >= demux->nb_streams
......@@ -104,21 +103,16 @@ int main(int argc, char *argv[])
pkt.duration = av_rescale_q(pkt.duration, demux->streams[pkt.stream_index]->time_base,
mux->streams[pkt.stream_index]->time_base);
pkt.pos = -1;
if (av_interleaved_write_frame(mux, &pkt))
goto fail;
if (err = av_interleaved_write_frame(mux, &pkt))
job_failed("Could not write frame: %s", av_err2str(err));
}
av_interleaved_write_frame(mux, 0);
if (av_write_trailer(mux))
goto fail;
if (err = av_write_trailer(mux))
job_failed("Error writing trailer to temporary file", av_err2str(err));
avio_closep(&mux->pb);
if (rename(tmp, path))
goto fail;
job_failed("Overwriting output file failed: %s", strerror(errno));
unlink(tmp);
ping_job(jobid, "finished", "{\"log\": \"%s\"}", get_avlogbuf());
ping_job(jobid, "finished", "{\"log\": \"%s\"}", jescape(get_avlogbuf()));
return 0;
fail:
unlink(tmp);
ping_job(jobid, "failed", "{\"log\": \"%s\"}", get_avlogbuf());
return 1;
}
......@@ -24,8 +24,8 @@ AVFrame *scale_frame(AVFrame *frame, enum AVPixelFormat pix_fmt,
int main(int argc, char *argv[])
{
int jobid, vidx;
char lectureid[JSTR_SIZE], src[100], tmp[100], dest[100];
int err, vidx;
char lectureid[JSTR_SIZE], *src, *tmp, *dest;
AVFormatContext *demux, *mux;
AVCodecContext *dec, *enc;
AVPacket pkt;
......@@ -33,25 +33,23 @@ int main(int argc, char *argv[])
if (argc != 5)
return 1;
av_register_all();
av_log_set_callback(avlogbuf_callback);
init_avlogbuf();
/* Prepare arguments */
jobid = atoi(argv[1]);
jstrb(jlookup(argv[4], "lectureid"), "-1", lectureid);
xsnprintf(BL(src), "%s/%s", CONFIG_VIDEOS_RELEASED,
jstr(jlookup(argv[4], "path"), ""));
xsnprintf(BL(tmp), "%s/.tmp-%i", CONFIG_VIDEOS_TMP, jobid);
xsnprintf(BL(dest), "%s/thumbnail/l_%s.jpg", CONFIG_VIDEOS_RELEASED,
lectureid);
src = mprintf("%s/%s", CONFIG_VIDEOS_RELEASED, jstr(jlookup(argv[4], "path"), ""));
tmp = mprintf("%s/.tmp-%i", CONFIG_VIDEOS_TMP, jobid);
dest = mprintf("%s/thumbnail/l_%s.jpg", CONFIG_VIDEOS_RELEASED, lectureid);
ping_job(jobid, "running", 0);
/* Open src */
demux = 0;
if (avformat_open_input(&demux, src, 0, 0))
goto fail;
if (err = avformat_open_input(&demux, src, 0, 0))
job_failed("Opening input file failed: %s", av_err2str(err));
avformat_find_stream_info(demux, 0);
if ((vidx = av_find_best_stream(demux, AVMEDIA_TYPE_VIDEO, -1, -1, 0, 0)) < 0)
goto fail;
job_failed("Could not find video stream in input file");
dec = avcodec_alloc_context3(avcodec_find_decoder(demux->streams[vidx]->codecpar->codec_id));
avcodec_parameters_to_context(dec, demux->streams[vidx]->codecpar);
avcodec_open2(dec, dec->codec, 0);
......@@ -71,8 +69,8 @@ int main(int argc, char *argv[])
avio_open(&mux->pb, tmp, AVIO_FLAG_WRITE);
avcodec_open2(enc, enc->codec, 0);
avcodec_parameters_from_context(mux->streams[0]->codecpar, enc);
if (avformat_write_header(mux, 0) < 0)
goto fail;
if ((err = avformat_write_header(mux, 0)) < 0)
job_failed("Writing temporary file failed: %s", av_err2str(err));
/* Create thumbnail */
av_seek_frame(demux, -1, (2L*demux->duration)/5L, 0);
......@@ -81,8 +79,8 @@ int main(int argc, char *argv[])
frame = av_frame_alloc();
do
{
if (av_read_frame(demux, &pkt))
goto fail;
if (err = av_read_frame(demux, &pkt))
job_failed("Reading frame failed: %s", av_err2str(err));
if (pkt.stream_index == vidx)
avcodec_send_packet(dec, &pkt);
}
......@@ -97,17 +95,12 @@ int main(int argc, char *argv[])
av_interleaved_write_frame(mux, &pkt);
}
av_interleaved_write_frame(mux, 0);
if (av_write_trailer(mux))
goto fail;
if (err = av_write_trailer(mux))
job_failed("Error writing trailer to temporary file: %s", av_err2str(err));
avio_closep(&mux->pb);
if (rename(tmp, dest))
goto fail;
job_failed("Overwriting output file failed: %s", strerror(errno));
unlink(tmp);
ping_job(jobid, "finished", "{\"log\": \"%s\"}", get_avlogbuf());
ping_job(jobid, "finished", "{\"log\": \"%s\"}", jescape(get_avlogbuf()));
return 0;
fail:
unlink(tmp);
ping_job(jobid, "failed", "{\"log\": \"%s\"}", get_avlogbuf());
return 1;
}
......@@ -4,14 +4,19 @@
/* Generic */
#define SL(s) (s), (sizeof(s)-1)
#define BL(b) (b), (sizeof(b))
size_t xvsnprintf(char *p, size_t len, const char *fmt, va_list ap);
size_t xsnprintf(char *p, size_t len, const char *fmt, ...);
extern int jobid;
char *vmprintf(const char *fmt, va_list ap);
char *mprintf(const char *fmt, ...);
/* Logging */
void init_avlogbuf(void);
void avlogbuf_callback(void *classp, int level, const char *fmt, va_list ap);
char *get_avlogbuf(void);
/* API */
int ping_job(int id, char *state, char *status, ...);
void job_failed(char *msg, ...);
/* JSON parser */
#define JSTR_SIZE 100
......@@ -24,4 +29,6 @@ char *jenter(char *s);
char *jnext(char *s);
char *jvalue(char *s);
char *jlookup(char *s, char *key);
/* JSON util */
char *jescape(char *s);
#include <curl/curl.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
......@@ -9,7 +10,7 @@
static size_t curl_write_cb(char *ptr, size_t size, size_t nmemb, void *user)
{
return size;
return size*nmemb;
}
int ping_job(int id, char *state, char *status, ...)
......@@ -17,39 +18,44 @@ int ping_job(int id, char *state, char *status, ...)
int ret;
CURL *curl;
va_list ap;
char *e_host, *e_status, *e_apikey, *e_state;
char url[100], buf[500];
char *p, *url, *e_host, *e_status, *e_apikey, *e_state;
char hostbuf[HOST_NAME_MAX+1];
if (!(curl = curl_easy_init()))
return -1;
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_cb);
e_apikey = curl_easy_escape(curl, CONFIG_APIKEY, 0);
e_state = curl_easy_escape(curl, state, 0);
if (gethostname(BL(buf)))
strcpy(buf, "localhost");
buf[sizeof(buf)-1] = 0;
e_host = curl_easy_escape(curl, buf, 0);
if (gethostname(BL(hostbuf)))
strcpy(hostbuf, "localhost");
e_host = curl_easy_escape(curl, hostbuf, 0);
if (status)
{
va_start(ap, status);
xvsnprintf(BL(buf), status, ap);
p = vmprintf(status, ap);
va_end(ap);
}
else
strcpy(buf, "{}");
e_status = curl_easy_escape(curl, buf, 0);
xsnprintf(BL(buf), "apikey=%s&state=%s&host=%s&status=%s",
e_apikey, e_state, e_host, e_status);
p = strdup("{}");
e_status = curl_easy_escape(curl, p, 0);
free(p);
p = mprintf("apikey=%s&state=%s&host=%s&status=%s", e_apikey, e_state,
e_host, e_status);
curl_free(e_apikey);
curl_free(e_state);
curl_free(e_host);
curl_free(e_status);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, buf);
xsnprintf(BL(url), "%s/internal/jobs/api/job/%i/ping", CONFIG_APIBASE, id);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, p);
url = mprintf("%s/internal/jobs/api/job/%i/ping", CONFIG_APIBASE, id);
curl_easy_setopt(curl, CURLOPT_URL, url);
ret = curl_easy_perform(curl);
free(p);
free(url);
curl_easy_cleanup(curl);
if (ret)
{
fprintf(stderr, "API call to \"%s\" failed: %s\n", url, curl_easy_strerror(ret));
return -1;
}
else
return 0;
}
......@@ -3,41 +3,38 @@
#include "../util.h"
static char *logbuffer = 0;
static size_t logoffset = 0, logsize = 0;
static pthread_mutex_t loglock = PTHREAD_MUTEX_INITIALIZER;;
static char *logbuffer;
static size_t logsize;
static FILE *logstream;
void init_avlogbuf(void)
{
logbuffer = 0;
logsize = 0;
if (!(logstream = open_memstream(&logbuffer, &logsize)))
exit(99);
av_log_set_callback(avlogbuf_callback);
}
void avlogbuf_callback(void *class, int level, const char *fmt, va_list ap)
{
int len, print_prefix;
int print_prefix;
char buf[200];
if (level >= AV_LOG_VERBOSE)
return;
av_log_default_callback(class, level, fmt, ap);
if (pthread_mutex_lock(&loglock))
return;
if (logsize-logoffset < 1024)
logbuffer = realloc(logbuffer, (logsize += 1024));
if (!logbuffer)
return;
print_prefix = 1;
len = av_log_format_line2(class, level, fmt, ap, logbuffer+logoffset,
logsize-logoffset, &print_prefix);
if (len < logsize-logoffset)
logoffset += len;
else
logoffset = logsize-1;
pthread_mutex_unlock(&loglock);
av_log_format_line(class, level, fmt, ap, BL(buf), &print_prefix);
fputs(buf, logstream);
}
char *get_avlogbuf(void)
{
char *ret, *p;
if (!logbuffer || pthread_mutex_lock(&loglock))
return strdup("");
ret = strdup(logbuffer);
pthread_mutex_unlock(&loglock);
for (p = ret; *p; p ++)
if (*p == '"')
*p = '\'';
return ret;
char *p;
if (!logstream)
return "";
fclose(logstream);
p = logbuffer;
init_avlogbuf();
fputs(p, logstream);
return p;
}
#include <stdio.h>
#include <stdlib.h>
#include "../util.h"
char *jescape(char *s)
{
int i;
char *ptr;
size_t size;
FILE *stream;
if (!(stream = open_memstream(&ptr, &size)))
exit(99);
for (; *s; s ++)
switch (*s)
{
case '"':
fputs("\\\"", stream); break;
case '\\':
fputs("\\\\", stream); break;
case '\b':
fputs("\\b", stream); break;
case '\f':
fputs("\\f", stream); break;
case '\n':
fputs("\\n", stream); break;
case '\r':
fputs("\\r", stream); break;
case '\t':
fputs("\\t", stream); break;
default:
if (*s <= 0x1f)
fprintf(stream, "\\u%04x", *s);
else
fputc(*s, stream);
}
fclose(stream);
return ptr;
}
#include <stdio.h>
#include <stdlib.h>
#include "../util.h"
int jobid;
void job_failed(char *msg, ...)
{
va_list ap;
va_start(ap, msg);
ping_job(jobid, "failed", "{\"reason\": \"%s\", \"log\": \"%s\"}",
jescape(vmprintf(msg, ap)), jescape(get_avlogbuf()));
va_end(ap);
exit(2);
}
......@@ -5,9 +5,6 @@
#include "../util.h"
static char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F'};
static char *skip_ws(char *s)
{
for (; *s == ' ' || *s == '\t' || *s == '\n' || *s == '\r'; s ++);
......@@ -213,41 +210,3 @@ char *jlookup(char *s, char *key)
return jvalue(s);
return 0;
}
char *jescape(char *s)
{
int i;
static __thread char buf[JSTR_SIZE];
for (i = 0; *s && i+7 < sizeof(buf); s ++)
switch (*s)
{
case '"':
buf[i ++] = '\\'; buf[i ++] = '"'; break;
case '\\':
buf[i ++] = '\\'; buf[i ++] = '\\'; break;
case '\b':
buf[i ++] = '\\'; buf[i ++] = 'b'; break;
case '\f':
buf[i ++] = '\\'; buf[i ++] = 'f'; break;
case '\n':
buf[i ++] = '\\'; buf[i ++] = 'n'; break;
case '\r':
buf[i ++] = '\\'; buf[i ++] = 'r'; break;
case '\t':
buf[i ++] = '\\'; buf[i ++] = 't'; break;
default:
if (*s <= 0x1f)
{
buf[i ++] = '\\';
buf[i ++] = 'u';
buf[i ++] = '0';
buf[i ++] = '0';
buf[i ++] = hex[*s >> 4];
buf[i ++] = hex[*s & 0xf];
}
else
buf[i ++] = *s;
}
buf[i] = 0;
return buf;
}
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include "../util.h"
char *vmprintf(const char *fmt, va_list ap)
{
char *ptr;
size_t size;
FILE *stream;
ptr = 0;
size = 0;
if (!(stream = open_memstream(&ptr, &size)))
exit(99);
if (vfprintf(stream, fmt, ap) < 0)
exit(99);
fclose(stream);
return ptr;
}
char *mprintf(const char *fmt, ...)
{
char *ret;
va_list ap;
va_start(ap, fmt);
ret = vmprintf(fmt, ap);
va_end(ap);
return ret;
}
#include <stdio.h>
#include <stdarg.h>
#include "../util.h"
size_t xvsnprintf(char *p, size_t len, const char *fmt, va_list ap)
{
int ret;
if ((ret = vsnprintf(p, len, fmt, ap)) >= len)
{
p[len-1] = 0;
return len;
}
return ret;
}
size_t xsnprintf(char *p, size_t len, const char *fmt, ...)
{
size_t ret;
va_list ap;
va_start(ap, fmt);
ret = vsnprintf(p, len, fmt, ap);
va_end(ap);
return ret;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment