| /* |
| * Copyright (C) 2020 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "VP9Utilities.h" |
| |
| #include <wtf/NeverDestroyed.h> |
| #include <wtf/text/StringToIntegerConversion.h> |
| |
| namespace WebCore { |
| |
| static bool isValidVPLevel(uint8_t level) |
| { |
| constexpr uint8_t validLevels[] = { |
| VPConfigurationLevel::Level_1, |
| VPConfigurationLevel::Level_1_1, |
| VPConfigurationLevel::Level_2, |
| VPConfigurationLevel::Level_2_1, |
| VPConfigurationLevel::Level_3, |
| VPConfigurationLevel::Level_3_1, |
| VPConfigurationLevel::Level_4, |
| VPConfigurationLevel::Level_4_1, |
| VPConfigurationLevel::Level_5, |
| VPConfigurationLevel::Level_5_1, |
| VPConfigurationLevel::Level_5_2, |
| VPConfigurationLevel::Level_6, |
| VPConfigurationLevel::Level_6_1, |
| VPConfigurationLevel::Level_6_2, |
| }; |
| |
| ASSERT(std::is_sorted(std::begin(validLevels), std::end(validLevels))); |
| return std::binary_search(std::begin(validLevels), std::end(validLevels), level); |
| } |
| |
| static bool isValidVPColorPrimaries(uint8_t colorPrimaries) |
| { |
| constexpr uint8_t validColorPrimaries[] = { |
| VPConfigurationColorPrimaries::BT_709_6, |
| VPConfigurationColorPrimaries::Unspecified, |
| VPConfigurationColorPrimaries::BT_470_6_M, |
| VPConfigurationColorPrimaries::BT_470_7_BG, |
| VPConfigurationColorPrimaries::BT_601_7, |
| VPConfigurationColorPrimaries::SMPTE_ST_240, |
| VPConfigurationColorPrimaries::Film, |
| VPConfigurationColorPrimaries::BT_2020_Nonconstant_Luminance, |
| VPConfigurationColorPrimaries::SMPTE_ST_428_1, |
| VPConfigurationColorPrimaries::SMPTE_RP_431_2, |
| VPConfigurationColorPrimaries::SMPTE_EG_432_1, |
| VPConfigurationColorPrimaries::EBU_Tech_3213_E, |
| }; |
| |
| ASSERT(std::is_sorted(std::begin(validColorPrimaries), std::end(validColorPrimaries))); |
| return std::binary_search(std::begin(validColorPrimaries), std::end(validColorPrimaries), colorPrimaries); |
| } |
| |
| static bool isValidVPTransferCharacteristics(uint8_t transferCharacteristics) |
| { |
| constexpr uint8_t validTransferCharacteristics[] = { |
| VPConfigurationTransferCharacteristics::BT_709_6, |
| VPConfigurationTransferCharacteristics::Unspecified, |
| VPConfigurationTransferCharacteristics::BT_470_6_M, |
| VPConfigurationTransferCharacteristics::BT_470_7_BG, |
| VPConfigurationTransferCharacteristics::BT_601_7, |
| VPConfigurationTransferCharacteristics::SMPTE_ST_240, |
| VPConfigurationTransferCharacteristics::Linear, |
| VPConfigurationTransferCharacteristics::Logrithmic, |
| VPConfigurationTransferCharacteristics::Logrithmic_Sqrt, |
| VPConfigurationTransferCharacteristics::IEC_61966_2_4, |
| VPConfigurationTransferCharacteristics::BT_1361_0, |
| VPConfigurationTransferCharacteristics::IEC_61966_2_1, |
| VPConfigurationTransferCharacteristics::BT_2020_10bit, |
| VPConfigurationTransferCharacteristics::BT_2020_12bit, |
| VPConfigurationTransferCharacteristics::SMPTE_ST_2084, |
| VPConfigurationTransferCharacteristics::SMPTE_ST_428_1, |
| VPConfigurationTransferCharacteristics::BT_2100_HLG, |
| }; |
| ASSERT(std::is_sorted(std::begin(validTransferCharacteristics), std::end(validTransferCharacteristics))); |
| return std::binary_search(std::begin(validTransferCharacteristics), std::end(validTransferCharacteristics), transferCharacteristics); |
| } |
| |
| static bool isValidVPMatrixCoefficients(uint8_t matrixCoefficients) |
| { |
| constexpr uint8_t validMatrixCoefficients[] = { |
| VPConfigurationMatrixCoefficients::Identity, |
| VPConfigurationMatrixCoefficients::BT_709_6, |
| VPConfigurationMatrixCoefficients::Unspecified, |
| VPConfigurationMatrixCoefficients::FCC, |
| VPConfigurationMatrixCoefficients::BT_470_7_BG, |
| VPConfigurationMatrixCoefficients::BT_601_7, |
| VPConfigurationMatrixCoefficients::SMPTE_ST_240, |
| VPConfigurationMatrixCoefficients::YCgCo, |
| VPConfigurationMatrixCoefficients::BT_2020_Nonconstant_Luminance, |
| VPConfigurationMatrixCoefficients::BT_2020_Constant_Luminance, |
| VPConfigurationMatrixCoefficients::SMPTE_ST_2085, |
| VPConfigurationMatrixCoefficients::Chromacity_Constant_Luminance, |
| VPConfigurationMatrixCoefficients::Chromacity_Nonconstant_Luminance, |
| VPConfigurationMatrixCoefficients::BT_2100_ICC, |
| }; |
| ASSERT(std::is_sorted(std::begin(validMatrixCoefficients), std::end(validMatrixCoefficients))); |
| return std::binary_search(std::begin(validMatrixCoefficients), std::end(validMatrixCoefficients), matrixCoefficients); |
| } |
| |
| std::optional<VPCodecConfigurationRecord> parseVPCodecParameters(StringView codecView) |
| { |
| auto codecSplit = codecView.split('.'); |
| auto nextElement = codecSplit.begin(); |
| if (nextElement == codecSplit.end()) |
| return std::nullopt; |
| |
| VPCodecConfigurationRecord configuration; |
| |
| configuration.codecName = (*nextElement).toString(); |
| ++nextElement; |
| |
| // Support the legacy identifiers (with no parameters) for VP8 and VP9. |
| if ((configuration.codecName == "vp8"_s || configuration.codecName == "vp9"_s) && nextElement == codecSplit.end()) |
| return configuration; |
| |
| // The format of the 'vp09' codec string is specified in the webm GitHub repo: |
| // <https://github.com/webmproject/vp9-dash/blob/master/VPCodecISOMediaFileFormatBinding.md#codecs-parameter-string> |
| |
| // "sample entry 4CC, profile, level, and bitDepth are all mandatory fields. If any of these fields are empty, or not |
| // within their allowed range, the processing device SHALL treat it as an error." |
| |
| // Codec identifier: legal values are 'vp08' or 'vp09'. |
| if (configuration.codecName != "vp08"_s && configuration.codecName != "vp09"_s) |
| return std::nullopt; |
| |
| if (nextElement == codecSplit.end()) |
| return std::nullopt; |
| |
| // First element: profile. Legal values are 0-3. |
| auto profile = parseInteger<uint8_t>(*nextElement); |
| if (!profile || *profile > 3) |
| return std::nullopt; |
| configuration.profile = *profile; |
| |
| if (++nextElement == codecSplit.end()) |
| return std::nullopt; |
| |
| // Second element: level. Legal values are enumerated in validVPLevels above. |
| auto level = parseInteger<uint8_t>(*nextElement); |
| if (!level || !isValidVPLevel(*level)) |
| return std::nullopt; |
| configuration.level = *level; |
| |
| if (++nextElement == codecSplit.end()) |
| return std::nullopt; |
| |
| // Third element: bitDepth. Legal values are 8, 10, and 12. |
| auto bitDepth = parseInteger<uint8_t>(*nextElement); |
| if (!bitDepth || (*bitDepth != 8 && *bitDepth != 10 && *bitDepth != 12)) |
| return std::nullopt; |
| configuration.bitDepth = *bitDepth; |
| |
| // "colorPrimaries, transferCharacteristics, matrixCoefficients, videoFullRangeFlag, and chromaSubsampling are OPTIONAL, |
| // mutually inclusive (all or none) fields. If not specified then the processing device MUST use the values listed in the |
| // table below as defaults when deciding if the device is able to decode and potentially render the video." |
| |
| if (++nextElement == codecSplit.end()) |
| return configuration; |
| |
| // Fourth element: chromaSubsampling. Legal values are 0-3. |
| auto chromaSubsampling = parseInteger<uint8_t>(*nextElement); |
| if (!chromaSubsampling || *chromaSubsampling > VPConfigurationChromaSubsampling::Subsampling_444) |
| return std::nullopt; |
| configuration.chromaSubsampling = *chromaSubsampling; |
| |
| if (++nextElement == codecSplit.end()) |
| return std::nullopt; |
| |
| // Fifth element: colorPrimaries. Legal values are defined by ISO/IEC 23001-8:2016, superseded |
| // by ISO/IEC 23091-2:2019. |
| auto colorPrimaries = parseInteger<uint8_t>(*nextElement); |
| if (!colorPrimaries || !isValidVPColorPrimaries(*colorPrimaries)) |
| return std::nullopt; |
| configuration.colorPrimaries = *colorPrimaries; |
| |
| if (++nextElement == codecSplit.end()) |
| return std::nullopt; |
| |
| // Sixth element: transferCharacteristics. Legal values are defined by ISO/IEC 23001-8:2016, superseded |
| // by ISO/IEC 23091-2:2019. |
| auto transferCharacteristics = parseInteger<uint8_t>(*nextElement); |
| if (!transferCharacteristics || !isValidVPTransferCharacteristics(*transferCharacteristics)) |
| return std::nullopt; |
| configuration.transferCharacteristics = *transferCharacteristics; |
| |
| if (++nextElement == codecSplit.end()) |
| return std::nullopt; |
| |
| // Seventh element: matrixCoefficients. Legal values are defined by ISO/IEC 23001-8:2016, superseded |
| // by ISO/IEC 23091-2:2019. |
| auto matrixCoefficients = parseInteger<uint8_t>(*nextElement); |
| if (!matrixCoefficients || !isValidVPMatrixCoefficients(*matrixCoefficients)) |
| return std::nullopt; |
| configuration.matrixCoefficients = *matrixCoefficients; |
| |
| // "If matrixCoefficients is 0 (RGB), then chroma subsampling MUST be 3 (4:4:4)." |
| if (!configuration.matrixCoefficients && configuration.chromaSubsampling != 3) |
| return std::nullopt; |
| |
| if (++nextElement == codecSplit.end()) |
| return std::nullopt; |
| |
| // Eighth element: videoFullRangeFlag. Legal values are 0 and 1. |
| auto videoFullRangeFlag = parseInteger<uint8_t>(*nextElement); |
| if (!videoFullRangeFlag || *videoFullRangeFlag > 1) |
| return std::nullopt; |
| configuration.videoFullRangeFlag = *videoFullRangeFlag; |
| |
| if (++nextElement != codecSplit.end()) |
| return std::nullopt; |
| |
| return configuration; |
| } |
| |
| } |