ref: adf3227845db11bde5f89abc0ca54864c4f8747d
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" int mainstacksize = 65536; int debug = 0; static RTMP *r; static ulong sid; static uvlong ns₀; static uvlong vms; static void usage(void) { fprint(2, "usage: %s [-a AUDIO] URL\n", argv0); threadexitsall("usage"); } static void audio(void *aux) { ADTSFrame af; Biobuf *a; u64int ms; a = aux; memset(&af, 0, sizeof(af)); af.ns₀ = Zns₀; for(;;){ if(adtsread(a, &af) != 0) goto err; if(af.sz == 0) /* eof */ break; ms = ((af.ns₀ != Zns₀ ? af.ns₀-ns₀ : 0) + af.ns)/1000000ULL; if(rtmpdata(r, sid, ms, Taudio, af.buf, af.sz) != 0){ err: fprint(2, "%r\n"); break; } /* protect against overruns */ if(vms+200 < ms) sleep(100); } /* FIXME properly close RTMP connection */ threadexitsall(nil); } void threadmain(int argc, char **argv) { Biobuf *a, v; IVFrame vf; u64int ms; IVF ivf; a = nil; ARGBEGIN{ case 'd': debug++; break; case 'a': if((a = Bopen(EARGF(usage()), OREAD)) == nil) sysfatal("%r"); break; default: usage(); }ARGEND if(argc != 1) usage(); if(Binit(&v, 0, OREAD) != 0 || ivfopen(&v, &ivf) != 0) sysfatal("%r"); if(strcmp(ivf.type, "AVC1") != 0) sysfatal("not H.264"); ns₀ = nsec() - 10ULL*1000000000ULL; /* base, -10s */ srand(time(nil)); if((r = rtmpdial(argv[0])) == nil) sysfatal("%r"); if(rtmpstream(r, &sid) != 0 || rtmppublish(r, sid, PubLive, nil) != 0 || rtmpmeta(r, 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 = ((ivf.ns₀ != Zns₀ ? ivf.ns₀-ns₀ : 0) + vf.ns)/1000000ULL; if(rtmpdata(r, sid, ms, Tvideo, vf.buf, vf.sz) != 0){ fprint(2, "%r\n"); break; } vms = ms; } /* FIXME properly close RTMP connection */ threadexitsall(nil); }