OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/base/video_codecs.h" | 5 #include "media/base/video_codecs.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/strings/string_number_conversions.h" | 8 #include "base/strings/string_number_conversions.h" |
9 #include "base/strings/string_split.h" | 9 #include "base/strings/string_split.h" |
10 #include "base/strings/string_util.h" | 10 #include "base/strings/string_util.h" |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
87 return "dolby vision profile 4"; | 87 return "dolby vision profile 4"; |
88 case DOLBYVISION_PROFILE5: | 88 case DOLBYVISION_PROFILE5: |
89 return "dolby vision profile 5"; | 89 return "dolby vision profile 5"; |
90 case DOLBYVISION_PROFILE7: | 90 case DOLBYVISION_PROFILE7: |
91 return "dolby vision profile 7"; | 91 return "dolby vision profile 7"; |
92 } | 92 } |
93 NOTREACHED(); | 93 NOTREACHED(); |
94 return ""; | 94 return ""; |
95 } | 95 } |
96 | 96 |
| 97 // Described in ISO 23001-8:2016 Table 3. |
| 98 bool ParseVp9Eotf(const int value, gfx::ColorSpace::TransferID* eotf) { |
| 99 switch (value) { |
| 100 case 1: |
| 101 *eotf = gfx::ColorSpace::TransferID::BT709; |
| 102 break; |
| 103 case 2: |
| 104 // "2" is interpreted as "Unspecified" |
| 105 *eotf = gfx::ColorSpace::TransferID::INVALID; |
| 106 break; |
| 107 case 4: |
| 108 *eotf = gfx::ColorSpace::TransferID::GAMMA22; |
| 109 break; |
| 110 case 5: |
| 111 *eotf = gfx::ColorSpace::TransferID::GAMMA28; |
| 112 break; |
| 113 case 6: |
| 114 *eotf = gfx::ColorSpace::TransferID::SMPTE170M; |
| 115 break; |
| 116 case 7: |
| 117 *eotf = gfx::ColorSpace::TransferID::SMPTE240M; |
| 118 break; |
| 119 case 8: |
| 120 *eotf = gfx::ColorSpace::TransferID::LINEAR; |
| 121 break; |
| 122 case 9: |
| 123 *eotf = gfx::ColorSpace::TransferID::LOG; |
| 124 break; |
| 125 case 10: |
| 126 *eotf = gfx::ColorSpace::TransferID::LOG_SQRT; |
| 127 break; |
| 128 case 11: |
| 129 *eotf = gfx::ColorSpace::TransferID::IEC61966_2_4; |
| 130 break; |
| 131 case 12: |
| 132 *eotf = gfx::ColorSpace::TransferID::BT1361_ECG; |
| 133 break; |
| 134 case 13: |
| 135 *eotf = gfx::ColorSpace::TransferID::IEC61966_2_1; |
| 136 break; |
| 137 case 14: |
| 138 *eotf = gfx::ColorSpace::TransferID::BT2020_10; |
| 139 break; |
| 140 case 15: |
| 141 *eotf = gfx::ColorSpace::TransferID::BT2020_12; |
| 142 break; |
| 143 case 16: |
| 144 *eotf = gfx::ColorSpace::TransferID::SMPTEST2084; |
| 145 break; |
| 146 case 17: |
| 147 *eotf = gfx::ColorSpace::TransferID::SMPTEST428_1; |
| 148 break; |
| 149 default: |
| 150 // Includes reserved values of 0, 3, 18 - 255. |
| 151 *eotf = gfx::ColorSpace::TransferID::INVALID; |
| 152 return false; |
| 153 } |
| 154 |
| 155 return true; |
| 156 } |
| 157 |
97 bool ParseNewStyleVp9CodecID(const std::string& codec_id, | 158 bool ParseNewStyleVp9CodecID(const std::string& codec_id, |
98 VideoCodecProfile* profile, | 159 VideoCodecProfile* profile, |
99 uint8_t* level_idc) { | 160 uint8_t* level_idc, |
| 161 gfx::ColorSpace::TransferID* eotf) { |
| 162 // Initialize optional fields to their defaults. |
| 163 *eotf = gfx::ColorSpace::TransferID::BT709; |
| 164 |
100 std::vector<std::string> fields = base::SplitString( | 165 std::vector<std::string> fields = base::SplitString( |
101 codec_id, ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); | 166 codec_id, ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); |
102 | 167 |
103 // TODO(kqyang): The spec specifies 8 fields. We do not allow missing or extra | 168 // First four fields are mandatory. No more than 9 fields are expected. |
104 // fields. See crbug.com/667834. | 169 if (fields.size() < 4 || fields.size() > 9) { |
105 if (fields.size() != 8) | 170 DVLOG(3) << __func__ << " Invalid number of fields (" << fields.size() |
| 171 << ")"; |
106 return false; | 172 return false; |
| 173 } |
107 | 174 |
108 if (fields[0] != "vp09") | 175 if (fields[0] != "vp09") { |
| 176 DVLOG(3) << __func__ << " Invalid 4CC (" << fields[0] << ")"; |
109 return false; | 177 return false; |
| 178 } |
110 | 179 |
111 std::vector<int> values; | 180 std::vector<int> values; |
112 for (size_t i = 1; i < fields.size(); ++i) { | 181 for (size_t i = 1; i < fields.size(); ++i) { |
113 // Missing value is not allowed. | 182 // Missing value is not allowed. |
114 if (fields[i] == "") | 183 if (fields[i] == "") { |
| 184 DVLOG(3) << __func__ << " Invalid missing field (position:" << i << ")"; |
115 return false; | 185 return false; |
| 186 } |
116 int value; | 187 int value; |
117 if (!base::StringToInt(fields[i], &value)) | 188 if (!base::StringToInt(fields[i], &value) || value < 0) { |
| 189 DVLOG(3) << __func__ << " Invalid field value (" << value << ")"; |
118 return false; | 190 return false; |
119 if (value < 0) | 191 } |
120 return false; | |
121 values.push_back(value); | 192 values.push_back(value); |
122 } | 193 } |
123 | 194 |
124 const int profile_idc = values[0]; | 195 const int profile_idc = values[0]; |
125 switch (profile_idc) { | 196 switch (profile_idc) { |
126 case 0: | 197 case 0: |
127 *profile = VP9PROFILE_PROFILE0; | 198 *profile = VP9PROFILE_PROFILE0; |
128 break; | 199 break; |
129 case 1: | 200 case 1: |
130 *profile = VP9PROFILE_PROFILE1; | 201 *profile = VP9PROFILE_PROFILE1; |
131 break; | 202 break; |
132 case 2: | 203 case 2: |
133 *profile = VP9PROFILE_PROFILE2; | 204 *profile = VP9PROFILE_PROFILE2; |
134 break; | 205 break; |
135 case 3: | 206 case 3: |
136 *profile = VP9PROFILE_PROFILE3; | 207 *profile = VP9PROFILE_PROFILE3; |
137 break; | 208 break; |
138 default: | 209 default: |
| 210 DVLOG(3) << __func__ << " Invalid profile (" << profile_idc << ")"; |
139 return false; | 211 return false; |
140 } | 212 } |
141 | 213 |
142 *level_idc = values[1]; | 214 *level_idc = values[1]; |
143 // TODO(kqyang): Check if |level_idc| is valid. See crbug.com/667834. | 215 switch (*level_idc) { |
| 216 case 1: |
| 217 case 11: |
| 218 case 2: |
| 219 case 21: |
| 220 case 3: |
| 221 case 31: |
| 222 case 4: |
| 223 case 41: |
| 224 case 5: |
| 225 case 51: |
| 226 case 52: |
| 227 case 6: |
| 228 case 61: |
| 229 case 62: |
| 230 break; |
| 231 default: |
| 232 DVLOG(3) << __func__ << " Invalid level (" << *level_idc << ")"; |
| 233 return false; |
| 234 } |
144 | 235 |
145 const int bit_depth = values[2]; | 236 const int bit_depth = values[2]; |
146 if (bit_depth != 8 && bit_depth != 10 && bit_depth != 12) | 237 if (bit_depth != 8 && bit_depth != 10 && bit_depth != 12) { |
| 238 DVLOG(3) << __func__ << " Invalid bit-depth (" << bit_depth << ")"; |
147 return false; | 239 return false; |
| 240 } |
148 | 241 |
149 const int color_space = values[3]; | 242 if (values.size() < 4) |
150 if (color_space > 7) | 243 return true; |
| 244 const int color_primaries = values[3]; |
| 245 // TODO(chcunningham): parse and bubble up color primaries, described in ISO |
| 246 // 23001-8:2016 Table 2. |
| 247 // Values 0, 3, and 23 - 255 are reserved. |
| 248 if (color_primaries == 0 || color_primaries == 3 || color_primaries > 22) { |
| 249 DVLOG(3) << __func__ << " Invalid color primaries (" << color_primaries |
| 250 << ")"; |
151 return false; | 251 return false; |
| 252 } |
152 | 253 |
153 const int chroma_subsampling = values[4]; | 254 if (values.size() < 5) |
154 if (chroma_subsampling > 3) | 255 return true; |
| 256 if (!ParseVp9Eotf(values[4], eotf)) { |
| 257 DVLOG(3) << __func__ << " Invalid transfer function (" << values[4] << ")"; |
155 return false; | 258 return false; |
| 259 } |
156 | 260 |
157 const int transfer_function = values[5]; | 261 // TODO(chcunningham): Parse and bubble up the following fields. For now just |
158 if (transfer_function > 1) | 262 // doing basic validation. |
| 263 |
| 264 if (values.size() < 6) |
| 265 return true; |
| 266 const int matrix_coefficients = values[5]; |
| 267 if (matrix_coefficients > 11) { |
| 268 DVLOG(3) << __func__ << " Invalid matrix coefficients (" |
| 269 << matrix_coefficients << ")"; |
159 return false; | 270 return false; |
| 271 } |
160 | 272 |
| 273 if (values.size() < 7) |
| 274 return true; |
161 const int video_full_range_flag = values[6]; | 275 const int video_full_range_flag = values[6]; |
162 if (video_full_range_flag > 1) | 276 if (video_full_range_flag > 1) { |
| 277 DVLOG(3) << __func__ << " Invalid full range flag (" |
| 278 << video_full_range_flag << ")"; |
163 return false; | 279 return false; |
| 280 } |
| 281 |
| 282 if (values.size() < 8) |
| 283 return true; |
| 284 const int chroma_subsampling = values[7]; |
| 285 if (chroma_subsampling > 3 || |
| 286 (chroma_subsampling != 3 && matrix_coefficients == 0)) { |
| 287 DVLOG(3) << __func__ << " Invalid chroma subsampling (" |
| 288 << chroma_subsampling << ")"; |
| 289 return false; |
| 290 } |
164 | 291 |
165 return true; | 292 return true; |
166 } | 293 } |
167 | 294 |
168 bool ParseLegacyVp9CodecID(const std::string& codec_id, | 295 bool ParseLegacyVp9CodecID(const std::string& codec_id, |
169 VideoCodecProfile* profile, | 296 VideoCodecProfile* profile, |
170 uint8_t* level_idc) { | 297 uint8_t* level_idc) { |
171 if (codec_id == "vp9" || codec_id == "vp9.0") { | 298 if (codec_id == "vp9" || codec_id == "vp9.0") { |
172 // Profile is not included in the codec string. Assuming profile 0 to be | 299 // Profile is not included in the codec string. Assuming profile 0 to be |
173 // backward compatible. | 300 // backward compatible. |
(...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
525 | 652 |
526 return true; | 653 return true; |
527 } | 654 } |
528 #endif | 655 #endif |
529 | 656 |
530 VideoCodec StringToVideoCodec(const std::string& codec_id) { | 657 VideoCodec StringToVideoCodec(const std::string& codec_id) { |
531 std::vector<std::string> elem = base::SplitString( | 658 std::vector<std::string> elem = base::SplitString( |
532 codec_id, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); | 659 codec_id, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); |
533 if (elem.empty()) | 660 if (elem.empty()) |
534 return kUnknownVideoCodec; | 661 return kUnknownVideoCodec; |
| 662 |
535 VideoCodecProfile profile = VIDEO_CODEC_PROFILE_UNKNOWN; | 663 VideoCodecProfile profile = VIDEO_CODEC_PROFILE_UNKNOWN; |
536 uint8_t level = 0; | 664 uint8_t level = 0; |
| 665 gfx::ColorSpace::TransferID eotf = gfx::ColorSpace::TransferID::INVALID; |
| 666 |
537 if (codec_id == "vp8" || codec_id == "vp8.0") | 667 if (codec_id == "vp8" || codec_id == "vp8.0") |
538 return kCodecVP8; | 668 return kCodecVP8; |
539 if (ParseNewStyleVp9CodecID(codec_id, &profile, &level) || | 669 if (ParseNewStyleVp9CodecID(codec_id, &profile, &level, &eotf) || |
540 ParseLegacyVp9CodecID(codec_id, &profile, &level)) { | 670 ParseLegacyVp9CodecID(codec_id, &profile, &level)) { |
541 return kCodecVP9; | 671 return kCodecVP9; |
542 } | 672 } |
543 if (codec_id == "theora") | 673 if (codec_id == "theora") |
544 return kCodecTheora; | 674 return kCodecTheora; |
545 if (ParseAVCCodecId(codec_id, &profile, &level)) | 675 if (ParseAVCCodecId(codec_id, &profile, &level)) |
546 return kCodecH264; | 676 return kCodecH264; |
547 #if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER) | 677 #if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER) |
548 if (ParseAVCCodecId(TranslateLegacyAvc1CodecIds(codec_id), &profile, &level)) | 678 if (ParseAVCCodecId(TranslateLegacyAvc1CodecIds(codec_id), &profile, &level)) |
549 return kCodecH264; | 679 return kCodecH264; |
550 #endif | 680 #endif |
551 #if BUILDFLAG(ENABLE_HEVC_DEMUXING) | 681 #if BUILDFLAG(ENABLE_HEVC_DEMUXING) |
552 if (ParseHEVCCodecId(codec_id, &profile, &level)) | 682 if (ParseHEVCCodecId(codec_id, &profile, &level)) |
553 return kCodecHEVC; | 683 return kCodecHEVC; |
554 #endif | 684 #endif |
555 #if BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING) | 685 #if BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING) |
556 if (ParseDolbyVisionCodecId(codec_id, &profile, &level)) | 686 if (ParseDolbyVisionCodecId(codec_id, &profile, &level)) |
557 return kCodecDolbyVision; | 687 return kCodecDolbyVision; |
558 #endif | 688 #endif |
559 return kUnknownVideoCodec; | 689 return kUnknownVideoCodec; |
560 } | 690 } |
561 | 691 |
562 } // namespace media | 692 } // namespace media |
OLD | NEW |