Exemplo n.º 1
0
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;
}