ref: b5c87f9d2711099c002406442c4839acd11f01a6
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 void usage(void) { fprint(2, "usage: %s [-a AUDIO] URL\n", argv0); threadexitsall("usage"); } void threadmain(int argc, char **argv) { u64int ms, until; Biobuf *a, v; ADTSFrame af; IVFrame vf; ulong sid; IVF ivf; RTMP *r; 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"); 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"); } memset(&af, 0, sizeof(af)); memset(&vf, 0, sizeof(vf)); for(;;){ if(ivfread(&v, &vf) != 0) sysfatal("%r"); if(vf.sz == 0) break; ms = ivfns(&ivf, vf.ts)/1000000ULL; if(rtmpdata(r, sid, ms, Tvideo, vf.buf, vf.sz) != 0){ fprint(2, "%r\n"); break; } /* FIXME obviously this has to run in a separate frame (same for video, actually) */ if(a == nil) continue; until = ms + 250; /* provide audio enough to cover + 250 ms over video */ do{ if(adtsread(a, &af) != 0) sysfatal("%r"); if(af.sz == 0) break; ms = af.ns/1000000ULL; if(rtmpdata(r, sid, ms, Taudio, af.buf, af.sz) != 0){ fprint(2, "%r\n"); break; } }while(ms < until); } if(a != nil) Bterm(a); rtmpclose(r); threadexitsall(nil); }