shithub: treason

ref: febd271a231c83b67d94e6cb2b9942edfe37e363
dir: /stream_mc.c/

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

enum {
	Maxstreams = 3,
	Bufsz = 64*1024,
};

typedef struct MCaux MCaux;

struct MCaux {
	int fd;
	Biobuf bio;
	u8int buf[Bufsz];
};

extern uvlong trackpref;

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

	pipe(p);
	if((pid = rfork(RFFDG|RFPROC)) == 0){
		close(0);
		close(p[0]);
		dup(p[1], 1); close(p[1]);
		exec("/bin/mcfs", argv);
		sysfatal("exec: %r");
	}
	close(p[1]);
	if(pid < 0)
		close(p[0]);
	*pipefd = p[0];

	return pid;
}

static void
freeaux(void *aux)
{
	MCaux *a;

	a = aux;
	close(a->fd);
	free(a);
}

static Stream *
mcopen(char *filename, int *num, int *failed)
{
	Waitmsg *w;
	char *line;
	int p, pid, n, ns;
	Biobuf b;
	MCaux *a;
	char *argv[] = {
		"mcfs",
		filename,
		nil,
		nil,
		nil,
	};
	Stream *s, *streams;
	int nvideo, naudio, nsub, 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 = nsub = 0; ns < Maxstreams && (line = Brdstr(&b, '\n', 1)) != nil;){
		n = tokenize(line, v, nelem(v));
		if(trackpref != 0 && (trackpref & (1<<atoi(v[0]))) == 0)
			continue;
		if(n >= 3 && str2fmt(v[2]) >= 0){
			argv[1] = "-t";
			argv[2] = v[0]; /* stream id */
			argv[3] = filename;
			s = streams+ns;

			if(n >= 5 && nvideo < 1 && strcmp(v[1], "video") == 0){
				s->video.w = atoi(v[3]);
				s->video.h = atoi(v[4]);
				if(mcfs(argv, &sp) > 0){
					if((a = malloc(sizeof(*a))) == nil)
						sysfatal("memory");
					a->fd = sp;
					s->aux = a;
					s->freeaux = freeaux;
					if(Binits(&a->bio, sp, OREAD, a->buf, Bufsz) == 0 && ivfopenb(&a->bio, s, failed) == 0){
						nvideo++;
						ns++;
					}
				}
			}else if(n >= 5 && naudio < 1 && strcmp(v[1], "audio") == 0 && (s->fmt = str2fmt(v[2])) >= 0){
				s->audio.nchan = atoi(v[3]);
				s->audio.srate = atoi(v[4]);
				snprint(s->info, sizeof(s->info), "%s (%d %d)", v[2], s->audio.nchan, s->audio.srate);
				if(mcfs(argv, &sp) > 0 && audopenfd(sp, s, failed) == 0){
					naudio++;
					ns++;
				}
			}else if(n >= 3 && nsub < 1 && strcmp(v[1], "subtitle") == 0 && (s->fmt = str2fmt(v[2])) >= 0){
				snprint(s->info, sizeof(s->info), "%s (%s)", v[2], (n > 3 && *v[3]) ? v[3] : "default");
				if(mcfs(argv, &sp) > 0 && subopenfd(sp, s, failed) == 0){
					nsub++;
					ns++;
				}
			}
		}
		free(line);
	}
	Bterm(&b);

	*num = ns;
	if(ns < 1){
		werrstr("no supported video 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,
};