Skip to content

Commit 8059ded

Browse files
H265: Support HEVC over SRT.(ossrs#465)
1 parent cd88eb0 commit 8059ded

File tree

5 files changed

+853
-1
lines changed

5 files changed

+853
-1
lines changed

trunk/src/app/srs_app_srt_source.cpp

+197-1
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ srs_error_t SrsRtmpFromSrtBridge::on_ts_message(SrsTsMessage* msg)
338338
}
339339

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

@@ -358,6 +358,14 @@ srs_error_t SrsRtmpFromSrtBridge::on_ts_message(SrsTsMessage* msg)
358358
}
359359

360360
// TODO: FIXME: implements other codec?
361+
#ifdef SRS_H265
362+
if (msg->channel->stream == SrsTsStreamVideoHEVC) {
363+
if ((err = on_ts_hevc(msg, &avs)) != srs_success) {
364+
return srs_error_wrap(err, "ts: consume hevc video");
365+
}
366+
}
367+
#endif
368+
361369
return err;
362370
}
363371

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

536+
#ifdef SRS_H265
537+
srs_error_t SrsRtmpFromSrtBridge::on_ts_hevc(SrsTsMessage *msg, SrsBuffer *avs)
538+
{
539+
srs_error_t err = srs_success;
540+
541+
vector<pair<char*, int> > ipb_frames;
542+
543+
SrsRawHEVCStream *hevc = new SrsRawHEVCStream();
544+
SrsAutoFree(SrsRawHEVCStream, hevc);
545+
546+
// send each frame.
547+
while (!avs->empty()) {
548+
char* frame = NULL;
549+
int frame_size = 0;
550+
if ((err = hevc->annexb_demux(avs, &frame, &frame_size)) != srs_success) {
551+
return srs_error_wrap(err, "demux hevc annexb");
552+
}
553+
554+
if (frame == NULL || frame_size == 0) {
555+
continue;
556+
}
557+
558+
// for vps
559+
if (hevc->is_vps(frame, frame_size)) {
560+
std::string vps;
561+
if ((err = hevc->sps_demux(frame, frame_size, vps)) != srs_success) {
562+
return srs_error_wrap(err, "demux vps");
563+
}
564+
565+
if (!vps.empty() && hevc_vps_ != vps) {
566+
vps_sps_pps_change_ = true;
567+
}
568+
569+
hevc_vps_ = vps;
570+
continue;
571+
}
572+
573+
// for sps
574+
if (hevc->is_sps(frame, frame_size)) {
575+
std::string sps;
576+
if ((err = hevc->sps_demux(frame, frame_size, sps)) != srs_success) {
577+
return srs_error_wrap(err, "demux sps");
578+
}
579+
580+
if (! sps.empty() && hevc_sps_ != sps) {
581+
vps_sps_pps_change_ = true;
582+
}
583+
584+
hevc_sps_ = sps;
585+
continue;
586+
}
587+
588+
// for pps
589+
if (hevc->is_pps(frame, frame_size)) {
590+
std::string pps;
591+
if ((err = hevc->pps_demux(frame, frame_size, pps)) != srs_success) {
592+
return srs_error_wrap(err, "demux pps");
593+
}
594+
595+
if (! pps.empty() && hevc_pps_ != pps) {
596+
vps_sps_pps_change_ = true;
597+
}
598+
599+
hevc_pps_ = pps;
600+
continue;
601+
}
602+
603+
ipb_frames.push_back(make_pair(frame, frame_size));
604+
}
605+
606+
if ((err = check_vps_sps_pps_change(msg)) != srs_success) {
607+
return srs_error_wrap(err, "check vps sps pps");
608+
}
609+
610+
return on_hevc_frame(msg, ipb_frames);
611+
}
612+
613+
srs_error_t SrsRtmpFromSrtBridge::check_vps_sps_pps_change(SrsTsMessage* msg)
614+
{
615+
srs_error_t err = srs_success;
616+
617+
if (!vps_sps_pps_change_) {
618+
return err;
619+
}
620+
621+
if (hevc_vps_.empty() || hevc_sps_.empty() || hevc_pps_.empty()) {
622+
return srs_error_new(ERROR_SRT_TO_RTMP_EMPTY_SPS_PPS, "vps or sps or pps empty");
623+
}
624+
625+
// vps/sps/pps changed, generate new video sh frame and dispatch it.
626+
vps_sps_pps_change_ = false;
627+
628+
// ts tbn to flv tbn.
629+
uint32_t dts = (uint32_t)(msg->dts / 90);
630+
631+
std::string sh;
632+
SrsRawHEVCStream* hevc = new SrsRawHEVCStream();
633+
SrsAutoFree(SrsRawHEVCStream, hevc);
634+
635+
if ((err = hevc->mux_sequence_header(hevc_vps_, hevc_sps_, hevc_pps_, sh)) != srs_success) {
636+
return srs_error_wrap(err, "mux sequence header");
637+
}
638+
639+
// h264 packet to flv packet.
640+
char* flv = NULL;
641+
int nb_flv = 0;
642+
if ((err = hevc->mux_avc2flv(sh, SrsVideoAvcFrameTypeKeyFrame, SrsVideoAvcFrameTraitSequenceHeader, dts, dts, &flv, &nb_flv)) != srs_success) {
643+
return srs_error_wrap(err, "avc to flv");
644+
}
645+
646+
SrsMessageHeader header;
647+
header.initialize_video(nb_flv, dts, video_streamid_);
648+
SrsCommonMessage rtmp;
649+
if ((err = rtmp.create(&header, flv, nb_flv)) != srs_success) {
650+
return srs_error_wrap(err, "create rtmp");
651+
}
652+
653+
if ((err = live_source_->on_video(&rtmp)) != srs_success) {
654+
return srs_error_wrap(err, "srt to rtmp sps/pps");
655+
}
656+
657+
return err;
658+
}
659+
660+
srs_error_t SrsRtmpFromSrtBridge::on_hevc_frame(SrsTsMessage* msg, vector<pair<char*, int> >& ipb_frames)
661+
{
662+
srs_error_t err = srs_success;
663+
664+
if (ipb_frames.empty()) {
665+
return srs_error_new(ERROR_SRT_CONN, "empty frame");
666+
}
667+
668+
// ts tbn to flv tbn.
669+
uint32_t dts = (uint32_t)(msg->dts / 90);
670+
uint32_t pts = (uint32_t)(msg->pts / 90);
671+
int32_t cts = pts - dts;
672+
673+
// for IDR frame, the frame is keyframe.
674+
SrsVideoAvcFrameType frame_type = SrsVideoAvcFrameTypeInterFrame;
675+
676+
// 5bytes video tag header
677+
int frame_size = 5;
678+
for (size_t i = 0; i != ipb_frames.size(); ++i) {
679+
// 4 bytes for nalu length.
680+
frame_size += 4 + ipb_frames[i].second;
681+
SrsHevcNaluType nal_unit_type = (SrsHevcNaluType)((ipb_frames[i].first[0] & 0x7e) >> 1);
682+
if ((nal_unit_type >= SrsHevcNaluType_CODED_SLICE_BLA) && (nal_unit_type <= SrsHevcNaluType_RESERVED_23)) {
683+
frame_type = SrsVideoAvcFrameTypeKeyFrame;
684+
}
685+
}
686+
687+
SrsCommonMessage rtmp;
688+
rtmp.header.initialize_video(frame_size, dts, video_streamid_);
689+
rtmp.create_payload(frame_size);
690+
rtmp.size = frame_size;
691+
SrsBuffer payload(rtmp.payload, rtmp.size);
692+
693+
// Write 5bytes video tag header.
694+
695+
// @see: E.4.3 Video Tags, video_file_format_spec_v10_1.pdf, page 78
696+
// Frame Type, Type of video frame.
697+
// CodecID, Codec Identifier.
698+
// set the rtmp header
699+
payload.write_1bytes((frame_type << 4) | SrsVideoCodecIdHEVC);
700+
// hevc_type: nalu
701+
payload.write_1bytes(0x01);
702+
// composition time
703+
payload.write_3bytes(cts);
704+
705+
// Write video nalus.
706+
for (size_t i = 0; i != ipb_frames.size(); ++i) {
707+
char* nal = ipb_frames[i].first;
708+
int nal_size = ipb_frames[i].second;
709+
710+
// write 4 bytes of nalu length.
711+
payload.write_4bytes(nal_size);
712+
// write nalu
713+
payload.write_bytes(nal, nal_size);
714+
}
715+
716+
if ((err = live_source_->on_video(&rtmp)) != srs_success) {
717+
return srs_error_wrap(err ,"srt ts hevc video to rtmp");
718+
}
719+
720+
return err;
721+
}
722+
#endif
723+
528724
srs_error_t SrsRtmpFromSrtBridge::on_ts_audio(SrsTsMessage* msg, SrsBuffer* avs)
529725
{
530726
srs_error_t err = srs_success;

trunk/src/app/srs_app_srt_source.hpp

+14
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,13 @@ class SrsRtmpFromSrtBridge : public ISrsSrtSourceBridge, public ISrsTsHandler
123123
srs_error_t on_h264_frame(SrsTsMessage* msg, std::vector<std::pair<char*, int> >& ipb_frames);
124124
srs_error_t check_audio_sh_change(SrsTsMessage* msg, uint32_t pts);
125125
srs_error_t on_aac_frame(SrsTsMessage* msg, uint32_t pts, char* frame, int frame_size);
126+
127+
#ifdef SRS_H265
128+
srs_error_t on_ts_hevc(SrsTsMessage *msg, SrsBuffer *avs);
129+
srs_error_t check_vps_sps_pps_change(SrsTsMessage *msg);
130+
srs_error_t on_hevc_frame(SrsTsMessage *msg, std::vector<std::pair<char *, int>> &ipb_frames);
131+
#endif
132+
126133
private:
127134
SrsTsContext* ts_ctx_;
128135

@@ -131,6 +138,13 @@ class SrsRtmpFromSrtBridge : public ISrsSrtSourceBridge, public ISrsTsHandler
131138
std::string sps_;
132139
std::string pps_;
133140

141+
#ifdef SRS_H265
142+
bool vps_sps_pps_change_;
143+
std::string hevc_vps_;
144+
std::string hevc_sps_;
145+
std::string hevc_pps_;
146+
#endif
147+
134148
// Record audio sepcific config had changed, if change, need to generate new audio sh frame.
135149
bool audio_sh_change_;
136150
std::string audio_sh_;

trunk/src/kernel/srs_kernel_error.hpp

+6
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,9 @@
275275
XX(ERROR_HEVC_DISABLED , 3098, "HevcDisabled", "HEVC is disabled") \
276276
XX(ERROR_HEVC_DECODE_ERROR , 3099, "HevcDecode", "HEVC decode av stream failed") \
277277
XX(ERROR_MP4_HVCC_CHANGE , 3100, "Mp4HvcCChange", "MP4 does not support video HvcC change")
278+
XX(ERROR_HEVC_DROP_BEFORE_SPS_PPS , 4050, "HevcDropBeforeSequence", "HEVC Drop frames before get sps and pps") \
279+
XX(ERROR_HEVC_API_NO_PREFIXED , 4051, "HevcAnnexbPrefix", "No annexb prefix for HEVC decoder")
280+
278281
/**************************************************/
279282
/* HTTP/StreamConverter protocol error. */
280283
#define SRS_ERRNO_MAP_HTTP(XX) \
@@ -324,6 +327,9 @@
324327
XX(ERROR_GB_SSRC_GENERATE , 4051, "GbSsrcGenerate", "Failed to generate SSRC for GB28181") \
325328
XX(ERROR_GB_CONFIG , 4052, "GbConfig", "Invalid configuration for GB28181") \
326329
XX(ERROR_GB_TIMEOUT , 4053, "GbTimeout", "SIP or media connection timeout for GB28181") \
330+
XX(ERROR_STREAM_CASTER_HEVC_VPS , 4060, "CasterTsHevcVps", "Invalid ts HEVC VPS for stream caster") \
331+
XX(ERROR_STREAM_CASTER_HEVC_SPS , 4061, "CasterTsHevcSps", "Invalid ts HEVC SPS for stream caster") \
332+
XX(ERROR_STREAM_CASTER_HEVC_PPS , 4062, "CasterTsHevcPps", "Invalid ts HEVC PPS for stream caster")
327333

328334
/**************************************************/
329335
/* RTC protocol error. */

0 commit comments

Comments
 (0)