complex_live_transcode.c 3.29 KB
Newer Older
Julian Rother's avatar
Julian Rother committed
1 2 3 4 5 6 7
#include <poll.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "util.h"

8
#define OUTPUT_FORMAT(bitrate) "-f", "flv", "-r", "25", "-c:v", "libx264", "-b:v", bitrate, "-bufsize", bitrate, "-preset", "veryfast", "-x264-params", "keyint=125:min-keyint=125:no-scenecut", "-c:a", "aac"
Julian Rother's avatar
Julian Rother committed
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

static void copy_to_log(int fd)
{
	static char buf[1024];
	size_t len;
	if ((len = read(fd, BL(buf))) > 0)
		fwrite(buf, 1, len, logstream);
}

int main(int argc, char *argv[])
{
	int ret, canceled = 0, errpipe[2] = {-1, -1};
	char *src1, *src2, *src1fmt = "flv", *src2fmt = "flv", *dest, *logo_expr;
	pid_t pid;
	struct pollfd fds = {.fd = -1, .events = POLLIN};
	if (argc != 5)
		return 1;
	init_env();
	init_avlogbuf();
	jobid = atoi(argv[1]);
	src1 = jlookup(argv[4], "src1");
	src2 = jlookup(argv[4], "src2");
	if (!jstr(jlookup(src1, "url"), 0))
		src1fmt = "lavfi";
	if (!jstr(jlookup(src2, "url"), 0))
		src2fmt = "lavfi";
	dest = jstr(jlookup(argv[4], "destbase"), "rtmp://127.0.0.1:999999/nourl");
	if (jint(jlookup(argv[4], "videoag_logo"), 1))
		logo_expr = "overlay=x=W-195:y=H-155";
	else
		logo_expr = "overlay=x=W+1000:y=H+1000";

	pipe(errpipe);
	if (!(pid = fork()))
	{
		close(errpipe[0]);
		dup2(errpipe[1], 2); close(errpipe[1]);
		dup2(open("/dev/null", O_RDONLY|O_CLOEXEC), 0);
		dup2(open("/dev/null", O_WRONLY|O_CLOEXEC), 1);
		execlp("ffmpeg", "ffmpeg", "-nostats",
49 50
				"-f", src1fmt, "-i", jstr(jlookup(src1, "url"), "smptehdbars,scale=1920:1080[out0]; anullsrc[out1]"),
				"-f", src2fmt, "-i", jstr(jlookup(src2, "url"), "smptehdbars,scale=1920:1080[out0]; anullsrc[out1]"),
Julian Rother's avatar
Julian Rother committed
51
				"-filter_complex",
52
				mprintf("[0:a]%s[a1]; [1:a]%s[a2]; [a1][a2]amix,%s,asplit=3[lowa][mida][higha];"
Julian Rother's avatar
Julian Rother committed
53 54
					"[0:v]%s[v1]; [1:v]%s[v2]; [v1][v2]%s,scale=1920:1080[tmp];"
					"movie=%s/video-logo-150px-trans.png,scale=w=100:h=100[logo];"
55
					"[tmp][logo]%s,split=3[lowtmp][midtmp][high];"
Julian Rother's avatar
Julian Rother committed
56 57
					"[lowtmp]scale=640:360[low];"
					"[midtmp]scale=1280:720[mid]",
58 59 60 61 62
					jstr(jlookup(src1, "afilter"), "anull"),
					jstr(jlookup(src2, "afilter"), "anull"),
					jstr(jlookup(argv[4], "afilter"), "anull"),
					jstr(jlookup(src1, "vfilter"), "null"),
					jstr(jlookup(src2, "vfilter"), "null"),
Julian Rother's avatar
Julian Rother committed
63 64 65 66
					jstr(jlookup(argv[4], "vmix"), "streamselect=map=0"),
					getenv(WORKER_RAW), logo_expr
				),
				"-map", "[low]", "-map", "[lowa]", OUTPUT_FORMAT("512k"), mprintf("%s_low", dest),
67 68
				"-map", "[mid]", "-map", "[mida]", OUTPUT_FORMAT("2024k"), mprintf("%s_mid", dest),
				"-map", "[high]", "-map", "[higha]", OUTPUT_FORMAT("6024k"), mprintf("%s_high", dest), 0);
Julian Rother's avatar
Julian Rother committed
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
		exit(1);
	}
	close(errpipe[1]);
	fds.fd = errpipe[0];

	while (1)
	{
		canceled = ping_job(jobid, "running", "{\"log\": \"%s\"}", jescape(get_avlogbuf()));
		if (canceled == 1)
			kill(pid, SIGINT); /* Stop ffmpeg */
		poll(&fds, 1, 15000);
		if (fds.revents & POLLIN)
			copy_to_log(fds.fd);
		else if (fds.revents & (POLLERR|POLLHUP|POLLNVAL))
			break;
	}

	waitpid(pid, &ret, 0);
	if (canceled == 1 && (WEXITSTATUS(ret) == 255 || (WIFSIGNALED(ret) && WTERMSIG(ret) == SIGINT)))
		ping_job(jobid, "finished", "{\"log\": \"%s\"}", jescape(get_avlogbuf()));
	else if (WIFSIGNALED(ret))
		job_failed("Subprocesses was killed by signal %s (%i)", strsignal(WTERMSIG(ret)), WTERMSIG(ret));
	else
		job_failed("Subprocesses terminated with exit status %i", WEXITSTATUS(ret));
	return 0;
}