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