Skip to content

Commit ea1383d

Browse files
ossrs-aiwinlinvip
authored andcommitted
AI: Add utest.
1 parent bdc1be8 commit ea1383d

File tree

5 files changed

+96
-10
lines changed

5 files changed

+96
-10
lines changed

trunk/src/app/srs_app_factory.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#ifdef SRS_GB28181
1616
#include <srs_app_gb28181.hpp>
1717
#endif
18+
#include <srs_app_hls.hpp>
1819
#include <srs_app_ingest.hpp>
1920
#include <srs_app_listener.hpp>
2021
#include <srs_app_rtc_conn.hpp>
@@ -173,6 +174,11 @@ ISrsFragmentedMp4 *SrsAppFactory::create_fragmented_mp4()
173174
return new SrsFragmentedMp4();
174175
}
175176

177+
SrsHlsM4sSegment *SrsAppFactory::create_hls_m4s_segment(ISrsFileWriter *fw)
178+
{
179+
return new SrsHlsM4sSegment(fw);
180+
}
181+
176182
ISrsIpListener *SrsAppFactory::create_tcp_listener(ISrsTcpHandler *handler)
177183
{
178184
return new SrsTcpListener(handler);

trunk/src/app/srs_app_factory.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class ISrsFragment;
3535
class ISrsInitMp4;
3636
class ISrsFragmentWindow;
3737
class ISrsFragmentedMp4;
38+
class SrsHlsM4sSegment;
3839
class SrsFinalFactory;
3940
class ISrsIpListener;
4041
class ISrsTcpHandler;
@@ -89,6 +90,7 @@ class ISrsAppFactory : public ISrsKernelFactory
8990
virtual ISrsInitMp4 *create_init_mp4() = 0;
9091
virtual ISrsFragmentWindow *create_fragment_window() = 0;
9192
virtual ISrsFragmentedMp4 *create_fragmented_mp4() = 0;
93+
virtual SrsHlsM4sSegment *create_hls_m4s_segment(ISrsFileWriter *fw) = 0;
9294
virtual ISrsIpListener *create_tcp_listener(ISrsTcpHandler *handler) = 0;
9395
virtual ISrsRtcConnection *create_rtc_connection(ISrsExecRtcAsyncTask *exec, const SrsContextId &cid) = 0;
9496
virtual ISrsFFMPEG *create_ffmpeg(std::string ffmpeg_bin) = 0;
@@ -142,6 +144,7 @@ class SrsAppFactory : public ISrsAppFactory
142144
virtual ISrsInitMp4 *create_init_mp4();
143145
virtual ISrsFragmentWindow *create_fragment_window();
144146
virtual ISrsFragmentedMp4 *create_fragmented_mp4();
147+
virtual SrsHlsM4sSegment *create_hls_m4s_segment(ISrsFileWriter *fw);
145148
virtual ISrsIpListener *create_tcp_listener(ISrsTcpHandler *handler);
146149
virtual ISrsRtcConnection *create_rtc_connection(ISrsExecRtcAsyncTask *exec, const SrsContextId &cid);
147150
virtual ISrsFFMPEG *create_ffmpeg(std::string ffmpeg_bin);

trunk/src/app/srs_app_hls.cpp

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,6 @@ SrsHlsFmp4Muxer::SrsHlsFmp4Muxer()
426426
segments_ = new SrsFragmentWindow();
427427
latest_acodec_ = SrsAudioCodecIdForbidden;
428428
latest_vcodec_ = SrsVideoCodecIdForbidden;
429-
sequence_header_ = false;
430429
video_track_id_ = 0;
431430
audio_track_id_ = 0;
432431
init_mp4_ready_ = false;
@@ -796,14 +795,9 @@ srs_error_t SrsHlsFmp4Muxer::segment_open(srs_utime_t basetime)
796795
}
797796

798797
// new segment.
799-
current_ = new SrsHlsM4sSegment(writer_);
798+
current_ = app_factory_->create_hls_m4s_segment(writer_);
800799
current_->sequence_no_ = sequence_no_++;
801800

802-
if (sequence_header_) {
803-
current_->set_sequence_header(true);
804-
sequence_header_ = false;
805-
}
806-
807801
if ((err = write_hls_key()) != srs_success) {
808802
return srs_error_wrap(err, "write hls key");
809803
}
@@ -901,7 +895,6 @@ bool SrsHlsFmp4Muxer::is_segment_open()
901895

902896
srs_error_t SrsHlsFmp4Muxer::on_sequence_header()
903897
{
904-
sequence_header_ = true;
905898
return srs_success;
906899
}
907900

trunk/src/app/srs_app_hls.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -488,8 +488,6 @@ class SrsHlsFmp4Muxer
488488
// The current writing segment.
489489
SrsHlsM4sSegment *current_;
490490

491-
bool sequence_header_;
492-
493491
// clang-format off
494492
SRS_DECLARE_PRIVATE: // clang-format on
495493
// Latest audio codec, parsed from stream.

trunk/src/utest/srs_utest_ai24.cpp

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <srs_app_utility.hpp>
1616
#include <srs_kernel_codec.hpp>
1717
#include <srs_kernel_error.hpp>
18+
#include <srs_kernel_mp4.hpp>
1819
#include <srs_kernel_packet.hpp>
1920
#include <srs_kernel_rtc_rtcp.hpp>
2021
#include <srs_kernel_utility.hpp>
@@ -1416,3 +1417,88 @@ VOID TEST(HttpApiPaginationTest, ParsePagination)
14161417
EXPECT_EQ(500, count);
14171418
}
14181419
}
1420+
1421+
// Mock SrsHlsM4sSegment to capture dts passed to reap()
1422+
// Used for testing issue #4594
1423+
class MockSrsHlsM4sSegmentForBug4594 : public SrsHlsM4sSegment
1424+
{
1425+
public:
1426+
uint64_t captured_reap_dts_;
1427+
bool reap_called_;
1428+
1429+
MockSrsHlsM4sSegmentForBug4594() : SrsHlsM4sSegment(NULL), captured_reap_dts_(0), reap_called_(false) {}
1430+
virtual ~MockSrsHlsM4sSegmentForBug4594() {}
1431+
1432+
// Override reap to capture the dts parameter
1433+
virtual srs_error_t reap(uint64_t dts) {
1434+
reap_called_ = true;
1435+
captured_reap_dts_ = dts;
1436+
return srs_success;
1437+
}
1438+
};
1439+
1440+
// Mock factory to create MockSrsHlsM4sSegmentForBug4594
1441+
class MockAppFactoryForBug4594 : public SrsAppFactory
1442+
{
1443+
public:
1444+
MockSrsHlsM4sSegmentForBug4594 *mock_segment_;
1445+
1446+
MockAppFactoryForBug4594() : mock_segment_(NULL) {}
1447+
virtual ~MockAppFactoryForBug4594() {}
1448+
1449+
virtual SrsHlsM4sSegment *create_hls_m4s_segment(ISrsFileWriter *fw) {
1450+
mock_segment_ = new MockSrsHlsM4sSegmentForBug4594();
1451+
return mock_segment_;
1452+
}
1453+
};
1454+
1455+
// Test for issue #4594: SrsHlsMp4Controller::on_unpublish() passes video_dts_=0 to reap()
1456+
// for audio-only streams.
1457+
//
1458+
// When on_unpublish() is called for audio-only streams, the muxer's video_dts_ is 0 because
1459+
// write_video() is never called. This causes reap(0) to be called, leading to
1460+
// incorrect last sample duration calculation (overflow to huge values like 4294894594).
1461+
//
1462+
// @see https://github.com/ossrs/srs/issues/4594
1463+
// @see https://github.com/ossrs/srs/pull/4602
1464+
VOID TEST(HlsFmp4AudioOnlyBugTest, OnUnpublishUsesVideoDtsZeroForAudioOnly)
1465+
{
1466+
srs_error_t err;
1467+
1468+
// Create SrsHlsMp4Controller - the entry point for HLS fMP4
1469+
SrsHlsMp4Controller controller;
1470+
1471+
// Access the internal muxer
1472+
SrsHlsFmp4Muxer *muxer = controller.muxer_;
1473+
1474+
// Set up mock request (required by do_segment_close for async hooks)
1475+
MockRequest mock_req("test_vhost", "live", "stream");
1476+
muxer->req_ = &mock_req;
1477+
1478+
// Create mock segment that captures the dts passed to reap()
1479+
MockSrsHlsM4sSegmentForBug4594 *mock_segment = new MockSrsHlsM4sSegmentForBug4594();
1480+
muxer->current_ = mock_segment;
1481+
1482+
// Simulate audio-only stream condition:
1483+
// - controller.audio_dts_ has a value (audio packets were written)
1484+
// - controller.video_dts_ is 0 (no video packets, write_video() never called)
1485+
controller.audio_dts_ = 72702; // Example audio DTS in milliseconds
1486+
controller.video_dts_ = 0; // No video for audio-only stream
1487+
1488+
// Call on_unpublish() - this triggers the bug path
1489+
HELPER_EXPECT_SUCCESS(controller.on_unpublish());
1490+
1491+
// Verify reap was called
1492+
ASSERT_TRUE(mock_segment->reap_called_) << "reap() should have been called by on_unpublish()";
1493+
1494+
// THE BUG TEST:
1495+
// This test SHOULD FAIL on the buggy develop branch because
1496+
// captured_reap_dts_ will be 0 instead of a proper audio timestamp (72702)
1497+
EXPECT_GT(mock_segment->captured_reap_dts_, 0u)
1498+
<< "Bug #4594: on_unpublish() resulted in reap(dts=0) for audio-only stream! "
1499+
<< "Expected non-zero dts (e.g., audio_dts_=" << controller.audio_dts_ << ") "
1500+
<< "but reap() received " << mock_segment->captured_reap_dts_;
1501+
1502+
// Cleanup
1503+
muxer->req_ = NULL;
1504+
}

0 commit comments

Comments
 (0)