remux.c 3.69 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
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#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);
Julian Rother's avatar
Julian Rother committed
63
	av_dict_copy(&mux->metadata, demux->metadata, 0);
Julian Rother's avatar
Julian Rother committed
64
65
66
67
68
	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 ++)
	{
Julian Rother's avatar
Julian Rother committed
69
		idxmap[i] = -1;
Julian Rother's avatar
Julian Rother committed
70
71
72
73
74
		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)
			continue;
		stream = avformat_new_stream(mux, 0);
Julian Rother's avatar
Julian Rother committed
75
		av_dict_copy(&stream->metadata, mux->streams[i]->metadata, 0);
Julian Rother's avatar
Julian Rother committed
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
		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;
}