From 03ba7991cffb0204295f1c6fc793331b8d6f63dc Mon Sep 17 00:00:00 2001
From: Julian Rother <julianr@fsmpi.rwth-aachen.de>
Date: Sun, 29 Oct 2017 03:44:42 +0100
Subject: [PATCH] Added remux worker

---
 remux.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 115 insertions(+)
 create mode 100644 remux.c

diff --git a/remux.c b/remux.c
new file mode 100644
index 0000000..7160d1b
--- /dev/null
+++ b/remux.c
@@ -0,0 +1,115 @@
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+
+#include "util.h"
+#include "config.h"
+
+static AVRational chapter_time_base = {1, 1};
+
+void parse_dict(AVDictionary **d, char *s)
+{
+	char key[JSTR_SIZE], value[JSTR_SIZE];
+	for (s = jenter(s); s; s = jnext(s))
+		av_dict_set(d, jstrb(s, 0, key), jstrb(jvalue(s), 0, value), 0);
+}
+
+void parse_chapters(AVFormatContext *ctx, char *s, int duration)
+{
+	char *p;
+	int i;
+	for (p = jenter(s), i = 0; p; p = jnext(p), i ++);
+	ctx->chapters = malloc(sizeof(AVChapter *)*i);
+	ctx->nb_chapters = i;
+	for (p = jenter(s), i = 0; p; p = jnext(p), i ++)
+	{
+		ctx->chapters[i] = malloc(sizeof(AVChapter));
+		memset(ctx->chapters[i], 0, sizeof(AVChapter));
+		ctx->chapters[i]->id = i;
+		ctx->chapters[i]->time_base = chapter_time_base;
+		ctx->chapters[i]->start = jint(jlookup(p, "time"), 0);
+		av_dict_set(&ctx->chapters[i]->metadata, "title", jstr(jlookup(p, "text"), "EMPTY"), 0);
+		if (i)
+			ctx->chapters[i-1]->end = ctx->chapters[i]->start;
+	}
+	ctx->chapters[i-1]->end = duration;
+}
+
+int main(int argc, char *argv[])
+{
+	int jobid, i;
+	int *idxmap;
+	char *p, path[100], tmp[100];
+	AVFormatContext *demux, *mux;
+	AVPacket pkt;
+	AVStream *stream;
+	if (argc != 5)
+		return 1;
+	av_register_all();
+	av_log_set_callback(avlogbuf_callback);
+	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);
+	ping_job(jobid, "running", 0);
+
+	demux = 0;
+	if (avformat_open_input(&demux, path, 0, 0))
+		goto fail;
+	avformat_find_stream_info(demux, 0);
+	avformat_alloc_output_context2(&mux, 0, 0, path);
+	parse_dict(&mux->metadata, jlookup(argv[4], "metadata"));
+	parse_chapters(mux, jlookup(argv[4], "chapters"), av_rescale_q(demux->duration, AV_TIME_BASE_Q, chapter_time_base));
+	idxmap = malloc(sizeof(int)*demux->nb_streams);
+	for (i = 0; i < demux->nb_streams; i ++)
+	{
+		if (demux->streams[i]->codecpar->codec_type != AVMEDIA_TYPE_AUDIO
+				&& demux->streams[i]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO
+				&& demux->streams[i]->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE)
+		{
+			idxmap[i] = -1;
+			continue;
+		}
+		stream = avformat_new_stream(mux, 0);
+		idxmap[i] = stream->index;
+		avcodec_parameters_copy(mux->streams[i]->codecpar,
+				demux->streams[i]->codecpar);
+		mux->streams[i]->codecpar->codec_tag = 0;
+		mux->streams[i]->time_base = demux->streams[i]->time_base;
+	}
+	avio_open(&mux->pb, tmp, AVIO_FLAG_WRITE);
+	if (avformat_write_header(mux, 0) < 0)
+		goto fail;
+	while (!av_read_frame(demux, &pkt))
+	{
+		if (pkt.stream_index >= demux->nb_streams
+				|| idxmap[pkt.stream_index] == -1)
+			continue;
+		pkt.stream_index = idxmap[pkt.stream_index];
+		pkt.pts = av_rescale_q_rnd(pkt.pts, demux->streams[pkt.stream_index]->time_base,
+				mux->streams[pkt.stream_index]->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
+		pkt.dts = av_rescale_q_rnd(pkt.dts, demux->streams[pkt.stream_index]->time_base,
+				mux->streams[pkt.stream_index]->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
+		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;
+	}
+	av_interleaved_write_frame(mux, 0);
+	if (av_write_trailer(mux))
+		goto fail;
+	avio_closep(&mux->pb);
+	if (rename(tmp, path))
+		goto fail;
+	unlink(tmp);
+	ping_job(jobid, "finished", "{\"log\": \"%s\"}", get_avlogbuf());
+	return 0;
+
+fail:
+	unlink(tmp);
+	ping_job(jobid, "failed", "{\"log\": \"%s\"}", get_avlogbuf());
+	return 1;
+}
-- 
GitLab