ref: 7d4898f6656fd7c060bb27c0b10d6735a1f76337
dir: /main.c/
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <bio.h>
#include "adts.h"
#include "ivf.h"
#include "rtmp.h"
#include "util.h"
typedef struct Conn Conn;
struct Conn {
char *url;
RTMP *r;
ulong sid;
};
int mainstacksize = 65536;
int debug = 0;
static Conn *cs;
static int ncs;
static uvlong ns₀, vms;
static uvlong
ns2ms(uvlong z, uvlong ns)
{
if(z != 0 && z != Zns₀)
ns = z - ns₀ + ns;
return ns / 1000000ULL;
}
static void
audio(void *aux)
{
ADTSFrame af;
Biobuf *a;
u64int ms;
Conn *c;
int i;
a = aux;
memset(&af, 0, sizeof(af));
af.ns₀ = Zns₀;
for(;;){
if(adtsread(a, &af) != 0)
sysfatal("%r");
if(af.sz == 0) /* eof */
break;
ms = ns2ms(af.ns₀, af.ns);
for(c = cs, i = 0; i < ncs; i++, c++){
if(rtmpdata(c->r, c->sid, ms, Taudio, af.buf, af.sz) != 0){
fprint(2, "%s: %r\n", c->url);
goto out;
}
}
/* protect against overruns */
if(vms+200 < ms)
sleep(100);
}
/* FIXME properly close RTMP connection */
out:
threadexitsall(nil);
}
static void
usage(void)
{
fprint(2, "usage: %s [-a AUDIO] URL [URL...]\n", argv0);
threadexitsall("usage");
}
void
threadmain(int argc, char **argv)
{
Biobuf *a, v;
IVFrame vf;
u64int ms;
IVF ivf;
Conn *c;
int i;
a = nil;
ARGBEGIN{
case 'd':
debug++;
break;
case 'a':
if((a = Bopen(EARGF(usage()), OREAD)) == nil)
sysfatal("%r");
break;
default:
usage();
}ARGEND
ncs = argc;
if(ncs < 1)
usage();
ns₀ = nsec() - 10ULL*1000000000ULL; /* base, -10s */
srand(time(nil));
if(Binit(&v, 0, OREAD) != 0 || ivfopen(&v, &ivf) != 0)
sysfatal("%r");
if(strcmp(ivf.type, "AVC1") != 0)
sysfatal("not H.264");
cs = ecalloc(argc, sizeof(*cs));
for(c = cs, i = 0; i < ncs; i++, c++){
c->url = "rtmp://REDACTED";//FIXME the key has to be redacted argv[i];
if((c->r = rtmpdial(argv[i])) == nil)
sysfatal("%r");
if(rtmpstream(c->r, &c->sid) != 0 ||
rtmppublish(c->r, c->sid, PubLive, nil) != 0 ||
rtmpmeta(c->r, c->sid, VcodecH264, ivf.w, ivf.h, a != nil ? AcodecAAC : -1) != 0){
sysfatal("%r");
}
}
if(a != nil)
proccreate(audio, a, mainstacksize);
memset(&vf, 0, sizeof(vf));
for(;;){
if(ivfread(&ivf, &vf) != 0)
sysfatal("%r");
if(vf.sz == 0)
break;
ms = ns2ms(ivf.ns₀, vf.ns);
vms = ms;
for(c = cs, i = 0; i < ncs; i++, c++){
if(rtmpdata(c->r, c->sid, ms, Tvideo, vf.buf, vf.sz) != 0){
fprint(2, "%s: %r\n", c->url);
goto out;
}
}
}
/* FIXME properly close RTMP connection */
out:
threadexitsall(nil);
}