diff --git a/BUILD.gn b/BUILD.gn index 130e1a2891..c247afb4d0 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -302,6 +302,10 @@ config("common_config") { 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 3d041ca218..a19fcdcb97 100644 --- a/api/video/rtp_video_frame_assembler.cc +++ b/api/video/rtp_video_frame_assembler.cc @@ -51,6 +51,10 @@ std::unique_ptr CreateDepacketizer( return std::make_unique(); case RtpVideoFrameAssembler::kGeneric: return std::make_unique(); + 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 83162cb818..099c962f23 100644 --- a/api/video/rtp_video_frame_assembler.h +++ b/api/video/rtp_video_frame_assembler.h @@ -52,7 +52,7 @@ class RtpVideoFrameAssembler { // FrameVector is just a vector-like type of std::unique_ptr. // The vector type may change without notice. using FrameVector = absl::InlinedVector; - 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 82defb8399..50d1aaae12 100644 --- a/api/video/rtp_video_frame_assembler_unittests.cc +++ b/api/video/rtp_video_frame_assembler_unittests.cc @@ -89,6 +89,9 @@ class PacketBuilder { 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 74a4bc4258..444eb9bcd0 100644 --- a/api/video/video_codec_type.h +++ b/api/video/video_codec_type.h @@ -22,6 +22,7 @@ enum VideoCodecType { 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 cb7e98a682..51ae18cd78 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 @@ bool IsSameCodecSpecific(const SdpVideoFormat& format1, 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 bb158aeb95..797a9a2e72 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 @@ TEST(SdpVideoFormatTest, SameCodecNameNoParameters) { 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 @@ TEST(SdpVideoFormatTest, SameCodecNameSameParameters) { .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 @@ TEST(SdpVideoFormatTest, SameCodecNameDifferentParameters) { .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 @@ TEST(SdpVideoFormatTest, DifferentCodecNameSameParameters) { .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 dfd2e216ab..39a345d699 100644 --- a/api/video_codecs/video_codec.cc +++ b/api/video_codecs/video_codec.cc @@ -28,6 +28,7 @@ constexpr char kPayloadNameAv1x[] = "AV1X"; 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 @@ const char* CodecTypeToPayloadString(VideoCodecType type) { return kPayloadNameMultiplex; case kVideoCodecGeneric: return kPayloadNameGeneric; + case kVideoCodecH265: + return kPayloadNameH265; } RTC_CHECK_NOTREACHED(); } @@ -142,6 +145,8 @@ VideoCodecType PayloadStringToCodecType(const std::string& name) { 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 c52ddbe511..2af4d39b3a 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 @@ void VideoDecoderSoftwareFallbackWrapper::UpdateFallbackDecoderHistograms() { 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 f4b09ce913..4b63ebefb3 100644 --- a/call/rtp_payload_params.cc +++ b/call/rtp_payload_params.cc @@ -100,6 +100,7 @@ void PopulateRtpWithCodecSpecifics(const CodecSpecificInfo& info, case kVideoCodecGeneric: rtp->codec = kVideoCodecGeneric; return; + // TODO(bugs.webrtc.org/13485): Implement H265 codec specific info default: return; } @@ -341,6 +342,9 @@ void RtpPayloadParams::SetGeneric(const CodecSpecificInfo* codec_specific_info, 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 @@ absl::optional RtpPayloadParams::GenericStructure( } 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 5d83c72a0b..2c9e42e064 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 @@ rtclog2::FrameDecodedEvents::Codec ConvertToProtoFormat(VideoCodecType codec) { 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 658df6b6ff..a417ded706 100644 --- a/logging/rtc_event_log/rtc_event_log2.proto +++ b/logging/rtc_event_log/rtc_event_log2.proto @@ -339,6 +339,7 @@ message FrameDecodedEvents { 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 0ea96431a7..37bb70a69b 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 @@ VideoCodecType GetRuntimeCodecType(rtclog2::FrameDecodedEvents::Codec codec) { 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 b378e8ff48..aece4b5753 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 @@ std::unique_ptr EventGenerator::NewFrameDecodedEvent( 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 f1e4eddb4b..95db212bef 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 @@ std::unique_ptr CreateVideoRtpDepacketizer( return std::make_unique(); case kVideoCodecAV1: return std::make_unique(); + case kVideoCodecH265: + // TODO(bugs.webrtc.org/13485): Implement VideoRtpDepacketizerH265. + return nullptr; case kVideoCodecGeneric: case kVideoCodecMultiplex: return std::make_unique(); diff --git a/modules/rtp_rtcp/source/rtp_format.cc b/modules/rtp_rtcp/source/rtp_format.cc index 7550b70f69..2c11a29bfa 100644 --- a/modules/rtp_rtcp/source/rtp_format.cc +++ b/modules/rtp_rtcp/source/rtp_format.cc @@ -57,6 +57,7 @@ std::unique_ptr RtpPacketizer::Create( return std::make_unique( 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(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 b846f7f7ea..4d819a80a9 100644 --- a/modules/rtp_rtcp/source/rtp_sender_video.cc +++ b/modules/rtp_rtcp/source/rtp_sender_video.cc @@ -92,6 +92,10 @@ bool IsBaseLayer(const RTPVideoHeader& video_header) { // 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 b07a7beec4..c4ab6097be 100644 --- a/modules/rtp_rtcp/source/rtp_video_header.cc +++ b/modules/rtp_rtcp/source/rtp_video_header.cc @@ -59,6 +59,9 @@ VideoFrameMetadata RTPVideoHeader::GetAsMetadata() const { metadata.SetRTPVideoHeaderCodecSpecifics( absl::get(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 80744e2d8c..80d01dc49b 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 @@ int MultiplexEncoderAdapter::InitEncode( 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 7543372e21..eb264e5285 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 @@ std::string CodecSpecificToString(const VideoCodec& codec) { ss << "\nnum_temporal_layers: " << static_cast(codec.H264().numberOfTemporalLayers); break; + case kVideoCodecH265: + // TODO(bugs.webrtc.org/13485) + break; default: break; } @@ -246,6 +249,9 @@ void VideoCodecTestFixtureImpl::Config::SetCodecSettings( codec_settings.H264()->numberOfTemporalLayers = static_cast(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 637a20cfc9..565a127819 100644 --- a/modules/video_coding/encoded_frame.cc +++ b/modules/video_coding/encoded_frame.cc @@ -140,6 +140,10 @@ void VCMEncodedFrame::CopyCodecSpecific(const RTPVideoHeader* header) { _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 13092b5e24..9fc233240a 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 kVp8Header[kCodecTypeBytesCount] = {'V', 'P', '8', '0'}; 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 @@ absl::optional IvfFileReader::ParseCodecType(uint8_t* buffer, 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 01025986d6..cc5aed3096 100644 --- a/modules/video_coding/utility/ivf_file_writer.cc +++ b/modules/video_coding/utility/ivf_file_writer.cc @@ -92,6 +92,12 @@ bool IvfFileWriter::WriteHeader() { 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 18f225447d..3b9aaa377e 100644 --- a/modules/video_coding/utility/qp_parser.cc +++ b/modules/video_coding/utility/qp_parser.cc @@ -36,6 +36,8 @@ absl::optional QpParser::Parse(VideoCodecType codec_type, } } 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 95e9488b01..824f4b0eac 100644 --- a/modules/video_coding/utility/simulcast_utility.cc +++ b/modules/video_coding/utility/simulcast_utility.cc @@ -94,6 +94,9 @@ int SimulcastUtility::NumberOfTemporalLayers(const VideoCodec& codec, 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 43fab8c432..79421ff3e4 100644 --- a/modules/video_coding/video_codec_initializer.cc +++ b/modules/video_coding/video_codec_initializer.cc @@ -344,6 +344,9 @@ VideoCodec VideoCodecInitializer::VideoEncoderConfigToVideoCodec( 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 1652e31704..1a269b4fa6 100644 --- a/rtc_base/experiments/balanced_degradation_settings.cc +++ b/rtc_base/experiments/balanced_degradation_settings.cc @@ -159,6 +159,8 @@ absl::optional GetThresholds( 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 @@ int GetFps(VideoCodecType type, 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 @@ absl::optional GetKbps( 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 @@ absl::optional GetKbpsRes( 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 f37c4e9c76..f9e7613a15 100644 --- a/rtc_base/experiments/min_video_bitrate_experiment.cc +++ b/rtc_base/experiments/min_video_bitrate_experiment.cc @@ -94,6 +94,8 @@ absl::optional GetExperimentalMinVideoBitrate(VideoCodecType type) { 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 7d5722bbe3..0c4ec22d71 100644 --- a/rtc_base/experiments/quality_scaling_experiment.cc +++ b/rtc_base/experiments/quality_scaling_experiment.cc @@ -81,6 +81,8 @@ QualityScalingExperiment::GetQpThresholds(VideoCodecType codec_type) { 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 f171260a4e..90d568f30f 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 @@ bool Convert(std::string inputfile, {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 a2eeef8d5f..74f59c4fdf 100644 --- a/rtc_tools/video_encoder/video_encoder.cc +++ b/rtc_tools/video_encoder/video_encoder.cc @@ -295,7 +295,9 @@ class TestVideoEncoderFactoryWrapper final { 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 242ce1b2b8..c8bfec2ade 100644 --- a/rtc_tools/video_replay.cc +++ b/rtc_tools/video_replay.cc @@ -267,6 +267,8 @@ class DecoderIvfFileWriter : public test::FakeDecoder { 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 22bfe77944..8c231c07fb 100644 --- a/sdk/android/src/jni/video_decoder_wrapper.cc +++ b/sdk/android/src/jni/video_decoder_wrapper.cc @@ -255,6 +255,13 @@ absl::optional VideoDecoderWrapper::ParseQP( 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 04b083cf53..53246f380e 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 @@ class VideoDecoderWrapper : public VideoDecoder { 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 3912ede048..6cd8acbb04 100644 --- a/sdk/android/src/jni/video_encoder_wrapper.cc +++ b/sdk/android/src/jni/video_encoder_wrapper.cc @@ -227,6 +227,8 @@ VideoEncoderWrapper::GetScalingSettingsInternal(JNIEnv* jni) const { 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 @@ int VideoEncoderWrapper::ParseQp(rtc::ArrayView buffer) { 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 d3eb2203f0..04d70f3e28 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 @@ class VideoEncoderWrapper : public VideoEncoder { 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 b1cabc31ac..ea66c4a1c8 100644 --- a/test/fuzzers/rtp_frame_reference_finder_fuzzer.cc +++ b/test/fuzzers/rtp_frame_reference_finder_fuzzer.cc @@ -120,6 +120,9 @@ void FuzzOneInput(const uint8_t* data, size_t size) { reader.CopyTo( &video_header.video_type_header.emplace()); 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 e082aa37c6..d376a8fbb3 100644 --- a/test/scenario/video_stream.cc +++ b/test/scenario/video_stream.cc @@ -51,6 +51,8 @@ uint8_t CodecTypeToPayloadType(VideoCodecType codec_type) { return VideoTestConstants::kPayloadTypeVP9; case VideoCodecType::kVideoCodecH264: return VideoTestConstants::kPayloadTypeH264; + case VideoCodecType::kVideoCodecH265: + return VideoTestConstants::kPayloadTypeH265; default: RTC_DCHECK_NOTREACHED(); } @@ -66,6 +68,8 @@ std::string CodecTypeToCodecName(VideoCodecType codec_type) { return cricket::kVp9CodecName; case VideoCodecType::kVideoCodecH264: return cricket::kH264CodecName; + case VideoCodecType::kVideoCodecH265: + return cricket::kH265CodecName; default: RTC_DCHECK_NOTREACHED(); } @@ -203,6 +207,7 @@ CreateEncoderSpecificSettings(VideoStreamConfig config) { 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 ec3c948fa4..0dec1135f0 100644 --- a/test/testsupport/ivf_video_frame_generator.cc +++ b/test/testsupport/ivf_video_frame_generator.cc @@ -148,6 +148,9 @@ std::unique_ptr IvfVideoFrameGenerator::CreateVideoDecoder( 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 732d4f0056..b9083987ed 100644 --- a/test/video_test_constants.h +++ b/test/video_test_constants.h @@ -31,6 +31,7 @@ class VideoTestConstants { 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 2c4efdb5a6..d5c1f91575 100644 --- a/video/encoder_overshoot_detector.cc +++ b/video/encoder_overshoot_detector.cc @@ -266,6 +266,12 @@ void EncoderOvershootDetector::UpdateHistograms() { 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 bdc2676281..2178957889 100644 --- a/video/encoder_overshoot_detector_unittest.cc +++ b/video/encoder_overshoot_detector_unittest.cc @@ -35,6 +35,8 @@ static std::string CodecTypeToHistogramSuffix(VideoCodecType codec) { return "Av1"; case kVideoCodecH264: return "H264"; + case kVideoCodecH265: + return "H265"; case kVideoCodecGeneric: return "Generic"; case kVideoCodecMultiplex: @@ -275,6 +277,8 @@ INSTANTIATE_TEST_SUITE_P( {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 9a5f69de89..9504bdac8b 100644 --- a/video/send_statistics_proxy.cc +++ b/video/send_statistics_proxy.cc @@ -47,6 +47,7 @@ enum HistogramCodecType { kVideoVp9 = 2, kVideoH264 = 3, kVideoAv1 = 4, + kVideoH265 = 5, kVideoMax = 64, }; @@ -76,6 +77,8 @@ HistogramCodecType PayloadNameToHistogramCodecType( 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 c367510b21..5eeb7400ce 100644 --- a/video/video_stream_encoder.cc +++ b/video/video_stream_encoder.cc @@ -135,7 +135,9 @@ bool RequiresEncoderReset(const VideoCodec& prev_send_codec, return true; } break; - + case kVideoCodecH265: + // TODO(bugs.webrtc.org/13485): Implement new send codec H265 + [[fallthrough]]; default: break; } @@ -1351,6 +1353,7 @@ void VideoStreamEncoder::ReconfigureEncoder() { // 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 44fc53f90d..53b4a0fa74 100644 --- a/video/video_stream_encoder_unittest.cc +++ b/video/video_stream_encoder_unittest.cc @@ -8822,6 +8822,9 @@ class VideoStreamEncoderWithRealEncoderTest 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(); }