Commit 36ac40a5 authored by Dale Curtis's avatar Dale Curtis Committed by Commit Bot

Add support for newer macOS color space types.

This adds a new vt_config_util.mm file which handles converting to
and from macOS color space information into a gfx::ColorSpace.

Most notably this adds support for HDR color spaces.

R=ccameron, sandersd

Bug: 1103432
Test: New tests.
Change-Id: I17f5c93276c1cc19a1623c007370e4f480bd2e0c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2336179
Auto-Submit: Dale Curtis <dalecurtis@chromium.org>
Commit-Queue: Dale Curtis <dalecurtis@chromium.org>
Reviewed-by: default avatarccameron <ccameron@chromium.org>
Reviewed-by: default avatarDan Sanders <sandersd@chromium.org>
Cr-Commit-Position: refs/heads/master@{#794827}
parent ac9be09f
...@@ -524,6 +524,10 @@ source_set("unit_tests") { ...@@ -524,6 +524,10 @@ source_set("unit_tests") {
] ]
libs = [ "dxguid.lib" ] libs = [ "dxguid.lib" ]
} }
if (is_mac) {
deps += [ "//media/gpu/mac:unit_tests" ]
}
} }
# TODO(crbug.com/1006266): consider using |use_chromeos_video_acceleration|. # TODO(crbug.com/1006266): consider using |use_chromeos_video_acceleration|.
......
...@@ -18,6 +18,8 @@ source_set("mac") { ...@@ -18,6 +18,8 @@ source_set("mac") {
visibility = [ "//media/gpu" ] visibility = [ "//media/gpu" ]
sources = [ sources = [
"vt_config_util.h",
"vt_config_util.mm",
"vt_video_decode_accelerator_mac.cc", "vt_video_decode_accelerator_mac.cc",
"vt_video_decode_accelerator_mac.h", "vt_video_decode_accelerator_mac.h",
"vt_video_encode_accelerator_mac.cc", "vt_video_encode_accelerator_mac.cc",
...@@ -42,3 +44,16 @@ source_set("mac") { ...@@ -42,3 +44,16 @@ source_set("mac") {
"//ui/gl", "//ui/gl",
] ]
} }
source_set("unit_tests") {
testonly = true
frameworks = [
"CoreFoundation.framework",
"CoreMedia.framework",
]
deps = [
"//media/gpu:test_support",
"//testing/gtest",
]
sources = [ "vt_config_util_unittest.cc" ]
}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_GPU_MAC_VT_CONFIG_UTIL_H_
#define MEDIA_GPU_MAC_VT_CONFIG_UTIL_H_
#include <CoreFoundation/CoreFoundation.h>
#include <CoreMedia/CoreMedia.h>
#include "base/optional.h"
#include "media/base/hdr_metadata.h"
#include "media/base/video_codecs.h"
#include "media/base/video_color_space.h"
#include "media/gpu/media_gpu_export.h"
#include "media/video/video_decode_accelerator.h"
namespace media {
MEDIA_GPU_EXPORT CFMutableDictionaryRef
CreateFormatExtensions(CMVideoCodecType codec_type,
VideoCodecProfile profile,
const VideoColorSpace& color_space,
base::Optional<HDRMetadata> hdr_metadata);
MEDIA_GPU_EXPORT gfx::ColorSpace GetImageBufferColorSpace(
CVImageBufferRef image_buffer);
} // namespace media
#endif // MEDIA_GPU_MAC_VT_CONFIG_UTIL_H_
This diff is collapsed.
This diff is collapsed.
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/mac/mac_logging.h" #include "base/mac/mac_logging.h"
#include "base/mac/mac_util.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/stl_util.h" #include "base/stl_util.h"
...@@ -32,6 +33,8 @@ ...@@ -32,6 +33,8 @@
#include "base/version.h" #include "base/version.h"
#include "components/crash/core/common/crash_key.h" #include "components/crash/core/common/crash_key.h"
#include "media/base/limits.h" #include "media/base/limits.h"
#include "media/base/media_switches.h"
#include "media/gpu/mac/vt_config_util.h"
#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect.h"
#include "ui/gl/gl_context.h" #include "ui/gl/gl_context.h"
#include "ui/gl/gl_image_io_surface.h" #include "ui/gl/gl_image_io_surface.h"
...@@ -110,6 +113,9 @@ base::ScopedCFTypeRef<CFMutableDictionaryRef> BuildImageConfig( ...@@ -110,6 +113,9 @@ base::ScopedCFTypeRef<CFMutableDictionaryRef> BuildImageConfig(
// Note that 4:2:0 textures cannot be used directly as RGBA in OpenGL, but are // Note that 4:2:0 textures cannot be used directly as RGBA in OpenGL, but are
// lower power than 4:2:2 when composited directly by CoreAnimation. // lower power than 4:2:2 when composited directly by CoreAnimation.
//
// TODO(crbug.com/1103432): Based on other > 8-bit codecs, we'll likely need
// to add kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange here.
int32_t pixel_format = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange; int32_t pixel_format = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
#define CFINT(i) CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i) #define CFINT(i) CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i)
base::ScopedCFTypeRef<CFNumberRef> cf_pixel_format(CFINT(pixel_format)); base::ScopedCFTypeRef<CFNumberRef> cf_pixel_format(CFINT(pixel_format));
...@@ -297,155 +303,6 @@ void OutputThunk(void* decompression_output_refcon, ...@@ -297,155 +303,6 @@ void OutputThunk(void* decompression_output_refcon,
vda->Output(source_frame_refcon, status, image_buffer); vda->Output(source_frame_refcon, status, image_buffer);
} }
// Read the value for the key in |key| to CFString and convert it to IdType.
// Use the list of pairs in |cfstr_id_pairs| to do the conversion (by doing a
// linear lookup).
template <typename IdType, typename StringIdPair>
bool GetImageBufferProperty(CVImageBufferRef image_buffer,
CFStringRef key,
const StringIdPair* cfstr_id_pairs,
size_t cfstr_id_pairs_size,
IdType* value_as_id) {
CFStringRef value_as_string = reinterpret_cast<CFStringRef>(
CVBufferGetAttachment(image_buffer, key, nullptr));
if (!value_as_string)
return false;
for (size_t i = 0; i < cfstr_id_pairs_size; ++i) {
if (!CFStringCompare(value_as_string, cfstr_id_pairs[i].cfstr, 0)) {
*value_as_id = cfstr_id_pairs[i].id;
return true;
}
}
return false;
}
// Use a matrix id that is coherent with a primary id. Useful when we fail to
// parse the matrix. Previously it was always defaulting to MatrixID::BT709
// See http://crbug.com/788236.
gfx::ColorSpace::MatrixID GetDefaultMatrixID(
const gfx::ColorSpace::PrimaryID primary_id) {
gfx::ColorSpace::MatrixID matrix_id = gfx::ColorSpace::MatrixID::BT709;
switch (primary_id) {
case gfx::ColorSpace::PrimaryID::BT709:
matrix_id = gfx::ColorSpace::MatrixID::BT709;
break;
case gfx::ColorSpace::PrimaryID::BT470BG:
matrix_id = gfx::ColorSpace::MatrixID::BT470BG;
break;
default:
break;
}
return matrix_id;
}
gfx::ColorSpace GetImageBufferColorSpace(CVImageBufferRef image_buffer) {
// The named primaries. Default to BT709.
gfx::ColorSpace::PrimaryID primary_id = gfx::ColorSpace::PrimaryID::BT709;
struct {
const CFStringRef cfstr;
const gfx::ColorSpace::PrimaryID id;
} primaries[] = {
{
kCVImageBufferColorPrimaries_ITU_R_709_2,
gfx::ColorSpace::PrimaryID::BT709,
},
{
kCVImageBufferColorPrimaries_EBU_3213,
gfx::ColorSpace::PrimaryID::BT470BG,
},
{
kCVImageBufferColorPrimaries_SMPTE_C,
gfx::ColorSpace::PrimaryID::SMPTE240M,
},
};
if (!GetImageBufferProperty(image_buffer, kCVImageBufferColorPrimariesKey,
primaries, base::size(primaries), &primary_id)) {
DLOG(ERROR) << "Failed to find CVImageBufferRef primaries.";
}
// The named transfer function.
gfx::ColorSpace::TransferID transfer_id = gfx::ColorSpace::TransferID::BT709;
skcms_TransferFunction custom_tr_fn = {2.2f, 1, 0, 1, 0, 0, 0};
struct {
const CFStringRef cfstr;
gfx::ColorSpace::TransferID id;
} transfers[] = {
{
kCVImageBufferTransferFunction_ITU_R_709_2,
gfx::ColorSpace::TransferID::BT709_APPLE,
},
{
kCVImageBufferTransferFunction_SMPTE_240M_1995,
gfx::ColorSpace::TransferID::SMPTE240M,
},
{
kCVImageBufferTransferFunction_UseGamma,
gfx::ColorSpace::TransferID::CUSTOM,
},
};
if (!GetImageBufferProperty(image_buffer, kCVImageBufferTransferFunctionKey,
transfers, base::size(transfers), &transfer_id)) {
DLOG(ERROR) << "Failed to find CVImageBufferRef transfer.";
}
// Transfer functions can also be specified as a gamma value.
if (transfer_id == gfx::ColorSpace::TransferID::CUSTOM) {
// If we fail to find the custom transfer function parameters, fall back to
// BT709.
transfer_id = gfx::ColorSpace::TransferID::BT709;
CFNumberRef gamma_number =
reinterpret_cast<CFNumberRef>(CVBufferGetAttachment(
image_buffer, kCVImageBufferGammaLevelKey, nullptr));
if (gamma_number) {
CGFloat gamma_float = 0;
if (CFNumberGetValue(gamma_number, kCFNumberCGFloatType, &gamma_float)) {
transfer_id = gfx::ColorSpace::TransferID::CUSTOM;
custom_tr_fn.g = gamma_float;
} else {
DLOG(ERROR) << "Failed to get CVImageBufferRef gamma level as float.";
}
} else {
DLOG(ERROR) << "Failed to get CVImageBufferRef gamma level.";
}
}
// Read the RGB to YUV matrix ID.
gfx::ColorSpace::MatrixID matrix_id = GetDefaultMatrixID(primary_id);
struct {
const CFStringRef cfstr;
gfx::ColorSpace::MatrixID id;
} matrices[] = {{
kCVImageBufferYCbCrMatrix_ITU_R_709_2,
gfx::ColorSpace::MatrixID::BT709,
},
{
kCVImageBufferYCbCrMatrix_ITU_R_601_4,
gfx::ColorSpace::MatrixID::SMPTE170M,
},
{
kCVImageBufferYCbCrMatrix_SMPTE_240M_1995,
gfx::ColorSpace::MatrixID::SMPTE240M,
}};
if (!GetImageBufferProperty(image_buffer, kCVImageBufferYCbCrMatrixKey,
matrices, base::size(matrices), &matrix_id)) {
DLOG(ERROR) << "Failed to find CVImageBufferRef YUV matrix.";
}
// It is specified to the decoder to use luma=[16,235] chroma=[16,240] via
// the kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange.
gfx::ColorSpace::RangeID range_id = gfx::ColorSpace::RangeID::LIMITED;
if (transfer_id == gfx::ColorSpace::TransferID::CUSTOM) {
return gfx::ColorSpace(primary_id, gfx::ColorSpace::TransferID::CUSTOM,
matrix_id, range_id, nullptr, &custom_tr_fn);
}
return gfx::ColorSpace(primary_id, transfer_id, matrix_id, range_id);
}
} // namespace } // namespace
bool InitializeVideoToolbox() { bool InitializeVideoToolbox() {
...@@ -615,6 +472,7 @@ bool VTVideoDecodeAccelerator::Initialize(const Config& config, ...@@ -615,6 +472,7 @@ bool VTVideoDecodeAccelerator::Initialize(const Config& config,
client_ = client; client_ = client;
// Spawn a thread to handle parsing and calling VideoToolbox. // Spawn a thread to handle parsing and calling VideoToolbox.
// TODO(sandersd): This should probably use a base::ThreadPool thread instead.
if (!decoder_thread_.Start()) { if (!decoder_thread_.Start()) {
DLOG(ERROR) << "Failed to start decoder thread"; DLOG(ERROR) << "Failed to start decoder thread";
return false; return false;
......
...@@ -447,6 +447,7 @@ CARendererLayerTree::ContentLayer::ContentLayer( ...@@ -447,6 +447,7 @@ CARendererLayerTree::ContentLayer::ContentLayer(
if (has_hdr_color_space) if (has_hdr_color_space)
type = CALayerType::kHDRCopier; type = CALayerType::kHDRCopier;
break; break;
// TODO(crbug.com/1103432): We'll likely need YpCbCr10 here for HDR.
case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange: case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
// Only allow 4:2:0 frames which fill the layer's contents to be // Only allow 4:2:0 frames which fill the layer's contents to be
// promoted to AV layers. // promoted to AV layers.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment