正在显示
12 个修改的文件
包含
148 行增加
和
148 行删除
| @@ -38,6 +38,9 @@ gcc srs_flv_injecter.c ../../objs/lib/srs_librtmp.a -g -O0 -lstdc++ -o srs_flv_i | @@ -38,6 +38,9 @@ gcc srs_flv_injecter.c ../../objs/lib/srs_librtmp.a -g -O0 -lstdc++ -o srs_flv_i | ||
| 38 | #define ERROR_INJECTED 10000 | 38 | #define ERROR_INJECTED 10000 |
| 39 | 39 | ||
| 40 | int process(const char* in_flv_file, const char* out_flv_file, srs_flv_t* pic, srs_flv_t* poc); | 40 | int process(const char* in_flv_file, const char* out_flv_file, srs_flv_t* pic, srs_flv_t* poc); |
| 41 | +int build_keyframes(srs_flv_t ic, srs_amf0_t *pname, srs_amf0_t* pdata, srs_amf0_t* pfilepositions, int64_t* pmetadata_end_offset); | ||
| 42 | +int do_inject_flv(srs_flv_t ic, srs_flv_t oc, srs_amf0_t amf0_name, srs_amf0_t amf0_data, srs_amf0_t filepositions, int64_t metadata_end_offset); | ||
| 43 | + | ||
| 41 | int main(int argc, char** argv) | 44 | int main(int argc, char** argv) |
| 42 | { | 45 | { |
| 43 | int ret = 0; | 46 | int ret = 0; |
| @@ -122,6 +122,8 @@ int parse_bytes(char* data, int size, char* hbuf, int hsize, char* tbuf, int tsi | @@ -122,6 +122,8 @@ int parse_bytes(char* data, int size, char* hbuf, int hsize, char* tbuf, int tsi | ||
| 122 | if (size > print_size * 2) { | 122 | if (size > print_size * 2) { |
| 123 | digit_to_char(data + size - print_size, size, tbuf, tsize - 1); | 123 | digit_to_char(data + size - print_size, size, tbuf, tsize - 1); |
| 124 | } | 124 | } |
| 125 | + | ||
| 126 | + return 0; | ||
| 125 | } | 127 | } |
| 126 | 128 | ||
| 127 | int parse_flv(srs_flv_t flv) | 129 | int parse_flv(srs_flv_t flv) |
| @@ -146,11 +146,11 @@ int main(int argc, char** argv) | @@ -146,11 +146,11 @@ int main(int argc, char** argv) | ||
| 146 | } | 146 | } |
| 147 | srs_human_trace("publish stream success"); | 147 | srs_human_trace("publish stream success"); |
| 148 | 148 | ||
| 149 | - u_int32_t dts = 0; | ||
| 150 | - u_int32_t pts = 0; | 149 | + int dts = 0; |
| 150 | + int pts = 0; | ||
| 151 | // @remark, the dts and pts if read from device, for instance, the encode lib, | 151 | // @remark, the dts and pts if read from device, for instance, the encode lib, |
| 152 | // so we assume the fps is 25, and each h264 frame is 1000ms/25fps=40ms/f. | 152 | // so we assume the fps is 25, and each h264 frame is 1000ms/25fps=40ms/f. |
| 153 | - u_int32_t fps = 25; | 153 | + int fps = 25; |
| 154 | // @remark, to decode the file. | 154 | // @remark, to decode the file. |
| 155 | char* p = h264_raw; | 155 | char* p = h264_raw; |
| 156 | for (;p < h264_raw + file_size;) { | 156 | for (;p < h264_raw + file_size;) { |
| @@ -158,9 +158,7 @@ int main(int argc, char** argv) | @@ -158,9 +158,7 @@ int main(int argc, char** argv) | ||
| 158 | char* data = NULL; | 158 | char* data = NULL; |
| 159 | int size = 0; | 159 | int size = 0; |
| 160 | int nb_start_code = 0; | 160 | int nb_start_code = 0; |
| 161 | - if (read_h264_frame(h264_raw, file_size, &p, &nb_start_code, fps, | ||
| 162 | - &data, &size, &dts, &pts) < 0 | ||
| 163 | - ) { | 161 | + if (read_h264_frame(h264_raw, (int)file_size, &p, &nb_start_code, fps, &data, &size, &dts, &pts) < 0) { |
| 164 | srs_human_trace("read a frame from file buffer failed."); | 162 | srs_human_trace("read a frame from file buffer failed."); |
| 165 | goto rtmp_destroy; | 163 | goto rtmp_destroy; |
| 166 | } | 164 | } |
| @@ -262,7 +262,6 @@ private: | @@ -262,7 +262,6 @@ private: | ||
| 262 | 262 | ||
| 263 | SrsHds::SrsHds(SrsSource *s) | 263 | SrsHds::SrsHds(SrsSource *s) |
| 264 | : currentSegment(NULL) | 264 | : currentSegment(NULL) |
| 265 | - , source(s) | ||
| 266 | , fragment_index(1) | 265 | , fragment_index(1) |
| 267 | , video_sh(NULL) | 266 | , video_sh(NULL) |
| 268 | , audio_sh(NULL) | 267 | , audio_sh(NULL) |
| @@ -55,7 +55,6 @@ private: | @@ -55,7 +55,6 @@ private: | ||
| 55 | private: | 55 | private: |
| 56 | std::list<SrsHdsFragment *> fragments; | 56 | std::list<SrsHdsFragment *> fragments; |
| 57 | SrsHdsFragment *currentSegment; | 57 | SrsHdsFragment *currentSegment; |
| 58 | - SrsSource *source; | ||
| 59 | int fragment_index; | 58 | int fragment_index; |
| 60 | SrsSharedPtrMessage *video_sh; | 59 | SrsSharedPtrMessage *video_sh; |
| 61 | SrsSharedPtrMessage *audio_sh; | 60 | SrsSharedPtrMessage *audio_sh; |
| @@ -932,8 +932,8 @@ int SrsHttpResponseReader::read_chunked(std::string& data) | @@ -932,8 +932,8 @@ int SrsHttpResponseReader::read_chunked(std::string& data) | ||
| 932 | srs_assert(length >= 3); | 932 | srs_assert(length >= 3); |
| 933 | 933 | ||
| 934 | // it's ok to set the pos and pos+1 to NULL. | 934 | // it's ok to set the pos and pos+1 to NULL. |
| 935 | - at[length - 1] = NULL; | ||
| 936 | - at[length - 2] = NULL; | 935 | + at[length - 1] = 0; |
| 936 | + at[length - 2] = 0; | ||
| 937 | 937 | ||
| 938 | // size is the bytes size, excludes the chunk header and end CRLF. | 938 | // size is the bytes size, excludes the chunk header and end CRLF. |
| 939 | int ilength = ::strtol(at, NULL, 16); | 939 | int ilength = ::strtol(at, NULL, 16); |
| @@ -33,7 +33,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -33,7 +33,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 33 | #include <srs_app_st.hpp> | 33 | #include <srs_app_st.hpp> |
| 34 | #include <srs_app_thread.hpp> | 34 | #include <srs_app_thread.hpp> |
| 35 | 35 | ||
| 36 | -class sockaddr_in; | 36 | +struct sockaddr_in; |
| 37 | 37 | ||
| 38 | /** | 38 | /** |
| 39 | * the udp packet handler. | 39 | * the udp packet handler. |
| @@ -32,7 +32,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -32,7 +32,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 32 | 32 | ||
| 33 | #ifdef SRS_AUTO_STREAM_CASTER | 33 | #ifdef SRS_AUTO_STREAM_CASTER |
| 34 | 34 | ||
| 35 | -class sockaddr_in; | 35 | +struct sockaddr_in; |
| 36 | #include <string> | 36 | #include <string> |
| 37 | #include <map> | 37 | #include <map> |
| 38 | 38 | ||
| @@ -46,7 +46,7 @@ class SrsRequest; | @@ -46,7 +46,7 @@ class SrsRequest; | ||
| 46 | class SrsRawH264Stream; | 46 | class SrsRawH264Stream; |
| 47 | class SrsSharedPtrMessage; | 47 | class SrsSharedPtrMessage; |
| 48 | class SrsRawAacStream; | 48 | class SrsRawAacStream; |
| 49 | -class SrsRawAacStreamCodec; | 49 | +struct SrsRawAacStreamCodec; |
| 50 | class SrsPithyPrint; | 50 | class SrsPithyPrint; |
| 51 | 51 | ||
| 52 | #include <srs_app_st.hpp> | 52 | #include <srs_app_st.hpp> |
| @@ -51,7 +51,7 @@ class SrsStSocket; | @@ -51,7 +51,7 @@ class SrsStSocket; | ||
| 51 | class SrsRtmpClient; | 51 | class SrsRtmpClient; |
| 52 | class SrsRawH264Stream; | 52 | class SrsRawH264Stream; |
| 53 | class SrsRawAacStream; | 53 | class SrsRawAacStream; |
| 54 | -class SrsRawAacStreamCodec; | 54 | +struct SrsRawAacStreamCodec; |
| 55 | class SrsSharedPtrMessage; | 55 | class SrsSharedPtrMessage; |
| 56 | class SrsCodecSample; | 56 | class SrsCodecSample; |
| 57 | class SrsSimpleBuffer; | 57 | class SrsSimpleBuffer; |
| @@ -2086,7 +2086,6 @@ char srs_utils_flv_audio_aac_packet_type(char* data, int size) | @@ -2086,7 +2086,6 @@ char srs_utils_flv_audio_aac_packet_type(char* data, int size) | ||
| 2086 | } | 2086 | } |
| 2087 | 2087 | ||
| 2088 | u_int8_t aac_packet_type = data[1]; | 2088 | u_int8_t aac_packet_type = data[1]; |
| 2089 | - aac_packet_type = aac_packet_type; | ||
| 2090 | if (aac_packet_type > 1) { | 2089 | if (aac_packet_type > 1) { |
| 2091 | return -1; | 2090 | return -1; |
| 2092 | } | 2091 | } |
| @@ -534,6 +534,85 @@ SrsSharedPtrMessage* SrsSharedPtrMessage::copy() | @@ -534,6 +534,85 @@ SrsSharedPtrMessage* SrsSharedPtrMessage::copy() | ||
| 534 | return copy; | 534 | return copy; |
| 535 | } | 535 | } |
| 536 | 536 | ||
| 537 | +SrsPacket::SrsPacket() | ||
| 538 | +{ | ||
| 539 | +} | ||
| 540 | + | ||
| 541 | +SrsPacket::~SrsPacket() | ||
| 542 | +{ | ||
| 543 | +} | ||
| 544 | + | ||
| 545 | +int SrsPacket::encode(int& psize, char*& ppayload) | ||
| 546 | +{ | ||
| 547 | + int ret = ERROR_SUCCESS; | ||
| 548 | + | ||
| 549 | + int size = get_size(); | ||
| 550 | + char* payload = NULL; | ||
| 551 | + | ||
| 552 | + SrsStream stream; | ||
| 553 | + | ||
| 554 | + if (size > 0) { | ||
| 555 | + payload = new char[size]; | ||
| 556 | + | ||
| 557 | + if ((ret = stream.initialize(payload, size)) != ERROR_SUCCESS) { | ||
| 558 | + srs_error("initialize the stream failed. ret=%d", ret); | ||
| 559 | + srs_freep(payload); | ||
| 560 | + return ret; | ||
| 561 | + } | ||
| 562 | + } | ||
| 563 | + | ||
| 564 | + if ((ret = encode_packet(&stream)) != ERROR_SUCCESS) { | ||
| 565 | + srs_error("encode the packet failed. ret=%d", ret); | ||
| 566 | + srs_freep(payload); | ||
| 567 | + return ret; | ||
| 568 | + } | ||
| 569 | + | ||
| 570 | + psize = size; | ||
| 571 | + ppayload = payload; | ||
| 572 | + srs_verbose("encode the packet success. size=%d", size); | ||
| 573 | + | ||
| 574 | + return ret; | ||
| 575 | +} | ||
| 576 | + | ||
| 577 | +int SrsPacket::decode(SrsStream* stream) | ||
| 578 | +{ | ||
| 579 | + int ret = ERROR_SUCCESS; | ||
| 580 | + | ||
| 581 | + srs_assert(stream != NULL); | ||
| 582 | + | ||
| 583 | + ret = ERROR_SYSTEM_PACKET_INVALID; | ||
| 584 | + srs_error("current packet is not support to decode. ret=%d", ret); | ||
| 585 | + | ||
| 586 | + return ret; | ||
| 587 | +} | ||
| 588 | + | ||
| 589 | +int SrsPacket::get_prefer_cid() | ||
| 590 | +{ | ||
| 591 | + return 0; | ||
| 592 | +} | ||
| 593 | + | ||
| 594 | +int SrsPacket::get_message_type() | ||
| 595 | +{ | ||
| 596 | + return 0; | ||
| 597 | +} | ||
| 598 | + | ||
| 599 | +int SrsPacket::get_size() | ||
| 600 | +{ | ||
| 601 | + return 0; | ||
| 602 | +} | ||
| 603 | + | ||
| 604 | +int SrsPacket::encode_packet(SrsStream* stream) | ||
| 605 | +{ | ||
| 606 | + int ret = ERROR_SUCCESS; | ||
| 607 | + | ||
| 608 | + srs_assert(stream != NULL); | ||
| 609 | + | ||
| 610 | + ret = ERROR_SYSTEM_PACKET_INVALID; | ||
| 611 | + srs_error("current packet is not support to encode. ret=%d", ret); | ||
| 612 | + | ||
| 613 | + return ret; | ||
| 614 | +} | ||
| 615 | + | ||
| 537 | SrsProtocol::AckWindowSize::AckWindowSize() | 616 | SrsProtocol::AckWindowSize::AckWindowSize() |
| 538 | { | 617 | { |
| 539 | ack_window_size = 0; | 618 | ack_window_size = 0; |
| @@ -2020,85 +2099,6 @@ SrsChunkStream::~SrsChunkStream() | @@ -2020,85 +2099,6 @@ SrsChunkStream::~SrsChunkStream() | ||
| 2020 | srs_freep(msg); | 2099 | srs_freep(msg); |
| 2021 | } | 2100 | } |
| 2022 | 2101 | ||
| 2023 | -SrsPacket::SrsPacket() | ||
| 2024 | -{ | ||
| 2025 | -} | ||
| 2026 | - | ||
| 2027 | -SrsPacket::~SrsPacket() | ||
| 2028 | -{ | ||
| 2029 | -} | ||
| 2030 | - | ||
| 2031 | -int SrsPacket::encode(int& psize, char*& ppayload) | ||
| 2032 | -{ | ||
| 2033 | - int ret = ERROR_SUCCESS; | ||
| 2034 | - | ||
| 2035 | - int size = get_size(); | ||
| 2036 | - char* payload = NULL; | ||
| 2037 | - | ||
| 2038 | - SrsStream stream; | ||
| 2039 | - | ||
| 2040 | - if (size > 0) { | ||
| 2041 | - payload = new char[size]; | ||
| 2042 | - | ||
| 2043 | - if ((ret = stream.initialize(payload, size)) != ERROR_SUCCESS) { | ||
| 2044 | - srs_error("initialize the stream failed. ret=%d", ret); | ||
| 2045 | - srs_freep(payload); | ||
| 2046 | - return ret; | ||
| 2047 | - } | ||
| 2048 | - } | ||
| 2049 | - | ||
| 2050 | - if ((ret = encode_packet(&stream)) != ERROR_SUCCESS) { | ||
| 2051 | - srs_error("encode the packet failed. ret=%d", ret); | ||
| 2052 | - srs_freep(payload); | ||
| 2053 | - return ret; | ||
| 2054 | - } | ||
| 2055 | - | ||
| 2056 | - psize = size; | ||
| 2057 | - ppayload = payload; | ||
| 2058 | - srs_verbose("encode the packet success. size=%d", size); | ||
| 2059 | - | ||
| 2060 | - return ret; | ||
| 2061 | -} | ||
| 2062 | - | ||
| 2063 | -int SrsPacket::decode(SrsStream* stream) | ||
| 2064 | -{ | ||
| 2065 | - int ret = ERROR_SUCCESS; | ||
| 2066 | - | ||
| 2067 | - srs_assert(stream != NULL); | ||
| 2068 | - | ||
| 2069 | - ret = ERROR_SYSTEM_PACKET_INVALID; | ||
| 2070 | - srs_error("current packet is not support to decode. ret=%d", ret); | ||
| 2071 | - | ||
| 2072 | - return ret; | ||
| 2073 | -} | ||
| 2074 | - | ||
| 2075 | -int SrsPacket::get_prefer_cid() | ||
| 2076 | -{ | ||
| 2077 | - return 0; | ||
| 2078 | -} | ||
| 2079 | - | ||
| 2080 | -int SrsPacket::get_message_type() | ||
| 2081 | -{ | ||
| 2082 | - return 0; | ||
| 2083 | -} | ||
| 2084 | - | ||
| 2085 | -int SrsPacket::get_size() | ||
| 2086 | -{ | ||
| 2087 | - return 0; | ||
| 2088 | -} | ||
| 2089 | - | ||
| 2090 | -int SrsPacket::encode_packet(SrsStream* stream) | ||
| 2091 | -{ | ||
| 2092 | - int ret = ERROR_SUCCESS; | ||
| 2093 | - | ||
| 2094 | - srs_assert(stream != NULL); | ||
| 2095 | - | ||
| 2096 | - ret = ERROR_SYSTEM_PACKET_INVALID; | ||
| 2097 | - srs_error("current packet is not support to encode. ret=%d", ret); | ||
| 2098 | - | ||
| 2099 | - return ret; | ||
| 2100 | -} | ||
| 2101 | - | ||
| 2102 | SrsConnectAppPacket::SrsConnectAppPacket() | 2102 | SrsConnectAppPacket::SrsConnectAppPacket() |
| 2103 | { | 2103 | { |
| 2104 | command_name = RTMP_AMF0_COMMAND_CONNECT; | 2104 | command_name = RTMP_AMF0_COMMAND_CONNECT; |
| @@ -318,6 +318,60 @@ public: | @@ -318,6 +318,60 @@ public: | ||
| 318 | }; | 318 | }; |
| 319 | 319 | ||
| 320 | /** | 320 | /** |
| 321 | + * the decoded message payload. | ||
| 322 | + * @remark we seperate the packet from message, | ||
| 323 | + * for the packet focus on logic and domain data, | ||
| 324 | + * the message bind to the protocol and focus on protocol, such as header. | ||
| 325 | + * we can merge the message and packet, using OOAD hierachy, packet extends from message, | ||
| 326 | + * it's better for me to use components -- the message use the packet as payload. | ||
| 327 | + */ | ||
| 328 | +class SrsPacket | ||
| 329 | +{ | ||
| 330 | +public: | ||
| 331 | + SrsPacket(); | ||
| 332 | + virtual ~SrsPacket(); | ||
| 333 | +public: | ||
| 334 | + /** | ||
| 335 | + * the subpacket can override this encode, | ||
| 336 | + * for example, video and audio will directly set the payload withou memory copy, | ||
| 337 | + * other packet which need to serialize/encode to bytes by override the | ||
| 338 | + * get_size and encode_packet. | ||
| 339 | + */ | ||
| 340 | + virtual int encode(int& size, char*& payload); | ||
| 341 | + // decode functions for concrete packet to override. | ||
| 342 | +public: | ||
| 343 | + /** | ||
| 344 | + * subpacket must override to decode packet from stream. | ||
| 345 | + * @remark never invoke the super.decode, it always failed. | ||
| 346 | + */ | ||
| 347 | + virtual int decode(SrsStream* stream); | ||
| 348 | + // encode functions for concrete packet to override. | ||
| 349 | +public: | ||
| 350 | + /** | ||
| 351 | + * the cid(chunk id) specifies the chunk to send data over. | ||
| 352 | + * generally, each message perfer some cid, for example, | ||
| 353 | + * all protocol control messages perfer RTMP_CID_ProtocolControl, | ||
| 354 | + * SrsSetWindowAckSizePacket is protocol control message. | ||
| 355 | + */ | ||
| 356 | + virtual int get_prefer_cid(); | ||
| 357 | + /** | ||
| 358 | + * subpacket must override to provide the right message type. | ||
| 359 | + * the message type set the RTMP message type in header. | ||
| 360 | + */ | ||
| 361 | + virtual int get_message_type(); | ||
| 362 | +protected: | ||
| 363 | + /** | ||
| 364 | + * subpacket can override to calc the packet size. | ||
| 365 | + */ | ||
| 366 | + virtual int get_size(); | ||
| 367 | + /** | ||
| 368 | + * subpacket can override to encode the payload to stream. | ||
| 369 | + * @remark never invoke the super.encode_packet, it always failed. | ||
| 370 | + */ | ||
| 371 | + virtual int encode_packet(SrsStream* stream); | ||
| 372 | +}; | ||
| 373 | + | ||
| 374 | +/** | ||
| 321 | * the protocol provides the rtmp-message-protocol services, | 375 | * the protocol provides the rtmp-message-protocol services, |
| 322 | * to recv RTMP message from RTMP chunk stream, | 376 | * to recv RTMP message from RTMP chunk stream, |
| 323 | * and to send out RTMP message over RTMP chunk stream. | 377 | * and to send out RTMP message over RTMP chunk stream. |
| @@ -663,60 +717,6 @@ public: | @@ -663,60 +717,6 @@ public: | ||
| 663 | }; | 717 | }; |
| 664 | 718 | ||
| 665 | /** | 719 | /** |
| 666 | -* the decoded message payload. | ||
| 667 | -* @remark we seperate the packet from message, | ||
| 668 | -* for the packet focus on logic and domain data, | ||
| 669 | -* the message bind to the protocol and focus on protocol, such as header. | ||
| 670 | -* we can merge the message and packet, using OOAD hierachy, packet extends from message, | ||
| 671 | -* it's better for me to use components -- the message use the packet as payload. | ||
| 672 | -*/ | ||
| 673 | -class SrsPacket | ||
| 674 | -{ | ||
| 675 | -public: | ||
| 676 | - SrsPacket(); | ||
| 677 | - virtual ~SrsPacket(); | ||
| 678 | -public: | ||
| 679 | - /** | ||
| 680 | - * the subpacket can override this encode, | ||
| 681 | - * for example, video and audio will directly set the payload withou memory copy, | ||
| 682 | - * other packet which need to serialize/encode to bytes by override the | ||
| 683 | - * get_size and encode_packet. | ||
| 684 | - */ | ||
| 685 | - virtual int encode(int& size, char*& payload); | ||
| 686 | -// decode functions for concrete packet to override. | ||
| 687 | -public: | ||
| 688 | - /** | ||
| 689 | - * subpacket must override to decode packet from stream. | ||
| 690 | - * @remark never invoke the super.decode, it always failed. | ||
| 691 | - */ | ||
| 692 | - virtual int decode(SrsStream* stream); | ||
| 693 | -// encode functions for concrete packet to override. | ||
| 694 | -public: | ||
| 695 | - /** | ||
| 696 | - * the cid(chunk id) specifies the chunk to send data over. | ||
| 697 | - * generally, each message perfer some cid, for example, | ||
| 698 | - * all protocol control messages perfer RTMP_CID_ProtocolControl, | ||
| 699 | - * SrsSetWindowAckSizePacket is protocol control message. | ||
| 700 | - */ | ||
| 701 | - virtual int get_prefer_cid(); | ||
| 702 | - /** | ||
| 703 | - * subpacket must override to provide the right message type. | ||
| 704 | - * the message type set the RTMP message type in header. | ||
| 705 | - */ | ||
| 706 | - virtual int get_message_type(); | ||
| 707 | -protected: | ||
| 708 | - /** | ||
| 709 | - * subpacket can override to calc the packet size. | ||
| 710 | - */ | ||
| 711 | - virtual int get_size(); | ||
| 712 | - /** | ||
| 713 | - * subpacket can override to encode the payload to stream. | ||
| 714 | - * @remark never invoke the super.encode_packet, it always failed. | ||
| 715 | - */ | ||
| 716 | - virtual int encode_packet(SrsStream* stream); | ||
| 717 | -}; | ||
| 718 | - | ||
| 719 | -/** | ||
| 720 | * 4.1.1. connect | 720 | * 4.1.1. connect |
| 721 | * The client sends the connect command to the server to request | 721 | * The client sends the connect command to the server to request |
| 722 | * connection to a server application instance. | 722 | * connection to a server application instance. |
-
请 注册 或 登录 后发表评论