shithub: treason

ref: 0a0e38c97f48a3dc902b71eaf31905a63a832232
dir: /stream_mc.c/

View raw version
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "stream.h"
#include "misc.h"

enum {
	Maxstreams = 2,
};

static int
mcfs(char **argv, int *pipefd)
{
	int p[2], pid, fd;

	pipe(p);
	if((pid = rfork(RFFDG|RFPROC|RFNOMNT)) == 0){
		close(0);
		close(p[0]);
		dup(p[1], 1); close(p[1]);
		if(!debug){
			dup(fd = open("/dev/null", OWRITE), 2);
			close(fd);
		}
		exec("/bin/mcfs", argv);
		sysfatal("exec: %r");
	}
	close(p[1]);
	if(pid < 0)
		close(p[0]);
	*pipefd = p[0];

	return pid;
}

static int
audfmt(char *fmt)
{
	static char *fmts[] = {
		[FmtAAC] = "mp4a",
		[FmtOpus] = "opus",
	};
	int i;

	for(i = 0; i < nelem(fmts); i++){
		if(fmts[i] != nil && strcmp(fmt, fmts[i]) == 0)
			return i;
	}

	return -1;
}

static Stream *
mcopen(char *filename, int *num, int *failed)
{
	Waitmsg *w;
	char *line;
	int p, pid, n, ns;
	Biobuf b;
	char *argv[] = {
		"mcfs",
		"-i",
		filename,
		nil,
		nil,
	};
	Stream *s, *streams;
	int nvideo, naudio, sp;
	char *v[8];

	if((pid = mcfs(argv, &p)) < 0)
		return nil;
	if((streams = calloc(Maxstreams, sizeof(Stream))) == nil)
		return nil;

	Binit(&b, p, OREAD);
	for(ns = naudio = nvideo = 0; ns < Maxstreams && (line = Brdstr(&b, '\n', 1)) != nil;){
		n = tokenize(line, v, nelem(v));
		if(n > 4 && str2fmt(v[2]) >= 0){
			argv[1] = "-t";
			argv[2] = v[0]; /* stream id */
			argv[3] = filename;
			s = streams+ns;

			if(nvideo < 1 && strcmp(v[1], "video") == 0){
				s->video.w = atoi(v[3]);
				s->video.h = atoi(v[4]);
				if(mcfs(argv, &sp) > 0 && ivfopenb(Bfdopen(sp, OREAD), s, failed) == 0){
					nvideo++;
					ns++;
				}
			}else if(naudio < 1 && strcmp(v[1], "audio") == 0 && (s->fmt = audfmt(v[2])) >= 0){
				s->audio.nchan = atoi(v[3]);
				s->audio.srate = atoi(v[4]);
				if(mcfs(argv, &sp) > 0 && audopenfd(sp, s, failed) == 0){
					naudio++;
					ns++;
				}
			}
		}
		free(line);
	}
	Bterm(&b);

	*num = ns;
	if(ns < 1){
		werrstr("no streams");
		*failed = 1;

		free(streams);
		streams = nil;

		while((w = wait()) != nil){
			if(w->pid == pid){
				if(w->msg[0] != 0){
					werrstr("%s", w->msg);
					goto err;
				}
				free(w);
				break;
			}
			free(w);
		}
	}

	return streams;
err:
	free(w);
	free(streams);
	return nil;
}

Streamops mcops = {
	.open = mcopen,
};