Commit 21f6ccca authored by Dale Curtis's avatar Dale Curtis Committed by Commit Bot

Reland #2: "Add support for creating VP9 format extensions for VTVDA."

Creates a vpcc box based on the configuration info. Reland now uses
a forward declaration for the kCMVideoCodecType_VP9 which is in the
11.0/10.16 SDK.

This version doesn't use MAC_OS_X_VERSION_MAX_ALLOWED which isn't
currently setup correctly in the SDK.

Bug: 1103432, 1105187
Test: Updated unittests.
Change-Id: I2df8f77e910e23a673ed538e5e475901bc4524e4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2349915Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Commit-Queue: Dale Curtis <dalecurtis@chromium.org>
Commit-Queue: Avi Drissman <avi@chromium.org>
Auto-Submit: Dale Curtis <dalecurtis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#796988}
parent 4e421ad1
......@@ -8,8 +8,8 @@
#ifndef BASE_MAC_SDK_FORWARD_DECLARATIONS_H_
#define BASE_MAC_SDK_FORWARD_DECLARATIONS_H_
#import <AppKit/AppKit.h>
#include <AvailabilityMacros.h>
#include <AvailabilityVersions.h>
#include <os/availability.h>
// NOTE: If an #import is needed only for a newer SDK, it might be found below.
......@@ -64,7 +64,9 @@
//
// ----------------------------------------------------------------------------
// Chromium currently is building with the most recent SDK. WWDC is not far
// away, though....
#if !defined(MAC_OS_VERSION_11_0)
#include <CoreMedia/CoreMedia.h>
enum : CMVideoCodecType { kCMVideoCodecType_VP9 = 'vp09' };
#endif // MAC_OS_VERSION_11_0
#endif // BASE_MAC_SDK_FORWARD_DECLARATIONS_H_
......@@ -415,6 +415,49 @@ gfx::ColorSpace::MatrixID GetImageBufferMatrix(CVImageBufferRef image_buffer) {
return matrix_id;
}
void SetVp9CodecConfigurationBox(
media::VideoCodecProfile codec_profile,
const media::VideoColorSpace& color_space,
NSMutableDictionary<NSString*, id>* extensions) {
// Synthesize a 'vpcC' box. See
// https://www.webmproject.org/vp9/mp4/#vp-codec-configuration-box.
uint8_t version = 1;
uint8_t profile = 0;
uint8_t level = 51;
uint8_t bit_depth = 8;
uint8_t chroma_subsampling = 1; // 4:2:0 colocated with luma (0, 0).
uint8_t primaries = 1; // BT.709.
uint8_t transfer = 1; // BT.709.
uint8_t matrix = 1; // BT.709.
if (color_space.IsSpecified()) {
primaries = static_cast<uint8_t>(color_space.primaries);
transfer = static_cast<uint8_t>(color_space.transfer);
matrix = static_cast<uint8_t>(color_space.matrix);
}
if (codec_profile == media::VP9PROFILE_PROFILE2) {
profile = 2;
bit_depth = 10;
}
uint8_t vpcc[12] = {0};
vpcc[0] = version;
vpcc[4] = profile;
vpcc[5] = level;
vpcc[6] |= bit_depth << 4;
vpcc[6] |= chroma_subsampling << 1;
vpcc[7] = primaries;
vpcc[8] = transfer;
vpcc[9] = matrix;
SetDictionaryValue(
extensions, kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms,
@{
@"vpcC" : [NSData dataWithBytes:&vpcc length:sizeof(vpcc)],
});
SetDictionaryValue(extensions, CFSTR("BitsPerComponent"), @(bit_depth));
}
} // namespace
namespace media {
......@@ -460,6 +503,9 @@ CFMutableDictionaryRef CreateFormatExtensions(
SetMasteringMetadata(*hdr_metadata, extensions);
}
if (profile >= VP9PROFILE_MIN && profile <= VP9PROFILE_MAX)
SetVp9CodecConfigurationBox(profile, color_space, extensions);
return base::mac::NSToCFCast(extensions);
}
......
......@@ -4,38 +4,40 @@
#include "media/gpu/mac/vt_config_util.h"
#include <CoreMedia/CoreMedia.h>
#include "base/containers/span.h"
#include "base/mac/foundation_util.h"
#include "base/mac/mac_util.h"
#include "base/mac/sdk_forward_declarations.h"
#include "base/strings/sys_string_conversions.h"
#include "media/formats/mp4/box_definitions.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
std::string GetStrValue(CFMutableDictionaryRef dict, CFStringRef key) {
std::string GetStrValue(CFDictionaryRef dict, CFStringRef key) {
return base::SysCFStringRefToUTF8(
base::mac::CFCastStrict<CFStringRef>(CFDictionaryGetValue(dict, key)));
}
CFStringRef GetCFStrValue(CFMutableDictionaryRef dict, CFStringRef key) {
CFStringRef GetCFStrValue(CFDictionaryRef dict, CFStringRef key) {
return base::mac::CFCastStrict<CFStringRef>(CFDictionaryGetValue(dict, key));
}
int GetIntValue(CFMutableDictionaryRef dict, CFStringRef key) {
int GetIntValue(CFDictionaryRef dict, CFStringRef key) {
CFNumberRef value =
base::mac::CFCastStrict<CFNumberRef>(CFDictionaryGetValue(dict, key));
int result;
return CFNumberGetValue(value, kCFNumberIntType, &result) ? result : -1;
}
bool GetBoolValue(CFMutableDictionaryRef dict, CFStringRef key) {
bool GetBoolValue(CFDictionaryRef dict, CFStringRef key) {
return CFBooleanGetValue(
base::mac::CFCastStrict<CFBooleanRef>(CFDictionaryGetValue(dict, key)));
}
base::span<const uint8_t> GetDataValue(CFMutableDictionaryRef dict,
CFStringRef key) {
base::span<const uint8_t> GetDataValue(CFDictionaryRef dict, CFStringRef key) {
CFDataRef data =
base::mac::CFCastStrict<CFDataRef>(CFDictionaryGetValue(dict, key));
return data ? base::span<const uint8_t>(
......@@ -44,9 +46,17 @@ base::span<const uint8_t> GetDataValue(CFMutableDictionaryRef dict,
: base::span<const uint8_t>();
}
base::span<const uint8_t> GetNestedDataValue(CFDictionaryRef dict,
CFStringRef key1,
CFStringRef key2) {
CFDictionaryRef nested_dict = base::mac::CFCastStrict<CFDictionaryRef>(
CFDictionaryGetValue(dict, key1));
return GetDataValue(nested_dict, key2);
}
base::ScopedCFTypeRef<CVImageBufferRef> CreateCVImageBuffer(
media::VideoColorSpace cs) {
base::ScopedCFTypeRef<CFMutableDictionaryRef> fmt(
base::ScopedCFTypeRef<CFDictionaryRef> fmt(
CreateFormatExtensions(kCMVideoCodecType_H264, media::H264PROFILE_MAIN,
cs, media::HDRMetadata()));
......@@ -71,7 +81,7 @@ gfx::ColorSpace ToBT709_APPLE(gfx::ColorSpace cs) {
cs.GetMatrixID(), cs.GetRangeID());
}
void AssertHasEmptyHDRMetadata(CFMutableDictionaryRef fmt) {
void AssertHasEmptyHDRMetadata(CFDictionaryRef fmt) {
if (__builtin_available(macos 10.13, *)) {
// We constructed with an empty HDRMetadata, so all values should be zero.
auto mdcv = GetDataValue(
......@@ -88,12 +98,15 @@ void AssertHasEmptyHDRMetadata(CFMutableDictionaryRef fmt) {
}
}
constexpr char kBitDepthKey[] = "BitsPerComponent";
constexpr char kVpccKey[] = "vpcC";
} // namespace
namespace media {
TEST(VTConfigUtil, CreateFormatExtensions_H264_BT709) {
base::ScopedCFTypeRef<CFMutableDictionaryRef> fmt(
base::ScopedCFTypeRef<CFDictionaryRef> fmt(
CreateFormatExtensions(kCMVideoCodecType_H264, H264PROFILE_MAIN,
VideoColorSpace::REC709(), base::nullopt));
EXPECT_EQ("avc1", GetStrValue(fmt, kCMFormatDescriptionExtension_FormatName));
......@@ -118,7 +131,7 @@ TEST(VTConfigUtil, CreateFormatExtensions_H264_BT709) {
}
TEST(VTConfigUtil, CreateFormatExtensions_H264_BT2020_PQ) {
base::ScopedCFTypeRef<CFMutableDictionaryRef> fmt(CreateFormatExtensions(
base::ScopedCFTypeRef<CFDictionaryRef> fmt(CreateFormatExtensions(
kCMVideoCodecType_H264, H264PROFILE_MAIN,
VideoColorSpace(VideoColorSpace::PrimaryID::BT2020,
VideoColorSpace::TransferID::SMPTEST2084,
......@@ -142,7 +155,7 @@ TEST(VTConfigUtil, CreateFormatExtensions_H264_BT2020_PQ) {
}
TEST(VTConfigUtil, CreateFormatExtensions_H264_BT2020_HLG) {
base::ScopedCFTypeRef<CFMutableDictionaryRef> fmt(CreateFormatExtensions(
base::ScopedCFTypeRef<CFDictionaryRef> fmt(CreateFormatExtensions(
kCMVideoCodecType_H264, H264PROFILE_MAIN,
VideoColorSpace(VideoColorSpace::PrimaryID::BT2020,
VideoColorSpace::TransferID::ARIB_STD_B67,
......@@ -178,7 +191,7 @@ TEST(VTConfigUtil, CreateFormatExtensions_HDRMetadata) {
mastering.primary_b = gfx::PointF(0.15, 0.06);
mastering.white_point = gfx::PointF(0.3127, 0.3290);
base::ScopedCFTypeRef<CFMutableDictionaryRef> fmt(CreateFormatExtensions(
base::ScopedCFTypeRef<CFDictionaryRef> fmt(CreateFormatExtensions(
kCMVideoCodecType_H264, H264PROFILE_MAIN,
VideoColorSpace(VideoColorSpace::PrimaryID::BT2020,
VideoColorSpace::TransferID::SMPTEST2084,
......@@ -226,6 +239,47 @@ TEST(VTConfigUtil, CreateFormatExtensions_HDRMetadata) {
}
}
TEST(VTConfigUtil, CreateFormatExtensions_VP9Profile0) {
constexpr VideoCodecProfile kTestProfile = VP9PROFILE_PROFILE0;
const auto kTestColorSpace = VideoColorSpace::REC709();
base::ScopedCFTypeRef<CFDictionaryRef> fmt(CreateFormatExtensions(
kCMVideoCodecType_VP9, kTestProfile, kTestColorSpace, base::nullopt));
EXPECT_EQ(8, GetIntValue(fmt, base::SysUTF8ToCFStringRef(kBitDepthKey)));
auto vpcc = GetNestedDataValue(
fmt, kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms,
base::SysUTF8ToCFStringRef(kVpccKey));
std::unique_ptr<mp4::BoxReader> box_reader(
mp4::BoxReader::ReadConcatentatedBoxes(vpcc.data(), vpcc.size(),
nullptr));
mp4::VPCodecConfigurationRecord vpcc_box;
ASSERT_TRUE(vpcc_box.Parse(box_reader.get()));
ASSERT_EQ(kTestProfile, vpcc_box.profile);
ASSERT_EQ(kTestColorSpace, vpcc_box.color_space);
}
TEST(VTConfigUtil, CreateFormatExtensions_VP9Profile2) {
constexpr VideoCodecProfile kTestProfile = VP9PROFILE_PROFILE2;
const VideoColorSpace kTestColorSpace(
VideoColorSpace::PrimaryID::BT2020,
VideoColorSpace::TransferID::SMPTEST2084,
VideoColorSpace::MatrixID::BT2020_NCL, gfx::ColorSpace::RangeID::LIMITED);
base::ScopedCFTypeRef<CFDictionaryRef> fmt(CreateFormatExtensions(
kCMVideoCodecType_VP9, kTestProfile, kTestColorSpace, base::nullopt));
EXPECT_EQ(10, GetIntValue(fmt, base::SysUTF8ToCFStringRef(kBitDepthKey)));
auto vpcc = GetNestedDataValue(
fmt, kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms,
base::SysUTF8ToCFStringRef(kVpccKey));
std::unique_ptr<mp4::BoxReader> box_reader(
mp4::BoxReader::ReadConcatentatedBoxes(vpcc.data(), vpcc.size(),
nullptr));
mp4::VPCodecConfigurationRecord vpcc_box;
ASSERT_TRUE(vpcc_box.Parse(box_reader.get()));
ASSERT_EQ(kTestProfile, vpcc_box.profile);
ASSERT_EQ(kTestColorSpace, vpcc_box.color_space);
}
TEST(VTConfigUtil, GetImageBufferColorSpace_BT601) {
auto cs = VideoColorSpace::REC601();
auto image_buffer = CreateCVImageBuffer(cs);
......
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