From add0f369c598568acded6cbf6aa8e8b443e0d44a Mon Sep 17 00:00:00 2001 From: "Mr. Li" Date: Sat, 9 Sep 2023 08:57:40 +0800 Subject: [PATCH] Fix RBSP issue, where 0x03 should be removed. v5.0.178 v6.0.75 (#3597) ISO_IEC_14496-10-AVC-2012.pdf, page 65 7.4.1.1 Encapsulation of an SODB within an RBSP (informative) ... 00 00 03 xx, the 03 byte should be drop where xx represents any 2 bit pattern: 00, 01, 10, or 11. --------- Co-authored-by: john Co-authored-by: chundonglinlin Co-authored-by: winlin --- trunk/conf/full.conf | 4 - trunk/conf/security.deny.publish.conf | 1 - trunk/doc/CHANGELOG.md | 2 + trunk/src/core/srs_core_version5.hpp | 2 +- trunk/src/core/srs_core_version6.hpp | 2 +- trunk/src/kernel/srs_kernel_codec.cpp | 125 ++++++--------- trunk/src/utest/srs_utest_kernel.cpp | 76 +++++++++- trunk/src/utest/srs_utest_kernel.hpp | 3 + trunk/src/utest/srs_utest_kernel2.cpp | 210 ++++++++++++++++++++++++++ 9 files changed, 339 insertions(+), 86 deletions(-) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 10a9f1db98..cfd4259c6e 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -1328,7 +1328,6 @@ vhost stream.control.com { vhost publish.srs.com { # the config for FMLE/Flash publisher, which push RTMP to SRS. publish { - # about MR, read https://github.com/ossrs/srs/issues/241 # when enabled the mr, SRS will read as large as possible. # Overwrite by env SRS_VHOST_PUBLISH_MR for all vhosts. # default: off @@ -1401,7 +1400,6 @@ vhost refer.anti_suck.com { # the security to allow or deny clients. vhost security.srs.com { # security for host to allow or deny clients. - # @see https://github.com/ossrs/srs/issues/211 security { # whether enable the security for vhost. # default: off @@ -1781,7 +1779,6 @@ vhost hls.srs.com { # the hls m3u8 target duration ratio, # EXT-X-TARGETDURATION = hls_td_ratio * hls_fragment // init # EXT-X-TARGETDURATION = max(ts_duration, EXT-X-TARGETDURATION) // for each ts - # @see https://github.com/ossrs/srs/issues/304#issuecomment-74000081 # Overwrite by env SRS_VHOST_HLS_HLS_TD_RATIO for all vhosts. # default: 1.5 hls_td_ratio 1.5; @@ -1800,7 +1797,6 @@ vhost hls.srs.com { # ignore, disable the hls. # disconnect, require encoder republish. # continue, ignore failed try to continue output hls. - # @see https://github.com/ossrs/srs/issues/264 # Overwrite by env SRS_VHOST_HLS_HLS_ON_ERROR for all vhosts. # default: continue hls_on_error continue; diff --git a/trunk/conf/security.deny.publish.conf b/trunk/conf/security.deny.publish.conf index fc2a2e809d..574b5fcec2 100644 --- a/trunk/conf/security.deny.publish.conf +++ b/trunk/conf/security.deny.publish.conf @@ -1,5 +1,4 @@ # security config for srs, allow play and deny publish. -# @see https://github.com/ossrs/srs/issues/211#issuecomment-68507035 # @see full.conf for detail config. listen 1935; diff --git a/trunk/doc/CHANGELOG.md b/trunk/doc/CHANGELOG.md index 7713cb1ecf..f0538ec957 100644 --- a/trunk/doc/CHANGELOG.md +++ b/trunk/doc/CHANGELOG.md @@ -7,6 +7,7 @@ The changelog for SRS. ## SRS 6.0 Changelog +* v6.0, 2023-09-08, Merge [#3597](https://github.com/ossrs/srs/pull/3597): Fix RBSP stream parsing bug, should drop 0x03. v6.0.75 (#3597) * v6.0, 2023-09-08, Merge [#3794](https://github.com/ossrs/srs/pull/3794): Support SRS Stack token for authentication. v6.0.74 (#3794) * v6.0, 2023-09-07, Merge [#3795](https://github.com/ossrs/srs/pull/3795): Fix dash crash if format not supported. v6.0.73 (#3795) * v6.0, 2023-08-30, Merge [#3776](https://github.com/ossrs/srs/pull/3776): Compile: Add aarch64 to the conditions of use of the cbrt function. v6.0.72 (#3776) @@ -86,6 +87,7 @@ The changelog for SRS. ## SRS 5.0 Changelog +* v5.0, 2023-09-08, Merge [#3597](https://github.com/ossrs/srs/pull/3597): Fix RBSP stream parsing bug, should drop 0x03. v5.0.178 (#3597) * v5.0, 2023-09-07, Merge [#3795](https://github.com/ossrs/srs/pull/3795): Fix dash crash if format not supported. v5.0.177 (#3795) * v5.0, 2023-08-30, Merge [#3779](https://github.com/ossrs/srs/pull/3779): Support HTTP-API for fetching reload result. v5.0.176 (#3779) * v5.0, 2023-08-28, Merge [#3503](https://github.com/ossrs/srs/pull/3503): SrsContextId assignment can be improved without create a duplicated one. v5.0.175 (#3503) diff --git a/trunk/src/core/srs_core_version5.hpp b/trunk/src/core/srs_core_version5.hpp index 78c2ca80e9..163f2a2a67 100644 --- a/trunk/src/core/srs_core_version5.hpp +++ b/trunk/src/core/srs_core_version5.hpp @@ -9,6 +9,6 @@ #define VERSION_MAJOR 5 #define VERSION_MINOR 0 -#define VERSION_REVISION 177 +#define VERSION_REVISION 178 #endif diff --git a/trunk/src/core/srs_core_version6.hpp b/trunk/src/core/srs_core_version6.hpp index 6883135174..e055cff175 100644 --- a/trunk/src/core/srs_core_version6.hpp +++ b/trunk/src/core/srs_core_version6.hpp @@ -9,6 +9,6 @@ #define VERSION_MAJOR 6 #define VERSION_MINOR 0 -#define VERSION_REVISION 74 +#define VERSION_REVISION 75 #endif diff --git a/trunk/src/kernel/srs_kernel_codec.cpp b/trunk/src/kernel/srs_kernel_codec.cpp index 727a9e7c44..cf4ec6cbe7 100644 --- a/trunk/src/kernel/srs_kernel_codec.cpp +++ b/trunk/src/kernel/srs_kernel_codec.cpp @@ -867,6 +867,44 @@ bool SrsFormat::is_avc_sequence_header() && video && video->avc_packet_type == SrsVideoAvcFrameTraitSequenceHeader; } +// Remove the emulation bytes from stream, and return num of bytes of the rbsp. +int srs_rbsp_remove_emulation_bytes(SrsBuffer* stream, std::vector& rbsp) +{ + int nb_rbsp = 0; + while (!stream->empty()) { + rbsp[nb_rbsp] = stream->read_1bytes(); + + // .. 00 00 03 xx, the 03 byte should be drop where xx represents any + // 2 bit pattern: 00, 01, 10, or 11. + if (nb_rbsp >= 2 && rbsp[nb_rbsp - 2] == 0 && rbsp[nb_rbsp - 1] == 0 && rbsp[nb_rbsp] == 3) { + // read 1byte more. + if (stream->empty()) { + nb_rbsp++; + break; + } + + // |---------------------|----------------------------| + // | rbsp | nalu with emulation bytes | + // |---------------------|----------------------------| + // | 0x00 0x00 0x00 | 0x00 0x00 0x03 0x00 | + // | 0x00 0x00 0x01 | 0x00 0x00 0x03 0x01 | + // | 0x00 0x00 0x02 | 0x00 0x00 0x03 0x02 | + // | 0x00 0x00 0x03 | 0x00 0x00 0x03 0x03 | + // | 0x00 0x00 0x03 0x04 | 0x00 0x00 0x03 0x04 | + // |---------------------|----------------------------| + uint8_t ev = stream->read_1bytes(); + if (ev > 3) { + nb_rbsp++; + } + rbsp[nb_rbsp] = ev; + } + + nb_rbsp++; + } + + return nb_rbsp; +} + srs_error_t SrsFormat::video_avc_demux(SrsBuffer* stream, int64_t timestamp) { srs_error_t err = srs_success; @@ -1224,26 +1262,9 @@ srs_error_t SrsFormat::hevc_demux_vps(SrsBuffer *stream) // decode the rbsp from vps. // rbsp[ i ] a raw byte sequence payload is specified as an ordered sequence of bytes. - std::vector rbsp(stream->size()); + std::vector rbsp(stream->size()); - int nb_rbsp = 0; - while (!stream->empty()) { - rbsp[nb_rbsp] = stream->read_1bytes(); - - // XX 00 00 03 XX, the 03 byte should be drop. - if (nb_rbsp > 2 && rbsp[nb_rbsp - 2] == 0 && rbsp[nb_rbsp - 1] == 0 && rbsp[nb_rbsp] == 3) { - // read 1byte more. - if (stream->empty()) { - break; - } - rbsp[nb_rbsp] = stream->read_1bytes(); - nb_rbsp++; - - continue; - } - - nb_rbsp++; - } + int nb_rbsp = srs_rbsp_remove_emulation_bytes(stream, rbsp); return hevc_demux_vps_rbsp((char*)&rbsp[0], nb_rbsp); } @@ -1370,26 +1391,9 @@ srs_error_t SrsFormat::hevc_demux_sps(SrsBuffer *stream) // decode the rbsp from sps. // rbsp[ i ] a raw byte sequence payload is specified as an ordered sequence of bytes. - std::vector rbsp(stream->size()); + std::vector rbsp(stream->size()); - int nb_rbsp = 0; - while (!stream->empty()) { - rbsp[nb_rbsp] = stream->read_1bytes(); - - // XX 00 00 03 XX, the 03 byte should be drop. - if (nb_rbsp > 2 && rbsp[nb_rbsp - 2] == 0 && rbsp[nb_rbsp - 1] == 0 && rbsp[nb_rbsp] == 3) { - // read 1byte more. - if (stream->empty()) { - break; - } - rbsp[nb_rbsp] = stream->read_1bytes(); - nb_rbsp++; - - continue; - } - - nb_rbsp++; - } + int nb_rbsp = srs_rbsp_remove_emulation_bytes(stream, rbsp); return hevc_demux_sps_rbsp((char*)&rbsp[0], nb_rbsp); } @@ -1571,28 +1575,11 @@ srs_error_t SrsFormat::hevc_demux_pps(SrsBuffer *stream) // nuh_layer_id + nuh_temporal_id_plus1 stream->skip(1); - // decode the rbsp from sps. + // decode the rbsp from pps. // rbsp[ i ] a raw byte sequence payload is specified as an ordered sequence of bytes. - std::vector rbsp(stream->size()); - - int nb_rbsp = 0; - while (!stream->empty()) { - rbsp[nb_rbsp] = stream->read_1bytes(); - - // XX 00 00 03 XX, the 03 byte should be drop. - if (nb_rbsp > 2 && rbsp[nb_rbsp - 2] == 0 && rbsp[nb_rbsp - 1] == 0 && rbsp[nb_rbsp] == 3) { - // read 1byte more. - if (stream->empty()) { - break; - } - rbsp[nb_rbsp] = stream->read_1bytes(); - nb_rbsp++; + std::vector rbsp(stream->size()); - continue; - } - - nb_rbsp++; - } + int nb_rbsp = srs_rbsp_remove_emulation_bytes(stream, rbsp); return hevc_demux_pps_rbsp((char*)&rbsp[0], nb_rbsp); } @@ -2270,31 +2257,13 @@ srs_error_t SrsFormat::avc_demux_sps() // decode the rbsp from sps. // rbsp[ i ] a raw byte sequence payload is specified as an ordered sequence of bytes. - std::vector rbsp(vcodec->sequenceParameterSetNALUnit.size()); + std::vector rbsp(vcodec->sequenceParameterSetNALUnit.size()); - int nb_rbsp = 0; - while (!stream.empty()) { - rbsp[nb_rbsp] = stream.read_1bytes(); - - // XX 00 00 03 XX, the 03 byte should be drop. - if (nb_rbsp > 2 && rbsp[nb_rbsp - 2] == 0 && rbsp[nb_rbsp - 1] == 0 && rbsp[nb_rbsp] == 3) { - // read 1byte more. - if (stream.empty()) { - break; - } - rbsp[nb_rbsp] = stream.read_1bytes(); - nb_rbsp++; - - continue; - } - - nb_rbsp++; - } + int nb_rbsp = srs_rbsp_remove_emulation_bytes(&stream, rbsp); return avc_demux_sps_rbsp((char*)&rbsp[0], nb_rbsp); } - srs_error_t SrsFormat::avc_demux_sps_rbsp(char* rbsp, int nb_rbsp) { srs_error_t err = srs_success; diff --git a/trunk/src/utest/srs_utest_kernel.cpp b/trunk/src/utest/srs_utest_kernel.cpp index f2b2e32b17..862c593815 100644 --- a/trunk/src/utest/srs_utest_kernel.cpp +++ b/trunk/src/utest/srs_utest_kernel.cpp @@ -3887,6 +3887,80 @@ VOID TEST(KernelCodecTest, VideoFormatSepcial) } } +VOID TEST(KernelCoecTest, VideoFormatRbspData) +{ + if (true) { + vector nalu = { + 0x25, 0x00, 0x1f, 0xe2, 0x22, 0x00, 0x00, 0x02, 0x00, 0x00, 0x80, 0xab, 0xff + }; + + SrsBuffer b((char*)nalu.data(), nalu.size()); + vector rbsp(nalu.size()); + int nb_rbsp = srs_rbsp_remove_emulation_bytes(&b, rbsp); + + ASSERT_EQ(nb_rbsp, (int)nalu.size()); + EXPECT_TRUE(srs_bytes_equals(rbsp.data(), nalu.data(), nb_rbsp)); + } + + if (true) { + SrsFormat f; + vector nalu = { + 0x25, 0x00, 0x1f, 0xe2, 0x22, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x80, 0xab, 0xff + }; + vector expect = { + 0x25, 0x00, 0x1f, 0xe2, 0x22, 0x00, 0x00, 0x02, 0x00, 0x00, 0x80, 0xab, 0xff + }; + + // |----------------|----------------------------| + // | rbsp | nalu with emulation bytes | + // |----------------|----------------------------| + // | 0x00 0x00 0x00 | 0x00 0x00 0x03 0x00 | + // | 0x00 0x00 0x01 | 0x00 0x00 0x03 0x01 | + // | 0x00 0x00 0x02 | 0x00 0x00 0x03 0x02 | + // | 0x00 0x00 0x03 | 0x00 0x00 0x03 0x03 | + // |----------------|----------------------------| + for (int i = 0; i <= 3; ++i) { + nalu[8] = uint8_t(i); + expect[7] = uint8_t(i); + + SrsBuffer b((char*)nalu.data(), nalu.size()); + vector rbsp(nalu.size()); + int nb_rbsp = srs_rbsp_remove_emulation_bytes(&b, rbsp); + + ASSERT_EQ(nb_rbsp, (int)expect.size()); + EXPECT_TRUE(srs_bytes_equals(rbsp.data(), expect.data(), nb_rbsp)); + } + + // 0x00 0x00 0x04 ~ 0x00 0x00 0xFF, no need to add emulation bytes. + for (int i = 4; i <= 0xff; ++i) { + nalu[8] = uint8_t(i); + + SrsBuffer b((char*)nalu.data(), nalu.size()); + vector rbsp(nalu.size()); + int nb_rbsp = srs_rbsp_remove_emulation_bytes(&b, rbsp); + + ASSERT_EQ(nb_rbsp, (int)nalu.size()); + EXPECT_TRUE(srs_bytes_equals(rbsp.data(), nalu.data(), nb_rbsp)); + } + } + + if (true) { + vector nalu = { + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x04 + }; + vector expect = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x04 + }; + + SrsBuffer b((char*)nalu.data(), nalu.size()); + vector rbsp(nalu.size()); + int nb_rbsp = srs_rbsp_remove_emulation_bytes(&b, rbsp); + + ASSERT_EQ(nb_rbsp, (int)expect.size()); + EXPECT_TRUE(srs_bytes_equals(rbsp.data(), expect.data(), nb_rbsp)); + } +} + VOID TEST(KernelCodecTest, VideoFormat) { srs_error_t err; @@ -6346,4 +6420,4 @@ VOID TEST(KernelUtilityTest, Base64Decode) HELPER_EXPECT_FAILED(srs_av_base64_decode("YWRtaW46YWRtaW", plaintext)); EXPECT_STRNE("admin:admin", plaintext.c_str()); } -} \ No newline at end of file +} diff --git a/trunk/src/utest/srs_utest_kernel.hpp b/trunk/src/utest/srs_utest_kernel.hpp index ef93f437f9..5f4cbd56fb 100644 --- a/trunk/src/utest/srs_utest_kernel.hpp +++ b/trunk/src/utest/srs_utest_kernel.hpp @@ -21,6 +21,7 @@ #include #include #include +#include class MockSrsFile { @@ -155,5 +156,7 @@ class MockPsHandler : public ISrsPsMessageHandler MockPsHandler* clear(); }; +extern int srs_rbsp_remove_emulation_bytes(SrsBuffer* stream, std::vector& rbsp); + #endif diff --git a/trunk/src/utest/srs_utest_kernel2.cpp b/trunk/src/utest/srs_utest_kernel2.cpp index ecaf4a9d15..42ed42a50f 100644 --- a/trunk/src/utest/srs_utest_kernel2.cpp +++ b/trunk/src/utest/srs_utest_kernel2.cpp @@ -526,3 +526,213 @@ VOID TEST(KernelCodecTest, VideoFormatSepcialAsan_DJI_M30) memcpy(data, "\x27\x01\x00\x00\x00\x00\x00\x00\x00", sizeof(data)); HELPER_EXPECT_SUCCESS(f.on_video(0, data, sizeof(data))); } + +VOID TEST(KernelCodecTest, VideoFormatRbspSimple) +{ + // |---------------------|----------------------------| + // | rbsp | nalu with emulation bytes | + // |---------------------|----------------------------| + // | 0x00 0x00 0x00 | 0x00 0x00 0x03 0x00 | + // | 0x00 0x00 0x01 | 0x00 0x00 0x03 0x01 | + // | 0x00 0x00 0x02 | 0x00 0x00 0x03 0x02 | + // | 0x00 0x00 0x03 | 0x00 0x00 0x03 0x03 | + // | 0x00 0x00 0x03 0x04 | 0x00 0x00 0x03 0x04 | + // |---------------------|----------------------------| + if (true) { + vector nalu = {0x00, 0x00, 0x03, 0x00}; + vector expect = {0x00, 0x00, 0x00}; + + vector rbsp(nalu.size()); + SrsBuffer b((char*)nalu.data(), nalu.size()); + int nb_rbsp = srs_rbsp_remove_emulation_bytes(&b, rbsp); + + ASSERT_EQ(nb_rbsp, (int)expect.size()); + EXPECT_TRUE(srs_bytes_equals(rbsp.data(), expect.data(), nb_rbsp)); + } + + if (true) { + vector nalu = {0x00, 0x00, 0x03, 0x01}; + vector expect = {0x00, 0x00, 0x01}; + + SrsBuffer b((char*)nalu.data(), nalu.size()); + vector rbsp(nalu.size()); + int nb_rbsp = srs_rbsp_remove_emulation_bytes(&b, rbsp); + + ASSERT_EQ(nb_rbsp, (int)expect.size()); + EXPECT_TRUE(srs_bytes_equals(rbsp.data(), expect.data(), nb_rbsp)); + } + + if (true) { + vector nalu = {0x00, 0x00, 0x03, 0x02}; + vector expect = {0x00, 0x00, 0x02}; + + SrsBuffer b((char*)nalu.data(), nalu.size()); + vector rbsp(nalu.size()); + int nb_rbsp = srs_rbsp_remove_emulation_bytes(&b, rbsp); + + ASSERT_EQ(nb_rbsp, (int)expect.size()); + EXPECT_TRUE(srs_bytes_equals(rbsp.data(), expect.data(), nb_rbsp)); + } + + if (true) { + vector nalu = {0x00, 0x00, 0x03, 0x03}; + vector expect = {0x00, 0x00, 0x03}; + + SrsBuffer b((char*)nalu.data(), nalu.size()); + vector rbsp(nalu.size()); + int nb_rbsp = srs_rbsp_remove_emulation_bytes(&b, rbsp); + + ASSERT_EQ(nb_rbsp, (int)expect.size()); + EXPECT_TRUE(srs_bytes_equals(rbsp.data(), expect.data(), nb_rbsp)); + } + + if (true) { + vector nalu = {0x00, 0x00, 0x03, 0x04}; + vector expect = {0x00, 0x00, 0x03, 0x04}; + + SrsBuffer b((char*)nalu.data(), nalu.size()); + vector rbsp(nalu.size()); + int nb_rbsp = srs_rbsp_remove_emulation_bytes(&b, rbsp); + + ASSERT_EQ(nb_rbsp, (int)expect.size()); + EXPECT_TRUE(srs_bytes_equals(rbsp.data(), expect.data(), nb_rbsp)); + } + + if (true) { + vector nalu = {0x00, 0x00, 0x03, 0xff}; + vector expect = {0x00, 0x00, 0x03, 0xff}; + + SrsBuffer b((char*)nalu.data(), nalu.size()); + vector rbsp(nalu.size()); + int nb_rbsp = srs_rbsp_remove_emulation_bytes(&b, rbsp); + + ASSERT_EQ(nb_rbsp, (int)expect.size()); + EXPECT_TRUE(srs_bytes_equals(rbsp.data(), expect.data(), nb_rbsp)); + } +} + +VOID TEST(KernelCodecTest, VideoFormatRbspEdge) +{ + if (true) { + vector nalu = {0x00, 0x00, 0x03}; + vector expect = {0x00, 0x00, 0x03}; + + vector rbsp(nalu.size()); + SrsBuffer b((char*)nalu.data(), nalu.size()); + int nb_rbsp = srs_rbsp_remove_emulation_bytes(&b, rbsp); + + ASSERT_EQ(nb_rbsp, (int)expect.size()); + EXPECT_TRUE(srs_bytes_equals(rbsp.data(), expect.data(), nb_rbsp)); + } + + if (true) { + vector nalu = {0xff, 0x00, 0x00, 0x03}; + vector expect = {0xff, 0x00, 0x00, 0x03}; + + vector rbsp(nalu.size()); + SrsBuffer b((char*)nalu.data(), nalu.size()); + int nb_rbsp = srs_rbsp_remove_emulation_bytes(&b, rbsp); + + ASSERT_EQ(nb_rbsp, (int)expect.size()); + EXPECT_TRUE(srs_bytes_equals(rbsp.data(), expect.data(), nb_rbsp)); + } + + for (uint16_t v = 0x01; v <= 0xff; v++) { + vector nalu = {(uint8_t)v, 0x00, 0x00, 0x03}; + vector expect = {(uint8_t)v, 0x00, 0x00, 0x03}; + + vector rbsp(nalu.size()); + SrsBuffer b((char*)nalu.data(), nalu.size()); + int nb_rbsp = srs_rbsp_remove_emulation_bytes(&b, rbsp); + + ASSERT_EQ(nb_rbsp, (int)expect.size()); + EXPECT_TRUE(srs_bytes_equals(rbsp.data(), expect.data(), nb_rbsp)); + } +} + +VOID TEST(KernelCodecTest, VideoFormatRbspNormal) +{ + for (uint16_t v = 0x01; v <= 0xff; v++) { + vector nalu = {0x00, (uint8_t)v, 0x03, 0x00}; + vector expect = {0x00, (uint8_t)v, 0x03, 0x00}; + + vector rbsp(nalu.size()); + SrsBuffer b((char*)nalu.data(), nalu.size()); + int nb_rbsp = srs_rbsp_remove_emulation_bytes(&b, rbsp); + + ASSERT_EQ(nb_rbsp, (int)expect.size()); + EXPECT_TRUE(srs_bytes_equals(rbsp.data(), expect.data(), nb_rbsp)); + } + + for (uint16_t v = 0x01; v <= 0xff; v++) { + vector nalu = {(uint8_t)v, 0x00, 0x03, 0x00}; + vector expect = {(uint8_t)v, 0x00, 0x03, 0x00}; + + vector rbsp(nalu.size()); + SrsBuffer b((char*)nalu.data(), nalu.size()); + int nb_rbsp = srs_rbsp_remove_emulation_bytes(&b, rbsp); + + ASSERT_EQ(nb_rbsp, (int)expect.size()); + EXPECT_TRUE(srs_bytes_equals(rbsp.data(), expect.data(), nb_rbsp)); + } + + for (uint16_t v = 0x00; v <= 0xff; v++) { + vector nalu = {0x00, 0x00, (uint8_t)v}; + vector expect = {0x00, 0x00, (uint8_t)v}; + + vector rbsp(nalu.size()); + SrsBuffer b((char*)nalu.data(), nalu.size()); + int nb_rbsp = srs_rbsp_remove_emulation_bytes(&b, rbsp); + + ASSERT_EQ(nb_rbsp, (int)expect.size()); + EXPECT_TRUE(srs_bytes_equals(rbsp.data(), expect.data(), nb_rbsp)); + } + + for (uint16_t v = 0x00; v <= 0xff; v++) { + vector nalu = {0x00, (uint8_t)v}; + vector expect = {0x00, (uint8_t)v}; + + vector rbsp(nalu.size()); + SrsBuffer b((char*)nalu.data(), nalu.size()); + int nb_rbsp = srs_rbsp_remove_emulation_bytes(&b, rbsp); + + ASSERT_EQ(nb_rbsp, (int)expect.size()); + EXPECT_TRUE(srs_bytes_equals(rbsp.data(), expect.data(), nb_rbsp)); + } + + for (uint16_t v = 0x00; v <= 0xff; v++) { + vector nalu = {(uint8_t)v}; + vector expect = {(uint8_t)v}; + + vector rbsp(nalu.size()); + SrsBuffer b((char*)nalu.data(), nalu.size()); + int nb_rbsp = srs_rbsp_remove_emulation_bytes(&b, rbsp); + + ASSERT_EQ(nb_rbsp, (int)expect.size()); + EXPECT_TRUE(srs_bytes_equals(rbsp.data(), expect.data(), nb_rbsp)); + } + + for (uint16_t v = 0x00; v <= 0xff; v++) { + vector nalu = {(uint8_t)v, (uint8_t)v}; + vector expect = {(uint8_t)v, (uint8_t)v}; + + vector rbsp(nalu.size()); + SrsBuffer b((char*)nalu.data(), nalu.size()); + int nb_rbsp = srs_rbsp_remove_emulation_bytes(&b, rbsp); + + ASSERT_EQ(nb_rbsp, (int)expect.size()); + EXPECT_TRUE(srs_bytes_equals(rbsp.data(), expect.data(), nb_rbsp)); + } + + for (uint16_t v = 0x00; v <= 0xff; v++) { + vector nalu = {(uint8_t)v, (uint8_t)v, (uint8_t)v}; + vector expect = {(uint8_t)v, (uint8_t)v, (uint8_t)v}; + + vector rbsp(nalu.size()); + SrsBuffer b((char*)nalu.data(), nalu.size()); + int nb_rbsp = srs_rbsp_remove_emulation_bytes(&b, rbsp); + + ASSERT_EQ(nb_rbsp, (int)expect.size()); + EXPECT_TRUE(srs_bytes_equals(rbsp.data(), expect.data(), nb_rbsp)); + } +}