summaryrefslogtreecommitdiff
path: root/dom/media/VideoUtils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/VideoUtils.cpp')
-rw-r--r--dom/media/VideoUtils.cpp189
1 files changed, 186 insertions, 3 deletions
diff --git a/dom/media/VideoUtils.cpp b/dom/media/VideoUtils.cpp
index 56033c2fae..cc8d561460 100644
--- a/dom/media/VideoUtils.cpp
+++ b/dom/media/VideoUtils.cpp
@@ -223,12 +223,185 @@ already_AddRefed<SharedThreadPool> GetMediaThreadPool(MediaThreadType aType)
}
bool
+ExtractVPXCodecDetails(const nsAString& aCodec,
+ uint8_t& aProfile,
+ uint8_t& aLevel,
+ uint8_t& aBitDepth)
+{
+ uint8_t dummyChromaSubsampling = 1;
+ VideoColorSpace dummyColorspace;
+ return ExtractVPXCodecDetails(aCodec,
+ aProfile,
+ aLevel,
+ aBitDepth,
+ dummyChromaSubsampling,
+ dummyColorspace);
+}
+
+bool ExtractVPXCodecDetails(const nsAString& aCodec,
+ uint8_t& aProfile,
+ uint8_t& aLevel,
+ uint8_t& aBitDepth,
+ uint8_t& aChromaSubsampling,
+ VideoColorSpace& aColorSpace)
+{
+ nsTArray<nsString> fieldsArr;
+
+ // Assign default value.
+ aChromaSubsampling = 1;
+
+ nsCharSeparatedTokenizer tokenizer(aCodec, '.');
+ while (tokenizer.hasMoreTokens()) {
+ const nsSubstring& token = tokenizer.nextToken();
+ fieldsArr.AppendElement(token);
+ }
+ auto fourCC = fieldsArr[0];
+
+ if (!fourCC.EqualsLiteral("vp09") && !fourCC.EqualsLiteral("vp08")) {
+ // Invalid 4CC
+ return false;
+ }
+ uint8_t *fields[] = { &aProfile, &aLevel, &aBitDepth, &aChromaSubsampling,
+ &aColorSpace.mPrimaryId, &aColorSpace.mTransferId,
+ &aColorSpace.mMatrixId, &aColorSpace.mRangeId };
+ int fieldsCount = 0;
+ nsresult rv;
+ for (int fieldsItr = 1; fieldsItr < fieldsArr.Length(); ++fieldsItr, ++fieldsCount) {
+ if (fieldsCount > 7) {
+ // No more than 8 fields are expected.
+ return false;
+ }
+ *(fields[fieldsCount]) =
+ static_cast<uint8_t>(fieldsArr[fieldsItr].ToInteger(&rv));
+ // We got invalid field value, parsing error.
+ NS_ENSURE_SUCCESS(rv, false);
+ }
+ // Mandatory Fields
+ // <sample entry 4CC>.<profile>.<level>.<bitDepth>.
+ // Optional Fields
+ // <chromaSubsampling>.<colourPrimaries>.<transferCharacteristics>.
+ // <matrixCoefficients>.<videoFullRangeFlag>
+ // First three fields are mandatory(we have parsed 4CC).
+ if (fieldsCount < 3) {
+ // Invalid number of fields.
+ return false;
+ }
+ // Start to validate the parsing value.
+
+ // profile should be 0,1,2 or 3.
+ // See https://www.webmproject.org/vp9/profiles/
+ // We don't support more than profile 2
+ if (aProfile > 2) {
+ // Invalid profile.
+ return false;
+ }
+
+ // level, See https://www.webmproject.org/vp9/mp4/#semantics_1
+ switch (aLevel) {
+ case 10:
+ case 11:
+ case 20:
+ case 21:
+ case 30:
+ case 31:
+ case 40:
+ case 41:
+ case 50:
+ case 51:
+ case 52:
+ case 60:
+ case 61:
+ case 62:
+ break;
+ default:
+ // Invalid level.
+ return false;
+ }
+
+ if (aBitDepth != 8 && aBitDepth != 10 && aBitDepth != 12) {
+ // Invalid bitDepth:
+ return false;
+ }
+
+ if (fieldsCount == 3) {
+ // No more options.
+ return true;
+ }
+
+ // chromaSubsampling should be 0,1,2,3...4~7 are reserved.
+ if (aChromaSubsampling > 3) {
+ return false;
+ }
+
+ if (fieldsCount == 4) {
+ // No more options.
+ return true;
+ }
+
+ // It is an integer that is defined by the "Colour primaries"
+ // section of ISO/IEC 23001-8:2016 Table 2.
+ // We treat reserved value as false case.
+ const auto& primaryId = aColorSpace.mPrimaryId;
+ if (primaryId == 0 || primaryId == 3 || primaryId > 22) {
+ // reserved value.
+ return false;
+ }
+ if (primaryId > 12 && primaryId < 22) {
+ // 13~21 are reserved values.
+ return false;
+ }
+
+ if (fieldsCount == 5) {
+ // No more options.
+ return true;
+ }
+
+ // It is an integer that is defined by the
+ // "Transfer characteristics" section of ISO/IEC 23001-8:2016 Table 3.
+ // We treat reserved value as false case.
+ const auto& transferId = aColorSpace.mTransferId;
+ if (transferId == 0 || transferId == 3 || transferId > 18) {
+ // reserved value.
+ return false;
+ }
+
+ if (fieldsCount == 6) {
+ // No more options.
+ return true;
+ }
+
+ // It is an integer that is defined by the
+ // "Matrix coefficients" section of ISO/IEC 23001-8:2016 Table 4.
+ // We treat reserved value as false case.
+ const auto& matrixId = aColorSpace.mMatrixId;
+ if (matrixId == 3 || matrixId > 11) {
+ return false;
+ }
+
+ // If matrixCoefficients is 0 (RGB), then chroma subsampling MUST be 3 (4:4:4).
+ if (matrixId == 0 && aChromaSubsampling != 3) {
+ return false;
+ }
+
+ if (fieldsCount == 7) {
+ // No more options.
+ return true;
+ }
+
+ // videoFullRangeFlag indicates the black level and range of the luma and
+ // chroma signals. 0 = legal range (e.g. 16-235 for 8 bit sample depth);
+ // 1 = full range (e.g. 0-255 for 8-bit sample depth).
+ const auto& rangeId = aColorSpace.mRangeId;
+ return rangeId <= 1;
+}
+
+bool
ExtractH264CodecDetails(const nsAString& aCodec,
int16_t& aProfile,
int16_t& aLevel)
{
// H.264 codecs parameters have a type defined as avcN.PPCCLL, where
- // N = avc type. avc3 is avcc with SPS & PPS implicit (within stream)
+ // N = avc type. avc3 is avcc with SPS & PPS implicit (within stream)
// PP = profile_idc, CC = constraint_set flags, LL = level_idc.
// We ignore the constraint_set flags, as it's not clear from any
// documentation what constraints the platform decoders support.
@@ -468,15 +641,25 @@ IsAACCodecString(const nsAString& aCodec)
bool
IsVP8CodecString(const nsAString& aCodec)
{
+ uint8_t profile = 0;
+ uint8_t level = 0;
+ uint8_t bitDepth = 0;
return aCodec.EqualsLiteral("vp8") ||
- aCodec.EqualsLiteral("vp8.0");
+ aCodec.EqualsLiteral("vp8.0") ||
+ (StartsWith(NS_ConvertUTF16toUTF8(aCodec), "vp08") &&
+ ExtractVPXCodecDetails(aCodec, profile, level, bitDepth));
}
bool
IsVP9CodecString(const nsAString& aCodec)
{
+ uint8_t profile = 0;
+ uint8_t level = 0;
+ uint8_t bitDepth = 0;
return aCodec.EqualsLiteral("vp9") ||
- aCodec.EqualsLiteral("vp9.0");
+ aCodec.EqualsLiteral("vp9.0") ||
+ (StartsWith(NS_ConvertUTF16toUTF8(aCodec), "vp09") &&
+ ExtractVPXCodecDetails(aCodec, profile, level, bitDepth));
}
#ifdef MOZ_AV1