diff options
-rw-r--r-- | dom/media/VideoUtils.cpp | 175 | ||||
-rw-r--r-- | dom/media/VideoUtils.h | 28 |
2 files changed, 202 insertions, 1 deletions
diff --git a/dom/media/VideoUtils.cpp b/dom/media/VideoUtils.cpp index 56033c2fae..66a6d6f9b7 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. diff --git a/dom/media/VideoUtils.h b/dom/media/VideoUtils.h index eee6561fde..421e6bb51d 100644 --- a/dom/media/VideoUtils.h +++ b/dom/media/VideoUtils.h @@ -257,6 +257,34 @@ ExtractH264CodecDetails(const nsAString& aCodecs, int16_t& aProfile, int16_t& aLevel); +struct VideoColorSpace +{ + // TODO: Define the value type as strong type enum + // to better know the exact meaning corresponding to ISO/IEC 23001-8:2016. + // Default value is listed https://www.webmproject.org/vp9/mp4/#optional-fields + uint8_t mPrimaryId = 1; // Table 2 + uint8_t mTransferId = 1; // Table 3 + uint8_t mMatrixId = 1; // Table 4 + uint8_t mRangeId = 0; +}; + +// Extracts the VPX codecs parameter string. +// See https://www.webmproject.org/vp9/mp4/#codecs-parameter-string +// for more details. +// Returns false on failure. +bool +ExtractVPXCodecDetails(const nsAString& aCodec, + uint8_t& aProfile, + uint8_t& aLevel, + uint8_t& aBitDepth); +bool +ExtractVPXCodecDetails(const nsAString& aCodec, + uint8_t& aProfile, + uint8_t& aLevel, + uint8_t& aBitDepth, + uint8_t& aChromaSubsampling, + VideoColorSpace& aColorSpace); + // Use a cryptographic quality PRNG to generate raw random bytes // and convert that to a base64 string. nsresult |