Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

H265: Support HEVC over SRT.(#465) v6.0.20 #3366

Merged
merged 28 commits into from
Jan 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
5465107
H265: Support parse vps/pps info.
chundonglinlin Jan 11, 2023
cd88eb0
H265: Refine demux vps/sps/pps interface for SRT and GB.
chundonglinlin Jan 12, 2023
8059ded
H265: Support HEVC over SRT.(#465)
chundonglinlin Jan 6, 2023
b69ad38
SRT: Refine hevc demux interface.
chundonglinlin Jan 12, 2023
ad9ea4d
H265: add comment and require bit length.
chundonglinlin Jan 12, 2023
e90f9f4
H265: Update referenced doc.
chundonglinlin Jan 13, 2023
c92a638
UTest: add hevc vps/sps/pps utest.
chundonglinlin Jan 14, 2023
2b933fd
UTest: Refine test numOfArrays.
chundonglinlin Jan 14, 2023
b014ee6
H265: Refine and comment for vps/sps/pps.
chundonglinlin Jan 15, 2023
3e70128
UTest: test sps for windows.
chundonglinlin Jan 15, 2023
ca6c768
H265: Refine comment.
chundonglinlin Jan 15, 2023
5e41229
UTest: test case.
chundonglinlin Jan 15, 2023
3e2f20e
UTest: test case name.
chundonglinlin Jan 15, 2023
07b5ced
UTest: Determine hevc defined for test.
chundonglinlin Jan 15, 2023
bae31c9
H265: Refine reference page num.
chundonglinlin Jan 16, 2023
3eba4dd
SRT: Refine hevc nalu type parse.
chundonglinlin Jan 16, 2023
6f69270
H265: Refine the exponential golomb for ue.
chundonglinlin Jan 16, 2023
25a1c51
Merge remote-tracking branch 'srs/develop' into feature/hevc-over-srt
chundonglinlin Jan 17, 2023
8655d58
SRT: use SrsHevcNaluTypeParse and modify comment.
chundonglinlin Jan 18, 2023
26ced71
SRT: Rename avc/hevc bridge interface.
chundonglinlin Jan 18, 2023
58b283d
Merge branch 'develop' into feature/hevc-over-srt
winlinvip Jan 19, 2023
84d5869
SRT: fix mpegts.js play hevc http-flv error.
chundonglinlin Jan 19, 2023
99cb033
Merge branch 'feature/hevc-over-srt' of github.com:chundonglinlin/srs…
chundonglinlin Jan 19, 2023
355ec04
SRT: Refine init SrsFormat error.
chundonglinlin Jan 19, 2023
654c4fa
UTest: add srt hevc utest.
chundonglinlin Jan 20, 2023
f203b58
UTest: add HttpTsPlay utest.
chundonglinlin Jan 21, 2023
2d306ec
UTest: add HlsPlay utest.
chundonglinlin Jan 21, 2023
3265c35
Update release v6.0.20
winlinvip Jan 22, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
389 changes: 389 additions & 0 deletions trunk/3rdparty/srs-bench/blackbox/hevc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -644,3 +644,392 @@ func TestSlow_RtmpPublish_DvrMp4_HEVC_Basic(t *testing.T) {
}
}
}

func TestSlow_SrtPublish_RtmpPlay_HEVC_Basic(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()

// Only enable for github actions, ignore for darwin.
if runtime.GOOS == "darwin" {
logger.Tf(ctx, "Depends on FFmpeg(HEVC over RTMP), only available for GitHub actions")
return
}

// Check a set of errors.
var r0, r1, r2, r3, r4, r5, r6, r7 error
defer func(ctx context.Context) {
if err := filterTestError(ctx.Err(), r0, r1, r2, r3, r4, r5, r6, r7); 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_SRT_SERVER_ENABLED=on",
"SRS_VHOST_SRT_ENABLED=on",
"SRS_VHOST_SRT_SRT_TO_RTMP=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("srt://localhost:%v?streamid=#!::r=live/%v,m=publish", svr.SRTPort(), streamID)
ffmpeg := NewFFmpeg(func(v *ffmpegClient) {
v.args = []string{
// Use the fastest preset of x265, see https://x265.readthedocs.io/en/master/presets.html
"-stream_loop", "-1", "-re", "-i", *srsPublishAvatar, "-acodec", "copy", "-vcodec", "libx265",
"-profile:v", "main", "-preset", "ultrafast", "-pes_payload_size", "0", "-f", "mpegts", streamURL,
}
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r1 = ffmpeg.Run(ctx, cancel)
}()

// Start FFprobe to detect and verify stream.
duration := time.Duration(*srsFFprobeDuration) * time.Millisecond
ffprobe := NewFFprobe(func(v *ffprobeClient) {
v.dvrFile = path.Join(svr.WorkDir(), "objs", fmt.Sprintf("srs-ffprobe-%v.ts", streamID))
v.streamURL = fmt.Sprintf("rtmp://localhost:%v/live/%v", svr.RTMPPort(), 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 HLS score is low, so we only check duration.
if dv := m.Duration(); dv < duration {
r5 = errors.Errorf("short duration=%v < %v, %v, %v", dv, duration, m.String(), str)
}

if v := m.Video(); v == nil {
r5 = errors.Errorf("no video %v, %v", m.String(), str)
} else if v.CodecName != "hevc" {
r6 = errors.Errorf("invalid video codec=%v, %v, %v", v.CodecName, m.String(), str)
}
}
}

func TestSlow_SrtPublish_HttpFlvPlay_HEVC_Basic(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()

// Only enable for github actions, ignore for darwin.
if runtime.GOOS == "darwin" {
logger.Tf(ctx, "Depends on FFmpeg(HEVC over RTMP), only available for GitHub actions")
return
}

// Check a set of errors.
var r0, r1, r2, r3, r4, r5, r6, r7 error
defer func(ctx context.Context) {
if err := filterTestError(ctx.Err(), r0, r1, r2, r3, r4, r5, r6, r7); 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_HTTP_SERVER_ENABLED=on",
"SRS_SRT_SERVER_ENABLED=on",
"SRS_VHOST_SRT_ENABLED=on",
"SRS_VHOST_SRT_SRT_TO_RTMP=on",
"SRS_VHOST_HTTP_REMUX_ENABLED=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("srt://localhost:%v?streamid=#!::r=live/%v,m=publish", svr.SRTPort(), streamID)
ffmpeg := NewFFmpeg(func(v *ffmpegClient) {
v.args = []string{
// Use the fastest preset of x265, see https://x265.readthedocs.io/en/master/presets.html
"-stream_loop", "-1", "-re", "-i", *srsPublishAvatar, "-acodec", "copy", "-vcodec", "libx265",
"-profile:v", "main", "-preset", "ultrafast", "-pes_payload_size", "0", "-f", "mpegts", streamURL,
}
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r1 = ffmpeg.Run(ctx, cancel)
}()

// Start FFprobe to detect and verify stream.
duration := time.Duration(*srsFFprobeDuration) * time.Millisecond
ffprobe := NewFFprobe(func(v *ffprobeClient) {
v.dvrFile = path.Join(svr.WorkDir(), "objs", fmt.Sprintf("srs-ffprobe-%v.ts", streamID))
v.streamURL = fmt.Sprintf("http://localhost:%v/live/%v.flv", svr.HTTPPort(), 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 HLS score is low, so we only check duration.
if dv := m.Duration(); dv < duration {
r5 = errors.Errorf("short duration=%v < %v, %v, %v", dv, duration, m.String(), str)
}

if v := m.Video(); v == nil {
r5 = errors.Errorf("no video %v, %v", m.String(), str)
} else if v.CodecName != "hevc" {
r6 = errors.Errorf("invalid video codec=%v, %v, %v", v.CodecName, m.String(), str)
}
}
}

func TestSlow_SrtPublish_HttpTsPlay_HEVC_Basic(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()

// Only enable for github actions, ignore for darwin.
if runtime.GOOS == "darwin" {
logger.Tf(ctx, "Depends on FFmpeg(HEVC over RTMP), only available for GitHub actions")
return
}

// Check a set of errors.
var r0, r1, r2, r3, r4, r5, r6, r7 error
defer func(ctx context.Context) {
if err := filterTestError(ctx.Err(), r0, r1, r2, r3, r4, r5, r6, r7); 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_HTTP_SERVER_ENABLED=on",
"SRS_SRT_SERVER_ENABLED=on",
"SRS_VHOST_SRT_ENABLED=on",
"SRS_VHOST_SRT_SRT_TO_RTMP=on",
"SRS_VHOST_HTTP_REMUX_ENABLED=on",
"SRS_VHOST_HTTP_REMUX_MOUNT=[vhost]/[app]/[stream].ts",
}
})
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("srt://localhost:%v?streamid=#!::r=live/%v,m=publish", svr.SRTPort(), streamID)
ffmpeg := NewFFmpeg(func(v *ffmpegClient) {
v.args = []string{
// Use the fastest preset of x265, see https://x265.readthedocs.io/en/master/presets.htmlß
"-stream_loop", "-1", "-re", "-i", *srsPublishAvatar, "-acodec", "copy", "-vcodec", "libx265",
"-profile:v", "main", "-preset", "ultrafast", "-pes_payload_size", "0", "-f", "mpegts", streamURL,
}
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r1 = ffmpeg.Run(ctx, cancel)
}()

// Start FFprobe to detect and verify stream.
duration := time.Duration(*srsFFprobeDuration) * time.Millisecond
ffprobe := NewFFprobe(func(v *ffprobeClient) {
v.dvrFile = path.Join(svr.WorkDir(), "objs", fmt.Sprintf("srs-ffprobe-%v.ts", streamID))
v.streamURL = fmt.Sprintf("http://localhost:%v/live/%v.ts", svr.HTTPPort(), streamID)
v.duration, v.timeout = duration, time.Duration(*srsFFprobeTimeout)*time.Millisecond
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()

// wait for ffmpeg
time.Sleep(3 * time.Second)

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 HLS score is low, so we only check duration.
if dv := m.Duration(); dv < duration {
r5 = errors.Errorf("short duration=%v < %v, %v, %v", dv, duration, m.String(), str)
}

if v := m.Video(); v == nil {
r5 = errors.Errorf("no video %v, %v", m.String(), str)
} else if v.CodecName != "hevc" {
r6 = errors.Errorf("invalid video codec=%v, %v, %v", v.CodecName, m.String(), str)
}
}
}

func TestSlow_SrtPublish_HlsPlay_HEVC_Basic(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 error
defer func(ctx context.Context) {
if err := filterTestError(ctx.Err(), r0, r1, r2, r3, r4); 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_HTTP_SERVER_ENABLED=on",
"SRS_SRT_SERVER_ENABLED=on",
"SRS_VHOST_SRT_ENABLED=on",
"SRS_VHOST_SRT_SRT_TO_RTMP=on",
"SRS_VHOST_HLS_ENABLED=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("srt://localhost:%v?streamid=#!::r=live/%v,m=publish", svr.SRTPort(), streamID)
ffmpeg := NewFFmpeg(func(v *ffmpegClient) {
v.args = []string{
// Use the fastest preset of x265, see https://x265.readthedocs.io/en/master/presets.html
"-stream_loop", "-1", "-re", "-i", *srsPublishAvatar, "-acodec", "copy", "-vcodec", "libx265",
"-profile:v", "main", "-preset", "ultrafast", "-r", "25", "-g", "50", "-pes_payload_size", "0",
"-f", "mpegts", streamURL,
}
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()

// wait for ffmpeg
time.Sleep(3 * time.Second)

r1 = ffmpeg.Run(ctx, cancel)
}()

// Start FFprobe to detect and verify stream.
duration := time.Duration(*srsFFprobeDuration) * time.Millisecond
ffprobe := NewFFprobe(func(v *ffprobeClient) {
v.dvrFile = path.Join(svr.WorkDir(), "objs", fmt.Sprintf("srs-ffprobe-%v.ts", streamID))
v.streamURL = fmt.Sprintf("http://localhost:%v/live/%v.m3u8", svr.HTTPPort(), streamID)
v.duration, v.timeout = duration, time.Duration(*srsFFprobeHEVCTimeout)*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 HLS score is low, so we only check duration. Note that only check half of duration, because we
// might get only some pieces of segments.
if dv := m.Duration(); dv < duration/2 {
r4 = errors.Errorf("short duration=%v < %v, %v, %v", dv, duration/2, m.String(), str)
}
}
}
Loading