Commit 6c5fa707 authored by Christopher Cameron's avatar Christopher Cameron Committed by Commit Bot

Add media::GetFormatDescriptionColorSpace

This function is nearly identical to media::GetImageBufferColorSpace,
but instead operates on a CMFormatDescriptionRef.

Add DCHECKs that the behavior of the two functions be the same, that is,
the kCVImageBuffer-prefixed and  kCMFormatDescription-prefixed
constants be equal.

Use base::mac::CFCast instead of reinterpret_casts.

The next patch in this sequence will move these two functions over
to media/base/mac, because it will be accessed in capture.

Bug: 959962
Change-Id: I8a4d8468abc866a13cb6181cbd49d9ee04288124
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2436513
Commit-Queue: ccameron <ccameron@chromium.org>
Reviewed-by: default avatarDale Curtis <dalecurtis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#811829}
parent 76a5b766
...@@ -26,6 +26,9 @@ CreateFormatExtensions(CMVideoCodecType codec_type, ...@@ -26,6 +26,9 @@ CreateFormatExtensions(CMVideoCodecType codec_type,
MEDIA_GPU_EXPORT gfx::ColorSpace GetImageBufferColorSpace( MEDIA_GPU_EXPORT gfx::ColorSpace GetImageBufferColorSpace(
CVImageBufferRef image_buffer); CVImageBufferRef image_buffer);
MEDIA_GPU_EXPORT gfx::ColorSpace GetFormatDescriptionColorSpace(
CMFormatDescriptionRef format_description);
} // namespace media } // namespace media
#endif // MEDIA_GPU_MAC_VT_CONFIG_UTIL_H_ #endif // MEDIA_GPU_MAC_VT_CONFIG_UTIL_H_
...@@ -253,17 +253,17 @@ void SetMasteringMetadata(const gl::HDRMetadata& hdr_metadata, ...@@ -253,17 +253,17 @@ void SetMasteringMetadata(const gl::HDRMetadata& hdr_metadata,
// Use the list of pairs in |cfstr_id_pairs| to do the conversion (by doing a // Use the list of pairs in |cfstr_id_pairs| to do the conversion (by doing a
// linear lookup). // linear lookup).
template <typename IdType, typename StringIdPair> template <typename IdType, typename StringIdPair>
bool GetImageBufferProperty(CVImageBufferRef image_buffer, bool GetImageBufferProperty(CFTypeRef value_untyped,
CFStringRef key,
const std::vector<StringIdPair>& cfstr_id_pairs, const std::vector<StringIdPair>& cfstr_id_pairs,
IdType* value_as_id) { IdType* value_as_id) {
CFStringRef value_as_string = reinterpret_cast<CFStringRef>( CFStringRef value_as_string = base::mac::CFCast<CFStringRef>(value_untyped);
CVBufferGetAttachment(image_buffer, key, nullptr));
if (!value_as_string) if (!value_as_string)
return false; return false;
for (const auto& p : cfstr_id_pairs) { for (const auto& p : cfstr_id_pairs) {
if (!CFStringCompare(value_as_string, p.cfstr, 0)) { if (p.cfstr_cm)
DCHECK(!CFStringCompare(p.cfstr_cv, p.cfstr_cm, 0));
if (!CFStringCompare(value_as_string, p.cfstr_cv, 0)) {
*value_as_id = p.id; *value_as_id = p.id;
return true; return true;
} }
...@@ -272,24 +272,32 @@ bool GetImageBufferProperty(CVImageBufferRef image_buffer, ...@@ -272,24 +272,32 @@ bool GetImageBufferProperty(CVImageBufferRef image_buffer,
return false; return false;
} }
gfx::ColorSpace::PrimaryID GetImageBufferPrimary( gfx::ColorSpace::PrimaryID GetCoreVideoPrimary(CFTypeRef primaries_untyped) {
CVImageBufferRef image_buffer) {
struct CVImagePrimary { struct CVImagePrimary {
const CFStringRef cfstr; const CFStringRef cfstr_cv;
const CFStringRef cfstr_cm;
const gfx::ColorSpace::PrimaryID id; const gfx::ColorSpace::PrimaryID id;
}; };
static const base::NoDestructor<std::vector<CVImagePrimary>> static const base::NoDestructor<std::vector<CVImagePrimary>>
kSupportedPrimaries([] { kSupportedPrimaries([] {
std::vector<CVImagePrimary> supported_primaries; std::vector<CVImagePrimary> supported_primaries;
supported_primaries.push_back({kCVImageBufferColorPrimaries_ITU_R_709_2, supported_primaries.push_back(
{kCVImageBufferColorPrimaries_ITU_R_709_2,
kCMFormatDescriptionColorPrimaries_ITU_R_709_2,
gfx::ColorSpace::PrimaryID::BT709}); gfx::ColorSpace::PrimaryID::BT709});
supported_primaries.push_back({kCVImageBufferColorPrimaries_EBU_3213, supported_primaries.push_back(
{kCVImageBufferColorPrimaries_EBU_3213,
kCMFormatDescriptionColorPrimaries_EBU_3213,
gfx::ColorSpace::PrimaryID::BT470BG}); gfx::ColorSpace::PrimaryID::BT470BG});
supported_primaries.push_back({kCVImageBufferColorPrimaries_SMPTE_C, supported_primaries.push_back(
{kCVImageBufferColorPrimaries_SMPTE_C,
kCMFormatDescriptionColorPrimaries_SMPTE_C,
gfx::ColorSpace::PrimaryID::SMPTE240M}); gfx::ColorSpace::PrimaryID::SMPTE240M});
if (@available(macos 10.11, *)) { if (@available(macos 10.11, *)) {
supported_primaries.push_back( supported_primaries.push_back(
{kCVImageBufferColorPrimaries_ITU_R_2020, {kCVImageBufferColorPrimaries_ITU_R_2020,
kCMFormatDescriptionColorPrimaries_ITU_R_2020,
gfx::ColorSpace::PrimaryID::BT2020}); gfx::ColorSpace::PrimaryID::BT2020});
} }
return supported_primaries; return supported_primaries;
...@@ -297,18 +305,19 @@ gfx::ColorSpace::PrimaryID GetImageBufferPrimary( ...@@ -297,18 +305,19 @@ gfx::ColorSpace::PrimaryID GetImageBufferPrimary(
// The named primaries. Default to BT709. // The named primaries. Default to BT709.
auto primary_id = gfx::ColorSpace::PrimaryID::BT709; auto primary_id = gfx::ColorSpace::PrimaryID::BT709;
if (!GetImageBufferProperty(image_buffer, kCVImageBufferColorPrimariesKey, if (!GetImageBufferProperty(primaries_untyped, *kSupportedPrimaries,
*kSupportedPrimaries, &primary_id)) { &primary_id)) {
DLOG(ERROR) << "Failed to find CVImageBufferRef primaries."; DLOG(ERROR) << "Failed to find CVImageBufferRef primaries.";
} }
return primary_id; return primary_id;
} }
gfx::ColorSpace::TransferID GetImageBufferTransferFn( gfx::ColorSpace::TransferID GetCoreVideoTransferFn(CFTypeRef transfer_untyped,
CVImageBufferRef image_buffer, CFTypeRef gamma_untyped,
double* gamma) { double* gamma) {
struct CVImageTransferFn { struct CVImageTransferFn {
const CFStringRef cfstr; const CFStringRef cfstr_cv;
const CFStringRef cfstr_cm;
const gfx::ColorSpace::TransferID id; const gfx::ColorSpace::TransferID id;
}; };
static const base::NoDestructor<std::vector<CVImageTransferFn>> static const base::NoDestructor<std::vector<CVImageTransferFn>>
...@@ -316,47 +325,61 @@ gfx::ColorSpace::TransferID GetImageBufferTransferFn( ...@@ -316,47 +325,61 @@ gfx::ColorSpace::TransferID GetImageBufferTransferFn(
std::vector<CVImageTransferFn> supported_transfer_funcs; std::vector<CVImageTransferFn> supported_transfer_funcs;
supported_transfer_funcs.push_back( supported_transfer_funcs.push_back(
{kCVImageBufferTransferFunction_ITU_R_709_2, {kCVImageBufferTransferFunction_ITU_R_709_2,
kCMFormatDescriptionTransferFunction_ITU_R_709_2,
gfx::ColorSpace::TransferID::BT709_APPLE}); gfx::ColorSpace::TransferID::BT709_APPLE});
supported_transfer_funcs.push_back( supported_transfer_funcs.push_back(
{kCVImageBufferTransferFunction_SMPTE_240M_1995, {kCVImageBufferTransferFunction_SMPTE_240M_1995,
kCMFormatDescriptionTransferFunction_SMPTE_240M_1995,
gfx::ColorSpace::TransferID::SMPTE240M}); gfx::ColorSpace::TransferID::SMPTE240M});
supported_transfer_funcs.push_back( supported_transfer_funcs.push_back(
{kCVImageBufferTransferFunction_UseGamma, {kCVImageBufferTransferFunction_UseGamma,
kCMFormatDescriptionTransferFunction_UseGamma,
gfx::ColorSpace::TransferID::CUSTOM}); gfx::ColorSpace::TransferID::CUSTOM});
if (@available(macos 10.11, *)) { if (@available(macos 10.11, *)) {
supported_transfer_funcs.push_back( supported_transfer_funcs.push_back(
{kCVImageBufferTransferFunction_ITU_R_2020, {kCVImageBufferTransferFunction_ITU_R_2020,
kCMFormatDescriptionTransferFunction_ITU_R_2020,
gfx::ColorSpace::TransferID::BT2020_10}); gfx::ColorSpace::TransferID::BT2020_10});
} }
if (@available(macos 10.12, *)) { if (@available(macos 10.12, *)) {
supported_transfer_funcs.push_back( supported_transfer_funcs.push_back(
{kCVImageBufferTransferFunction_SMPTE_ST_428_1, {kCVImageBufferTransferFunction_SMPTE_ST_428_1,
kCMFormatDescriptionTransferFunction_SMPTE_ST_428_1,
gfx::ColorSpace::TransferID::SMPTEST428_1}); gfx::ColorSpace::TransferID::SMPTEST428_1});
} }
if (@available(macos 10.13, *)) { if (@available(macos 10.13, *)) {
supported_transfer_funcs.push_back( supported_transfer_funcs.push_back(
{kCVImageBufferTransferFunction_SMPTE_ST_2084_PQ, {kCVImageBufferTransferFunction_SMPTE_ST_2084_PQ,
kCMFormatDescriptionTransferFunction_SMPTE_ST_2084_PQ,
gfx::ColorSpace::TransferID::SMPTEST2084}); gfx::ColorSpace::TransferID::SMPTEST2084});
supported_transfer_funcs.push_back( supported_transfer_funcs.push_back(
{kCVImageBufferTransferFunction_ITU_R_2100_HLG, {kCVImageBufferTransferFunction_ITU_R_2100_HLG,
kCMFormatDescriptionTransferFunction_ITU_R_2100_HLG,
gfx::ColorSpace::TransferID::ARIB_STD_B67}); gfx::ColorSpace::TransferID::ARIB_STD_B67});
supported_transfer_funcs.push_back( supported_transfer_funcs.push_back(
{kCVImageBufferTransferFunction_sRGB, {kCVImageBufferTransferFunction_sRGB, nullptr,
gfx::ColorSpace::TransferID::IEC61966_2_1}); gfx::ColorSpace::TransferID::IEC61966_2_1});
} }
if (@available(macos 10.14, *)) { if (@available(macos 10.14, *)) {
supported_transfer_funcs.push_back( supported_transfer_funcs.push_back(
{kCVImageBufferTransferFunction_Linear, {kCVImageBufferTransferFunction_Linear,
kCMFormatDescriptionTransferFunction_Linear,
gfx::ColorSpace::TransferID::LINEAR}); gfx::ColorSpace::TransferID::LINEAR});
} }
if (@available(macos 10.15, *)) {
supported_transfer_funcs.push_back(
{kCVImageBufferTransferFunction_sRGB,
kCMFormatDescriptionTransferFunction_sRGB,
gfx::ColorSpace::TransferID::IEC61966_2_1});
}
return supported_transfer_funcs; return supported_transfer_funcs;
}()); }());
// The named transfer function. // The named transfer function.
auto transfer_id = gfx::ColorSpace::TransferID::BT709; auto transfer_id = gfx::ColorSpace::TransferID::BT709;
if (!GetImageBufferProperty(image_buffer, kCVImageBufferTransferFunctionKey, if (!GetImageBufferProperty(transfer_untyped, *kSupportedTransferFuncs,
*kSupportedTransferFuncs, &transfer_id)) { &transfer_id)) {
DLOG(ERROR) << "Failed to find CVImageBufferRef transfer."; DLOG(ERROR) << "Failed to find CVImageBufferRef transfer.";
} }
...@@ -365,11 +388,9 @@ gfx::ColorSpace::TransferID GetImageBufferTransferFn( ...@@ -365,11 +388,9 @@ gfx::ColorSpace::TransferID GetImageBufferTransferFn(
// If we fail to retrieve the gamma parameter, fall back to BT709. // If we fail to retrieve the gamma parameter, fall back to BT709.
constexpr auto kDefaultTransferFn = gfx::ColorSpace::TransferID::BT709; constexpr auto kDefaultTransferFn = gfx::ColorSpace::TransferID::BT709;
CFNumberRef gamma_number = CFNumberRef gamma_number = base::mac::CFCast<CFNumberRef>(gamma_untyped);
reinterpret_cast<CFNumberRef>(CVBufferGetAttachment(
image_buffer, kCVImageBufferGammaLevelKey, nullptr));
if (!gamma_number) { if (!gamma_number) {
DLOG(ERROR) << "Failed to get CVImageBufferRef gamma level."; DLOG(ERROR) << "Failed to get gamma level.";
return kDefaultTransferFn; return kDefaultTransferFn;
} }
...@@ -389,30 +410,39 @@ gfx::ColorSpace::TransferID GetImageBufferTransferFn( ...@@ -389,30 +410,39 @@ gfx::ColorSpace::TransferID GetImageBufferTransferFn(
return transfer_id; return transfer_id;
} }
gfx::ColorSpace::MatrixID GetImageBufferMatrix(CVImageBufferRef image_buffer) { gfx::ColorSpace::MatrixID GetCoreVideoMatrix(CFTypeRef matrix_untyped) {
struct CVImageMatrix { struct CVImageMatrix {
const CFStringRef cfstr; const CFStringRef cfstr_cv;
const CFStringRef cfstr_cm;
gfx::ColorSpace::MatrixID id; gfx::ColorSpace::MatrixID id;
}; };
static const base::NoDestructor<std::vector<CVImageMatrix>> static const base::NoDestructor<std::vector<CVImageMatrix>>
kSupportedMatrices([] { kSupportedMatrices([] {
std::vector<CVImageMatrix> supported_matrices; std::vector<CVImageMatrix> supported_matrices;
supported_matrices.push_back({kCVImageBufferYCbCrMatrix_ITU_R_709_2, supported_matrices.push_back(
{kCVImageBufferYCbCrMatrix_ITU_R_709_2,
kCMFormatDescriptionYCbCrMatrix_ITU_R_709_2,
gfx::ColorSpace::MatrixID::BT709}); gfx::ColorSpace::MatrixID::BT709});
supported_matrices.push_back({kCVImageBufferYCbCrMatrix_ITU_R_601_4, supported_matrices.push_back(
{kCVImageBufferYCbCrMatrix_ITU_R_601_4,
kCMFormatDescriptionYCbCrMatrix_ITU_R_601_4,
gfx::ColorSpace::MatrixID::SMPTE170M}); gfx::ColorSpace::MatrixID::SMPTE170M});
supported_matrices.push_back({kCVImageBufferYCbCrMatrix_SMPTE_240M_1995, supported_matrices.push_back(
{kCVImageBufferYCbCrMatrix_SMPTE_240M_1995,
kCMFormatDescriptionYCbCrMatrix_SMPTE_240M_1995,
gfx::ColorSpace::MatrixID::SMPTE240M}); gfx::ColorSpace::MatrixID::SMPTE240M});
if (@available(macos 10.11, *)) { if (@available(macos 10.11, *)) {
supported_matrices.push_back({kCVImageBufferYCbCrMatrix_ITU_R_2020, supported_matrices.push_back(
{kCVImageBufferYCbCrMatrix_ITU_R_2020,
kCMFormatDescriptionYCbCrMatrix_ITU_R_2020,
gfx::ColorSpace::MatrixID::BT2020_NCL}); gfx::ColorSpace::MatrixID::BT2020_NCL});
} }
return supported_matrices; return supported_matrices;
}()); }());
auto matrix_id = gfx::ColorSpace::MatrixID::INVALID; auto matrix_id = gfx::ColorSpace::MatrixID::INVALID;
if (!GetImageBufferProperty(image_buffer, kCVImageBufferYCbCrMatrixKey, if (!GetImageBufferProperty(matrix_untyped, *kSupportedMatrices,
*kSupportedMatrices, &matrix_id)) { &matrix_id)) {
DLOG(ERROR) << "Failed to find CVImageBufferRef YUV matrix."; DLOG(ERROR) << "Failed to find CVImageBufferRef YUV matrix.";
} }
return matrix_id; return matrix_id;
...@@ -512,11 +542,17 @@ CFMutableDictionaryRef CreateFormatExtensions( ...@@ -512,11 +542,17 @@ CFMutableDictionaryRef CreateFormatExtensions(
return base::mac::NSToCFCast(extensions); return base::mac::NSToCFCast(extensions);
} }
gfx::ColorSpace GetImageBufferColorSpace(CVImageBufferRef image_buffer) { namespace {
gfx::ColorSpace GetCoreVideoColorSpaceInternal(CFTypeRef primaries_untyped,
CFTypeRef transfer_untyped,
CFTypeRef gamma_untyped,
CFTypeRef matrix_untyped) {
double gamma; double gamma;
auto primary_id = GetImageBufferPrimary(image_buffer); auto primary_id = GetCoreVideoPrimary(primaries_untyped);
auto matrix_id = GetImageBufferMatrix(image_buffer); auto matrix_id = GetCoreVideoMatrix(matrix_untyped);
auto transfer_id = GetImageBufferTransferFn(image_buffer, &gamma); auto transfer_id =
GetCoreVideoTransferFn(transfer_untyped, gamma_untyped, &gamma);
// Use a matrix id that is coherent with a primary id. Useful when we fail to // 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 // parse the matrix. Previously it was always defaulting to MatrixID::BT709
...@@ -548,4 +584,30 @@ gfx::ColorSpace GetImageBufferColorSpace(CVImageBufferRef image_buffer) { ...@@ -548,4 +584,30 @@ gfx::ColorSpace GetImageBufferColorSpace(CVImageBufferRef image_buffer) {
return gfx::ColorSpace(primary_id, transfer_id, matrix_id, range_id); return gfx::ColorSpace(primary_id, transfer_id, matrix_id, range_id);
} }
} // anonymous namespace
gfx::ColorSpace GetImageBufferColorSpace(CVImageBufferRef image_buffer) {
return GetCoreVideoColorSpaceInternal(
CVBufferGetAttachment(image_buffer, kCVImageBufferColorPrimariesKey,
nullptr),
CVBufferGetAttachment(image_buffer, kCVImageBufferTransferFunctionKey,
nullptr),
CVBufferGetAttachment(image_buffer, kCVImageBufferGammaLevelKey, nullptr),
CVBufferGetAttachment(image_buffer, kCVImageBufferYCbCrMatrixKey,
nullptr));
}
gfx::ColorSpace GetFormatDescriptionColorSpace(
CMFormatDescriptionRef format_description) {
return GetCoreVideoColorSpaceInternal(
CMFormatDescriptionGetExtension(
format_description, kCMFormatDescriptionExtension_ColorPrimaries),
CMFormatDescriptionGetExtension(
format_description, kCMFormatDescriptionExtension_TransferFunction),
CMFormatDescriptionGetExtension(format_description,
kCMFormatDescriptionExtension_GammaLevel),
CMFormatDescriptionGetExtension(
format_description, kCMFormatDescriptionExtension_YCbCrMatrix));
}
} // namespace media } // namespace media
...@@ -74,6 +74,34 @@ base::ScopedCFTypeRef<CVImageBufferRef> CreateCVImageBuffer( ...@@ -74,6 +74,34 @@ base::ScopedCFTypeRef<CVImageBufferRef> CreateCVImageBuffer(
return image_buffer; return image_buffer;
} }
base::ScopedCFTypeRef<CMFormatDescriptionRef> CreateFormatDescription(
CFStringRef primaries,
CFStringRef transfer,
CFStringRef matrix) {
base::ScopedCFTypeRef<CFMutableDictionaryRef> extensions(
CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks));
if (primaries) {
CFDictionarySetValue(
extensions, kCMFormatDescriptionExtension_ColorPrimaries, primaries);
}
if (transfer) {
CFDictionarySetValue(
extensions, kCMFormatDescriptionExtension_TransferFunction, transfer);
}
if (matrix) {
CFDictionarySetValue(extensions, kCMFormatDescriptionExtension_YCbCrMatrix,
matrix);
}
base::ScopedCFTypeRef<CMFormatDescriptionRef> result;
CMFormatDescriptionCreate(nullptr, kCMMediaType_Video,
kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange,
extensions.get(), result.InitializeInto());
return result;
}
gfx::ColorSpace ToBT709_APPLE(gfx::ColorSpace cs) { gfx::ColorSpace ToBT709_APPLE(gfx::ColorSpace cs) {
return gfx::ColorSpace(cs.GetPrimaryID(), return gfx::ColorSpace(cs.GetPrimaryID(),
gfx::ColorSpace::TransferID::BT709_APPLE, gfx::ColorSpace::TransferID::BT709_APPLE,
...@@ -364,4 +392,22 @@ TEST(VTConfigUtil, GetImageBufferColorSpace_BT2020_HLG) { ...@@ -364,4 +392,22 @@ TEST(VTConfigUtil, GetImageBufferColorSpace_BT2020_HLG) {
} }
} }
TEST(VTConfigUtil, FormatDescriptionInvalid) {
auto format_descriptor =
CreateFormatDescription(CFSTR("Cows"), CFSTR("Go"), CFSTR("Moo"));
ASSERT_TRUE(format_descriptor);
auto cs = GetFormatDescriptionColorSpace(format_descriptor);
EXPECT_EQ(gfx::ColorSpace::CreateREC709(), cs);
}
TEST(VTConfigUtil, FormatDescriptionBT709) {
auto format_descriptor =
CreateFormatDescription(kCMFormatDescriptionColorPrimaries_ITU_R_709_2,
kCMFormatDescriptionTransferFunction_ITU_R_709_2,
kCMFormatDescriptionYCbCrMatrix_ITU_R_709_2);
ASSERT_TRUE(format_descriptor);
auto cs = GetFormatDescriptionColorSpace(format_descriptor);
EXPECT_EQ(ToBT709_APPLE(gfx::ColorSpace::CreateREC709()), cs);
}
} // namespace media } // namespace media
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