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 21 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
202 changes: 199 additions & 3 deletions trunk/src/app/srs_app_srt_source.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ srs_error_t SrsRtmpFromSrtBridge::on_ts_message(SrsTsMessage* msg)
}

// check supported codec
if (msg->channel->stream != SrsTsStreamVideoH264 && msg->channel->stream != SrsTsStreamAudioAAC) {
if (msg->channel->stream != SrsTsStreamVideoH264 && msg->channel->stream != SrsTsStreamVideoHEVC && msg->channel->stream != SrsTsStreamAudioAAC) {
return srs_error_new(ERROR_STREAM_CASTER_TS_CODEC, "ts: unsupported stream codec=%d", msg->channel->stream);
}

Expand All @@ -347,7 +347,7 @@ srs_error_t SrsRtmpFromSrtBridge::on_ts_message(SrsTsMessage* msg)

// publish audio or video.
if (msg->channel->stream == SrsTsStreamVideoH264) {
if ((err = on_ts_video(msg, &avs)) != srs_success) {
if ((err = on_ts_video_avc(msg, &avs)) != srs_success) {
return srs_error_wrap(err, "ts: consume video");
}
}
Expand All @@ -358,10 +358,18 @@ srs_error_t SrsRtmpFromSrtBridge::on_ts_message(SrsTsMessage* msg)
}

// TODO: FIXME: implements other codec?
#ifdef SRS_H265
chundonglinlin marked this conversation as resolved.
Show resolved Hide resolved
if (msg->channel->stream == SrsTsStreamVideoHEVC) {
if ((err = on_ts_video_hevc(msg, &avs)) != srs_success) {
return srs_error_wrap(err, "ts: consume hevc video");
}
}
#endif

return err;
}

srs_error_t SrsRtmpFromSrtBridge::on_ts_video(SrsTsMessage* msg, SrsBuffer* avs)
srs_error_t SrsRtmpFromSrtBridge::on_ts_video_avc(SrsTsMessage* msg, SrsBuffer* avs)
{
srs_error_t err = srs_success;

Expand Down Expand Up @@ -525,6 +533,194 @@ srs_error_t SrsRtmpFromSrtBridge::on_h264_frame(SrsTsMessage* msg, vector<pair<c
return err;
}

#ifdef SRS_H265
srs_error_t SrsRtmpFromSrtBridge::on_ts_video_hevc(SrsTsMessage *msg, SrsBuffer *avs)
{
srs_error_t err = srs_success;

vector<pair<char*, int> > ipb_frames;

SrsRawHEVCStream *hevc = new SrsRawHEVCStream();
SrsAutoFree(SrsRawHEVCStream, hevc);

// send each frame.
while (!avs->empty()) {
char* frame = NULL;
int frame_size = 0;
if ((err = hevc->annexb_demux(avs, &frame, &frame_size)) != srs_success) {
return srs_error_wrap(err, "demux hevc annexb");
}

if (frame == NULL || frame_size == 0) {
continue;
}

// for vps
if (hevc->is_vps(frame, frame_size)) {
std::string vps;
if ((err = hevc->vps_demux(frame, frame_size, vps)) != srs_success) {
return srs_error_wrap(err, "demux vps");
}

if (!vps.empty() && hevc_vps_ != vps) {
vps_sps_pps_change_ = true;
}

hevc_vps_ = vps;
continue;
}

// for sps
if (hevc->is_sps(frame, frame_size)) {
std::string sps;
if ((err = hevc->sps_demux(frame, frame_size, sps)) != srs_success) {
return srs_error_wrap(err, "demux sps");
}

if (! sps.empty() && hevc_sps_ != sps) {
vps_sps_pps_change_ = true;
}

hevc_sps_ = sps;
continue;
}

// for pps
if (hevc->is_pps(frame, frame_size)) {
std::string pps;
if ((err = hevc->pps_demux(frame, frame_size, pps)) != srs_success) {
return srs_error_wrap(err, "demux pps");
}

if (! pps.empty() && hevc_pps_ != pps) {
vps_sps_pps_change_ = true;
}

hevc_pps_ = pps;
continue;
}

ipb_frames.push_back(make_pair(frame, frame_size));
}

if ((err = check_vps_sps_pps_change(msg)) != srs_success) {
return srs_error_wrap(err, "check vps sps pps");
}

return on_hevc_frame(msg, ipb_frames);
}

srs_error_t SrsRtmpFromSrtBridge::check_vps_sps_pps_change(SrsTsMessage* msg)
{
srs_error_t err = srs_success;

if (!vps_sps_pps_change_) {
return err;
}

if (hevc_vps_.empty() || hevc_sps_.empty() || hevc_pps_.empty()) {
return srs_error_new(ERROR_SRT_TO_RTMP_EMPTY_SPS_PPS, "vps or sps or pps empty");
}

// vps/sps/pps changed, generate new video sh frame and dispatch it.
vps_sps_pps_change_ = false;

// ts tbn to flv tbn.
uint32_t dts = (uint32_t)(msg->dts / 90);

std::string sh;
SrsRawHEVCStream* hevc = new SrsRawHEVCStream();
SrsAutoFree(SrsRawHEVCStream, hevc);

if ((err = hevc->mux_sequence_header(hevc_vps_, hevc_sps_, hevc_pps_, sh)) != srs_success) {
return srs_error_wrap(err, "mux sequence header");
}

// h265 packet to flv packet.
char* flv = NULL;
int nb_flv = 0;
if ((err = hevc->mux_avc2flv(sh, SrsVideoAvcFrameTypeKeyFrame, SrsVideoAvcFrameTraitSequenceHeader, dts, dts, &flv, &nb_flv)) != srs_success) {
return srs_error_wrap(err, "avc to flv");
}

SrsMessageHeader header;
header.initialize_video(nb_flv, dts, video_streamid_);
SrsCommonMessage rtmp;
if ((err = rtmp.create(&header, flv, nb_flv)) != srs_success) {
return srs_error_wrap(err, "create rtmp");
}

if ((err = live_source_->on_video(&rtmp)) != srs_success) {
return srs_error_wrap(err, "srt to rtmp sps/pps");
}

return err;
}

srs_error_t SrsRtmpFromSrtBridge::on_hevc_frame(SrsTsMessage* msg, vector<pair<char*, int> >& ipb_frames)
{
srs_error_t err = srs_success;

if (ipb_frames.empty()) {
return srs_error_new(ERROR_SRT_CONN, "empty frame");
}

// ts tbn to flv tbn.
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.
SrsVideoAvcFrameType frame_type = SrsVideoAvcFrameTypeInterFrame;

// 5bytes video tag header
int frame_size = 5;
for (size_t i = 0; i != ipb_frames.size(); ++i) {
// 4 bytes for nalu length.
frame_size += 4 + ipb_frames[i].second;
SrsHevcNaluType nalu_type = SrsHevcNaluTypeParse(ipb_frames[i].first[0]);
if ((nalu_type >= SrsHevcNaluType_CODED_SLICE_BLA) && (nalu_type <= SrsHevcNaluType_RESERVED_23)) {
frame_type = SrsVideoAvcFrameTypeKeyFrame;
}
}

SrsCommonMessage rtmp;
rtmp.header.initialize_video(frame_size, dts, video_streamid_);
rtmp.create_payload(frame_size);
rtmp.size = frame_size;
SrsBuffer payload(rtmp.payload, rtmp.size);

// Write 5bytes video tag header.

// @see: E.4.3 Video Tags, video_file_format_spec_v10_1.pdf, page 78
// Frame Type, Type of video frame.
// 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.
for (size_t i = 0; i != ipb_frames.size(); ++i) {
char* nal = ipb_frames[i].first;
int nal_size = ipb_frames[i].second;

// write 4 bytes of nalu length.
payload.write_4bytes(nal_size);
// write nalu
payload.write_bytes(nal, nal_size);
}

if ((err = live_source_->on_video(&rtmp)) != srs_success) {
return srs_error_wrap(err ,"srt ts hevc video to rtmp");
}

return err;
}
#endif

srs_error_t SrsRtmpFromSrtBridge::on_ts_audio(SrsTsMessage* msg, SrsBuffer* avs)
{
srs_error_t err = srs_success;
Expand Down
16 changes: 15 additions & 1 deletion trunk/src/app/srs_app_srt_source.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,19 @@ class SrsRtmpFromSrtBridge : public ISrsSrtSourceBridge, public ISrsTsHandler
public:
virtual srs_error_t on_ts_message(SrsTsMessage* msg);
private:
srs_error_t on_ts_video(SrsTsMessage* msg, SrsBuffer* avs);
srs_error_t on_ts_video_avc(SrsTsMessage* msg, SrsBuffer* avs);
srs_error_t on_ts_audio(SrsTsMessage* msg, SrsBuffer* avs);
srs_error_t check_sps_pps_change(SrsTsMessage* msg);
srs_error_t on_h264_frame(SrsTsMessage* msg, std::vector<std::pair<char*, int> >& ipb_frames);
srs_error_t check_audio_sh_change(SrsTsMessage* msg, uint32_t pts);
srs_error_t on_aac_frame(SrsTsMessage* msg, uint32_t pts, char* frame, int frame_size);

#ifdef SRS_H265
srs_error_t on_ts_video_hevc(SrsTsMessage *msg, SrsBuffer *avs);
srs_error_t check_vps_sps_pps_change(SrsTsMessage *msg);
srs_error_t on_hevc_frame(SrsTsMessage *msg, std::vector<std::pair<char *, int>> &ipb_frames);
#endif

private:
SrsTsContext* ts_ctx_;

Expand All @@ -131,6 +138,13 @@ class SrsRtmpFromSrtBridge : public ISrsSrtSourceBridge, public ISrsTsHandler
std::string sps_;
std::string pps_;

#ifdef SRS_H265
bool vps_sps_pps_change_;
std::string hevc_vps_;
std::string hevc_sps_;
winlinvip marked this conversation as resolved.
Show resolved Hide resolved
std::string hevc_pps_;
#endif

// Record audio sepcific config had changed, if change, need to generate new audio sh frame.
bool audio_sh_change_;
std::string audio_sh_;
Expand Down
4 changes: 4 additions & 0 deletions trunk/src/kernel/srs_kernel_codec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,10 @@ SrsFormat::~SrsFormat()

srs_error_t SrsFormat::initialize()
{
if (!vcodec) {
vcodec = new SrsVideoCodecConfig();
}

return srs_success;
}

Expand Down
9 changes: 7 additions & 2 deletions trunk/src/kernel/srs_kernel_error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,9 @@
XX(ERROR_HTTP_WITH_BODY , 3097, "HttpWithBody", "Failed for HTTP body") \
XX(ERROR_HEVC_DISABLED , 3098, "HevcDisabled", "HEVC is disabled") \
XX(ERROR_HEVC_DECODE_ERROR , 3099, "HevcDecode", "HEVC decode av stream failed") \
XX(ERROR_MP4_HVCC_CHANGE , 3100, "Mp4HvcCChange", "MP4 does not support video HvcC change")
XX(ERROR_MP4_HVCC_CHANGE , 3100, "Mp4HvcCChange", "MP4 does not support video HvcC change") \
XX(ERROR_HEVC_API_NO_PREFIXED , 3101, "HevcAnnexbPrefix", "No annexb prefix for HEVC decoder")

/**************************************************/
/* HTTP/StreamConverter protocol error. */
#define SRS_ERRNO_MAP_HTTP(XX) \
Expand Down Expand Up @@ -325,7 +327,10 @@
XX(ERROR_GB_CONFIG , 4052, "GbConfig", "Invalid configuration for GB28181") \
XX(ERROR_GB_TIMEOUT , 4053, "GbTimeout", "SIP or media connection timeout for GB28181") \
XX(ERROR_HEVC_NALU_UEV , 4054, "HevcNaluUev", "Failed to read UEV for HEVC NALU") \
XX(ERROR_HEVC_NALU_SEV , 4055, "HevcNaluSev", "Failed to read SEV for HEVC NALU")
XX(ERROR_HEVC_NALU_SEV , 4055, "HevcNaluSev", "Failed to read SEV for HEVC NALU") \
XX(ERROR_STREAM_CASTER_HEVC_VPS , 4054, "CasterTsHevcVps", "Invalid ts HEVC VPS for stream caster") \
XX(ERROR_STREAM_CASTER_HEVC_SPS , 4055, "CasterTsHevcSps", "Invalid ts HEVC SPS for stream caster") \
XX(ERROR_STREAM_CASTER_HEVC_PPS , 4056, "CasterTsHevcPps", "Invalid ts HEVC PPS for stream caster")

/**************************************************/
/* RTC protocol error. */
Expand Down
Loading