Avi Drissman | 3e1a26c | 2022-09-15 20:26:03 | [diff] [blame] | 1 | // Copyright 2022 The Chromium Authors |
Christopher Cameron | b6914526 | 2022-09-13 17:06:39 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Elly Fong-Jones | a8ea66f1 | 2024-07-24 18:37:10 | [diff] [blame] | 5 | #ifdef UNSAFE_BUFFERS_BUILD |
| 6 | // TODO(crbug.com/354829279): Remove this and convert code to safer constructs. |
| 7 | #pragma allow_unsafe_buffers |
| 8 | #endif |
| 9 | |
Christopher Cameron | b6914526 | 2022-09-13 17:06:39 | [diff] [blame] | 10 | #include "ui/gfx/hdr_metadata_mac.h" |
| 11 | #include "ui/gfx/hdr_metadata.h" |
| 12 | |
| 13 | #include <simd/simd.h> |
| 14 | |
| 15 | namespace gfx { |
| 16 | |
Avi Drissman | 28154a6 | 2023-08-22 04:06:45 | [diff] [blame] | 17 | base::apple::ScopedCFTypeRef<CFDataRef> GenerateContentLightLevelInfo( |
Arthur Sonzogni | 3eb9fd51 | 2024-02-09 12:20:43 | [diff] [blame] | 18 | const std::optional<gfx::HDRMetadata>& hdr_metadata) { |
Christopher Cameron | 52f82ba0 | 2023-06-08 19:06:04 | [diff] [blame] | 19 | if (!hdr_metadata || !hdr_metadata->cta_861_3 || |
| 20 | hdr_metadata->cta_861_3->max_content_light_level == 0.f || |
| 21 | hdr_metadata->cta_861_3->max_frame_average_light_level == 0.f) { |
Avi Drissman | 28154a6 | 2023-08-22 04:06:45 | [diff] [blame] | 22 | return base::apple::ScopedCFTypeRef<CFDataRef>(); |
Christopher Cameron | e08ac3e3 | 2022-10-19 11:37:46 | [diff] [blame] | 23 | } |
| 24 | |
Christopher Cameron | b6914526 | 2022-09-13 17:06:39 | [diff] [blame] | 25 | // This is a SMPTEST2086 Content Light Level Information box. |
| 26 | struct ContentLightLevelInfoSEI { |
| 27 | uint16_t max_content_light_level; |
| 28 | uint16_t max_frame_average_light_level; |
| 29 | } __attribute__((packed, aligned(2))); |
| 30 | static_assert(sizeof(ContentLightLevelInfoSEI) == 4, "Must be 4 bytes"); |
| 31 | |
| 32 | // Values are stored in big-endian... |
| 33 | ContentLightLevelInfoSEI sei; |
| 34 | sei.max_content_light_level = |
Christopher Cameron | 52f82ba0 | 2023-06-08 19:06:04 | [diff] [blame] | 35 | __builtin_bswap16(hdr_metadata->cta_861_3->max_content_light_level); |
Christopher Cameron | b6914526 | 2022-09-13 17:06:39 | [diff] [blame] | 36 | sei.max_frame_average_light_level = |
Christopher Cameron | 52f82ba0 | 2023-06-08 19:06:04 | [diff] [blame] | 37 | __builtin_bswap16(hdr_metadata->cta_861_3->max_frame_average_light_level); |
Christopher Cameron | b6914526 | 2022-09-13 17:06:39 | [diff] [blame] | 38 | |
Avi Drissman | 28154a6 | 2023-08-22 04:06:45 | [diff] [blame] | 39 | return base::apple::ScopedCFTypeRef<CFDataRef>( |
Christopher Cameron | b6914526 | 2022-09-13 17:06:39 | [diff] [blame] | 40 | CFDataCreate(nullptr, reinterpret_cast<const UInt8*>(&sei), 4)); |
| 41 | } |
| 42 | |
Avi Drissman | 28154a6 | 2023-08-22 04:06:45 | [diff] [blame] | 43 | base::apple::ScopedCFTypeRef<CFDataRef> GenerateMasteringDisplayColorVolume( |
Arthur Sonzogni | 3eb9fd51 | 2024-02-09 12:20:43 | [diff] [blame] | 44 | const std::optional<gfx::HDRMetadata>& hdr_metadata) { |
Christopher Cameron | b6914526 | 2022-09-13 17:06:39 | [diff] [blame] | 45 | // This is a SMPTEST2086 Mastering Display Color Volume box. |
| 46 | struct MasteringDisplayColorVolumeSEI { |
| 47 | vector_ushort2 primaries[3]; // GBR |
| 48 | vector_ushort2 white_point; |
| 49 | uint32_t luminance_max; |
| 50 | uint32_t luminance_min; |
| 51 | } __attribute__((packed, aligned(4))); |
| 52 | static_assert(sizeof(MasteringDisplayColorVolumeSEI) == 24, |
| 53 | "Must be 24 bytes"); |
| 54 | |
Christopher Cameron | e08ac3e3 | 2022-10-19 11:37:46 | [diff] [blame] | 55 | // Make a copy with all values populated, and which we can manipulate. |
Christopher Cameron | ef71a52a | 2023-05-18 15:30:18 | [diff] [blame] | 56 | auto md = |
| 57 | HDRMetadata::PopulateUnspecifiedWithDefaults(hdr_metadata).smpte_st_2086; |
Christopher Cameron | b6914526 | 2022-09-13 17:06:39 | [diff] [blame] | 58 | |
| 59 | constexpr float kColorCoordinateUpperBound = 50000.0f; |
Christopher Cameron | b6914526 | 2022-09-13 17:06:39 | [diff] [blame] | 60 | constexpr float kUnitOfMasteringLuminance = 10000.0f; |
Christopher Cameron | 52f82ba0 | 2023-06-08 19:06:04 | [diff] [blame] | 61 | md->luminance_max *= kUnitOfMasteringLuminance; |
| 62 | md->luminance_min *= kUnitOfMasteringLuminance; |
Christopher Cameron | b6914526 | 2022-09-13 17:06:39 | [diff] [blame] | 63 | |
| 64 | // Values are stored in big-endian... |
| 65 | MasteringDisplayColorVolumeSEI sei; |
Christopher Cameron | 52f82ba0 | 2023-06-08 19:06:04 | [diff] [blame] | 66 | const auto& primaries = md->primaries; |
Christopher Cameron | 22d153d | 2022-11-11 21:18:46 | [diff] [blame] | 67 | sei.primaries[0].x = |
| 68 | __builtin_bswap16(primaries.fGX * kColorCoordinateUpperBound + 0.5f); |
| 69 | sei.primaries[0].y = |
| 70 | __builtin_bswap16(primaries.fGY * kColorCoordinateUpperBound + 0.5f); |
| 71 | sei.primaries[1].x = |
| 72 | __builtin_bswap16(primaries.fBX * kColorCoordinateUpperBound + 0.5f); |
| 73 | sei.primaries[1].y = |
| 74 | __builtin_bswap16(primaries.fBY * kColorCoordinateUpperBound + 0.5f); |
| 75 | sei.primaries[2].x = |
| 76 | __builtin_bswap16(primaries.fRX * kColorCoordinateUpperBound + 0.5f); |
| 77 | sei.primaries[2].y = |
| 78 | __builtin_bswap16(primaries.fRY * kColorCoordinateUpperBound + 0.5f); |
| 79 | sei.white_point.x = |
| 80 | __builtin_bswap16(primaries.fWX * kColorCoordinateUpperBound + 0.5f); |
| 81 | sei.white_point.y = |
| 82 | __builtin_bswap16(primaries.fWY * kColorCoordinateUpperBound + 0.5f); |
Christopher Cameron | 52f82ba0 | 2023-06-08 19:06:04 | [diff] [blame] | 83 | sei.luminance_max = __builtin_bswap32(md->luminance_max + 0.5f); |
| 84 | sei.luminance_min = __builtin_bswap32(md->luminance_min + 0.5f); |
Christopher Cameron | b6914526 | 2022-09-13 17:06:39 | [diff] [blame] | 85 | |
Avi Drissman | 28154a6 | 2023-08-22 04:06:45 | [diff] [blame] | 86 | return base::apple::ScopedCFTypeRef<CFDataRef>( |
Christopher Cameron | b6914526 | 2022-09-13 17:06:39 | [diff] [blame] | 87 | CFDataCreate(nullptr, reinterpret_cast<const UInt8*>(&sei), 24)); |
| 88 | } |
| 89 | |
Christopher Cameron | 1fceb6a | 2024-11-27 15:38:15 | [diff] [blame] | 90 | base::apple::ScopedCFTypeRef<CFDataRef> GenerateAmbientViewingEnvironment() { |
| 91 | // The AMVE box is documented in Technical Note 3145. |
| 92 | // https://developer.apple.com/documentation/technotes/tn3145-hdr-video-metadata |
| 93 | struct AmveSEI { |
| 94 | uint32_t ambient_illuminance; |
| 95 | uint16_t ambient_light_x; |
| 96 | uint16_t ambient_light_y; |
| 97 | } __attribute__((packed, aligned(2))); |
| 98 | static_assert(sizeof(AmveSEI) == 8, "Must be 8 bytes"); |
| 99 | |
| 100 | // The actual values specified in the AMVE box have no effect on rendering. In |
| 101 | // fact, the full box does not even need to be specified (just an single byte |
| 102 | // set to 0 will have the same effect). Use the default values set by iPhone |
| 103 | // HDR videos (314 nits, just to be safe. |
| 104 | AmveSEI sei; |
|
|