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
76 return p;76 return p;
77}77}
78 78
79u8int *
80a₀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
79u8int *90u8int *
80a₀num(u8int *p, u8int *e, double v)91a₀num(u8int *p, u8int *e, double v)
81{92{
amf0.h+1−0
@@ -33,6 +33,7 @@ u8int *a₀bool(u8int *p, u8int *e, int v); · 32 unmodified lines
33u8int *a₀byte(u8int *p, u8int *e, u8int byte);33u8int *a₀byte(u8int *p, u8int *e, u8int byte);
34u8int *a₀i24(u8int *p, u8int *e, s32int i);34u8int *a₀i24(u8int *p, u8int *e, s32int i);
35u8int *a₀i32(u8int *p, u8int *e, s32int i);35u8int *a₀i32(u8int *p, u8int *e, s32int i);
36u8int *a₀i32le(u8int *p, u8int *e, s32int i);
36u8int *a₀num(u8int *p, u8int *e, double v);37u8int *a₀num(u8int *p, u8int *e, double v);
37u8int *a₀str(u8int *p, u8int *e, char *s);38u8int *a₀str(u8int *p, u8int *e, char *s);
38u8int *a₀arr(u8int *p, u8int *e);39u8int *a₀arr(u8int *p, u8int *e);
main.c+3−3
@@ -59,9 +59,9 @@ threadmain(int argc, char **argv) · 58 unmodified lines
59 59
60 if(rtmpstream(r, &sid) == 0){60 if(rtmpstream(r, &sid) == 0){
61 fprint(2, "stream: %lud\n", sid);61 fprint(2, "stream: %lud\n", sid);
62 if(rtmppublish(r, sid, PubLive, "live") == 0){62 if(rtmppublish(r, sid, PubLive, "???") == 0){
63 fprint(2, "stream published\n");63 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)
65 fprint(2, "metadata sent\n");65 fprint(2, "metadata sent\n");
66 else66 else
67 fprint(2, "metadata failed: %r\n");67 fprint(2, "metadata failed: %r\n");
@@ -79,7 +79,7 @@ threadmain(int argc, char **argv) · 11 unmodified lines
79 if(f.sz == 0)79 if(f.sz == 0)
80 break;80 break;
81 ns = ivfns(&ivf, f.ts);81 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)
83 sysfatal("video: flvdata: %r");83 sysfatal("video: flvdata: %r");
84 ons = ns;84 ons = ns;
85 }85 }
rtmp.c+141−23
@@ -14,7 +14,10 @@ enum { · 13 unmodified lines
14 Port = 1935,14 Port = 1935,
15 CSsz = 1536,15 CSsz = 1536,
16 ChunkDefault = 128,16 ChunkDefault = 128,
17 ChunkDesired = 4096,17 ChunkDesired = 65536,
18
19 FlKey = 1<<0,
20 FlHdr = 1<<1,
18 21
19 Type0 = 0,22 Type0 = 0,
20 Type1,23 Type1,
@@ -23,6 +26,7 @@ enum { · 2 unmodified lines
23 26
24 CSUserCtl = 2,27 CSUserCtl = 2,
25 CSCtl = 3,28 CSCtl = 3,
29 CSData = 4,
26 30
27 CbCommand = 0,31 CbCommand = 0,
28 CbTransID,32 CbTransID,
@@ -76,6 +80,7 @@ struct Command { · 47 unmodified lines
76 void (*cb)(RTMP *r, int ok, A₀ *a[NumCb], void *aux);80 void (*cb)(RTMP *r, int ok, A₀ *a[NumCb], void *aux);
77 void *aux;81 void *aux;
78 int tid;82 int tid;
83 int cs;
79 84
80 Command *prev, *next;85 Command *prev, *next;
81};86};
@@ -117,6 +122,13 @@ struct RTMP { · 35 unmodified lines
117 int tid;122 int tid;
118 Command *w;123 Command *w;
119 }cmds;124 }cmds;
125 struct {
126 int hsent;
127 int spssz;
128 int ppssz;
129 u8int sps[128];
130 u8int pps[128];
131 }v;
120 u8int biobuf[Biobufsz];132 u8int biobuf[Biobufsz];
121};133};
122 134
@@ -142,6 +154,11 @@ struct RTMP { · 19 unmodified lines
142 r->o.msg.cmd.cb = cb_; \154 r->o.msg.cmd.cb = cb_; \
143}while(0)155}while(0)
144 156
157#define putcall(name) do { \
158 putstr(name); \
159 putnum(r->o.msg.cmd.tid); \
160}while(0)
161
145static int szs[] = {162static int szs[] = {
146 [Type3] = 0,163 [Type3] = 0,
147 [Type2] = 3,164 [Type2] = 3,
@@ -204,6 +221,7 @@ newmsg(RTMP *r, int type, int fmt, int cs) · 56 unmodified lines
204 r->o.msg.cmd.tid = ++r->cmds.tid;221 r->o.msg.cmd.tid = ++r->cmds.tid;
205 else222 else
206 r->o.msg.cmd.tid = 0;223 r->o.msg.cmd.tid = 0;
224 r->o.msg.cmd.cs = cs;
207}225}
208 226
209static void227static void
@@ -328,12 +346,12 @@ rtmpsend(RTMP *r) · 118 unmodified lines
328 hsz = szs[m->fmt];346 hsz = szs[m->fmt];
329 e = h + hsz;347 e = h + hsz;
330 if(hsz >= szs[Type2]){348 if(hsz >= szs[Type2]){
331 h = a₀i24(h, e, 0); /* FIXME put actual timestamps? */349 h = a₀i24(h, e, m->ts);
332 if(hsz >= szs[Type1]){350 if(hsz >= szs[Type1]){
333 h = a₀i24(h, e, m->sz);351 h = a₀i24(h, e, m->sz);
334 h = a₀byte(h, e, m->type);352 h = a₀byte(h, e, m->type);
335 if(hsz >= szs[Type0])353 if(hsz >= szs[Type0])
336 h = a₀i32(h, e, m->sid);354 h = a₀i32le(h, e, m->sid);
337 }355 }
338 }356 }
339 assert(h != nil);357 assert(h != nil);
@@ -487,7 +505,14 @@ loop(void *aux) · 147 unmodified lines
487 werrstr("transaction ID is not a number");505 werrstr("transaction ID is not a number");
488 goto err;506 goto err;
489 }507 }
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 }
491 if(c == nil)516 if(c == nil)
492 fprint(2, "response to non-existent transaction %d", (int)a[n]->num);517 fprint(2, "response to non-existent transaction %d", (int)a[n]->num);
493 break;518 break;
@@ -648,8 +673,7 @@ rtmpstream(RTMP *r, ulong *sid) · 154 unmodified lines
648 qlock(r);673 qlock(r);
649 674
650 newmsg(r, AMF0Command, Type0, CSCtl);675 newmsg(r, AMF0Command, Type0, CSCtl);
651 putstr("createStream");676 putcall("createStream");
652 putnum(r->o.msg.cmd.tid);
653 putnull();677 putnull();
654 678
655 r->o.msg.cmd.cb = streamcreated;679 r->o.msg.cmd.cb = streamcreated;
@@ -698,10 +722,8 @@ rtmppublish(RTMP *r, ulong sid, int type, char *name) · 42 unmodified lines
698 722
699 qlock(r);723 qlock(r);
700 724
701 newmsg(r, AMF0Command, Type0, CSCtl);725 newmsg(r, AMF0Command, Type0, CSData);
702 notransaction(r);726 putcall("publish");
703 putstr("publish");
704 putnum(0);
705 putnull();727 putnull();
706 putstr(name);728 putstr(name);
707 putstr(pubtype2s[type]);729 putstr(pubtype2s[type]);
@@ -735,12 +757,13 @@ rtmpmeta(RTMP *r, ulong sid, int vcodec, int w, int h, int acodec) · 27 unmodified lines
735 757
736 qlock(r);758 qlock(r);
737 759
738 newmsg(r, AMF0Metadata, Type0, CSCtl);760 newmsg(r, AMF0Metadata, Type0, CSData);
739 r->o.msg.sid = sid;761
762 putstr("@setDataFrame");
740 763
741 putstr("onMetaData");764 putstr("onMetaData");
742 putnum(0);765 putarr();
743 putobj();766 puti32(1 + (vcodec < 0 ? 0 : 3) + (acodec < 0 ? 0 : 1));
744 putkvnum("duration", 0.0);767 putkvnum("duration", 0.0);
745 if(vcodec >= 0){768 if(vcodec >= 0){
746 putkvnum("videocodecid", vcodec);769 putkvnum("videocodecid", vcodec);
@@ -750,6 +773,7 @@ rtmpmeta(RTMP *r, ulong sid, int vcodec, int w, int h, int acodec) · 3 unmodified lines
750 if(acodec >= 0)773 if(acodec >= 0)
751 putkvnum("audiocodecid", acodec);774 putkvnum("audiocodecid", acodec);
752 putend();775 putend();
776 r->o.msg.sid = sid;
753 777
754 res = rtmpsend(r);778 res = rtmpsend(r);
755 779
@@ -758,18 +782,59 @@ rtmpmeta(RTMP *r, ulong sid, int vcodec, int w, int h, int acodec) · 2 unmodified lines
758 return res;782 return res;
759}783}
760 784
761int785static int
762rtmpdata(RTMP *r, ulong sid, u32int dt, int type, int fl, void *data, int sz)786nalsz(u8int *p, int sz, int *csz)
763{787{
764 int res;788 int n;
765 789
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 }
767 800
768 qlock(r);801 *csz = 0;
802
803 return sz;
804}
805
806static int
807mkps(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}
769 830
831static int
832data(RTMP *r, ulong sid, u32int dt, int type, int fl, void *data, int sz)
833{
770 bextend(&r->o, 64 + sz);834 bextend(&r->o, 64 + sz);
771 835
772 newmsg(r, type == Taudio ? Audio : Video, Type0, CSCtl);836 newmsg(r, type == Taudio ? Audio : Video, Type0, CSData);
837 r->o.msg.ts = dt;
773 r->o.msg.sid = sid;838 r->o.msg.sid = sid;
774 839
775 if(type == Taudio){840 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
779 if(type == Tvideo){844 if(type == Tvideo){
780 putbyte(((fl & FlKey) ? 0x10 : 0x20) | VcodecH264);845 putbyte(((fl & FlKey) ? 0x10 : 0x20) | VcodecH264);
781 putbyte((fl & FlHdr) ? 0 : 1);846 putbyte((fl & FlHdr) ? 0 : 1);
782 puti24(dt);847 puti24(0);
783 if((fl & FlHdr) == 0)848 if((fl & FlHdr) == 0)
784 puti32(sz);849 puti32(sz);
785 }850 }
786 putdata(data, sz);851 putdata(data, sz);
787 852
788 res = rtmpsend(r);853 return rtmpsend(r);
854}
855
856static int
857h264data(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;
789 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 }
892 }
893
894 return 0;
895}
896
897int
898rtmpdata(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);
790 qunlock(r);908 qunlock(r);
791 909
792 return res;910 return res;
@@ -817,6 +935,7 @@ connect(RTMP *r) · 24 unmodified lines
817 putcommand("connect", connected);935 putcommand("connect", connected);
818 putkvstr("app", r->app);936 putkvstr("app", r->app);
819 putkvstr("tcUrl", r->tcurl);937 putkvstr("tcUrl", r->tcurl);
938 putkvstr("type", "nonprivate");
820 putkvbool("fpad", 0); /* no proxy */939 putkvbool("fpad", 0); /* no proxy */
821 putkvnum("audioCodecs", 0x4 | 0x400); /* mp3 + aac */940 putkvnum("audioCodecs", 0x4 | 0x400); /* mp3 + aac */
822 putkvnum("videoCodecs", 0x80); /* h.264 */941 putkvnum("videoCodecs", 0x80); /* h.264 */
@@ -907,7 +1026,6 @@ rtmpdial(char *url) · 84 unmodified lines
907 *s = 0;1026 *s = 0;
908 path = s+1;1027 path = s+1;
909 }else{1028 }else{
910 *s = 0;
911 path = nil;1029 path = nil;
912 }1030 }
913 1031
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
20enum {20enum {
21 Taudio,21 Taudio,
22 Tvideo,22 Tvideo,
23
24 FlKey = 1<<0,
25 FlHdr = 1<<1,
26};23};
27int rtmpdata(RTMP *r, ulong sid, u32int ts, int type, int fl, void *data, int sz);24int rtmpdata(RTMP *r, ulong sid, u32int dt, int type, void *data, int sz);
28 25
29RTMP *rtmpdial(char *url);26RTMP *rtmpdial(char *url);
30void rtmpclose(RTMP *r);27void 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