Add codec name H265 to support H265 in WebRTC

Bug: webrtc:13485
Change-Id: I352b15a65867f0d56fc8e9a9e03081bd3258108e
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/316283
Reviewed-by: Sergey Silkin <ssilkin@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Sergey Silkin <ssilkin@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40773}
diff --git a/BUILD.gn b/BUILD.gn
index 130e1a2..c247afb 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -302,6 +302,10 @@
     defines += [ "RTC_ENABLE_VP9" ]
   }
 
+  if (rtc_use_h265) {
+    defines += [ "RTC_ENABLE_H265" ]
+  }
+
   if (rtc_include_dav1d_in_internal_decoder_factory) {
     defines += [ "RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY" ]
   }
diff --git a/api/video/rtp_video_frame_assembler.cc b/api/video/rtp_video_frame_assembler.cc
index 3d041ca..a19fcdc 100644
--- a/api/video/rtp_video_frame_assembler.cc
+++ b/api/video/rtp_video_frame_assembler.cc
@@ -51,6 +51,10 @@
       return std::make_unique<VideoRtpDepacketizerAv1>();
     case RtpVideoFrameAssembler::kGeneric:
       return std::make_unique<VideoRtpDepacketizerGeneric>();
+    case RtpVideoFrameAssembler::kH265:
+      // TODO(bugs.webrtc.org/13485): Implement VideoRtpDepacketizerH265
+      RTC_DCHECK_NOTREACHED();
+      return nullptr;
   }
   RTC_DCHECK_NOTREACHED();
   return nullptr;
diff --git a/api/video/rtp_video_frame_assembler.h b/api/video/rtp_video_frame_assembler.h
index 83162cb..099c962 100644
--- a/api/video/rtp_video_frame_assembler.h
+++ b/api/video/rtp_video_frame_assembler.h
@@ -52,7 +52,7 @@
   // FrameVector is just a vector-like type of std::unique_ptr<EncodedFrame>.
   // The vector type may change without notice.
   using FrameVector = absl::InlinedVector<AssembledFrame, 3>;
-  enum PayloadFormat { kRaw, kH264, kVp8, kVp9, kAv1, kGeneric };
+  enum PayloadFormat { kRaw, kH264, kVp8, kVp9, kAv1, kGeneric, kH265 };
 
   explicit RtpVideoFrameAssembler(PayloadFormat payload_format);
   RtpVideoFrameAssembler(const RtpVideoFrameAssembler& other) = delete;
diff --git a/api/video/rtp_video_frame_assembler_unittests.cc b/api/video/rtp_video_frame_assembler_unittests.cc
index 82defb8..50d1aaa 100644
--- a/api/video/rtp_video_frame_assembler_unittests.cc
+++ b/api/video/rtp_video_frame_assembler_unittests.cc
@@ -89,6 +89,9 @@
       case PayloadFormat::kAv1: {
         return kVideoCodecAV1;
       }
+      case PayloadFormat::kH265: {
+        return kVideoCodecH265;
+      }
       case PayloadFormat::kGeneric: {
         return kVideoCodecGeneric;
       }
diff --git a/api/video/video_codec_type.h b/api/video/video_codec_type.h
index 74a4bc4..444eb9b 100644
--- a/api/video/video_codec_type.h
+++ b/api/video/video_codec_type.h
@@ -22,6 +22,7 @@
   kVideoCodecAV1,
   kVideoCodecH264,
   kVideoCodecMultiplex,
+  kVideoCodecH265,
 };
 
 }  // namespace webrtc
diff --git a/api/video_codecs/sdp_video_format.cc b/api/video_codecs/sdp_video_format.cc
index cb7e98a..51ae18c 100644
--- a/api/video_codecs/sdp_video_format.cc
+++ b/api/video_codecs/sdp_video_format.cc
@@ -15,6 +15,9 @@
 #include "api/array_view.h"
 #include "api/video_codecs/av1_profile.h"
 #include "api/video_codecs/h264_profile_level_id.h"
+#ifdef RTC_ENABLE_H265
+#include "api/video_codecs/h265_profile_tier_level.h"
+#endif
 #include "api/video_codecs/video_codec.h"
 #include "api/video_codecs/vp9_profile.h"
 #include "rtc_base/checks.h"
@@ -61,6 +64,10 @@
       return VP9IsSameProfile(format1.parameters, format2.parameters);
     case kVideoCodecAV1:
       return AV1IsSameProfile(format1.parameters, format2.parameters);
+#ifdef RTC_ENABLE_H265
+    case kVideoCodecH265:
+      return H265IsSameProfileTierLevel(format1.parameters, format2.parameters);
+#endif
     default:
       return true;
   }
diff --git a/api/video_codecs/test/sdp_video_format_unittest.cc b/api/video_codecs/test/sdp_video_format_unittest.cc
index bb158ae..797a9a2 100644
--- a/api/video_codecs/test/sdp_video_format_unittest.cc
+++ b/api/video_codecs/test/sdp_video_format_unittest.cc
@@ -25,12 +25,18 @@
   EXPECT_TRUE(Sdp("VP8").IsSameCodec(Sdp("vp8")));
   EXPECT_TRUE(Sdp("VP9").IsSameCodec(Sdp("vp9")));
   EXPECT_TRUE(Sdp("AV1").IsSameCodec(Sdp("Av1")));
+#ifdef RTC_ENABLE_H265
+  EXPECT_TRUE(Sdp("H265").IsSameCodec(Sdp("h265")));
+#endif
 }
 
 TEST(SdpVideoFormatTest, DifferentCodecNameNoParameters) {
   EXPECT_FALSE(Sdp("H264").IsSameCodec(Sdp("VP8")));
   EXPECT_FALSE(Sdp("VP8").IsSameCodec(Sdp("VP9")));
   EXPECT_FALSE(Sdp("AV1").IsSameCodec(Sdp("VP8")));
+#ifdef RTC_ENABLE_H265
+  EXPECT_FALSE(Sdp("H265").IsSameCodec(Sdp("VP8")));
+#endif
 }
 
 TEST(SdpVideoFormatTest, SameCodecNameSameParameters) {
@@ -50,6 +56,17 @@
                   .IsSameCodec(Sdp("AV1", Params{{"profile", "0"}})));
   EXPECT_TRUE(Sdp("AV1", Params{{"profile", "2"}})
                   .IsSameCodec(Sdp("AV1", Params{{"profile", "2"}})));
+#ifdef RTC_ENABLE_H265
+  EXPECT_TRUE(Sdp("H265").IsSameCodec(Sdp(
+      "H265",
+      Params{{"profile-id", "1"}, {"tier-flag", "0"}, {"level-id", "93"}})));
+  EXPECT_TRUE(
+      Sdp("H265",
+          Params{{"profile-id", "2"}, {"tier-flag", "0"}, {"level-id", "93"}})
+          .IsSameCodec(Sdp("H265", Params{{"profile-id", "2"},
+                                          {"tier-flag", "0"},
+                                          {"level-id", "93"}})));
+#endif
 }
 
 TEST(SdpVideoFormatTest, SameCodecNameDifferentParameters) {
@@ -69,6 +86,35 @@
                    .IsSameCodec(Sdp("AV1", Params{{"profile", "1"}})));
   EXPECT_FALSE(Sdp("AV1", Params{{"profile", "1"}})
                    .IsSameCodec(Sdp("AV1", Params{{"profile", "2"}})));
+#ifdef RTC_ENABLE_H265
+  EXPECT_FALSE(Sdp("H265").IsSameCodec(Sdp(
+      "H265",
+      Params{{"profile-id", "0"}, {"tier-flag", "0"}, {"level-id", "93"}})));
+  EXPECT_FALSE(Sdp("H265").IsSameCodec(Sdp(
+      "H265",
+      Params{{"profile-id", "1"}, {"tier-flag", "1"}, {"level-id", "93"}})));
+  EXPECT_FALSE(Sdp("H265").IsSameCodec(Sdp(
+      "H265",
+      Params{{"profile-id", "1"}, {"tier-flag", "0"}, {"level-id", "90"}})));
+  EXPECT_FALSE(
+      Sdp("H265",
+          Params{{"profile-id", "2"}, {"tier-flag", "0"}, {"level-id", "93"}})
+          .IsSameCodec(Sdp("H265", Params{{"profile-id", "1"},
+                                          {"tier-flag", "0"},
+                                          {"level-id", "93"}})));
+  EXPECT_FALSE(
+      Sdp("H265",
+          Params{{"profile-id", "1"}, {"tier-flag", "1"}, {"level-id", "120"}})
+          .IsSameCodec(Sdp("H265", Params{{"profile-id", "1"},
+                                          {"tier-flag", "0"},
+                                          {"level-id", "120"}})));
+  EXPECT_FALSE(
+      Sdp("H265",
+          Params{{"profile-id", "1"}, {"tier-flag", "0"}, {"level-id", "93"}})
+          .IsSameCodec(Sdp("H265", Params{{"profile-id", "1"},
+                                          {"tier-flag", "0"},
+                                          {"level-id", "90"}})));
+#endif
 }
 
 TEST(SdpVideoFormatTest, DifferentCodecNameSameParameters) {
@@ -86,6 +132,12 @@
                    .IsSameCodec(Sdp("H264", Params{{"profile", "0"}})));
   EXPECT_FALSE(Sdp("AV1", Params{{"profile", "2"}})
                    .IsSameCodec(Sdp("VP9", Params{{"profile", "2"}})));
+#ifdef RTC_ENABLE_H265
+  EXPECT_FALSE(Sdp("H265", Params{{"profile-id", "0"}})
+                   .IsSameCodec(Sdp("H264", Params{{"profile-id", "0"}})));
+  EXPECT_FALSE(Sdp("H265", Params{{"profile-id", "2"}})
+                   .IsSameCodec(Sdp("VP9", Params{{"profile-id", "2"}})));
+#endif
 }
 
 TEST(SdpVideoFormatTest, H264PacketizationMode) {
diff --git a/api/video_codecs/video_codec.cc b/api/video_codecs/video_codec.cc
index dfd2e21..39a345d 100644
--- a/api/video_codecs/video_codec.cc
+++ b/api/video_codecs/video_codec.cc
@@ -28,6 +28,7 @@
 constexpr char kPayloadNameH264[] = "H264";
 constexpr char kPayloadNameGeneric[] = "Generic";
 constexpr char kPayloadNameMultiplex[] = "Multiplex";
+constexpr char kPayloadNameH265[] = "H265";
 }  // namespace
 
 bool VideoCodecVP8::operator==(const VideoCodecVP8& other) const {
@@ -126,6 +127,8 @@
       return kPayloadNameMultiplex;
     case kVideoCodecGeneric:
       return kPayloadNameGeneric;
+    case kVideoCodecH265:
+      return kPayloadNameH265;
   }
   RTC_CHECK_NOTREACHED();
 }
@@ -142,6 +145,8 @@
     return kVideoCodecH264;
   if (absl::EqualsIgnoreCase(name, kPayloadNameMultiplex))
     return kVideoCodecMultiplex;
+  if (absl::EqualsIgnoreCase(name, kPayloadNameH265))
+    return kVideoCodecH265;
   return kVideoCodecGeneric;
 }
 
diff --git a/api/video_codecs/video_decoder_software_fallback_wrapper.cc b/api/video_codecs/video_decoder_software_fallback_wrapper.cc
index c52ddbe..2af4d39 100644
--- a/api/video_codecs/video_decoder_software_fallback_wrapper.cc
+++ b/api/video_codecs/video_decoder_software_fallback_wrapper.cc
@@ -170,6 +170,10 @@
       RTC_HISTOGRAM_COUNTS_100000(kFallbackHistogramsUmaPrefix + "Multiplex",
                                   hw_decoded_frames_since_last_fallback_);
       break;
+    case kVideoCodecH265:
+      RTC_HISTOGRAM_COUNTS_100000(kFallbackHistogramsUmaPrefix + "H265",
+                                  hw_decoded_frames_since_last_fallback_);
+      break;
   }
 }
 
diff --git a/call/rtp_payload_params.cc b/call/rtp_payload_params.cc
index f4b09ce..4b63ebe 100644
--- a/call/rtp_payload_params.cc
+++ b/call/rtp_payload_params.cc
@@ -100,6 +100,7 @@
     case kVideoCodecGeneric:
       rtp->codec = kVideoCodecGeneric;
       return;
+    // TODO(bugs.webrtc.org/13485): Implement H265 codec specific info
     default:
       return;
   }
@@ -341,6 +342,9 @@
       return;
     case VideoCodecType::kVideoCodecMultiplex:
       return;
+    case VideoCodecType::kVideoCodecH265:
+      // TODO(bugs.webrtc.org/13485): Implement H265 to generic descriptor.
+      return;
   }
   RTC_DCHECK_NOTREACHED() << "Unsupported codec.";
 }
@@ -402,6 +406,7 @@
     }
     case VideoCodecType::kVideoCodecAV1:
     case VideoCodecType::kVideoCodecH264:
+    case VideoCodecType::kVideoCodecH265:
     case VideoCodecType::kVideoCodecMultiplex:
       return absl::nullopt;
   }
diff --git a/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc b/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc
index 5d83c72..2c9e42e 100644
--- a/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc
+++ b/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc
@@ -110,6 +110,8 @@
     case VideoCodecType::kVideoCodecMultiplex:
       // This codec type is afaik not used.
       return rtclog2::FrameDecodedEvents::CODEC_UNKNOWN;
+    case VideoCodecType::kVideoCodecH265:
+      return rtclog2::FrameDecodedEvents::CODEC_H265;
   }
   RTC_DCHECK_NOTREACHED();
   return rtclog2::FrameDecodedEvents::CODEC_UNKNOWN;
diff --git a/logging/rtc_event_log/rtc_event_log2.proto b/logging/rtc_event_log/rtc_event_log2.proto
index 658df6b..a417ded 100644
--- a/logging/rtc_event_log/rtc_event_log2.proto
+++ b/logging/rtc_event_log/rtc_event_log2.proto
@@ -339,6 +339,7 @@
     CODEC_VP9 = 3;
     CODEC_AV1 = 4;
     CODEC_H264 = 5;
+    CODEC_H265 = 6;
   }
 
   // required
diff --git a/logging/rtc_event_log/rtc_event_log_parser.cc b/logging/rtc_event_log/rtc_event_log_parser.cc
index 0ea9643..37bb70a 100644
--- a/logging/rtc_event_log/rtc_event_log_parser.cc
+++ b/logging/rtc_event_log/rtc_event_log_parser.cc
@@ -261,6 +261,8 @@
       return VideoCodecType::kVideoCodecAV1;
     case rtclog2::FrameDecodedEvents::CODEC_H264:
       return VideoCodecType::kVideoCodecH264;
+    case rtclog2::FrameDecodedEvents::CODEC_H265:
+      return VideoCodecType::kVideoCodecH265;
     case rtclog2::FrameDecodedEvents::CODEC_UNKNOWN:
       RTC_LOG(LS_ERROR) << "Unknown codec type. Assuming "
                            "VideoCodecType::kVideoCodecMultiplex";
diff --git a/logging/rtc_event_log/rtc_event_log_unittest_helper.cc b/logging/rtc_event_log/rtc_event_log_unittest_helper.cc
index b378e8f..aece4b5 100644
--- a/logging/rtc_event_log/rtc_event_log_unittest_helper.cc
+++ b/logging/rtc_event_log/rtc_event_log_unittest_helper.cc
@@ -169,11 +169,11 @@
   constexpr int kMaxHeight = 8640;
   constexpr int kMinWidth = 16;
   constexpr int kMinHeight = 16;
-  constexpr int kNumCodecTypes = 5;
+  constexpr int kNumCodecTypes = 6;
 
   constexpr VideoCodecType kCodecList[kNumCodecTypes] = {
-      kVideoCodecGeneric, kVideoCodecVP8, kVideoCodecVP9, kVideoCodecAV1,
-      kVideoCodecH264};
+      kVideoCodecGeneric, kVideoCodecVP8,  kVideoCodecVP9,
+      kVideoCodecAV1,     kVideoCodecH264, kVideoCodecH265};
   const int64_t render_time_ms =
       rtc::TimeMillis() + prng_.Rand(kMinRenderDelayMs, kMaxRenderDelayMs);
   const int width = prng_.Rand(kMinWidth, kMaxWidth);
diff --git a/modules/rtp_rtcp/source/create_video_rtp_depacketizer.cc b/modules/rtp_rtcp/source/create_video_rtp_depacketizer.cc
index f1e4edd..95db212 100644
--- a/modules/rtp_rtcp/source/create_video_rtp_depacketizer.cc
+++ b/modules/rtp_rtcp/source/create_video_rtp_depacketizer.cc
@@ -33,6 +33,9 @@
       return std::make_unique<VideoRtpDepacketizerVp9>();
     case kVideoCodecAV1:
       return std::make_unique<VideoRtpDepacketizerAv1>();
+    case kVideoCodecH265:
+      // TODO(bugs.webrtc.org/13485): Implement VideoRtpDepacketizerH265.
+      return nullptr;
     case kVideoCodecGeneric:
     case kVideoCodecMultiplex:
       return std::make_unique<VideoRtpDepacketizerGeneric>();
diff --git a/modules/rtp_rtcp/source/rtp_format.cc b/modules/rtp_rtcp/source/rtp_format.cc
index 7550b70..2c11a29 100644
--- a/modules/rtp_rtcp/source/rtp_format.cc
+++ b/modules/rtp_rtcp/source/rtp_format.cc
@@ -57,6 +57,7 @@
       return std::make_unique<RtpPacketizerAv1>(
           payload, limits, rtp_video_header.frame_type,
           rtp_video_header.is_last_frame_in_picture);
+    // TODO(bugs.webrtc.org/13485): Implement RtpPacketizerH265.
     default: {
       return std::make_unique<RtpPacketizerGeneric>(payload, limits,
                                                     rtp_video_header);
diff --git a/modules/rtp_rtcp/source/rtp_sender_video.cc b/modules/rtp_rtcp/source/rtp_sender_video.cc
index b846f7f..4d819a8 100644
--- a/modules/rtp_rtcp/source/rtp_sender_video.cc
+++ b/modules/rtp_rtcp/source/rtp_sender_video.cc
@@ -92,6 +92,10 @@
       // TODO(kron): Implement logic for H264 once WebRTC supports temporal
       // layers for H264.
       break;
+    case kVideoCodecH265:
+      // TODO(bugs.webrtc.org/13485): Implement logic for H265 once WebRTC
+      // supports temporal layers for H265.
+      break;
     default:
       break;
   }
diff --git a/modules/rtp_rtcp/source/rtp_video_header.cc b/modules/rtp_rtcp/source/rtp_video_header.cc
index b07a7be..c4ab609 100644
--- a/modules/rtp_rtcp/source/rtp_video_header.cc
+++ b/modules/rtp_rtcp/source/rtp_video_header.cc
@@ -59,6 +59,9 @@
       metadata.SetRTPVideoHeaderCodecSpecifics(
           absl::get<RTPVideoHeaderH264>(video_type_header));
       break;
+    case VideoCodecType::kVideoCodecH265:
+      // TODO(bugs.webrtc.org/13485)
+      break;
     default:
       // Codec-specifics are not supported for this codec.
       break;
diff --git a/modules/video_coding/codecs/multiplex/multiplex_encoder_adapter.cc b/modules/video_coding/codecs/multiplex/multiplex_encoder_adapter.cc
index 80744e2..80d01dc 100644
--- a/modules/video_coding/codecs/multiplex/multiplex_encoder_adapter.cc
+++ b/modules/video_coding/codecs/multiplex/multiplex_encoder_adapter.cc
@@ -93,6 +93,9 @@
       key_frame_interval_ = video_codec.H264()->keyFrameInterval;
       video_codec.H264()->keyFrameInterval = 0;
       break;
+    case kVideoCodecH265:
+      // TODO(bugs.webrtc.org/13485)
+      break;
     default:
       break;
   }
diff --git a/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc b/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc
index 7543372..eb264e5 100644
--- a/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc
+++ b/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc
@@ -137,6 +137,9 @@
       ss << "\nnum_temporal_layers: "
          << static_cast<int>(codec.H264().numberOfTemporalLayers);
       break;
+    case kVideoCodecH265:
+      // TODO(bugs.webrtc.org/13485)
+      break;
     default:
       break;
   }
@@ -246,6 +249,9 @@
       codec_settings.H264()->numberOfTemporalLayers =
           static_cast<uint8_t>(num_temporal_layers);
       break;
+    case kVideoCodecH265:
+      // TODO(bugs.webrtc.org/13485)
+      break;
     default:
       break;
   }
diff --git a/modules/video_coding/encoded_frame.cc b/modules/video_coding/encoded_frame.cc
index 637a20c..565a127 100644
--- a/modules/video_coding/encoded_frame.cc
+++ b/modules/video_coding/encoded_frame.cc
@@ -140,6 +140,10 @@
         _codecSpecificInfo.codecType = kVideoCodecAV1;
         break;
       }
+      case kVideoCodecH265: {
+        _codecSpecificInfo.codecType = kVideoCodecH265;
+        break;
+      }
       default: {
         _codecSpecificInfo.codecType = kVideoCodecGeneric;
         break;
diff --git a/modules/video_coding/utility/ivf_file_reader.cc b/modules/video_coding/utility/ivf_file_reader.cc
index 13092b5..9fc2332 100644
--- a/modules/video_coding/utility/ivf_file_reader.cc
+++ b/modules/video_coding/utility/ivf_file_reader.cc
@@ -29,6 +29,7 @@
 constexpr uint8_t kVp9Header[kCodecTypeBytesCount] = {'V', 'P', '9', '0'};
 constexpr uint8_t kAv1Header[kCodecTypeBytesCount] = {'A', 'V', '0', '1'};
 constexpr uint8_t kH264Header[kCodecTypeBytesCount] = {'H', '2', '6', '4'};
+constexpr uint8_t kH265Header[kCodecTypeBytesCount] = {'H', '2', '6', '5'};
 
 // RTP standard required 90kHz clock rate.
 constexpr int32_t kRtpClockRateHz = 90000;
@@ -192,6 +193,9 @@
   if (memcmp(&buffer[start_pos], kH264Header, kCodecTypeBytesCount) == 0) {
     return VideoCodecType::kVideoCodecH264;
   }
+  if (memcmp(&buffer[start_pos], kH265Header, kCodecTypeBytesCount) == 0) {
+    return VideoCodecType::kVideoCodecH265;
+  }
   has_error_ = true;
   RTC_LOG(LS_ERROR) << "Unknown codec type: "
                     << std::string(
diff --git a/modules/video_coding/utility/ivf_file_writer.cc b/modules/video_coding/utility/ivf_file_writer.cc
index 0102598..cc5aed3 100644
--- a/modules/video_coding/utility/ivf_file_writer.cc
+++ b/modules/video_coding/utility/ivf_file_writer.cc
@@ -92,6 +92,12 @@
       ivf_header[10] = '6';
       ivf_header[11] = '4';
       break;
+    case kVideoCodecH265:
+      ivf_header[8] = 'H';
+      ivf_header[9] = '2';
+      ivf_header[10] = '6';
+      ivf_header[11] = '5';
+      break;
     default:
       // For unknown codec type use **** code. You can specify actual payload
       // format when playing the video with ffplay: ffplay -f H263 file.ivf
diff --git a/modules/video_coding/utility/qp_parser.cc b/modules/video_coding/utility/qp_parser.cc
index 18f2254..3b9aaa3 100644
--- a/modules/video_coding/utility/qp_parser.cc
+++ b/modules/video_coding/utility/qp_parser.cc
@@ -36,6 +36,8 @@
     }
   } else if (codec_type == kVideoCodecH264) {
     return h264_parsers_[spatial_idx].Parse(frame_data, frame_size);
+  } else if (codec_type == kVideoCodecH265) {
+    // TODO(bugs.webrtc.org/13485)
   }
 
   return absl::nullopt;
diff --git a/modules/video_coding/utility/simulcast_utility.cc b/modules/video_coding/utility/simulcast_utility.cc
index 95e9488..824f4b0 100644
--- a/modules/video_coding/utility/simulcast_utility.cc
+++ b/modules/video_coding/utility/simulcast_utility.cc
@@ -94,6 +94,9 @@
       case kVideoCodecH264:
         num_temporal_layers = codec.H264().numberOfTemporalLayers;
         break;
+      case kVideoCodecH265:
+        // TODO(bugs.webrtc.org/13485)
+        break;
       default:
         break;
     }
diff --git a/modules/video_coding/video_codec_initializer.cc b/modules/video_coding/video_codec_initializer.cc
index 43fab8c..79421ff 100644
--- a/modules/video_coding/video_codec_initializer.cc
+++ b/modules/video_coding/video_codec_initializer.cc
@@ -344,6 +344,9 @@
                     kMaxTemporalStreams);
       break;
     }
+    case kVideoCodecH265:
+      // TODO(bugs.webrtc.org/13485)
+      break;
     default:
       // TODO(pbos): Support encoder_settings codec-agnostically.
       RTC_DCHECK(!config.encoder_specific_settings)
diff --git a/rtc_base/experiments/balanced_degradation_settings.cc b/rtc_base/experiments/balanced_degradation_settings.cc
index 1652e31..1a269b4 100644
--- a/rtc_base/experiments/balanced_degradation_settings.cc
+++ b/rtc_base/experiments/balanced_degradation_settings.cc
@@ -159,6 +159,8 @@
       low = config.vp9.GetQpLow();
       high = config.vp9.GetQpHigh();
       break;
+    case kVideoCodecH265:
+    //  TODO(bugs.webrtc.org/13485): Use H264 QP thresholds for now.
     case kVideoCodecH264:
       low = config.h264.GetQpLow();
       high = config.h264.GetQpHigh();
@@ -194,6 +196,8 @@
     case kVideoCodecVP8:
       fps = config->vp8.GetFps();
       break;
+    case kVideoCodecH265:
+    //  TODO(bugs.webrtc.org/13485): Use VP9 bitrate limits for now.
     case kVideoCodecVP9:
       fps = config->vp9.GetFps();
       break;
@@ -226,6 +230,8 @@
     case kVideoCodecVP8:
       kbps = config->vp8.GetKbps();
       break;
+    case kVideoCodecH265:
+    //  TODO(bugs.webrtc.org/13485): Use VP9 bitrate limits for now.
     case kVideoCodecVP9:
       kbps = config->vp9.GetKbps();
       break;
@@ -259,6 +265,8 @@
     case kVideoCodecVP8:
       kbps_res = config->vp8.GetKbpsRes();
       break;
+    case kVideoCodecH265:
+    //  TODO(bugs.webrtc.org/13485): Use VP9 bitrate limits for now.
     case kVideoCodecVP9:
       kbps_res = config->vp9.GetKbpsRes();
       break;
diff --git a/rtc_base/experiments/min_video_bitrate_experiment.cc b/rtc_base/experiments/min_video_bitrate_experiment.cc
index f37c4e9..f9e7613 100644
--- a/rtc_base/experiments/min_video_bitrate_experiment.cc
+++ b/rtc_base/experiments/min_video_bitrate_experiment.cc
@@ -94,6 +94,8 @@
     switch (type) {
       case kVideoCodecVP8:
         return min_bitrate_vp8.GetOptional();
+      case kVideoCodecH265:
+      //  TODO(bugs.webrtc.org/13485): Use VP9 bitrate limits for now.
       case kVideoCodecVP9:
         return min_bitrate_vp9.GetOptional();
       case kVideoCodecAV1:
diff --git a/rtc_base/experiments/quality_scaling_experiment.cc b/rtc_base/experiments/quality_scaling_experiment.cc
index 7d5722b..0c4ec22 100644
--- a/rtc_base/experiments/quality_scaling_experiment.cc
+++ b/rtc_base/experiments/quality_scaling_experiment.cc
@@ -81,6 +81,8 @@
       return GetThresholds(settings->vp8_low, settings->vp8_high, kMaxVp8Qp);
     case kVideoCodecVP9:
       return GetThresholds(settings->vp9_low, settings->vp9_high, kMaxVp9Qp);
+    case kVideoCodecH265:
+    //  TODO(bugs.webrtc.org/13485): Use H264 QP thresholds for now.
     case kVideoCodecH264:
       return GetThresholds(settings->h264_low, settings->h264_high, kMaxH264Qp);
     case kVideoCodecGeneric:
diff --git a/rtc_tools/rtc_event_log_to_text/converter.cc b/rtc_tools/rtc_event_log_to_text/converter.cc
index f171260..90d568f 100644
--- a/rtc_tools/rtc_event_log_to_text/converter.cc
+++ b/rtc_tools/rtc_event_log_to_text/converter.cc
@@ -430,7 +430,8 @@
         {VideoCodecType::kVideoCodecVP9, "VP9"},
         {VideoCodecType::kVideoCodecAV1, "AV1"},
         {VideoCodecType::kVideoCodecH264, "H264"},
-        {VideoCodecType::kVideoCodecMultiplex, "MULTIPLEX"}};
+        {VideoCodecType::kVideoCodecMultiplex, "MULTIPLEX"},
+        {VideoCodecType::kVideoCodecH265, "H265"}};
 
     fprintf(output,
             "FRAME_DECODED %" PRId64 " render_time=%" PRId64
diff --git a/rtc_tools/video_encoder/video_encoder.cc b/rtc_tools/video_encoder/video_encoder.cc
index a2eeef8..74f59c4 100644
--- a/rtc_tools/video_encoder/video_encoder.cc
+++ b/rtc_tools/video_encoder/video_encoder.cc
@@ -295,7 +295,9 @@
           RTC_LOG(LS_WARNING) << "Failed to configure svc bitrates for av1.";
         }
         break;
-
+      case kVideoCodecH265:
+        // TODO(bugs.webrtc.org/13485)
+        break;
       default:
         RTC_CHECK_NOTREACHED();
         break;
diff --git a/rtc_tools/video_replay.cc b/rtc_tools/video_replay.cc
index 242ce1b..c8bfec2 100644
--- a/rtc_tools/video_replay.cc
+++ b/rtc_tools/video_replay.cc
@@ -267,6 +267,8 @@
       video_codec_type_ = VideoCodecType::kVideoCodecH264;
     } else if (codec == "AV1") {
       video_codec_type_ = VideoCodecType::kVideoCodecAV1;
+    } else if (codec == "H265") {
+      video_codec_type_ = VideoCodecType::kVideoCodecH265;
     } else {
       RTC_LOG(LS_ERROR) << "Unsupported video codec " << codec;
       RTC_DCHECK_NOTREACHED();
diff --git a/sdk/android/src/jni/video_decoder_wrapper.cc b/sdk/android/src/jni/video_decoder_wrapper.cc
index 22bfe77..8c231c0 100644
--- a/sdk/android/src/jni/video_decoder_wrapper.cc
+++ b/sdk/android/src/jni/video_decoder_wrapper.cc
@@ -255,6 +255,13 @@
       qp = h264_bitstream_parser_.GetLastSliceQp();
       break;
     }
+#ifdef RTC_ENABLE_H265
+    case kVideoCodecH265:
+      h265_bitstream_parser_.ParseBitstream(buffer);
+      qp = h265_bitstream_parser_.GetLastSliceQp().value_or(-1);
+      success = (qp >= 0);
+      break;
+#endif
     default:
       break;  // Default is to not provide QP.
   }
diff --git a/sdk/android/src/jni/video_decoder_wrapper.h b/sdk/android/src/jni/video_decoder_wrapper.h
index 04b083c..53246f3 100644
--- a/sdk/android/src/jni/video_decoder_wrapper.h
+++ b/sdk/android/src/jni/video_decoder_wrapper.h
@@ -19,6 +19,9 @@
 #include "api/sequence_checker.h"
 #include "api/video_codecs/video_decoder.h"
 #include "common_video/h264/h264_bitstream_parser.h"
+#ifdef RTC_ENABLE_H265
+#include "common_video/h265/h265_bitstream_parser.h"
+#endif
 #include "rtc_base/race_checker.h"
 #include "rtc_base/synchronization/mutex.h"
 #include "sdk/android/src/jni/jni_helpers.h"
@@ -96,6 +99,10 @@
   bool initialized_ RTC_GUARDED_BY(decoder_thread_checker_);
   H264BitstreamParser h264_bitstream_parser_
       RTC_GUARDED_BY(decoder_thread_checker_);
+#ifdef RTC_ENABLE_H265
+  H265BitstreamParser h265_bitstream_parser_
+      RTC_GUARDED_BY(decoder_thread_checker_);
+#endif
 
   DecodedImageCallback* callback_ RTC_GUARDED_BY(callback_race_checker_);
 
diff --git a/sdk/android/src/jni/video_encoder_wrapper.cc b/sdk/android/src/jni/video_encoder_wrapper.cc
index 3912ede..6cd8acb 100644
--- a/sdk/android/src/jni/video_encoder_wrapper.cc
+++ b/sdk/android/src/jni/video_encoder_wrapper.cc
@@ -227,6 +227,8 @@
       return VideoEncoder::ScalingSettings(kLowVp9QpThreshold,
                                            kHighVp9QpThreshold);
     }
+    case kVideoCodecH265:
+    // TODO(bugs.webrtc.org/13485): Use H264 QP thresholds for now.
     case kVideoCodecH264: {
       // Same as in h264_encoder_impl.cc.
       static const int kLowH264QpThreshold = 24;
@@ -355,6 +357,13 @@
       qp = h264_bitstream_parser_.GetLastSliceQp().value_or(-1);
       success = (qp >= 0);
       break;
+#ifdef RTC_ENABLE_H265
+    case kVideoCodecH265:
+      h265_bitstream_parser_.ParseBitstream(buffer);
+      qp = h265_bitstream_parser_.GetLastSliceQp().value_or(-1);
+      success = (qp >= 0);
+      break;
+#endif
     default:  // Default is to not provide QP.
       success = false;
       break;
diff --git a/sdk/android/src/jni/video_encoder_wrapper.h b/sdk/android/src/jni/video_encoder_wrapper.h
index d3eb220..04d70f3 100644
--- a/sdk/android/src/jni/video_encoder_wrapper.h
+++ b/sdk/android/src/jni/video_encoder_wrapper.h
@@ -21,6 +21,9 @@
 #include "absl/types/optional.h"
 #include "api/video_codecs/video_encoder.h"
 #include "common_video/h264/h264_bitstream_parser.h"
+#ifdef RTC_ENABLE_H265
+#include "common_video/h265/h265_bitstream_parser.h"
+#endif
 #include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
 #include "modules/video_coding/svc/scalable_video_controller_no_layering.h"
 #include "rtc_base/synchronization/mutex.h"
@@ -103,6 +106,9 @@
   VideoCodec codec_settings_;
   EncoderInfo encoder_info_;
   H264BitstreamParser h264_bitstream_parser_;
+#ifdef RTC_ENABLE_H265
+  H265BitstreamParser h265_bitstream_parser_;
+#endif
 
   // Fills frame dependencies in codec-agnostic format.
   ScalableVideoControllerNoLayering svc_controller_;
diff --git a/test/fuzzers/rtp_frame_reference_finder_fuzzer.cc b/test/fuzzers/rtp_frame_reference_finder_fuzzer.cc
index b1cabc3..ea66c4a 100644
--- a/test/fuzzers/rtp_frame_reference_finder_fuzzer.cc
+++ b/test/fuzzers/rtp_frame_reference_finder_fuzzer.cc
@@ -120,6 +120,9 @@
         reader.CopyTo(
             &video_header.video_type_header.emplace<RTPVideoHeaderH264>());
         break;
+      case kVideoCodecH265:
+        // TODO(bugs.webrtc.org/13485)
+        break;
       default:
         break;
     }
diff --git a/test/scenario/video_stream.cc b/test/scenario/video_stream.cc
index e082aa3..d376a8f 100644
--- a/test/scenario/video_stream.cc
+++ b/test/scenario/video_stream.cc
@@ -51,6 +51,8 @@
       return VideoTestConstants::kPayloadTypeVP9;
     case VideoCodecType::kVideoCodecH264:
       return VideoTestConstants::kPayloadTypeH264;
+    case VideoCodecType::kVideoCodecH265:
+      return VideoTestConstants::kPayloadTypeH265;
     default:
       RTC_DCHECK_NOTREACHED();
   }
@@ -66,6 +68,8 @@
       return cricket::kVp9CodecName;
     case VideoCodecType::kVideoCodecH264:
       return cricket::kH264CodecName;
+    case VideoCodecType::kVideoCodecH265:
+      return cricket::kH265CodecName;
     default:
       RTC_DCHECK_NOTREACHED();
   }
@@ -203,6 +207,7 @@
       return CreateVp9SpecificSettings(config);
     case Codec::kVideoCodecGeneric:
     case Codec::kVideoCodecAV1:
+    case Codec::kVideoCodecH265:
       return nullptr;
     case Codec::kVideoCodecMultiplex:
       RTC_DCHECK_NOTREACHED();
diff --git a/test/testsupport/ivf_video_frame_generator.cc b/test/testsupport/ivf_video_frame_generator.cc
index ec3c948..0dec113 100644
--- a/test/testsupport/ivf_video_frame_generator.cc
+++ b/test/testsupport/ivf_video_frame_generator.cc
@@ -148,6 +148,9 @@
   if (codec_type == VideoCodecType::kVideoCodecAV1) {
     return CreateDav1dDecoder();
   }
+  if (codec_type == VideoCodecType::kVideoCodecH265) {
+    // TODO(bugs.webrtc.org/13485): implement H265 decoder
+  }
   return nullptr;
 }
 
diff --git a/test/video_test_constants.h b/test/video_test_constants.h
index 732d4f0..b908398 100644
--- a/test/video_test_constants.h
+++ b/test/video_test_constants.h
@@ -31,6 +31,7 @@
     kRtxRedPayloadType = 99,
     kVideoSendPayloadType = 100,
     kAudioSendPayloadType = 103,
+    kPayloadTypeH265 = 117,
     kRedPayloadType = 118,
     kUlpfecPayloadType = 119,
     kFlexfecPayloadType = 120,
diff --git a/video/encoder_overshoot_detector.cc b/video/encoder_overshoot_detector.cc
index 2c4efdb..d5c1f91 100644
--- a/video/encoder_overshoot_detector.cc
+++ b/video/encoder_overshoot_detector.cc
@@ -266,6 +266,12 @@
       RTC_HISTOGRAMS_COUNTS_10000(index, overshoot_histogram_prefix + "H264",
                                   average_overshoot_percent);
       break;
+    case VideoCodecType::kVideoCodecH265:
+      RTC_HISTOGRAMS_COUNTS_10000(index, rmse_histogram_prefix + "H265",
+                                  bitrate_rmse);
+      RTC_HISTOGRAMS_COUNTS_10000(index, overshoot_histogram_prefix + "H265",
+                                  average_overshoot_percent);
+      break;
     case VideoCodecType::kVideoCodecGeneric:
     case VideoCodecType::kVideoCodecMultiplex:
       break;
diff --git a/video/encoder_overshoot_detector_unittest.cc b/video/encoder_overshoot_detector_unittest.cc
index bdc2676..2178957 100644
--- a/video/encoder_overshoot_detector_unittest.cc
+++ b/video/encoder_overshoot_detector_unittest.cc
@@ -35,6 +35,8 @@
       return "Av1";
     case kVideoCodecH264:
       return "H264";
+    case kVideoCodecH265:
+      return "H265";
     case kVideoCodecGeneric:
       return "Generic";
     case kVideoCodecMultiplex:
@@ -275,6 +277,8 @@
                           {VideoCodecType::kVideoCodecAV1, false},
                           {VideoCodecType::kVideoCodecAV1, true},
                           {VideoCodecType::kVideoCodecH264, false},
-                          {VideoCodecType::kVideoCodecH264, true}}));
+                          {VideoCodecType::kVideoCodecH264, true},
+                          {VideoCodecType::kVideoCodecH265, false},
+                          {VideoCodecType::kVideoCodecH265, true}}));
 
 }  // namespace webrtc
diff --git a/video/send_statistics_proxy.cc b/video/send_statistics_proxy.cc
index 9a5f69d..9504bda 100644
--- a/video/send_statistics_proxy.cc
+++ b/video/send_statistics_proxy.cc
@@ -47,6 +47,7 @@
   kVideoVp9 = 2,
   kVideoH264 = 3,
   kVideoAv1 = 4,
+  kVideoH265 = 5,
   kVideoMax = 64,
 };
 
@@ -76,6 +77,8 @@
       return kVideoH264;
     case kVideoCodecAV1:
       return kVideoAv1;
+    case kVideoCodecH265:
+      return kVideoH265;
     default:
       return kVideoUnknown;
   }
diff --git a/video/video_stream_encoder.cc b/video/video_stream_encoder.cc
index c367510..5eeb740 100644
--- a/video/video_stream_encoder.cc
+++ b/video/video_stream_encoder.cc
@@ -135,7 +135,9 @@
         return true;
       }
       break;
-
+    case kVideoCodecH265:
+      // TODO(bugs.webrtc.org/13485): Implement new send codec H265
+      [[fallthrough]];
     default:
       break;
   }
@@ -1351,6 +1353,7 @@
     // TODO(sprang): Add a better way to disable frame dropping.
     num_layers = codec.simulcastStream[0].numberOfTemporalLayers;
   } else {
+    // TODO(bugs.webrtc.org/13485): Implement H265 temporal layer
     num_layers = 1;
   }
 
diff --git a/video/video_stream_encoder_unittest.cc b/video/video_stream_encoder_unittest.cc
index 44fc53f..53b4a0f 100644
--- a/video/video_stream_encoder_unittest.cc
+++ b/video/video_stream_encoder_unittest.cc
@@ -8822,6 +8822,9 @@
             mock_encoder_factory_for_multiplex_.get(), SdpVideoFormat("VP8"),
             false);
         break;
+      case kVideoCodecH265:
+        // TODO(bugs.webrtc.org/13485): Use a fake encoder
+        break;
       default:
         RTC_DCHECK_NOTREACHED();
     }