History

fix video stream packing and url parsing (can stream to Twitch directly now)

Sigrid Solveig Haflínudóttir committed 5 years ago

Commit 94d64d61 parent 09b812b4 files · +132 −143Browse files

Unified · Split

4 files
  1. amf0.c +3 −0
  2. ivf.c +4 −9
  3. main.c +9 −19
  4. rtmp.c +116 −115
amf0.c+3−0
@@ -243,10 +243,13 @@ a₀free(A₀ *a) · 242 unmodified lines
243243 free(a->obj.k[i]);
244244 a₀free(a->obj.v[i]);
245245 }
246+ free(a->obj.k);
247+ free(a->obj.v);
246248 break;
247249 case Tarr:
248250 for(i = 0; i < a->arr.n; i++)
249251 a₀free(a->arr.v[i]);
252+ free(a->arr.v);
250253 case Tnull:
251254 case Tnum:
252255 case Tbool:
ivf.c+4−9
@@ -2,6 +2,7 @@ · 1 unmodified line
22 #include <libc.h>
33 #include <bio.h>
44 #include "ivf.h"
5+#include "util.h"
56
67 static int
78 Bu16le(Biobuf *b, u16int *o)
@@ -84,7 +85,6 @@ err: · 76 unmodified lines
8485 int
8586 ivfread(Biobuf *v, IVFrame *f)
8687 {
87− u8int *buf;
8888 u64int ts;
8989 u32int sz;
9090 int n;
@@ -94,19 +94,14 @@ ivfread(Biobuf *v, IVFrame *f) · 3 unmodified lines
9494 f->sz = 0;
9595 return 0;
9696 }
97− buf = f->buf;
9897 if(sz > f->bufsz){
99− if((buf = realloc(f->buf, sz)) == nil){
100− werrstr("frame is too big: %d bytes", sz);
101− goto err;
102− }
103− f->buf = buf;
98+ f->bufsz = sz*2;
99+ f->buf = erealloc(f->buf, sz*2);
104100 }
105− if((n = Bread(v, buf, sz)) != sz){
101+ if((n = Bread(v, f->buf, sz)) != sz){
106102 werrstr("short read (%d < %d)", n, sz);
107103 goto err;
108104 }
109− f->buf = buf;
110105 f->sz = sz;
111106 f->ts = ts;
112107
main.c+9−19
@@ -19,8 +19,9 @@ usage(void) · 18 unmodified lines
1919 void
2020 threadmain(int argc, char **argv)
2121 {
22− u64int ns, ons;
2322 Biobuf *a, *v;
23+ u64int ns;
24+ ulong sid;
2425 IVFrame f;
2526 IVF ivf;
2627 RTMP *r;
@@ -51,37 +52,26 @@ threadmain(int argc, char **argv) · 24 unmodified lines
5152 sysfatal("%r");
5253 if(strcmp(ivf.type, "AVC1") != 0)
5354 sysfatal("not H.264");
55+
5456 srand(time(nil));
5557 if((r = rtmpdial(argv[0])) == nil)
5658 sysfatal("%r");
57− ulong sid;
58− fprint(2, "asking for a stream\n");
5959
60− if(rtmpstream(r, &sid) == 0){
61− fprint(2, "stream: %lud\n", sid);
62− if(rtmppublish(r, sid, PubLive, "???") == 0){
63− fprint(2, "stream published\n");
64− if(rtmpmeta(r, sid, VcodecH264, 1920, 1088, -1) == 0)
65− fprint(2, "metadata sent\n");
66− else
67− fprint(2, "metadata failed: %r\n");
68− }else
69− fprint(2, "stream publish failed: %r\n");
70− }else{
71− fprint(2, "stream failed\n");
60+ if(rtmpstream(r, &sid) != 0 ||
61+ rtmppublish(r, sid, PubLive, nil) != 0 ||
62+ rtmpmeta(r, sid, VcodecH264, ivf.w, ivf.h, -1) != 0){
63+ sysfatal("%r");
7264 }
7365
74− ons = 0;
7566 memset(&f, 0, sizeof(f));
7667 for(;;){
7768 if(ivfread(v, &f) != 0)
7869 sysfatal("%r");
7970 if(f.sz == 0)
8071 break;
81− ns = ivfns(&ivf, f.ts);
82− if(rtmpdata(r, sid, (ns - ons) / 1000000ULL, Tvideo, f.buf, f.sz) != 0)
72+ ns = ivfns(&ivf, f.ts)/1000000ULL;
73+ if(rtmpdata(r, sid, ns, Tvideo, f.buf, f.sz) != 0)
8374 sysfatal("video: flvdata: %r");
84− ons = ns;
8575 }
8676
8777 threadexitsall(nil);
rtmp.c+116−115
@@ -108,9 +108,10 @@ struct RTMP { · 107 unmodified lines
108108 Buffer i;
109109 Buffer o;
110110 Channel *c;
111− char *app;
112− char *path;
113111 char *tcurl;
112+ char *app;
113+ char *inst;
114+ char *path; /* FIXME no idea what this is for */
114115 int chunkin;
115116 int chunkout;
116117 int mode;
@@ -122,13 +123,7 @@ struct RTMP { · 5 unmodified lines
122123 int tid;
123124 Command *w;
124125 }cmds;
125− struct {
126− int hsent;
127− int spssz;
128− int ppssz;
129− u8int sps[128];
130− u8int pps[128];
131− }v;
126+ int sps;
132127 u8int biobuf[Biobufsz];
133128 };
134129
@@ -238,7 +233,7 @@ bextend(Buffer *b, int bsz) · 103 unmodified lines
238233 if(b->bsz >= bsz)
239234 return;
240235 ob = b->b;
241− b->b = erealloc(b->b, bsz*2);
236+ b->b = erealloc(ob, bsz*2);
242237 if(ob != nil)
243238 b->p = b->b + (intptr)(ob - b->p);
244239 b->bsz = bsz*2;
@@ -411,11 +406,12 @@ err: · 166 unmodified lines
411406 static void
412407 rtmpfree(RTMP *r)
413408 {
414− free(r->app);
415409 free(r->i.b);
416410 free(r->o.b);
417− free(r->path);
418411 free(r->tcurl);
412+ free(r->app);
413+ free(r->inst);
414+ free(r->path);
419415 if(r->c != nil){
420416 sendp(r->c, "done");
421417 chanfree(r->c);
@@ -569,7 +565,7 @@ loop(void *aux) · 147 unmodified lines
569565 }
570566 break;
571567
572− case WindowAckSize:
568+ case WindowAckSize: /* FIXME send acks too */
573569 if(a₀i32get(s, e, &r->winacksz) == nil)
574570 goto err;
575571 if(debug)
@@ -715,8 +711,10 @@ rtmppublish(RTMP *r, ulong sid, int type, char *name) · 139 unmodified lines
715711 werrstr("invalid publish type %d", type);
716712 return -1;
717713 }
718− if(name == nil)
719− name = "";
714+ if(name == nil && (name = r->inst) == nil){
715+ werrstr("no name to publish to");
716+ return -1;
717+ }
720718
721719 c = chancreate(sizeof(char*), 0);
722720
@@ -763,8 +761,9 @@ rtmpmeta(RTMP *r, ulong sid, int vcodec, int w, int h, int acodec) · 40 unmodified lines
763761
764762 putstr("onMetaData");
765763 putarr();
766− puti32(1 + (vcodec < 0 ? 0 : 3) + (acodec < 0 ? 0 : 1));
767− putkvnum("duration", 0.0);
764+ puti32(2 + (vcodec < 0 ? 0 : 3) + (acodec < 0 ? 0 : 1));
765+ putkvnum("duration", 0);
766+ putkvnum("filesize", 0);
768767 if(vcodec >= 0){
769768 putkvnum("videocodecid", vcodec);
770769 putkvnum("width", w);
@@ -787,111 +786,116 @@ nalsz(u8int *p, int sz, int *csz) · 16 unmodified lines
787786 {
788787 int n;
789788
790− for(n = 3; sz-n > 3; n++){
791− if(p[n] == 0 && p[n+1] == 0 && p[n+2] == 1){
792− *csz = 3;
793− return n;
794− }
795− if(p[n] == 0 && p[n+1] == 0 && p[n+2] == 0 && p[n+3] == 1){
796− *csz = 4;
797− return n;
798− }
789+ *csz = 0;
790+ for(n = 0; n < sz-3;){
791+ if(p[n] == 0 && p[n+1] == 0){
792+ if(p[n+2] == 1){
793+ *csz += 3;
794+ n += 3;
795+ }else if(p[n+2] == 0 && p[n+3] == 1){
796+ *csz += 4;
797+ n += 4;
798+ }else
799+ break;
800+ }else
801+ break;
799802 }
800803
801− *csz = 0;
804+ for(; n < sz-3; n++){
805+ if(p[n] == 0 && p[n+1] == 0){
806+ if(p[n+2] == 1)
807+ return n;
808+ else if(p[n+2] == 0 && p[n+3] == 1)
809+ return n;
810+ }
811+ }
802812
803813 return sz;
804814 }
805815
806816 static int
807−mkps(RTMP *r, u8int *p)
817+h264data(RTMP *r, ulong sid, u32int dt, u8int *p, int sz)
808818 {
809− u8int *p₀;
819+ u8int *p₀, sps[128], pps[128], ps[16+sizeof(sps)+sizeof(pps)];
820+ int sz₀, csz, nsz, ntype, spssz, ppssz, key, total;
810821
822+ sz₀ = sz;
811823 p₀ = p;
824+ spssz = 0;
825+ ppssz = 0;
826+ key = 0;
827+ for(total = 0; sz > 0; total += 4+nsz, p += nsz, sz -= nsz){
828+ nsz = nalsz(p, sz, &csz);
829+ p += csz;
830+ sz -= csz;
831+ nsz -= csz;
812832
813− *p++ = 1; /* version */
814− *p++ = r->v.sps[1]; /* profile */
815− *p++ = r->v.sps[2]; /* compatibility */
816− *p++ = r->v.sps[3]; /* level */
817− *p++ = 0xfc | 3; /* reserved (6 bits), NULA length size - 1 (2 bits) */
818− *p++ = 0xe0 | 1; /* reserved (3 bits), num of SPS (5 bits) */
819− *p++ = r->v.spssz >> 8;
820− *p++ = r->v.spssz;
821− p = (u8int*)memmove(p, r->v.sps, r->v.spssz) + r->v.spssz;
822−
823− *p++ = 1;
824− *p++ = r->v.ppssz >> 8;
825− *p++ = r->v.ppssz;
826− p = (u8int*)memmove(p, r->v.pps, r->v.ppssz) + r->v.ppssz;
827−
828− return p - p₀;
829−}
830−
831−static int
832−data(RTMP *r, ulong sid, u32int dt, int type, int fl, void *data, int sz)
833−{
834− bextend(&r->o, 64 + sz);
833+ ntype = *p & 0x1f;
834+ if(ntype == 7){
835+ memmove(sps, p, nsz);
836+ spssz = nsz;
837+ }
838+ if(ntype == 8){
839+ memmove(pps, p, nsz);
840+ ppssz = nsz;
841+ }
842+ if(ntype == 5)
843+ key = 1;
844+ }
835845
836− newmsg(r, type == Taudio ? Audio : Video, Type0, CSData);
837− r->o.msg.ts = dt;
838− r->o.msg.sid = sid;
846+ if(spssz > 0 && ppssz > 0 && !r->sps){
847+ newmsg(r, Video, Type0, CSData);
848+ r->o.msg.ts = dt;
849+ r->o.msg.sid = sid;
839850
840− if(type == Taudio){
841− putbyte(AcodecAAC<<4 | 0x0f);
842− putbyte((fl & FlHdr) ? 0 : 1);
843− }
844− if(type == Tvideo){
845− putbyte(((fl & FlKey) ? 0x10 : 0x20) | VcodecH264);
846− putbyte((fl & FlHdr) ? 0 : 1);
851+ putbyte(0x10 | VcodecH264);
852+ putbyte(0);
847853 puti24(0);
848− if((fl & FlHdr) == 0)
849− puti32(sz);
854+
855+ p = ps;
856+ *p++ = 1; /* version */
857+ *p++ = sps[1]; /* profile */
858+ *p++ = sps[2]; /* compatibility */
859+ *p++ = sps[3]; /* level */
860+ *p++ = 0xfc | 3; /* reserved (6 bits), NULA length size - 1 (2 bits) */
861+ *p++ = 0xe0 | 1; /* reserved (3 bits), num of SPS (5 bits) */
862+ *p++ = spssz >> 8;
863+ *p++ = spssz;
864+ p = (u8int*)memmove(p, sps, spssz) + spssz;
865+ *p++ = 1;
866+ *p++ = ppssz >> 8;
867+ *p++ = ppssz;
868+ p = (u8int*)memmove(p, pps, ppssz) + ppssz;
869+
870+ putdata(ps, p-ps);
871+
872+ if(rtmpsend(r) < 0)
873+ return -1;
874+
875+ r->sps = 1;
850876 }
851− putdata(data, sz);
852877
853− return rtmpsend(r);
854−}
878+ bextend(&r->o, 64+total);
855879
856−static int
857−h264data(RTMP *r, ulong sid, u32int dt, u8int *p, int sz)
858−{
859− int csz, nsz, ntype;
860− u8int ps[32+256];
880+ newmsg(r, Video, Type0, CSData);
881+ r->o.msg.ts = dt;
882+ r->o.msg.sid = sid;
861883
862− for(; sz > 0; p += nsz, sz -= nsz){
884+ putbyte((key ? 0x10 : 0x20) | VcodecH264);
885+ putbyte(1);
886+ puti24(0);
887+
888+ for(p = p₀, sz = sz₀; sz > 0; p += nsz, sz -= nsz){
863889 nsz = nalsz(p, sz, &csz);
864890 p += csz;
865891 sz -= csz;
866892 nsz -= csz;
867893
868− ntype = *p & 0x1f;
869− if(ntype == 7){
870− memmove(r->v.sps, p, nsz);
871− r->v.spssz = nsz;
872− continue;
873− }
874− if(ntype == 8){
875− memmove(r->v.pps, p, nsz);
876− r->v.ppssz = nsz;
877− continue;
878− }
879−
880− if(r->v.spssz < 1 || r->v.ppssz < 1)
881− continue;
882−
883− if(!r->v.hsent || ntype == 8){
884− r->v.hsent = 1;
885− if(data(r, sid, 0, Tvideo, FlKey|FlHdr, ps, mkps(r, ps)) < 0)
886− return -1;
887− }
888− if(ntype != 7 && ntype != 8){
889− if(data(r, sid, 100, Tvideo, ntype == 5 ? FlKey : 0, p-csz, nsz+csz) < 0)
890− return -1;
891− }
894+ puti32(nsz);
895+ putdata(p, nsz);
892896 }
893897
894− return 0;
898+ return rtmpsend(r);
895899 }
896900
897901 int
@@ -974,7 +978,7 @@ msgfmt(Fmt *f) · 76 unmodified lines
974978 RTMP *
975979 rtmpdial(char *url)
976980 {
977− char *s, *e, *path, *app;
981+ char *s, *e, *p, *app, *inst, *path;
978982 int f, port, ctl;
979983 RTMP *r;
980984
@@ -997,14 +1001,14 @@ rtmpdial(char *url) · 16 unmodified lines
9971001 }
9981002 port = 1935;
9991003 if(*e == ':'){
1000− if((port = strtol(e+1, &path, 10)) < 1 || path == e+1 || *path != '/'){
1004+ if((port = strtol(e+1, &p, 10)) < 1 || p == e+1 || *p != '/'){
10011005 werrstr("invalid port");
10021006 goto err;
10031007 }
10041008 }else{
1005− path = e;
1009+ p = e;
10061010 }
1007− while(*(++path) == '/');
1011+ while(*(++p) == '/');
10081012
10091013 s = smprint("tcp!%.*s!%d", (int)(e-s), s, port);
10101014 f = dial(s, nil, nil, &ctl);
@@ -1012,21 +1016,17 @@ rtmpdial(char *url) · 1 unmodified line
10121016 if(f < 0)
10131017 goto err;
10141018
1015− app = path;
1016− if((s = strchr(path, '/')) == nil){
1017− werrstr("no path");
1018− goto err;
1019− }
1020− if((e = strchr(s+1, '/')) != nil){
1021− /* at this point it can be app instance if there is another slash following */
1022− if((s = strchr(e+1, '/')) == nil){
1023− /* no, just path leftovers */
1024− s = e;
1025− }
1019+ /* rtmp://host:port/app[/inst[/path]] */
1020+ app = p;
1021+ inst = nil;
1022+ path = nil;
1023+ if((s = strchr(p, '/')) != nil){ /* app instance */
10261024 *s = 0;
1027− path = s+1;
1028− }else{
1029− path = nil;
1025+ inst = s+1;
1026+ if((s = strchr(s+1, '/')) != nil){ /* path */
1027+ *s = 0;
1028+ path = s+1;
1029+ }
10301030 }
10311031
10321032 if(handshake(f) != 0)
@@ -1040,6 +1040,7 @@ rtmpdial(char *url) · 7 unmodified lines
10401040 url = nil;
10411041 r->c = chancreate(sizeof(void*), 0);
10421042 r->app = estrdup(app);
1043+ r->inst = inst == nil ? nil : estrdup(inst);
10431044 r->path = path == nil ? nil : estrdup(path);
10441045 bextend(&r->i, Bufsz);
10451046 bextend(&r->o, Bufsz);

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t