bool ExtractVPXCodecDetails(const nsAString& aCodec, uint8_t& aProfile, uint8_t& aLevel, uint8_t& aBitDepth, uint8_t& aChromaSubsampling, VideoColorSpace& aColorSpace) { // Assign default value. aChromaSubsampling = 1; auto splitter = aCodec.Split(u'.'); auto fieldsItr = splitter.begin(); auto fourCC = *fieldsItr; if (!fourCC.EqualsLiteral("vp09") && !fourCC.EqualsLiteral("vp08")) { // Invalid 4CC return false; } ++fieldsItr; uint8_t *fields[] = { &aProfile, &aLevel, &aBitDepth, &aChromaSubsampling, &aColorSpace.mPrimaryId, &aColorSpace.mTransferId, &aColorSpace.mMatrixId, &aColorSpace.mRangeId }; int fieldsCount = 0; nsresult rv; for (; fieldsItr != splitter.end(); ++fieldsItr, ++fieldsCount) { if (fieldsCount > 7) { // No more than 8 fields are expected. return false; } *(fields[fieldsCount]) = static_cast<uint8_t>(PromiseFlatString((*fieldsItr)).ToInteger(&rv, 10)); // 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; }