Index: media/base/video_codecs.cc |
diff --git a/media/base/video_codecs.cc b/media/base/video_codecs.cc |
index e68e4337693b6fc816bb298430198ada750d0d6c..f726b034ed27a8fc5f114d4ec4b7c86a82bb631e 100644 |
--- a/media/base/video_codecs.cc |
+++ b/media/base/video_codecs.cc |
@@ -94,30 +94,101 @@ std::string GetProfileName(VideoCodecProfile profile) { |
return ""; |
} |
+// Described in ISO 23001-8:2016 Table 3. |
+bool ParseVp9Eotf(const int value, gfx::ColorSpace::TransferID* eotf) { |
+ switch (value) { |
+ case 1: |
+ *eotf = gfx::ColorSpace::TransferID::BT709; |
+ break; |
+ case 2: |
+ // "2" is interpreted as "Unspecified" |
+ *eotf = gfx::ColorSpace::TransferID::INVALID; |
+ break; |
+ case 4: |
+ *eotf = gfx::ColorSpace::TransferID::GAMMA22; |
+ break; |
+ case 5: |
+ *eotf = gfx::ColorSpace::TransferID::GAMMA28; |
+ break; |
+ case 6: |
+ *eotf = gfx::ColorSpace::TransferID::SMPTE170M; |
+ break; |
+ case 7: |
+ *eotf = gfx::ColorSpace::TransferID::SMPTE240M; |
+ break; |
+ case 8: |
+ *eotf = gfx::ColorSpace::TransferID::LINEAR; |
+ break; |
+ case 9: |
+ *eotf = gfx::ColorSpace::TransferID::LOG; |
+ break; |
+ case 10: |
+ *eotf = gfx::ColorSpace::TransferID::LOG_SQRT; |
+ break; |
+ case 11: |
+ *eotf = gfx::ColorSpace::TransferID::IEC61966_2_4; |
+ break; |
+ case 12: |
+ *eotf = gfx::ColorSpace::TransferID::BT1361_ECG; |
+ break; |
+ case 13: |
+ *eotf = gfx::ColorSpace::TransferID::IEC61966_2_1; |
+ break; |
+ case 14: |
+ *eotf = gfx::ColorSpace::TransferID::BT2020_10; |
+ break; |
+ case 15: |
+ *eotf = gfx::ColorSpace::TransferID::BT2020_12; |
+ break; |
+ case 16: |
+ *eotf = gfx::ColorSpace::TransferID::SMPTEST2084; |
+ break; |
+ case 17: |
+ *eotf = gfx::ColorSpace::TransferID::SMPTEST428_1; |
+ break; |
+ default: |
+ // Includes reserved values of 0, 3, 18 - 255. |
+ *eotf = gfx::ColorSpace::TransferID::INVALID; |
+ return false; |
+ } |
+ |
+ return true; |
+} |
+ |
bool ParseNewStyleVp9CodecID(const std::string& codec_id, |
VideoCodecProfile* profile, |
- uint8_t* level_idc) { |
+ uint8_t* level_idc, |
+ gfx::ColorSpace::TransferID* eotf) { |
+ // Initialize optional fields to their defaults. |
+ *eotf = gfx::ColorSpace::TransferID::BT709; |
+ |
std::vector<std::string> fields = base::SplitString( |
codec_id, ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); |
- // TODO(kqyang): The spec specifies 8 fields. We do not allow missing or extra |
- // fields. See crbug.com/667834. |
- if (fields.size() != 8) |
+ // First four fields are mandatory. No more than 9 fields are expected. |
+ if (fields.size() < 4 || fields.size() > 9) { |
+ DVLOG(3) << __func__ << " Invalid number of fields (" << fields.size() |
+ << ")"; |
return false; |
+ } |
- if (fields[0] != "vp09") |
+ if (fields[0] != "vp09") { |
+ DVLOG(3) << __func__ << " Invalid 4CC (" << fields[0] << ")"; |
return false; |
+ } |
std::vector<int> values; |
for (size_t i = 1; i < fields.size(); ++i) { |
// Missing value is not allowed. |
- if (fields[i] == "") |
+ if (fields[i] == "") { |
+ DVLOG(3) << __func__ << " Invalid missing field (position:" << i << ")"; |
return false; |
+ } |
int value; |
- if (!base::StringToInt(fields[i], &value)) |
- return false; |
- if (value < 0) |
+ if (!base::StringToInt(fields[i], &value) || value < 0) { |
+ DVLOG(3) << __func__ << " Invalid field value (" << value << ")"; |
return false; |
+ } |
values.push_back(value); |
} |
@@ -136,31 +207,87 @@ bool ParseNewStyleVp9CodecID(const std::string& codec_id, |
*profile = VP9PROFILE_PROFILE3; |
break; |
default: |
+ DVLOG(3) << __func__ << " Invalid profile (" << profile_idc << ")"; |
return false; |
} |
*level_idc = values[1]; |
- // TODO(kqyang): Check if |level_idc| is valid. See crbug.com/667834. |
+ switch (*level_idc) { |
+ case 1: |
+ case 11: |
+ case 2: |
+ case 21: |
+ case 3: |
+ case 31: |
+ case 4: |
+ case 41: |
+ case 5: |
+ case 51: |
+ case 52: |
+ case 6: |
+ case 61: |
+ case 62: |
+ break; |
+ default: |
+ DVLOG(3) << __func__ << " Invalid level (" << *level_idc << ")"; |
+ return false; |
+ } |
const int bit_depth = values[2]; |
- if (bit_depth != 8 && bit_depth != 10 && bit_depth != 12) |
+ if (bit_depth != 8 && bit_depth != 10 && bit_depth != 12) { |
+ DVLOG(3) << __func__ << " Invalid bit-depth (" << bit_depth << ")"; |
return false; |
+ } |
- const int color_space = values[3]; |
- if (color_space > 7) |
+ if (values.size() < 4) |
+ return true; |
+ const int color_primaries = values[3]; |
+ // TODO(chcunningham): parse and bubble up color primaries, described in ISO |
+ // 23001-8:2016 Table 2. |
+ // Values 0, 3, and 23 - 255 are reserved. |
+ if (color_primaries == 0 || color_primaries == 3 || color_primaries > 22) { |
+ DVLOG(3) << __func__ << " Invalid color primaries (" << color_primaries |
+ << ")"; |
return false; |
+ } |
- const int chroma_subsampling = values[4]; |
- if (chroma_subsampling > 3) |
+ if (values.size() < 5) |
+ return true; |
+ if (!ParseVp9Eotf(values[4], eotf)) { |
+ DVLOG(3) << __func__ << " Invalid transfer function (" << values[4] << ")"; |
return false; |
+ } |
- const int transfer_function = values[5]; |
- if (transfer_function > 1) |
+ // TODO(chcunningham): Parse and bubble up the following fields. For now just |
+ // doing basic validation. |
+ |
+ if (values.size() < 6) |
+ return true; |
+ const int matrix_coefficients = values[5]; |
+ if (matrix_coefficients > 11) { |
+ DVLOG(3) << __func__ << " Invalid matrix coefficients (" |
+ << matrix_coefficients << ")"; |
return false; |
+ } |
+ if (values.size() < 7) |
+ return true; |
const int video_full_range_flag = values[6]; |
- if (video_full_range_flag > 1) |
+ if (video_full_range_flag > 1) { |
+ DVLOG(3) << __func__ << " Invalid full range flag (" |
+ << video_full_range_flag << ")"; |
return false; |
+ } |
+ |
+ if (values.size() < 8) |
+ return true; |
+ const int chroma_subsampling = values[7]; |
+ if (chroma_subsampling > 3 || |
+ (chroma_subsampling != 3 && matrix_coefficients == 0)) { |
+ DVLOG(3) << __func__ << " Invalid chroma subsampling (" |
+ << chroma_subsampling << ")"; |
+ return false; |
+ } |
return true; |
} |
@@ -532,11 +659,14 @@ VideoCodec StringToVideoCodec(const std::string& codec_id) { |
codec_id, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); |
if (elem.empty()) |
return kUnknownVideoCodec; |
+ |
VideoCodecProfile profile = VIDEO_CODEC_PROFILE_UNKNOWN; |
uint8_t level = 0; |
+ gfx::ColorSpace::TransferID eotf = gfx::ColorSpace::TransferID::INVALID; |
+ |
if (codec_id == "vp8" || codec_id == "vp8.0") |
return kCodecVP8; |
- if (ParseNewStyleVp9CodecID(codec_id, &profile, &level) || |
+ if (ParseNewStyleVp9CodecID(codec_id, &profile, &level, &eotf) || |
ParseLegacyVp9CodecID(codec_id, &profile, &level)) { |
return kCodecVP9; |
} |