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
3 // found in the LICENSE file.
4
5 #include "media/base/video_codecs.h"
6
7 #include "base/logging.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/string_split.h"
10 #include "base/strings/string_util.h"
11 #include "media/base/video_color_space.h"
12
13 namespace media {
14
15 // The names come from src/third_party/ffmpeg/libavcodec/codec_desc.c
GetCodecName(VideoCodec codec)16 std::string GetCodecName(VideoCodec codec) {
17 switch (codec) {
18 case kUnknownVideoCodec:
19 return "unknown";
20 case kCodecH264:
21 return "h264";
22 case kCodecHEVC:
23 return "hevc";
24 case kCodecDolbyVision:
25 return "dolbyvision";
26 case kCodecVC1:
27 return "vc1";
28 case kCodecMPEG2:
29 return "mpeg2video";
30 case kCodecMPEG4:
31 return "mpeg4";
32 case kCodecTheora:
33 return "theora";
34 case kCodecVP8:
35 return "vp8";
36 case kCodecVP9:
37 return "vp9";
38 case kCodecAV1:
39 return "av1";
40 }
41 NOTREACHED();
42 return "";
43 }
44
GetProfileName(VideoCodecProfile profile)45 std::string GetProfileName(VideoCodecProfile profile) {
46 switch (profile) {
47 case VIDEO_CODEC_PROFILE_UNKNOWN:
48 return "unknown";
49 case H264PROFILE_BASELINE:
50 return "h264 baseline";
51 case H264PROFILE_MAIN:
52 return "h264 main";
53 case H264PROFILE_EXTENDED:
54 return "h264 extended";
55 case H264PROFILE_HIGH:
56 return "h264 high";
57 case H264PROFILE_HIGH10PROFILE:
58 return "h264 high 10";
59 case H264PROFILE_HIGH422PROFILE:
60 return "h264 high 4:2:2";
61 case H264PROFILE_HIGH444PREDICTIVEPROFILE:
62 return "h264 high 4:4:4 predictive";
63 case H264PROFILE_SCALABLEBASELINE:
64 return "h264 scalable baseline";
65 case H264PROFILE_SCALABLEHIGH:
66 return "h264 scalable high";
67 case H264PROFILE_STEREOHIGH:
68 return "h264 stereo high";
69 case H264PROFILE_MULTIVIEWHIGH:
70 return "h264 multiview high";
71 case HEVCPROFILE_MAIN:
72 return "hevc main";
73 case HEVCPROFILE_MAIN10:
74 return "hevc main 10";
75 case HEVCPROFILE_MAIN_STILL_PICTURE:
76 return "hevc main still-picture";
77 case VP8PROFILE_ANY:
78 return "vp8";
79 case VP9PROFILE_PROFILE0:
80 return "vp9 profile0";
81 case VP9PROFILE_PROFILE1:
82 return "vp9 profile1";
83 case VP9PROFILE_PROFILE2:
84 return "vp9 profile2";
85 case VP9PROFILE_PROFILE3:
86 return "vp9 profile3";
87 case DOLBYVISION_PROFILE0:
88 return "dolby vision profile 0";
89 case DOLBYVISION_PROFILE4:
90 return "dolby vision profile 4";
91 case DOLBYVISION_PROFILE5:
92 return "dolby vision profile 5";
93 case DOLBYVISION_PROFILE7:
94 return "dolby vision profile 7";
95 case DOLBYVISION_PROFILE8:
96 return "dolby vision profile 8";
97 case DOLBYVISION_PROFILE9:
98 return "dolby vision profile 9";
99 case THEORAPROFILE_ANY:
100 return "theora";
101 case AV1PROFILE_PROFILE_MAIN:
102 return "av1 profile main";
103 case AV1PROFILE_PROFILE_HIGH:
104 return "av1 profile high";
105 case AV1PROFILE_PROFILE_PRO:
106 return "av1 profile pro";
107 }
108 NOTREACHED();
109 return "";
110 }
111
ParseNewStyleVp9CodecID(const std::string & codec_id,VideoCodecProfile * profile,uint8_t * level_idc,VideoColorSpace * color_space)112 bool ParseNewStyleVp9CodecID(const std::string& codec_id,
113 VideoCodecProfile* profile,
114 uint8_t* level_idc,
115 VideoColorSpace* color_space) {
116 // Initialize optional fields to their defaults.
117 *color_space = VideoColorSpace::REC709();
118
119 std::vector<std::string> fields = base::SplitString(
120 codec_id, ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
121
122 // First four fields are mandatory. No more than 9 fields are expected.
123 if (fields.size() < 4 || fields.size() > 9) {
124 DVLOG(3) << __func__ << " Invalid number of fields (" << fields.size()
125 << ")";
126 return false;
127 }
128
129 if (fields[0] != "vp09") {
130 DVLOG(3) << __func__ << " Invalid 4CC (" << fields[0] << ")";
131 return false;
132 }
133
134 std::vector<int> values;
135 for (size_t i = 1; i < fields.size(); ++i) {
136 // Missing value is not allowed.
137 if (fields[i] == "") {
138 DVLOG(3) << __func__ << " Invalid missing field (position:" << i << ")";
139 return false;
140 }
141 int value;
142 if (!base::StringToInt(fields[i], &value) || value < 0) {
143 DVLOG(3) << __func__ << " Invalid field value (" << value << ")";
144 return false;
145 }
146 values.push_back(value);
147 }
148
149 const int profile_idc = values[0];
150 switch (profile_idc) {
151 case 0:
152 *profile = VP9PROFILE_PROFILE0;
153 break;
154 case 1:
155 *profile = VP9PROFILE_PROFILE1;
156 break;
157 case 2:
158 *profile = VP9PROFILE_PROFILE2;
159 break;
160 case 3:
161 *profile = VP9PROFILE_PROFILE3;
162 break;
163 default:
164 DVLOG(3) << __func__ << " Invalid profile (" << profile_idc << ")";
165 return false;
166 }
167
168 *level_idc = values[1];
169 switch (*level_idc) {
170 case 10:
171 case 11:
172 case 20:
173 case 21:
174 case 30:
175 case 31:
176 case 40:
177 case 41:
178 case 50:
179 case 51:
180 case 52:
181 case 60:
182 case 61:
183 case 62:
184 break;
185 default:
186 DVLOG(3) << __func__ << " Invalid level (" << *level_idc << ")";
187 return false;
188 }
189
190 const int bit_depth = values[2];
191 if (bit_depth != 8 && bit_depth != 10 && bit_depth != 12) {
192 DVLOG(3) << __func__ << " Invalid bit-depth (" << bit_depth << ")";
193 return false;
194 }
195
196 if (values.size() < 4)
197 return true;
198 const int chroma_subsampling = values[3];
199 if (chroma_subsampling > 3) {
200 DVLOG(3) << __func__ << " Invalid chroma subsampling ("
201 << chroma_subsampling << ")";
202 return false;
203 }
204
205 if (values.size() < 5)
206 return true;
207 color_space->primaries = VideoColorSpace::GetPrimaryID(values[4]);
208 if (color_space->primaries == VideoColorSpace::PrimaryID::INVALID) {
209 DVLOG(3) << __func__ << " Invalid color primaries (" << values[4] << ")";
210 return false;
211 }
212
213 if (values.size() < 6)
214 return true;
215 color_space->transfer = VideoColorSpace::GetTransferID(values[5]);
216 if (color_space->transfer == VideoColorSpace::TransferID::INVALID) {
217 DVLOG(3) << __func__ << " Invalid transfer function (" << values[5] << ")";
218 return false;
219 }
220
221 if (values.size() < 7)
222 return true;
223 color_space->matrix = VideoColorSpace::GetMatrixID(values[6]);
224 if (color_space->matrix == VideoColorSpace::MatrixID::INVALID) {
225 DVLOG(3) << __func__ << " Invalid matrix coefficients (" << values[6]
226 << ")";
227 return false;
228 }
229 if (color_space->matrix == VideoColorSpace::MatrixID::RGB &&
230 chroma_subsampling != 3) {
231 DVLOG(3) << __func__ << " Invalid combination of chroma_subsampling ("
232 << ") and matrix coefficients (" << values[6] << ")";
233 }
234
235 if (values.size() < 8)
236 return true;
237 const int video_full_range_flag = values[7];
238 if (video_full_range_flag > 1) {
239 DVLOG(3) << __func__ << " Invalid full range flag ("
240 << video_full_range_flag << ")";
241 return false;
242 }
243 color_space->range = video_full_range_flag == 1
244 ? gfx::ColorSpace::RangeID::FULL
245 : gfx::ColorSpace::RangeID::LIMITED;
246
247 return true;
248 }
249
ParseLegacyVp9CodecID(const std::string & codec_id,VideoCodecProfile * profile,uint8_t * level_idc)250 bool ParseLegacyVp9CodecID(const std::string& codec_id,
251 VideoCodecProfile* profile,
252 uint8_t* level_idc) {
253 if (codec_id == "vp9" || codec_id == "vp9.0") {
254 // Profile is not included in the codec string. Consumers of parsed codec
255 // should handle by rejecting ambiguous string or resolving to a default
256 // profile.
257 *profile = VIDEO_CODEC_PROFILE_UNKNOWN;
258 // Use 0 to indicate unknown level.
259 *level_idc = 0;
260 return true;
261 }
262 return false;
263 }
264
265 #if BUILDFLAG(ENABLE_AV1_DECODER)
ParseAv1CodecId(const std::string & codec_id,VideoCodecProfile * profile,uint8_t * level_idc,VideoColorSpace * color_space)266 bool ParseAv1CodecId(const std::string& codec_id,
267 VideoCodecProfile* profile,
268 uint8_t* level_idc,
269 VideoColorSpace* color_space) {
270 // The codecs parameter string for the AOM AV1 codec is as follows:
271 // See https://aomediacodec.github.io/av1-isobmff/#codecsparam.
272 //
273 // <sample entry4CC>.<profile>.<level><tier>.<bitDepth>.<monochrome>.
274 // <chromaSubsampling>.<colorPrimaries>.<transferCharacteristics>.
275 // <matrixCoefficients>.<videoFullRangeFlag>
276
277 std::vector<std::string> fields = base::SplitString(
278 codec_id, ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
279
280 // The parameters sample entry 4CC, profile, level, tier, and bitDepth are all
281 // mandatory fields. If any of these fields are empty, or not within their
282 // allowed range, the processing device SHOULD treat it as an error.
283 if (fields.size() < 4 || fields.size() > 10) {
284 DVLOG(3) << __func__ << " Invalid number of fields (" << fields.size()
285 << ")";
286 return false;
287 }
288
289 // All the other fields (including their leading '.') are optional, mutually
290 // inclusive (all or none) fields. If not specified then the values listed in
291 // the table below are assumed.
292 //
293 // mono_chrome 0
294 // chromaSubsampling 112 (4:2:0 colocated with luma (0,0))
295 // colorPrimaries 1 (ITU-R BT.709)
296 // transferCharacteristics 1 (ITU-R BT.709)
297 // matrixCoefficients 1 (ITU-R BT.709)
298 // videoFullRangeFlag 0 (studio swing representation)
299 *color_space = VideoColorSpace::REC709();
300
301 if (fields[0] != "av01") {
302 DVLOG(3) << __func__ << " Invalid AV1 4CC (" << fields[0] << ")";
303 return false;
304 }
305
306 // The level parameter value SHALL equal the first level value indicated by
307 // seq_level_idx in the Sequence Header. The tier parameter value SHALL be
308 // equal to M when the first seq_tier value in the Sequence Header is equal to
309 // 0, and H when it is equal to 1.
310 if (fields[2].size() != 3 || (fields[2][2] != 'M' && fields[2][2] != 'H')) {
311 DVLOG(3) << __func__ << " Invalid level+tier (" << fields[2] << ")";
312 return false;
313 }
314
315 // Since tier has been validated, strip the trailing tier indicator to allow
316 // int conversion below.
317 fields[2].resize(2);
318
319 // Fill with dummy values to ensure parallel indices with fields.
320 std::vector<int> values(fields.size(), 0);
321 for (size_t i = 1; i < fields.size(); ++i) {
322 if (fields[i].empty()) {
323 DVLOG(3) << __func__ << " Invalid empty field (position:" << i << ")";
324 return false;
325 }
326
327 if (!base::StringToInt(fields[i], &values[i]) || values[i] < 0) {
328 DVLOG(3) << __func__ << " Invalid field value (" << values[i] << ")";
329 return false;
330 }
331 }
332
333 // The profile parameter value, represented by a single digit decimal, SHALL
334 // equal the value of seq_profile in the Sequence Header.
335 const int profile_idc = fields[1].size() == 1 ? values[1] : -1;
336 switch (profile_idc) {
337 case 0:
338 *profile = AV1PROFILE_PROFILE_MAIN;
339 break;
340 case 1:
341 *profile = AV1PROFILE_PROFILE_HIGH;
342 break;
343 case 2:
344 *profile = AV1PROFILE_PROFILE_PRO;
345 break;
346 default:
347 DVLOG(3) << __func__ << " Invalid profile (" << fields[1] << ")";
348 return false;
349 }
350
351 // The level parameter value SHALL equal the first level value indicated by
352 // seq_level_idx in the Sequence Header. Note: We validate that this field has
353 // the required leading zeros above.
354 *level_idc = values[2];
355 if (*level_idc > 31) {
356 DVLOG(3) << __func__ << " Invalid level (" << *level_idc << ")";
357 return false;
358 }
359
360 // The bitDepth parameter value SHALL equal the value of BitDepth variable as
361 // defined in [AV1] derived from the Sequence Header. Leading zeros required.
362 const int bit_depth = values[3];
363 if (fields[3].size() != 2 ||
364 (bit_depth != 8 && bit_depth != 10 && bit_depth != 12)) {
365 DVLOG(3) << __func__ << " Invalid bit-depth (" << fields[3] << ")";
366 return false;
367 }
368
369 if (values.size() <= 4)
370 return true;
371
372 // The monochrome parameter value, represented by a single digit decimal,
373 // SHALL equal the value of mono_chrome in the Sequence Header.
374 const int monochrome = values[4];
375 if (fields[4].size() != 1 || monochrome > 1) {
376 DVLOG(3) << __func__ << " Invalid monochrome (" << fields[4] << ")";
377 return false;
378 }
379
380 if (values.size() <= 5)
381 return true;
382
383 // The chromaSubsampling parameter value, represented by a three-digit
384 // decimal, SHALL have its first digit equal to subsampling_x and its second
385 // digit equal to subsampling_y. If both subsampling_x and subsampling_y are
386 // set to 1, then the third digit SHALL be equal to chroma_sample_position,
387 // otherwise it SHALL be set to 0.
388 if (fields[5].size() != 3) {
389 DVLOG(3) << __func__ << " Invalid chroma subsampling (" << fields[5] << ")";
390 return false;
391 }
392
393 const char subsampling_x = fields[5][0];
394 const char subsampling_y = fields[5][1];
395 const char chroma_sample_position = fields[5][2];
396 if ((subsampling_x < '0' || subsampling_x > '1') ||
397 (subsampling_y < '0' || subsampling_y > '1') ||
398 (chroma_sample_position < '0' || chroma_sample_position > '3')) {
399 DVLOG(3) << __func__ << " Invalid chroma subsampling (" << fields[5] << ")";
400 return false;
401 }
402
403 if (((subsampling_x == '0' || subsampling_y == '0') &&
404 chroma_sample_position != '0')) {
405 DVLOG(3) << __func__ << " Invalid chroma subsampling (" << fields[5] << ")";
406 return false;
407 }
408
409 if (values.size() <= 6)
410 return true;
411
412 // The colorPrimaries, transferCharacteristics, matrixCoefficients and
413 // videoFullRangeFlag parameter values SHALL equal the value of matching
414 // fields in the Sequence Header, if color_description_present_flag is set to
415 // 1, otherwise they SHOULD not be set, defaulting to the values below. The
416 // videoFullRangeFlag is represented by a single digit.
417 color_space->primaries = VideoColorSpace::GetPrimaryID(values[6]);
418 if (fields[6].size() != 2 ||
419 color_space->primaries == VideoColorSpace::PrimaryID::INVALID) {
420 DVLOG(3) << __func__ << " Invalid color primaries (" << fields[6] << ")";
421 return false;
422 }
423
424 if (values.size() <= 7)
425 return true;
426
427 color_space->transfer = VideoColorSpace::GetTransferID(values[7]);
428 if (fields[7].size() != 2 ||
429 color_space->transfer == VideoColorSpace::TransferID::INVALID) {
430 DVLOG(3) << __func__ << " Invalid transfer function (" << fields[7] << ")";
431 return false;
432 }
433
434 if (values.size() <= 8)
435 return true;
436
437 color_space->matrix = VideoColorSpace::GetMatrixID(values[8]);
438 if (fields[8].size() != 2 ||
439 color_space->matrix == VideoColorSpace::MatrixID::INVALID) {
440 // TODO(dalecurtis): AV1 allows a few matrices we don't support yet.
441 // https://crbug.com/854290
442 if (values[8] == 12 || values[8] == 13 || values[8] == 14) {
443 DVLOG(3) << __func__ << " Unsupported matrix coefficients (" << fields[8]
444 << ")";
445 } else {
446 DVLOG(3) << __func__ << " Invalid matrix coefficients (" << fields[8]
447 << ")";
448 }
449 return false;
450 }
451
452 if (values.size() <= 9)
453 return true;
454
455 const int video_full_range_flag = values[9];
456 if (fields[9].size() != 1 || video_full_range_flag > 1) {
457 DVLOG(3) << __func__ << " Invalid full range flag (" << fields[9] << ")";
458 return false;
459 }
460 color_space->range = video_full_range_flag == 1
461 ? gfx::ColorSpace::RangeID::FULL
462 : gfx::ColorSpace::RangeID::LIMITED;
463
464 return true;
465 }
466 #endif // BUILDFLAG(ENABLE_AV1_DECODER)
467
ParseAVCCodecId(const std::string & codec_id,VideoCodecProfile * profile,uint8_t * level_idc)468 bool ParseAVCCodecId(const std::string& codec_id,
469 VideoCodecProfile* profile,
470 uint8_t* level_idc) {
471 // Make sure we have avc1.xxxxxx or avc3.xxxxxx , where xxxxxx are hex digits
472 if (!base::StartsWith(codec_id, "avc1.", base::CompareCase::SENSITIVE) &&
473 !base::StartsWith(codec_id, "avc3.", base::CompareCase::SENSITIVE)) {
474 return false;
475 }
476 uint32_t elem = 0;
477 if (codec_id.size() != 11 ||
478 !base::HexStringToUInt(base::StringPiece(codec_id).substr(5), &elem)) {
479 DVLOG(4) << __func__ << ": invalid avc codec id (" << codec_id << ")";
480 return false;
481 }
482
483 uint8_t level_byte = elem & 0xFF;
484 uint8_t constraints_byte = (elem >> 8) & 0xFF;
485 uint8_t profile_idc = (elem >> 16) & 0xFF;
486
487 // Check that the lower two bits of |constraints_byte| are zero (those are
488 // reserved and must be zero according to ISO IEC 14496-10).
489 if (constraints_byte & 3) {
490 DVLOG(4) << __func__ << ": non-zero reserved bits in codec id " << codec_id;
491 return false;
492 }
493
494 VideoCodecProfile out_profile = VIDEO_CODEC_PROFILE_UNKNOWN;
495 // profile_idc values for each profile are taken from ISO IEC 14496-10 and
496 // https://en.wikipedia.org/wiki/H.264/MPEG-4_AVC#Profiles
497 switch (profile_idc) {
498 case 66:
499 out_profile = H264PROFILE_BASELINE;
500 break;
501 case 77:
502 out_profile = H264PROFILE_MAIN;
503 break;
504 case 83:
505 out_profile = H264PROFILE_SCALABLEBASELINE;
506 break;
507 case 86:
508 out_profile = H264PROFILE_SCALABLEHIGH;
509 break;
510 case 88:
511 out_profile = H264PROFILE_EXTENDED;
512 break;
513 case 100:
514 out_profile = H264PROFILE_HIGH;
515 break;
516 case 110:
517 out_profile = H264PROFILE_HIGH10PROFILE;
518 break;
519 case 118:
520 out_profile = H264PROFILE_MULTIVIEWHIGH;
521 break;
522 case 122:
523 out_profile = H264PROFILE_HIGH422PROFILE;
524 break;
525 case 128:
526 out_profile = H264PROFILE_STEREOHIGH;
527 break;
528 case 244:
529 out_profile = H264PROFILE_HIGH444PREDICTIVEPROFILE;
530 break;
531 default:
532 DVLOG(1) << "Warning: unrecognized AVC/H.264 profile " << profile_idc;
533 return false;
534 }
535
536 // TODO(servolk): Take into account also constraint set flags 3 through 5.
537 uint8_t constraint_set0_flag = (constraints_byte >> 7) & 1;
538 uint8_t constraint_set1_flag = (constraints_byte >> 6) & 1;
539 uint8_t constraint_set2_flag = (constraints_byte >> 5) & 1;
540 if (constraint_set2_flag && out_profile > H264PROFILE_EXTENDED) {
541 out_profile = H264PROFILE_EXTENDED;
542 }
543 if (constraint_set1_flag && out_profile > H264PROFILE_MAIN) {
544 out_profile = H264PROFILE_MAIN;
545 }
546 if (constraint_set0_flag && out_profile > H264PROFILE_BASELINE) {
547 out_profile = H264PROFILE_BASELINE;
548 }
549
550 if (level_idc)
551 *level_idc = level_byte;
552
553 if (profile)
554 *profile = out_profile;
555
556 return true;
557 }
558
559 #if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)
560 static const char kHexString[] = "0123456789ABCDEF";
IntToHex(int i)561 static char IntToHex(int i) {
562 DCHECK_GE(i, 0) << i << " not a hex value";
563 DCHECK_LE(i, 15) << i << " not a hex value";
564 return kHexString[i];
565 }
566
TranslateLegacyAvc1CodecIds(const std::string & codec_id)567 std::string TranslateLegacyAvc1CodecIds(const std::string& codec_id) {
568 // Special handling for old, pre-RFC 6381 format avc1 strings, which are still
569 // being used by some HLS apps to preserve backward compatibility with older
570 // iOS devices. The old format was avc1.<profile>.<level>
571 // Where <profile> is H.264 profile_idc encoded as a decimal number, i.e.
572 // 66 is baseline profile (0x42)
573 // 77 is main profile (0x4d)
574 // 100 is high profile (0x64)
575 // And <level> is H.264 level multiplied by 10, also encoded as decimal number
576 // E.g. <level> 31 corresponds to H.264 level 3.1
577 // See, for example, http://qtdevseed.apple.com/qadrift/testcases/tc-0133.php
578 uint32_t level_start = 0;
579 std::string result;
580 if (base::StartsWith(codec_id, "avc1.66.", base::CompareCase::SENSITIVE)) {
581 level_start = 8;
582 result = "avc1.4200";
583 } else if (base::StartsWith(codec_id, "avc1.77.",
584 base::CompareCase::SENSITIVE)) {
585 level_start = 8;
586 result = "avc1.4D00";
587 } else if (base::StartsWith(codec_id, "avc1.100.",
588 base::CompareCase::SENSITIVE)) {
589 level_start = 9;
590 result = "avc1.6400";
591 }
592
593 uint32_t level = 0;
594 if (level_start > 0 &&
595 base::StringToUint(codec_id.substr(level_start), &level) && level < 256) {
596 // This is a valid legacy avc1 codec id - return the codec id translated
597 // into RFC 6381 format.
598 result.push_back(IntToHex(level >> 4));
599 result.push_back(IntToHex(level & 0xf));
600 return result;
601 }
602
603 // This is not a valid legacy avc1 codec id - return the original codec id.
604 return codec_id;
605 }
606 #endif
607
608 #if BUILDFLAG(ENABLE_PLATFORM_HEVC)
609 // The specification for HEVC codec id strings can be found in ISO IEC 14496-15
610 // dated 2012 or newer in the Annex E.3
ParseHEVCCodecId(const std::string & codec_id,VideoCodecProfile * profile,uint8_t * level_idc)611 bool ParseHEVCCodecId(const std::string& codec_id,
612 VideoCodecProfile* profile,
613 uint8_t* level_idc) {
614 if (!base::StartsWith(codec_id, "hev1.", base::CompareCase::SENSITIVE) &&
615 !base::StartsWith(codec_id, "hvc1.", base::CompareCase::SENSITIVE)) {
616 return false;
617 }
618
619 // HEVC codec id consists of:
620 const int kMaxHevcCodecIdLength =
621 5 + // 'hev1.' or 'hvc1.' prefix (5 chars)
622 4 + // profile, e.g. '.A12' (max 4 chars)
623 9 + // profile_compatibility, dot + 32-bit hex number (max 9 chars)
624 5 + // tier and level, e.g. '.H120' (max 5 chars)
625 18; // up to 6 constraint bytes, bytes are dot-separated and hex-encoded.
626
627 if (codec_id.size() > kMaxHevcCodecIdLength) {
628 DVLOG(4) << __func__ << ": Codec id is too long (" << codec_id << ")";
629 return false;
630 }
631
632 std::vector<std::string> elem = base::SplitString(
633 codec_id, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
634 DCHECK(elem[0] == "hev1" || elem[0] == "hvc1");
635
636 if (elem.size() < 4) {
637 DVLOG(4) << __func__ << ": invalid HEVC codec id " << codec_id;
638 return false;
639 }
640
641 uint8_t general_profile_space = 0;
642 if (elem[1].size() > 0 &&
643 (elem[1][0] == 'A' || elem[1][0] == 'B' || elem[1][0] == 'C')) {
644 general_profile_space = 1 + (elem[1][0] - 'A');
645 elem[1].erase(0, 1);
646 }
647 DCHECK(general_profile_space >= 0 && general_profile_space <= 3);
648
649 unsigned general_profile_idc = 0;
650 if (!base::StringToUint(elem[1], &general_profile_idc) ||
651 general_profile_idc > 0x1f) {
652 DVLOG(4) << __func__ << ": invalid general_profile_idc=" << elem[1];
653 return false;
654 }
655
656 uint32_t general_profile_compatibility_flags = 0;
657 if (!base::HexStringToUInt(elem[2], &general_profile_compatibility_flags)) {
658 DVLOG(4) << __func__
659 << ": invalid general_profile_compatibility_flags=" << elem[2];
660 return false;
661 }
662
663 if (profile) {
664 // TODO(servolk): Handle format range extension profiles as explained in
665 // HEVC standard (ISO/IEC ISO/IEC 23008-2) section A.3.5
666 if (general_profile_idc == 3 || (general_profile_compatibility_flags & 4)) {
667 *profile = HEVCPROFILE_MAIN_STILL_PICTURE;
668 }
669 if (general_profile_idc == 2 || (general_profile_compatibility_flags & 2)) {
670 *profile = HEVCPROFILE_MAIN10;
671 }
672 if (general_profile_idc == 1 || (general_profile_compatibility_flags & 1)) {
673 *profile = HEVCPROFILE_MAIN;
674 }
675 }
676
677 uint8_t general_tier_flag;
678 if (elem[3].size() > 0 && (elem[3][0] == 'L' || elem[3][0] == 'H')) {
679 general_tier_flag = (elem[3][0] == 'L') ? 0 : 1;
680 elem[3].erase(0, 1);
681 } else {
682 DVLOG(4) << __func__ << ": invalid general_tier_flag=" << elem[3];
683 return false;
684 }
685 DCHECK(general_tier_flag == 0 || general_tier_flag == 1);
686
687 unsigned general_level_idc = 0;
688 if (!base::StringToUint(elem[3], &general_level_idc) ||
689 general_level_idc > 0xff) {
690 DVLOG(4) << __func__ << ": invalid general_level_idc=" << elem[3];
691 return false;
692 }
693
694 if (level_idc)
695 *level_idc = static_cast<uint8_t>(general_level_idc);
696
697 uint8_t constraint_flags[6];
698 memset(constraint_flags, 0, sizeof(constraint_flags));
699
700 if (elem.size() > 10) {
701 DVLOG(4) << __func__ << ": unexpected number of trailing bytes in HEVC "
702 << "codec id " << codec_id;
703 return false;
704 }
705 for (size_t i = 4; i < elem.size(); ++i) {
706 unsigned constr_byte = 0;
707 if (!base::HexStringToUInt(elem[i], &constr_byte) || constr_byte > 0xFF) {
708 DVLOG(4) << __func__ << ": invalid constraint byte=" << elem[i];
709 return false;
710 }
711 constraint_flags[i - 4] = constr_byte;
712 }
713
714 return true;
715 }
716 #endif
717
718 #if BUILDFLAG(ENABLE_PLATFORM_DOLBY_VISION)
IsDolbyVisionAVCCodecId(const std::string & codec_id)719 bool IsDolbyVisionAVCCodecId(const std::string& codec_id) {
720 return base::StartsWith(codec_id, "dva1.", base::CompareCase::SENSITIVE) ||
721 base::StartsWith(codec_id, "dvav.", base::CompareCase::SENSITIVE);
722 }
723
IsDolbyVisionHEVCCodecId(const std::string & codec_id)724 bool IsDolbyVisionHEVCCodecId(const std::string& codec_id) {
725 return base::StartsWith(codec_id, "dvh1.", base::CompareCase::SENSITIVE) ||
726 base::StartsWith(codec_id, "dvhe.", base::CompareCase::SENSITIVE);
727 }
728
729 // The specification for Dolby Vision codec id strings can be found in Dolby
730 // Vision streams within the MPEG-DASH format.
ParseDolbyVisionCodecId(const std::string & codec_id,VideoCodecProfile * profile,uint8_t * level_idc)731 bool ParseDolbyVisionCodecId(const std::string& codec_id,
732 VideoCodecProfile* profile,
733 uint8_t* level_idc) {
734 if (!IsDolbyVisionAVCCodecId(codec_id) &&
735 !IsDolbyVisionHEVCCodecId(codec_id)) {
736 return false;
737 }
738
739 const int kMaxDvCodecIdLength = 5 // FOURCC string
740 + 1 // delimiting period
741 + 2 // profile id as 2 digit string
742 + 1 // delimiting period
743 + 2; // level id as 2 digit string.
744
745 if (codec_id.size() > kMaxDvCodecIdLength) {
746 DVLOG(4) << __func__ << ": Codec id is too long (" << codec_id << ")";
747 return false;
748 }
749
750 std::vector<std::string> elem = base::SplitString(
751 codec_id, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
752 DCHECK(elem[0] == "dvh1" || elem[0] == "dvhe" || elem[0] == "dva1" ||
753 elem[0] == "dvav");
754
755 if (elem.size() != 3) {
756 DVLOG(4) << __func__ << ": invalid dolby vision codec id " << codec_id;
757 return false;
758 }
759
760 // Profile string should be two digits.
761 unsigned profile_id = 0;
762 if (elem[1].size() != 2 || !base::StringToUint(elem[1], &profile_id) ||
763 profile_id > 9) {
764 DVLOG(4) << __func__ << ": invalid format or profile_id=" << elem[1];
765 return false;
766 }
767
768 // Only profiles 0, 4, 5, 7, 8 and 9 are valid. Profile 0 and 9 are encoded
769 // based on AVC while profile 4, 5, 7 and 8 are based on HEVC.
770 switch (profile_id) {
771 case 0:
772 case 9:
773 if (!IsDolbyVisionAVCCodecId(codec_id)) {
774 DVLOG(4) << __func__
775 << ": codec id is mismatched with profile_id=" << profile_id;
776 return false;
777 }
778 if (profile_id == 0)
779 *profile = DOLBYVISION_PROFILE0;
780 else if (profile_id == 9)
781 *profile = DOLBYVISION_PROFILE9;
782 break;
783 #if BUILDFLAG(ENABLE_PLATFORM_HEVC)
784 case 4:
785 case 5:
786 case 7:
787 case 8:
788 if (!IsDolbyVisionHEVCCodecId(codec_id)) {
789 DVLOG(4) << __func__
790 << ": codec id is mismatched with profile_id=" << profile_id;
791 return false;
792 }
793 if (profile_id == 4)
794 *profile = DOLBYVISION_PROFILE4;
795 else if (profile_id == 5)
796 *profile = DOLBYVISION_PROFILE5;
797 else if (profile_id == 7)
798 *profile = DOLBYVISION_PROFILE7;
799 else if (profile_id == 8)
800 *profile = DOLBYVISION_PROFILE8;
801 break;
802 #endif
803 default:
804 DVLOG(4) << __func__
805 << ": depecrated and not supported profile_id=" << profile_id;
806 return false;
807 }
808
809 // Level string should be two digits.
810 unsigned level_id = 0;
811 if (elem[2].size() != 2 || !base::StringToUint(elem[2], &level_id) ||
812 level_id > 9 || level_id < 1) {
813 DVLOG(4) << __func__ << ": invalid format level_id=" << elem[2];
814 return false;
815 }
816
817 *level_idc = level_id;
818
819 return true;
820 }
821 #endif
822
StringToVideoCodec(const std::string & codec_id)823 VideoCodec StringToVideoCodec(const std::string& codec_id) {
824 std::vector<std::string> elem = base::SplitString(
825 codec_id, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
826 if (elem.empty())
827 return kUnknownVideoCodec;
828
829 VideoCodecProfile profile = VIDEO_CODEC_PROFILE_UNKNOWN;
830 uint8_t level = 0;
831 VideoColorSpace color_space;
832
833 if (codec_id == "vp8" || codec_id == "vp8.0")
834 return kCodecVP8;
835 if (ParseNewStyleVp9CodecID(codec_id, &profile, &level, &color_space) ||
836 ParseLegacyVp9CodecID(codec_id, &profile, &level)) {
837 return kCodecVP9;
838 }
839
840 #if BUILDFLAG(ENABLE_AV1_DECODER)
841 if (ParseAv1CodecId(codec_id, &profile, &level, &color_space))
842 return kCodecAV1;
843 #endif
844
845 if (codec_id == "theora")
846 return kCodecTheora;
847 if (ParseAVCCodecId(codec_id, &profile, &level))
848 return kCodecH264;
849 #if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)
850 if (ParseAVCCodecId(TranslateLegacyAvc1CodecIds(codec_id), &profile, &level))
851 return kCodecH264;
852 #endif
853 #if BUILDFLAG(ENABLE_PLATFORM_HEVC)
854 if (ParseHEVCCodecId(codec_id, &profile, &level))
855 return kCodecHEVC;
856 #endif
857 #if BUILDFLAG(ENABLE_PLATFORM_DOLBY_VISION)
858 if (ParseDolbyVisionCodecId(codec_id, &profile, &level))
859 return kCodecDolbyVision;
860 #endif
861 return kUnknownVideoCodec;
862 }
863
864 } // namespace media
865