Skip to content

Commit a2870bb

Browse files
RTC: support hevc
1 parent 13597d1 commit a2870bb

12 files changed

+922
-125
lines changed

trunk/src/app/srs_app_rtc_conn.cpp

+122-44
Original file line numberDiff line numberDiff line change
@@ -2598,6 +2598,51 @@ bool srs_sdp_has_h264_profile(const SrsSdp& sdp, const string& profile)
25982598
return false;
25992599
}
26002600

2601+
bool srs_sdp_has_h265_profile(const SrsMediaPayloadType& payload_type, const string& profile)
2602+
{
2603+
srs_error_t err = srs_success;
2604+
2605+
if (payload_type.format_specific_param_.empty()) {
2606+
return false;
2607+
}
2608+
2609+
H265SpecificParam h265_param;
2610+
if ((err = srs_parse_h265_fmtp(payload_type.format_specific_param_, h265_param)) != srs_success) {
2611+
srs_error_reset(err);
2612+
return false;
2613+
}
2614+
2615+
if (h265_param.profile_id == profile) {
2616+
return true;
2617+
}
2618+
2619+
return false;
2620+
}
2621+
2622+
bool srs_sdp_has_h265_profile(const SrsSdp& sdp, const string& profile)
2623+
{
2624+
for (size_t i = 0; i < sdp.media_descs_.size(); ++i) {
2625+
const SrsMediaDesc& desc = sdp.media_descs_[i];
2626+
if (!desc.is_video()) {
2627+
continue;
2628+
}
2629+
2630+
std::vector<SrsMediaPayloadType> payloads = desc.find_media_with_encoding_name("H265");
2631+
if (payloads.empty()) {
2632+
continue;
2633+
}
2634+
2635+
for (std::vector<SrsMediaPayloadType>::iterator it = payloads.begin(); it != payloads.end(); ++it) {
2636+
const SrsMediaPayloadType& payload_type = *it;
2637+
if (srs_sdp_has_h265_profile(payload_type, profile)) {
2638+
return true;
2639+
}
2640+
}
2641+
}
2642+
2643+
return false;
2644+
}
2645+
26012646
srs_error_t SrsRtcConnection::negotiate_publish_capability(SrsRtcUserConfig* ruc, SrsRtcSourceDescription* stream_desc)
26022647
{
26032648
srs_error_t err = srs_success;
@@ -3041,8 +3086,6 @@ srs_error_t SrsRtcConnection::negotiate_play_capability(SrsRtcUserConfig* ruc, s
30413086

30423087
bool nack_enabled = _srs_config->get_rtc_nack_enabled(req->vhost);
30433088
bool twcc_enabled = _srs_config->get_rtc_twcc_enabled(req->vhost);
3044-
// TODO: FIME: Should check packetization-mode=1 also.
3045-
bool has_42e01f = srs_sdp_has_h264_profile(remote_sdp, "42e01f");
30463089

30473090
SrsSharedPtr<SrsRtcSource> source;
30483091
if ((err = _srs_rtc_sources->fetch_or_create(req, source)) != srs_success) {
@@ -3083,56 +3126,87 @@ srs_error_t SrsRtcConnection::negotiate_play_capability(SrsRtcUserConfig* ruc, s
30833126

30843127
remote_payload = payloads.at(0);
30853128
track_descs = source->get_track_desc("audio", "opus");
3086-
} else if (remote_media_desc.is_video() && ruc->codec_ == "av1") {
3087-
std::vector<SrsMediaPayloadType> payloads = remote_media_desc.find_media_with_encoding_name("AV1");
3088-
if (payloads.empty()) {
3089-
// Be compatible with the Chrome M96, still check the AV1X encoding name
3090-
// @see https://bugs.chromium.org/p/webrtc/issues/detail?id=13166
3091-
payloads = remote_media_desc.find_media_with_encoding_name("AV1X");
3092-
}
3093-
if (payloads.empty()) {
3094-
return srs_error_new(ERROR_RTC_SDP_EXCHANGE, "no found valid AV1 payload type");
3129+
} else if (remote_media_desc.is_video()) {
3130+
std::string prefer_codec = ruc->codec_;
3131+
if (prefer_codec.empty()) {
3132+
// Get the source codec if not specified.
3133+
std::vector<SrsRtcTrackDescription*> track_descs = source->get_track_desc("video", "");
3134+
if (!track_descs.empty()) {
3135+
std::string codec_name = track_descs.at(0)->media_->name_;
3136+
std::transform(codec_name.begin(), codec_name.end(), codec_name.begin(), ::tolower);
3137+
if (codec_name == "h265") {
3138+
prefer_codec = "hevc";
3139+
} else {
3140+
prefer_codec = codec_name;
3141+
}
3142+
} else {
3143+
return srs_error_new(ERROR_RTC_SDP_EXCHANGE, "no video track in source");
3144+
}
30953145
}
30963146

3097-
remote_payload = payloads.at(0);
3098-
track_descs = source->get_track_desc("video", "AV1");
3099-
if (track_descs.empty()) {
3100-
// Be compatible with the Chrome M96, still check the AV1X encoding name
3101-
// @see https://bugs.chromium.org/p/webrtc/issues/detail?id=13166
3102-
track_descs = source->get_track_desc("video", "AV1X");
3103-
}
3104-
} else if (remote_media_desc.is_video() && ruc->codec_ == "hevc") {
3105-
std::vector<SrsMediaPayloadType> payloads = remote_media_desc.find_media_with_encoding_name("H265");
3106-
if (payloads.empty()) {
3107-
return srs_error_new(ERROR_RTC_SDP_EXCHANGE, "no valid found h265 payload type");
3108-
}
3147+
if (prefer_codec == "av1") {
3148+
std::vector<SrsMediaPayloadType> payloads = remote_media_desc.find_media_with_encoding_name("AV1");
3149+
if (payloads.empty()) {
3150+
// Be compatible with the Chrome M96, still check the AV1X encoding name
3151+
// @see https://bugs.chromium.org/p/webrtc/issues/detail?id=13166
3152+
payloads = remote_media_desc.find_media_with_encoding_name("AV1X");
3153+
}
3154+
if (payloads.empty()) {
3155+
return srs_error_new(ERROR_RTC_SDP_EXCHANGE, "no found valid AV1 payload type");
3156+
}
31093157

3110-
remote_payload = payloads.at(0);
3158+
remote_payload = payloads.at(0);
3159+
track_descs = source->get_track_desc("video", "AV1");
3160+
if (track_descs.empty()) {
3161+
// Be compatible with the Chrome M96, still check the AV1X encoding name
3162+
// @see https://bugs.chromium.org/p/webrtc/issues/detail?id=13166
3163+
track_descs = source->get_track_desc("video", "AV1X");
3164+
}
3165+
} else if (prefer_codec == "hevc") {
3166+
std::vector<SrsMediaPayloadType> payloads = remote_media_desc.find_media_with_encoding_name("H265");
3167+
if (payloads.empty()) {
3168+
return srs_error_new(ERROR_RTC_SDP_EXCHANGE, "no valid found h265 payload type");
3169+
}
3170+
3171+
// @see https://www.rfc-editor.org/rfc/rfc7798#section-7.2.1
3172+
bool has_main_profile = srs_sdp_has_h265_profile(remote_sdp, "1");
3173+
remote_payload = payloads.at(0);
3174+
3175+
for (int j = 0; j < (int)payloads.size(); j++) {
3176+
const SrsMediaPayloadType& payload = payloads.at(j);
3177+
3178+
// For H.265, we only check if profile-id=1 (Main Profile)
3179+
// Format example: level-id=180;profile-id=1;tier-flag=0;tx-mode=SRST
3180+
if (!has_main_profile || srs_sdp_has_h265_profile(payload, "1")) {
3181+
remote_payload = payload;
3182+
break;
3183+
}
3184+
}
31113185

3112-
// TODO: FIXME: pick up a profile for HEVC.
3113-
// @see https://www.rfc-editor.org/rfc/rfc7798#section-7.2.1
3186+
track_descs = source->get_track_desc("video", "H265");
3187+
} else {
3188+
vector<SrsMediaPayloadType> payloads = remote_media_desc.find_media_with_encoding_name("H264");
3189+
if (payloads.empty()) {
3190+
return srs_error_new(ERROR_RTC_SDP_EXCHANGE, "no valid found h264 payload type");
3191+
}
31143192

3115-
track_descs = source->get_track_desc("video", "H265");
3116-
} else if (remote_media_desc.is_video()) {
3117-
// TODO: check opus format specific param
3118-
vector<SrsMediaPayloadType> payloads = remote_media_desc.find_media_with_encoding_name("H264");
3119-
if (payloads.empty()) {
3120-
return srs_error_new(ERROR_RTC_SDP_EXCHANGE, "no valid found h264 payload type");
3121-
}
3193+
// TODO: FIME: Should check packetization-mode=1 also.
3194+
bool has_42e01f = srs_sdp_has_h264_profile(remote_sdp, "42e01f");
31223195

3123-
remote_payload = payloads.at(0);
3124-
for (int j = 0; j < (int)payloads.size(); j++) {
3125-
const SrsMediaPayloadType& payload = payloads.at(j);
3196+
remote_payload = payloads.at(0);
3197+
for (int j = 0; j < (int)payloads.size(); j++) {
3198+
const SrsMediaPayloadType& payload = payloads.at(j);
31263199

3127-
// If exists 42e01f profile, choose it; otherwise, use the first payload.
3128-
// TODO: FIME: Should check packetization-mode=1 also.
3129-
if (!has_42e01f || srs_sdp_has_h264_profile(payload, "42e01f")) {
3130-
remote_payload = payload;
3131-
break;
3200+
// If exists 42e01f profile, choose it; otherwise, use the first payload.
3201+
// TODO: FIME: Should check packetization-mode=1 also.
3202+
if (!has_42e01f || srs_sdp_has_h264_profile(payload, "42e01f")) {
3203+
remote_payload = payload;
3204+
break;
3205+
}
31323206
}
3133-
}
31343207

3135-
track_descs = source->get_track_desc("video", "H264");
3208+
track_descs = source->get_track_desc("video", "H264");
3209+
}
31363210
}
31373211

31383212
for (int j = 0; j < (int)track_descs.size(); ++j) {
@@ -3238,7 +3312,11 @@ void video_track_generate_play_offer(SrsRtcTrackDescription* track, string mid,
32383312

32393313
SrsVideoPayload* payload = (SrsVideoPayload*)track->media_;
32403314

3241-
local_media_desc.payload_types_.push_back(payload->generate_media_payload_type());
3315+
if (payload->name_ == "H265") {
3316+
local_media_desc.payload_types_.push_back(payload->generate_media_payload_type_h265());
3317+
} else {
3318+
local_media_desc.payload_types_.push_back(payload->generate_media_payload_type());
3319+
}
32423320

32433321
if (track->red_) {
32443322
SrsRedPayload* red_payload = (SrsRedPayload*)track->red_;

trunk/src/app/srs_app_rtc_sdp.cpp

+37-2
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,42 @@ srs_error_t srs_parse_h264_fmtp(const std::string& fmtp, H264SpecificParam& h264
9292
return err;
9393
}
9494

95+
srs_error_t srs_parse_h265_fmtp(const std::string& fmtp, H265SpecificParam& h265_param)
96+
{
97+
srs_error_t err = srs_success;
98+
99+
std::vector<std::string> vec = srs_string_split(fmtp, ";");
100+
for (size_t i = 0; i < vec.size(); ++i) {
101+
std::vector<std::string> kv = srs_string_split(vec[i], "=");
102+
if (kv.size() != 2) continue;
103+
104+
if (kv[0] == "level-id") {
105+
h265_param.level_id = kv[1];
106+
} else if (kv[0] == "profile-id") {
107+
h265_param.profile_id = kv[1];
108+
} else if (kv[0] == "tier-flag") {
109+
h265_param.tier_flag = kv[1];
110+
} else if (kv[0] == "tx-mode") {
111+
h265_param.tx_mode = kv[1];
112+
}
113+
}
114+
115+
if (h265_param.level_id.empty()) {
116+
return srs_error_new(ERROR_RTC_SDP_DECODE, "no h265 param: level-id");
117+
}
118+
if (h265_param.profile_id.empty()) {
119+
return srs_error_new(ERROR_RTC_SDP_DECODE, "no h265 param: profile-id");
120+
}
121+
if (h265_param.tier_flag.empty()) {
122+
return srs_error_new(ERROR_RTC_SDP_DECODE, "no h265 param: tier-flag");
123+
}
124+
if (h265_param.tx_mode.empty()) {
125+
return srs_error_new(ERROR_RTC_SDP_DECODE, "no h265 param: tx-mode");
126+
}
127+
128+
return err;
129+
}
130+
95131
SrsSessionInfo::SrsSessionInfo()
96132
{
97133
}
@@ -1216,5 +1252,4 @@ srs_error_t SrsSdp::update_msid(string id)
12161252
}
12171253

12181254
return err;
1219-
}
1220-
1255+
}

trunk/src/app/srs_app_rtc_sdp.hpp

+9-1
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,16 @@ struct H264SpecificParam
9797
std::string level_asymmerty_allow;
9898
};
9999

100-
extern srs_error_t srs_parse_h264_fmtp(const std::string& fmtp, H264SpecificParam& h264_param);
100+
struct H265SpecificParam
101+
{
102+
std::string level_id;
103+
std::string profile_id;
104+
std::string tier_flag;
105+
std::string tx_mode;
106+
};
101107

108+
extern srs_error_t srs_parse_h264_fmtp(const std::string& fmtp, H264SpecificParam& h264_param);
109+
extern srs_error_t srs_parse_h265_fmtp(const std::string& fmtp, H265SpecificParam& h265_param);
102110
class SrsMediaPayloadType
103111
{
104112
public:

0 commit comments

Comments
 (0)