From 25c0781248e6e0922792f8934c7fc12e8c42c0f1 Mon Sep 17 00:00:00 2001 From: David Liu Date: Thu, 24 Jul 2025 22:22:27 +0900 Subject: [PATCH] h265 patch --- common_video/h264/sps_parser.cc | 4 +- common_video/h264/sps_parser.h | 2 + common_video/h265/h265_vps_parser.cc | 45 +++++++++++++++++++ common_video/h265/h265_vps_parser.h | 4 ++ .../webrtc/HardwareVideoEncoderFactory.java | 5 +++ sdk/android/api/org/webrtc/VideoEncoder.java | 2 + .../java/org/webrtc/HardwareVideoEncoder.java | 4 ++ webrtc.gni | 2 +- 8 files changed, 66 insertions(+), 2 deletions(-) diff --git a/common_video/h264/sps_parser.cc b/common_video/h264/sps_parser.cc index 197fac9573..84cbb8dc0b 100644 --- a/common_video/h264/sps_parser.cc +++ b/common_video/h264/sps_parser.cc @@ -164,9 +164,11 @@ std::optional SpsParser::ParseSpsUpToVui( // to signify resolutions that aren't multiples of 16. // // pic_width_in_mbs_minus1: ue(v) - sps.width = 16 * (reader.ReadExponentialGolomb() + 1); + sps.pic_width_in_mbs_minus1 = reader.ReadExponentialGolomb(); + sps.width = 16 * (sps.pic_width_in_mbs_minus1 + 1); // pic_height_in_map_units_minus1: ue(v) uint32_t pic_height_in_map_units_minus1 = reader.ReadExponentialGolomb(); + sps.pic_height_in_map_units_minus1 = pic_height_in_map_units_minus1; // frame_mbs_only_flag: u(1) sps.frame_mbs_only_flag = reader.ReadBit(); if (!sps.frame_mbs_only_flag) { diff --git a/common_video/h264/sps_parser.h b/common_video/h264/sps_parser.h index a8a6675e0a..04a4a2a4df 100644 --- a/common_video/h264/sps_parser.h +++ b/common_video/h264/sps_parser.h @@ -28,6 +28,8 @@ class RTC_EXPORT SpsParser { SpsState(const SpsState&); ~SpsState(); + uint32_t pic_width_in_mbs_minus1 = 0; + uint32_t pic_height_in_map_units_minus1 = 0; uint32_t width = 0; uint32_t height = 0; uint32_t delta_pic_order_always_zero_flag = 0; diff --git a/common_video/h265/h265_vps_parser.cc b/common_video/h265/h265_vps_parser.cc index 5b3fc6b12f..7b097e1a50 100644 --- a/common_video/h265/h265_vps_parser.cc +++ b/common_video/h265/h265_vps_parser.cc @@ -11,6 +11,7 @@ #include "common_video/h265/h265_vps_parser.h" #include "common_video/h265/h265_common.h" +#include "common_video/h265/h265_sps_parser.h" #include "rtc_base/bit_buffer.h" #include "rtc_base/bitstream_reader.h" #include "rtc_base/logging.h" @@ -44,6 +45,50 @@ std::optional H265VpsParser::ParseInternal( if (!reader.Ok()) { return std::nullopt; } + // vps_base_layer_internal_flag u(1) + reader.ConsumeBits(1); + // vps_base_layer_available_flag u(1) + reader.ConsumeBits(1); + // vps_max_layers_minus1 u(6) + vps.vps_max_sub_layers_minus1 = reader.ReadBits(6); + + if (!reader.Ok() || (vps.vps_max_sub_layers_minus1 >= kMaxSubLayers)) { + return std::nullopt; + } + + // vps_max_sub_layers_minus1 u(3) + reader.ConsumeBits(3); + // vps_temporal_id_nesting_flag u(1) + reader.ConsumeBits(1); + // vps_reserved_0xffff_16bits u(16) + reader.ConsumeBits(16); + + auto profile_tier_level = H265SpsParser::ParseProfileTierLevel(true, vps.vps_max_sub_layers_minus1, reader); + if (!reader.Ok() || !profile_tier_level) { + return std::nullopt; + } + + bool vps_sub_layer_ordering_info_present_flag = reader.Read(); + for (uint32_t i = (vps_sub_layer_ordering_info_present_flag != 0) ? 0 : vps.vps_max_sub_layers_minus1; i <= vps.vps_max_sub_layers_minus1; i++) { + // vps_max_dec_pic_buffering_minus1[ i ]: ue(v) + reader.ReadExponentialGolomb(); + // vps_max_num_reorder_pics[ i ]: ue(v) + vps.vps_max_num_reorder_pics[i] = reader.ReadExponentialGolomb(); + if (!reader.Ok() || (i > 0 && vps.vps_max_num_reorder_pics[i] < vps.vps_max_num_reorder_pics[i - 1])) { + return std::nullopt; + } + + // vps_max_latency_increase_plus1: ue(v) + reader.ReadExponentialGolomb(); + } + if (!vps_sub_layer_ordering_info_present_flag) { + for (uint32_t i = 0; i < vps.vps_max_sub_layers_minus1; ++i) { + vps.vps_max_num_reorder_pics[i] = vps.vps_max_num_reorder_pics[vps.vps_max_sub_layers_minus1]; + } + } + if (!reader.Ok() || !profile_tier_level) { + return std::nullopt; + } return vps; } diff --git a/common_video/h265/h265_vps_parser.h b/common_video/h265/h265_vps_parser.h index 619ae2e211..bfb2da8179 100644 --- a/common_video/h265/h265_vps_parser.h +++ b/common_video/h265/h265_vps_parser.h @@ -21,12 +21,16 @@ namespace webrtc { // A class for parsing out video parameter set (VPS) data from an H265 NALU. class RTC_EXPORT H265VpsParser { public: + static constexpr uint32_t kMaxSubLayers = 7; + // The parsed state of the VPS. Only some select values are stored. // Add more as they are actually needed. struct RTC_EXPORT VpsState { VpsState(); uint32_t id = 0; + uint32_t vps_max_sub_layers_minus1 = 0; + uint32_t vps_max_num_reorder_pics[kMaxSubLayers] = {}; }; // Unpack RBSP and parse VPS state from the supplied buffer. diff --git a/sdk/android/api/org/webrtc/HardwareVideoEncoderFactory.java b/sdk/android/api/org/webrtc/HardwareVideoEncoderFactory.java index 125e1d01c4..1307787db5 100644 --- a/sdk/android/api/org/webrtc/HardwareVideoEncoderFactory.java +++ b/sdk/android/api/org/webrtc/HardwareVideoEncoderFactory.java @@ -197,6 +197,7 @@ private boolean isHardwareSupportedInCurrentSdk(MediaCodecInfo info, VideoCodecM case H264: return isHardwareSupportedInCurrentSdkH264(info); case H265: + return isHardwareSupportedInCurrentSdkH265(info); case AV1: return false; } @@ -230,6 +231,10 @@ private boolean isHardwareSupportedInCurrentSdkH264(MediaCodecInfo info) { return name.startsWith(QCOM_PREFIX) || name.startsWith(EXYNOS_PREFIX); } + private boolean isHardwareSupportedInCurrentSdkH265(MediaCodecInfo unusedInfo) { + return true; + } + private boolean isMediaCodecAllowed(MediaCodecInfo info) { if (codecAllowedPredicate == null) { return true; diff --git a/sdk/android/api/org/webrtc/VideoEncoder.java b/sdk/android/api/org/webrtc/VideoEncoder.java index 7c07c82cb9..b6a8316ab1 100644 --- a/sdk/android/api/org/webrtc/VideoEncoder.java +++ b/sdk/android/api/org/webrtc/VideoEncoder.java @@ -86,6 +86,8 @@ public class CodecSpecificInfoVP9 extends CodecSpecificInfo {} public class CodecSpecificInfoH264 extends CodecSpecificInfo {} + public class CodecSpecificInfoH265 extends CodecSpecificInfo {} + public class CodecSpecificInfoAV1 extends CodecSpecificInfo {} /** diff --git a/sdk/android/src/java/org/webrtc/HardwareVideoEncoder.java b/sdk/android/src/java/org/webrtc/HardwareVideoEncoder.java index ae7137a8f9..58abc5f5d8 100644 --- a/sdk/android/src/java/org/webrtc/HardwareVideoEncoder.java +++ b/sdk/android/src/java/org/webrtc/HardwareVideoEncoder.java @@ -512,6 +512,10 @@ public ScalingSettings getScalingSettings() { final int kLowH264QpThreshold = 24; final int kHighH264QpThreshold = 37; return new ScalingSettings(kLowH264QpThreshold, kHighH264QpThreshold); + } else if (codecType == VideoCodecMimeType.H265) { + final int kLowH265QpThreshold = 24; + final int kHighH265QpThreshold = 37; + return new ScalingSettings(kLowH265QpThreshold, kHighH265QpThreshold); } } return ScalingSettings.OFF; diff --git a/webrtc.gni b/webrtc.gni index be03d29e02..60641a05e1 100644 --- a/webrtc.gni +++ b/webrtc.gni @@ -196,7 +196,7 @@ declare_args() { if (build_with_chromium) { rtc_use_h265 = enable_hevc_parser_and_hw_decoder } else { - rtc_use_h265 = proprietary_codecs + rtc_use_h265 = true } # Enable this flag to make webrtc::Mutex be implemented by absl::Mutex.