winlin

merge from 2.0

@@ -326,7 +326,7 @@ Remark: @@ -326,7 +326,7 @@ Remark:
326 * 2014-04-28, [Release v1.0-mainline2](https://github.com/simple-rtmp-server/srs/releases/tag/1.0.mainline2), support [dvr](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_DVR), android, [edge](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_Edge). 35255 lines.<br/> 326 * 2014-04-28, [Release v1.0-mainline2](https://github.com/simple-rtmp-server/srs/releases/tag/1.0.mainline2), support [dvr](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_DVR), android, [edge](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_Edge). 35255 lines.<br/>
327 * 2014-04-07, [Release v1.0-mainline](https://github.com/simple-rtmp-server/srs/releases/tag/1.0.mainline), support [arm](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_SrsLinuxArm), [init.d](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_LinuxService), http [server](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_HTTPServer)/[api](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_HTTPApi), [ingest](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_SampleIngest). 30000 lines.<br/> 327 * 2014-04-07, [Release v1.0-mainline](https://github.com/simple-rtmp-server/srs/releases/tag/1.0.mainline), support [arm](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_SrsLinuxArm), [init.d](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_LinuxService), http [server](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_HTTPServer)/[api](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_HTTPApi), [ingest](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_SampleIngest). 30000 lines.<br/>
328 * 2013-12-25, [Release v0.9](https://github.com/simple-rtmp-server/srs/releases/tag/0.9), support bandwidth test, player/encoder/chat [demos](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_SampleDemo). 20926 lines.<br/> 328 * 2013-12-25, [Release v0.9](https://github.com/simple-rtmp-server/srs/releases/tag/0.9), support bandwidth test, player/encoder/chat [demos](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_SampleDemo). 20926 lines.<br/>
329 -* 2013-12-08, [Release v0.8](https://github.com/simple-rtmp-server/srs/releases/tag/0.8), support [http hooks callback](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_HTTPCallback), update [st_load](https://github.com/winlinvip/st-load). 19186 lines.<br/> 329 +* 2013-12-08, [Release v0.8](https://github.com/simple-rtmp-server/srs/releases/tag/0.8), support [http hooks callback](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_HTTPCallback), update [SB](https://github.com/simple-rtmp-server/srs-bench). 19186 lines.<br/>
330 * 2013-12-03, [Release v0.7](https://github.com/simple-rtmp-server/srs/releases/tag/0.7), support [live stream transcoding](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_FFMPEG). 17605 lines.<br/> 330 * 2013-12-03, [Release v0.7](https://github.com/simple-rtmp-server/srs/releases/tag/0.7), support [live stream transcoding](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_FFMPEG). 17605 lines.<br/>
331 * 2013-11-29, [Release v0.6](https://github.com/simple-rtmp-server/srs/releases/tag/0.6), support [forward](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_Forward) stream to origin/edge. 16094 lines.<br/> 331 * 2013-11-29, [Release v0.6](https://github.com/simple-rtmp-server/srs/releases/tag/0.6), support [forward](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_Forward) stream to origin/edge. 16094 lines.<br/>
332 * 2013-11-26, [Release v0.5](https://github.com/simple-rtmp-server/srs/releases/tag/0.5), support [HLS(m3u8)](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_DeliveryHLS), fragment and window. 14449 lines.<br/> 332 * 2013-11-26, [Release v0.5](https://github.com/simple-rtmp-server/srs/releases/tag/0.5), support [HLS(m3u8)](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_DeliveryHLS), fragment and window. 14449 lines.<br/>
@@ -525,7 +525,7 @@ Remark: @@ -525,7 +525,7 @@ Remark:
525 * v1.0, 2014-06-27, SRS online 30days with RTMP/HLS. 525 * v1.0, 2014-06-27, SRS online 30days with RTMP/HLS.
526 * v1.0, 2014-06-25, fix [#108](https://github.com/simple-rtmp-server/srs/issues/108), support config time jitter for encoder non-monotonical stream. 0.9.133 526 * v1.0, 2014-06-25, fix [#108](https://github.com/simple-rtmp-server/srs/issues/108), support config time jitter for encoder non-monotonical stream. 0.9.133
527 * v1.0, 2014-06-23, support report summaries in heartbeat. 0.9.132 527 * v1.0, 2014-06-23, support report summaries in heartbeat. 0.9.132
528 -* v1.0, 2014-06-22, performance refine, support [3k+](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_Performance#%E6%80%A7%E8%83%BD%E4%BE%8B%E8%A1%8C%E6%8A%A5%E5%91%8A4k) connections(270kbps). 0.9.130 528 +* v1.0, 2014-06-22, performance refine, support [3k+](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_Performance#performancereport4k) connections(270kbps). 0.9.130
529 * v1.0, 2014-06-21, support edge [token traverse](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_DRM#tokentraverse), fix [#104](https://github.com/simple-rtmp-server/srs/issues/104). 0.9.129 529 * v1.0, 2014-06-21, support edge [token traverse](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_DRM#tokentraverse), fix [#104](https://github.com/simple-rtmp-server/srs/issues/104). 0.9.129
530 * v1.0, 2014-06-19, add connections count to api summaries. 0.9.127 530 * v1.0, 2014-06-19, add connections count to api summaries. 0.9.127
531 * v1.0, 2014-06-19, add srs bytes and kbps to api summaries. 0.9.126 531 * v1.0, 2014-06-19, add srs bytes and kbps to api summaries. 0.9.126
@@ -618,7 +618,7 @@ Remark: @@ -618,7 +618,7 @@ Remark:
618 * v0.8, 2013-12-08, support multiple http hooks for a event. 618 * v0.8, 2013-12-08, support multiple http hooks for a event.
619 * v0.8, 2013-12-07, support http callback hooks, on_connect. 619 * v0.8, 2013-12-07, support http callback hooks, on_connect.
620 * v0.8, 2013-12-07, support network based cli and json result, add CherryPy 3.2.4. 620 * v0.8, 2013-12-07, support network based cli and json result, add CherryPy 3.2.4.
621 -* v0.8, 2013-12-07, update http/hls/rtmp load test tool [st_load](https://github.com/winlinvip/st-load), use SRS rtmp sdk. 621 +* v0.8, 2013-12-07, update http/hls/rtmp load test tool [SB](https://github.com/simple-rtmp-server/srs-bench), use SRS rtmp sdk.
622 * v0.8, 2013-12-06, support max_connections, drop if exceed. 622 * v0.8, 2013-12-06, support max_connections, drop if exceed.
623 * v0.8, 2013-12-05, support log_dir, write ffmpeg log to file. 623 * v0.8, 2013-12-05, support log_dir, write ffmpeg log to file.
624 * v0.8, 2013-12-05, fix the forward/hls/encoder bug. 624 * v0.8, 2013-12-05, fix the forward/hls/encoder bug.
@@ -676,9 +676,9 @@ Performance benchmark history, on virtual box. @@ -676,9 +676,9 @@ Performance benchmark history, on virtual box.
676 * See also: [Performance for x86/x64 Test Guide](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_Performance) 676 * See also: [Performance for x86/x64 Test Guide](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_Performance)
677 * See also: [Performance for RaspberryPi](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_RaspberryPi) 677 * See also: [Performance for RaspberryPi](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_RaspberryPi)
678 678
679 -### Play benchmark 679 +### Play RTMP benchmark
680 680
681 -The play benchmark by [st-load](https://github.com/winlinvip/st-load): 681 +The play RTMP benchmark by [SB](https://github.com/simple-rtmp-server/srs-bench):
682 682
683 683
684 | Update | SRS | Clients | Type | CPU | Memory | Commit | 684 | Update | SRS | Clients | Type | CPU | Memory | Commit |
@@ -696,9 +696,9 @@ The play benchmark by [st-load](https://github.com/winlinvip/st-load): @@ -696,9 +696,9 @@ The play benchmark by [st-load](https://github.com/winlinvip/st-load):
696 | 2014-12-05 | 2.0.57 | 9.0k(9000) | players | 90% | 468MB | [code][p11] | 696 | 2014-12-05 | 2.0.57 | 9.0k(9000) | players | 90% | 468MB | [code][p11] |
697 | 2014-12-07 | 2.0.67 | 10k(10000) | players | 95% | 656MB | [code][p12] | 697 | 2014-12-07 | 2.0.67 | 10k(10000) | players | 95% | 656MB | [code][p12] |
698 698
699 -### Publish benchmark 699 +### Publish RTMP benchmark
700 700
701 -The publish benchmark by [st-load](https://github.com/winlinvip/st-load): 701 +The publish RTMP benchmark by [SB](https://github.com/simple-rtmp-server/srs-bench):
702 702
703 | Update | SRS | Clients | Type | CPU | Memory | Commit | 703 | Update | SRS | Clients | Type | CPU | Memory | Commit |
704 | ------------- | --------- | ------------- | ------------- | --------- | -------- | ------------ | 704 | ------------- | --------- | ------------- | ------------- | --------- | -------- | ------------ |
@@ -712,6 +712,19 @@ The publish benchmark by [st-load](https://github.com/winlinvip/st-load): @@ -712,6 +712,19 @@ The publish benchmark by [st-load](https://github.com/winlinvip/st-load):
712 | 2014-12-04 | 2.0.51 | 2.5k(2500) | publishers | 91% | 259MB | [code][p4] | 712 | 2014-12-04 | 2.0.51 | 2.5k(2500) | publishers | 91% | 259MB | [code][p4] |
713 | 2014-12-04 | 2.0.52 | 4.0k(4000) | publishers | 80% | 331MB | [code][p5] | 713 | 2014-12-04 | 2.0.52 | 4.0k(4000) | publishers | 80% | 331MB | [code][p5] |
714 714
  715 +### Play HTTP FLV benchmark
  716 +
  717 +The play HTTP FLV benchmark by [SB](https://github.com/simple-rtmp-server/srs-bench):
  718 +
  719 +
  720 +| Update | SRS | Clients | Type | CPU | Memory | Commit |
  721 +| ------------- | --------- | ------------- | ------------- | --------- | -------- | ------------ |
  722 +| 2014-05-24 | 2.0.167 | 1.0k(1000) | players | 82% | 86MB | - |
  723 +| 2014-05-24 | 2.0.168 | 2.3k(2300) | players | 92% | 276MB | [code][p17] |
  724 +| 2014-05-24 | 2.0.169 | 3.0k(3000) | players | 94% | 188MB | [code][p18] |
  725 +| 2014-05-24 | 2.0.170 | 3.0k(3000) | players | 89% | 96MB | [code][p19] |
  726 +| 2014-05-25 | 2.0.171 | 6.0k(6000) | players | 84% | 297MB | [code][p20] |
  727 +
715 ### Latency benchmark 728 ### Latency benchmark
716 729
717 The latency between encoder and player with realtime config( 730 The latency between encoder and player with realtime config(
@@ -826,6 +839,10 @@ Winlin @@ -826,6 +839,10 @@ Winlin
826 [p14]: https://github.com/simple-rtmp-server/srs/commit/10297fab519811845b549a8af40a6bcbd23411e8 839 [p14]: https://github.com/simple-rtmp-server/srs/commit/10297fab519811845b549a8af40a6bcbd23411e8
827 [p15]: https://github.com/simple-rtmp-server/srs/commit/0d6b91039d408328caab31a1077d56a809b6bebc 840 [p15]: https://github.com/simple-rtmp-server/srs/commit/0d6b91039d408328caab31a1077d56a809b6bebc
828 [p16]: https://github.com/simple-rtmp-server/srs/commit/0d6b91039d408328caab31a1077d56a809b6bebc 841 [p16]: https://github.com/simple-rtmp-server/srs/commit/0d6b91039d408328caab31a1077d56a809b6bebc
  842 +[p17]: https://github.com/simple-rtmp-server/srs/commit/fc995473eb02c7cf64b5b212b456e11f34aa7984
  843 +[p18]: https://github.com/simple-rtmp-server/srs/commit/960341b9b2b9646270ccfd113b4dd784d9826c73
  844 +[p19]: https://github.com/simple-rtmp-server/srs/commit/4df19ba99a4e4d80cd89b304f9298d343497bec9
  845 +[p20]: https://github.com/simple-rtmp-server/srs/commit/d12fc7fcc5b2e9e3c8ee5c7da01d0e41c8f8ca4a
829 846
830 [authors]: https://github.com/simple-rtmp-server/srs/blob/develop/AUTHORS.txt 847 [authors]: https://github.com/simple-rtmp-server/srs/blob/develop/AUTHORS.txt
831 [bigthanks]: https://github.com/simple-rtmp-server/srs/wiki/v1_CN_Product#bigthanks 848 [bigthanks]: https://github.com/simple-rtmp-server/srs/wiki/v1_CN_Product#bigthanks
@@ -66,11 +66,14 @@ SrsHttpResponseWriter::SrsHttpResponseWriter(SrsStSocket* io) @@ -66,11 +66,14 @@ SrsHttpResponseWriter::SrsHttpResponseWriter(SrsStSocket* io)
66 content_length = -1; 66 content_length = -1;
67 written = 0; 67 written = 0;
68 header_sent = false; 68 header_sent = false;
  69 + nb_iovss_cache = 0;
  70 + iovss_cache = NULL;
69 } 71 }
70 72
71 SrsHttpResponseWriter::~SrsHttpResponseWriter() 73 SrsHttpResponseWriter::~SrsHttpResponseWriter()
72 { 74 {
73 srs_freep(hdr); 75 srs_freep(hdr);
  76 + srs_freep(iovss_cache);
74 } 77 }
75 78
76 int SrsHttpResponseWriter::final_request() 79 int SrsHttpResponseWriter::final_request()
@@ -98,8 +101,14 @@ int SrsHttpResponseWriter::write(char* data, int size) @@ -98,8 +101,14 @@ int SrsHttpResponseWriter::write(char* data, int size)
98 101
99 if (!header_wrote) { 102 if (!header_wrote) {
100 write_header(SRS_CONSTS_HTTP_OK); 103 write_header(SRS_CONSTS_HTTP_OK);
  104 +
  105 + if ((ret = send_header(data, size)) != ERROR_SUCCESS) {
  106 + srs_error("http: send header failed. ret=%d", ret);
  107 + return ret;
  108 + }
101 } 109 }
102 110
  111 + // check the bytes send and content length.
103 written += size; 112 written += size;
104 if (content_length != -1 && written > content_length) { 113 if (content_length != -1 && written > content_length) {
105 ret = ERROR_HTTP_CONTENT_LENGTH; 114 ret = ERROR_HTTP_CONTENT_LENGTH;
@@ -107,11 +116,6 @@ int SrsHttpResponseWriter::write(char* data, int size) @@ -107,11 +116,6 @@ int SrsHttpResponseWriter::write(char* data, int size)
107 return ret; 116 return ret;
108 } 117 }
109 118
110 - if ((ret = send_header(data, size)) != ERROR_SUCCESS) {  
111 - srs_error("http: send header failed. ret=%d", ret);  
112 - return ret;  
113 - }  
114 -  
115 // ignore NULL content. 119 // ignore NULL content.
116 if (!data) { 120 if (!data) {
117 return ret; 121 return ret;
@@ -123,19 +127,107 @@ int SrsHttpResponseWriter::write(char* data, int size) @@ -123,19 +127,107 @@ int SrsHttpResponseWriter::write(char* data, int size)
123 } 127 }
124 128
125 // send in chunked encoding. 129 // send in chunked encoding.
126 - std::stringstream ss;  
127 - ss << hex << size << SRS_HTTP_CRLF;  
128 - std::string ch = ss.str();  
129 - if ((ret = skt->write((void*)ch.data(), (int)ch.length(), NULL)) != ERROR_SUCCESS) { 130 + int nb_size = snprintf(header_cache, SRS_HTTP_HEADER_CACHE_SIZE, "%x", size);
  131 +
  132 + iovec iovs[4];
  133 + iovs[0].iov_base = (char*)header_cache;
  134 + iovs[0].iov_len = (int)nb_size;
  135 + iovs[1].iov_base = (char*)SRS_HTTP_CRLF;
  136 + iovs[1].iov_len = 2;
  137 + iovs[2].iov_base = (char*)data;
  138 + iovs[2].iov_len = size;
  139 + iovs[3].iov_base = (char*)SRS_HTTP_CRLF;
  140 + iovs[3].iov_len = 2;
  141 +
  142 + ssize_t nwrite;
  143 + if ((ret = skt->writev(iovs, 4, &nwrite)) != ERROR_SUCCESS) {
130 return ret; 144 return ret;
131 } 145 }
132 - if ((ret = skt->write((void*)data, size, NULL)) != ERROR_SUCCESS) { 146 +
  147 + return ret;
  148 +}
  149 +
  150 +int SrsHttpResponseWriter::writev(iovec* iov, int iovcnt, ssize_t* pnwrite)
  151 +{
  152 + int ret = ERROR_SUCCESS;
  153 +
  154 + // when header not ready, or not chunked, send one by one.
  155 + if (!header_wrote || content_length != -1) {
  156 + ssize_t nwrite = 0;
  157 + for (int i = 0; i < iovcnt; i++) {
  158 + iovec* piovc = iov + i;
  159 + nwrite += piovc->iov_len;
  160 + if ((ret = write((char*)piovc->iov_base, (int)piovc->iov_len)) != ERROR_SUCCESS) {
133 return ret; 161 return ret;
134 } 162 }
135 - if ((ret = skt->write((void*)SRS_HTTP_CRLF, 2, NULL)) != ERROR_SUCCESS) { 163 + }
  164 +
  165 + if (pnwrite) {
  166 + *pnwrite = nwrite;
  167 + }
  168 +
136 return ret; 169 return ret;
137 } 170 }
138 171
  172 + // ignore NULL content.
  173 + if (iovcnt <= 0) {
  174 + return ret;
  175 + }
  176 +
  177 + // send in chunked encoding.
  178 + int nb_iovss = 3 + iovcnt;
  179 + iovec* iovss = iovss_cache;
  180 + if (nb_iovss_cache < nb_iovss) {
  181 + srs_freep(iovss_cache);
  182 + nb_iovss_cache = nb_iovss;
  183 + iovss = iovss_cache = new iovec[nb_iovss];
  184 + }
  185 +
  186 + // send in chunked encoding.
  187 +
  188 + // chunk size.
  189 + int size = 0;
  190 + for (int i = 0; i < iovcnt; i++) {
  191 + iovec* data_iov = iov + i;
  192 + size += data_iov->iov_len;
  193 + }
  194 + written += size;
  195 +
  196 + // chunk header
  197 + int nb_size = snprintf(header_cache, SRS_HTTP_HEADER_CACHE_SIZE, "%x", size);
  198 + iovec* iovs = iovss;
  199 + iovs[0].iov_base = (char*)header_cache;
  200 + iovs[0].iov_len = (int)nb_size;
  201 + iovs++;
  202 +
  203 + // chunk header eof.
  204 + iovs[0].iov_base = (char*)SRS_HTTP_CRLF;
  205 + iovs[0].iov_len = 2;
  206 + iovs++;
  207 +
  208 + // chunk body.
  209 + for (int i = 0; i < iovcnt; i++) {
  210 + iovec* data_iov = iov + i;
  211 + iovs[0].iov_base = (char*)data_iov->iov_base;
  212 + iovs[0].iov_len = (int)data_iov->iov_len;
  213 + iovs++;
  214 + }
  215 +
  216 + // chunk body eof.
  217 + iovs[0].iov_base = (char*)SRS_HTTP_CRLF;
  218 + iovs[0].iov_len = 2;
  219 + iovs++;
  220 +
  221 + // sendout all ioves.
  222 + ssize_t nwrite;
  223 + if ((ret = srs_write_large_iovs(skt, iovss, nb_iovss, &nwrite)) != ERROR_SUCCESS) {
  224 + return ret;
  225 + }
  226 +
  227 + if (pnwrite) {
  228 + *pnwrite = nwrite;
  229 + }
  230 +
139 return ret; 231 return ret;
140 } 232 }
141 233
@@ -1365,6 +1457,21 @@ int SrsFlvStreamEncoder::dump_cache(SrsConsumer* /*consumer*/) @@ -1365,6 +1457,21 @@ int SrsFlvStreamEncoder::dump_cache(SrsConsumer* /*consumer*/)
1365 return ERROR_SUCCESS; 1457 return ERROR_SUCCESS;
1366 } 1458 }
1367 1459
  1460 +#ifdef SRS_PERF_FAST_FLV_ENCODER
  1461 +SrsFastFlvStreamEncoder::SrsFastFlvStreamEncoder()
  1462 +{
  1463 +}
  1464 +
  1465 +SrsFastFlvStreamEncoder::~SrsFastFlvStreamEncoder()
  1466 +{
  1467 +}
  1468 +
  1469 +int SrsFastFlvStreamEncoder::write_tags(SrsSharedPtrMessage** msgs, int count)
  1470 +{
  1471 + return enc->write_tags(msgs, count);
  1472 +}
  1473 +#endif
  1474 +
1368 SrsAacStreamEncoder::SrsAacStreamEncoder() 1475 SrsAacStreamEncoder::SrsAacStreamEncoder()
1369 { 1476 {
1370 enc = new SrsAacEncoder(); 1477 enc = new SrsAacEncoder();
@@ -1509,6 +1616,11 @@ int SrsStreamWriter::write(void* buf, size_t count, ssize_t* pnwrite) @@ -1509,6 +1616,11 @@ int SrsStreamWriter::write(void* buf, size_t count, ssize_t* pnwrite)
1509 return writer->write((char*)buf, (int)count); 1616 return writer->write((char*)buf, (int)count);
1510 } 1617 }
1511 1618
  1619 +int SrsStreamWriter::writev(iovec* iov, int iovcnt, ssize_t* pnwrite)
  1620 +{
  1621 + return writer->writev(iov, iovcnt, pnwrite);
  1622 +}
  1623 +
1512 SrsLiveStream::SrsLiveStream(SrsSource* s, SrsRequest* r, SrsStreamCache* c) 1624 SrsLiveStream::SrsLiveStream(SrsSource* s, SrsRequest* r, SrsStreamCache* c)
1513 { 1625 {
1514 source = s; 1626 source = s;
@@ -1530,7 +1642,11 @@ int SrsLiveStream::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) @@ -1530,7 +1642,11 @@ int SrsLiveStream::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
1530 srs_assert(entry); 1642 srs_assert(entry);
1531 if (srs_string_ends_with(entry->pattern, ".flv")) { 1643 if (srs_string_ends_with(entry->pattern, ".flv")) {
1532 w->header()->set_content_type("video/x-flv"); 1644 w->header()->set_content_type("video/x-flv");
  1645 +#ifdef SRS_PERF_FAST_FLV_ENCODER
  1646 + enc = new SrsFastFlvStreamEncoder();
  1647 +#else
1533 enc = new SrsFlvStreamEncoder(); 1648 enc = new SrsFlvStreamEncoder();
  1649 +#endif
1534 } else if (srs_string_ends_with(entry->pattern, ".aac")) { 1650 } else if (srs_string_ends_with(entry->pattern, ".aac")) {
1535 w->header()->set_content_type("audio/x-aac"); 1651 w->header()->set_content_type("audio/x-aac");
1536 enc = new SrsAacStreamEncoder(); 1652 enc = new SrsAacStreamEncoder();
@@ -1576,6 +1692,10 @@ int SrsLiveStream::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) @@ -1576,6 +1692,10 @@ int SrsLiveStream::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
1576 } 1692 }
1577 } 1693 }
1578 1694
  1695 +#ifdef SRS_PERF_FAST_FLV_ENCODER
  1696 + SrsFastFlvStreamEncoder* ffe = dynamic_cast<SrsFastFlvStreamEncoder*>(enc);
  1697 +#endif
  1698 +
1579 while (true) { 1699 while (true) {
1580 pprint->elapse(); 1700 pprint->elapse();
1581 1701
@@ -1602,7 +1722,15 @@ int SrsLiveStream::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) @@ -1602,7 +1722,15 @@ int SrsLiveStream::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
1602 } 1722 }
1603 1723
1604 // sendout all messages. 1724 // sendout all messages.
  1725 +#ifdef SRS_PERF_FAST_FLV_ENCODER
  1726 + if (ffe) {
  1727 + ret = ffe->write_tags(msgs.msgs, count);
  1728 + } else {
  1729 + ret = streaming_send_messages(enc, msgs.msgs, count);
  1730 + }
  1731 +#else
1605 ret = streaming_send_messages(enc, msgs.msgs, count); 1732 ret = streaming_send_messages(enc, msgs.msgs, count);
  1733 +#endif
1606 1734
1607 // free the messages. 1735 // free the messages.
1608 for (int i = 0; i < count; i++) { 1736 for (int i = 0; i < count; i++) {
@@ -71,6 +71,10 @@ class SrsHttpMessage; @@ -71,6 +71,10 @@ class SrsHttpMessage;
71 71
72 #ifdef SRS_AUTO_HTTP_PARSER 72 #ifdef SRS_AUTO_HTTP_PARSER
73 73
  74 +// the http chunked header size,
  75 +// for writev, there always one chunk to send it.
  76 +#define SRS_HTTP_HEADER_CACHE_SIZE 64
  77 +
74 /** 78 /**
75 * response writer use st socket 79 * response writer use st socket
76 */ 80 */
@@ -80,6 +84,10 @@ private: @@ -80,6 +84,10 @@ private:
80 SrsStSocket* skt; 84 SrsStSocket* skt;
81 SrsHttpHeader* hdr; 85 SrsHttpHeader* hdr;
82 private: 86 private:
  87 + char header_cache[SRS_HTTP_HEADER_CACHE_SIZE];
  88 + iovec* iovss_cache;
  89 + int nb_iovss_cache;
  90 +private:
83 // reply header has been (logically) written 91 // reply header has been (logically) written
84 bool header_wrote; 92 bool header_wrote;
85 // status code passed to WriteHeader 93 // status code passed to WriteHeader
@@ -102,6 +110,7 @@ public: @@ -102,6 +110,7 @@ public:
102 virtual int final_request(); 110 virtual int final_request();
103 virtual SrsHttpHeader* header(); 111 virtual SrsHttpHeader* header();
104 virtual int write(char* data, int size); 112 virtual int write(char* data, int size);
  113 + virtual int writev(iovec* iov, int iovcnt, ssize_t* pnwrite);
105 virtual void write_header(int code); 114 virtual void write_header(int code);
106 virtual int send_header(char* data, int size); 115 virtual int send_header(char* data, int size);
107 }; 116 };
@@ -443,7 +452,7 @@ public: @@ -443,7 +452,7 @@ public:
443 */ 452 */
444 class SrsFlvStreamEncoder : public ISrsStreamEncoder 453 class SrsFlvStreamEncoder : public ISrsStreamEncoder
445 { 454 {
446 -private: 455 +protected:
447 SrsFlvEncoder* enc; 456 SrsFlvEncoder* enc;
448 public: 457 public:
449 SrsFlvStreamEncoder(); 458 SrsFlvStreamEncoder();
@@ -458,6 +467,24 @@ public: @@ -458,6 +467,24 @@ public:
458 virtual int dump_cache(SrsConsumer* consumer); 467 virtual int dump_cache(SrsConsumer* consumer);
459 }; 468 };
460 469
  470 +#ifdef SRS_PERF_FAST_FLV_ENCODER
  471 +/**
  472 + * the fast flv stream encoder.
  473 + * @see https://github.com/simple-rtmp-server/srs/issues/405
  474 + */
  475 +class SrsFastFlvStreamEncoder : public SrsFlvStreamEncoder
  476 +{
  477 +public:
  478 + SrsFastFlvStreamEncoder();
  479 + virtual ~SrsFastFlvStreamEncoder();
  480 +public:
  481 + /**
  482 + * write the tags in a time.
  483 + */
  484 + virtual int write_tags(SrsSharedPtrMessage** msgs, int count);
  485 +};
  486 +#endif
  487 +
461 /** 488 /**
462 * the ts stream encoder, remux rtmp stream to ts stream. 489 * the ts stream encoder, remux rtmp stream to ts stream.
463 */ 490 */
@@ -538,6 +565,7 @@ public: @@ -538,6 +565,7 @@ public:
538 virtual int64_t tellg(); 565 virtual int64_t tellg();
539 public: 566 public:
540 virtual int write(void* buf, size_t count, ssize_t* pnwrite); 567 virtual int write(void* buf, size_t count, ssize_t* pnwrite);
  568 + virtual int writev(iovec* iov, int iovcnt, ssize_t* pnwrite);
541 }; 569 };
542 570
543 /** 571 /**
@@ -181,5 +181,12 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -181,5 +181,12 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
181 #undef SRS_PERF_SO_SNDBUF_SIZE 181 #undef SRS_PERF_SO_SNDBUF_SIZE
182 #endif 182 #endif
183 183
  184 +/**
  185 + * define the following macro to enable the fast flv encoder.
  186 + * @see https://github.com/simple-rtmp-server/srs/issues/405
  187 + */
  188 +#undef SRS_PERF_FAST_FLV_ENCODER
  189 +#define SRS_PERF_FAST_FLV_ENCODER
  190 +
184 #endif 191 #endif
185 192
@@ -30,6 +30,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -30,6 +30,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 30
31 #include <fcntl.h> 31 #include <fcntl.h>
32 #include <sstream> 32 #include <sstream>
  33 +#include <sys/uio.h>
33 using namespace std; 34 using namespace std;
34 35
35 #include <srs_kernel_log.hpp> 36 #include <srs_kernel_log.hpp>
@@ -145,6 +146,27 @@ int SrsFileWriter::write(void* buf, size_t count, ssize_t* pnwrite) @@ -145,6 +146,27 @@ int SrsFileWriter::write(void* buf, size_t count, ssize_t* pnwrite)
145 return ret; 146 return ret;
146 } 147 }
147 148
  149 +int SrsFileWriter::writev(iovec* iov, int iovcnt, ssize_t* pnwrite)
  150 +{
  151 + int ret = ERROR_SUCCESS;
  152 +
  153 + ssize_t nwrite = 0;
  154 + for (int i = 0; i < iovcnt; i++) {
  155 + iovec* piov = iov + i;
  156 + ssize_t this_nwrite = 0;
  157 + if ((ret = write(piov->iov_base, piov->iov_len, &this_nwrite)) != ERROR_SUCCESS) {
  158 + return ret;
  159 + }
  160 + nwrite += this_nwrite;
  161 + }
  162 +
  163 + if (pnwrite) {
  164 + *pnwrite = nwrite;
  165 + }
  166 +
  167 + return ret;
  168 +}
  169 +
148 SrsFileReader::SrsFileReader() 170 SrsFileReader::SrsFileReader()
149 { 171 {
150 fd = -1; 172 fd = -1;
@@ -31,6 +31,11 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -31,6 +31,11 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 31
32 #include <string> 32 #include <string>
33 33
  34 +// for srs-librtmp, @see https://github.com/simple-rtmp-server/srs/issues/213
  35 +#ifndef _WIN32
  36 +#include <sys/uio.h>
  37 +#endif
  38 +
34 /** 39 /**
35 * file writer, to write to file. 40 * file writer, to write to file.
36 */ 41 */
@@ -62,6 +67,11 @@ public: @@ -62,6 +67,11 @@ public:
62 * @param pnwrite the output nb_write, NULL to ignore. 67 * @param pnwrite the output nb_write, NULL to ignore.
63 */ 68 */
64 virtual int write(void* buf, size_t count, ssize_t* pnwrite); 69 virtual int write(void* buf, size_t count, ssize_t* pnwrite);
  70 + /**
  71 + * for the HTTP FLV, to writev to improve performance.
  72 + * @see https://github.com/simple-rtmp-server/srs/issues/405
  73 + */
  74 + virtual int writev(iovec* iov, int iovcnt, ssize_t* pnwrite);
65 }; 75 };
66 76
67 /** 77 /**
@@ -37,19 +37,304 @@ using namespace std; @@ -37,19 +37,304 @@ using namespace std;
37 #include <srs_kernel_stream.hpp> 37 #include <srs_kernel_stream.hpp>
38 #include <srs_kernel_file.hpp> 38 #include <srs_kernel_file.hpp>
39 #include <srs_kernel_codec.hpp> 39 #include <srs_kernel_codec.hpp>
  40 +#include <srs_kernel_utility.hpp>
40 41
41 -#define SRS_FLV_TAG_HEADER_SIZE 11  
42 -#define SRS_FLV_PREVIOUS_TAG_SIZE 4 42 +SrsMessageHeader::SrsMessageHeader()
  43 +{
  44 + message_type = 0;
  45 + payload_length = 0;
  46 + timestamp_delta = 0;
  47 + stream_id = 0;
  48 +
  49 + timestamp = 0;
  50 + // we always use the connection chunk-id
  51 + perfer_cid = RTMP_CID_OverConnection;
  52 +}
  53 +
  54 +SrsMessageHeader::~SrsMessageHeader()
  55 +{
  56 +}
  57 +
  58 +bool SrsMessageHeader::is_audio()
  59 +{
  60 + return message_type == RTMP_MSG_AudioMessage;
  61 +}
  62 +
  63 +bool SrsMessageHeader::is_video()
  64 +{
  65 + return message_type == RTMP_MSG_VideoMessage;
  66 +}
  67 +
  68 +bool SrsMessageHeader::is_amf0_command()
  69 +{
  70 + return message_type == RTMP_MSG_AMF0CommandMessage;
  71 +}
  72 +
  73 +bool SrsMessageHeader::is_amf0_data()
  74 +{
  75 + return message_type == RTMP_MSG_AMF0DataMessage;
  76 +}
  77 +
  78 +bool SrsMessageHeader::is_amf3_command()
  79 +{
  80 + return message_type == RTMP_MSG_AMF3CommandMessage;
  81 +}
  82 +
  83 +bool SrsMessageHeader::is_amf3_data()
  84 +{
  85 + return message_type == RTMP_MSG_AMF3DataMessage;
  86 +}
  87 +
  88 +bool SrsMessageHeader::is_window_ackledgement_size()
  89 +{
  90 + return message_type == RTMP_MSG_WindowAcknowledgementSize;
  91 +}
  92 +
  93 +bool SrsMessageHeader::is_ackledgement()
  94 +{
  95 + return message_type == RTMP_MSG_Acknowledgement;
  96 +}
  97 +
  98 +bool SrsMessageHeader::is_set_chunk_size()
  99 +{
  100 + return message_type == RTMP_MSG_SetChunkSize;
  101 +}
  102 +
  103 +bool SrsMessageHeader::is_user_control_message()
  104 +{
  105 + return message_type == RTMP_MSG_UserControlMessage;
  106 +}
  107 +
  108 +bool SrsMessageHeader::is_set_peer_bandwidth()
  109 +{
  110 + return message_type == RTMP_MSG_SetPeerBandwidth;
  111 +}
  112 +
  113 +bool SrsMessageHeader::is_aggregate()
  114 +{
  115 + return message_type == RTMP_MSG_AggregateMessage;
  116 +}
  117 +
  118 +void SrsMessageHeader::initialize_amf0_script(int size, int stream)
  119 +{
  120 + message_type = RTMP_MSG_AMF0DataMessage;
  121 + payload_length = (int32_t)size;
  122 + timestamp_delta = (int32_t)0;
  123 + timestamp = (int64_t)0;
  124 + stream_id = (int32_t)stream;
  125 +
  126 + // amf0 script use connection2 chunk-id
  127 + perfer_cid = RTMP_CID_OverConnection2;
  128 +}
  129 +
  130 +void SrsMessageHeader::initialize_audio(int size, u_int32_t time, int stream)
  131 +{
  132 + message_type = RTMP_MSG_AudioMessage;
  133 + payload_length = (int32_t)size;
  134 + timestamp_delta = (int32_t)time;
  135 + timestamp = (int64_t)time;
  136 + stream_id = (int32_t)stream;
  137 +
  138 + // audio chunk-id
  139 + perfer_cid = RTMP_CID_Audio;
  140 +}
  141 +
  142 +void SrsMessageHeader::initialize_video(int size, u_int32_t time, int stream)
  143 +{
  144 + message_type = RTMP_MSG_VideoMessage;
  145 + payload_length = (int32_t)size;
  146 + timestamp_delta = (int32_t)time;
  147 + timestamp = (int64_t)time;
  148 + stream_id = (int32_t)stream;
  149 +
  150 + // video chunk-id
  151 + perfer_cid = RTMP_CID_Video;
  152 +}
  153 +
  154 +SrsCommonMessage::SrsCommonMessage()
  155 +{
  156 + payload = NULL;
  157 + size = 0;
  158 +}
  159 +
  160 +SrsCommonMessage::~SrsCommonMessage()
  161 +{
  162 + srs_freep(payload);
  163 +}
  164 +
  165 +SrsSharedPtrMessage::SrsSharedPtrPayload::SrsSharedPtrPayload()
  166 +{
  167 + payload = NULL;
  168 + size = 0;
  169 + shared_count = 0;
  170 +}
  171 +
  172 +SrsSharedPtrMessage::SrsSharedPtrPayload::~SrsSharedPtrPayload()
  173 +{
  174 + srs_freep(payload);
  175 +}
  176 +
  177 +SrsSharedPtrMessage::SrsSharedPtrMessage()
  178 +{
  179 + ptr = NULL;
  180 +}
  181 +
  182 +SrsSharedPtrMessage::~SrsSharedPtrMessage()
  183 +{
  184 + if (ptr) {
  185 + if (ptr->shared_count == 0) {
  186 + srs_freep(ptr);
  187 + } else {
  188 + ptr->shared_count--;
  189 + }
  190 + }
  191 +}
  192 +
  193 +int SrsSharedPtrMessage::create(SrsCommonMessage* msg)
  194 +{
  195 + int ret = ERROR_SUCCESS;
  196 +
  197 + if ((ret = create(&msg->header, msg->payload, msg->size)) != ERROR_SUCCESS) {
  198 + return ret;
  199 + }
  200 +
  201 + // to prevent double free of payload:
  202 + // initialize already attach the payload of msg,
  203 + // detach the payload to transfer the owner to shared ptr.
  204 + msg->payload = NULL;
  205 + msg->size = 0;
  206 +
  207 + return ret;
  208 +}
  209 +
  210 +int SrsSharedPtrMessage::create(SrsMessageHeader* pheader, char* payload, int size)
  211 +{
  212 + int ret = ERROR_SUCCESS;
  213 +
  214 + if (ptr) {
  215 + ret = ERROR_SYSTEM_ASSERT_FAILED;
  216 + srs_error("should not set the payload twice. ret=%d", ret);
  217 + srs_assert(false);
  218 +
  219 + return ret;
  220 + }
  221 +
  222 + ptr = new SrsSharedPtrPayload();
  223 +
  224 + // direct attach the data.
  225 + if (pheader) {
  226 + ptr->header.message_type = pheader->message_type;
  227 + ptr->header.payload_length = size;
  228 + ptr->header.perfer_cid = pheader->perfer_cid;
  229 + this->timestamp = pheader->timestamp;
  230 + this->stream_id = pheader->stream_id;
  231 + }
  232 + ptr->payload = payload;
  233 + ptr->size = size;
  234 +
  235 + // message can access it.
  236 + this->payload = ptr->payload;
  237 + this->size = ptr->size;
  238 +
  239 + return ret;
  240 +}
  241 +
  242 +int SrsSharedPtrMessage::count()
  243 +{
  244 + srs_assert(ptr);
  245 + return ptr->shared_count;
  246 +}
  247 +
  248 +bool SrsSharedPtrMessage::check(int stream_id)
  249 +{
  250 + // we donot use the complex basic header,
  251 + // ensure the basic header is 1bytes.
  252 + if (ptr->header.perfer_cid < 2) {
  253 + srs_info("change the chunk_id=%d to default=%d",
  254 + ptr->header.perfer_cid, RTMP_CID_ProtocolControl);
  255 + ptr->header.perfer_cid = RTMP_CID_ProtocolControl;
  256 + }
  257 +
  258 + // we assume that the stream_id in a group must be the same.
  259 + if (this->stream_id == stream_id) {
  260 + return true;
  261 + }
  262 + this->stream_id = stream_id;
  263 +
  264 + return false;
  265 +}
  266 +
  267 +bool SrsSharedPtrMessage::is_av()
  268 +{
  269 + return ptr->header.message_type == RTMP_MSG_AudioMessage
  270 + || ptr->header.message_type == RTMP_MSG_VideoMessage;
  271 +}
  272 +
  273 +bool SrsSharedPtrMessage::is_audio()
  274 +{
  275 + return ptr->header.message_type == RTMP_MSG_AudioMessage;
  276 +}
  277 +
  278 +bool SrsSharedPtrMessage::is_video()
  279 +{
  280 + return ptr->header.message_type == RTMP_MSG_VideoMessage;
  281 +}
  282 +
  283 +int SrsSharedPtrMessage::chunk_header(char* cache, int nb_cache, bool c0)
  284 +{
  285 + if (c0) {
  286 + return srs_chunk_header_c0(
  287 + ptr->header.perfer_cid, timestamp, ptr->header.payload_length,
  288 + ptr->header.message_type, stream_id,
  289 + cache, nb_cache);
  290 + } else {
  291 + return srs_chunk_header_c3(
  292 + ptr->header.perfer_cid, timestamp,
  293 + cache, nb_cache);
  294 + }
  295 +}
  296 +
  297 +SrsSharedPtrMessage* SrsSharedPtrMessage::copy()
  298 +{
  299 + srs_assert(ptr);
  300 +
  301 + SrsSharedPtrMessage* copy = new SrsSharedPtrMessage();
  302 +
  303 + copy->ptr = ptr;
  304 + ptr->shared_count++;
  305 +
  306 + copy->timestamp = timestamp;
  307 + copy->stream_id = stream_id;
  308 + copy->payload = ptr->payload;
  309 + copy->size = ptr->size;
  310 +
  311 + return copy;
  312 +}
43 313
44 SrsFlvEncoder::SrsFlvEncoder() 314 SrsFlvEncoder::SrsFlvEncoder()
45 { 315 {
46 _fs = NULL; 316 _fs = NULL;
47 tag_stream = new SrsStream(); 317 tag_stream = new SrsStream();
  318 +
  319 +#ifdef SRS_PERF_FAST_FLV_ENCODER
  320 + nb_tag_headers = 0;
  321 + tag_headers = NULL;
  322 + nb_iovss_cache = 0;
  323 + iovss_cache = NULL;
  324 + nb_ppts = 0;
  325 + ppts = NULL;
  326 +#endif
48 } 327 }
49 328
50 SrsFlvEncoder::~SrsFlvEncoder() 329 SrsFlvEncoder::~SrsFlvEncoder()
51 { 330 {
52 srs_freep(tag_stream); 331 srs_freep(tag_stream);
  332 +
  333 +#ifdef SRS_PERF_FAST_FLV_ENCODER
  334 + srs_freep(tag_headers);
  335 + srs_freep(iovss_cache);
  336 + srs_freep(ppts);
  337 +#endif
53 } 338 }
54 339
55 int SrsFlvEncoder::initialize(SrsFileWriter* fs) 340 int SrsFlvEncoder::initialize(SrsFileWriter* fs)
@@ -118,32 +403,176 @@ int SrsFlvEncoder::write_metadata(char type, char* data, int size) @@ -118,32 +403,176 @@ int SrsFlvEncoder::write_metadata(char type, char* data, int size)
118 403
119 srs_assert(data); 404 srs_assert(data);
120 405
  406 + if ((ret = write_metadata_to_cache(type, data, size, tag_header)) != ERROR_SUCCESS) {
  407 + return ret;
  408 + }
  409 +
  410 + if ((ret = write_tag(tag_header, sizeof(tag_header), data, size)) != ERROR_SUCCESS) {
  411 + if (!srs_is_client_gracefully_close(ret)) {
  412 + srs_error("write flv data tag failed. ret=%d", ret);
  413 + }
  414 + return ret;
  415 + }
  416 +
  417 + return ret;
  418 +}
  419 +
  420 +int SrsFlvEncoder::write_audio(int64_t timestamp, char* data, int size)
  421 +{
  422 + int ret = ERROR_SUCCESS;
  423 +
  424 + srs_assert(data);
  425 +
  426 + if ((ret = write_audio_to_cache(timestamp, data, size, tag_header)) != ERROR_SUCCESS) {
  427 + return ret;
  428 + }
  429 +
  430 + if ((ret = write_tag(tag_header, sizeof(tag_header), data, size)) != ERROR_SUCCESS) {
  431 + if (!srs_is_client_gracefully_close(ret)) {
  432 + srs_error("write flv audio tag failed. ret=%d", ret);
  433 + }
  434 + return ret;
  435 + }
  436 +
  437 + return ret;
  438 +}
  439 +
  440 +int SrsFlvEncoder::write_video(int64_t timestamp, char* data, int size)
  441 +{
  442 + int ret = ERROR_SUCCESS;
  443 +
  444 + srs_assert(data);
  445 +
  446 + if ((ret = write_video_to_cache(timestamp, data, size, tag_header)) != ERROR_SUCCESS) {
  447 + return ret;
  448 + }
  449 +
  450 + if ((ret = write_tag(tag_header, sizeof(tag_header), data, size)) != ERROR_SUCCESS) {
  451 + srs_error("write flv video tag failed. ret=%d", ret);
  452 + return ret;
  453 + }
  454 +
  455 + return ret;
  456 +}
  457 +
  458 +int SrsFlvEncoder::size_tag(int data_size)
  459 +{
  460 + srs_assert(data_size >= 0);
  461 + return SRS_FLV_TAG_HEADER_SIZE + data_size + SRS_FLV_PREVIOUS_TAG_SIZE;
  462 +}
  463 +
  464 +#ifdef SRS_PERF_FAST_FLV_ENCODER
  465 +int SrsFlvEncoder::write_tags(SrsSharedPtrMessage** msgs, int count)
  466 +{
  467 + int ret = ERROR_SUCCESS;
  468 +
  469 + // realloc the iovss.
  470 + int nb_iovss = 3 * count;
  471 + iovec* iovss = iovss_cache;
  472 + if (nb_iovss_cache < nb_iovss) {
  473 + srs_freep(iovss_cache);
  474 +
  475 + nb_iovss_cache = nb_iovss;
  476 + iovss = iovss_cache = new iovec[nb_iovss];
  477 + }
  478 +
  479 + // realloc the tag headers.
  480 + char* cache = tag_headers;
  481 + if (nb_tag_headers < count) {
  482 + srs_freep(tag_headers);
  483 +
  484 + nb_tag_headers = count;
  485 + cache = tag_headers = new char[SRS_FLV_TAG_HEADER_SIZE * count];
  486 + }
  487 +
  488 + // realloc the pts.
  489 + char* pts = ppts;
  490 + if (nb_ppts < count) {
  491 + srs_freep(ppts);
  492 +
  493 + nb_ppts = count;
  494 + pts = ppts = new char[SRS_FLV_PREVIOUS_TAG_SIZE * count];
  495 + }
  496 +
  497 + // the cache is ok, write each messages.
  498 + iovec* iovs = iovss;
  499 + for (int i = 0; i < count; i++) {
  500 + SrsSharedPtrMessage* msg = msgs[i];
  501 +
  502 + // cache all flv header.
  503 + if (msg->is_audio()) {
  504 + if ((ret = write_audio_to_cache(msg->timestamp, msg->payload, msg->size, cache)) != ERROR_SUCCESS) {
  505 + return ret;
  506 + }
  507 + } else if (msg->is_video()) {
  508 + if ((ret = write_video_to_cache(msg->timestamp, msg->payload, msg->size, cache)) != ERROR_SUCCESS) {
  509 + return ret;
  510 + }
  511 + } else {
  512 + if ((ret = write_metadata_to_cache(SrsCodecFlvTagScript, msg->payload, msg->size, cache)) != ERROR_SUCCESS) {
  513 + return ret;
  514 + }
  515 + }
  516 +
  517 + // cache all pts.
  518 + if ((ret = write_pts_to_cache(SRS_FLV_TAG_HEADER_SIZE + msg->size, pts)) != ERROR_SUCCESS) {
  519 + return ret;
  520 + }
  521 +
  522 + // all ioves.
  523 + iovs[0].iov_base = cache;
  524 + iovs[0].iov_len = SRS_FLV_TAG_HEADER_SIZE;
  525 + iovs[1].iov_base = msg->payload;
  526 + iovs[1].iov_len = msg->size;
  527 + iovs[2].iov_base = pts;
  528 + iovs[2].iov_len = SRS_FLV_PREVIOUS_TAG_SIZE;
  529 +
  530 + // move next.
  531 + cache += SRS_FLV_TAG_HEADER_SIZE;
  532 + pts += SRS_FLV_PREVIOUS_TAG_SIZE;
  533 + iovs += 3;
  534 + }
  535 +
  536 + if ((ret = _fs->writev(iovss, nb_iovss, NULL)) != ERROR_SUCCESS) {
  537 + if (!srs_is_client_gracefully_close(ret)) {
  538 + srs_error("write flv tags failed. ret=%d", ret);
  539 + }
  540 + return ret;
  541 + }
  542 +
  543 + return ret;
  544 +}
  545 +#endif
  546 +
  547 +int SrsFlvEncoder::write_metadata_to_cache(char type, char* data, int size, char* cache)
  548 +{
  549 + int ret = ERROR_SUCCESS;
  550 +
  551 + srs_assert(data);
  552 +
121 // 11 bytes tag header 553 // 11 bytes tag header
122 - char tag_header[] = { 554 + /*char tag_header[] = {
123 (char)type, // TagType UB [5], 18 = script data 555 (char)type, // TagType UB [5], 18 = script data
124 (char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message. 556 (char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message.
125 (char)0x00, (char)0x00, (char)0x00, // Timestamp UI24 Time in milliseconds at which the data in this tag applies. 557 (char)0x00, (char)0x00, (char)0x00, // Timestamp UI24 Time in milliseconds at which the data in this tag applies.
126 (char)0x00, // TimestampExtended UI8 558 (char)0x00, // TimestampExtended UI8
127 (char)0x00, (char)0x00, (char)0x00, // StreamID UI24 Always 0. 559 (char)0x00, (char)0x00, (char)0x00, // StreamID UI24 Always 0.
128 - }; 560 + };*/
129 561
130 // write data size. 562 // write data size.
131 - if ((ret = tag_stream->initialize(tag_header + 1, 3)) != ERROR_SUCCESS) { 563 + if ((ret = tag_stream->initialize(cache, 11)) != ERROR_SUCCESS) {
132 return ret; 564 return ret;
133 } 565 }
  566 + tag_stream->write_1bytes(type);
134 tag_stream->write_3bytes(size); 567 tag_stream->write_3bytes(size);
135 -  
136 - if ((ret = write_tag(tag_header, sizeof(tag_header), data, size)) != ERROR_SUCCESS) {  
137 - if (!srs_is_client_gracefully_close(ret)) {  
138 - srs_error("write flv data tag failed. ret=%d", ret);  
139 - }  
140 - return ret;  
141 - } 568 + tag_stream->write_3bytes(0x00);
  569 + tag_stream->write_1bytes(0x00);
  570 + tag_stream->write_3bytes(0x00);
142 571
143 return ret; 572 return ret;
144 } 573 }
145 574
146 -int SrsFlvEncoder::write_audio(int64_t timestamp, char* data, int size) 575 +int SrsFlvEncoder::write_audio_to_cache(int64_t timestamp, char* data, int size, char* cache)
147 { 576 {
148 int ret = ERROR_SUCCESS; 577 int ret = ERROR_SUCCESS;
149 578
@@ -152,34 +581,29 @@ int SrsFlvEncoder::write_audio(int64_t timestamp, char* data, int size) @@ -152,34 +581,29 @@ int SrsFlvEncoder::write_audio(int64_t timestamp, char* data, int size)
152 timestamp &= 0x7fffffff; 581 timestamp &= 0x7fffffff;
153 582
154 // 11bytes tag header 583 // 11bytes tag header
155 - char tag_header[] = { 584 + /*char tag_header[] = {
156 (char)SrsCodecFlvTagAudio, // TagType UB [5], 8 = audio 585 (char)SrsCodecFlvTagAudio, // TagType UB [5], 8 = audio
157 (char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message. 586 (char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message.
158 (char)0x00, (char)0x00, (char)0x00, // Timestamp UI24 Time in milliseconds at which the data in this tag applies. 587 (char)0x00, (char)0x00, (char)0x00, // Timestamp UI24 Time in milliseconds at which the data in this tag applies.
159 (char)0x00, // TimestampExtended UI8 588 (char)0x00, // TimestampExtended UI8
160 (char)0x00, (char)0x00, (char)0x00, // StreamID UI24 Always 0. 589 (char)0x00, (char)0x00, (char)0x00, // StreamID UI24 Always 0.
161 - }; 590 + };*/
162 591
163 // write data size. 592 // write data size.
164 - if ((ret = tag_stream->initialize(tag_header + 1, 7)) != ERROR_SUCCESS) { 593 + if ((ret = tag_stream->initialize(cache, 11)) != ERROR_SUCCESS) {
165 return ret; 594 return ret;
166 } 595 }
  596 + tag_stream->write_1bytes(SrsCodecFlvTagAudio);
167 tag_stream->write_3bytes(size); 597 tag_stream->write_3bytes(size);
168 tag_stream->write_3bytes((int32_t)timestamp); 598 tag_stream->write_3bytes((int32_t)timestamp);
169 // default to little-endian 599 // default to little-endian
170 tag_stream->write_1bytes((timestamp >> 24) & 0xFF); 600 tag_stream->write_1bytes((timestamp >> 24) & 0xFF);
171 -  
172 - if ((ret = write_tag(tag_header, sizeof(tag_header), data, size)) != ERROR_SUCCESS) {  
173 - if (!srs_is_client_gracefully_close(ret)) {  
174 - srs_error("write flv audio tag failed. ret=%d", ret);  
175 - }  
176 - return ret;  
177 - } 601 + tag_stream->write_3bytes(0x00);
178 602
179 return ret; 603 return ret;
180 } 604 }
181 605
182 -int SrsFlvEncoder::write_video(int64_t timestamp, char* data, int size) 606 +int SrsFlvEncoder::write_video_to_cache(int64_t timestamp, char* data, int size, char* cache)
183 { 607 {
184 int ret = ERROR_SUCCESS; 608 int ret = ERROR_SUCCESS;
185 609
@@ -188,66 +612,61 @@ int SrsFlvEncoder::write_video(int64_t timestamp, char* data, int size) @@ -188,66 +612,61 @@ int SrsFlvEncoder::write_video(int64_t timestamp, char* data, int size)
188 timestamp &= 0x7fffffff; 612 timestamp &= 0x7fffffff;
189 613
190 // 11bytes tag header 614 // 11bytes tag header
191 - char tag_header[] = { 615 + /*char tag_header[] = {
192 (char)SrsCodecFlvTagVideo, // TagType UB [5], 9 = video 616 (char)SrsCodecFlvTagVideo, // TagType UB [5], 9 = video
193 (char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message. 617 (char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message.
194 (char)0x00, (char)0x00, (char)0x00, // Timestamp UI24 Time in milliseconds at which the data in this tag applies. 618 (char)0x00, (char)0x00, (char)0x00, // Timestamp UI24 Time in milliseconds at which the data in this tag applies.
195 (char)0x00, // TimestampExtended UI8 619 (char)0x00, // TimestampExtended UI8
196 (char)0x00, (char)0x00, (char)0x00, // StreamID UI24 Always 0. 620 (char)0x00, (char)0x00, (char)0x00, // StreamID UI24 Always 0.
197 - }; 621 + };*/
198 622
199 // write data size. 623 // write data size.
200 - if ((ret = tag_stream->initialize(tag_header + 1, 7)) != ERROR_SUCCESS) { 624 + if ((ret = tag_stream->initialize(cache, 11)) != ERROR_SUCCESS) {
201 return ret; 625 return ret;
202 } 626 }
  627 + tag_stream->write_1bytes(SrsCodecFlvTagVideo);
203 tag_stream->write_3bytes(size); 628 tag_stream->write_3bytes(size);
204 tag_stream->write_3bytes((int32_t)timestamp); 629 tag_stream->write_3bytes((int32_t)timestamp);
205 // default to little-endian 630 // default to little-endian
206 tag_stream->write_1bytes((timestamp >> 24) & 0xFF); 631 tag_stream->write_1bytes((timestamp >> 24) & 0xFF);
207 -  
208 - if ((ret = write_tag(tag_header, sizeof(tag_header), data, size)) != ERROR_SUCCESS) {  
209 - srs_error("write flv video tag failed. ret=%d", ret);  
210 - return ret;  
211 - } 632 + tag_stream->write_3bytes(0x00);
212 633
213 return ret; 634 return ret;
214 } 635 }
215 636
216 -int SrsFlvEncoder::size_tag(int data_size)  
217 -{  
218 - srs_assert(data_size >= 0);  
219 - return SRS_FLV_TAG_HEADER_SIZE + data_size + SRS_FLV_PREVIOUS_TAG_SIZE;  
220 -}  
221 -  
222 -int SrsFlvEncoder::write_tag(char* header, int header_size, char* tag, int tag_size) 637 +int SrsFlvEncoder::write_pts_to_cache(int size, char* cache)
223 { 638 {
224 int ret = ERROR_SUCCESS; 639 int ret = ERROR_SUCCESS;
225 640
226 - // write tag header.  
227 - if ((ret = _fs->write(header, header_size, NULL)) != ERROR_SUCCESS) {  
228 - if (!srs_is_client_gracefully_close(ret)) {  
229 - srs_error("write flv tag header failed. ret=%d", ret);  
230 - } 641 + if ((ret = tag_stream->initialize(cache, SRS_FLV_PREVIOUS_TAG_SIZE)) != ERROR_SUCCESS) {
231 return ret; 642 return ret;
232 } 643 }
  644 + tag_stream->write_4bytes(size);
233 645
234 - // write tag data.  
235 - if ((ret = _fs->write(tag, tag_size, NULL)) != ERROR_SUCCESS) {  
236 - if (!srs_is_client_gracefully_close(ret)) {  
237 - srs_error("write flv tag failed. ret=%d", ret);  
238 - }  
239 return ret; 646 return ret;
240 - } 647 +}
  648 +
  649 +int SrsFlvEncoder::write_tag(char* header, int header_size, char* tag, int tag_size)
  650 +{
  651 + int ret = ERROR_SUCCESS;
241 652
242 // PreviousTagSizeN UI32 Size of last tag, including its header, in bytes. 653 // PreviousTagSizeN UI32 Size of last tag, including its header, in bytes.
243 char pre_size[SRS_FLV_PREVIOUS_TAG_SIZE]; 654 char pre_size[SRS_FLV_PREVIOUS_TAG_SIZE];
244 - if ((ret = tag_stream->initialize(pre_size, SRS_FLV_PREVIOUS_TAG_SIZE)) != ERROR_SUCCESS) { 655 + if ((ret = write_pts_to_cache(tag_size + header_size, pre_size)) != ERROR_SUCCESS) {
245 return ret; 656 return ret;
246 } 657 }
247 - tag_stream->write_4bytes(tag_size + header_size);  
248 - if ((ret = _fs->write(pre_size, sizeof(pre_size), NULL)) != ERROR_SUCCESS) { 658 +
  659 + iovec iovs[3];
  660 + iovs[0].iov_base = header;
  661 + iovs[0].iov_len = header_size;
  662 + iovs[1].iov_base = tag;
  663 + iovs[1].iov_len = tag_size;
  664 + iovs[2].iov_base = pre_size;
  665 + iovs[2].iov_len = SRS_FLV_PREVIOUS_TAG_SIZE;
  666 +
  667 + if ((ret = _fs->writev(iovs, 3, NULL)) != ERROR_SUCCESS) {
249 if (!srs_is_client_gracefully_close(ret)) { 668 if (!srs_is_client_gracefully_close(ret)) {
250 - srs_error("write flv previous tag size failed. ret=%d", ret); 669 + srs_error("write flv tag failed. ret=%d", ret);
251 } 670 }
252 return ret; 671 return ret;
253 } 672 }
@@ -31,10 +31,399 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -31,10 +31,399 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 31
32 #include <string> 32 #include <string>
33 33
  34 +// for srs-librtmp, @see https://github.com/simple-rtmp-server/srs/issues/213
  35 +#ifndef _WIN32
  36 +#include <sys/uio.h>
  37 +#endif
  38 +
34 class SrsStream; 39 class SrsStream;
35 class SrsFileWriter; 40 class SrsFileWriter;
36 class SrsFileReader; 41 class SrsFileReader;
37 42
  43 +#define SRS_FLV_TAG_HEADER_SIZE 11
  44 +#define SRS_FLV_PREVIOUS_TAG_SIZE 4
  45 +
  46 +/****************************************************************************
  47 + *****************************************************************************
  48 + ****************************************************************************/
  49 +/**
  50 + 5. Protocol Control Messages
  51 + RTMP reserves message type IDs 1-7 for protocol control messages.
  52 + These messages contain information needed by the RTM Chunk Stream
  53 + protocol or RTMP itself. Protocol messages with IDs 1 & 2 are
  54 + reserved for usage with RTM Chunk Stream protocol. Protocol messages
  55 + with IDs 3-6 are reserved for usage of RTMP. Protocol message with ID
  56 + 7 is used between edge server and origin server.
  57 + */
  58 +#define RTMP_MSG_SetChunkSize 0x01
  59 +#define RTMP_MSG_AbortMessage 0x02
  60 +#define RTMP_MSG_Acknowledgement 0x03
  61 +#define RTMP_MSG_UserControlMessage 0x04
  62 +#define RTMP_MSG_WindowAcknowledgementSize 0x05
  63 +#define RTMP_MSG_SetPeerBandwidth 0x06
  64 +#define RTMP_MSG_EdgeAndOriginServerCommand 0x07
  65 +/**
  66 + 3. Types of messages
  67 + The server and the client send messages over the network to
  68 + communicate with each other. The messages can be of any type which
  69 + includes audio messages, video messages, command messages, shared
  70 + object messages, data messages, and user control messages.
  71 + 3.1. Command message
  72 + Command messages carry the AMF-encoded commands between the client
  73 + and the server. These messages have been assigned message type value
  74 + of 20 for AMF0 encoding and message type value of 17 for AMF3
  75 + encoding. These messages are sent to perform some operations like
  76 + connect, createStream, publish, play, pause on the peer. Command
  77 + messages like onstatus, result etc. are used to inform the sender
  78 + about the status of the requested commands. A command message
  79 + consists of command name, transaction ID, and command object that
  80 + contains related parameters. A client or a server can request Remote
  81 + Procedure Calls (RPC) over streams that are communicated using the
  82 + command messages to the peer.
  83 + */
  84 +#define RTMP_MSG_AMF3CommandMessage 17 // 0x11
  85 +#define RTMP_MSG_AMF0CommandMessage 20 // 0x14
  86 +/**
  87 + 3.2. Data message
  88 + The client or the server sends this message to send Metadata or any
  89 + user data to the peer. Metadata includes details about the
  90 + data(audio, video etc.) like creation time, duration, theme and so
  91 + on. These messages have been assigned message type value of 18 for
  92 + AMF0 and message type value of 15 for AMF3.
  93 + */
  94 +#define RTMP_MSG_AMF0DataMessage 18 // 0x12
  95 +#define RTMP_MSG_AMF3DataMessage 15 // 0x0F
  96 +/**
  97 + 3.3. Shared object message
  98 + A shared object is a Flash object (a collection of name value pairs)
  99 + that are in synchronization across multiple clients, instances, and
  100 + so on. The message types kMsgContainer=19 for AMF0 and
  101 + kMsgContainerEx=16 for AMF3 are reserved for shared object events.
  102 + Each message can contain multiple events.
  103 + */
  104 +#define RTMP_MSG_AMF3SharedObject 16 // 0x10
  105 +#define RTMP_MSG_AMF0SharedObject 19 // 0x13
  106 +/**
  107 + 3.4. Audio message
  108 + The client or the server sends this message to send audio data to the
  109 + peer. The message type value of 8 is reserved for audio messages.
  110 + */
  111 +#define RTMP_MSG_AudioMessage 8 // 0x08
  112 +/* *
  113 + 3.5. Video message
  114 + The client or the server sends this message to send video data to the
  115 + peer. The message type value of 9 is reserved for video messages.
  116 + These messages are large and can delay the sending of other type of
  117 + messages. To avoid such a situation, the video message is assigned
  118 + the lowest priority.
  119 + */
  120 +#define RTMP_MSG_VideoMessage 9 // 0x09
  121 +/**
  122 + 3.6. Aggregate message
  123 + An aggregate message is a single message that contains a list of submessages.
  124 + The message type value of 22 is reserved for aggregate
  125 + messages.
  126 + */
  127 +#define RTMP_MSG_AggregateMessage 22 // 0x16
  128 +
  129 +/****************************************************************************
  130 + *****************************************************************************
  131 + ****************************************************************************/
  132 +/**
  133 + * the chunk stream id used for some under-layer message,
  134 + * for example, the PC(protocol control) message.
  135 + */
  136 +#define RTMP_CID_ProtocolControl 0x02
  137 +/**
  138 + * the AMF0/AMF3 command message, invoke method and return the result, over NetConnection.
  139 + * generally use 0x03.
  140 + */
  141 +#define RTMP_CID_OverConnection 0x03
  142 +/**
  143 + * the AMF0/AMF3 command message, invoke method and return the result, over NetConnection,
  144 + * the midst state(we guess).
  145 + * rarely used, e.g. onStatus(NetStream.Play.Reset).
  146 + */
  147 +#define RTMP_CID_OverConnection2 0x04
  148 +/**
  149 + * the stream message(amf0/amf3), over NetStream.
  150 + * generally use 0x05.
  151 + */
  152 +#define RTMP_CID_OverStream 0x05
  153 +/**
  154 + * the stream message(amf0/amf3), over NetStream, the midst state(we guess).
  155 + * rarely used, e.g. play("mp4:mystram.f4v")
  156 + */
  157 +#define RTMP_CID_OverStream2 0x08
  158 +/**
  159 + * the stream message(video), over NetStream
  160 + * generally use 0x06.
  161 + */
  162 +#define RTMP_CID_Video 0x06
  163 +/**
  164 + * the stream message(audio), over NetStream.
  165 + * generally use 0x07.
  166 + */
  167 +#define RTMP_CID_Audio 0x07
  168 +
  169 +/**
  170 + * 6.1. Chunk Format
  171 + * Extended timestamp: 0 or 4 bytes
  172 + * This field MUST be sent when the normal timsestamp is set to
  173 + * 0xffffff, it MUST NOT be sent if the normal timestamp is set to
  174 + * anything else. So for values less than 0xffffff the normal
  175 + * timestamp field SHOULD be used in which case the extended timestamp
  176 + * MUST NOT be present. For values greater than or equal to 0xffffff
  177 + * the normal timestamp field MUST NOT be used and MUST be set to
  178 + * 0xffffff and the extended timestamp MUST be sent.
  179 + */
  180 +#define RTMP_EXTENDED_TIMESTAMP 0xFFFFFF
  181 +
  182 +/**
  183 + * 4.1. Message Header
  184 + */
  185 +class SrsMessageHeader
  186 +{
  187 +public:
  188 + /**
  189 + * 3bytes.
  190 + * Three-byte field that contains a timestamp delta of the message.
  191 + * @remark, only used for decoding message from chunk stream.
  192 + */
  193 + int32_t timestamp_delta;
  194 + /**
  195 + * 3bytes.
  196 + * Three-byte field that represents the size of the payload in bytes.
  197 + * It is set in big-endian format.
  198 + */
  199 + int32_t payload_length;
  200 + /**
  201 + * 1byte.
  202 + * One byte field to represent the message type. A range of type IDs
  203 + * (1-7) are reserved for protocol control messages.
  204 + */
  205 + int8_t message_type;
  206 + /**
  207 + * 4bytes.
  208 + * Four-byte field that identifies the stream of the message. These
  209 + * bytes are set in little-endian format.
  210 + */
  211 + int32_t stream_id;
  212 +
  213 + /**
  214 + * Four-byte field that contains a timestamp of the message.
  215 + * The 4 bytes are packed in the big-endian order.
  216 + * @remark, used as calc timestamp when decode and encode time.
  217 + * @remark, we use 64bits for large time for jitter detect and hls.
  218 + */
  219 + int64_t timestamp;
  220 +public:
  221 + /**
  222 + * get the perfered cid(chunk stream id) which sendout over.
  223 + * set at decoding, and canbe used for directly send message,
  224 + * for example, dispatch to all connections.
  225 + */
  226 + int perfer_cid;
  227 +public:
  228 + SrsMessageHeader();
  229 + virtual ~SrsMessageHeader();
  230 +public:
  231 + bool is_audio();
  232 + bool is_video();
  233 + bool is_amf0_command();
  234 + bool is_amf0_data();
  235 + bool is_amf3_command();
  236 + bool is_amf3_data();
  237 + bool is_window_ackledgement_size();
  238 + bool is_ackledgement();
  239 + bool is_set_chunk_size();
  240 + bool is_user_control_message();
  241 + bool is_set_peer_bandwidth();
  242 + bool is_aggregate();
  243 +public:
  244 + /**
  245 + * create a amf0 script header, set the size and stream_id.
  246 + */
  247 + void initialize_amf0_script(int size, int stream);
  248 + /**
  249 + * create a audio header, set the size, timestamp and stream_id.
  250 + */
  251 + void initialize_audio(int size, u_int32_t time, int stream);
  252 + /**
  253 + * create a video header, set the size, timestamp and stream_id.
  254 + */
  255 + void initialize_video(int size, u_int32_t time, int stream);
  256 +};
  257 +
  258 +/**
  259 + * message is raw data RTMP message, bytes oriented,
  260 + * protcol always recv RTMP message, and can send RTMP message or RTMP packet.
  261 + * the common message is read from underlay protocol sdk.
  262 + * while the shared ptr message used to copy and send.
  263 + */
  264 +class SrsCommonMessage
  265 +{
  266 + // 4.1. Message Header
  267 +public:
  268 + SrsMessageHeader header;
  269 + // 4.2. Message Payload
  270 +public:
  271 + /**
  272 + * current message parsed size,
  273 + * size <= header.payload_length
  274 + * for the payload maybe sent in multiple chunks.
  275 + */
  276 + int size;
  277 + /**
  278 + * the payload of message, the SrsCommonMessage never know about the detail of payload,
  279 + * user must use SrsProtocol.decode_message to get concrete packet.
  280 + * @remark, not all message payload can be decoded to packet. for example,
  281 + * video/audio packet use raw bytes, no video/audio packet.
  282 + */
  283 + char* payload;
  284 +public:
  285 + SrsCommonMessage();
  286 +public:
  287 + virtual ~SrsCommonMessage();
  288 +};
  289 +
  290 +/**
  291 + * the message header for shared ptr message.
  292 + * only the message for all msgs are same.
  293 + */
  294 +struct SrsSharedMessageHeader
  295 +{
  296 + /**
  297 + * 3bytes.
  298 + * Three-byte field that represents the size of the payload in bytes.
  299 + * It is set in big-endian format.
  300 + */
  301 + int32_t payload_length;
  302 + /**
  303 + * 1byte.
  304 + * One byte field to represent the message type. A range of type IDs
  305 + * (1-7) are reserved for protocol control messages.
  306 + */
  307 + int8_t message_type;
  308 + /**
  309 + * get the perfered cid(chunk stream id) which sendout over.
  310 + * set at decoding, and canbe used for directly send message,
  311 + * for example, dispatch to all connections.
  312 + */
  313 + int perfer_cid;
  314 +};
  315 +
  316 +/**
  317 + * shared ptr message.
  318 + * for audio/video/data message that need less memory copy.
  319 + * and only for output.
  320 + *
  321 + * create first object by constructor and create(),
  322 + * use copy if need reference count message.
  323 + *
  324 + */
  325 +class SrsSharedPtrMessage
  326 +{
  327 + // 4.1. Message Header
  328 +public:
  329 + // the header can shared, only set the timestamp and stream id.
  330 + // @see https://github.com/simple-rtmp-server/srs/issues/251
  331 + //SrsSharedMessageHeader header;
  332 + /**
  333 + * Four-byte field that contains a timestamp of the message.
  334 + * The 4 bytes are packed in the big-endian order.
  335 + * @remark, used as calc timestamp when decode and encode time.
  336 + * @remark, we use 64bits for large time for jitter detect and hls.
  337 + */
  338 + int64_t timestamp;
  339 + /**
  340 + * 4bytes.
  341 + * Four-byte field that identifies the stream of the message. These
  342 + * bytes are set in big-endian format.
  343 + */
  344 + int32_t stream_id;
  345 + // 4.2. Message Payload
  346 +public:
  347 + /**
  348 + * current message parsed size,
  349 + * size <= header.payload_length
  350 + * for the payload maybe sent in multiple chunks.
  351 + */
  352 + int size;
  353 + /**
  354 + * the payload of message, the SrsCommonMessage never know about the detail of payload,
  355 + * user must use SrsProtocol.decode_message to get concrete packet.
  356 + * @remark, not all message payload can be decoded to packet. for example,
  357 + * video/audio packet use raw bytes, no video/audio packet.
  358 + */
  359 + char* payload;
  360 +private:
  361 + class SrsSharedPtrPayload
  362 + {
  363 + public:
  364 + // shared message header.
  365 + // @see https://github.com/simple-rtmp-server/srs/issues/251
  366 + SrsSharedMessageHeader header;
  367 + // actual shared payload.
  368 + char* payload;
  369 + // size of payload.
  370 + int size;
  371 + // the reference count
  372 + int shared_count;
  373 + public:
  374 + SrsSharedPtrPayload();
  375 + virtual ~SrsSharedPtrPayload();
  376 + };
  377 + SrsSharedPtrPayload* ptr;
  378 +public:
  379 + SrsSharedPtrMessage();
  380 + virtual ~SrsSharedPtrMessage();
  381 +public:
  382 + /**
  383 + * create shared ptr message,
  384 + * copy header, manage the payload of msg,
  385 + * set the payload to NULL to prevent double free.
  386 + * @remark payload of msg set to NULL if success.
  387 + */
  388 + virtual int create(SrsCommonMessage* msg);
  389 + /**
  390 + * create shared ptr message,
  391 + * from the header and payload.
  392 + * @remark user should never free the payload.
  393 + * @param pheader, the header to copy to the message. NULL to ignore.
  394 + */
  395 + virtual int create(SrsMessageHeader* pheader, char* payload, int size);
  396 + /**
  397 + * get current reference count.
  398 + * when this object created, count set to 0.
  399 + * if copy() this object, count increase 1.
  400 + * if this or copy deleted, free payload when count is 0, or count--.
  401 + * @remark, assert object is created.
  402 + */
  403 + virtual int count();
  404 + /**
  405 + * check perfer cid and stream id.
  406 + * @return whether stream id already set.
  407 + */
  408 + virtual bool check(int stream_id);
  409 +public:
  410 + virtual bool is_av();
  411 + virtual bool is_audio();
  412 + virtual bool is_video();
  413 +public:
  414 + /**
  415 + * generate the chunk header to cache.
  416 + * @return the size of header.
  417 + */
  418 + virtual int chunk_header(char* cache, int nb_cache, bool c0);
  419 +public:
  420 + /**
  421 + * copy current shared ptr message, use ref-count.
  422 + * @remark, assert object is created.
  423 + */
  424 + virtual SrsSharedPtrMessage* copy();
  425 +};
  426 +
38 /** 427 /**
39 * encode data to flv file. 428 * encode data to flv file.
40 */ 429 */
@@ -44,6 +433,7 @@ private: @@ -44,6 +433,7 @@ private:
44 SrsFileWriter* _fs; 433 SrsFileWriter* _fs;
45 private: 434 private:
46 SrsStream* tag_stream; 435 SrsStream* tag_stream;
  436 + char tag_header[SRS_FLV_TAG_HEADER_SIZE];
47 public: 437 public:
48 SrsFlvEncoder(); 438 SrsFlvEncoder();
49 virtual ~SrsFlvEncoder(); 439 virtual ~SrsFlvEncoder();
@@ -87,7 +477,28 @@ public: @@ -87,7 +477,28 @@ public:
87 * @remark assert data_size is not negative. 477 * @remark assert data_size is not negative.
88 */ 478 */
89 static int size_tag(int data_size); 479 static int size_tag(int data_size);
  480 +#ifdef SRS_PERF_FAST_FLV_ENCODER
  481 +private:
  482 + // cache tag header.
  483 + int nb_tag_headers;
  484 + char* tag_headers;
  485 + // cache pps(previous tag size)
  486 + int nb_ppts;
  487 + char* ppts;
  488 + // cache iovss.
  489 + int nb_iovss_cache;
  490 + iovec* iovss_cache;
  491 +public:
  492 + /**
  493 + * write the tags in a time.
  494 + */
  495 + virtual int write_tags(SrsSharedPtrMessage** msgs, int count);
  496 +#endif
90 private: 497 private:
  498 + virtual int write_metadata_to_cache(char type, char* data, int size, char* cache);
  499 + virtual int write_audio_to_cache(int64_t timestamp, char* data, int size, char* cache);
  500 + virtual int write_video_to_cache(int64_t timestamp, char* data, int size, char* cache);
  501 + virtual int write_pts_to_cache(int size, char* cache);
91 virtual int write_tag(char* header, int header_size, char* tag, int tag_size); 502 virtual int write_tag(char* header, int header_size, char* tag, int tag_size);
92 }; 503 };
93 504
@@ -40,6 +40,7 @@ using namespace std; @@ -40,6 +40,7 @@ using namespace std;
40 #include <srs_kernel_log.hpp> 40 #include <srs_kernel_log.hpp>
41 #include <srs_kernel_error.hpp> 41 #include <srs_kernel_error.hpp>
42 #include <srs_kernel_stream.hpp> 42 #include <srs_kernel_stream.hpp>
  43 +#include <srs_kernel_flv.hpp>
43 44
44 // this value must: 45 // this value must:
45 // equals to (SRS_SYS_CYCLE_INTERVAL*SRS_SYS_TIME_RESOLUTION_MS_TIMES)*1000 46 // equals to (SRS_SYS_CYCLE_INTERVAL*SRS_SYS_TIME_RESOLUTION_MS_TIMES)*1000
@@ -759,3 +760,131 @@ int ff_hex_to_data(u_int8_t* data, const char* p) @@ -759,3 +760,131 @@ int ff_hex_to_data(u_int8_t* data, const char* p)
759 return len; 760 return len;
760 } 761 }
761 762
  763 +int srs_chunk_header_c0(
  764 + int perfer_cid, u_int32_t timestamp, int32_t payload_length,
  765 + int8_t message_type, int32_t stream_id,
  766 + char* cache, int nb_cache
  767 +) {
  768 + // to directly set the field.
  769 + char* pp = NULL;
  770 +
  771 + // generate the header.
  772 + char* p = cache;
  773 +
  774 + // no header.
  775 + if (nb_cache < SRS_CONSTS_RTMP_MAX_FMT0_HEADER_SIZE) {
  776 + return 0;
  777 + }
  778 +
  779 + // write new chunk stream header, fmt is 0
  780 + *p++ = 0x00 | (perfer_cid & 0x3F);
  781 +
  782 + // chunk message header, 11 bytes
  783 + // timestamp, 3bytes, big-endian
  784 + if (timestamp < RTMP_EXTENDED_TIMESTAMP) {
  785 + pp = (char*)&timestamp;
  786 + *p++ = pp[2];
  787 + *p++ = pp[1];
  788 + *p++ = pp[0];
  789 + } else {
  790 + *p++ = 0xFF;
  791 + *p++ = 0xFF;
  792 + *p++ = 0xFF;
  793 + }
  794 +
  795 + // message_length, 3bytes, big-endian
  796 + pp = (char*)&payload_length;
  797 + *p++ = pp[2];
  798 + *p++ = pp[1];
  799 + *p++ = pp[0];
  800 +
  801 + // message_type, 1bytes
  802 + *p++ = message_type;
  803 +
  804 + // stream_id, 4bytes, little-endian
  805 + pp = (char*)&stream_id;
  806 + *p++ = pp[0];
  807 + *p++ = pp[1];
  808 + *p++ = pp[2];
  809 + *p++ = pp[3];
  810 +
  811 + // for c0
  812 + // chunk extended timestamp header, 0 or 4 bytes, big-endian
  813 + //
  814 + // for c3:
  815 + // chunk extended timestamp header, 0 or 4 bytes, big-endian
  816 + // 6.1.3. Extended Timestamp
  817 + // This field is transmitted only when the normal time stamp in the
  818 + // chunk message header is set to 0x00ffffff. If normal time stamp is
  819 + // set to any value less than 0x00ffffff, this field MUST NOT be
  820 + // present. This field MUST NOT be present if the timestamp field is not
  821 + // present. Type 3 chunks MUST NOT have this field.
  822 + // adobe changed for Type3 chunk:
  823 + // FMLE always sendout the extended-timestamp,
  824 + // must send the extended-timestamp to FMS,
  825 + // must send the extended-timestamp to flash-player.
  826 + // @see: ngx_rtmp_prepare_message
  827 + // @see: http://blog.csdn.net/win_lin/article/details/13363699
  828 + // TODO: FIXME: extract to outer.
  829 + if (timestamp >= RTMP_EXTENDED_TIMESTAMP) {
  830 + pp = (char*)&timestamp;
  831 + *p++ = pp[3];
  832 + *p++ = pp[2];
  833 + *p++ = pp[1];
  834 + *p++ = pp[0];
  835 + }
  836 +
  837 + // always has header
  838 + return p - cache;
  839 +}
  840 +
  841 +int srs_chunk_header_c3(
  842 + int perfer_cid, u_int32_t timestamp,
  843 + char* cache, int nb_cache
  844 +) {
  845 + // to directly set the field.
  846 + char* pp = NULL;
  847 +
  848 + // generate the header.
  849 + char* p = cache;
  850 +
  851 + // no header.
  852 + if (nb_cache < SRS_CONSTS_RTMP_MAX_FMT3_HEADER_SIZE) {
  853 + return 0;
  854 + }
  855 +
  856 + // write no message header chunk stream, fmt is 3
  857 + // @remark, if perfer_cid > 0x3F, that is, use 2B/3B chunk header,
  858 + // SRS will rollback to 1B chunk header.
  859 + *p++ = 0xC0 | (perfer_cid & 0x3F);
  860 +
  861 + // for c0
  862 + // chunk extended timestamp header, 0 or 4 bytes, big-endian
  863 + //
  864 + // for c3:
  865 + // chunk extended timestamp header, 0 or 4 bytes, big-endian
  866 + // 6.1.3. Extended Timestamp
  867 + // This field is transmitted only when the normal time stamp in the
  868 + // chunk message header is set to 0x00ffffff. If normal time stamp is
  869 + // set to any value less than 0x00ffffff, this field MUST NOT be
  870 + // present. This field MUST NOT be present if the timestamp field is not
  871 + // present. Type 3 chunks MUST NOT have this field.
  872 + // adobe changed for Type3 chunk:
  873 + // FMLE always sendout the extended-timestamp,
  874 + // must send the extended-timestamp to FMS,
  875 + // must send the extended-timestamp to flash-player.
  876 + // @see: ngx_rtmp_prepare_message
  877 + // @see: http://blog.csdn.net/win_lin/article/details/13363699
  878 + // TODO: FIXME: extract to outer.
  879 + if (timestamp >= RTMP_EXTENDED_TIMESTAMP) {
  880 + pp = (char*)&timestamp;
  881 + *p++ = pp[3];
  882 + *p++ = pp[2];
  883 + *p++ = pp[1];
  884 + *p++ = pp[0];
  885 + }
  886 +
  887 + // always has header
  888 + return p - cache;
  889 +}
  890 +
@@ -138,5 +138,28 @@ extern char* srs_av_base64_encode(char* out, int out_size, const u_int8_t* in, i @@ -138,5 +138,28 @@ extern char* srs_av_base64_encode(char* out, int out_size, const u_int8_t* in, i
138 */ 138 */
139 extern int ff_hex_to_data(u_int8_t* data, const char* p); 139 extern int ff_hex_to_data(u_int8_t* data, const char* p);
140 140
  141 +/**
  142 + * generate the c0 chunk header for msg.
  143 + * @param cache, the cache to write header.
  144 + * @param nb_cache, the size of cache.
  145 + * @return the size of header. 0 if cache not enough.
  146 + */
  147 +extern int srs_chunk_header_c0(
  148 + int perfer_cid, u_int32_t timestamp, int32_t payload_length,
  149 + int8_t message_type, int32_t stream_id,
  150 + char* cache, int nb_cache
  151 + );
  152 +
  153 +/**
  154 + * generate the c3 chunk header for msg.
  155 + * @param cache, the cache to write header.
  156 + * @param nb_cache, the size of cache.
  157 + * @return the size of header. 0 if cache not enough.
  158 + */
  159 +extern int srs_chunk_header_c3(
  160 + int perfer_cid, u_int32_t timestamp,
  161 + char* cache, int nb_cache
  162 + );
  163 +
141 #endif 164 #endif
142 165
@@ -33,6 +33,11 @@ @@ -33,6 +33,11 @@
33 #include <string> 33 #include <string>
34 #include <vector> 34 #include <vector>
35 35
  36 +// for srs-librtmp, @see https://github.com/simple-rtmp-server/srs/issues/213
  37 +#ifndef _WIN32
  38 +#include <sys/uio.h>
  39 +#endif
  40 +
36 class SrsFileReader; 41 class SrsFileReader;
37 class SrsHttpHeader; 42 class SrsHttpHeader;
38 class ISrsHttpMessage; 43 class ISrsHttpMessage;
@@ -188,6 +193,11 @@ public: @@ -188,6 +193,11 @@ public:
188 // the initial 512 bytes of written data to DetectContentType. 193 // the initial 512 bytes of written data to DetectContentType.
189 // @param data, the data to send. NULL to flush header only. 194 // @param data, the data to send. NULL to flush header only.
190 virtual int write(char* data, int size) = 0; 195 virtual int write(char* data, int size) = 0;
  196 + /**
  197 + * for the HTTP FLV, to writev to improve performance.
  198 + * @see https://github.com/simple-rtmp-server/srs/issues/405
  199 + */
  200 + virtual int writev(iovec* iov, int iovcnt, ssize_t* pnwrite) = 0;
191 201
192 // WriteHeader sends an HTTP response header with status code. 202 // WriteHeader sends an HTTP response header with status code.
193 // If WriteHeader is not called explicitly, the first call to Write 203 // If WriteHeader is not called explicitly, the first call to Write
@@ -120,318 +120,6 @@ using namespace std; @@ -120,318 +120,6 @@ using namespace std;
120 /**************************************************************************** 120 /****************************************************************************
121 ***************************************************************************** 121 *****************************************************************************
122 ****************************************************************************/ 122 ****************************************************************************/
123 -/**  
124 -* the chunk stream id used for some under-layer message,  
125 -* for example, the PC(protocol control) message.  
126 -*/  
127 -#define RTMP_CID_ProtocolControl 0x02  
128 -/**  
129 -* the AMF0/AMF3 command message, invoke method and return the result, over NetConnection.  
130 -* generally use 0x03.  
131 -*/  
132 -#define RTMP_CID_OverConnection 0x03  
133 -/**  
134 -* the AMF0/AMF3 command message, invoke method and return the result, over NetConnection,  
135 -* the midst state(we guess).  
136 -* rarely used, e.g. onStatus(NetStream.Play.Reset).  
137 -*/  
138 -#define RTMP_CID_OverConnection2 0x04  
139 -/**  
140 -* the stream message(amf0/amf3), over NetStream.  
141 -* generally use 0x05.  
142 -*/  
143 -#define RTMP_CID_OverStream 0x05  
144 -/**  
145 -* the stream message(amf0/amf3), over NetStream, the midst state(we guess).  
146 -* rarely used, e.g. play("mp4:mystram.f4v")  
147 -*/  
148 -#define RTMP_CID_OverStream2 0x08  
149 -/**  
150 -* the stream message(video), over NetStream  
151 -* generally use 0x06.  
152 -*/  
153 -#define RTMP_CID_Video 0x06  
154 -/**  
155 -* the stream message(audio), over NetStream.  
156 -* generally use 0x07.  
157 -*/  
158 -#define RTMP_CID_Audio 0x07  
159 -  
160 -/****************************************************************************  
161 -*****************************************************************************  
162 -****************************************************************************/  
163 -  
164 -SrsMessageHeader::SrsMessageHeader()  
165 -{  
166 - message_type = 0;  
167 - payload_length = 0;  
168 - timestamp_delta = 0;  
169 - stream_id = 0;  
170 -  
171 - timestamp = 0;  
172 - // we always use the connection chunk-id  
173 - perfer_cid = RTMP_CID_OverConnection;  
174 -}  
175 -  
176 -SrsMessageHeader::~SrsMessageHeader()  
177 -{  
178 -}  
179 -  
180 -bool SrsMessageHeader::is_audio()  
181 -{  
182 - return message_type == RTMP_MSG_AudioMessage;  
183 -}  
184 -  
185 -bool SrsMessageHeader::is_video()  
186 -{  
187 - return message_type == RTMP_MSG_VideoMessage;  
188 -}  
189 -  
190 -bool SrsMessageHeader::is_amf0_command()  
191 -{  
192 - return message_type == RTMP_MSG_AMF0CommandMessage;  
193 -}  
194 -  
195 -bool SrsMessageHeader::is_amf0_data()  
196 -{  
197 - return message_type == RTMP_MSG_AMF0DataMessage;  
198 -}  
199 -  
200 -bool SrsMessageHeader::is_amf3_command()  
201 -{  
202 - return message_type == RTMP_MSG_AMF3CommandMessage;  
203 -}  
204 -  
205 -bool SrsMessageHeader::is_amf3_data()  
206 -{  
207 - return message_type == RTMP_MSG_AMF3DataMessage;  
208 -}  
209 -  
210 -bool SrsMessageHeader::is_window_ackledgement_size()  
211 -{  
212 - return message_type == RTMP_MSG_WindowAcknowledgementSize;  
213 -}  
214 -  
215 -bool SrsMessageHeader::is_ackledgement()  
216 -{  
217 - return message_type == RTMP_MSG_Acknowledgement;  
218 -}  
219 -  
220 -bool SrsMessageHeader::is_set_chunk_size()  
221 -{  
222 - return message_type == RTMP_MSG_SetChunkSize;  
223 -}  
224 -  
225 -bool SrsMessageHeader::is_user_control_message()  
226 -{  
227 - return message_type == RTMP_MSG_UserControlMessage;  
228 -}  
229 -  
230 -bool SrsMessageHeader::is_set_peer_bandwidth()  
231 -{  
232 - return message_type == RTMP_MSG_SetPeerBandwidth;  
233 -}  
234 -  
235 -bool SrsMessageHeader::is_aggregate()  
236 -{  
237 - return message_type == RTMP_MSG_AggregateMessage;  
238 -}  
239 -  
240 -void SrsMessageHeader::initialize_amf0_script(int size, int stream)  
241 -{  
242 - message_type = RTMP_MSG_AMF0DataMessage;  
243 - payload_length = (int32_t)size;  
244 - timestamp_delta = (int32_t)0;  
245 - timestamp = (int64_t)0;  
246 - stream_id = (int32_t)stream;  
247 -  
248 - // amf0 script use connection2 chunk-id  
249 - perfer_cid = RTMP_CID_OverConnection2;  
250 -}  
251 -  
252 -void SrsMessageHeader::initialize_audio(int size, u_int32_t time, int stream)  
253 -{  
254 - message_type = RTMP_MSG_AudioMessage;  
255 - payload_length = (int32_t)size;  
256 - timestamp_delta = (int32_t)time;  
257 - timestamp = (int64_t)time;  
258 - stream_id = (int32_t)stream;  
259 -  
260 - // audio chunk-id  
261 - perfer_cid = RTMP_CID_Audio;  
262 -}  
263 -  
264 -void SrsMessageHeader::initialize_video(int size, u_int32_t time, int stream)  
265 -{  
266 - message_type = RTMP_MSG_VideoMessage;  
267 - payload_length = (int32_t)size;  
268 - timestamp_delta = (int32_t)time;  
269 - timestamp = (int64_t)time;  
270 - stream_id = (int32_t)stream;  
271 -  
272 - // video chunk-id  
273 - perfer_cid = RTMP_CID_Video;  
274 -}  
275 -  
276 -SrsCommonMessage::SrsCommonMessage()  
277 -{  
278 - payload = NULL;  
279 - size = 0;  
280 -}  
281 -  
282 -SrsCommonMessage::~SrsCommonMessage()  
283 -{  
284 - srs_freep(payload);  
285 -}  
286 -  
287 -SrsSharedPtrMessage::SrsSharedPtrPayload::SrsSharedPtrPayload()  
288 -{  
289 - payload = NULL;  
290 - size = 0;  
291 - shared_count = 0;  
292 -}  
293 -  
294 -SrsSharedPtrMessage::SrsSharedPtrPayload::~SrsSharedPtrPayload()  
295 -{  
296 - srs_freep(payload);  
297 -}  
298 -  
299 -SrsSharedPtrMessage::SrsSharedPtrMessage()  
300 -{  
301 - ptr = NULL;  
302 -}  
303 -  
304 -SrsSharedPtrMessage::~SrsSharedPtrMessage()  
305 -{  
306 - if (ptr) {  
307 - if (ptr->shared_count == 0) {  
308 - srs_freep(ptr);  
309 - } else {  
310 - ptr->shared_count--;  
311 - }  
312 - }  
313 -}  
314 -  
315 -int SrsSharedPtrMessage::create(SrsCommonMessage* msg)  
316 -{  
317 - int ret = ERROR_SUCCESS;  
318 -  
319 - if ((ret = create(&msg->header, msg->payload, msg->size)) != ERROR_SUCCESS) {  
320 - return ret;  
321 - }  
322 -  
323 - // to prevent double free of payload:  
324 - // initialize already attach the payload of msg,  
325 - // detach the payload to transfer the owner to shared ptr.  
326 - msg->payload = NULL;  
327 - msg->size = 0;  
328 -  
329 - return ret;  
330 -}  
331 -  
332 -int SrsSharedPtrMessage::create(SrsMessageHeader* pheader, char* payload, int size)  
333 -{  
334 - int ret = ERROR_SUCCESS;  
335 -  
336 - if (ptr) {  
337 - ret = ERROR_SYSTEM_ASSERT_FAILED;  
338 - srs_error("should not set the payload twice. ret=%d", ret);  
339 - srs_assert(false);  
340 -  
341 - return ret;  
342 - }  
343 -  
344 - ptr = new SrsSharedPtrPayload();  
345 -  
346 - // direct attach the data.  
347 - if (pheader) {  
348 - ptr->header.message_type = pheader->message_type;  
349 - ptr->header.payload_length = size;  
350 - ptr->header.perfer_cid = pheader->perfer_cid;  
351 - this->timestamp = pheader->timestamp;  
352 - this->stream_id = pheader->stream_id;  
353 - }  
354 - ptr->payload = payload;  
355 - ptr->size = size;  
356 -  
357 - // message can access it.  
358 - this->payload = ptr->payload;  
359 - this->size = ptr->size;  
360 -  
361 - return ret;  
362 -}  
363 -  
364 -int SrsSharedPtrMessage::count()  
365 -{  
366 - srs_assert(ptr);  
367 - return ptr->shared_count;  
368 -}  
369 -  
370 -bool SrsSharedPtrMessage::check(int stream_id)  
371 -{  
372 - // we donot use the complex basic header,  
373 - // ensure the basic header is 1bytes.  
374 - if (ptr->header.perfer_cid < 2) {  
375 - srs_info("change the chunk_id=%d to default=%d",  
376 - ptr->header.perfer_cid, RTMP_CID_ProtocolControl);  
377 - ptr->header.perfer_cid = RTMP_CID_ProtocolControl;  
378 - }  
379 -  
380 - // we assume that the stream_id in a group must be the same.  
381 - if (this->stream_id == stream_id) {  
382 - return true;  
383 - }  
384 - this->stream_id = stream_id;  
385 -  
386 - return false;  
387 -}  
388 -  
389 -bool SrsSharedPtrMessage::is_av()  
390 -{  
391 - return ptr->header.message_type == RTMP_MSG_AudioMessage  
392 - || ptr->header.message_type == RTMP_MSG_VideoMessage;  
393 -}  
394 -  
395 -bool SrsSharedPtrMessage::is_audio()  
396 -{  
397 - return ptr->header.message_type == RTMP_MSG_AudioMessage;  
398 -}  
399 -  
400 -bool SrsSharedPtrMessage::is_video()  
401 -{  
402 - return ptr->header.message_type == RTMP_MSG_VideoMessage;  
403 -}  
404 -  
405 -int SrsSharedPtrMessage::chunk_header(char* cache, int nb_cache, bool c0)  
406 -{  
407 - if (c0) {  
408 - return srs_chunk_header_c0(  
409 - ptr->header.perfer_cid, timestamp, ptr->header.payload_length,  
410 - ptr->header.message_type, stream_id,  
411 - cache, nb_cache);  
412 - } else {  
413 - return srs_chunk_header_c3(  
414 - ptr->header.perfer_cid, timestamp,  
415 - cache, nb_cache);  
416 - }  
417 -}  
418 -  
419 -SrsSharedPtrMessage* SrsSharedPtrMessage::copy()  
420 -{  
421 - srs_assert(ptr);  
422 -  
423 - SrsSharedPtrMessage* copy = new SrsSharedPtrMessage();  
424 -  
425 - copy->ptr = ptr;  
426 - ptr->shared_count++;  
427 -  
428 - copy->timestamp = timestamp;  
429 - copy->stream_id = stream_id;  
430 - copy->payload = ptr->payload;  
431 - copy->size = ptr->size;  
432 -  
433 - return copy;  
434 -}  
435 123
436 SrsPacket::SrsPacket() 124 SrsPacket::SrsPacket()
437 { 125 {
@@ -904,41 +592,7 @@ int SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msgs) @@ -904,41 +592,7 @@ int SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msgs)
904 592
905 int SrsProtocol::do_iovs_send(iovec* iovs, int size) 593 int SrsProtocol::do_iovs_send(iovec* iovs, int size)
906 { 594 {
907 - int ret = ERROR_SUCCESS;  
908 -  
909 - // the limits of writev iovs.  
910 - // for srs-librtmp, @see https://github.com/simple-rtmp-server/srs/issues/213  
911 -#ifndef _WIN32  
912 - static int limits = sysconf(_SC_IOV_MAX);  
913 -#else  
914 - static int limits = 1024;  
915 -#endif  
916 -  
917 - // send in a time.  
918 - if (size < limits) {  
919 - if ((ret = skt->writev(iovs, size, NULL)) != ERROR_SUCCESS) {  
920 - if (!srs_is_client_gracefully_close(ret)) {  
921 - srs_error("send with writev failed. ret=%d", ret);  
922 - }  
923 - return ret;  
924 - }  
925 - return ret;  
926 - }  
927 -  
928 - // send in multiple times.  
929 - int cur_iov = 0;  
930 - while (cur_iov < size) {  
931 - int cur_count = srs_min(limits, size - cur_iov);  
932 - if ((ret = skt->writev(iovs + cur_iov, cur_count, NULL)) != ERROR_SUCCESS) {  
933 - if (!srs_is_client_gracefully_close(ret)) {  
934 - srs_error("send with writev failed. ret=%d", ret);  
935 - }  
936 - return ret;  
937 - }  
938 - cur_iov += cur_count;  
939 - }  
940 -  
941 - return ret; 595 + return srs_write_large_iovs(skt, iovs, size);
942 } 596 }
943 597
944 int SrsProtocol::do_send_and_free_packet(SrsPacket* packet, int stream_id) 598 int SrsProtocol::do_send_and_free_packet(SrsPacket* packet, int stream_id)
@@ -43,6 +43,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -43,6 +43,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
43 #include <srs_kernel_error.hpp> 43 #include <srs_kernel_error.hpp>
44 #include <srs_kernel_consts.hpp> 44 #include <srs_kernel_consts.hpp>
45 #include <srs_core_performance.hpp> 45 #include <srs_core_performance.hpp>
  46 +#include <srs_kernel_flv.hpp>
46 47
47 class ISrsProtocolReaderWriter; 48 class ISrsProtocolReaderWriter;
48 class SrsFastBuffer; 49 class SrsFastBuffer;
@@ -60,89 +61,6 @@ class IMergeReadHandler; @@ -60,89 +61,6 @@ class IMergeReadHandler;
60 ***************************************************************************** 61 *****************************************************************************
61 ****************************************************************************/ 62 ****************************************************************************/
62 /** 63 /**
63 - 5. Protocol Control Messages  
64 - RTMP reserves message type IDs 1-7 for protocol control messages.  
65 - These messages contain information needed by the RTM Chunk Stream  
66 - protocol or RTMP itself. Protocol messages with IDs 1 & 2 are  
67 - reserved for usage with RTM Chunk Stream protocol. Protocol messages  
68 - with IDs 3-6 are reserved for usage of RTMP. Protocol message with ID  
69 - 7 is used between edge server and origin server.  
70 - */  
71 -#define RTMP_MSG_SetChunkSize 0x01  
72 -#define RTMP_MSG_AbortMessage 0x02  
73 -#define RTMP_MSG_Acknowledgement 0x03  
74 -#define RTMP_MSG_UserControlMessage 0x04  
75 -#define RTMP_MSG_WindowAcknowledgementSize 0x05  
76 -#define RTMP_MSG_SetPeerBandwidth 0x06  
77 -#define RTMP_MSG_EdgeAndOriginServerCommand 0x07  
78 -/**  
79 - 3. Types of messages  
80 - The server and the client send messages over the network to  
81 - communicate with each other. The messages can be of any type which  
82 - includes audio messages, video messages, command messages, shared  
83 - object messages, data messages, and user control messages.  
84 - 3.1. Command message  
85 - Command messages carry the AMF-encoded commands between the client  
86 - and the server. These messages have been assigned message type value  
87 - of 20 for AMF0 encoding and message type value of 17 for AMF3  
88 - encoding. These messages are sent to perform some operations like  
89 - connect, createStream, publish, play, pause on the peer. Command  
90 - messages like onstatus, result etc. are used to inform the sender  
91 - about the status of the requested commands. A command message  
92 - consists of command name, transaction ID, and command object that  
93 - contains related parameters. A client or a server can request Remote  
94 - Procedure Calls (RPC) over streams that are communicated using the  
95 - command messages to the peer.  
96 - */  
97 -#define RTMP_MSG_AMF3CommandMessage 17 // 0x11  
98 -#define RTMP_MSG_AMF0CommandMessage 20 // 0x14  
99 -/**  
100 - 3.2. Data message  
101 - The client or the server sends this message to send Metadata or any  
102 - user data to the peer. Metadata includes details about the  
103 - data(audio, video etc.) like creation time, duration, theme and so  
104 - on. These messages have been assigned message type value of 18 for  
105 - AMF0 and message type value of 15 for AMF3.  
106 - */  
107 -#define RTMP_MSG_AMF0DataMessage 18 // 0x12  
108 -#define RTMP_MSG_AMF3DataMessage 15 // 0x0F  
109 -/**  
110 - 3.3. Shared object message  
111 - A shared object is a Flash object (a collection of name value pairs)  
112 - that are in synchronization across multiple clients, instances, and  
113 - so on. The message types kMsgContainer=19 for AMF0 and  
114 - kMsgContainerEx=16 for AMF3 are reserved for shared object events.  
115 - Each message can contain multiple events.  
116 - */  
117 -#define RTMP_MSG_AMF3SharedObject 16 // 0x10  
118 -#define RTMP_MSG_AMF0SharedObject 19 // 0x13  
119 -/**  
120 - 3.4. Audio message  
121 - The client or the server sends this message to send audio data to the  
122 - peer. The message type value of 8 is reserved for audio messages.  
123 - */  
124 -#define RTMP_MSG_AudioMessage 8 // 0x08  
125 -/* *  
126 - 3.5. Video message  
127 - The client or the server sends this message to send video data to the  
128 - peer. The message type value of 9 is reserved for video messages.  
129 - These messages are large and can delay the sending of other type of  
130 - messages. To avoid such a situation, the video message is assigned  
131 - the lowest priority.  
132 - */  
133 -#define RTMP_MSG_VideoMessage 9 // 0x09  
134 -/**  
135 - 3.6. Aggregate message  
136 - An aggregate message is a single message that contains a list of submessages.  
137 - The message type value of 22 is reserved for aggregate  
138 - messages.  
139 - */  
140 -#define RTMP_MSG_AggregateMessage 22 // 0x16  
141 -  
142 -/****************************************************************************  
143 - *****************************************************************************  
144 - ****************************************************************************/  
145 -/**  
146 * amf0 command message, command name macros 64 * amf0 command message, command name macros
147 */ 65 */
148 #define RTMP_AMF0_COMMAND_CONNECT "connect" 66 #define RTMP_AMF0_COMMAND_CONNECT "connect"
@@ -163,263 +81,6 @@ class IMergeReadHandler; @@ -163,263 +81,6 @@ class IMergeReadHandler;
163 /**************************************************************************** 81 /****************************************************************************
164 ***************************************************************************** 82 *****************************************************************************
165 ****************************************************************************/ 83 ****************************************************************************/
166 -/**  
167 -* 6.1. Chunk Format  
168 -* Extended timestamp: 0 or 4 bytes  
169 -* This field MUST be sent when the normal timsestamp is set to  
170 -* 0xffffff, it MUST NOT be sent if the normal timestamp is set to  
171 -* anything else. So for values less than 0xffffff the normal  
172 -* timestamp field SHOULD be used in which case the extended timestamp  
173 -* MUST NOT be present. For values greater than or equal to 0xffffff  
174 -* the normal timestamp field MUST NOT be used and MUST be set to  
175 -* 0xffffff and the extended timestamp MUST be sent.  
176 -*/  
177 -#define RTMP_EXTENDED_TIMESTAMP 0xFFFFFF  
178 -  
179 -/**  
180 -* 4.1. Message Header  
181 -*/  
182 -class SrsMessageHeader  
183 -{  
184 -public:  
185 - /**  
186 - * 3bytes.  
187 - * Three-byte field that contains a timestamp delta of the message.  
188 - * @remark, only used for decoding message from chunk stream.  
189 - */  
190 - int32_t timestamp_delta;  
191 - /**  
192 - * 3bytes.  
193 - * Three-byte field that represents the size of the payload in bytes.  
194 - * It is set in big-endian format.  
195 - */  
196 - int32_t payload_length;  
197 - /**  
198 - * 1byte.  
199 - * One byte field to represent the message type. A range of type IDs  
200 - * (1-7) are reserved for protocol control messages.  
201 - */  
202 - int8_t message_type;  
203 - /**  
204 - * 4bytes.  
205 - * Four-byte field that identifies the stream of the message. These  
206 - * bytes are set in little-endian format.  
207 - */  
208 - int32_t stream_id;  
209 -  
210 - /**  
211 - * Four-byte field that contains a timestamp of the message.  
212 - * The 4 bytes are packed in the big-endian order.  
213 - * @remark, used as calc timestamp when decode and encode time.  
214 - * @remark, we use 64bits for large time for jitter detect and hls.  
215 - */  
216 - int64_t timestamp;  
217 -public:  
218 - /**  
219 - * get the perfered cid(chunk stream id) which sendout over.  
220 - * set at decoding, and canbe used for directly send message,  
221 - * for example, dispatch to all connections.  
222 - */  
223 - int perfer_cid;  
224 -public:  
225 - SrsMessageHeader();  
226 - virtual ~SrsMessageHeader();  
227 -public:  
228 - bool is_audio();  
229 - bool is_video();  
230 - bool is_amf0_command();  
231 - bool is_amf0_data();  
232 - bool is_amf3_command();  
233 - bool is_amf3_data();  
234 - bool is_window_ackledgement_size();  
235 - bool is_ackledgement();  
236 - bool is_set_chunk_size();  
237 - bool is_user_control_message();  
238 - bool is_set_peer_bandwidth();  
239 - bool is_aggregate();  
240 -public:  
241 - /**  
242 - * create a amf0 script header, set the size and stream_id.  
243 - */  
244 - void initialize_amf0_script(int size, int stream);  
245 - /**  
246 - * create a audio header, set the size, timestamp and stream_id.  
247 - */  
248 - void initialize_audio(int size, u_int32_t time, int stream);  
249 - /**  
250 - * create a video header, set the size, timestamp and stream_id.  
251 - */  
252 - void initialize_video(int size, u_int32_t time, int stream);  
253 -};  
254 -  
255 -/**  
256 -* message is raw data RTMP message, bytes oriented,  
257 -* protcol always recv RTMP message, and can send RTMP message or RTMP packet.  
258 -* the common message is read from underlay protocol sdk.  
259 -* while the shared ptr message used to copy and send.  
260 -*/  
261 -class SrsCommonMessage  
262 -{  
263 -// 4.1. Message Header  
264 -public:  
265 - SrsMessageHeader header;  
266 -// 4.2. Message Payload  
267 -public:  
268 - /**  
269 - * current message parsed size,  
270 - * size <= header.payload_length  
271 - * for the payload maybe sent in multiple chunks.  
272 - */  
273 - int size;  
274 - /**  
275 - * the payload of message, the SrsCommonMessage never know about the detail of payload,  
276 - * user must use SrsProtocol.decode_message to get concrete packet.  
277 - * @remark, not all message payload can be decoded to packet. for example,  
278 - * video/audio packet use raw bytes, no video/audio packet.  
279 - */  
280 - char* payload;  
281 -public:  
282 - SrsCommonMessage();  
283 -public:  
284 - virtual ~SrsCommonMessage();  
285 -};  
286 -  
287 -/**  
288 -* the message header for shared ptr message.  
289 -* only the message for all msgs are same.  
290 -*/  
291 -struct SrsSharedMessageHeader  
292 -{  
293 - /**  
294 - * 3bytes.  
295 - * Three-byte field that represents the size of the payload in bytes.  
296 - * It is set in big-endian format.  
297 - */  
298 - int32_t payload_length;  
299 - /**  
300 - * 1byte.  
301 - * One byte field to represent the message type. A range of type IDs  
302 - * (1-7) are reserved for protocol control messages.  
303 - */  
304 - int8_t message_type;  
305 - /**  
306 - * get the perfered cid(chunk stream id) which sendout over.  
307 - * set at decoding, and canbe used for directly send message,  
308 - * for example, dispatch to all connections.  
309 - */  
310 - int perfer_cid;  
311 -};  
312 -  
313 -/**  
314 -* shared ptr message.  
315 -* for audio/video/data message that need less memory copy.  
316 -* and only for output.  
317 -*  
318 -* create first object by constructor and create(),  
319 -* use copy if need reference count message.  
320 -*  
321 -*/  
322 -class SrsSharedPtrMessage  
323 -{  
324 -// 4.1. Message Header  
325 -public:  
326 - // the header can shared, only set the timestamp and stream id.  
327 - // @see https://github.com/simple-rtmp-server/srs/issues/251  
328 - //SrsSharedMessageHeader header;  
329 - /**  
330 - * Four-byte field that contains a timestamp of the message.  
331 - * The 4 bytes are packed in the big-endian order.  
332 - * @remark, used as calc timestamp when decode and encode time.  
333 - * @remark, we use 64bits for large time for jitter detect and hls.  
334 - */  
335 - int64_t timestamp;  
336 - /**  
337 - * 4bytes.  
338 - * Four-byte field that identifies the stream of the message. These  
339 - * bytes are set in big-endian format.  
340 - */  
341 - int32_t stream_id;  
342 -// 4.2. Message Payload  
343 -public:  
344 - /**  
345 - * current message parsed size,  
346 - * size <= header.payload_length  
347 - * for the payload maybe sent in multiple chunks.  
348 - */  
349 - int size;  
350 - /**  
351 - * the payload of message, the SrsCommonMessage never know about the detail of payload,  
352 - * user must use SrsProtocol.decode_message to get concrete packet.  
353 - * @remark, not all message payload can be decoded to packet. for example,  
354 - * video/audio packet use raw bytes, no video/audio packet.  
355 - */  
356 - char* payload;  
357 -private:  
358 - class SrsSharedPtrPayload  
359 - {  
360 - public:  
361 - // shared message header.  
362 - // @see https://github.com/simple-rtmp-server/srs/issues/251  
363 - SrsSharedMessageHeader header;  
364 - // actual shared payload.  
365 - char* payload;  
366 - // size of payload.  
367 - int size;  
368 - // the reference count  
369 - int shared_count;  
370 - public:  
371 - SrsSharedPtrPayload();  
372 - virtual ~SrsSharedPtrPayload();  
373 - };  
374 - SrsSharedPtrPayload* ptr;  
375 -public:  
376 - SrsSharedPtrMessage();  
377 - virtual ~SrsSharedPtrMessage();  
378 -public:  
379 - /**  
380 - * create shared ptr message,  
381 - * copy header, manage the payload of msg,  
382 - * set the payload to NULL to prevent double free.  
383 - * @remark payload of msg set to NULL if success.  
384 - */  
385 - virtual int create(SrsCommonMessage* msg);  
386 - /**  
387 - * create shared ptr message,  
388 - * from the header and payload.  
389 - * @remark user should never free the payload.  
390 - * @param pheader, the header to copy to the message. NULL to ignore.  
391 - */  
392 - virtual int create(SrsMessageHeader* pheader, char* payload, int size);  
393 - /**  
394 - * get current reference count.  
395 - * when this object created, count set to 0.  
396 - * if copy() this object, count increase 1.  
397 - * if this or copy deleted, free payload when count is 0, or count--.  
398 - * @remark, assert object is created.  
399 - */  
400 - virtual int count();  
401 - /**  
402 - * check perfer cid and stream id.  
403 - * @return whether stream id already set.  
404 - */  
405 - virtual bool check(int stream_id);  
406 -public:  
407 - virtual bool is_av();  
408 - virtual bool is_audio();  
409 - virtual bool is_video();  
410 -public:  
411 - /**  
412 - * generate the chunk header to cache.  
413 - * @return the size of header.  
414 - */  
415 - virtual int chunk_header(char* cache, int nb_cache, bool c0);  
416 -public:  
417 - /**  
418 - * copy current shared ptr message, use ref-count.  
419 - * @remark, assert object is created.  
420 - */  
421 - virtual SrsSharedPtrMessage* copy();  
422 -};  
423 84
424 /** 85 /**
425 * the decoded message payload. 86 * the decoded message payload.
@@ -23,6 +23,11 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -23,6 +23,11 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 23
24 #include <srs_rtmp_utility.hpp> 24 #include <srs_rtmp_utility.hpp>
25 25
  26 +// for srs-librtmp, @see https://github.com/simple-rtmp-server/srs/issues/213
  27 +#ifndef _WIN32
  28 +#include <unistd.h>
  29 +#endif
  30 +
26 #include <stdlib.h> 31 #include <stdlib.h>
27 using namespace std; 32 using namespace std;
28 33
@@ -32,6 +37,8 @@ using namespace std; @@ -32,6 +37,8 @@ using namespace std;
32 #include <srs_rtmp_stack.hpp> 37 #include <srs_rtmp_stack.hpp>
33 #include <srs_kernel_codec.hpp> 38 #include <srs_kernel_codec.hpp>
34 #include <srs_kernel_consts.hpp> 39 #include <srs_kernel_consts.hpp>
  40 +#include <srs_rtmp_stack.hpp>
  41 +#include <srs_rtmp_io.hpp>
35 42
36 void srs_discovery_tc_url( 43 void srs_discovery_tc_url(
37 string tcUrl, 44 string tcUrl,
@@ -159,136 +166,6 @@ bool srs_bytes_equals(void* pa, void* pb, int size) @@ -159,136 +166,6 @@ bool srs_bytes_equals(void* pa, void* pb, int size)
159 return true; 166 return true;
160 } 167 }
161 168
162 -int srs_chunk_header_c0(  
163 - int perfer_cid, u_int32_t timestamp, int32_t payload_length,  
164 - int8_t message_type, int32_t stream_id,  
165 - char* cache, int nb_cache  
166 -)  
167 -{  
168 - // to directly set the field.  
169 - char* pp = NULL;  
170 -  
171 - // generate the header.  
172 - char* p = cache;  
173 -  
174 - // no header.  
175 - if (nb_cache < SRS_CONSTS_RTMP_MAX_FMT0_HEADER_SIZE) {  
176 - return 0;  
177 - }  
178 -  
179 - // write new chunk stream header, fmt is 0  
180 - *p++ = 0x00 | (perfer_cid & 0x3F);  
181 -  
182 - // chunk message header, 11 bytes  
183 - // timestamp, 3bytes, big-endian  
184 - if (timestamp < RTMP_EXTENDED_TIMESTAMP) {  
185 - pp = (char*)&timestamp;  
186 - *p++ = pp[2];  
187 - *p++ = pp[1];  
188 - *p++ = pp[0];  
189 - } else {  
190 - *p++ = 0xFF;  
191 - *p++ = 0xFF;  
192 - *p++ = 0xFF;  
193 - }  
194 -  
195 - // message_length, 3bytes, big-endian  
196 - pp = (char*)&payload_length;  
197 - *p++ = pp[2];  
198 - *p++ = pp[1];  
199 - *p++ = pp[0];  
200 -  
201 - // message_type, 1bytes  
202 - *p++ = message_type;  
203 -  
204 - // stream_id, 4bytes, little-endian  
205 - pp = (char*)&stream_id;  
206 - *p++ = pp[0];  
207 - *p++ = pp[1];  
208 - *p++ = pp[2];  
209 - *p++ = pp[3];  
210 -  
211 - // for c0  
212 - // chunk extended timestamp header, 0 or 4 bytes, big-endian  
213 - //  
214 - // for c3:  
215 - // chunk extended timestamp header, 0 or 4 bytes, big-endian  
216 - // 6.1.3. Extended Timestamp  
217 - // This field is transmitted only when the normal time stamp in the  
218 - // chunk message header is set to 0x00ffffff. If normal time stamp is  
219 - // set to any value less than 0x00ffffff, this field MUST NOT be  
220 - // present. This field MUST NOT be present if the timestamp field is not  
221 - // present. Type 3 chunks MUST NOT have this field.  
222 - // adobe changed for Type3 chunk:  
223 - // FMLE always sendout the extended-timestamp,  
224 - // must send the extended-timestamp to FMS,  
225 - // must send the extended-timestamp to flash-player.  
226 - // @see: ngx_rtmp_prepare_message  
227 - // @see: http://blog.csdn.net/win_lin/article/details/13363699  
228 - // TODO: FIXME: extract to outer.  
229 - if (timestamp >= RTMP_EXTENDED_TIMESTAMP) {  
230 - pp = (char*)&timestamp;  
231 - *p++ = pp[3];  
232 - *p++ = pp[2];  
233 - *p++ = pp[1];  
234 - *p++ = pp[0];  
235 - }  
236 -  
237 - // always has header  
238 - return p - cache;  
239 -}  
240 -  
241 -int srs_chunk_header_c3(  
242 - int perfer_cid, u_int32_t timestamp,  
243 - char* cache, int nb_cache  
244 -)  
245 -{  
246 - // to directly set the field.  
247 - char* pp = NULL;  
248 -  
249 - // generate the header.  
250 - char* p = cache;  
251 -  
252 - // no header.  
253 - if (nb_cache < SRS_CONSTS_RTMP_MAX_FMT3_HEADER_SIZE) {  
254 - return 0;  
255 - }  
256 -  
257 - // write no message header chunk stream, fmt is 3  
258 - // @remark, if perfer_cid > 0x3F, that is, use 2B/3B chunk header,  
259 - // SRS will rollback to 1B chunk header.  
260 - *p++ = 0xC0 | (perfer_cid & 0x3F);  
261 -  
262 - // for c0  
263 - // chunk extended timestamp header, 0 or 4 bytes, big-endian  
264 - //  
265 - // for c3:  
266 - // chunk extended timestamp header, 0 or 4 bytes, big-endian  
267 - // 6.1.3. Extended Timestamp  
268 - // This field is transmitted only when the normal time stamp in the  
269 - // chunk message header is set to 0x00ffffff. If normal time stamp is  
270 - // set to any value less than 0x00ffffff, this field MUST NOT be  
271 - // present. This field MUST NOT be present if the timestamp field is not  
272 - // present. Type 3 chunks MUST NOT have this field.  
273 - // adobe changed for Type3 chunk:  
274 - // FMLE always sendout the extended-timestamp,  
275 - // must send the extended-timestamp to FMS,  
276 - // must send the extended-timestamp to flash-player.  
277 - // @see: ngx_rtmp_prepare_message  
278 - // @see: http://blog.csdn.net/win_lin/article/details/13363699  
279 - // TODO: FIXME: extract to outer.  
280 - if (timestamp >= RTMP_EXTENDED_TIMESTAMP) {  
281 - pp = (char*)&timestamp;  
282 - *p++ = pp[3];  
283 - *p++ = pp[2];  
284 - *p++ = pp[1];  
285 - *p++ = pp[0];  
286 - }  
287 -  
288 - // always has header  
289 - return p - cache;  
290 -}  
291 -  
292 int srs_do_rtmp_create_msg(char type, u_int32_t timestamp, char* data, int size, int stream_id, SrsSharedPtrMessage** ppmsg) 169 int srs_do_rtmp_create_msg(char type, u_int32_t timestamp, char* data, int size, int stream_id, SrsSharedPtrMessage** ppmsg)
293 { 170 {
294 int ret = ERROR_SUCCESS; 171 int ret = ERROR_SUCCESS;
@@ -362,3 +239,43 @@ std::string srs_generate_stream_url(std::string vhost, std::string app, std::str @@ -362,3 +239,43 @@ std::string srs_generate_stream_url(std::string vhost, std::string app, std::str
362 return url; 239 return url;
363 } 240 }
364 241
  242 +int srs_write_large_iovs(ISrsProtocolReaderWriter* skt, iovec* iovs, int size, ssize_t* pnwrite)
  243 +{
  244 + int ret = ERROR_SUCCESS;
  245 +
  246 + // the limits of writev iovs.
  247 + // for srs-librtmp, @see https://github.com/simple-rtmp-server/srs/issues/213
  248 +#ifndef _WIN32
  249 + // for linux, generally it's 1024.
  250 + static int limits = sysconf(_SC_IOV_MAX);
  251 +#else
  252 + static int limits = 1024;
  253 +#endif
  254 +
  255 + // send in a time.
  256 + if (size < limits) {
  257 + if ((ret = skt->writev(iovs, size, pnwrite)) != ERROR_SUCCESS) {
  258 + if (!srs_is_client_gracefully_close(ret)) {
  259 + srs_error("send with writev failed. ret=%d", ret);
  260 + }
  261 + return ret;
  262 + }
  263 + return ret;
  264 + }
  265 +
  266 + // send in multiple times.
  267 + int cur_iov = 0;
  268 + while (cur_iov < size) {
  269 + int cur_count = srs_min(limits, size - cur_iov);
  270 + if ((ret = skt->writev(iovs + cur_iov, cur_count, pnwrite)) != ERROR_SUCCESS) {
  271 + if (!srs_is_client_gracefully_close(ret)) {
  272 + srs_error("send with writev failed. ret=%d", ret);
  273 + }
  274 + return ret;
  275 + }
  276 + cur_iov += cur_count;
  277 + }
  278 +
  279 + return ret;
  280 +}
  281 +
@@ -29,12 +29,18 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -29,12 +29,18 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 */ 29 */
30 #include <srs_core.hpp> 30 #include <srs_core.hpp>
31 31
  32 +// for srs-librtmp, @see https://github.com/simple-rtmp-server/srs/issues/213
  33 +#ifndef _WIN32
  34 +#include <sys/uio.h>
  35 +#endif
  36 +
32 #include <string> 37 #include <string>
33 38
34 #include <srs_kernel_consts.hpp> 39 #include <srs_kernel_consts.hpp>
35 40
36 class SrsMessageHeader; 41 class SrsMessageHeader;
37 class SrsSharedPtrMessage; 42 class SrsSharedPtrMessage;
  43 +class ISrsProtocolReaderWriter;
38 44
39 /** 45 /**
40 * parse the tcUrl, output the schema, host, vhost, app and port. 46 * parse the tcUrl, output the schema, host, vhost, app and port.
@@ -91,29 +97,6 @@ extern std::string srs_generate_tc_url( @@ -91,29 +97,6 @@ extern std::string srs_generate_tc_url(
91 extern bool srs_bytes_equals(void* pa, void* pb, int size); 97 extern bool srs_bytes_equals(void* pa, void* pb, int size);
92 98
93 /** 99 /**
94 -* generate the c0 chunk header for msg.  
95 -* @param cache, the cache to write header.  
96 -* @param nb_cache, the size of cache.  
97 -* @return the size of header. 0 if cache not enough.  
98 -*/  
99 -extern int srs_chunk_header_c0(  
100 - int perfer_cid, u_int32_t timestamp, int32_t payload_length,  
101 - int8_t message_type, int32_t stream_id,  
102 - char* cache, int nb_cache  
103 -);  
104 -  
105 -/**  
106 -* generate the c3 chunk header for msg.  
107 -* @param cache, the cache to write header.  
108 -* @param nb_cache, the size of cache.  
109 -* @return the size of header. 0 if cache not enough.  
110 -*/  
111 -extern int srs_chunk_header_c3(  
112 - int perfer_cid, u_int32_t timestamp,  
113 - char* cache, int nb_cache  
114 -);  
115 -  
116 -/**  
117 * create shared ptr message from bytes. 100 * create shared ptr message from bytes.
118 * @param data the packet bytes. user should never free it. 101 * @param data the packet bytes. user should never free it.
119 * @param ppmsg output the shared ptr message. user should free it. 102 * @param ppmsg output the shared ptr message. user should free it.
@@ -123,5 +106,8 @@ extern int srs_rtmp_create_msg(char type, u_int32_t timestamp, char* data, int s @@ -123,5 +106,8 @@ extern int srs_rtmp_create_msg(char type, u_int32_t timestamp, char* data, int s
123 // get the stream identify, vhost/app/stream. 106 // get the stream identify, vhost/app/stream.
124 extern std::string srs_generate_stream_url(std::string vhost, std::string app, std::string stream); 107 extern std::string srs_generate_stream_url(std::string vhost, std::string app, std::string stream);
125 108
  109 +// write large numbers of iovs.
  110 +extern int srs_write_large_iovs(ISrsProtocolReaderWriter* skt, iovec* iovs, int size, ssize_t* pnwrite = NULL);
  111 +
126 #endif 112 #endif
127 113