shithub: treason

Download patch

ref: 4812d7f4d60a30404a8f0d0cb1f244ae288387d5
parent: 3f03592d6961c9f33b681b3269803739766b0c4b
author: Sigrid Haflínudóttir <[email protected]>
date: Thu Sep 10 08:28:42 EDT 2020

support MP4 container via mcfs

--- a/main.c
+++ b/main.c
@@ -95,7 +95,11 @@
 		[Cnum] = { nil, nil, CHANEND },
 	};
 
+	debug = 0;
 	ARGBEGIN{
+	case 'd':
+		debug++;
+		break;
 	}ARGEND
 
 	if(argc < 1)
@@ -102,6 +106,8 @@
 		sysfatal("usage");
 
 	nproc = atoi((s = getenv("NPROC")) != nil ? s : "1");
+	if(nproc < 1)
+		nproc = 1;
 
 	srand(nanosec());
 	if(initdraw(nil, nil, "treason") < 0)
--- a/misc.c
+++ b/misc.c
@@ -1,8 +1,28 @@
 #include <u.h>
 #include <libc.h>
 #include <tos.h>
+#include "misc.h"
+#include "stream.h"
 
-int nproc;
+int nproc, debug;
+
+static char *fmts[] = {
+	[FmtAV1]  = "av01",
+	[FmtVP9]  = "vp09",
+	[FmtVP8]  = "vp08",
+	[FmtAAC]  = "mp4a",
+	[FmtOpus] = "opus",
+};
+
+int
+str2fmt(char *s)
+{
+	int i;
+
+	for(i = 0; i < nelem(fmts) && strcmp(fmts[i], s) != 0; i++);
+
+	return i < nelem(fmts) ? i : -1;
+}
 
 uvlong
 nanosec(void)
--- a/misc.h
+++ b/misc.h
@@ -1,3 +1,4 @@
+int str2fmt(char *s);
 uvlong nanosec(void);
 void yuv420_rgb24(
 	u32int width, u32int height,
@@ -5,3 +6,4 @@
 	u8int *RGB, u32int RGB_stride);
 
 extern int nproc;
+extern int debug;
--- a/stream.c
+++ b/stream.c
@@ -9,8 +9,8 @@
 	char *name;
 	Streamops *o;
 }ops[] = {
-	{"ivf", &ivfops},
 	{"mp4", &mp4ops},
+	{"ivf", &ivfops},
 };
 
 Stream *
@@ -21,10 +21,8 @@
 
 	for(i = 0; i < nelem(ops); i++){
 		failed = 0;
-		if((s = ops[i].o->open(filename, &failed, num)) != nil){
-			memmove(&s->ops, ops[i].o, sizeof(Streamops));
+		if((s = ops[i].o->open(filename, &failed, num)) != nil)
 			return s;
-		}
 		if(failed){
 			werrstr("%s: %r", ops[i].name);
 			return nil;
--- a/stream.h
+++ b/stream.h
@@ -26,7 +26,7 @@
 };
 
 struct Streamops {
-	Stream *(*open)(char *filename, int *num, int *failed);
+	Stream *(*open)(char *path, int *num, int *failed);
 	u8int *(*alloc)(void *aux, int sz);
 	void (*close)(Stream *s);
 	vlong (*offset)(Stream *s);
@@ -69,3 +69,5 @@
 vlong Soffset(Stream *s);
 void Sclose(Stream *s);
 int Sread(Stream *s, Streamframe *f);
+
+int ivfopenb(void *bio, Stream *s, int *failed);
--- a/stream_ivf.c
+++ b/stream_ivf.c
@@ -3,6 +3,8 @@
 #include <bio.h>
 #include "stream.h"
 
+extern Streamops ivfops;
+
 static int
 Bu16le(Biobuf *b, u16int *o)
 {
@@ -49,23 +51,28 @@
 	return 0;
 }
 
-static Stream *
-ivfopen(char *filename, int *num, int *failed)
+int
+ivfopenb(void *bio, Stream *s, int *failed)
 {
-	Biobuf *b;
-	Stream *s;
 	u16int hlen, w, h, fmt;
 	u32int tbdenum, tbnum;
 	char tmp[6];
 
-	s = nil;
-	if((b = Bopen(filename, OREAD)) == nil)
-		return nil;
-	if(Bread(b, tmp, 6) != 6 || memcmp(tmp, "DKIF", 4) != 0 || Bu16le(b, &hlen) < 0){
-		Bterm(b);
-		return nil;
+	if(bio == nil){
+		werrstr("nil bio");
+		return -1;
 	}
-	if(hlen < 0x20 || Bread(b, tmp, 4) != 4){
+	if(Bread(bio, tmp, 6) != 6 || Bu16le(bio, &hlen) < 0){
+		werrstr("header read failed");
+		Bterm(bio);
+		return -1;
+	}
+	if(memcmp(tmp, "DKIF", 4) != 0){
+		werrstr("expected DKIF, got %02x%02x%02x%02x", tmp[0], tmp[1], tmp[2], tmp[3]);
+		Bterm(bio);
+		return -1;
+	}
+	if(hlen < 0x20 || Bread(bio, tmp, 4) != 4){
 		werrstr("invalid header: hlen=%d", hlen);
 		goto err;
 	}
@@ -81,18 +88,15 @@
 		goto err;
 	}
 
-	if(Bu16le(b, &w) < 0 || Bu16le(b, &h) < 0 || Bu32le(b, &tbdenum) < 0 || Bu32le(b, &tbnum) < 0){
+	if(Bu16le(bio, &w) < 0 || Bu16le(bio, &h) < 0 || Bu32le(bio, &tbdenum) < 0 || Bu32le(bio, &tbnum) < 0){
 		werrstr("invalid header: %r");
 		goto err;
 	}
-	if(Bseek(b, hlen, 0) != hlen){
+	if(Bseek(bio, hlen, 0) != hlen){
 		werrstr("invalid IVF stream");
 		goto err;
 	}
 
-	if((s = calloc(1, sizeof(*s))) == nil)
-		goto err;
-	*num = 1;
 	s->type = Svideo;
 	s->fmt = fmt;
 	s->video.w = w;
@@ -99,14 +103,34 @@
 	s->video.h = h;
 	s->timebase.denum = tbdenum;
 	s->timebase.num = tbnum;
-	s->b = b;
+	s->b = bio;
+	memmove(&s->ops, &ivfops, sizeof(ivfops));
 
-	return s;
+	return 0;
 err:
 	*failed = 1;
-	Bterm(b);
+	Bterm(bio);
 	free(s);
-	return nil;
+	return -1;
+}
+
+static Stream *
+ivfopen(char *path, int *num, int *failed)
+{
+	Stream *s;
+
+	if((s = calloc(1, sizeof(*s))) == nil){
+		*failed = 1;
+		return nil;
+	}
+
+	*num = 1;
+	if(ivfopenb(Bopen(path, OREAD), s, failed) != 0){
+		free(s);
+		s = nil;
+	}
+
+	return s;
 }
 
 static void
--- a/stream_mp4.c
+++ b/stream_mp4.c
@@ -2,37 +2,108 @@
 #include <libc.h>
 #include <bio.h>
 #include "stream.h"
+#include "misc.h"
 
-static Stream *
-mp4open(char *filename, int *num, int *failed)
+enum {
+	Maxstreams = 2,
+};
+
+static int
+mcfs(char **argv, int *pipefd)
 {
-	USED(filename); USED(num); USED(failed);
-	return nil;
+	int p[2], pid, fd;
+
+	pipe(p);
+	if((pid = rfork(RFPROC|RFFDG|RFREND)) == 0){
+		close(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 void
-mp4close(Stream *s)
+static Stream *
+mp4open(char *filename, int *num, int *failed)
 {
-	free(s);
-}
+	Waitmsg *w;
+	char *line;
+	int p, pid, n, ns;
+	Biobuf b;
+	char *argv[] = {
+		"mcfs",
+		"-i",
+		filename,
+		nil,
+		nil,
+	};
+	Stream *streams;
+	int nvideo, naudio, sp;
+	char *v[8];
 
-static int
-mp4read(Stream *s, Streamframe *f)
-{
-	USED(s); USED(f);
-	return -1;
-}
+	if((pid = mcfs(argv, &p)) < 0)
+		return nil;
+	if((streams = calloc(Maxstreams, sizeof(Stream))) == nil)
+		return nil;
 
-static vlong
-mp4offset(Stream *s)
-{
-	USED(s);
-	return -1;
+	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;
+
+			if(nvideo < 1 && strcmp(v[1], "video") == 0){
+				if(mcfs(argv, &sp) > 0 && ivfopenb(Bfdopen(sp, OREAD), streams+ns, failed) == 0){
+					nvideo++;
+					ns++;
+				}
+			}else if(naudio < 1 && strcmp(v[1], "audio") == 0){
+				/* FIXME add audio streams */
+			}
+		}
+		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 mp4ops = {
 	.open = mp4open,
-	.close = mp4close,
-	.read = mp4read,
-	.offset = mp4offset,
 };