simple_live_transcode.c 2.41 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#include <poll.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "util.h"

#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"

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[])
{
Julian Rother's avatar
Julian Rother committed
20
	int ret, canceled = 0, errpipe[2] = {-1, -1};
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
	char *src, *dest;
	pid_t pid;
	struct pollfd fds = {.fd = -1, .events = POLLIN};
	if (argc != 5)
		return 1;
	init_env();
	init_avlogbuf();
	jobid = atoi(argv[1]);
	src = jstr(jlookup(argv[4], "src"), "rtmp://127.0.0.1:999999/nourl");
	dest = jstr(jlookup(argv[4], "destbase"), "rtmp://127.0.0.1:999999/nourl");

	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", "-i", src, "-filter_complex",
				mprintf("[0:a]asplit=3[lowa][mida][higha]; movie=%s/video-logo-150px-trans.png,scale=w=100:h=100[logo]; [0:v]yadif,scale=1920:1080[tmp]; [tmp][logo]overlay=x=W-195:y=H-155,split=3[lowtmp][midtmp][high]; [lowtmp]scale=640:360[low]; [midtmp]scale=1280:720[mid]", getenv(WORKER_RAW)),
				"-map", "[low]", "-map", "[lowa]", OUTPUT_FORMAT("512k"), mprintf("%s_low", dest),
				"-map", "[mid]", "-map", "[mida]", OUTPUT_FORMAT("2024k"), mprintf("%s_mid", dest),
				"-map", "[high]", "-map", "[higha]", OUTPUT_FORMAT("6024k"), mprintf("%s_high", dest), 0);
		exit(1);
	}
	close(errpipe[1]);
	fds.fd = errpipe[0];

	while (1)
	{
Julian Rother's avatar
Julian Rother committed
51
		canceled = ping_job(jobid, "running", "{\"log\": \"%s\"}", jescape(get_avlogbuf()));
Julian Rother's avatar
Julian Rother committed
52
		if (canceled == 1)
Julian Rother's avatar
Julian Rother committed
53
			kill(pid, SIGINT); /* Stop ffmpeg */
54 55 56 57 58 59 60 61
		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);
Julian Rother's avatar
Julian Rother committed
62
	if (canceled == 1 && (WEXITSTATUS(ret) == 255 || (WIFSIGNALED(ret) && WTERMSIG(ret) == SIGINT)))
63 64 65 66 67 68 69
		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;
}