diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ac9eaa501..225a59e01 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -70,6 +70,8 @@ jobs: - name: Checkout repository uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 # Build for Ubuntu20 + - name: Build on Ubuntu20, default + run: DOCKER_BUILDKIT=1 docker build -f trunk/Dockerfile.builds --target ubuntu20-default . - name: Build on Ubuntu20, baseline run: DOCKER_BUILDKIT=1 docker build -f trunk/Dockerfile.builds --target ubuntu20-baseline . - name: Build on Ubuntu20, with all features diff --git a/trunk/Dockerfile.builds b/trunk/Dockerfile.builds index ed5c1b8d7..f02c0c7d0 100644 --- a/trunk/Dockerfile.builds +++ b/trunk/Dockerfile.builds @@ -42,6 +42,12 @@ FROM ossrs/srs:ubuntu20-cache AS ubuntu20-baseline COPY . /srs RUN cd /srs/trunk && ./configure --sanitizer=on --srt=off --gb28181=off && make +FROM ossrs/srs:ubuntu20-cache AS ubuntu20-default +COPY . /srs +# Remove the ST from cache, which build with sanitizer, but we are not by default. +RUN cd /usr/local/srs-cache/srs/trunk && rm -rf objs/Platform-*/3rdparty/st && du -sh objs/Platform-*/3rdparty/* +RUN cd /srs/trunk && ./configure && make + FROM ossrs/srs:ubuntu20-cache AS ubuntu20-all COPY . /srs RUN cd /srs/trunk && ./configure --sanitizer=on --srt=on --gb28181=on --apm=on --h265=on && make diff --git a/trunk/src/kernel/srs_kernel_utility.cpp b/trunk/src/kernel/srs_kernel_utility.cpp index 363fa2332..e1d531c18 100644 --- a/trunk/src/kernel/srs_kernel_utility.cpp +++ b/trunk/src/kernel/srs_kernel_utility.cpp @@ -567,7 +567,7 @@ srs_error_t SrsPath::unlink(std::string path) "/usr", "/var", }; - for (int i = 0; i < sizeof(forbidden) / sizeof(forbidden[0]); i++) { + for (int i = 0; i < (int)(sizeof(forbidden) / sizeof(string)); i++) { if (path == forbidden[i]) { return srs_error_new(ERROR_SYSTEM_FILE_UNLINK, "unlink forbidden %s", path.c_str()); } diff --git a/trunk/src/utest/srs_utest_ai24.cpp b/trunk/src/utest/srs_utest_ai24.cpp index 362f41cd4..233c9f07f 100644 --- a/trunk/src/utest/srs_utest_ai24.cpp +++ b/trunk/src/utest/srs_utest_ai24.cpp @@ -9,6 +9,20 @@ #include #include #include +#include +#include + +#ifdef SRS_FFMPEG_FIT +#include + +#ifdef __cplusplus +extern "C" { +#endif +#include +#ifdef __cplusplus +} +#endif +#endif using namespace std; @@ -303,3 +317,155 @@ VOID TEST(RtcAVSyncTest, ZeroTimeElapsedBetweenSRs) // Rate should remain unchanged (SDP rate) EXPECT_DOUBLE_EQ(rate_before, track.get_rate()); } + +// Test: SrsParsedPacket::copy() method +VOID TEST(ParsedPacketTest, CopyParsedPacket) +{ + srs_error_t err; + + // Create a parsed packet with sample data + SrsParsedPacket packet; + SrsVideoCodecConfig codec; + HELPER_EXPECT_SUCCESS(packet.initialize(&codec)); + + // Set packet properties + packet.dts_ = 1000; + packet.cts_ = 100; + + // Add sample data + char sample_data1[] = {0x01, 0x02, 0x03}; + char sample_data2[] = {0x04, 0x05, 0x06, 0x07}; + HELPER_EXPECT_SUCCESS(packet.add_sample(sample_data1, sizeof(sample_data1))); + HELPER_EXPECT_SUCCESS(packet.add_sample(sample_data2, sizeof(sample_data2))); + + // Copy the packet + SrsParsedPacket *copied = packet.copy(); + ASSERT_TRUE(copied != NULL); + + // Verify all fields are copied correctly + EXPECT_EQ(packet.dts_, copied->dts_); + EXPECT_EQ(packet.cts_, copied->cts_); + EXPECT_EQ(packet.codec_, copied->codec_); + EXPECT_EQ(packet.nb_samples_, copied->nb_samples_); + + // Verify samples are copied (shared pointers) + for (int i = 0; i < packet.nb_samples_; i++) { + EXPECT_EQ(packet.samples_[i].bytes_, copied->samples_[i].bytes_); + EXPECT_EQ(packet.samples_[i].size_, copied->samples_[i].size_); + } + + srs_freep(copied); +} + +// Test: SrsParsedVideoPacket::copy() method +VOID TEST(ParsedPacketTest, CopyParsedVideoPacket) +{ + srs_error_t err; + + // Create a parsed video packet with sample data + SrsParsedVideoPacket packet; + SrsVideoCodecConfig codec; + HELPER_EXPECT_SUCCESS(packet.initialize(&codec)); + + // Set packet properties + packet.dts_ = 2000; + packet.cts_ = 200; + packet.frame_type_ = SrsVideoAvcFrameTypeKeyFrame; + packet.avc_packet_type_ = SrsVideoAvcFrameTraitNALU; + packet.has_idr_ = true; + packet.has_aud_ = false; + packet.has_sps_pps_ = true; + packet.first_nalu_type_ = SrsAvcNaluTypeIDR; + + // Add sample data + uint8_t sample_data[] = {0x65, 0x88, 0x84, 0x00}; + HELPER_EXPECT_SUCCESS(packet.add_sample((char*)sample_data, sizeof(sample_data))); + + // Copy the packet + SrsParsedVideoPacket *copied = packet.copy(); + ASSERT_TRUE(copied != NULL); + + // Verify base class fields are copied + EXPECT_EQ(packet.dts_, copied->dts_); + EXPECT_EQ(packet.cts_, copied->cts_); + EXPECT_EQ(packet.codec_, copied->codec_); + EXPECT_EQ(packet.nb_samples_, copied->nb_samples_); + + // Verify video-specific fields are copied + EXPECT_EQ(packet.frame_type_, copied->frame_type_); + EXPECT_EQ(packet.avc_packet_type_, copied->avc_packet_type_); + EXPECT_EQ(packet.has_idr_, copied->has_idr_); + EXPECT_EQ(packet.has_aud_, copied->has_aud_); + EXPECT_EQ(packet.has_sps_pps_, copied->has_sps_pps_); + EXPECT_EQ(packet.first_nalu_type_, copied->first_nalu_type_); + + // Verify samples are copied (shared pointers) + for (int i = 0; i < packet.nb_samples_; i++) { + EXPECT_EQ(packet.samples_[i].bytes_, copied->samples_[i].bytes_); + EXPECT_EQ(packet.samples_[i].size_, copied->samples_[i].size_); + } + + srs_freep(copied); +} + +#ifdef SRS_FFMPEG_FIT +// Helper function to call ffmpeg_log_callback with formatted string +static void call_ffmpeg_log(int level, const char *fmt, ...) +{ + va_list vl; + va_start(vl, fmt); + SrsFFmpegLogHelper::ffmpeg_log_callback(NULL, level, fmt, vl); + va_end(vl); +} + +// Test: SrsFFmpegLogHelper::ffmpeg_log_callback() method +VOID TEST(FFmpegLogHelperTest, LogCallback) +{ + // Save original disabled state + bool original_disabled = SrsFFmpegLogHelper::disabled_; + + // Test 1: Callback should work when not disabled + SrsFFmpegLogHelper::disabled_ = false; + + // AV_LOG_WARNING level + call_ffmpeg_log(AV_LOG_WARNING, "Test warning message\n"); + + // AV_LOG_INFO level + call_ffmpeg_log(AV_LOG_INFO, "Test info message\n"); + + // AV_LOG_VERBOSE/DEBUG/TRACE levels + call_ffmpeg_log(AV_LOG_VERBOSE, "Test verbose message\n"); + call_ffmpeg_log(AV_LOG_DEBUG, "Test debug message\n"); + call_ffmpeg_log(AV_LOG_TRACE, "Test trace message\n"); + + // Test message without newline (should not strip last character) + call_ffmpeg_log(AV_LOG_INFO, "Test message without newline"); + + // Test message with newline (should strip newline) + call_ffmpeg_log(AV_LOG_INFO, "Test message with newline\n"); + + // Test 2: Callback should return early when disabled + SrsFFmpegLogHelper::disabled_ = true; + + // These calls should return immediately without processing + call_ffmpeg_log(AV_LOG_ERROR, "This should not be logged\n"); + call_ffmpeg_log(AV_LOG_WARNING, "This should not be logged\n"); + call_ffmpeg_log(AV_LOG_INFO, "This should not be logged\n"); + + // Test 3: Test edge cases + SrsFFmpegLogHelper::disabled_ = false; + + // Empty message + call_ffmpeg_log(AV_LOG_INFO, ""); + + // Very long message (should be truncated to buffer size) + std::string long_msg(5000, 'x'); + call_ffmpeg_log(AV_LOG_INFO, "%s", long_msg.c_str()); + + // Restore original disabled state + SrsFFmpegLogHelper::disabled_ = original_disabled; + + // If we reach here without crashing, the test passes + EXPECT_TRUE(true); +} +#endif