1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-03-09 15:49:59 +00:00

RTMP: Support enhanced RTMP specification for HEVC. v6.0.42 (#3495)

* RTMP: Support enhanced RTMP specification for HEVC,  v6.0.42.
* Player: Upgrade mpegts.js to support it.

Enhanced RTMP specification: https://github.com/veovera/enhanced-rtmp

First, start SRS `v6.0.42+` with HTTP-TS support:

```bash
./objs/srs -c conf/http.ts.live.conf
```

Then, you can use [OBS 29.1+](https://github.com/obsproject/obs-studio/releases) to push HEVC via RTMP.
Start OBS with the following settings in the `Settings > Stream` tab:

* Server: `rtmp://localhost/live`
* Stream Key: `livestream`
* Encoder: Please select the HEVC hardware encoder.

Finally, open the player http://localhost:8080/players/srs_player.html?stream=livestream.ts

Or use VLS or ffplay to play `http://localhost:8080/live/livestream.ts`

---------

Co-authored-by: chundonglinlin <chundonglinlin@163.com>
This commit is contained in:
Winlin 2023-04-08 09:18:10 +08:00 committed by GitHub
parent dcd02fe69c
commit 26aabe413d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 351 additions and 78 deletions

View file

@ -3897,7 +3897,8 @@ VOID TEST(KernelCodecTest, VideoFormat)
HELPER_EXPECT_SUCCESS(f.on_video(0, NULL, 0));
HELPER_EXPECT_SUCCESS(f.on_video(0, (char*)"\x00", 0));
HELPER_EXPECT_SUCCESS(f.on_video(0, (char*)"\x00", 1));
HELPER_EXPECT_FAILED(f.on_video(0, (char*)"\x00", 1));
HELPER_EXPECT_SUCCESS(f.on_video(0, (char*)"\x57", 1));
}
if (true) {
@ -4001,7 +4002,16 @@ VOID TEST(KernelCodecTest, HevcVideoFormat)
HELPER_EXPECT_SUCCESS(f.on_video(0, NULL, 0));
HELPER_EXPECT_SUCCESS(f.on_video(0, (char*)"\x00", 0));
HELPER_EXPECT_SUCCESS(f.on_video(0, (char*)"\x00", 1));
HELPER_EXPECT_FAILED(f.on_video(0, (char*)"\x00", 1));
// enhanced rtmp/flv
HELPER_EXPECT_SUCCESS(f.on_video(0, NULL, 0));
HELPER_EXPECT_SUCCESS(f.on_video(0, (char*)"\x80", 0));
HELPER_EXPECT_SUCCESS(f.on_video(0, (char*)"\x90", 0));
HELPER_EXPECT_SUCCESS(f.on_video(0, (char*)"\xd0\x68\x76\x63\x31", 5));
HELPER_EXPECT_FAILED(f.on_video(0, (char*)"\x80", 1));
HELPER_EXPECT_FAILED(f.on_video(0, (char*)"\x90", 1));
HELPER_EXPECT_FAILED(f.on_video(0, (char*)"\x90\x68\x76\x63\x31", 5));
}
if (true) {
@ -4010,11 +4020,22 @@ VOID TEST(KernelCodecTest, HevcVideoFormat)
//HEVC: 0x5c
HELPER_EXPECT_SUCCESS(f.on_video(0, (char*)"\x5c", 1));
HELPER_EXPECT_FAILED(f.on_video(0, (char*)"\x1c", 1));
// CodecId: 0x00
SrsBuffer b((char*)"\x00", 1);
srs_error_t err = f.video_avc_demux(&b, 0);
HELPER_EXPECT_FAILED(err);
// enhanced rtmp/flv
SrsBuffer b1((char*)"\x80", 1);
HELPER_EXPECT_FAILED(f.video_avc_demux(&b1, 0));
SrsBuffer b2((char*)"\x90", 1);
HELPER_EXPECT_FAILED(f.video_avc_demux(&b2, 0));
SrsBuffer b3((char*)"\x90\x68\x76\x63\x31", 5);
HELPER_EXPECT_FAILED(f.video_avc_demux(&b3, 0));
SrsBuffer b4((char*)"\xd0\x68\x76\x63\x31", 5);
HELPER_EXPECT_SUCCESS(f.video_avc_demux(&b4, 0));
}
uint8_t vps_sps_pps[] = {
@ -4075,6 +4096,93 @@ VOID TEST(KernelCodecTest, HevcVideoFormat)
HELPER_EXPECT_SUCCESS(f.on_video(0, (char*)rawIBMF, sizeof(rawIBMF)));
EXPECT_EQ(1, f.video->nb_samples);
}
// enhanced rtmp
uint8_t ext_vps_sps_pps[] = {
// IsExHeader | FrameType: UB[4]
// PacketType: UB[4]
0x90,
// Video FourCC
0x68, 0x76, 0x63, 0x31,
// SrsHevcDecoderConfigurationRecord
0x01, 0x01, 0x60, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0xf0, 0x00, 0xfc, 0xfd, 0xf8, 0xf8, 0x00, 0x00, 0x0f, 0x03,
// Nalus
// data_byte(1B)+num_nalus(2B)+nal_unit_length(2B)
0x20, 0x00, 0x01, 0x00, 0x18,
// VPS
0x40, 0x01, 0x0c, 0x01, 0xff, 0xff, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00, 0x90, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x5d, 0x95, 0x98, 0x09,
// data_byte(1B)+num_nalus(2B)+nal_unit_length(2B)
0x21, 0x00, 0x01, 0x00, 0x28,
// SPS
0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00, 0x90, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x5d, 0xa0, 0x02, 0x80, 0x80, 0x2d, 0x16,
0x59, 0x59, 0xa4, 0x93, 0x2b, 0xc0, 0x40, 0x40, 0x00, 0x00, 0xfa, 0x40, 0x00, 0x17, 0x70, 0x02,
// data_byte(1B)+num_nalus(2B)+nal_unit_length(2B)
0x22, 0x00, 0x01, 0x00, 0x07,
// PPS
0x44, 0x01, 0xc1, 0x72, 0xb4, 0x62, 0x40
};
uint8_t ext_rawIBMF[] = {
// IsExHeader | FrameType: UB[4]
// PacketType: UB[4]
0x93,
// Video FourCC
0x68, 0x76, 0x63, 0x31,
// HEVC NALU
0x00, 0x00, 0x00, 0x0b,
0x28, 0x1, 0xaf, 0x1d, 0x18, 0x38, 0xd4, 0x38, 0x32, 0xda, 0x23
};
uint8_t ext_rawIBMF1[] = {
// IsExHeader | FrameType: UB[4]
// PacketType: UB[4]
0x91,
// Video FourCC
0x68, 0x76, 0x63, 0x31,
// CompositionTime Offset
0x00, 0x00, 0x7d,
// HEVC NALU
0x00, 0x00, 0x00, 0x0b,
0x28, 0x1, 0xaf, 0x1d, 0x18, 0x38, 0xd4, 0x38, 0x32, 0xda, 0x23
};
if (true) {
SrsFormat f;
HELPER_EXPECT_SUCCESS(f.initialize());
// firstly demux sequence header
HELPER_EXPECT_SUCCESS(f.on_video(0, (char*)ext_vps_sps_pps, sizeof(ext_vps_sps_pps)));
EXPECT_EQ(1, f.video->frame_type);
EXPECT_EQ(0, f.video->avc_packet_type);
EXPECT_EQ(3, f.vcodec->hevc_dec_conf_record_.nalu_vec.size());
EXPECT_EQ(1280, f.vcodec->width);
EXPECT_EQ(720, f.vcodec->height);
// secondly demux sequence header
HELPER_EXPECT_SUCCESS(f.on_video(0, (char*)ext_vps_sps_pps, sizeof(ext_vps_sps_pps)));
EXPECT_EQ(1, f.video->frame_type);
EXPECT_EQ(0, f.video->avc_packet_type);
EXPECT_EQ(3, f.vcodec->hevc_dec_conf_record_.nalu_vec.size());
EXPECT_EQ(1280, f.vcodec->width);
EXPECT_EQ(720, f.vcodec->height);
HELPER_EXPECT_SUCCESS(f.on_video(0, (char*)ext_rawIBMF, sizeof(ext_rawIBMF)));
EXPECT_EQ(1, f.video->frame_type);
EXPECT_EQ(3, f.video->avc_packet_type);
EXPECT_EQ(1, f.video->nb_samples);
HELPER_EXPECT_SUCCESS(f.on_video(0, (char*)ext_rawIBMF, sizeof(ext_rawIBMF)));
EXPECT_EQ(1, f.video->frame_type);
EXPECT_EQ(3, f.video->avc_packet_type);
EXPECT_EQ(1, f.video->nb_samples);
// check cts
HELPER_EXPECT_SUCCESS(f.on_video(0, (char*)ext_rawIBMF1, sizeof(ext_rawIBMF1)));
EXPECT_EQ(1, f.video->frame_type);
EXPECT_EQ(125, f.video->cts);
EXPECT_EQ(1, f.video->avc_packet_type);
EXPECT_EQ(1, f.video->nb_samples);
}
}
#endif

View file

@ -411,3 +411,75 @@ VOID TEST(KernelFileWriterTest, RealfileTest)
EXPECT_STREQ("HelloWorld", str.substr(20).c_str());
}
VOID TEST(KernelRTMPExtTest, ExtRTMPTest)
{
srs_error_t err;
// For legacy RTMP specification, without ext tag header.
if (true) {
SrsFormat f;
HELPER_ASSERT_SUCCESS(f.initialize());
HELPER_EXPECT_SUCCESS(f.on_video(0, (char*) "\x17\x01\x00\x00\x12", 5));
// Verify the frame type, codec id, avc packet type and composition time.
EXPECT_EQ(SrsVideoAvcFrameTypeKeyFrame, f.video->frame_type);
EXPECT_EQ(SrsVideoCodecIdAVC, f.vcodec->id);
EXPECT_EQ(SrsVideoAvcFrameTraitNALU, f.video->avc_packet_type);
EXPECT_EQ(0x12, f.video->cts);
}
// For new RTMP enhanced specification, with ext tag header.
if (true) {
SrsFormat f;
HELPER_ASSERT_SUCCESS(f.initialize());
HELPER_EXPECT_SUCCESS(f.on_video(0, (char*) "\x91hvc1\x00\x00\x12", 8));
// Verify the frame type, codec id, avc packet type and composition time.
EXPECT_EQ(SrsVideoAvcFrameTypeKeyFrame, f.video->frame_type);
EXPECT_EQ(SrsVideoCodecIdHEVC, f.vcodec->id);
EXPECT_EQ(SrsVideoHEVCFrameTraitPacketTypeCodedFrames, f.video->avc_packet_type);
EXPECT_EQ(0x12, f.video->cts);
}
// If packet type is 3, which is coded frame X, the composition time is 0.
if (true) {
SrsFormat f;
HELPER_ASSERT_SUCCESS(f.initialize());
HELPER_EXPECT_SUCCESS(f.on_video(0, (char*) "\x93hvc1", 5));
// Verify the frame type, codec id, avc packet type and composition time.
EXPECT_EQ(SrsVideoAvcFrameTypeKeyFrame, f.video->frame_type);
EXPECT_EQ(SrsVideoCodecIdHEVC, f.vcodec->id);
EXPECT_EQ(SrsVideoHEVCFrameTraitPacketTypeCodedFramesX, f.video->avc_packet_type);
EXPECT_EQ(0, f.video->cts);
}
// Should fail if only 1 byte for ext tag header, should be more bytes for fourcc.
if (true) {
SrsFormat f;
HELPER_ASSERT_SUCCESS(f.initialize());
HELPER_EXPECT_FAILED(f.on_video(0, (char*) "\x91", 1));
}
// Should fail if only 5 bytes for ext tag header, should be more bytes for fourcc.
if (true) {
SrsFormat f;
HELPER_ASSERT_SUCCESS(f.initialize());
HELPER_EXPECT_FAILED(f.on_video(0, (char*) "\x91hvc1", 5));
}
// Should fail if codec id is hvc2 for ext tag header, should be hvc1.
if (true) {
SrsFormat f;
HELPER_ASSERT_SUCCESS(f.initialize());
HELPER_EXPECT_FAILED(f.on_video(0, (char*) "\x93hvc2", 5));
}
// Should fail if codec id is mvc1 for ext tag header, should be hvc1.
if (true) {
SrsFormat f;
HELPER_ASSERT_SUCCESS(f.initialize());
HELPER_EXPECT_FAILED(f.on_video(0, (char*) "\x93mvc1", 5));
}
}