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