ref: 4812d7f4d60a30404a8f0d0cb1f244ae288387d5
parent: 3f03592d6961c9f33b681b3269803739766b0c4b
author: Sigrid Haflínudóttir <ftrvxmtrx@gmail.com>
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,
};
--
⑨