1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-02-13 11:51:57 +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

@ -8,8 +8,9 @@ The changelog for SRS.
## SRS 6.0 Changelog
* v5.0, 2023-04-01, Merge [#3392](https://github.com/ossrs/srs/pull/3392): Support composited bridges for 1:N protocols converting. v6.0.41 (#3392)
* v5.0, 2023-04-01, Merge [#3458](https://github.com/ossrs/srs/pull/3450): API: Support HTTP basic authentication for API. v6.0.40 (#3458)
* v6.0, 2023-04-08, Merge [#3495](https://github.com/ossrs/srs/pull/3495): RTMP: Support enhanced RTMP specification for HEVC. v6.0.42 (#3495)
* v6.0, 2023-04-01, Merge [#3392](https://github.com/ossrs/srs/pull/3392): Support composited bridges for 1:N protocols converting. v6.0.41 (#3392)
* v6.0, 2023-04-01, Merge [#3458](https://github.com/ossrs/srs/pull/3450): API: Support HTTP basic authentication for API. v6.0.40 (#3458)
* v6.0, 2023-03-27, Merge [#3450](https://github.com/ossrs/srs/pull/3450): WebRTC: Error message carries the SDP when failed. v6.0.39 (#3450)
* v6.0, 2023-03-25, Merge [#3477](https://github.com/ossrs/srs/pull/3477): Remove unnecessary NULL check in srs_freep. v6.0.38 (#3477)
* v6.0, 2023-03-25, Merge [#3455](https://github.com/ossrs/srs/pull/3455): RTC: Call on_play before create session, for it might be freed for timeout. v6.0.37 (#3455)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -102,7 +102,7 @@
</body>
<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="js/bootstrap.min.js"></script>
<script type="text/javascript" src="js/mpegts-1.7.2.min.js"></script>
<script type="text/javascript" src="js/mpegts-1.7.3.min.js"></script>
<script type="text/javascript" src="js/hls-0.14.17.min.js"></script>
<script type="text/javascript" src="js/dash-v4.5.1.all.min.js"></script>
<script type="text/javascript" src="js/json2.js"></script>

View file

@ -9,6 +9,6 @@
#define VERSION_MAJOR 6
#define VERSION_MINOR 0
#define VERSION_REVISION 41
#define VERSION_REVISION 42
#endif

View file

@ -153,8 +153,10 @@ bool SrsFlvVideo::keyframe(char* data, int size)
if (size < 1) {
return false;
}
char frame_type = data[0];
// See rtmp_specification_1.0.pdf
// See https://github.com/veovera/enhanced-rtmp
uint8_t frame_type = data[0] & 0x7f;
frame_type = (frame_type >> 4) & 0x0F;
return frame_type == SrsVideoAvcFrameTypeKeyFrame;
@ -173,14 +175,23 @@ bool SrsFlvVideo::sh(char* data, int size)
if (size < 2) {
return false;
}
char frame_type = data[0];
frame_type = (frame_type >> 4) & 0x0F;
char avc_packet_type = data[1];
uint8_t frame_type = data[0];
bool is_ext_header = frame_type & 0x80;
SrsVideoAvcFrameTrait avc_packet_type = SrsVideoAvcFrameTraitForbidden;
if (!is_ext_header) {
// See rtmp_specification_1.0.pdf
frame_type = (frame_type >> 4) & 0x0F;
avc_packet_type = (SrsVideoAvcFrameTrait)data[1];
} else {
// See https://github.com/veovera/enhanced-rtmp
avc_packet_type = (SrsVideoAvcFrameTrait)(frame_type & 0x0f);
frame_type = (frame_type >> 4) & 0x07;
}
// Note that SrsVideoHEVCFrameTraitPacketTypeSequenceStart is equal to SrsVideoAvcFrameTraitSequenceHeader
return frame_type == SrsVideoAvcFrameTypeKeyFrame
&& avc_packet_type == SrsVideoAvcFrameTraitSequenceHeader;
&& avc_packet_type == SrsVideoAvcFrameTraitSequenceHeader;
}
bool SrsFlvVideo::h264(char* data, int size)
@ -204,8 +215,24 @@ bool SrsFlvVideo::hevc(char* data, int size)
return false;
}
char codec_id = data[0];
codec_id = codec_id & 0x0F;
uint8_t frame_type = data[0];
bool is_ext_header = frame_type & 0x80;
SrsVideoCodecId codec_id = SrsVideoCodecIdForbidden;
if (!is_ext_header) {
// See rtmp_specification_1.0.pdf
codec_id = (SrsVideoCodecId)(frame_type & 0x0F);
} else {
// See https://github.com/veovera/enhanced-rtmp
if (size < 5) {
return false;
}
// Video FourCC
if (data[1] != 'h' || data[2] != 'v' || data[3] != 'c' || data[4] != '1') {
return false;
}
codec_id = SrsVideoCodecIdHEVC;
}
return codec_id == SrsVideoCodecIdHEVC;
}
@ -218,12 +245,34 @@ bool SrsFlvVideo::acceptable(char* data, int size)
return false;
}
char frame_type = data[0];
SrsVideoCodecId codec_id = (SrsVideoCodecId)(uint8_t)(frame_type & 0x0f);
frame_type = (frame_type >> 4) & 0x0f;
if (frame_type < 1 || frame_type > 5) {
return false;
uint8_t frame_type = data[0];
bool is_ext_header = frame_type & 0x80;
SrsVideoCodecId codec_id = SrsVideoCodecIdForbidden;
if (!is_ext_header) {
// See rtmp_specification_1.0.pdf
codec_id = (SrsVideoCodecId)(frame_type & 0x0f);
frame_type = (frame_type >> 4) & 0x0f;
if (frame_type < 1 || frame_type > 5) {
return false;
}
} else {
// See https://github.com/veovera/enhanced-rtmp
uint8_t packet_type = frame_type & 0x0f;
frame_type = (frame_type >> 4) & 0x07;
if (packet_type > SrsVideoHEVCFrameTraitPacketTypeMPEG2TSSequenceStart || frame_type > SrsVideoAvcFrameTypeVideoInfoFrame) {
return false;
}
if (size < 5) {
return false;
}
if (data[1] != 'h' || data[2] != 'v' || data[3] != 'c' || data[4] != '1') {
return false;
}
codec_id = SrsVideoCodecIdHEVC;
}
if (codec_id != SrsVideoCodecIdAVC && codec_id != SrsVideoCodecIdAV1 && codec_id != SrsVideoCodecIdHEVC) {
@ -775,33 +824,7 @@ srs_error_t SrsFormat::on_video(int64_t timestamp, char* data, int size)
SrsBuffer* buffer = new SrsBuffer(data, size);
SrsAutoFree(SrsBuffer, buffer);
// We already checked the size is positive and data is not NULL.
srs_assert(buffer->require(1));
// @see: E.4.3 Video Tags, video_file_format_spec_v10_1.pdf, page 78
int8_t frame_type = buffer->read_1bytes();
SrsVideoCodecId codec_id = (SrsVideoCodecId)(frame_type & 0x0f);
// Check codec for H.264 and H.265.
bool codec_ok = (codec_id == SrsVideoCodecIdAVC);
#ifdef SRS_H265
codec_ok = codec_ok ? true : (codec_id == SrsVideoCodecIdHEVC);
#endif
if (!codec_ok) return err;
if (!vcodec) {
vcodec = new SrsVideoCodecConfig();
}
if (!video) {
video = new SrsVideoFrame();
}
if ((err = video->initialize(vcodec)) != srs_success) {
return srs_error_wrap(err, "init video");
}
buffer->skip(-1 * buffer->pos());
return video_avc_demux(buffer, timestamp);
}
@ -847,18 +870,55 @@ bool SrsFormat::is_avc_sequence_header()
srs_error_t SrsFormat::video_avc_demux(SrsBuffer* stream, int64_t timestamp)
{
srs_error_t err = srs_success;
if (!stream->require(1)) {
return srs_error_new(ERROR_HLS_DECODE_ERROR, "video avc demux shall atleast 1bytes");
}
// Parse the frame type and the first bit indicates the ext header.
uint8_t frame_type = stream->read_1bytes();
bool is_ext_header = frame_type & 0x80;
// @see: E.4.3 Video Tags, video_file_format_spec_v10_1.pdf, page 78
int8_t frame_type = stream->read_1bytes();
SrsVideoCodecId codec_id = (SrsVideoCodecId)(frame_type & 0x0f);
frame_type = (frame_type >> 4) & 0x0f;
SrsVideoCodecId codec_id = SrsVideoCodecIdForbidden;
SrsVideoAvcFrameTrait packet_type = SrsVideoAvcFrameTraitForbidden;
if (!is_ext_header) {
// See rtmp_specification_1.0.pdf
codec_id = (SrsVideoCodecId)(frame_type & 0x0f);
frame_type = (frame_type >> 4) & 0x0f;
} else {
// See https://github.com/veovera/enhanced-rtmp
packet_type = (SrsVideoAvcFrameTrait)(frame_type & 0x0f);
frame_type = (frame_type >> 4) & 0x07;
if (!stream->require(4)) {
return srs_error_new(ERROR_HLS_DECODE_ERROR, "fourCC requires 4bytes, only %dbytes", stream->left());
}
uint32_t four_cc = stream->read_4bytes();
if (four_cc == 0x68766331) { // 'hvc1'=0x68766331
codec_id = SrsVideoCodecIdHEVC;
}
}
if (!vcodec) {
vcodec = new SrsVideoCodecConfig();
}
if (!video) {
video = new SrsVideoFrame();
}
if ((err = video->initialize(vcodec)) != srs_success) {
return srs_error_wrap(err, "init video");
}
video->frame_type = (SrsVideoAvcFrameType)frame_type;
// ignore info frame without error,
// @see https://github.com/ossrs/srs/issues/288#issuecomment-69863909
if (video->frame_type == SrsVideoAvcFrameTypeVideoInfoFrame) {
srs_warn("avc igone the info frame");
srs_warn("avc ignore the info frame");
return err;
}
@ -871,17 +931,29 @@ srs_error_t SrsFormat::video_avc_demux(SrsBuffer* stream, int64_t timestamp)
return srs_error_new(ERROR_HLS_DECODE_ERROR, "only support video H.264/H.265, actual=%d", codec_id);
}
vcodec->id = codec_id;
if (!stream->require(4)) {
return srs_error_new(ERROR_HLS_DECODE_ERROR, "avc decode avc_packet_type");
int32_t composition_time = 0;
if (!is_ext_header) {
// See rtmp_specification_1.0.pdf
if (!stream->require(4)) {
return srs_error_new(ERROR_HLS_DECODE_ERROR, "requires 4bytes, only %dbytes", stream->left());
}
packet_type = (SrsVideoAvcFrameTrait)stream->read_1bytes();
composition_time = stream->read_3bytes();
} else {
// See https://github.com/veovera/enhanced-rtmp
if (packet_type == SrsVideoHEVCFrameTraitPacketTypeCodedFrames) {
if (!stream->require(3)) {
return srs_error_new(ERROR_HLS_DECODE_ERROR, "requires 3 bytes, only %dbytes", stream->left());
}
composition_time = stream->read_3bytes();
}
}
int8_t avc_packet_type = stream->read_1bytes();
int32_t composition_time = stream->read_3bytes();
// pts = dts + cts.
video->dts = timestamp;
video->cts = composition_time;
video->avc_packet_type = (SrsVideoAvcFrameTrait)avc_packet_type;
video->avc_packet_type = packet_type;
// Update the RAW AVC data.
raw = stream->data() + stream->pos();
@ -890,12 +962,12 @@ srs_error_t SrsFormat::video_avc_demux(SrsBuffer* stream, int64_t timestamp)
// Parse sequence header for H.265/HEVC.
if (codec_id == SrsVideoCodecIdHEVC) {
#ifdef SRS_H265
if (avc_packet_type == SrsVideoAvcFrameTraitSequenceHeader) {
if (packet_type == SrsVideoAvcFrameTraitSequenceHeader) {
// TODO: demux vps/sps/pps for hevc
if ((err = hevc_demux_hvcc(stream)) != srs_success) {
return srs_error_wrap(err, "demux hevc VPS/SPS/PPS");
}
} else if (avc_packet_type == SrsVideoAvcFrameTraitNALU) {
} else if (packet_type == SrsVideoAvcFrameTraitNALU || packet_type == SrsVideoHEVCFrameTraitPacketTypeCodedFramesX) {
// TODO: demux nalu for hevc
if ((err = video_nalu_demux(stream)) != srs_success) {
return srs_error_wrap(err, "demux hevc NALU");
@ -908,12 +980,12 @@ srs_error_t SrsFormat::video_avc_demux(SrsBuffer* stream, int64_t timestamp)
}
// Parse sequence header for H.264/AVC.
if (avc_packet_type == SrsVideoAvcFrameTraitSequenceHeader) {
if (packet_type == SrsVideoAvcFrameTraitSequenceHeader) {
// TODO: FIXME: Maybe we should ignore any error for parsing sps/pps.
if ((err = avc_demux_sps_pps(stream)) != srs_success) {
return srs_error_wrap(err, "demux SPS/PPS");
}
} else if (avc_packet_type == SrsVideoAvcFrameTraitNALU){
} else if (packet_type == SrsVideoAvcFrameTraitNALU){
if ((err = video_nalu_demux(stream)) != srs_success) {
return srs_error_wrap(err, "demux NALU");
}

View file

@ -64,12 +64,32 @@ std::string srs_video_codec_id2str(SrsVideoCodecId codec);
enum SrsVideoAvcFrameTrait
{
// set to the max value to reserved, for array map.
SrsVideoAvcFrameTraitReserved = 3,
SrsVideoAvcFrameTraitForbidden = 3,
SrsVideoAvcFrameTraitReserved = 6,
SrsVideoAvcFrameTraitForbidden = 6,
SrsVideoAvcFrameTraitSequenceHeader = 0,
SrsVideoAvcFrameTraitNALU = 1,
SrsVideoAvcFrameTraitSequenceHeaderEOF = 2,
SrsVideoHEVCFrameTraitPacketTypeSequenceStart = 0,
SrsVideoHEVCFrameTraitPacketTypeCodedFrames = 1,
SrsVideoHEVCFrameTraitPacketTypeSequenceEnd = 2,
// CompositionTime Offset is implied to equal zero. This is
// an optimization to save putting SI24 composition time value of zero on
// the wire. See pseudo code below in the VideoTagBody section
SrsVideoHEVCFrameTraitPacketTypeCodedFramesX = 3,
// VideoTagBody does not contain video data. VideoTagBody
// instead contains an AMF encoded metadata. See Metadata Frame
// section for an illustration of its usage. As an example, the metadata
// can be HDR information. This is a good way to signal HDR
// information. This also opens up future ways to express additional
// metadata that is meant for the next video sequence.
//
// note: presence of PacketTypeMetadata means that FrameType
// flags at the top of this table should be ignored
SrsVideoHEVCFrameTraitPacketTypeMetadata = 4,
// Carriage of bitstream in MPEG-2 TS format
SrsVideoHEVCFrameTraitPacketTypeMPEG2TSSequenceStart = 5,
};
/**

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));
}
}