diff --git a/README.md b/README.md index a06dda986..120af1dc7 100755 --- a/README.md +++ b/README.md @@ -145,6 +145,7 @@ For previous versions, please read: ## V3 changes +* v3.0, 2019-12-18, For [#1042][bug #1042], add test for RAW AVC protocol. * v3.0, 2019-12-18, Detect whether flash enabled for srs-player. 3.0.73 * v3.0, 2019-12-17, Fix HTTP CORS bug when sending response for OPTIONS. 3.0.72 * v3.0, 2019-12-17, Enhance HTTP response write for final_request. diff --git a/trunk/auto/options.sh b/trunk/auto/options.sh index d938fb52c..8921ecadf 100755 --- a/trunk/auto/options.sh +++ b/trunk/auto/options.sh @@ -19,7 +19,7 @@ SRS_HDS=NO SRS_NGINX=NO SRS_FFMPEG_TOOL=NO SRS_LIBRTMP=NO -SRS_RESEARCH=YES +SRS_RESEARCH=NO SRS_UTEST=YES SRS_GPERF=NO # Performance test: tcmalloc SRS_GPERF_MC=NO # Performance test: gperf memory check diff --git a/trunk/configure b/trunk/configure index 000f60975..16e85a6c5 100755 --- a/trunk/configure +++ b/trunk/configure @@ -315,7 +315,8 @@ fi # utest, the unit-test cases of srs, base on gtest1.6 if [ $SRS_UTEST = YES ]; then MODULE_FILES=("srs_utest" "srs_utest_amf0" "srs_utest_protocol" "srs_utest_kernel" "srs_utest_core" - "srs_utest_config" "srs_utest_rtmp" "srs_utest_http" "srs_utest_reload" "srs_utest_service" "srs_utest_app") + "srs_utest_config" "srs_utest_rtmp" "srs_utest_http" "srs_utest_avc" "srs_utest_reload" + "srs_utest_service" "srs_utest_app") ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSSLRoot}) ModuleLibFiles=(${LibSTfile} ${LibSSLfile}) MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP") diff --git a/trunk/src/protocol/srs_raw_avc.cpp b/trunk/src/protocol/srs_raw_avc.cpp index 94f90999e..9ff69bcff 100644 --- a/trunk/src/protocol/srs_raw_avc.cpp +++ b/trunk/src/protocol/srs_raw_avc.cpp @@ -107,34 +107,22 @@ srs_error_t SrsRawH264Stream::sps_demux(char* frame, int nb_frame, string& sps) if (nb_frame < 4) { return err; } - - sps = ""; - if (nb_frame > 0) { - sps.append(frame, nb_frame); - } - - // should never be empty. - if (sps.empty()) { - return srs_error_new(ERROR_STREAM_CASTER_AVC_SPS, "no sps"); - } - + + sps = string(frame, nb_frame); + return err; } srs_error_t SrsRawH264Stream::pps_demux(char* frame, int nb_frame, string& pps) { srs_error_t err = srs_success; - - pps = ""; - if (nb_frame > 0) { - pps.append(frame, nb_frame); - } - - // should never be empty. - if (pps.empty()) { + + if (nb_frame <= 0) { return srs_error_new(ERROR_STREAM_CASTER_AVC_PPS, "no pps"); } - + + pps = string(frame, nb_frame); + return err; } diff --git a/trunk/src/utest/srs_utest_avc.cpp b/trunk/src/utest/srs_utest_avc.cpp new file mode 100644 index 000000000..b0ca629e9 --- /dev/null +++ b/trunk/src/utest/srs_utest_avc.cpp @@ -0,0 +1,218 @@ +/* +The MIT License (MIT) + +Copyright (c) 2013-2019 Winlin + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#include + +#include +#include +#include +#include + +VOID TEST(SrsH264Test, ParseAnnexb) +{ + srs_error_t err; + + // Multiple frames. + if (true) { + SrsRawH264Stream h; + + uint8_t buf[] = { + 0, 0, 1, 0xd, 0xa, 0xf, 0, 0, 1, 0xa, + }; + SrsBuffer b((char*)buf, sizeof(buf)); + + char* frame = NULL; int nb_frame = 0; + HELPER_ASSERT_SUCCESS(h.annexb_demux(&b, &frame, &nb_frame)); + EXPECT_EQ(3, nb_frame); + EXPECT_EQ((char*)(buf+3), frame); + + HELPER_ASSERT_SUCCESS(h.annexb_demux(&b, &frame, &nb_frame)); + EXPECT_EQ(1, nb_frame); + EXPECT_EQ((char*)(buf+9), frame); + } + + // N prefix case, should success. + if (true) { + SrsRawH264Stream h; + + uint8_t buf[] = { + 0, 0, 0, 1, 0xd, 0xa, 0xf, 0xa, + }; + SrsBuffer b((char*)buf, sizeof(buf)); + + char* frame = NULL; int nb_frame = 0; + HELPER_ASSERT_SUCCESS(h.annexb_demux(&b, &frame, &nb_frame)); + EXPECT_EQ(4, nb_frame); + EXPECT_EQ((char*)(buf+4), frame); + } + + // No prefix, should fail and return an empty frame. + if (true) { + SrsRawH264Stream h; + + uint8_t buf[] = { + 0, 0, 2, 0xd, 0xa, 0xf, 0xa, + }; + SrsBuffer b((char*)buf, sizeof(buf)); + + char* frame = NULL; int nb_frame = 0; + HELPER_ASSERT_FAILED(h.annexb_demux(&b, &frame, &nb_frame)); + EXPECT_EQ(0, nb_frame); + } + + // No prefix, should fail and return an empty frame. + if (true) { + SrsRawH264Stream h; + + uint8_t buf[] = { + 0, 1, 0xd, 0xa, 0xf, 0xa, + }; + SrsBuffer b((char*)buf, sizeof(buf)); + + char* frame = NULL; int nb_frame = 0; + HELPER_ASSERT_FAILED(h.annexb_demux(&b, &frame, &nb_frame)); + EXPECT_EQ(0, nb_frame); + } + + // No prefix, should fail and return an empty frame. + if (true) { + SrsRawH264Stream h; + + uint8_t buf[] = { + 0xd, 0xa, 0xf, 0xa, + }; + SrsBuffer b((char*)buf, sizeof(buf)); + + char* frame = NULL; int nb_frame = 0; + HELPER_ASSERT_FAILED(h.annexb_demux(&b, &frame, &nb_frame)); + EXPECT_EQ(0, nb_frame); + } + + // Normal case, should success. + if (true) { + SrsRawH264Stream h; + + uint8_t buf[] = { + 0, 0, 1, 0xd, 0xa, 0xf, 0xa, + }; + SrsBuffer b((char*)buf, sizeof(buf)); + + char* frame = NULL; int nb_frame = 0; + HELPER_ASSERT_SUCCESS(h.annexb_demux(&b, &frame, &nb_frame)); + EXPECT_EQ(4, nb_frame); + EXPECT_EQ((char*)(buf+3), frame); + } +} + +VOID TEST(SrsH264Test, SequenceHeader) +{ + srs_error_t err; + + // For PPS demux. + if (true) { + SrsRawH264Stream h; + string pps; + HELPER_ASSERT_FAILED(h.pps_demux(NULL, 0, pps)); + EXPECT_TRUE(pps.empty()); + } + if (true) { + SrsRawH264Stream h; + string frame = "Hello, world!", pps; + HELPER_ASSERT_SUCCESS(h.pps_demux((char*)frame.data(), frame.length(), pps)); + EXPECT_STREQ("Hello, world!", pps.c_str()); + } + + // For SPS demux. + if (true) { + SrsRawH264Stream h; + string sps; + HELPER_ASSERT_SUCCESS(h.sps_demux(NULL, 0, sps)); + EXPECT_TRUE(sps.empty()); + } + if (true) { + SrsRawH264Stream h; + string frame = "Hello, world!", sps; + HELPER_ASSERT_SUCCESS(h.sps_demux((char*)frame.data(), frame.length(), sps)); + EXPECT_STREQ("Hello, world!", sps.c_str()); + } + + // For PPS. + if (true) { + SrsRawH264Stream h; + uint8_t frame[] = { + 0x9, + }; + EXPECT_FALSE(h.is_pps((char*)frame, sizeof(frame))); + } + if (true) { + SrsRawH264Stream h; + uint8_t frame[] = { + 0xf8, + }; + EXPECT_FALSE(h.is_pps((char*)frame, sizeof(frame))); + } + if (true) { + SrsRawH264Stream h; + uint8_t frame[] = { + 0xe8, + }; + EXPECT_TRUE(h.is_pps((char*)frame, sizeof(frame))); + } + if (true) { + SrsRawH264Stream h; + uint8_t frame[] = { + 8, + }; + EXPECT_TRUE(h.is_pps((char*)frame, sizeof(frame))); + } + + // For SPS. + if (true) { + SrsRawH264Stream h; + uint8_t frame[] = { + 0x8, + }; + EXPECT_FALSE(h.is_sps((char*)frame, sizeof(frame))); + } + if (true) { + SrsRawH264Stream h; + uint8_t frame[] = { + 0xf7, + }; + EXPECT_FALSE(h.is_sps((char*)frame, sizeof(frame))); + } + if (true) { + SrsRawH264Stream h; + uint8_t frame[] = { + 0xe7, + }; + EXPECT_TRUE(h.is_sps((char*)frame, sizeof(frame))); + } + if (true) { + SrsRawH264Stream h; + uint8_t frame[] = { + 7, + }; + EXPECT_TRUE(h.is_sps((char*)frame, sizeof(frame))); + } +} + diff --git a/trunk/src/utest/srs_utest_avc.hpp b/trunk/src/utest/srs_utest_avc.hpp new file mode 100644 index 000000000..9013781cb --- /dev/null +++ b/trunk/src/utest/srs_utest_avc.hpp @@ -0,0 +1,33 @@ +/* +The MIT License (MIT) + +Copyright (c) 2013-2019 Winlin + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef SRS_UTEST_AVC_HPP +#define SRS_UTEST_AVC_HPP + +/* +#include +*/ +#include + +#endif +