| 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;
|
| }
|
|
|