@@ -2598,6 +2598,51 @@ bool srs_sdp_has_h264_profile(const SrsSdp& sdp, const string& profile)
2598
2598
return false ;
2599
2599
}
2600
2600
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
+
2601
2646
srs_error_t SrsRtcConnection::negotiate_publish_capability (SrsRtcUserConfig* ruc, SrsRtcSourceDescription* stream_desc)
2602
2647
{
2603
2648
srs_error_t err = srs_success;
@@ -3041,8 +3086,6 @@ srs_error_t SrsRtcConnection::negotiate_play_capability(SrsRtcUserConfig* ruc, s
3041
3086
3042
3087
bool nack_enabled = _srs_config->get_rtc_nack_enabled (req->vhost );
3043
3088
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" );
3046
3089
3047
3090
SrsSharedPtr<SrsRtcSource> source;
3048
3091
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
3083
3126
3084
3127
remote_payload = payloads.at (0 );
3085
3128
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
+ }
3095
3145
}
3096
3146
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
+ }
3109
3157
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
+ }
3111
3185
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
+ }
3114
3192
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" );
3122
3195
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);
3126
3199
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
+ }
3132
3206
}
3133
- }
3134
3207
3135
- track_descs = source->get_track_desc (" video" , " H264" );
3208
+ track_descs = source->get_track_desc (" video" , " H264" );
3209
+ }
3136
3210
}
3137
3211
3138
3212
for (int j = 0 ; j < (int )track_descs.size (); ++j) {
@@ -3238,7 +3312,11 @@ void video_track_generate_play_offer(SrsRtcTrackDescription* track, string mid,
3238
3312
3239
3313
SrsVideoPayload* payload = (SrsVideoPayload*)track->media_ ;
3240
3314
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
+ }
3242
3320
3243
3321
if (track->red_ ) {
3244
3322
SrsRedPayload* red_payload = (SrsRedPayload*)track->red_ ;
0 commit comments