History

send video data

Sigrid Solveig Haflínudóttir committed 5 years ago

Commit 09b812b1 parent 36986cc5 files · +157 −30Browse files

Unified · Split

5 files
  1. amf0.c +11 −0
  2. amf0.h +1 −0
  3. main.c +3 −3
  4. rtmp.c +141 −23
  5. rtmp.h +1 −4
amf0.c+11−0
@@ -76,6 +76,17 @@ a₀i32(u8int *p, u8int *e, s32int i) · 75 unmodified lines
7676 return p;
7777 }
7878
79+u8int *
80+a₀i32le(u8int *p, u8int *e, s32int i)
81+{
82+ atleast("i32le", 4);
83+ *p++ = i;
84+ *p++ = i >> 8;
85+ *p++ = i >> 16;
86+ *p++ = i >> 24;
87+ return p;
88+}
89+
7990 u8int *
8091 a₀num(u8int *p, u8int *e, double v)
8192 {
amf0.h+1−0
@@ -33,6 +33,7 @@ u8int *a₀bool(u8int *p, u8int *e, int v); · 32 unmodified lines
3333 u8int *a₀byte(u8int *p, u8int *e, u8int byte);
3434 u8int *a₀i24(u8int *p, u8int *e, s32int i);
3535 u8int *a₀i32(u8int *p, u8int *e, s32int i);
36+u8int *a₀i32le(u8int *p, u8int *e, s32int i);
3637 u8int *a₀num(u8int *p, u8int *e, double v);
3738 u8int *a₀str(u8int *p, u8int *e, char *s);
3839 u8int *a₀arr(u8int *p, u8int *e);
main.c+3−3
@@ -59,9 +59,9 @@ threadmain(int argc, char **argv) · 58 unmodified lines
5959
6060 if(rtmpstream(r, &sid) == 0){
6161 fprint(2, "stream: %lud\n", sid);
62− if(rtmppublish(r, sid, PubLive, "live") == 0){
62+ if(rtmppublish(r, sid, PubLive, "???") == 0){
6363 fprint(2, "stream published\n");
64− if(rtmpmeta(r, sid, VcodecH264, 1920, 1080, -1) == 0)
64+ if(rtmpmeta(r, sid, VcodecH264, 1920, 1088, -1) == 0)
6565 fprint(2, "metadata sent\n");
6666 else
6767 fprint(2, "metadata failed: %r\n");
@@ -79,7 +79,7 @@ threadmain(int argc, char **argv) · 11 unmodified lines
7979 if(f.sz == 0)
8080 break;
8181 ns = ivfns(&ivf, f.ts);
82− if(rtmpdata(r, sid, (ns - ons) / 1000000ULL, Tvideo, FlHdr, f.buf, f.sz) != 0)
82+ if(rtmpdata(r, sid, (ns - ons) / 1000000ULL, Tvideo, f.buf, f.sz) != 0)
8383 sysfatal("video: flvdata: %r");
8484 ons = ns;
8585 }
rtmp.c+141−23
@@ -14,7 +14,10 @@ enum { · 13 unmodified lines
1414 Port = 1935,
1515 CSsz = 1536,
1616 ChunkDefault = 128,
17− ChunkDesired = 4096,
17+ ChunkDesired = 65536,
18+
19+ FlKey = 1<<0,
20+ FlHdr = 1<<1,
1821
1922 Type0 = 0,
2023 Type1,
@@ -23,6 +26,7 @@ enum { · 2 unmodified lines
2326
2427 CSUserCtl = 2,
2528 CSCtl = 3,
29+ CSData = 4,
2630
2731 CbCommand = 0,
2832 CbTransID,
@@ -76,6 +80,7 @@ struct Command { · 47 unmodified lines
7680 void (*cb)(RTMP *r, int ok, A₀ *a[NumCb], void *aux);
7781 void *aux;
7882 int tid;
83+ int cs;
7984
8085 Command *prev, *next;
8186 };
@@ -117,6 +122,13 @@ struct RTMP { · 35 unmodified lines
117122 int tid;
118123 Command *w;
119124 }cmds;
125+ struct {
126+ int hsent;
127+ int spssz;
128+ int ppssz;
129+ u8int sps[128];
130+ u8int pps[128];
131+ }v;
120132 u8int biobuf[Biobufsz];
121133 };
122134
@@ -142,6 +154,11 @@ struct RTMP { · 19 unmodified lines
142154 r->o.msg.cmd.cb = cb_; \
143155 }while(0)
144156
157+#define putcall(name) do { \
158+ putstr(name); \
159+ putnum(r->o.msg.cmd.tid); \
160+}while(0)
161+
145162 static int szs[] = {
146163 [Type3] = 0,
147164 [Type2] = 3,
@@ -204,6 +221,7 @@ newmsg(RTMP *r, int type, int fmt, int cs) · 56 unmodified lines
204221 r->o.msg.cmd.tid = ++r->cmds.tid;
205222 else
206223 r->o.msg.cmd.tid = 0;
224+ r->o.msg.cmd.cs = cs;
207225 }
208226
209227 static void
@@ -328,12 +346,12 @@ rtmpsend(RTMP *r) · 118 unmodified lines
328346 hsz = szs[m->fmt];
329347 e = h + hsz;
330348 if(hsz >= szs[Type2]){
331− h = a₀i24(h, e, 0); /* FIXME put actual timestamps? */
349+ h = a₀i24(h, e, m->ts);
332350 if(hsz >= szs[Type1]){
333351 h = a₀i24(h, e, m->sz);
334352 h = a₀byte(h, e, m->type);
335353 if(hsz >= szs[Type0])
336− h = a₀i32(h, e, m->sid);
354+ h = a₀i32le(h, e, m->sid);
337355 }
338356 }
339357 assert(h != nil);
@@ -487,7 +505,14 @@ loop(void *aux) · 147 unmodified lines
487505 werrstr("transaction ID is not a number");
488506 goto err;
489507 }
490− for(c = r->cmds.w; c != nil && c->tid != a[n]->num; c = c->next);
508+ for(c = r->cmds.w; c != nil; c = c->next){
509+ /* transaction id match */
510+ if(c->tid == a[n]->num)
511+ break;
512+ /* no transaction id, but the chunk stream matches */
513+ if(a[n]->num == 0 && c->cs == m->cs)
514+ break;
515+ }
491516 if(c == nil)
492517 fprint(2, "response to non-existent transaction %d", (int)a[n]->num);
493518 break;
@@ -648,8 +673,7 @@ rtmpstream(RTMP *r, ulong *sid) · 154 unmodified lines
648673 qlock(r);
649674
650675 newmsg(r, AMF0Command, Type0, CSCtl);
651− putstr("createStream");
652− putnum(r->o.msg.cmd.tid);
676+ putcall("createStream");
653677 putnull();
654678
655679 r->o.msg.cmd.cb = streamcreated;
@@ -698,10 +722,8 @@ rtmppublish(RTMP *r, ulong sid, int type, char *name) · 42 unmodified lines
698722
699723 qlock(r);
700724
701− newmsg(r, AMF0Command, Type0, CSCtl);
702− notransaction(r);
703− putstr("publish");
704− putnum(0);
725+ newmsg(r, AMF0Command, Type0, CSData);
726+ putcall("publish");
705727 putnull();
706728 putstr(name);
707729 putstr(pubtype2s[type]);
@@ -735,12 +757,13 @@ rtmpmeta(RTMP *r, ulong sid, int vcodec, int w, int h, int acodec) · 27 unmodified lines
735757
736758 qlock(r);
737759
738− newmsg(r, AMF0Metadata, Type0, CSCtl);
739− r->o.msg.sid = sid;
760+ newmsg(r, AMF0Metadata, Type0, CSData);
761+
762+ putstr("@setDataFrame");
740763
741764 putstr("onMetaData");
742− putnum(0);
743− putobj();
765+ putarr();
766+ puti32(1 + (vcodec < 0 ? 0 : 3) + (acodec < 0 ? 0 : 1));
744767 putkvnum("duration", 0.0);
745768 if(vcodec >= 0){
746769 putkvnum("videocodecid", vcodec);
@@ -750,6 +773,7 @@ rtmpmeta(RTMP *r, ulong sid, int vcodec, int w, int h, int acodec) · 3 unmodified lines
750773 if(acodec >= 0)
751774 putkvnum("audiocodecid", acodec);
752775 putend();
776+ r->o.msg.sid = sid;
753777
754778 res = rtmpsend(r);
755779
@@ -758,18 +782,59 @@ rtmpmeta(RTMP *r, ulong sid, int vcodec, int w, int h, int acodec) · 2 unmodified lines
758782 return res;
759783 }
760784
761−int
762−rtmpdata(RTMP *r, ulong sid, u32int dt, int type, int fl, void *data, int sz)
785+static int
786+nalsz(u8int *p, int sz, int *csz)
763787 {
764− int res;
788+ int n;
765789
766− assert(type == Taudio || type == Tvideo);
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+ }
799+ }
767800
768− qlock(r);
801+ *csz = 0;
802+
803+ return sz;
804+}
805+
806+static int
807+mkps(RTMP *r, u8int *p)
808+{
809+ u8int *p₀;
810+
811+ p₀ = p;
812+
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+}
769830
831+static int
832+data(RTMP *r, ulong sid, u32int dt, int type, int fl, void *data, int sz)
833+{
770834 bextend(&r->o, 64 + sz);
771835
772− newmsg(r, type == Taudio ? Audio : Video, Type0, CSCtl);
836+ newmsg(r, type == Taudio ? Audio : Video, Type0, CSData);
837+ r->o.msg.ts = dt;
773838 r->o.msg.sid = sid;
774839
775840 if(type == Taudio){
@@ -779,14 +844,67 @@ rtmpdata(RTMP *r, ulong sid, u32int dt, int type, int fl, void *data, int sz) · 3 unmodified lines
779844 if(type == Tvideo){
780845 putbyte(((fl & FlKey) ? 0x10 : 0x20) | VcodecH264);
781846 putbyte((fl & FlHdr) ? 0 : 1);
782− puti24(dt);
847+ puti24(0);
783848 if((fl & FlHdr) == 0)
784849 puti32(sz);
785850 }
786851 putdata(data, sz);
787852
788− res = rtmpsend(r);
853+ return rtmpsend(r);
854+}
855+
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];
861+
862+ for(; sz > 0; p += nsz, sz -= nsz){
863+ nsz = nalsz(p, sz, &csz);
864+ p += csz;
865+ sz -= csz;
866+ nsz -= csz;
867+
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;
789882
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+ }
892+ }
893+
894+ return 0;
895+}
896+
897+int
898+rtmpdata(RTMP *r, ulong sid, u32int dt, int type, void *p, int sz)
899+{
900+ int res;
901+
902+ assert(type == Taudio || type == Tvideo);
903+
904+ qlock(r);
905+ res = 0;
906+ if(type == Tvideo)
907+ res = h264data(r, sid, dt, p, sz);
790908 qunlock(r);
791909
792910 return res;
@@ -817,6 +935,7 @@ connect(RTMP *r) · 24 unmodified lines
817935 putcommand("connect", connected);
818936 putkvstr("app", r->app);
819937 putkvstr("tcUrl", r->tcurl);
938+ putkvstr("type", "nonprivate");
820939 putkvbool("fpad", 0); /* no proxy */
821940 putkvnum("audioCodecs", 0x4 | 0x400); /* mp3 + aac */
822941 putkvnum("videoCodecs", 0x80); /* h.264 */
@@ -907,7 +1026,6 @@ rtmpdial(char *url) · 84 unmodified lines
9071026 *s = 0;
9081027 path = s+1;
9091028 }else{
910− *s = 0;
9111029 path = nil;
9121030 }
9131031
rtmp.h+1−4
@@ -20,11 +20,8 @@ int rtmpmeta(RTMP *r, ulong sid, int vcodec, int w, int h, int acodec); · 19 unmodified lines
2020 enum {
2121 Taudio,
2222 Tvideo,
23−
24− FlKey = 1<<0,
25− FlHdr = 1<<1,
2623 };
27−int rtmpdata(RTMP *r, ulong sid, u32int ts, int type, int fl, void *data, int sz);
24+int rtmpdata(RTMP *r, ulong sid, u32int dt, int type, void *data, int sz);
2825
2926 RTMP *rtmpdial(char *url);
3027 void rtmpclose(RTMP *r);

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