Add support for HEVC codec types in Media Capabilities
[WebKit-https.git] / Source / WebCore / platform / graphics / HEVCUtilities.cpp
1 /*
2  * Copyright (C) 2018 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "HEVCUtilities.h"
28
29 #include <wtf/text/StringToIntegerConversion.h>
30
31 namespace WebCore {
32
33 std::optional<HEVCParameterSet> parseHEVCCodecParameters(const String& codecString)
34 {
35     // The format of the 'hevc' codec string is specified in ISO/IEC 14496-15:2014, Annex E.3.
36     StringView codecView(codecString);
37     auto codecSplit = codecView.split('.');
38     auto nextElement = codecSplit.begin();
39     if (nextElement == codecSplit.end())
40         return std::nullopt;
41
42     HEVCParameterSet parameters;
43
44     // Codec identifier: legal values are specified in ISO/IEC 14496-15:2014, section 8:
45     parameters.codecName = (*nextElement).toString();
46     if (!equal(parameters.codecName, "hvc1") && !equal(parameters.codecName, "hev1"))
47         return std::nullopt;
48
49     if (++nextElement == codecSplit.end())
50         return std::nullopt;
51
52     // First element: Optional General Profile Space parameter ['A', 'B', 'C'], mapping to [1, 2, 3]
53     // and [0] for absent, then General Profile IDC as a 5-bit decimal number.
54     auto profileSpace = *nextElement;
55     if (!profileSpace.length())
56         return std::nullopt;
57
58     auto firstCharacter = profileSpace[0];
59     bool hasProfileSpace = firstCharacter >= 'A' && firstCharacter <= 'C';
60     if (hasProfileSpace) {
61         parameters.generalProfileSpace = 1 + (firstCharacter - 'A');
62         profileSpace = profileSpace.substring(1);
63     }
64
65     bool isValidProfileIDC = false;
66     parameters.generalProfileIDC = toIntegralType<uint8_t>(profileSpace, &isValidProfileIDC);
67     if (!isValidProfileIDC)
68         return std::nullopt;
69
70     if (++nextElement == codecSplit.end())
71         return std::nullopt;
72
73     // Second element: 32 bit of General Profile Compatibility Flags, in reverse bit order,
74     // in hex with leading zeros omitted.
75     auto compatibilityFlags = *nextElement;
76     bool isValidCompatibilityFlags = false;
77     parameters.generalProfileCompatibilityFlags = toIntegralType<uint32_t>(compatibilityFlags, &isValidCompatibilityFlags, 16);
78     if (!isValidCompatibilityFlags)
79         return std::nullopt;
80
81     if (++nextElement == codecSplit.end())
82         return std::nullopt;
83
84     // Third element: General Tier Flag ['L', 'H'], mapping to [false, true], followed by
85     // General Level IDC as a 8-bit decimal number.
86     auto generalTier = *nextElement;
87     firstCharacter = generalTier[0];
88     if (firstCharacter != 'L' && firstCharacter != 'H')
89         return std::nullopt;
90
91     parameters.generalTierFlag = firstCharacter == 'H';
92     bool isValidGeneralLevelIDC = false;
93     parameters.generalLevelIDC = toIntegralType<uint8_t>(generalTier.substring(1), &isValidGeneralLevelIDC);
94     if (!isValidGeneralLevelIDC)
95         return std::nullopt;
96
97     // Optional fourth and remaning elements: a sequence of 6 1-byte constraint flags, each byte encoded
98     // in hex, and separated by a period, with trailing zero bytes omitted.
99     parameters.constraintFlags.fill(0, 6);
100     for (auto& flag : parameters.constraintFlags) {
101         if (++nextElement == codecSplit.end())
102             break;
103
104         bool isValidFlag = false;
105         flag = toIntegralType<uint8_t>(*nextElement, &isValidFlag, 16);
106         if (!isValidFlag)
107             return std::nullopt;
108     }
109
110     return WTFMove(parameters);
111 }
112
113 }