Issue #1820 - Part 1 : Add an extraction function to parse the RFC-6381 VP9 codec string.

This commit is contained in:
Moonchild 2022-04-26 14:49:54 +00:00 committed by roytam1
commit 55504b39bf
2 changed files with 202 additions and 1 deletions

View file

@ -223,13 +223,186 @@ already_AddRefed<SharedThreadPool> GetMediaThreadPool(MediaThreadType aType)
return pool.forget();
}
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.

View file

@ -258,6 +258,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