improve blackbox test for rtsp. v7.0.93 (#4505)
Co-authored-by: winlin <winlinvip@gmail.com>
This commit is contained in:
parent
a1dd73545a
commit
2dfa54e21b
296
trunk/3rdparty/srs-bench/blackbox/rtsp_test.go
vendored
296
trunk/3rdparty/srs-bench/blackbox/rtsp_test.go
vendored
|
|
@ -109,7 +109,8 @@ func TestFast_RtmpPublish_RtspPlay_Basic(t *testing.T) {
|
|||
r3 = errors.Errorf("invalid streams=%v, %v, %v", len(m.Streams), m.String(), str)
|
||||
}
|
||||
|
||||
if ts := 90; m.Format.ProbeScore < ts {
|
||||
// Note that RTSP score might be lower than RTMP, so we use a lower threshold
|
||||
if ts := 80; m.Format.ProbeScore < ts {
|
||||
r4 = errors.Errorf("low score=%v < %v, %v, %v", m.Format.ProbeScore, ts, m.String(), str)
|
||||
}
|
||||
if dv := m.Duration(); dv < duration {
|
||||
|
|
@ -117,3 +118,296 @@ func TestFast_RtmpPublish_RtspPlay_Basic(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFast_RtmpPublish_RtspPlay_MultipleClients(t *testing.T) {
|
||||
// This case is run in parallel.
|
||||
t.Parallel()
|
||||
|
||||
// Setup the max timeout for this case.
|
||||
ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
// Check a set of errors.
|
||||
var r0, r1, r2, r3, r4, r5, r6, r7, r8, r9 error
|
||||
defer func(ctx context.Context) {
|
||||
if err := filterTestError(ctx.Err(), r0, r1, r2, r3, r4, r5, r6, r7, r8, r9); err != nil {
|
||||
t.Errorf("Fail for err %+v", err)
|
||||
} else {
|
||||
logger.Tf(ctx, "test done with err %+v", err)
|
||||
}
|
||||
}(ctx)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
defer wg.Wait()
|
||||
|
||||
// Start SRS server and wait for it to be ready.
|
||||
svr := NewSRSServer(func(v *srsServer) {
|
||||
v.envs = []string{
|
||||
"SRS_RTSP_SERVER_ENABLED=on",
|
||||
"SRS_VHOST_RTSP_ENABLED=on",
|
||||
"SRS_VHOST_RTSP_RTMP_TO_RTSP=on",
|
||||
}
|
||||
})
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
r0 = svr.Run(ctx, cancel)
|
||||
}()
|
||||
|
||||
// Start FFmpeg to publish stream.
|
||||
streamID := fmt.Sprintf("stream-%v-%v", os.Getpid(), rand.Int())
|
||||
streamURL := fmt.Sprintf("rtmp://localhost:%v/live/%v", svr.RTMPPort(), streamID)
|
||||
ffmpeg := NewFFmpeg(func(v *ffmpegClient) {
|
||||
v.args = []string{
|
||||
"-stream_loop", "-1", "-re", "-i", *srsPublishAvatar, "-c", "copy", "-f", "flv", streamURL,
|
||||
}
|
||||
})
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
<-svr.ReadyCtx().Done()
|
||||
r1 = ffmpeg.Run(ctx, cancel)
|
||||
}()
|
||||
|
||||
// Start multiple FFprobe clients to test concurrent RTSP playback.
|
||||
duration := time.Duration(*srsFFprobeDuration) * time.Millisecond
|
||||
rtspURL := fmt.Sprintf("rtsp://localhost:%v/live/%v", svr.RTSPPort(), streamID)
|
||||
|
||||
// First RTSP client
|
||||
ffprobe1 := NewFFprobe(func(v *ffprobeClient) {
|
||||
v.dvrFile = path.Join(svr.WorkDir(), "objs", fmt.Sprintf("srs-ffprobe1-%v.mp4", streamID))
|
||||
v.streamURL = rtspURL
|
||||
v.duration, v.timeout = duration, time.Duration(*srsFFprobeTimeout)*time.Millisecond
|
||||
})
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
<-svr.ReadyCtx().Done()
|
||||
r2 = ffprobe1.Run(ctx, cancel)
|
||||
}()
|
||||
|
||||
// Second RTSP client
|
||||
ffprobe2 := NewFFprobe(func(v *ffprobeClient) {
|
||||
v.dvrFile = path.Join(svr.WorkDir(), "objs", fmt.Sprintf("srs-ffprobe2-%v.mp4", streamID))
|
||||
v.streamURL = rtspURL
|
||||
v.duration, v.timeout = duration, time.Duration(*srsFFprobeTimeout)*time.Millisecond
|
||||
})
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
<-svr.ReadyCtx().Done()
|
||||
r3 = ffprobe2.Run(ctx, cancel)
|
||||
}()
|
||||
|
||||
// Wait for both probes to complete and verify results.
|
||||
var probe1Done, probe2Done bool
|
||||
for !probe1Done || !probe2Done {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ffprobe1.ProbeDoneCtx().Done():
|
||||
if !probe1Done {
|
||||
probe1Done = true
|
||||
str, m := ffprobe1.Result()
|
||||
if len(m.Streams) != 2 {
|
||||
r4 = errors.Errorf("client1: invalid streams=%v, %v, %v", len(m.Streams), m.String(), str)
|
||||
}
|
||||
if ts := 80; m.Format.ProbeScore < ts {
|
||||
r5 = errors.Errorf("client1: low score=%v < %v, %v, %v", m.Format.ProbeScore, ts, m.String(), str)
|
||||
}
|
||||
if dv := m.Duration(); dv < duration {
|
||||
r6 = errors.Errorf("client1: short duration=%v < %v, %v, %v", dv, duration, m.String(), str)
|
||||
}
|
||||
}
|
||||
case <-ffprobe2.ProbeDoneCtx().Done():
|
||||
if !probe2Done {
|
||||
probe2Done = true
|
||||
str, m := ffprobe2.Result()
|
||||
if len(m.Streams) != 2 {
|
||||
r7 = errors.Errorf("client2: invalid streams=%v, %v, %v", len(m.Streams), m.String(), str)
|
||||
}
|
||||
if ts := 80; m.Format.ProbeScore < ts {
|
||||
r8 = errors.Errorf("client2: low score=%v < %v, %v, %v", m.Format.ProbeScore, ts, m.String(), str)
|
||||
}
|
||||
if dv := m.Duration(); dv < duration {
|
||||
r9 = errors.Errorf("client2: short duration=%v < %v, %v, %v", dv, duration, m.String(), str)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
defer cancel()
|
||||
}
|
||||
|
||||
func TestFast_RtmpPublish_RtspPlay_CustomPort(t *testing.T) {
|
||||
// This case is run in parallel.
|
||||
t.Parallel()
|
||||
|
||||
// Setup the max timeout for this case.
|
||||
ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
// Check a set of errors.
|
||||
var r0, r1, r2, r3, r4, r5 error
|
||||
defer func(ctx context.Context) {
|
||||
if err := filterTestError(ctx.Err(), r0, r1, r2, r3, r4, r5); err != nil {
|
||||
t.Errorf("Fail for err %+v", err)
|
||||
} else {
|
||||
logger.Tf(ctx, "test done with err %+v", err)
|
||||
}
|
||||
}(ctx)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
defer wg.Wait()
|
||||
|
||||
// Start SRS server with custom RTSP port.
|
||||
customRTSPPort := 15540 + rand.Intn(1000)
|
||||
svr := NewSRSServer(func(v *srsServer) {
|
||||
v.envs = []string{
|
||||
"SRS_RTSP_SERVER_ENABLED=on",
|
||||
"SRS_VHOST_RTSP_ENABLED=on",
|
||||
"SRS_VHOST_RTSP_RTMP_TO_RTSP=on",
|
||||
fmt.Sprintf("SRS_RTSP_SERVER_LISTEN=%d", customRTSPPort),
|
||||
}
|
||||
})
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
r0 = svr.Run(ctx, cancel)
|
||||
}()
|
||||
|
||||
// Start FFmpeg to publish stream.
|
||||
streamID := fmt.Sprintf("stream-%v-%v", os.Getpid(), rand.Int())
|
||||
streamURL := fmt.Sprintf("rtmp://localhost:%v/live/%v", svr.RTMPPort(), streamID)
|
||||
ffmpeg := NewFFmpeg(func(v *ffmpegClient) {
|
||||
v.args = []string{
|
||||
"-stream_loop", "-1", "-re", "-i", *srsPublishAvatar, "-c", "copy", "-f", "flv", streamURL,
|
||||
}
|
||||
})
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
<-svr.ReadyCtx().Done()
|
||||
r1 = ffmpeg.Run(ctx, cancel)
|
||||
}()
|
||||
|
||||
// Start FFprobe to detect and verify stream on custom port.
|
||||
duration := time.Duration(*srsFFprobeDuration) * time.Millisecond
|
||||
ffprobe := NewFFprobe(func(v *ffprobeClient) {
|
||||
v.dvrFile = path.Join(svr.WorkDir(), "objs", fmt.Sprintf("srs-ffprobe-%v.mp4", streamID))
|
||||
v.streamURL = fmt.Sprintf("rtsp://localhost:%v/live/%v", customRTSPPort, streamID)
|
||||
v.duration, v.timeout = duration, time.Duration(*srsFFprobeTimeout)*time.Millisecond
|
||||
})
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
<-svr.ReadyCtx().Done()
|
||||
r2 = ffprobe.Run(ctx, cancel)
|
||||
}()
|
||||
|
||||
// Fast quit for probe done.
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case <-ffprobe.ProbeDoneCtx().Done():
|
||||
defer cancel()
|
||||
|
||||
str, m := ffprobe.Result()
|
||||
if len(m.Streams) != 2 {
|
||||
r3 = errors.Errorf("invalid streams=%v, %v, %v", len(m.Streams), m.String(), str)
|
||||
}
|
||||
|
||||
// Note that RTSP score might be lower than RTMP, so we use a lower threshold
|
||||
if ts := 80; m.Format.ProbeScore < ts {
|
||||
r4 = errors.Errorf("low score=%v < %v, %v, %v", m.Format.ProbeScore, ts, m.String(), str)
|
||||
}
|
||||
if dv := m.Duration(); dv < duration {
|
||||
r5 = errors.Errorf("short duration=%v < %v, %v, %v", dv, duration, m.String(), str)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFast_RtmpPublish_RtspPlay_AudioOnly(t *testing.T) {
|
||||
// This case is run in parallel.
|
||||
t.Parallel()
|
||||
|
||||
// Setup the max timeout for this case.
|
||||
ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
// Check a set of errors.
|
||||
var r0, r1, r2, r3, r4, r5 error
|
||||
defer func(ctx context.Context) {
|
||||
if err := filterTestError(ctx.Err(), r0, r1, r2, r3, r4, r5); err != nil {
|
||||
t.Errorf("Fail for err %+v", err)
|
||||
} else {
|
||||
logger.Tf(ctx, "test done with err %+v", err)
|
||||
}
|
||||
}(ctx)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
defer wg.Wait()
|
||||
|
||||
// Start SRS server and wait for it to be ready.
|
||||
svr := NewSRSServer(func(v *srsServer) {
|
||||
v.envs = []string{
|
||||
"SRS_RTSP_SERVER_ENABLED=on",
|
||||
"SRS_VHOST_RTSP_ENABLED=on",
|
||||
"SRS_VHOST_RTSP_RTMP_TO_RTSP=on",
|
||||
}
|
||||
})
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
r0 = svr.Run(ctx, cancel)
|
||||
}()
|
||||
|
||||
// Start FFmpeg to publish audio-only stream.
|
||||
streamID := fmt.Sprintf("stream-%v-%v", os.Getpid(), rand.Int())
|
||||
streamURL := fmt.Sprintf("rtmp://localhost:%v/live/%v", svr.RTMPPort(), streamID)
|
||||
ffmpeg := NewFFmpeg(func(v *ffmpegClient) {
|
||||
v.args = []string{
|
||||
"-stream_loop", "-1", "-re", "-i", *srsPublishAvatar, "-vn", "-c:a", "copy", "-f", "flv", streamURL,
|
||||
}
|
||||
})
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
<-svr.ReadyCtx().Done()
|
||||
r1 = ffmpeg.Run(ctx, cancel)
|
||||
}()
|
||||
|
||||
// Start FFprobe to detect and verify audio-only stream.
|
||||
duration := time.Duration(*srsFFprobeDuration) * time.Millisecond
|
||||
ffprobe := NewFFprobe(func(v *ffprobeClient) {
|
||||
v.dvrFile = path.Join(svr.WorkDir(), "objs", fmt.Sprintf("srs-ffprobe-%v.mp4", streamID))
|
||||
v.streamURL = fmt.Sprintf("rtsp://localhost:%v/live/%v", svr.RTSPPort(), streamID)
|
||||
v.duration, v.timeout = duration, time.Duration(*srsFFprobeTimeout)*time.Millisecond
|
||||
})
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
<-svr.ReadyCtx().Done()
|
||||
r2 = ffprobe.Run(ctx, cancel)
|
||||
}()
|
||||
|
||||
// Fast quit for probe done.
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case <-ffprobe.ProbeDoneCtx().Done():
|
||||
defer cancel()
|
||||
|
||||
str, m := ffprobe.Result()
|
||||
// Audio-only stream should have 1 stream
|
||||
if len(m.Streams) != 1 {
|
||||
r3 = errors.Errorf("invalid streams=%v, expected 1 for audio-only, %v, %v", len(m.Streams), m.String(), str)
|
||||
}
|
||||
|
||||
// Check if it's audio stream
|
||||
if len(m.Streams) > 0 && m.Streams[0].CodecType != "audio" {
|
||||
r4 = errors.Errorf("expected audio stream, got %v, %v, %v", m.Streams[0].CodecType, m.String(), str)
|
||||
}
|
||||
|
||||
if dv := m.Duration(); dv < duration {
|
||||
r5 = errors.Errorf("short duration=%v < %v, %v, %v", dv, duration, m.String(), str)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ The changelog for SRS.
|
|||
<a name="v7-changes"></a>
|
||||
|
||||
## SRS 7.0 Changelog
|
||||
* v7.0, 2025-09-21, Merge [#4505](https://github.com/ossrs/srs/pull/4505): improve blackbox test for rtsp. v7.0.93 (#4505)
|
||||
* v7.0, 2025-09-21, Fix WHIP with transcoding bug. v7.0.92 (#4495)
|
||||
* v7.0, 2025-09-20, Merge [#4504](https://github.com/ossrs/srs/pull/4504): fix rtsp compiling warning. v7.0.91 (#4504)
|
||||
* v7.0, 2025-09-19, Merge [#4503](https://github.com/ossrs/srs/pull/4503): AI: Refine RTMP/SRT/RTC bridge. v7.0.90 (#4503)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,6 @@
|
|||
|
||||
#define VERSION_MAJOR 7
|
||||
#define VERSION_MINOR 0
|
||||
#define VERSION_REVISION 92
|
||||
#define VERSION_REVISION 93
|
||||
|
||||
#endif
|
||||
|
|
@ -1287,13 +1287,13 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterSEIFiltering)
|
|||
|
||||
// Create SEI NALU sample
|
||||
uint8_t sei_data[] = {0x06, 0x01, 0x02, 0x03}; // SEI NALU type (6)
|
||||
SrsNaluSample sei_sample((char*)sei_data, sizeof(sei_data));
|
||||
SrsNaluSample sei_sample((char *)sei_data, sizeof(sei_data));
|
||||
format.video_->samples_[0] = sei_sample;
|
||||
format.video_->nb_samples_ = 1;
|
||||
|
||||
SrsMediaPacket msg;
|
||||
bool has_idr = false;
|
||||
std::vector<SrsNaluSample*> samples;
|
||||
std::vector<SrsNaluSample *> samples;
|
||||
|
||||
// When keep_avc_nalu_sei_ = true, SEI should be kept
|
||||
HELPER_EXPECT_SUCCESS(builder.filter(&msg, &format, has_idr, samples));
|
||||
|
|
@ -1309,7 +1309,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterSEIFiltering)
|
|||
|
||||
// Test 3: Non-SEI NALU with SEI filtering enabled
|
||||
uint8_t idr_data[] = {0x05, 0x01, 0x02, 0x03}; // IDR NALU type (5)
|
||||
SrsNaluSample idr_sample((char*)idr_data, sizeof(idr_data));
|
||||
SrsNaluSample idr_sample((char *)idr_data, sizeof(idr_data));
|
||||
format.video_->samples_[0] = idr_sample;
|
||||
samples.clear();
|
||||
|
||||
|
|
@ -1319,9 +1319,9 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterSEIFiltering)
|
|||
|
||||
// Test 4: Mixed SEI and non-SEI NALUs
|
||||
SrsNaluSample mixed_samples[3];
|
||||
mixed_samples[0] = sei_sample; // SEI (should be filtered)
|
||||
mixed_samples[1] = idr_sample; // IDR (should be kept)
|
||||
mixed_samples[2] = sei_sample; // SEI (should be filtered)
|
||||
mixed_samples[0] = sei_sample; // SEI (should be filtered)
|
||||
mixed_samples[1] = idr_sample; // IDR (should be kept)
|
||||
mixed_samples[2] = sei_sample; // SEI (should be filtered)
|
||||
|
||||
format.video_->samples_[0] = mixed_samples[0];
|
||||
format.video_->samples_[1] = mixed_samples[1];
|
||||
|
|
@ -1365,14 +1365,14 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterBFrameFilteringAVC)
|
|||
|
||||
SrsMediaPacket msg;
|
||||
bool has_idr = false;
|
||||
std::vector<SrsNaluSample*> samples;
|
||||
std::vector<SrsNaluSample *> samples;
|
||||
|
||||
// Test 1: B-frame filtering disabled (keep_bframe_ = true)
|
||||
builder.keep_bframe_ = true;
|
||||
|
||||
// Create B-frame NALU sample (NonIDR with B-frame slice type)
|
||||
uint8_t bframe_data[] = {0x01, 0xA8, 0x00, 0x00}; // NonIDR NALU type (1), slice_type=1 (B)
|
||||
SrsNaluSample bframe_sample((char*)bframe_data, sizeof(bframe_data));
|
||||
SrsNaluSample bframe_sample((char *)bframe_data, sizeof(bframe_data));
|
||||
format.video_->samples_[0] = bframe_sample;
|
||||
format.video_->nb_samples_ = 1;
|
||||
|
||||
|
|
@ -1390,7 +1390,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterBFrameFilteringAVC)
|
|||
|
||||
// Test 3: Non-B-frame NALU with B-frame filtering enabled
|
||||
uint8_t pframe_data[] = {0x01, 0x88, 0x00, 0x00}; // NonIDR NALU type (1), slice_type=0 (P)
|
||||
SrsNaluSample pframe_sample((char*)pframe_data, sizeof(pframe_data));
|
||||
SrsNaluSample pframe_sample((char *)pframe_data, sizeof(pframe_data));
|
||||
format.video_->samples_[0] = pframe_sample;
|
||||
samples.clear();
|
||||
|
||||
|
|
@ -1446,14 +1446,14 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterBFrameFilteringHEVC)
|
|||
|
||||
SrsMediaPacket msg;
|
||||
bool has_idr = false;
|
||||
std::vector<SrsNaluSample*> samples;
|
||||
std::vector<SrsNaluSample *> samples;
|
||||
|
||||
// Test 1: B-frame filtering disabled (keep_bframe_ = true)
|
||||
builder.keep_bframe_ = true;
|
||||
|
||||
// Create HEVC B-frame NALU sample
|
||||
uint8_t hevc_bframe_data[] = {0x02, 0x01, 0xE0, 0x44}; // HEVC NALU with B-frame slice type
|
||||
SrsNaluSample hevc_bframe_sample((char*)hevc_bframe_data, sizeof(hevc_bframe_data));
|
||||
SrsNaluSample hevc_bframe_sample((char *)hevc_bframe_data, sizeof(hevc_bframe_data));
|
||||
format.video_->samples_[0] = hevc_bframe_sample;
|
||||
format.video_->nb_samples_ = 1;
|
||||
|
||||
|
|
@ -1471,7 +1471,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterBFrameFilteringHEVC)
|
|||
|
||||
// Test 3: Non-B-frame HEVC NALU with B-frame filtering enabled
|
||||
uint8_t hevc_pframe_data[] = {0x02, 0x01, 0xD0, 0x30}; // HEVC NALU with P-frame slice type
|
||||
SrsNaluSample hevc_pframe_sample((char*)hevc_pframe_data, sizeof(hevc_pframe_data));
|
||||
SrsNaluSample hevc_pframe_sample((char *)hevc_pframe_data, sizeof(hevc_pframe_data));
|
||||
format.video_->samples_[0] = hevc_pframe_sample;
|
||||
samples.clear();
|
||||
|
||||
|
|
@ -1481,7 +1481,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterBFrameFilteringHEVC)
|
|||
|
||||
// Test 4: HEVC VPS/SPS/PPS NALUs (should not be filtered as B-frames)
|
||||
uint8_t hevc_vps_data[] = {0x40, 0x01, 0xE0, 0x44}; // VPS NALU
|
||||
SrsNaluSample hevc_vps_sample((char*)hevc_vps_data, sizeof(hevc_vps_data));
|
||||
SrsNaluSample hevc_vps_sample((char *)hevc_vps_data, sizeof(hevc_vps_data));
|
||||
format.video_->samples_[0] = hevc_vps_sample;
|
||||
samples.clear();
|
||||
|
||||
|
|
@ -1522,33 +1522,33 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterCombinedSEIAndBFrameFiltering
|
|||
|
||||
SrsMediaPacket msg;
|
||||
bool has_idr = false;
|
||||
std::vector<SrsNaluSample*> samples;
|
||||
std::vector<SrsNaluSample *> samples;
|
||||
|
||||
// Test complex scenario with multiple NALU types
|
||||
SrsNaluSample test_samples[6];
|
||||
|
||||
// SEI NALU (should be filtered by SEI filter)
|
||||
uint8_t sei_data[] = {0x06, 0x01, 0x02, 0x03};
|
||||
test_samples[0] = SrsNaluSample((char*)sei_data, sizeof(sei_data));
|
||||
test_samples[0] = SrsNaluSample((char *)sei_data, sizeof(sei_data));
|
||||
|
||||
// B-frame NALU (should be filtered by B-frame filter)
|
||||
uint8_t bframe_data[] = {0x01, 0xA8, 0x00, 0x00};
|
||||
test_samples[1] = SrsNaluSample((char*)bframe_data, sizeof(bframe_data));
|
||||
test_samples[1] = SrsNaluSample((char *)bframe_data, sizeof(bframe_data));
|
||||
|
||||
// P-frame NALU (should be kept)
|
||||
uint8_t pframe_data[] = {0x01, 0x88, 0x00, 0x00};
|
||||
test_samples[2] = SrsNaluSample((char*)pframe_data, sizeof(pframe_data));
|
||||
test_samples[2] = SrsNaluSample((char *)pframe_data, sizeof(pframe_data));
|
||||
|
||||
// IDR NALU (should be kept)
|
||||
uint8_t idr_data[] = {0x05, 0x01, 0x02, 0x03};
|
||||
test_samples[3] = SrsNaluSample((char*)idr_data, sizeof(idr_data));
|
||||
test_samples[3] = SrsNaluSample((char *)idr_data, sizeof(idr_data));
|
||||
|
||||
// Another SEI NALU (should be filtered by SEI filter)
|
||||
test_samples[4] = SrsNaluSample((char*)sei_data, sizeof(sei_data));
|
||||
test_samples[4] = SrsNaluSample((char *)sei_data, sizeof(sei_data));
|
||||
|
||||
// SPS NALU (should be kept)
|
||||
uint8_t sps_data[] = {0x07, 0x01, 0x02, 0x03};
|
||||
test_samples[5] = SrsNaluSample((char*)sps_data, sizeof(sps_data));
|
||||
test_samples[5] = SrsNaluSample((char *)sps_data, sizeof(sps_data));
|
||||
|
||||
// Set up format with all samples
|
||||
for (int i = 0; i < 6; i++) {
|
||||
|
|
@ -1564,9 +1564,12 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterCombinedSEIAndBFrameFiltering
|
|||
bool found_pframe = false, found_idr = false, found_sps = false;
|
||||
for (size_t i = 0; i < samples.size(); i++) {
|
||||
uint8_t nalu_type = samples[i]->bytes_[0] & 0x1F;
|
||||
if (nalu_type == 0x01) found_pframe = true; // P-frame
|
||||
if (nalu_type == 0x05) found_idr = true; // IDR
|
||||
if (nalu_type == 0x07) found_sps = true; // SPS
|
||||
if (nalu_type == 0x01)
|
||||
found_pframe = true; // P-frame
|
||||
if (nalu_type == 0x05)
|
||||
found_idr = true; // IDR
|
||||
if (nalu_type == 0x07)
|
||||
found_sps = true; // SPS
|
||||
}
|
||||
EXPECT_TRUE(found_pframe);
|
||||
EXPECT_TRUE(found_idr);
|
||||
|
|
@ -1606,12 +1609,12 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterIDRDetection)
|
|||
|
||||
SrsMediaPacket msg;
|
||||
bool has_idr = false;
|
||||
std::vector<SrsNaluSample*> samples;
|
||||
std::vector<SrsNaluSample *> samples;
|
||||
|
||||
// Test 1: No IDR frame
|
||||
format.video_->has_idr_ = false;
|
||||
uint8_t pframe_data[] = {0x01, 0x88, 0x00, 0x00};
|
||||
SrsNaluSample pframe_sample((char*)pframe_data, sizeof(pframe_data));
|
||||
SrsNaluSample pframe_sample((char *)pframe_data, sizeof(pframe_data));
|
||||
format.video_->samples_[0] = pframe_sample;
|
||||
format.video_->nb_samples_ = 1;
|
||||
|
||||
|
|
@ -1660,7 +1663,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterErrorHandling)
|
|||
|
||||
SrsMediaPacket msg;
|
||||
bool has_idr = false;
|
||||
std::vector<SrsNaluSample*> samples;
|
||||
std::vector<SrsNaluSample *> samples;
|
||||
|
||||
// Test with empty NALU sample (should cause parse error)
|
||||
SrsNaluSample empty_sample(NULL, 0);
|
||||
|
|
@ -1706,13 +1709,13 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterNonAVCCodecSkipsSEIFiltering)
|
|||
|
||||
// Create a sample that would be SEI in AVC (0x06), but should be kept for HEVC
|
||||
uint8_t hevc_data[] = {0x06, 0x01, 0x02, 0x03};
|
||||
SrsNaluSample hevc_sample((char*)hevc_data, sizeof(hevc_data));
|
||||
SrsNaluSample hevc_sample((char *)hevc_data, sizeof(hevc_data));
|
||||
hevc_format.video_->samples_[0] = hevc_sample;
|
||||
hevc_format.video_->nb_samples_ = 1;
|
||||
|
||||
SrsMediaPacket msg;
|
||||
bool has_idr = false;
|
||||
std::vector<SrsNaluSample*> samples;
|
||||
std::vector<SrsNaluSample *> samples;
|
||||
|
||||
// For HEVC, SEI filtering should be skipped, so sample should be kept
|
||||
HELPER_EXPECT_SUCCESS(builder.filter(&msg, &hevc_format, has_idr, samples));
|
||||
|
|
@ -1729,7 +1732,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterNonAVCCodecSkipsSEIFiltering)
|
|||
unknown_format.video_ = new SrsParsedVideoPacket();
|
||||
|
||||
uint8_t unknown_data[] = {0x06, 0x01, 0x02, 0x03};
|
||||
SrsNaluSample unknown_sample((char*)unknown_data, sizeof(unknown_data));
|
||||
SrsNaluSample unknown_sample((char *)unknown_data, sizeof(unknown_data));
|
||||
unknown_format.video_->samples_[0] = unknown_sample;
|
||||
unknown_format.video_->nb_samples_ = 1;
|
||||
|
||||
|
|
@ -1775,7 +1778,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterZeroSamples)
|
|||
|
||||
SrsMediaPacket msg;
|
||||
bool has_idr = false;
|
||||
std::vector<SrsNaluSample*> samples;
|
||||
std::vector<SrsNaluSample *> samples;
|
||||
|
||||
// Should handle zero samples gracefully
|
||||
HELPER_EXPECT_SUCCESS(builder.filter(&msg, &format, has_idr, samples));
|
||||
|
|
@ -1811,8 +1814,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoMergeNalusMultipleSamples)
|
|||
0x17, // keyframe + AVC codec
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20,
|
||||
0xac, 0xd9, 0x40, 0xc0, 0x29, 0xb0, 0x11, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00,
|
||||
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c
|
||||
};
|
||||
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c};
|
||||
|
||||
char *h264_data = new char[sizeof(h264_seq_raw)];
|
||||
memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw));
|
||||
|
|
@ -1831,10 +1833,10 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoMergeNalusMultipleSamples)
|
|||
|
||||
// Create H.264 frame with single NALU (known working pattern)
|
||||
uint8_t h264_frame_raw[] = {
|
||||
0x17, // keyframe + AVC codec
|
||||
0x01, // AVC NALU (not sequence header)
|
||||
0x00, 0x00, 0x00, // composition time
|
||||
0x00, 0x00, 0x00, 0x05, // NALU length (5 bytes)
|
||||
0x17, // keyframe + AVC codec
|
||||
0x01, // AVC NALU (not sequence header)
|
||||
0x00, 0x00, 0x00, // composition time
|
||||
0x00, 0x00, 0x00, 0x05, // NALU length (5 bytes)
|
||||
0x65, 0x88, 0x84, 0x00, (uint8_t)(0x10 + i) // IDR slice data (vary last byte)
|
||||
};
|
||||
|
||||
|
|
@ -1885,8 +1887,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoLargeNaluPackageFuA)
|
|||
0x17, // keyframe + AVC codec
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20,
|
||||
0xac, 0xd9, 0x40, 0xc0, 0x29, 0xb0, 0x11, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00,
|
||||
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c
|
||||
};
|
||||
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c};
|
||||
|
||||
char *h264_data = new char[sizeof(h264_seq_raw)];
|
||||
memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw));
|
||||
|
|
@ -1971,8 +1972,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoExtremelyLargeNaluPackageFuA
|
|||
0x17, // keyframe + AVC codec
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20,
|
||||
0xac, 0xd9, 0x40, 0xc0, 0x29, 0xb0, 0x11, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00,
|
||||
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c
|
||||
};
|
||||
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c};
|
||||
|
||||
char *h264_data = new char[sizeof(h264_seq_raw)];
|
||||
memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw));
|
||||
|
|
@ -2052,8 +2052,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoMergeNalusWithMultipleNalus)
|
|||
0x17, // keyframe + AVC codec
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20,
|
||||
0xac, 0xd9, 0x40, 0xc0, 0x29, 0xb0, 0x11, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00,
|
||||
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c
|
||||
};
|
||||
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c};
|
||||
|
||||
char *h264_data = new char[sizeof(h264_seq_raw)];
|
||||
memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw));
|
||||
|
|
@ -2070,17 +2069,17 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoMergeNalusWithMultipleNalus)
|
|||
// Create frame with multiple small NALUs - use minimal valid NALU structure
|
||||
// Total frame: 5 (header) + 4+3 (first NALU) + 4+3 (second NALU) = 19 bytes
|
||||
uint8_t h264_idr_raw[] = {
|
||||
0x17, // keyframe + AVC codec
|
||||
0x01, // AVC NALU (not sequence header)
|
||||
0x17, // keyframe + AVC codec
|
||||
0x01, // AVC NALU (not sequence header)
|
||||
0x00, 0x00, 0x00, // composition time
|
||||
|
||||
// First NALU: 3 bytes of data
|
||||
0x00, 0x00, 0x00, 0x03, // NALU length (3 bytes)
|
||||
0x65, 0x88, 0x84, // Minimal IDR slice
|
||||
0x65, 0x88, 0x84, // Minimal IDR slice
|
||||
|
||||
// Second NALU: 3 bytes of data
|
||||
0x00, 0x00, 0x00, 0x03, // NALU length (3 bytes)
|
||||
0x65, 0x88, 0x85 // Minimal IDR slice (slightly different)
|
||||
0x65, 0x88, 0x85 // Minimal IDR slice (slightly different)
|
||||
};
|
||||
|
||||
char *idr_data = new char[sizeof(h264_idr_raw)];
|
||||
|
|
@ -2136,8 +2135,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoMultipleLargeNalusPackageFuA
|
|||
0x17, // keyframe + AVC codec
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20,
|
||||
0xac, 0xd9, 0x40, 0xc0, 0x29, 0xb0, 0x11, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00,
|
||||
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c
|
||||
};
|
||||
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c};
|
||||
|
||||
char *h264_data = new char[sizeof(h264_seq_raw)];
|
||||
memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw));
|
||||
|
|
@ -2217,8 +2215,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoMergeNalusLargePayload)
|
|||
0x17, // keyframe + AVC codec
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20,
|
||||
0xac, 0xd9, 0x40, 0xc0, 0x29, 0xb0, 0x11, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00,
|
||||
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c
|
||||
};
|
||||
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c};
|
||||
|
||||
char *h264_data = new char[sizeof(h264_seq_raw)];
|
||||
memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw));
|
||||
|
|
@ -2244,7 +2241,9 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoMergeNalusLargePayload)
|
|||
// AVC header
|
||||
large_data[pos++] = 0x17; // keyframe + AVC codec
|
||||
large_data[pos++] = 0x01; // AVC NALU
|
||||
large_data[pos++] = 0x00; large_data[pos++] = 0x00; large_data[pos++] = 0x00; // composition time
|
||||
large_data[pos++] = 0x00;
|
||||
large_data[pos++] = 0x00;
|
||||
large_data[pos++] = 0x00; // composition time
|
||||
|
||||
// First large NALU
|
||||
large_data[pos++] = (first_nalu_size >> 24) & 0xFF;
|
||||
|
|
@ -2318,7 +2317,9 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnAudioRealAacFrames)
|
|||
frame_data[0] = 0xAF; // AAC, 44kHz, 16-bit, stereo
|
||||
frame_data[1] = 0x01; // AAC raw data (not sequence header)
|
||||
// Add minimal AAC raw data - transcoding may fail but we'll reach the target lines
|
||||
frame_data[2] = 0x21; frame_data[3] = 0x10; frame_data[4] = 0x05;
|
||||
frame_data[2] = 0x21;
|
||||
frame_data[3] = 0x10;
|
||||
frame_data[4] = 0x05;
|
||||
|
||||
aac_frame->wrap(frame_data, 5);
|
||||
aac_frame->timestamp_ = 2000;
|
||||
|
|
@ -2379,7 +2380,9 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnAudioAddSampleFailure)
|
|||
char *frame_data = new char[5];
|
||||
frame_data[0] = 0xAF; // AAC, 44kHz, 16-bit, stereo
|
||||
frame_data[1] = 0x01; // AAC raw data
|
||||
frame_data[2] = 0x21; frame_data[3] = 0x10; frame_data[4] = 0x05;
|
||||
frame_data[2] = 0x21;
|
||||
frame_data[3] = 0x10;
|
||||
frame_data[4] = 0x05;
|
||||
|
||||
aac_frame->wrap(frame_data, 5);
|
||||
aac_frame->timestamp_ = 2000;
|
||||
|
|
@ -2433,7 +2436,8 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnAudioTranscodeFailure)
|
|||
frame_data[0] = 0xAF; // AAC, 44kHz, 16-bit, stereo
|
||||
frame_data[1] = 0x01; // AAC raw data
|
||||
// Add minimal AAC data - will likely cause transcoding to fail
|
||||
frame_data[2] = 0x00; frame_data[3] = 0x00;
|
||||
frame_data[2] = 0x00;
|
||||
frame_data[3] = 0x00;
|
||||
|
||||
aac_frame->wrap(frame_data, 4);
|
||||
aac_frame->timestamp_ = 2000;
|
||||
|
|
@ -2486,7 +2490,9 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnAudioMemoryCleanup)
|
|||
char *frame_data = new char[5];
|
||||
frame_data[0] = 0xAF; // AAC, 44kHz, 16-bit, stereo
|
||||
frame_data[1] = 0x01; // AAC raw data
|
||||
frame_data[2] = 0x21 + i; frame_data[3] = 0x10; frame_data[4] = 0x05;
|
||||
frame_data[2] = 0x21 + i;
|
||||
frame_data[3] = 0x10;
|
||||
frame_data[4] = 0x05;
|
||||
|
||||
aac_frame->wrap(frame_data, 5);
|
||||
aac_frame->timestamp_ = 2000 + i * 1000;
|
||||
|
|
@ -2531,8 +2537,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoComprehensiveCoverage)
|
|||
0x17, // keyframe + AVC codec
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20,
|
||||
0xac, 0xd9, 0x40, 0xc0, 0x29, 0xb0, 0x11, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00,
|
||||
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c
|
||||
};
|
||||
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c};
|
||||
|
||||
char *h264_data = new char[sizeof(h264_seq_raw)];
|
||||
memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw));
|
||||
|
|
@ -2548,10 +2553,10 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoComprehensiveCoverage)
|
|||
h264_frame->message_type_ = SrsFrameTypeVideo;
|
||||
|
||||
uint8_t h264_frame_raw[] = {
|
||||
0x17, // keyframe + AVC codec
|
||||
0x01, // AVC NALU (not sequence header)
|
||||
0x00, 0x00, 0x00, // composition time
|
||||
0x00, 0x00, 0x00, 0x05, // NALU length
|
||||
0x17, // keyframe + AVC codec
|
||||
0x01, // AVC NALU (not sequence header)
|
||||
0x00, 0x00, 0x00, // composition time
|
||||
0x00, 0x00, 0x00, 0x05, // NALU length
|
||||
0x65, 0x88, 0x84, 0x00, 0x10 // IDR slice data
|
||||
};
|
||||
|
||||
|
|
@ -2592,9 +2597,9 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoUnsupportedCodec)
|
|||
h263_frame->message_type_ = SrsFrameTypeVideo;
|
||||
|
||||
uint8_t h263_raw[] = {
|
||||
0x22, // keyframe + H.263 codec (codec ID 2)
|
||||
0x00, // packet type
|
||||
0x00, 0x00, 0x00, // composition time
|
||||
0x22, // keyframe + H.263 codec (codec ID 2)
|
||||
0x00, // packet type
|
||||
0x00, 0x00, 0x00, // composition time
|
||||
0x01, 0x02, 0x03, 0x04, 0x05 // dummy H.263 data
|
||||
};
|
||||
|
||||
|
|
@ -2633,7 +2638,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoNoVcodecParsed)
|
|||
|
||||
// Create invalid video data that format_->on_video() can process but won't set vcodec_
|
||||
uint8_t invalid_raw[] = {
|
||||
0x00, // invalid frame type and codec combination
|
||||
0x00, // invalid frame type and codec combination
|
||||
0x00, 0x00, 0x00, 0x00 // minimal data
|
||||
};
|
||||
|
||||
|
|
@ -2675,8 +2680,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoInitializeTrackError)
|
|||
0x17, // keyframe + AVC codec
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20,
|
||||
0xac, 0xd9, 0x40, 0xc0, 0x29, 0xb0, 0x11, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00,
|
||||
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c
|
||||
};
|
||||
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c};
|
||||
|
||||
char *h264_data = new char[sizeof(h264_seq_raw)];
|
||||
memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw));
|
||||
|
|
@ -2696,10 +2700,10 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoInitializeTrackError)
|
|||
h264_frame2->message_type_ = SrsFrameTypeVideo;
|
||||
|
||||
uint8_t h264_frame_raw[] = {
|
||||
0x17, // keyframe + AVC codec
|
||||
0x01, // AVC NALU (not sequence header)
|
||||
0x00, 0x00, 0x00, // composition time
|
||||
0x00, 0x00, 0x00, 0x05, // NALU length
|
||||
0x17, // keyframe + AVC codec
|
||||
0x01, // AVC NALU (not sequence header)
|
||||
0x00, 0x00, 0x00, // composition time
|
||||
0x00, 0x00, 0x00, 0x05, // NALU length
|
||||
0x65, 0x88, 0x84, 0x00, 0x10 // IDR slice data
|
||||
};
|
||||
|
||||
|
|
@ -2739,8 +2743,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoFilterMethod)
|
|||
0x17, // keyframe + AVC codec
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20,
|
||||
0xac, 0xd9, 0x40, 0xc0, 0x29, 0xb0, 0x11, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00,
|
||||
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c
|
||||
};
|
||||
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c};
|
||||
|
||||
char *h264_data = new char[sizeof(h264_seq_raw)];
|
||||
memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw));
|
||||
|
|
@ -2755,17 +2758,17 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoFilterMethod)
|
|||
|
||||
// Create IDR frame with multiple NALUs to test filter method thoroughly
|
||||
uint8_t idr_raw[] = {
|
||||
0x17, // keyframe + AVC codec
|
||||
0x01, // AVC NALU (not sequence header)
|
||||
0x17, // keyframe + AVC codec
|
||||
0x01, // AVC NALU (not sequence header)
|
||||
0x00, 0x00, 0x00, // composition time
|
||||
// First NALU (SPS)
|
||||
0x00, 0x00, 0x00, 0x08, // NALU length
|
||||
0x00, 0x00, 0x00, 0x08, // NALU length
|
||||
0x67, 0x64, 0x00, 0x20, 0xac, 0xd9, 0x40, 0xc0, // SPS data
|
||||
// Second NALU (PPS)
|
||||
0x00, 0x00, 0x00, 0x04, // NALU length
|
||||
0x68, 0xeb, 0xec, 0xb2, // PPS data
|
||||
// Third NALU (IDR slice)
|
||||
0x00, 0x00, 0x00, 0x06, // NALU length
|
||||
0x00, 0x00, 0x00, 0x06, // NALU length
|
||||
0x65, 0x88, 0x84, 0x00, 0x10, 0x20 // IDR slice data
|
||||
};
|
||||
|
||||
|
|
@ -2782,10 +2785,10 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoFilterMethod)
|
|||
p_frame->message_type_ = SrsFrameTypeVideo;
|
||||
|
||||
uint8_t p_raw[] = {
|
||||
0x27, // inter frame + AVC codec
|
||||
0x01, // AVC NALU
|
||||
0x00, 0x00, 0x00, // composition time
|
||||
0x00, 0x00, 0x00, 0x05, // NALU length
|
||||
0x27, // inter frame + AVC codec
|
||||
0x01, // AVC NALU
|
||||
0x00, 0x00, 0x00, // composition time
|
||||
0x00, 0x00, 0x00, 0x05, // NALU length
|
||||
0x41, 0x88, 0x84, 0x00, 0x10 // P slice data
|
||||
};
|
||||
|
||||
|
|
@ -2843,8 +2846,8 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoFormatError)
|
|||
|
||||
// Create malformed data with valid codec ID but invalid structure
|
||||
uint8_t malformed_raw[] = {
|
||||
0x17, // keyframe + AVC codec
|
||||
0x00, // sequence header indicator
|
||||
0x17, // keyframe + AVC codec
|
||||
0x00, // sequence header indicator
|
||||
0xFF, 0xFF, 0xFF // invalid composition time and truncated data
|
||||
};
|
||||
|
||||
|
|
@ -2888,8 +2891,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoCodecSwitching)
|
|||
0x17, // keyframe + AVC codec
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20,
|
||||
0xac, 0xd9, 0x40, 0xc0, 0x29, 0xb0, 0x11, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00,
|
||||
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c
|
||||
};
|
||||
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c};
|
||||
|
||||
char *h264_data = new char[sizeof(h264_seq_raw)];
|
||||
memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw));
|
||||
|
|
@ -2903,10 +2905,10 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoCodecSwitching)
|
|||
h264_frame->message_type_ = SrsFrameTypeVideo;
|
||||
|
||||
uint8_t h264_frame_raw[] = {
|
||||
0x17, // keyframe + AVC codec
|
||||
0x01, // AVC NALU
|
||||
0x00, 0x00, 0x00, // composition time
|
||||
0x00, 0x00, 0x00, 0x05, // NALU length
|
||||
0x17, // keyframe + AVC codec
|
||||
0x01, // AVC NALU
|
||||
0x00, 0x00, 0x00, // composition time
|
||||
0x00, 0x00, 0x00, 0x05, // NALU length
|
||||
0x65, 0x88, 0x84, 0x00, 0x10 // IDR slice data
|
||||
};
|
||||
|
||||
|
|
@ -2927,8 +2929,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoCodecSwitching)
|
|||
0x17, // keyframe + AVC codec
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20,
|
||||
0xac, 0xd9, 0x40, 0xc0, 0x29, 0xb0, 0x11, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00,
|
||||
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c
|
||||
};
|
||||
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c};
|
||||
|
||||
char *h264_data2 = new char[sizeof(h264_seq_raw2)];
|
||||
memcpy(h264_data2, h264_seq_raw2, sizeof(h264_seq_raw2));
|
||||
|
|
@ -4256,8 +4257,6 @@ VOID TEST(RtcFrameBuilderTest, TranscodeAudio_ErrorInTranscoderLoop)
|
|||
EXPECT_EQ(1, target.on_frame_count_); // Failed on first transcoded frame
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Test SrsRtcFrameBuilder::packet_video with complete frame detection and packet_video_rtmp error
|
||||
VOID TEST(RtcFrameBuilderTest, PacketVideo_CompleteFrameDetectionWithPacketVideoRtmpError)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,15 +8,15 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
#include <srs_app_rtc_codec.hpp>
|
||||
#include <srs_app_rtc_source.hpp>
|
||||
#include <srs_app_rtmp_source.hpp>
|
||||
#include <srs_core_autofree.hpp>
|
||||
#include <srs_kernel_error.hpp>
|
||||
#include <srs_kernel_packet.hpp>
|
||||
#include <srs_kernel_rtc_rtp.hpp>
|
||||
#include <srs_protocol_format.hpp>
|
||||
#include <srs_protocol_rtmp_stack.hpp>
|
||||
#include <srs_app_rtmp_source.hpp>
|
||||
#include <srs_app_rtc_codec.hpp>
|
||||
#include <srs_kernel_packet.hpp>
|
||||
|
||||
MockRtcFrameTarget::MockRtcFrameTarget()
|
||||
{
|
||||
|
|
@ -33,13 +33,13 @@ MockRtcFrameTarget::~MockRtcFrameTarget()
|
|||
srs_error_t MockRtcFrameTarget::on_frame(SrsMediaPacket *frame)
|
||||
{
|
||||
on_frame_count_++;
|
||||
|
||||
|
||||
// Store a copy of the frame for verification
|
||||
srs_freep(last_frame_);
|
||||
if (frame) {
|
||||
last_frame_ = frame->copy();
|
||||
}
|
||||
|
||||
|
||||
return srs_error_copy(frame_error_);
|
||||
}
|
||||
|
||||
|
|
@ -360,21 +360,21 @@ SrsRtpPacket *create_hevc_stap_packet_with_vps_sps_pps()
|
|||
VOID TEST(RtcFrameBuilderTest, OnRtp_NoPayload)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
||||
MockRtcFrameTarget target;
|
||||
SrsRtcFrameBuilder builder(&target);
|
||||
|
||||
|
||||
// Initialize the builder
|
||||
SrsUniquePtr<MockRtcRequest> req(new MockRtcRequest());
|
||||
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
|
||||
|
||||
|
||||
// Create RTP packet with no payload
|
||||
SrsUniquePtr<SrsRtpPacket> pkt(new SrsRtpPacket());
|
||||
pkt->set_avsync_time(1000);
|
||||
|
||||
|
||||
// Should return success but do nothing
|
||||
HELPER_EXPECT_SUCCESS(builder.on_rtp(pkt.get()));
|
||||
|
||||
|
||||
// No frames should be generated
|
||||
EXPECT_EQ(0, target.on_frame_count_);
|
||||
}
|
||||
|
|
@ -383,20 +383,20 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_NoPayload)
|
|||
VOID TEST(RtcFrameBuilderTest, OnRtp_NoAvsyncTime_InitialState)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
||||
MockRtcFrameTarget target;
|
||||
SrsRtcFrameBuilder builder(&target);
|
||||
|
||||
|
||||
// Initialize the builder
|
||||
SrsUniquePtr<MockRtcRequest> req(new MockRtcRequest());
|
||||
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
|
||||
|
||||
|
||||
// Create RTP packet with no avsync_time (initial sync_state_ is -1)
|
||||
SrsUniquePtr<SrsRtpPacket> pkt(create_mock_rtp_packet(true, 0)); // avsync_time = 0
|
||||
|
||||
|
||||
// Should return success but discard packet and change sync_state_ from -1 to 0
|
||||
HELPER_EXPECT_SUCCESS(builder.on_rtp(pkt.get()));
|
||||
|
||||
|
||||
// No frames should be generated
|
||||
EXPECT_EQ(0, target.on_frame_count_);
|
||||
}
|
||||
|
|
@ -405,22 +405,22 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_NoAvsyncTime_InitialState)
|
|||
VOID TEST(RtcFrameBuilderTest, OnRtp_NoAvsyncTime_StateZero)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
||||
MockRtcFrameTarget target;
|
||||
SrsRtcFrameBuilder builder(&target);
|
||||
|
||||
|
||||
// Initialize the builder
|
||||
SrsUniquePtr<MockRtcRequest> req(new MockRtcRequest());
|
||||
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
|
||||
|
||||
|
||||
// First packet with no avsync_time to set sync_state_ to 0
|
||||
SrsUniquePtr<SrsRtpPacket> pkt1(create_mock_rtp_packet(true, 0));
|
||||
HELPER_EXPECT_SUCCESS(builder.on_rtp(pkt1.get()));
|
||||
|
||||
|
||||
// Second packet with no avsync_time (sync_state_ is now 0, should not trace)
|
||||
SrsUniquePtr<SrsRtpPacket> pkt2(create_mock_rtp_packet(false, -1)); // avsync_time = -1
|
||||
HELPER_EXPECT_SUCCESS(builder.on_rtp(pkt2.get()));
|
||||
|
||||
|
||||
// No frames should be generated
|
||||
EXPECT_EQ(0, target.on_frame_count_);
|
||||
}
|
||||
|
|
@ -1789,8 +1789,6 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_ComprehensiveCodePathCoverage)
|
|||
HELPER_EXPECT_SUCCESS(builder.on_rtp(video_process.get()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Helper function to create a mock RTP packet with STAP-A payload containing SPS and PPS
|
||||
SrsRtpPacket *create_stap_a_packet_with_sps_pps()
|
||||
{
|
||||
|
|
@ -1844,10 +1842,6 @@ SrsRtpPacket *create_raw_payload_packet(SrsAvcNaluType nalu_type, const uint8_t
|
|||
return pkt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Test SrsRtcFrameBuilder::packet_sequence_header_avc with STAP-A payload containing SPS and PPS
|
||||
VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderAvc_STAPAPayload_WithSPSAndPPS)
|
||||
{
|
||||
|
|
@ -3332,7 +3326,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_OutOfOrderPackets)
|
|||
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
|
||||
|
||||
// Helper function to create audio packet
|
||||
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket* {
|
||||
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket * {
|
||||
SrsRtpPacket *pkt = new SrsRtpPacket();
|
||||
pkt->header_.set_ssrc(12345);
|
||||
pkt->header_.set_sequence(seq);
|
||||
|
|
@ -3354,23 +3348,28 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_OutOfOrderPackets)
|
|||
// Send packets out of order: 100, 102, 101, 104, 103
|
||||
SrsUniquePtr<SrsRtpPacket> pkt1(create_audio_packet(100, 48000, 1000));
|
||||
srs_error_t result1 = builder.packet_audio(pkt1.get());
|
||||
if (result1 != srs_success) srs_freep(result1);
|
||||
if (result1 != srs_success)
|
||||
srs_freep(result1);
|
||||
|
||||
SrsUniquePtr<SrsRtpPacket> pkt3(create_audio_packet(102, 48000 + 2 * 960, 1040));
|
||||
srs_error_t result3 = builder.packet_audio(pkt3.get());
|
||||
if (result3 != srs_success) srs_freep(result3);
|
||||
if (result3 != srs_success)
|
||||
srs_freep(result3);
|
||||
|
||||
SrsUniquePtr<SrsRtpPacket> pkt2(create_audio_packet(101, 48000 + 960, 1020));
|
||||
srs_error_t result2 = builder.packet_audio(pkt2.get());
|
||||
if (result2 != srs_success) srs_freep(result2);
|
||||
if (result2 != srs_success)
|
||||
srs_freep(result2);
|
||||
|
||||
SrsUniquePtr<SrsRtpPacket> pkt5(create_audio_packet(104, 48000 + 4 * 960, 1080));
|
||||
srs_error_t result5 = builder.packet_audio(pkt5.get());
|
||||
if (result5 != srs_success) srs_freep(result5);
|
||||
if (result5 != srs_success)
|
||||
srs_freep(result5);
|
||||
|
||||
SrsUniquePtr<SrsRtpPacket> pkt4(create_audio_packet(103, 48000 + 3 * 960, 1060));
|
||||
srs_error_t result4 = builder.packet_audio(pkt4.get());
|
||||
if (result4 != srs_success) srs_freep(result4);
|
||||
if (result4 != srs_success)
|
||||
srs_freep(result4);
|
||||
|
||||
// Audio cache should handle out-of-order packets and deliver them in sequence
|
||||
}
|
||||
|
|
@ -3388,7 +3387,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_DuplicatePackets)
|
|||
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
|
||||
|
||||
// Helper function to create audio packet
|
||||
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket* {
|
||||
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket * {
|
||||
SrsRtpPacket *pkt = new SrsRtpPacket();
|
||||
pkt->header_.set_ssrc(12345);
|
||||
pkt->header_.set_sequence(seq);
|
||||
|
|
@ -3410,17 +3409,20 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_DuplicatePackets)
|
|||
// Send original packet
|
||||
SrsUniquePtr<SrsRtpPacket> pkt1(create_audio_packet(100, 48000, 1000));
|
||||
srs_error_t result1 = builder.packet_audio(pkt1.get());
|
||||
if (result1 != srs_success) srs_freep(result1);
|
||||
if (result1 != srs_success)
|
||||
srs_freep(result1);
|
||||
|
||||
// Send duplicate packet with same sequence number
|
||||
SrsUniquePtr<SrsRtpPacket> pkt1_dup(create_audio_packet(100, 48000, 1000));
|
||||
srs_error_t result1_dup = builder.packet_audio(pkt1_dup.get());
|
||||
if (result1_dup != srs_success) srs_freep(result1_dup);
|
||||
if (result1_dup != srs_success)
|
||||
srs_freep(result1_dup);
|
||||
|
||||
// Send next packet
|
||||
SrsUniquePtr<SrsRtpPacket> pkt2(create_audio_packet(101, 48000 + 960, 1020));
|
||||
srs_error_t result2 = builder.packet_audio(pkt2.get());
|
||||
if (result2 != srs_success) srs_freep(result2);
|
||||
if (result2 != srs_success)
|
||||
srs_freep(result2);
|
||||
|
||||
// Audio cache should handle duplicate packets gracefully
|
||||
}
|
||||
|
|
@ -3438,7 +3440,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_LatePackets)
|
|||
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
|
||||
|
||||
// Helper function to create audio packet
|
||||
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket* {
|
||||
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket * {
|
||||
SrsRtpPacket *pkt = new SrsRtpPacket();
|
||||
pkt->header_.set_ssrc(12345);
|
||||
pkt->header_.set_sequence(seq);
|
||||
|
|
@ -3460,20 +3462,24 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_LatePackets)
|
|||
// Send packets in order: 100, 101, 102
|
||||
SrsUniquePtr<SrsRtpPacket> pkt1(create_audio_packet(100, 48000, 1000));
|
||||
srs_error_t result1 = builder.packet_audio(pkt1.get());
|
||||
if (result1 != srs_success) srs_freep(result1);
|
||||
if (result1 != srs_success)
|
||||
srs_freep(result1);
|
||||
|
||||
SrsUniquePtr<SrsRtpPacket> pkt2(create_audio_packet(101, 48000 + 960, 1020));
|
||||
srs_error_t result2 = builder.packet_audio(pkt2.get());
|
||||
if (result2 != srs_success) srs_freep(result2);
|
||||
if (result2 != srs_success)
|
||||
srs_freep(result2);
|
||||
|
||||
SrsUniquePtr<SrsRtpPacket> pkt3(create_audio_packet(102, 48000 + 2 * 960, 1040));
|
||||
srs_error_t result3 = builder.packet_audio(pkt3.get());
|
||||
if (result3 != srs_success) srs_freep(result3);
|
||||
if (result3 != srs_success)
|
||||
srs_freep(result3);
|
||||
|
||||
// Now send a late packet with sequence number 99 (before already processed 100)
|
||||
SrsUniquePtr<SrsRtpPacket> late_pkt(create_audio_packet(99, 48000 - 960, 980));
|
||||
srs_error_t late_result = builder.packet_audio(late_pkt.get());
|
||||
if (late_result != srs_success) srs_freep(late_result);
|
||||
if (late_result != srs_success)
|
||||
srs_freep(late_result);
|
||||
|
||||
// Audio cache should discard late packets gracefully
|
||||
}
|
||||
|
|
@ -3662,7 +3668,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_SequenceWrapAround)
|
|||
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
|
||||
|
||||
// Helper function to create audio packet
|
||||
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket* {
|
||||
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket * {
|
||||
SrsRtpPacket *pkt = new SrsRtpPacket();
|
||||
pkt->header_.set_ssrc(12345);
|
||||
pkt->header_.set_sequence(seq);
|
||||
|
|
@ -3684,19 +3690,23 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_SequenceWrapAround)
|
|||
// Test sequence number wrap-around: 65534, 65535, 0, 1
|
||||
SrsUniquePtr<SrsRtpPacket> pkt1(create_audio_packet(65534, 48000, 1000));
|
||||
srs_error_t result1 = builder.packet_audio(pkt1.get());
|
||||
if (result1 != srs_success) srs_freep(result1);
|
||||
if (result1 != srs_success)
|
||||
srs_freep(result1);
|
||||
|
||||
SrsUniquePtr<SrsRtpPacket> pkt2(create_audio_packet(65535, 48000 + 960, 1020));
|
||||
srs_error_t result2 = builder.packet_audio(pkt2.get());
|
||||
if (result2 != srs_success) srs_freep(result2);
|
||||
if (result2 != srs_success)
|
||||
srs_freep(result2);
|
||||
|
||||
SrsUniquePtr<SrsRtpPacket> pkt3(create_audio_packet(0, 48000 + 2 * 960, 1040));
|
||||
srs_error_t result3 = builder.packet_audio(pkt3.get());
|
||||
if (result3 != srs_success) srs_freep(result3);
|
||||
if (result3 != srs_success)
|
||||
srs_freep(result3);
|
||||
|
||||
SrsUniquePtr<SrsRtpPacket> pkt4(create_audio_packet(1, 48000 + 3 * 960, 1060));
|
||||
srs_error_t result4 = builder.packet_audio(pkt4.get());
|
||||
if (result4 != srs_success) srs_freep(result4);
|
||||
if (result4 != srs_success)
|
||||
srs_freep(result4);
|
||||
|
||||
// Audio cache should handle sequence number wrap-around correctly
|
||||
}
|
||||
|
|
@ -3714,7 +3724,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_TimestampWrapAround)
|
|||
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
|
||||
|
||||
// Helper function to create audio packet
|
||||
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket* {
|
||||
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket * {
|
||||
SrsRtpPacket *pkt = new SrsRtpPacket();
|
||||
pkt->header_.set_ssrc(12345);
|
||||
pkt->header_.set_sequence(seq);
|
||||
|
|
@ -3736,19 +3746,23 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_TimestampWrapAround)
|
|||
// Test timestamp wrap-around: near UINT32_MAX, then wrap to 0
|
||||
SrsUniquePtr<SrsRtpPacket> pkt1(create_audio_packet(100, UINT32_MAX - 960, 1000));
|
||||
srs_error_t result1 = builder.packet_audio(pkt1.get());
|
||||
if (result1 != srs_success) srs_freep(result1);
|
||||
if (result1 != srs_success)
|
||||
srs_freep(result1);
|
||||
|
||||
SrsUniquePtr<SrsRtpPacket> pkt2(create_audio_packet(101, UINT32_MAX, 1020));
|
||||
srs_error_t result2 = builder.packet_audio(pkt2.get());
|
||||
if (result2 != srs_success) srs_freep(result2);
|
||||
if (result2 != srs_success)
|
||||
srs_freep(result2);
|
||||
|
||||
SrsUniquePtr<SrsRtpPacket> pkt3(create_audio_packet(102, 0, 1040));
|
||||
srs_error_t result3 = builder.packet_audio(pkt3.get());
|
||||
if (result3 != srs_success) srs_freep(result3);
|
||||
if (result3 != srs_success)
|
||||
srs_freep(result3);
|
||||
|
||||
SrsUniquePtr<SrsRtpPacket> pkt4(create_audio_packet(103, 960, 1060));
|
||||
srs_error_t result4 = builder.packet_audio(pkt4.get());
|
||||
if (result4 != srs_success) srs_freep(result4);
|
||||
if (result4 != srs_success)
|
||||
srs_freep(result4);
|
||||
|
||||
// Should handle timestamp wrap-around correctly
|
||||
}
|
||||
|
|
@ -3766,7 +3780,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_DifferentSSRC)
|
|||
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
|
||||
|
||||
// Helper function to create audio packet
|
||||
auto create_audio_packet = [](uint16_t seq, uint32_t ssrc, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket* {
|
||||
auto create_audio_packet = [](uint16_t seq, uint32_t ssrc, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket * {
|
||||
SrsRtpPacket *pkt = new SrsRtpPacket();
|
||||
pkt->header_.set_ssrc(ssrc);
|
||||
pkt->header_.set_sequence(seq);
|
||||
|
|
@ -3788,15 +3802,18 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_DifferentSSRC)
|
|||
// Send packets with different SSRC values
|
||||
SrsUniquePtr<SrsRtpPacket> pkt1(create_audio_packet(100, 11111, 48000, 1000));
|
||||
srs_error_t result1 = builder.packet_audio(pkt1.get());
|
||||
if (result1 != srs_success) srs_freep(result1);
|
||||
if (result1 != srs_success)
|
||||
srs_freep(result1);
|
||||
|
||||
SrsUniquePtr<SrsRtpPacket> pkt2(create_audio_packet(101, 22222, 48000 + 960, 1020));
|
||||
srs_error_t result2 = builder.packet_audio(pkt2.get());
|
||||
if (result2 != srs_success) srs_freep(result2);
|
||||
if (result2 != srs_success)
|
||||
srs_freep(result2);
|
||||
|
||||
SrsUniquePtr<SrsRtpPacket> pkt3(create_audio_packet(102, 33333, 48000 + 2 * 960, 1040));
|
||||
srs_error_t result3 = builder.packet_audio(pkt3.get());
|
||||
if (result3 != srs_success) srs_freep(result3);
|
||||
if (result3 != srs_success)
|
||||
srs_freep(result3);
|
||||
|
||||
// Should handle packets with different SSRC values
|
||||
}
|
||||
|
|
@ -3814,7 +3831,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_RapidSequence)
|
|||
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
|
||||
|
||||
// Helper function to create audio packet
|
||||
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket* {
|
||||
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket * {
|
||||
SrsRtpPacket *pkt = new SrsRtpPacket();
|
||||
pkt->header_.set_ssrc(12345);
|
||||
pkt->header_.set_sequence(seq);
|
||||
|
|
@ -3837,7 +3854,8 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_RapidSequence)
|
|||
for (int i = 0; i < 50; ++i) {
|
||||
SrsUniquePtr<SrsRtpPacket> pkt(create_audio_packet(100 + i, 48000 + i * 960, 1000 + i * 20));
|
||||
srs_error_t result = builder.packet_audio(pkt.get());
|
||||
if (result != srs_success) srs_freep(result);
|
||||
if (result != srs_success)
|
||||
srs_freep(result);
|
||||
}
|
||||
|
||||
// All packets should be processed through audio cache (transcoding may fail)
|
||||
|
|
@ -4185,7 +4203,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_SequenceWrapAround)
|
|||
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
|
||||
|
||||
// Helper function to create video packet
|
||||
auto create_video_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket* {
|
||||
auto create_video_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket * {
|
||||
SrsRtpPacket *pkt = new SrsRtpPacket();
|
||||
pkt->header_.set_ssrc(12345);
|
||||
pkt->header_.set_sequence(seq);
|
||||
|
|
@ -4234,7 +4252,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_TimestampWrapAround)
|
|||
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
|
||||
|
||||
// Helper function to create video packet
|
||||
auto create_video_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket* {
|
||||
auto create_video_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket * {
|
||||
SrsRtpPacket *pkt = new SrsRtpPacket();
|
||||
pkt->header_.set_ssrc(12345);
|
||||
pkt->header_.set_sequence(seq);
|
||||
|
|
@ -4283,7 +4301,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_DifferentSSRC)
|
|||
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
|
||||
|
||||
// Helper function to create video packet
|
||||
auto create_video_packet = [](uint16_t seq, uint32_t ssrc, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket* {
|
||||
auto create_video_packet = [](uint16_t seq, uint32_t ssrc, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket * {
|
||||
SrsRtpPacket *pkt = new SrsRtpPacket();
|
||||
pkt->header_.set_ssrc(ssrc);
|
||||
pkt->header_.set_sequence(seq);
|
||||
|
|
@ -4371,7 +4389,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_RapidSequence)
|
|||
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
|
||||
|
||||
// Helper function to create video packet
|
||||
auto create_video_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time, bool is_keyframe = false) -> SrsRtpPacket* {
|
||||
auto create_video_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time, bool is_keyframe = false) -> SrsRtpPacket * {
|
||||
SrsRtpPacket *pkt = new SrsRtpPacket();
|
||||
pkt->header_.set_ssrc(12345);
|
||||
pkt->header_.set_sequence(seq);
|
||||
|
|
@ -4414,7 +4432,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_MixedKeyframeSequence)
|
|||
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
|
||||
|
||||
// Helper function to create video packet
|
||||
auto create_video_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time, SrsAvcNaluType nalu_type) -> SrsRtpPacket* {
|
||||
auto create_video_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time, SrsAvcNaluType nalu_type) -> SrsRtpPacket * {
|
||||
SrsRtpPacket *pkt = new SrsRtpPacket();
|
||||
pkt->header_.set_ssrc(12345);
|
||||
pkt->header_.set_sequence(seq);
|
||||
|
|
@ -4653,7 +4671,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_MixedPayloadSizes)
|
|||
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
|
||||
|
||||
// Helper function to create audio packet with specific payload size
|
||||
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time, int payload_size) -> SrsRtpPacket* {
|
||||
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time, int payload_size) -> SrsRtpPacket * {
|
||||
SrsRtpPacket *pkt = new SrsRtpPacket();
|
||||
pkt->header_.set_ssrc(12345);
|
||||
pkt->header_.set_sequence(seq);
|
||||
|
|
@ -4675,7 +4693,8 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_MixedPayloadSizes)
|
|||
for (int i = 0; i < 8; ++i) {
|
||||
SrsUniquePtr<SrsRtpPacket> pkt(create_audio_packet(100 + i, 48000 + i * 960, 1000 + i * 20, payload_sizes[i]));
|
||||
srs_error_t result = builder.packet_audio(pkt.get());
|
||||
if (result != srs_success) srs_freep(result);
|
||||
if (result != srs_success)
|
||||
srs_freep(result);
|
||||
}
|
||||
|
||||
// Should handle packets with different payload sizes
|
||||
|
|
@ -4694,7 +4713,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_ComprehensiveScenario)
|
|||
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
|
||||
|
||||
// Helper function to create audio packet
|
||||
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket* {
|
||||
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket * {
|
||||
SrsRtpPacket *pkt = new SrsRtpPacket();
|
||||
pkt->header_.set_ssrc(12345);
|
||||
pkt->header_.set_sequence(seq);
|
||||
|
|
@ -4717,36 +4736,43 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_ComprehensiveScenario)
|
|||
// 1. Normal sequential packets
|
||||
SrsUniquePtr<SrsRtpPacket> pkt1(create_audio_packet(100, 48000, 1000));
|
||||
srs_error_t result1 = builder.packet_audio(pkt1.get());
|
||||
if (result1 != srs_success) srs_freep(result1);
|
||||
if (result1 != srs_success)
|
||||
srs_freep(result1);
|
||||
|
||||
SrsUniquePtr<SrsRtpPacket> pkt2(create_audio_packet(101, 48000 + 960, 1020));
|
||||
srs_error_t result2 = builder.packet_audio(pkt2.get());
|
||||
if (result2 != srs_success) srs_freep(result2);
|
||||
if (result2 != srs_success)
|
||||
srs_freep(result2);
|
||||
|
||||
// 2. Out-of-order packet
|
||||
SrsUniquePtr<SrsRtpPacket> pkt4(create_audio_packet(103, 48000 + 3 * 960, 1060));
|
||||
srs_error_t result4 = builder.packet_audio(pkt4.get());
|
||||
if (result4 != srs_success) srs_freep(result4);
|
||||
if (result4 != srs_success)
|
||||
srs_freep(result4);
|
||||
|
||||
// 3. Fill the gap
|
||||
SrsUniquePtr<SrsRtpPacket> pkt3(create_audio_packet(102, 48000 + 2 * 960, 1040));
|
||||
srs_error_t result3 = builder.packet_audio(pkt3.get());
|
||||
if (result3 != srs_success) srs_freep(result3);
|
||||
if (result3 != srs_success)
|
||||
srs_freep(result3);
|
||||
|
||||
// 4. Duplicate packet
|
||||
SrsUniquePtr<SrsRtpPacket> pkt3_dup(create_audio_packet(102, 48000 + 2 * 960, 1040));
|
||||
srs_error_t result3_dup = builder.packet_audio(pkt3_dup.get());
|
||||
if (result3_dup != srs_success) srs_freep(result3_dup);
|
||||
if (result3_dup != srs_success)
|
||||
srs_freep(result3_dup);
|
||||
|
||||
// 5. Late packet (should be discarded)
|
||||
SrsUniquePtr<SrsRtpPacket> late_pkt(create_audio_packet(99, 48000 - 960, 980));
|
||||
srs_error_t late_result = builder.packet_audio(late_pkt.get());
|
||||
if (late_result != srs_success) srs_freep(late_result);
|
||||
if (late_result != srs_success)
|
||||
srs_freep(late_result);
|
||||
|
||||
// 6. Continue with normal sequence
|
||||
SrsUniquePtr<SrsRtpPacket> pkt5(create_audio_packet(104, 48000 + 4 * 960, 1080));
|
||||
srs_error_t result5 = builder.packet_audio(pkt5.get());
|
||||
if (result5 != srs_success) srs_freep(result5);
|
||||
if (result5 != srs_success)
|
||||
srs_freep(result5);
|
||||
|
||||
// All scenarios should be handled correctly by the audio cache (transcoding may fail)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,12 +12,12 @@
|
|||
*/
|
||||
#include <srs_utest.hpp>
|
||||
|
||||
#include <srs_app_rtc_codec.hpp>
|
||||
#include <srs_app_rtc_source.hpp>
|
||||
#include <srs_kernel_rtc_rtp.hpp>
|
||||
#include <srs_protocol_amf0.hpp>
|
||||
#include <srs_protocol_format.hpp>
|
||||
#include <srs_protocol_rtmp_stack.hpp>
|
||||
#include <srs_protocol_amf0.hpp>
|
||||
#include <srs_app_rtc_codec.hpp>
|
||||
|
||||
// Forward declarations
|
||||
class SrsMediaPacket;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user