SRT2RTMP: fix srt bridge hevc to rtmp error. v7.0.84 (#4446)
try to fix #4428. ## Cause rtmp do not support hevc, rtmp enhanced do. ## How to reproduce 1. start srs. `./objs/srs -c conf/srt.conf` 2. publish hevc (h.265) stream to srs by srt. `ffmpeg -re -i ./doc/source.flv -c:v libx265 -crf 28 -preset medium -c:a copy -pes_payload_size 0 -f mpegts 'srt://127.0.0.1:10080?streamid=#!::r=live/livestream,m=publish'` 3. probe the rtmp stream `ffprobe rtmp://localhost/live/livestream` ## About the Failed BlackBox test The failed blackbox test: `TestSlow_SrtPublish_RtmpPlay_HEVC_Basic` `TestSlow_SrtPublish_HttpFlvPlay_HEVC_Basic` ### Cause: The ffmpeg 5 is used to record a piece of video (DRV), the ffmpeg will transcode the enhanced flv format to TS format, but ffmpeg 5 don't support enhanced rtmp (or flv) in this case. The solution is to replace the ffmpeg to version 7 in those 2 test cases. ### why not upgrade ffmpeg to version 7? The black tests dependency on ffmpeg 5 will fail, and there are a few of them are not easy to resolve in ffmpeg 7. --------- Co-authored-by: winlin <winlinvip@gmail.com>
This commit is contained in:
parent
3a29e5c550
commit
a6d14eb09a
|
|
@ -709,6 +709,8 @@ func TestSlow_SrtPublish_RtmpPlay_HEVC_Basic(t *testing.T) {
|
||||||
v.dvrFile = path.Join(svr.WorkDir(), "objs", fmt.Sprintf("srs-ffprobe-%v.ts", streamID))
|
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.streamURL = fmt.Sprintf("rtmp://localhost:%v/live/%v", svr.RTMPPort(), streamID)
|
||||||
v.duration, v.timeout = duration, time.Duration(*srsFFprobeTimeout)*time.Millisecond
|
v.duration, v.timeout = duration, time.Duration(*srsFFprobeTimeout)*time.Millisecond
|
||||||
|
v.ffmpegCmdName = "ffmpeg7" // ffmpeg 5 don't support enhanced rtmp, so use ffmpeg 7 instead.
|
||||||
|
v.ffprobeCmdName = "ffprobe7"
|
||||||
})
|
})
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
|
|
@ -807,6 +809,8 @@ func TestSlow_SrtPublish_HttpFlvPlay_HEVC_Basic(t *testing.T) {
|
||||||
v.dvrFile = path.Join(svr.WorkDir(), "objs", fmt.Sprintf("srs-ffprobe-%v.ts", streamID))
|
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.streamURL = fmt.Sprintf("http://localhost:%v/live/%v.flv", svr.HTTPPort(), streamID)
|
||||||
v.duration, v.timeout = duration, time.Duration(*srsFFprobeTimeout)*time.Millisecond
|
v.duration, v.timeout = duration, time.Duration(*srsFFprobeTimeout)*time.Millisecond
|
||||||
|
v.ffmpegCmdName = "ffmpeg7" // ffmpeg 5 don't support enhanced rtmp, so use ffmpeg 7 instead.
|
||||||
|
v.ffprobeCmdName = "ffprobe7"
|
||||||
})
|
})
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
|
|
|
||||||
19
trunk/3rdparty/srs-bench/blackbox/util.go
vendored
19
trunk/3rdparty/srs-bench/blackbox/util.go
vendored
|
|
@ -666,6 +666,8 @@ type ffmpegClient struct {
|
||||||
// The backend service process.
|
// The backend service process.
|
||||||
process *backendService
|
process *backendService
|
||||||
|
|
||||||
|
// FFmpeg cmd name
|
||||||
|
ffmpegCmdName string
|
||||||
// FFmpeg cli args, without ffmpeg binary.
|
// FFmpeg cli args, without ffmpeg binary.
|
||||||
args []string
|
args []string
|
||||||
// Let the process quit, do not cancel the case.
|
// Let the process quit, do not cancel the case.
|
||||||
|
|
@ -678,6 +680,7 @@ func NewFFmpeg(opts ...func(v *ffmpegClient)) FFmpegClient {
|
||||||
v := &ffmpegClient{
|
v := &ffmpegClient{
|
||||||
process: newBackendService(),
|
process: newBackendService(),
|
||||||
cancelCaseWhenQuit: true,
|
cancelCaseWhenQuit: true,
|
||||||
|
ffmpegCmdName: *srsFFmpeg,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do cleanup.
|
// Do cleanup.
|
||||||
|
|
@ -702,7 +705,7 @@ func (v *ffmpegClient) ReadyCtx() context.Context {
|
||||||
func (v *ffmpegClient) Run(ctx context.Context, cancel context.CancelFunc) error {
|
func (v *ffmpegClient) Run(ctx context.Context, cancel context.CancelFunc) error {
|
||||||
logger.Tf(ctx, "Starting FFmpeg by %v", strings.Join(v.args, " "))
|
logger.Tf(ctx, "Starting FFmpeg by %v", strings.Join(v.args, " "))
|
||||||
|
|
||||||
v.process.name = *srsFFmpeg
|
v.process.name = v.ffmpegCmdName
|
||||||
v.process.args = v.args
|
v.process.args = v.args
|
||||||
v.process.env = os.Environ()
|
v.process.env = os.Environ()
|
||||||
v.process.duration = v.ffmpegDuration
|
v.process.duration = v.ffmpegDuration
|
||||||
|
|
@ -746,6 +749,10 @@ type ffprobeClient struct {
|
||||||
// The timeout to wait for task to done.
|
// The timeout to wait for task to done.
|
||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
|
|
||||||
|
// the FFprobe cmd name
|
||||||
|
ffprobeCmdName string
|
||||||
|
// the ffmpeg cmd name
|
||||||
|
ffmpegCmdName string
|
||||||
// Whether do DVR by FFmpeg, if using SRS DVR, please set to false.
|
// Whether do DVR by FFmpeg, if using SRS DVR, please set to false.
|
||||||
dvrByFFmpeg bool
|
dvrByFFmpeg bool
|
||||||
// The stream to DVR for probing. Ignore if not DVR by ffmpeg
|
// The stream to DVR for probing. Ignore if not DVR by ffmpeg
|
||||||
|
|
@ -764,8 +771,10 @@ type ffprobeClient struct {
|
||||||
|
|
||||||
func NewFFprobe(opts ...func(v *ffprobeClient)) FFprobeClient {
|
func NewFFprobe(opts ...func(v *ffprobeClient)) FFprobeClient {
|
||||||
v := &ffprobeClient{
|
v := &ffprobeClient{
|
||||||
metadata: &ffprobeObject{},
|
metadata: &ffprobeObject{},
|
||||||
dvrByFFmpeg: true,
|
dvrByFFmpeg: true,
|
||||||
|
ffprobeCmdName: *srsFFprobe,
|
||||||
|
ffmpegCmdName: *srsFFmpeg,
|
||||||
}
|
}
|
||||||
v.doneCtx, v.doneCancel = context.WithCancel(context.Background())
|
v.doneCtx, v.doneCancel = context.WithCancel(context.Background())
|
||||||
|
|
||||||
|
|
@ -842,7 +851,7 @@ func (v *ffprobeClient) doDVR(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
process := newBackendService()
|
process := newBackendService()
|
||||||
process.name = *srsFFmpeg
|
process.name = v.ffmpegCmdName
|
||||||
process.args = []string{
|
process.args = []string{
|
||||||
"-t", fmt.Sprintf("%v", int64(v.duration/time.Second)),
|
"-t", fmt.Sprintf("%v", int64(v.duration/time.Second)),
|
||||||
"-i", v.streamURL, "-c", "copy", "-y", v.dvrFile,
|
"-i", v.streamURL, "-c", "copy", "-y", v.dvrFile,
|
||||||
|
|
@ -869,7 +878,7 @@ func (v *ffprobeClient) doDVR(ctx context.Context) error {
|
||||||
|
|
||||||
func (v *ffprobeClient) doProbe(ctx context.Context, cancel context.CancelFunc) error {
|
func (v *ffprobeClient) doProbe(ctx context.Context, cancel context.CancelFunc) error {
|
||||||
process := newBackendService()
|
process := newBackendService()
|
||||||
process.name = *srsFFprobe
|
process.name = v.ffprobeCmdName
|
||||||
process.args = []string{
|
process.args = []string{
|
||||||
"-show_error", "-show_private_data", "-v", "quiet", "-find_stream_info",
|
"-show_error", "-show_private_data", "-v", "quiet", "-find_stream_info",
|
||||||
"-analyzeduration", fmt.Sprintf("%v", int64(v.duration/time.Microsecond)),
|
"-analyzeduration", fmt.Sprintf("%v", int64(v.duration/time.Microsecond)),
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ The changelog for SRS.
|
||||||
<a name="v7-changes"></a>
|
<a name="v7-changes"></a>
|
||||||
|
|
||||||
## SRS 7.0 Changelog
|
## SRS 7.0 Changelog
|
||||||
|
* v7.0, 2025-09-09, Merge [#4446](https://github.com/ossrs/srs/pull/4446): SRT2RTMP: fix srt bridge hevc to rtmp error. v7.0.84 (#4446)
|
||||||
* v7.0, 2025-09-09, Merge [#4482](https://github.com/ossrs/srs/pull/4482): AI: Fix naming issue for protocol module. v7.0.83 (#4482)
|
* v7.0, 2025-09-09, Merge [#4482](https://github.com/ossrs/srs/pull/4482): AI: Fix naming issue for protocol module. v7.0.83 (#4482)
|
||||||
* v7.0, 2025-09-07, Merge [#4479](https://github.com/ossrs/srs/pull/4479): AI: Fix naming problem in kernel module. v7.0.82 (#4479)
|
* v7.0, 2025-09-07, Merge [#4479](https://github.com/ossrs/srs/pull/4479): AI: Fix naming problem in kernel module. v7.0.82 (#4479)
|
||||||
* v7.0, 2025-09-06, Merge [#4478](https://github.com/ossrs/srs/pull/4478): AI: Add more utests for kernel module. v7.0.81 (#4478)
|
* v7.0, 2025-09-06, Merge [#4478](https://github.com/ossrs/srs/pull/4478): AI: Add more utests for kernel module. v7.0.81 (#4478)
|
||||||
|
|
|
||||||
|
|
@ -671,6 +671,7 @@ srs_error_t SrsSrtFrameBuilder::check_vps_sps_pps_change(SrsTsMessage *msg)
|
||||||
|
|
||||||
// ts tbn to flv tbn.
|
// ts tbn to flv tbn.
|
||||||
uint32_t dts = (uint32_t)(msg->dts_ / 90);
|
uint32_t dts = (uint32_t)(msg->dts_ / 90);
|
||||||
|
uint32_t pts = (uint32_t)(msg->pts_ / 90);
|
||||||
|
|
||||||
std::string sh;
|
std::string sh;
|
||||||
SrsUniquePtr<SrsRawHEVCStream> hevc(new SrsRawHEVCStream());
|
SrsUniquePtr<SrsRawHEVCStream> hevc(new SrsRawHEVCStream());
|
||||||
|
|
@ -682,8 +683,14 @@ srs_error_t SrsSrtFrameBuilder::check_vps_sps_pps_change(SrsTsMessage *msg)
|
||||||
// h265 packet to flv packet.
|
// h265 packet to flv packet.
|
||||||
char *flv = NULL;
|
char *flv = NULL;
|
||||||
int nb_flv = 0;
|
int nb_flv = 0;
|
||||||
if ((err = hevc->mux_avc2flv(sh, SrsVideoAvcFrameTypeKeyFrame, SrsVideoAvcFrameTraitSequenceHeader, dts, dts, &flv, &nb_flv)) != srs_success) {
|
if ((err = hevc->mux_avc2flv_enhanced(sh,
|
||||||
return srs_error_wrap(err, "avc to flv");
|
SrsVideoAvcFrameTypeKeyFrame,
|
||||||
|
SrsVideoHEVCFrameTraitPacketTypeSequenceStart,
|
||||||
|
dts,
|
||||||
|
pts,
|
||||||
|
&flv,
|
||||||
|
&nb_flv)) != srs_success) {
|
||||||
|
return srs_error_wrap(err, "hevc sh to flv");
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsMessageHeader header;
|
SrsMessageHeader header;
|
||||||
|
|
@ -713,8 +720,6 @@ srs_error_t SrsSrtFrameBuilder::on_hevc_frame(SrsTsMessage *msg, vector<pair<cha
|
||||||
|
|
||||||
// ts tbn to flv tbn.
|
// ts tbn to flv tbn.
|
||||||
uint32_t dts = (uint32_t)(msg->dts_ / 90);
|
uint32_t dts = (uint32_t)(msg->dts_ / 90);
|
||||||
uint32_t pts = (uint32_t)(msg->pts_ / 90);
|
|
||||||
int32_t cts = pts - dts;
|
|
||||||
|
|
||||||
// for IDR frame, the frame is keyframe.
|
// for IDR frame, the frame is keyframe.
|
||||||
SrsVideoAvcFrameType frame_type = SrsVideoAvcFrameTypeInterFrame;
|
SrsVideoAvcFrameType frame_type = SrsVideoAvcFrameTypeInterFrame;
|
||||||
|
|
@ -736,16 +741,9 @@ srs_error_t SrsSrtFrameBuilder::on_hevc_frame(SrsTsMessage *msg, vector<pair<cha
|
||||||
SrsBuffer payload(rtmp.payload(), rtmp.size());
|
SrsBuffer payload(rtmp.payload(), rtmp.size());
|
||||||
|
|
||||||
// Write 5bytes video tag header.
|
// Write 5bytes video tag header.
|
||||||
|
// @see: https://veovera.org/docs/enhanced/enhanced-rtmp-v1.pdf, page 8
|
||||||
// @see: E.4.3 Video Tags, video_file_format_spec_v10_1.pdf, page 78
|
payload.write_1bytes(SRS_FLV_IS_EX_HEADER | (frame_type << 4) | SrsVideoHEVCFrameTraitPacketTypeCodedFramesX);
|
||||||
// Frame Type, Type of video frame.
|
payload.write_4bytes(0x68766331); // 'h' 'v' 'c' '1'
|
||||||
// CodecID, Codec Identifier.
|
|
||||||
// set the rtmp header
|
|
||||||
payload.write_1bytes((frame_type << 4) | SrsVideoCodecIdHEVC);
|
|
||||||
// hevc_type: nalu
|
|
||||||
payload.write_1bytes(0x01);
|
|
||||||
// composition time
|
|
||||||
payload.write_3bytes(cts);
|
|
||||||
|
|
||||||
// Write video nalus.
|
// Write video nalus.
|
||||||
for (size_t i = 0; i != ipb_frames.size(); ++i) {
|
for (size_t i = 0; i != ipb_frames.size(); ++i) {
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,6 @@
|
||||||
|
|
||||||
#define VERSION_MAJOR 7
|
#define VERSION_MAJOR 7
|
||||||
#define VERSION_MINOR 0
|
#define VERSION_MINOR 0
|
||||||
#define VERSION_REVISION 83
|
#define VERSION_REVISION 84
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
Loading…
Reference in New Issue
Block a user