probe.c 2.79 KB
Newer Older
Julian Rother's avatar
Julian Rother committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>

#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>

#include "util.h"

static char *getxmlattr(xmlAttr *a, char *name, char *err)
{
	for (; a && strcmp(a->name, name); a = a->next);
	if (!a)
		return err;
	return a->children->content;
}

char *get_xmpchapters(char *xmp)
{
Julian Rother's avatar
Julian Rother committed
21
22
23
24
	int i;
	char *ptr;
	size_t size;
	FILE *stream;
Julian Rother's avatar
Julian Rother committed
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
	xmlDocPtr doc;
	xmlXPathContextPtr xpath;
	xmlXPathObjectPtr res;
	xmlNodePtr node;
	double framerate, start;
	if (!(doc = xmlParseMemory(xmp, strlen(xmp))))
		return "";
	if (!(xpath = xmlXPathNewContext(doc)))
		return "";
	xmlXPathRegisterNs(xpath, "x", "adobe:ns:meta/");
	xmlXPathRegisterNs(xpath, "rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
	xmlXPathRegisterNs(xpath, "xmpDM", "http://ns.adobe.com/xmp/1.0/DynamicMedia/");
	res = xmlXPathEvalExpression("/x:xmpmeta/rdf:RDF/rdf:Description/@xmpDM:videoFrameRate", xpath);
	if (!res || !res->nodesetval->nodeNr)
		return "";
	framerate = strtod(res->nodesetval->nodeTab[0]->children->content, 0);
	xmlXPathFreeObject(res);
	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 "";
Julian Rother's avatar
Julian Rother committed
45
46
47
48
49
	ptr = 0;
	size = 0;
	if (!(stream = open_memstream(&ptr, &size)))
		exit(99);
	fprintf(stream, "[");
Julian Rother's avatar
Julian Rother committed
50
51
52
53
	for (i = 0; i < res->nodesetval->nodeNr; i ++)
	{
		start = atoi(getxmlattr(res->nodesetval->nodeTab[i]->properties, "startTime", "0"))/framerate;
		if (i)
Julian Rother's avatar
Julian Rother committed
54
55
56
			fprintf(stream, ",");
		fprintf(stream, "{\"time\": %f, \"text\": \"%s\"}", start,
				jescape(getxmlattr(res->nodesetval->nodeTab[i]->properties, "name", "")));
Julian Rother's avatar
Julian Rother committed
57
	}
Julian Rother's avatar
Julian Rother committed
58
59
60
	fprintf(stream, "]");
	fclose(stream);
	return ptr;
Julian Rother's avatar
Julian Rother committed
61
62
63
64
}

int main(int argc, char *argv[])
{
Julian Rother's avatar
Julian Rother committed
65
	int err;
66
	char *path, *xmp, *xmp_chapters = "[]";
Julian Rother's avatar
Julian Rother committed
67
68
69
70
71
72
	AVFormatContext *demux, *mux;
	AVDictionaryEntry *tag;
	AVDictionary *opts;
	if (argc != 5)
		return 1;
	av_register_all();
73
	init_env();
Julian Rother's avatar
Julian Rother committed
74
	init_avlogbuf();
Julian Rother's avatar
Julian Rother committed
75
76

	jobid = atoi(argv[1]);
77
78
79
80
	if (!strcmp(argv[2], "probe-raw"))
		path = mprintf("%s/%s", getenv(WORKER_RAW), jstr(jlookup(argv[4], "path"), ""));
	else
		path = mprintf("%s/%s", getenv(WORKER_RELEASED), jstr(jlookup(argv[4], "path"), ""));
Julian Rother's avatar
Julian Rother committed
81
82
83
	ping_job(jobid, "running", 0);

	opts = 0;
84
	av_dict_set_int(&opts, "export_xmp", 1, 0); /* Ignored if not supported */
Julian Rother's avatar
Julian Rother committed
85
	demux = 0;
Julian Rother's avatar
Julian Rother committed
86
87
	if (err = avformat_open_input(&demux, path, 0, &opts))
		job_failed("Opening input file failed: %s", av_err2str(err));
Julian Rother's avatar
Julian Rother committed
88
89
	avformat_find_stream_info(demux, 0);
	if (tag = av_dict_get(demux->metadata, "xmp", 0, 0))
90
91
92
		xmp_chapters = get_xmpchapters(tag->value);
	ping_job(jobid, "finished", "{%s, \"xmp_chapters\": %s, \"log\": \"%s\"}",
			json_fileinfo(path), xmp_chapters, jescape(get_avlogbuf()));
Julian Rother's avatar
Julian Rother committed
93
94
	return 0;
}