winlin

for bug #251, refine code before mic.

@@ -830,6 +830,17 @@ int SrsConfig::reload_vhost(SrsConfDirective* old_root) @@ -830,6 +830,17 @@ int SrsConfig::reload_vhost(SrsConfDirective* old_root)
830 } 830 }
831 srs_trace("vhost %s reload mr success.", vhost.c_str()); 831 srs_trace("vhost %s reload mr success.", vhost.c_str());
832 } 832 }
  833 + // chunk_size, only one per vhost.
  834 + if (!srs_directive_equals(new_vhost->get("chunk_size"), old_vhost->get("chunk_size"))) {
  835 + for (it = subscribes.begin(); it != subscribes.end(); ++it) {
  836 + ISrsReloadHandler* subscribe = *it;
  837 + if ((ret = subscribe->on_reload_vhost_chunk_size(vhost)) != ERROR_SUCCESS) {
  838 + srs_error("vhost %s notify subscribes chunk_size failed. ret=%d", vhost.c_str(), ret);
  839 + return ret;
  840 + }
  841 + }
  842 + srs_trace("vhost %s reload chunk_size success.", vhost.c_str());
  843 + }
833 // mw, only one per vhost 844 // mw, only one per vhost
834 if (!srs_directive_equals(new_vhost->get("mw_latency"), old_vhost->get("mw_latency"))) { 845 if (!srs_directive_equals(new_vhost->get("mw_latency"), old_vhost->get("mw_latency"))) {
835 for (it = subscribes.begin(); it != subscribes.end(); ++it) { 846 for (it = subscribes.begin(); it != subscribes.end(); ++it) {
@@ -150,6 +150,11 @@ int ISrsReloadHandler::on_reload_vhost_mw(string /*vhost*/) @@ -150,6 +150,11 @@ int ISrsReloadHandler::on_reload_vhost_mw(string /*vhost*/)
150 return ERROR_SUCCESS; 150 return ERROR_SUCCESS;
151 } 151 }
152 152
  153 +int ISrsReloadHandler::on_reload_vhost_chunk_size(string /*vhost*/)
  154 +{
  155 + return ERROR_SUCCESS;
  156 +}
  157 +
153 int ISrsReloadHandler::on_reload_vhost_transcode(string /*vhost*/) 158 int ISrsReloadHandler::on_reload_vhost_transcode(string /*vhost*/)
154 { 159 {
155 return ERROR_SUCCESS; 160 return ERROR_SUCCESS;
@@ -67,6 +67,7 @@ public: @@ -67,6 +67,7 @@ public:
67 virtual int on_reload_vhost_dvr(std::string vhost); 67 virtual int on_reload_vhost_dvr(std::string vhost);
68 virtual int on_reload_vhost_mr(std::string vhost); 68 virtual int on_reload_vhost_mr(std::string vhost);
69 virtual int on_reload_vhost_mw(std::string vhost); 69 virtual int on_reload_vhost_mw(std::string vhost);
  70 + virtual int on_reload_vhost_chunk_size(std::string vhost);
70 virtual int on_reload_vhost_transcode(std::string vhost); 71 virtual int on_reload_vhost_transcode(std::string vhost);
71 virtual int on_reload_ingest_removed(std::string vhost, std::string ingest_id); 72 virtual int on_reload_ingest_removed(std::string vhost, std::string ingest_id);
72 virtual int on_reload_ingest_added(std::string vhost, std::string ingest_id); 73 virtual int on_reload_ingest_added(std::string vhost, std::string ingest_id);
@@ -1173,7 +1173,7 @@ int SrsSource::on_audio(SrsCommonMessage* __audio) @@ -1173,7 +1173,7 @@ int SrsSource::on_audio(SrsCommonMessage* __audio)
1173 std::vector<SrsForwarder*>::iterator it; 1173 std::vector<SrsForwarder*>::iterator it;
1174 for (it = forwarders.begin(); it != forwarders.end(); ++it) { 1174 for (it = forwarders.begin(); it != forwarders.end(); ++it) {
1175 SrsForwarder* forwarder = *it; 1175 SrsForwarder* forwarder = *it;
1176 - if ((ret = forwarder->on_audio(msg.copy())) != ERROR_SUCCESS) { 1176 + if ((ret = forwarder->on_audio(&msg)) != ERROR_SUCCESS) {
1177 srs_error("forwarder process audio message failed. ret=%d", ret); 1177 srs_error("forwarder process audio message failed. ret=%d", ret);
1178 return ret; 1178 return ret;
1179 } 1179 }
@@ -162,6 +162,8 @@ void check_macro_features() @@ -162,6 +162,8 @@ void check_macro_features()
162 srs_warn("MR(merged-read) is disabled, hurts read performance. @see %s", RTMP_SIG_SRS_ISSUES(241)); 162 srs_warn("MR(merged-read) is disabled, hurts read performance. @see %s", RTMP_SIG_SRS_ISSUES(241));
163 #endif 163 #endif
164 164
  165 + srs_trace("writev limits write %d iovs a time", sysconf(_SC_IOV_MAX));
  166 +
165 #if VERSION_MAJOR > 1 167 #if VERSION_MAJOR > 1
166 #warning "using develop SRS, please use release instead." 168 #warning "using develop SRS, please use release instead."
167 srs_warn("SRS %s is develop branch, please use %s instead", RTMP_SIG_SRS_VERSION, RTMP_SIG_SRS_RELEASE); 169 srs_warn("SRS %s is develop branch, please use %s instead", RTMP_SIG_SRS_VERSION, RTMP_SIG_SRS_RELEASE);
@@ -29,6 +29,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -29,6 +29,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 #include <srs_core_autofree.hpp> 29 #include <srs_core_autofree.hpp>
30 #include <srs_kernel_utility.hpp> 30 #include <srs_kernel_utility.hpp>
31 #include <srs_protocol_buffer.hpp> 31 #include <srs_protocol_buffer.hpp>
  32 +#include <srs_protocol_utility.hpp>
32 33
33 #include <stdlib.h> 34 #include <stdlib.h>
34 using namespace std; 35 using namespace std;
@@ -167,22 +168,6 @@ messages. @@ -167,22 +168,6 @@ messages.
167 ***************************************************************************** 168 *****************************************************************************
168 ****************************************************************************/ 169 ****************************************************************************/
169 /** 170 /**
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 -*****************************************************************************  
184 -****************************************************************************/  
185 -/**  
186 * amf0 command message, command name macros 171 * amf0 command message, command name macros
187 */ 172 */
188 #define RTMP_AMF0_COMMAND_CONNECT "connect" 173 #define RTMP_AMF0_COMMAND_CONNECT "connect"
@@ -756,13 +741,11 @@ int SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msgs) @@ -756,13 +741,11 @@ int SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msgs)
756 // always write the header event payload is empty. 741 // always write the header event payload is empty.
757 while (p < pend) { 742 while (p < pend) {
758 // always has header 743 // always has header
759 - int nbh = 0;  
760 - char* header = NULL;  
761 - generate_chunk_header(c0c3_cache, &msg->header, p == msg->payload, &nbh, &header); 744 + int nbh = srs_chunk_header(c0c3_cache, &msg->header, p == msg->payload);
762 srs_assert(nbh > 0); 745 srs_assert(nbh > 0);
763 746
764 // header iov 747 // header iov
765 - iov[0].iov_base = header; 748 + iov[0].iov_base = c0c3_cache;
766 iov[0].iov_len = nbh; 749 iov[0].iov_len = nbh;
767 750
768 // payload iov 751 // payload iov
@@ -813,7 +796,7 @@ int SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msgs) @@ -813,7 +796,7 @@ int SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msgs)
813 // sendout all messages and reset the cache, then send again. 796 // sendout all messages and reset the cache, then send again.
814 if ((ret = skt->writev(out_iovs, iov_index, NULL)) != ERROR_SUCCESS) { 797 if ((ret = skt->writev(out_iovs, iov_index, NULL)) != ERROR_SUCCESS) {
815 if (!srs_is_client_gracefully_close(ret)) { 798 if (!srs_is_client_gracefully_close(ret)) {
816 - srs_error("send with writev failed. ret=%d", ret); 799 + srs_error("send msgs with writev failed. ret=%d", ret);
817 } 800 }
818 return ret; 801 return ret;
819 } 802 }
@@ -834,31 +817,47 @@ int SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msgs) @@ -834,31 +817,47 @@ int SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msgs)
834 if (iov_index <= 0) { 817 if (iov_index <= 0) {
835 return ret; 818 return ret;
836 } 819 }
837 -  
838 - // calc the bytes of iovs, for debug.  
839 #if 0 820 #if 0
  821 + // calc the bytes of iovs, for debug.
840 int nb_bytes = 0; 822 int nb_bytes = 0;
841 for (int i = 0; i < iov_index; i++) { 823 for (int i = 0; i < iov_index; i++) {
842 iovec* iov = out_iovs + i; 824 iovec* iov = out_iovs + i;
843 nb_bytes += iov->iov_len; 825 nb_bytes += iov->iov_len;
844 } 826 }
845 - srs_warn("mw %d msgs %dB in %d iovs, max_msgs=%d, nb_out_iovs=%d", 827 + srs_info("mw %d msgs %dB in %d iovs, max_msgs=%d, nb_out_iovs=%d",
846 nb_msgs, nb_bytes, iov_index, SRS_PERF_MW_MSGS, nb_out_iovs); 828 nb_msgs, nb_bytes, iov_index, SRS_PERF_MW_MSGS, nb_out_iovs);
847 #else 829 #else
848 srs_info("mw %d msgs in %d iovs, max_msgs=%d, nb_out_iovs=%d", 830 srs_info("mw %d msgs in %d iovs, max_msgs=%d, nb_out_iovs=%d",
849 nb_msgs, iov_index, SRS_PERF_MW_MSGS, nb_out_iovs); 831 nb_msgs, iov_index, SRS_PERF_MW_MSGS, nb_out_iovs);
850 #endif 832 #endif
851 833
852 - // send by writev  
853 - // sendout header and payload by writev.  
854 - // decrease the sys invoke count to get higher performance.  
855 - if ((ret = skt->writev(out_iovs, iov_index, NULL)) != ERROR_SUCCESS) {  
856 - if (!srs_is_client_gracefully_close(ret)) {  
857 - srs_error("send with writev failed. ret=%d", ret); 834 + // the limits of writev iovs.
  835 + static int limits = sysconf(_SC_IOV_MAX);
  836 +
  837 + // send in a time.
  838 + if (iov_index < limits) {
  839 + if ((ret = skt->writev(out_iovs, iov_index, NULL)) != ERROR_SUCCESS) {
  840 + if (!srs_is_client_gracefully_close(ret)) {
  841 + srs_error("send with writev failed. ret=%d", ret);
  842 + }
  843 + return ret;
858 } 844 }
859 return ret; 845 return ret;
860 } 846 }
861 847
  848 + // send in multiple times.
  849 + int cur_iov = 0;
  850 + while (cur_iov < iov_index) {
  851 + int cur_count = srs_min(limits, iov_index - cur_iov);
  852 + if ((ret = skt->writev(out_iovs + cur_iov, cur_count, NULL)) != ERROR_SUCCESS) {
  853 + if (!srs_is_client_gracefully_close(ret)) {
  854 + srs_error("send with writev failed. ret=%d", ret);
  855 + }
  856 + return ret;
  857 + }
  858 + cur_iov += cur_count;
  859 + }
  860 +
862 return ret; 861 return ret;
863 } 862 }
864 863
@@ -888,102 +887,46 @@ int SrsProtocol::do_send_and_free_packet(SrsPacket* packet, int stream_id) @@ -888,102 +887,46 @@ int SrsProtocol::do_send_and_free_packet(SrsPacket* packet, int stream_id)
888 header.message_type = packet->get_message_type(); 887 header.message_type = packet->get_message_type();
889 header.stream_id = stream_id; 888 header.stream_id = stream_id;
890 header.perfer_cid = packet->get_prefer_cid(); 889 header.perfer_cid = packet->get_prefer_cid();
891 -  
892 - SrsSharedPtrMessage* msg = new SrsSharedPtrMessage();  
893 - ret = msg->create(&header, payload, size); 890 +
  891 + ret = do_simple_send(&header, payload, size);
894 if (ret == ERROR_SUCCESS) { 892 if (ret == ERROR_SUCCESS) {
895 - ret = do_send_messages(&msg, 1);  
896 - if (ret == ERROR_SUCCESS) {  
897 - ret = on_send_packet(msg, packet);  
898 - } 893 + ret = on_send_packet(&header, packet);
899 } 894 }
900 -  
901 - // donot use the auto free to free the msg,  
902 - // for performance issue.  
903 - srs_freep(msg);  
904 895
905 return ret; 896 return ret;
906 } 897 }
907 898
908 -void SrsProtocol::generate_chunk_header(char* cache, SrsMessageHeader* mh, bool c0, int* pnbh, char** ph) 899 +int SrsProtocol::do_simple_send(SrsMessageHeader* mh, char* payload, int size)
909 { 900 {
910 - // to directly set the field.  
911 - char* pp = NULL;  
912 -  
913 - // generate the header.  
914 - char* p = cache;  
915 -  
916 - // timestamp for c0/c3  
917 - u_int32_t timestamp = (u_int32_t)mh->timestamp; 901 + int ret = ERROR_SUCCESS;
918 902
919 - if (c0) {  
920 - // write new chunk stream header, fmt is 0  
921 - *p++ = 0x00 | (mh->perfer_cid & 0x3F);  
922 -  
923 - // chunk message header, 11 bytes  
924 - // timestamp, 3bytes, big-endian  
925 - if (timestamp < RTMP_EXTENDED_TIMESTAMP) {  
926 - pp = (char*)&timestamp;  
927 - *p++ = pp[2];  
928 - *p++ = pp[1];  
929 - *p++ = pp[0];  
930 - } else {  
931 - *p++ = 0xFF;  
932 - *p++ = 0xFF;  
933 - *p++ = 0xFF;  
934 - } 903 + // we directly send out the packet,
  904 + // use very simple algorithm, not very fast,
  905 + // but it's ok.
  906 + char* p = payload;
  907 + char* end = p + size;
  908 + char c0c3[SRS_CONSTS_RTMP_MAX_FMT0_HEADER_SIZE];
  909 + while (p < end) {
  910 + int nbh = srs_chunk_header(c0c3, mh, p == payload);
935 911
936 - // message_length, 3bytes, big-endian  
937 - pp = (char*)&mh->payload_length;  
938 - *p++ = pp[2];  
939 - *p++ = pp[1];  
940 - *p++ = pp[0]; 912 + iovec iovs[2];
  913 + iovs[0].iov_base = c0c3;
  914 + iovs[0].iov_len = nbh;
941 915
942 - // message_type, 1bytes  
943 - *p++ = mh->message_type; 916 + int payload_size = srs_min(end - p, out_chunk_size);
  917 + iovs[1].iov_base = p;
  918 + iovs[1].iov_len = payload_size;
  919 + p += payload_size;
944 920
945 - // message_length, 3bytes, little-endian  
946 - pp = (char*)&mh->stream_id;  
947 - *p++ = pp[0];  
948 - *p++ = pp[1];  
949 - *p++ = pp[2];  
950 - *p++ = pp[3];  
951 - } else {  
952 - // write no message header chunk stream, fmt is 3  
953 - // @remark, if perfer_cid > 0x3F, that is, use 2B/3B chunk header,  
954 - // SRS will rollback to 1B chunk header.  
955 - *p++ = 0xC0 | (mh->perfer_cid & 0x3F); 921 + if ((ret = skt->writev(iovs, 2, NULL)) != ERROR_SUCCESS) {
  922 + if (!srs_is_client_gracefully_close(ret)) {
  923 + srs_error("send packet with writev failed. ret=%d", ret);
  924 + }
  925 + return ret;
  926 + }
956 } 927 }
957 928
958 - // for c0  
959 - // chunk extended timestamp header, 0 or 4 bytes, big-endian  
960 - //  
961 - // for c3:  
962 - // chunk extended timestamp header, 0 or 4 bytes, big-endian  
963 - // 6.1.3. Extended Timestamp  
964 - // This field is transmitted only when the normal time stamp in the  
965 - // chunk message header is set to 0x00ffffff. If normal time stamp is  
966 - // set to any value less than 0x00ffffff, this field MUST NOT be  
967 - // present. This field MUST NOT be present if the timestamp field is not  
968 - // present. Type 3 chunks MUST NOT have this field.  
969 - // adobe changed for Type3 chunk:  
970 - // FMLE always sendout the extended-timestamp,  
971 - // must send the extended-timestamp to FMS,  
972 - // must send the extended-timestamp to flash-player.  
973 - // @see: ngx_rtmp_prepare_message  
974 - // @see: http://blog.csdn.net/win_lin/article/details/13363699  
975 - // TODO: FIXME: extract to outer.  
976 - if (timestamp >= RTMP_EXTENDED_TIMESTAMP) {  
977 - pp = (char*)&timestamp;  
978 - *p++ = pp[3];  
979 - *p++ = pp[2];  
980 - *p++ = pp[1];  
981 - *p++ = pp[0];  
982 - }  
983 -  
984 - // always has header  
985 - *pnbh = p - cache;  
986 - *ph = cache; 929 + return ret;
987 } 930 }
988 931
989 int SrsProtocol::do_decode_message(SrsMessageHeader& header, SrsStream* stream, SrsPacket** ppacket) 932 int SrsProtocol::do_decode_message(SrsMessageHeader& header, SrsStream* stream, SrsPacket** ppacket)
@@ -1842,7 +1785,7 @@ int SrsProtocol::on_recv_message(SrsCommonMessage* msg) @@ -1842,7 +1785,7 @@ int SrsProtocol::on_recv_message(SrsCommonMessage* msg)
1842 return ret; 1785 return ret;
1843 } 1786 }
1844 1787
1845 -int SrsProtocol::on_send_packet(SrsSharedPtrMessage* msg, SrsPacket* packet) 1788 +int SrsProtocol::on_send_packet(SrsMessageHeader* mh, SrsPacket* packet)
1846 { 1789 {
1847 int ret = ERROR_SUCCESS; 1790 int ret = ERROR_SUCCESS;
1848 1791
@@ -1851,7 +1794,7 @@ int SrsProtocol::on_send_packet(SrsSharedPtrMessage* msg, SrsPacket* packet) @@ -1851,7 +1794,7 @@ int SrsProtocol::on_send_packet(SrsSharedPtrMessage* msg, SrsPacket* packet)
1851 return ret; 1794 return ret;
1852 } 1795 }
1853 1796
1854 - switch (msg->header.message_type) { 1797 + switch (mh->message_type) {
1855 case RTMP_MSG_SetChunkSize: { 1798 case RTMP_MSG_SetChunkSize: {
1856 SrsSetChunkSizePacket* pkt = dynamic_cast<SrsSetChunkSizePacket*>(packet); 1799 SrsSetChunkSizePacket* pkt = dynamic_cast<SrsSetChunkSizePacket*>(packet);
1857 srs_assert(pkt != NULL); 1800 srs_assert(pkt != NULL);
@@ -56,6 +56,22 @@ class SrsChunkStream; @@ -56,6 +56,22 @@ class SrsChunkStream;
56 class SrsSharedPtrMessage; 56 class SrsSharedPtrMessage;
57 class IMergeReadHandler; 57 class IMergeReadHandler;
58 58
  59 +/****************************************************************************
  60 +*****************************************************************************
  61 +****************************************************************************/
  62 +/**
  63 +* 6.1. Chunk Format
  64 +* Extended timestamp: 0 or 4 bytes
  65 +* This field MUST be sent when the normal timsestamp is set to
  66 +* 0xffffff, it MUST NOT be sent if the normal timestamp is set to
  67 +* anything else. So for values less than 0xffffff the normal
  68 +* timestamp field SHOULD be used in which case the extended timestamp
  69 +* MUST NOT be present. For values greater than or equal to 0xffffff
  70 +* the normal timestamp field MUST NOT be used and MUST be set to
  71 +* 0xffffff and the extended timestamp MUST be sent.
  72 +*/
  73 +#define RTMP_EXTENDED_TIMESTAMP 0xFFFFFF
  74 +
59 /** 75 /**
60 * 4.1. Message Header 76 * 4.1. Message Header
61 */ 77 */
@@ -493,14 +509,10 @@ private: @@ -493,14 +509,10 @@ private:
493 */ 509 */
494 virtual int do_send_and_free_packet(SrsPacket* packet, int stream_id); 510 virtual int do_send_and_free_packet(SrsPacket* packet, int stream_id);
495 /** 511 /**
496 - * generate the chunk header for msg.  
497 - * @param mh, the header of msg to send.  
498 - * @param c0, whether the first chunk, the c0 chunk.  
499 - * @param pnbh, output the size of header.  
500 - * @param ph, output the header cache.  
501 - * user should never free it, it's cached header. 512 + * use simple algorithm to send the header and bytes.
  513 + * @remark, for do_send_and_free_packet to send.
502 */ 514 */
503 - virtual void generate_chunk_header(char* cache, SrsMessageHeader* mh, bool c0, int* pnbh, char** ph); 515 + virtual int do_simple_send(SrsMessageHeader* mh, char* payload, int size);
504 /** 516 /**
505 * imp for decode_message 517 * imp for decode_message
506 */ 518 */
@@ -534,7 +546,7 @@ private: @@ -534,7 +546,7 @@ private:
534 /** 546 /**
535 * when message sentout, update the context. 547 * when message sentout, update the context.
536 */ 548 */
537 - virtual int on_send_packet(SrsSharedPtrMessage* msg, SrsPacket* packet); 549 + virtual int on_send_packet(SrsMessageHeader* mh, SrsPacket* packet);
538 private: 550 private:
539 /** 551 /**
540 * auto response the ack message. 552 * auto response the ack message.
@@ -29,6 +29,7 @@ using namespace std; @@ -29,6 +29,7 @@ using namespace std;
29 #include <srs_kernel_log.hpp> 29 #include <srs_kernel_log.hpp>
30 #include <srs_kernel_utility.hpp> 30 #include <srs_kernel_utility.hpp>
31 #include <srs_kernel_stream.hpp> 31 #include <srs_kernel_stream.hpp>
  32 +#include <srs_protocol_stack.hpp>
32 33
33 void srs_discovery_tc_url( 34 void srs_discovery_tc_url(
34 string tcUrl, 35 string tcUrl,
@@ -203,3 +204,83 @@ bool srs_aac_startswith_adts(SrsStream* stream) @@ -203,3 +204,83 @@ bool srs_aac_startswith_adts(SrsStream* stream)
203 return true; 204 return true;
204 } 205 }
205 206
  207 +int srs_chunk_header(char* cache, SrsMessageHeader* mh, bool c0)
  208 +{
  209 + // to directly set the field.
  210 + char* pp = NULL;
  211 +
  212 + // generate the header.
  213 + char* p = cache;
  214 +
  215 + // timestamp for c0/c3
  216 + u_int32_t timestamp = (u_int32_t)mh->timestamp;
  217 +
  218 + if (c0) {
  219 + // write new chunk stream header, fmt is 0
  220 + *p++ = 0x00 | (mh->perfer_cid & 0x3F);
  221 +
  222 + // chunk message header, 11 bytes
  223 + // timestamp, 3bytes, big-endian
  224 + if (timestamp < RTMP_EXTENDED_TIMESTAMP) {
  225 + pp = (char*)&timestamp;
  226 + *p++ = pp[2];
  227 + *p++ = pp[1];
  228 + *p++ = pp[0];
  229 + } else {
  230 + *p++ = 0xFF;
  231 + *p++ = 0xFF;
  232 + *p++ = 0xFF;
  233 + }
  234 +
  235 + // message_length, 3bytes, big-endian
  236 + pp = (char*)&mh->payload_length;
  237 + *p++ = pp[2];
  238 + *p++ = pp[1];
  239 + *p++ = pp[0];
  240 +
  241 + // message_type, 1bytes
  242 + *p++ = mh->message_type;
  243 +
  244 + // stream_id, 4bytes, little-endian
  245 + pp = (char*)&mh->stream_id;
  246 + *p++ = pp[0];
  247 + *p++ = pp[1];
  248 + *p++ = pp[2];
  249 + *p++ = pp[3];
  250 + } else {
  251 + // write no message header chunk stream, fmt is 3
  252 + // @remark, if perfer_cid > 0x3F, that is, use 2B/3B chunk header,
  253 + // SRS will rollback to 1B chunk header.
  254 + *p++ = 0xC0 | (mh->perfer_cid & 0x3F);
  255 + }
  256 +
  257 + // for c0
  258 + // chunk extended timestamp header, 0 or 4 bytes, big-endian
  259 + //
  260 + // for c3:
  261 + // chunk extended timestamp header, 0 or 4 bytes, big-endian
  262 + // 6.1.3. Extended Timestamp
  263 + // This field is transmitted only when the normal time stamp in the
  264 + // chunk message header is set to 0x00ffffff. If normal time stamp is
  265 + // set to any value less than 0x00ffffff, this field MUST NOT be
  266 + // present. This field MUST NOT be present if the timestamp field is not
  267 + // present. Type 3 chunks MUST NOT have this field.
  268 + // adobe changed for Type3 chunk:
  269 + // FMLE always sendout the extended-timestamp,
  270 + // must send the extended-timestamp to FMS,
  271 + // must send the extended-timestamp to flash-player.
  272 + // @see: ngx_rtmp_prepare_message
  273 + // @see: http://blog.csdn.net/win_lin/article/details/13363699
  274 + // TODO: FIXME: extract to outer.
  275 + if (timestamp >= RTMP_EXTENDED_TIMESTAMP) {
  276 + pp = (char*)&timestamp;
  277 + *p++ = pp[3];
  278 + *p++ = pp[2];
  279 + *p++ = pp[1];
  280 + *p++ = pp[0];
  281 + }
  282 +
  283 + // always has header
  284 + return p - cache;
  285 +}
  286 +
@@ -34,6 +34,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -34,6 +34,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 #include <srs_kernel_consts.hpp> 34 #include <srs_kernel_consts.hpp>
35 35
36 class SrsStream; 36 class SrsStream;
  37 +class SrsMessageHeader;
37 38
38 /** 39 /**
39 * parse the tcUrl, output the schema, host, vhost, app and port. 40 * parse the tcUrl, output the schema, host, vhost, app and port.
@@ -103,5 +104,13 @@ extern bool srs_avc_startswith_annexb(SrsStream* stream, int* pnb_start_code = N @@ -103,5 +104,13 @@ extern bool srs_avc_startswith_annexb(SrsStream* stream, int* pnb_start_code = N
103 */ 104 */
104 extern bool srs_aac_startswith_adts(SrsStream* stream); 105 extern bool srs_aac_startswith_adts(SrsStream* stream);
105 106
  107 +/**
  108 +* generate the chunk header for msg.
  109 +* @param mh, the header of msg to send.
  110 +* @param c0, whether the first chunk, the c0 chunk.
  111 +* @return the size of header.
  112 +*/
  113 +extern int srs_chunk_header(char* cache, SrsMessageHeader* mh, bool c0);
  114 +
106 #endif 115 #endif
107 116