From 7182a22085bb3b8c23970bd385532660f0ac11c1 Mon Sep 17 00:00:00 2001 From: qiin <414382190@qq.com> Date: Mon, 3 Aug 2026 16:14:15 +0800 Subject: [PATCH 1/3] =?UTF-8?q?fix(hdr):=20=E6=8C=89=E7=A0=81=E6=B5=81?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E8=AF=86=E5=88=AB=20HDR=20Vivid?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nativelib/src/main/cpp/video_decoder.cpp | 41 +++++++++--------------- nativelib/src/main/cpp/video_decoder.h | 2 +- 2 files changed, 16 insertions(+), 27 deletions(-) diff --git a/nativelib/src/main/cpp/video_decoder.cpp b/nativelib/src/main/cpp/video_decoder.cpp index dc91df0..a0cde21 100644 --- a/nativelib/src/main/cpp/video_decoder.cpp +++ b/nativelib/src/main/cpp/video_decoder.cpp @@ -482,8 +482,7 @@ int VideoDecoder::Init(const VideoDecoderConfig& config, OHNativeWindow* window) hdrVividProbeActive_.store( (config.codec == VideoCodecType::HEVC || config.codec == VideoCodecType::AV1) && - config.enableHdr && - config.hdrType == HdrType::HLG, + config.enableHdr, std::memory_order_relaxed); hdrVividDetected_.store(false, std::memory_order_relaxed); window_ = window; @@ -745,12 +744,13 @@ int VideoDecoder::Init(const VideoDecoderConfig& config, OHNativeWindow* window) // HDR Vivid is signalled by CUVA metadata preserved in the elementary // stream. OH_MD_KEY_VIDEO_IS_HDR_VIVID describes a media-file track and is // only supported by demuxers/muxers, so it is not a decoder Configure key. - if (config_.enableHdr && config_.hdrType == HdrType::HLG) { - OH_LOG_INFO(LOG_APP, "{Init} HLG stream relies on in-band CUVA metadata for HDR Vivid"); + if (config_.enableHdr) { + OH_LOG_INFO(LOG_APP, + "{Init} CUVA metadata remains in-band; no client-side HDR Vivid override"); } OH_LOG_INFO(LOG_APP, "{Init} Configuring decoder: HDR=%{public}d, hdrType=%{public}d (0=SDR,1=HDR10,2=HLG), colorSpace=%{public}d, colorRange=%{public}d", - config_.enableHdr ? 1 : 0, static_cast(config_.hdrType), + config_.enableHdr ? 1 : 0, static_cast(config_.hdrType), static_cast(config_.colorSpace), static_cast(config_.colorRange)); ret = OH_VideoDecoder_Configure(decoder_, format); @@ -780,26 +780,19 @@ int VideoDecoder::Init(const VideoDecoderConfig& config, OHNativeWindow* window) // OH_COLORSPACE_BT2020_PQ_LIMIT = 10 (COLORPRIMARIES_BT2020 | TRANSFUNC_PQ | RANGE_LIMITED) OH_NativeBuffer_ColorSpace windowColorSpace; - OH_NativeBuffer_MetadataType metadataType; bool isFullRange = (config_.colorRange == ColorRange::FULL); switch (config_.hdrType) { - case HdrType::HLG: // HLG with HDR Vivid + case HdrType::HLG: windowColorSpace = isFullRange ? OH_COLORSPACE_BT2020_HLG_FULL : OH_COLORSPACE_BT2020_HLG_LIMIT; - // 使用 OH_VIDEO_HDR_VIVID 而非 OH_VIDEO_HDR_HLG - // Sunshine 编码端会在 HLG 码流中携带 CUVA T.35 Vivid 动态元数据 - // OH_VIDEO_HDR_VIVID 告知显示管线按 Vivid 标准处理色调映射 - metadataType = OH_VIDEO_HDR_VIVID; break; case HdrType::HDR10: // PQ default: windowColorSpace = isFullRange ? OH_COLORSPACE_BT2020_PQ_FULL : OH_COLORSPACE_BT2020_PQ_LIMIT; - metadataType = OH_VIDEO_HDR_HDR10; break; } - - OH_LOG_INFO(LOG_APP, "{Init} HDR NativeWindow: colorspace=%{public}d, metadata=%{public}d, fullRange=%{public}d", - static_cast(windowColorSpace), static_cast(metadataType), isFullRange ? 1 : 0); + OH_LOG_INFO(LOG_APP, "{Init} HDR NativeWindow: colorspace=%{public}d, fullRange=%{public}d", + static_cast(windowColorSpace), isFullRange ? 1 : 0); #ifdef __OHOS__ // 1. 设置 Color Gamut(颜色域) @@ -810,27 +803,23 @@ int VideoDecoder::Init(const VideoDecoderConfig& config, OHNativeWindow* window) OH_LOG_WARN(LOG_APP, "{Init} Failed to set color gamut: %{public}d", gamutRet); } - // 2. 设置 HDR 元数据类型 - int32_t metaRet = OH_NativeWindow_SetMetadataValue(window_, OH_HDR_METADATA_TYPE, - sizeof(metadataType), reinterpret_cast(&metadataType)); - if (metaRet != 0) { - OH_LOG_WARN(LOG_APP, "{Init} Failed to set HDR metadata: %{public}d", metaRet); - } - - // 3. 设置 colorspace + // 不在 Window 上预设 OH_HDR_METADATA_TYPE,保留解码器从码流 + // CUVA 动态元数据判定输出 Buffer HDR 类型的能力。 + + // 2. 设置 colorspace int32_t csRet = OH_NativeWindow_SetColorSpace(window_, windowColorSpace); if (csRet != 0) { OH_LOG_WARN(LOG_APP, "{Init} Failed to set colorspace: %{public}d", csRet); } - // 4. 设置 HDR 白点亮度 + // 3. 设置 HDR 白点亮度 float hdrWhitePointBrightness = 1.0f; int32_t hdrBrightRet = OH_NativeWindow_NativeWindowHandleOpt(window_, SET_HDR_WHITE_POINT_BRIGHTNESS, hdrWhitePointBrightness); if (hdrBrightRet != 0) { OH_LOG_WARN(LOG_APP, "{Init} Failed to set HDR white point: %{public}d", hdrBrightRet); } - // 5. 设置 HDR 静态元数据(SMPTE 2086 + CTA 861.3) + // 4. 设置 HDR 静态元数据(SMPTE 2086 + CTA 861.3) // Sunshine 会通过控制流传递主机显示器/内容元数据;缺失时才使用 BT.2020 默认值。 OH_NativeBuffer_StaticMetadata staticMetadata; bool hasHostHdrStaticMetadata = false; @@ -2657,7 +2646,7 @@ void SetHdrConfig(bool enableHdr, int hdrType, int colorSpace, int colorRange) { OH_LOG_INFO(LOG_APP, "SetHdrConfig: HDR=%{public}d, type=%{public}d, cs=%{public}d, cr=%{public}d", enableHdr ? 1 : 0, hdrType, colorSpace, colorRange); - + g_enableHdr = enableHdr; switch (hdrType) { case 1: g_hdrType = HdrType::HDR10; break; diff --git a/nativelib/src/main/cpp/video_decoder.h b/nativelib/src/main/cpp/video_decoder.h index 5b99675..9b4ca93 100644 --- a/nativelib/src/main/cpp/video_decoder.h +++ b/nativelib/src/main/cpp/video_decoder.h @@ -428,7 +428,7 @@ class VideoDecoder { std::atomic syncDrainEvents_{0}; std::atomic syncDrainFrames_{0}; - // HLG 会话开始阶段扫描 CUVA T.35 SEI;命中结果保持到会话结束。 + // 会话开始阶段扫描 CUVA T.35 元数据,仅用于状态观测。 std::atomic hdrVividProbeDecodeUnits_{0}; std::atomic hdrVividProbeActive_{false}; std::atomic hdrVividDetected_{false}; From cf01f9d75f3877ca9e93c0cf1db85075d9ecf0e2 Mon Sep 17 00:00:00 2001 From: qiin <414382190@qq.com> Date: Mon, 3 Aug 2026 16:31:14 +0800 Subject: [PATCH 2/3] =?UTF-8?q?fix(hdr):=20=E5=90=8C=E6=AD=A5=E8=A7=A3?= =?UTF-8?q?=E7=A0=81=E8=BE=93=E5=87=BA=20HDR=20=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nativelib/src/main/cpp/video_decoder.cpp | 83 ++++++++++++++++++++++-- nativelib/src/main/cpp/video_decoder.h | 7 ++ 2 files changed, 85 insertions(+), 5 deletions(-) diff --git a/nativelib/src/main/cpp/video_decoder.cpp b/nativelib/src/main/cpp/video_decoder.cpp index a0cde21..f2c8baa 100644 --- a/nativelib/src/main/cpp/video_decoder.cpp +++ b/nativelib/src/main/cpp/video_decoder.cpp @@ -485,7 +485,11 @@ int VideoDecoder::Init(const VideoDecoderConfig& config, OHNativeWindow* window) config.enableHdr, std::memory_order_relaxed); hdrVividDetected_.store(false, std::memory_order_relaxed); - window_ = window; + { + std::lock_guard lock(windowMetadataMutex_); + window_ = window; + hasAppliedHdrMetadataType_ = false; + } render_ = NativeRender::GetInstance(); OH_LOG_INFO(LOG_APP, "{Init} Initializing video decoder: %{public}dx%{public}d@%.2f, codec=%{public}d, window=%{public}p", @@ -802,9 +806,12 @@ int VideoDecoder::Init(const VideoDecoderConfig& config, OHNativeWindow* window) if (gamutRet != 0) { OH_LOG_WARN(LOG_APP, "{Init} Failed to set color gamut: %{public}d", gamutRet); } - - // 不在 Window 上预设 OH_HDR_METADATA_TYPE,保留解码器从码流 - // CUVA 动态元数据判定输出 Buffer HDR 类型的能力。 + + // 先写入基础 HDR 类型,覆盖同一 Surface 上一会话可能遗留的 Vivid。 + // 如果后续从输出格式或 CUVA 码流检测到 Vivid,再切换类型。 + const OH_NativeBuffer_MetadataType baseMetadataType = + config_.hdrType == HdrType::HLG ? OH_VIDEO_HDR_HLG : OH_VIDEO_HDR_HDR10; + SetNativeWindowHdrMetadataType(baseMetadataType, "session baseline"); // 2. 设置 colorspace int32_t csRet = OH_NativeWindow_SetColorSpace(window_, windowColorSpace); @@ -1018,7 +1025,11 @@ void VideoDecoder::Cleanup() { timestampWriteIndex_ = 0; } - window_ = nullptr; + { + std::lock_guard lock(windowMetadataMutex_); + window_ = nullptr; + hasAppliedHdrMetadataType_ = false; + } configured_ = false; firstFrameReceived_ = false; lastInstantDecodeTimeMs_ = 0; @@ -1154,6 +1165,7 @@ int VideoDecoder::SubmitDecodeUnitScatter(const BufferSegment* segments, int seg if (scanner.Finish()) { hdrVividDetected_.store(true, std::memory_order_relaxed); hdrVividProbeActive_.store(false, std::memory_order_relaxed); + SetNativeWindowHdrMetadataType(OH_VIDEO_HDR_VIVID, "CUVA bitstream"); OH_LOG_INFO(LOG_APP, "HDR Vivid CUVA dynamic metadata detected in %{public}s", config_.codec == VideoCodecType::AV1 ? @@ -1541,6 +1553,61 @@ void VideoDecoder::RecordDroppedFrames(DropReason reason, uint64_t count) { // AVCodec 回调实现 // ============================================================================= +void VideoDecoder::SetNativeWindowHdrMetadataType( + OH_NativeBuffer_MetadataType metadataType, const char* source) { +#ifdef __OHOS__ + std::lock_guard lock(windowMetadataMutex_); + if (window_ == nullptr || + (hasAppliedHdrMetadataType_ && appliedHdrMetadataType_ == metadataType)) { + return; + } + + OH_NativeBuffer_MetadataType value = metadataType; + const int32_t ret = OH_NativeWindow_SetMetadataValue( + window_, OH_HDR_METADATA_TYPE, sizeof(value), reinterpret_cast(&value)); + if (ret != 0) { + OH_LOG_WARN(LOG_APP, + "Failed to set HDR metadata type=%{public}d from %{public}s: %{public}d", + static_cast(metadataType), source, ret); + return; + } + + appliedHdrMetadataType_ = metadataType; + hasAppliedHdrMetadataType_ = true; + OH_LOG_INFO(LOG_APP, "HDR metadata type=%{public}d applied from %{public}s", + static_cast(metadataType), source); +#else + (void)metadataType; + (void)source; +#endif +} + +void VideoDecoder::ApplyOutputHdrMetadata(OH_AVFormat* format) { + if (!config_.enableHdr || format == nullptr) { + return; + } + + int32_t vividFlag = 0; + if (OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_IS_HDR_VIVID, &vividFlag) && + vividFlag != 0) { + hdrVividDetected_.store(true, std::memory_order_relaxed); + } + + int32_t transferChar = config_.hdrType == HdrType::HLG ? + kTransferCharHLG : kTransferCharPQ; + OH_AVFormat_GetIntValue(format, OH_MD_KEY_TRANSFER_CHARACTERISTICS, &transferChar); + + OH_NativeBuffer_MetadataType metadataType; + if (hdrVividDetected_.load(std::memory_order_relaxed)) { + metadataType = OH_VIDEO_HDR_VIVID; + } else if (transferChar == kTransferCharHLG) { + metadataType = OH_VIDEO_HDR_HLG; + } else { + metadataType = OH_VIDEO_HDR_HDR10; + } + SetNativeWindowHdrMetadataType(metadataType, "decoder output format"); +} + void VideoDecoder::OnError(OH_AVCodec* codec, int32_t errorCode, void* userData) { OH_LOG_ERROR(LOG_APP, "Decoder error: %{public}d", errorCode); } @@ -1557,6 +1624,11 @@ void VideoDecoder::OnOutputFormatChanged(OH_AVCodec* codec, OH_AVFormat* format, OH_AVFormat_GetIntValue(format, OH_MD_KEY_HEIGHT, &height); } OH_LOG_INFO(LOG_APP, "Output format changed: %{public}dx%{public}d", width, height); + + auto* self = static_cast(userData); + if (self != nullptr) { + self->ApplyOutputHdrMetadata(format); + } } void VideoDecoder::OnInputBufferAvailable(OH_AVCodec* codec, uint32_t index, @@ -2176,6 +2248,7 @@ int VideoDecoder::SyncProcessOutput(int64_t timeoutUs) { OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_PIC_WIDTH, &width); OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_PIC_HEIGHT, &height); OH_LOG_INFO(LOG_APP, "Sync: output format changed to %{public}dx%{public}d", width, height); + ApplyOutputHdrMetadata(format); OH_AVFormat_Destroy(format); } return 0; // 流变化不算帧输出,继续处理 diff --git a/nativelib/src/main/cpp/video_decoder.h b/nativelib/src/main/cpp/video_decoder.h index 9b4ca93..e3c8615 100644 --- a/nativelib/src/main/cpp/video_decoder.h +++ b/nativelib/src/main/cpp/video_decoder.h @@ -302,6 +302,10 @@ class VideoDecoder { static void OnOutputFormatChanged(OH_AVCodec* codec, OH_AVFormat* format, void* userData); static void OnInputBufferAvailable(OH_AVCodec* codec, uint32_t index, OH_AVBuffer* data, void* userData); static void OnOutputBufferAvailable(OH_AVCodec* codec, uint32_t index, OH_AVBuffer* data, void* userData); + + void ApplyOutputHdrMetadata(OH_AVFormat* format); + void SetNativeWindowHdrMetadataType(OH_NativeBuffer_MetadataType metadataType, + const char* source); // 获取 MIME 类型 const char* GetMimeType(VideoCodecType codec) const; @@ -349,6 +353,9 @@ class VideoDecoder { // 渲染窗口 OHNativeWindow* window_ = nullptr; + std::mutex windowMetadataMutex_; + bool hasAppliedHdrMetadataType_ = false; + OH_NativeBuffer_MetadataType appliedHdrMetadataType_ = OH_VIDEO_HDR_HDR10; // NativeRender's singleton lifetime covers the decoder session. Cache it so // output callbacks do not contend on the singleton mutex for every frame. From 5986dd40fa9c105deb1d6cbc552e945266343eec Mon Sep 17 00:00:00 2001 From: qiin <414382190@qq.com> Date: Mon, 3 Aug 2026 17:17:46 +0800 Subject: [PATCH 3/3] =?UTF-8?q?fix(hdr):=20=E4=BF=9D=E6=8C=81=20Vivid=20?= =?UTF-8?q?=E4=BC=9A=E8=AF=9D=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nativelib/src/main/cpp/video_decoder.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/nativelib/src/main/cpp/video_decoder.cpp b/nativelib/src/main/cpp/video_decoder.cpp index f2c8baa..4290a7d 100644 --- a/nativelib/src/main/cpp/video_decoder.cpp +++ b/nativelib/src/main/cpp/video_decoder.cpp @@ -1557,8 +1557,15 @@ void VideoDecoder::SetNativeWindowHdrMetadataType( OH_NativeBuffer_MetadataType metadataType, const char* source) { #ifdef __OHOS__ std::lock_guard lock(windowMetadataMutex_); - if (window_ == nullptr || - (hasAppliedHdrMetadataType_ && appliedHdrMetadataType_ == metadataType)) { + if (window_ == nullptr) { + return; + } + if (hasAppliedHdrMetadataType_ && + appliedHdrMetadataType_ == OH_VIDEO_HDR_VIVID && + metadataType != OH_VIDEO_HDR_VIVID) { + return; + } + if (hasAppliedHdrMetadataType_ && appliedHdrMetadataType_ == metadataType) { return; } @@ -1587,12 +1594,6 @@ void VideoDecoder::ApplyOutputHdrMetadata(OH_AVFormat* format) { return; } - int32_t vividFlag = 0; - if (OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_IS_HDR_VIVID, &vividFlag) && - vividFlag != 0) { - hdrVividDetected_.store(true, std::memory_order_relaxed); - } - int32_t transferChar = config_.hdrType == HdrType::HLG ? kTransferCharHLG : kTransferCharPQ; OH_AVFormat_GetIntValue(format, OH_MD_KEY_TRANSFER_CHARACTERISTICS, &transferChar);