3bd01bfce881d0968978c16ea0b14785738a10c0
[platform/framework/web/chromium-efl.git] / media / base / video_codecs.cc
1 // Copyright 2015 The Chromium Authors
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_piece.h"
11 #include "base/strings/string_split.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "media/base/video_color_space.h"
15 #include "ui/gfx/color_space.h"
16
17 namespace media {
18
19 // The names come from src/third_party/ffmpeg/libavcodec/codec_desc.c
20 // TODO(crbug.com/1357080): The returned strings are used by ChunkDemuxer in
21 // the code logic as well in tests. Merge with GetCodecNameForUMA() if possible.
22 std::string GetCodecName(VideoCodec codec) {
23   switch (codec) {
24     case VideoCodec::kUnknown:
25       return "unknown";
26     case VideoCodec::kH264:
27       return "h264";
28     case VideoCodec::kHEVC:
29       return "hevc";
30     case VideoCodec::kDolbyVision:
31       return "dolbyvision";
32     case VideoCodec::kVC1:
33       return "vc1";
34     case VideoCodec::kMPEG2:
35       return "mpeg2video";
36     case VideoCodec::kMPEG4:
37       return "mpeg4";
38     case VideoCodec::kTheora:
39       return "theora";
40     case VideoCodec::kVP8:
41       return "vp8";
42     case VideoCodec::kVP9:
43       return "vp9";
44     case VideoCodec::kAV1:
45       return "av1";
46   }
47   NOTREACHED_NORETURN();
48 }
49
50 // Reported as part of some UMA names. NEVER change existing strings!
51 std::string GetCodecNameForUMA(VideoCodec codec) {
52   switch (codec) {
53     case VideoCodec::kUnknown:
54       return "Unknown";
55     case VideoCodec::kH264:
56       return "H264";
57     case VideoCodec::kHEVC:
58       return "HEVC";
59     case VideoCodec::kDolbyVision:
60       return "DolbyVision";
61     case VideoCodec::kVC1:
62       return "VC1";
63     case VideoCodec::kMPEG2:
64       return "MPEG2Video";
65     case VideoCodec::kMPEG4:
66       return "MPEG4";
67     case VideoCodec::kTheora:
68       return "Theora";
69     case VideoCodec::kVP8:
70       return "VP8";
71     case VideoCodec::kVP9:
72       return "VP9";
73     case VideoCodec::kAV1:
74       return "AV1";
75   }
76   NOTREACHED_NORETURN();
77 }
78
79 std::string GetProfileName(VideoCodecProfile profile) {
80   switch (profile) {
81     case VIDEO_CODEC_PROFILE_UNKNOWN:
82       return "unknown";
83     case H264PROFILE_BASELINE:
84       return "h264 baseline";
85     case H264PROFILE_MAIN:
86       return "h264 main";
87     case H264PROFILE_EXTENDED:
88       return "h264 extended";
89     case H264PROFILE_HIGH:
90       return "h264 high";
91     case H264PROFILE_HIGH10PROFILE:
92       return "h264 high 10";
93     case H264PROFILE_HIGH422PROFILE:
94       return "h264 high 4:2:2";
95     case H264PROFILE_HIGH444PREDICTIVEPROFILE:
96       return "h264 high 4:4:4 predictive";
97     case H264PROFILE_SCALABLEBASELINE:
98       return "h264 scalable baseline";
99     case H264PROFILE_SCALABLEHIGH:
100       return "h264 scalable high";
101     case H264PROFILE_STEREOHIGH:
102       return "h264 stereo high";
103     case H264PROFILE_MULTIVIEWHIGH:
104       return "h264 multiview high";
105     case HEVCPROFILE_MAIN:
106       return "hevc main";
107     case HEVCPROFILE_MAIN10:
108       return "hevc main 10";
109     case HEVCPROFILE_MAIN_STILL_PICTURE:
110       return "hevc main still-picture";
111     case HEVCPROFILE_REXT:
112       return "hevc range extensions";
113     case HEVCPROFILE_HIGH_THROUGHPUT:
114       return "hevc high throughput";
115     case HEVCPROFILE_MULTIVIEW_MAIN:
116       return "hevc multiview main";
117     case HEVCPROFILE_SCALABLE_MAIN:
118       return "hevc scalable main";
119     case HEVCPROFILE_3D_MAIN:
120       return "hevc 3d main";
121     case HEVCPROFILE_SCREEN_EXTENDED:
122       return "hevc screen extended";
123     case HEVCPROFILE_SCALABLE_REXT:
124       return "hevc scalable range extensions";
125     case HEVCPROFILE_HIGH_THROUGHPUT_SCREEN_EXTENDED:
126       return "hevc high throughput screen extended";
127     case VP8PROFILE_ANY:
128       return "vp8";
129     case VP9PROFILE_PROFILE0:
130       return "vp9 profile0";
131     case VP9PROFILE_PROFILE1:
132       return "vp9 profile1";
133     case VP9PROFILE_PROFILE2:
134       return "vp9 profile2";
135     case VP9PROFILE_PROFILE3:
136       return "vp9 profile3";
137     case DOLBYVISION_PROFILE0:
138       return "dolby vision profile 0";
139     case DOLBYVISION_PROFILE4:
140       return "dolby vision profile 4";
141     case DOLBYVISION_PROFILE5:
142       return "dolby vision profile 5";
143     case DOLBYVISION_PROFILE7:
144       return "dolby vision profile 7";
145     case DOLBYVISION_PROFILE8:
146       return "dolby vision profile 8";
147     case DOLBYVISION_PROFILE9:
148       return "dolby vision profile 9";
149     case THEORAPROFILE_ANY:
150       return "theora";
151     case AV1PROFILE_PROFILE_MAIN:
152       return "av1 profile main";
153     case AV1PROFILE_PROFILE_HIGH:
154       return "av1 profile high";
155     case AV1PROFILE_PROFILE_PRO:
156       return "av1 profile pro";
157     case VVCPROFILE_MAIN10:
158       return "vvc profile main10";
159     case VVCPROFILE_MAIN12:
160       return "vvc profile main12";
161     case VVCPROFILE_MAIN12_INTRA:
162       return "vvc profile main12 intra";
163     case VVCPROIFLE_MULTILAYER_MAIN10:
164       return "vvc profile multilayer main10";
165     case VVCPROFILE_MAIN10_444:
166       return "vvc profile main10 444";
167     case VVCPROFILE_MAIN12_444:
168       return "vvc profile main12 444";
169     case VVCPROFILE_MAIN16_444:
170       return "vvc profile main16 444";
171     case VVCPROFILE_MAIN12_444_INTRA:
172       return "vvc profile main12 444 intra";
173     case VVCPROFILE_MAIN16_444_INTRA:
174       return "vvc profile main16 444 intra";
175     case VVCPROFILE_MULTILAYER_MAIN10_444:
176       return "vvc profile multilayer main10 444";
177     case VVCPROFILE_MAIN10_STILL_PICTURE:
178       return "vvc profile main10 still picture";
179     case VVCPROFILE_MAIN12_STILL_PICTURE:
180       return "vvc profile main12 still picture";
181     case VVCPROFILE_MAIN10_444_STILL_PICTURE:
182       return "vvc profile main10 444 still picture";
183     case VVCPROFILE_MAIN12_444_STILL_PICTURE:
184       return "vvc profile main12 444 still picture";
185     case VVCPROFILE_MAIN16_444_STILL_PICTURE:
186       return "vvc profile main16 444 still picture";
187   }
188   NOTREACHED_NORETURN();
189 }
190
191 std::string BuildH264MimeSuffix(media::VideoCodecProfile profile,
192                                 uint8_t level) {
193   std::string profile_str;
194   switch (profile) {
195     case media::VideoCodecProfile::H264PROFILE_BASELINE:
196       profile_str = "42";
197       break;
198     case media::VideoCodecProfile::H264PROFILE_MAIN:
199       profile_str = "4d";
200       break;
201     case media::VideoCodecProfile::H264PROFILE_SCALABLEBASELINE:
202       profile_str = "53";
203       break;
204     case media::VideoCodecProfile::H264PROFILE_SCALABLEHIGH:
205       profile_str = "56";
206       break;
207     case media::VideoCodecProfile::H264PROFILE_EXTENDED:
208       profile_str = "58";
209       break;
210     case media::VideoCodecProfile::H264PROFILE_HIGH:
211       profile_str = "64";
212       break;
213     case media::VideoCodecProfile::H264PROFILE_HIGH10PROFILE:
214       profile_str = "6e";
215       break;
216     case media::VideoCodecProfile::H264PROFILE_MULTIVIEWHIGH:
217       profile_str = "76";
218       break;
219     case media::VideoCodecProfile::H264PROFILE_HIGH422PROFILE:
220       profile_str = "7a";
221       break;
222     case media::VideoCodecProfile::H264PROFILE_STEREOHIGH:
223       profile_str = "80";
224       break;
225     case media::VideoCodecProfile::H264PROFILE_HIGH444PREDICTIVEPROFILE:
226       profile_str = "f4";
227       break;
228     default:
229       return "";
230   }
231
232   return base::StringPrintf(".%s%04x", profile_str.c_str(), level);
233 }
234
235 bool ParseNewStyleVp9CodecID(base::StringPiece codec_id,
236                              VideoCodecProfile* profile,
237                              uint8_t* level_idc,
238                              VideoColorSpace* color_space) {
239   // Initialize optional fields to their defaults.
240   *color_space = VideoColorSpace::REC709();
241
242   std::vector<std::string> fields = base::SplitString(
243       codec_id, ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
244
245   // First four fields are mandatory. No more than 9 fields are expected.
246   if (fields.size() < 4 || fields.size() > 9) {
247     DVLOG(3) << __func__ << " Invalid number of fields (" << fields.size()
248              << ")";
249     return false;
250   }
251
252   if (fields[0] != "vp09") {
253     DVLOG(3) << __func__ << " Invalid 4CC (" << fields[0] << ")";
254     return false;
255   }
256
257   std::vector<int> values;
258   for (size_t i = 1; i < fields.size(); ++i) {
259     // Missing value is not allowed.
260     if (fields[i] == "") {
261       DVLOG(3) << __func__ << " Invalid missing field (position:" << i << ")";
262       return false;
263     }
264     int value;
265     if (!base::StringToInt(fields[i], &value) || value < 0) {
266       DVLOG(3) << __func__ << " Invalid field value (" << value << ")";
267       return false;
268     }
269     values.push_back(value);
270   }
271
272   const int profile_idc = values[0];
273   switch (profile_idc) {
274     case 0:
275       *profile = VP9PROFILE_PROFILE0;
276       break;
277     case 1:
278       *profile = VP9PROFILE_PROFILE1;
279       break;
280     case 2:
281       *profile = VP9PROFILE_PROFILE2;
282       break;
283     case 3:
284       *profile = VP9PROFILE_PROFILE3;
285       break;
286     default:
287       DVLOG(3) << __func__ << " Invalid profile (" << profile_idc << ")";
288       return false;
289   }
290
291   *level_idc = values[1];
292   switch (*level_idc) {
293     case 10:
294     case 11:
295     case 20:
296     case 21:
297     case 30:
298     case 31:
299     case 40:
300     case 41:
301     case 50:
302     case 51:
303     case 52:
304     case 60:
305     case 61:
306     case 62:
307       break;
308     default:
309       DVLOG(3) << __func__ << " Invalid level (" << *level_idc << ")";
310       return false;
311   }
312
313   const int bit_depth = values[2];
314   if (bit_depth != 8 && bit_depth != 10 && bit_depth != 12) {
315     DVLOG(3) << __func__ << " Invalid bit-depth (" << bit_depth << ")";
316     return false;
317   }
318
319   if (values.size() < 4)
320     return true;
321   const int chroma_subsampling = values[3];
322   if (chroma_subsampling > 3) {
323     DVLOG(3) << __func__ << " Invalid chroma subsampling ("
324              << chroma_subsampling << ")";
325     return false;
326   }
327
328   if (values.size() < 5)
329     return true;
330   color_space->primaries = VideoColorSpace::GetPrimaryID(values[4]);
331   if (color_space->primaries == VideoColorSpace::PrimaryID::INVALID) {
332     DVLOG(3) << __func__ << " Invalid color primaries (" << values[4] << ")";
333     return false;
334   }
335
336   if (values.size() < 6)
337     return true;
338   color_space->transfer = VideoColorSpace::GetTransferID(values[5]);
339   if (color_space->transfer == VideoColorSpace::TransferID::INVALID) {
340     DVLOG(3) << __func__ << " Invalid transfer function (" << values[5] << ")";
341     return false;
342   }
343
344   if (values.size() < 7)
345     return true;
346   color_space->matrix = VideoColorSpace::GetMatrixID(values[6]);
347   if (color_space->matrix == VideoColorSpace::MatrixID::INVALID) {
348     DVLOG(3) << __func__ << " Invalid matrix coefficients (" << values[6]
349              << ")";
350     return false;
351   }
352   if (color_space->matrix == VideoColorSpace::MatrixID::RGB &&
353       chroma_subsampling != 3) {
354     DVLOG(3) << __func__ << " Invalid combination of chroma_subsampling ("
355              << ") and matrix coefficients (" << values[6] << ")";
356   }
357
358   if (values.size() < 8)
359     return true;
360   const int video_full_range_flag = values[7];
361   if (video_full_range_flag > 1) {
362     DVLOG(3) << __func__ << " Invalid full range flag ("
363              << video_full_range_flag << ")";
364     return false;
365   }
366   color_space->range = video_full_range_flag == 1
367                            ? gfx::ColorSpace::RangeID::FULL
368                            : gfx::ColorSpace::RangeID::LIMITED;
369
370   return true;
371 }
372
373 bool ParseLegacyVp9CodecID(base::StringPiece codec_id,
374                            VideoCodecProfile* profile,
375                            uint8_t* level_idc) {
376   if (codec_id == "vp9" || codec_id == "vp9.0") {
377     // Profile is not included in the codec string. Consumers of parsed codec
378     // should handle by rejecting ambiguous string or resolving to a default
379     // profile.
380     *profile = VIDEO_CODEC_PROFILE_UNKNOWN;
381     // Use 0 to indicate unknown level.
382     *level_idc = 0;
383     return true;
384   }
385   return false;
386 }
387
388 #if BUILDFLAG(ENABLE_AV1_DECODER)
389 bool ParseAv1CodecId(base::StringPiece codec_id,
390                      VideoCodecProfile* profile,
391                      uint8_t* level_idc,
392                      VideoColorSpace* color_space) {
393   // The codecs parameter string for the AOM AV1 codec is as follows:
394   // See https://aomediacodec.github.io/av1-isobmff/#codecsparam.
395   //
396   // <sample entry4CC>.<profile>.<level><tier>.<bitDepth>.<monochrome>.
397   // <chromaSubsampling>.<colorPrimaries>.<transferCharacteristics>.
398   // <matrixCoefficients>.<videoFullRangeFlag>
399
400   std::vector<std::string> fields = base::SplitString(
401       codec_id, ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
402
403   // The parameters sample entry 4CC, profile, level, tier, and bitDepth are all
404   // mandatory fields. If any of these fields are empty, or not within their
405   // allowed range, the processing device SHOULD treat it as an error.
406   if (fields.size() < 4 || fields.size() > 10) {
407     DVLOG(3) << __func__ << " Invalid number of fields (" << fields.size()
408              << ")";
409     return false;
410   }
411
412   // All the other fields (including their leading '.') are optional, mutually
413   // inclusive (all or none) fields. If not specified then the values listed in
414   // the table below are assumed.
415   //
416   // mono_chrome              0
417   // chromaSubsampling        112 (4:2:0 colocated with luma (0,0))
418   // colorPrimaries           1 (ITU-R BT.709)
419   // transferCharacteristics  1 (ITU-R BT.709)
420   // matrixCoefficients       1 (ITU-R BT.709)
421   // videoFullRangeFlag       0 (studio swing representation)
422   *color_space = VideoColorSpace::REC709();
423
424   if (fields[0] != "av01") {
425     DVLOG(3) << __func__ << " Invalid AV1 4CC (" << fields[0] << ")";
426     return false;
427   }
428
429   // The level parameter value SHALL equal the first level value indicated by
430   // seq_level_idx in the Sequence Header. The tier parameter value SHALL be
431   // equal to M when the first seq_tier value in the Sequence Header is equal to
432   // 0, and H when it is equal to 1.
433   if (fields[2].size() != 3 || (fields[2][2] != 'M' && fields[2][2] != 'H')) {
434     DVLOG(3) << __func__ << " Invalid level+tier (" << fields[2] << ")";
435     return false;
436   }
437
438   // Since tier has been validated, strip the trailing tier indicator to allow
439   // int conversion below.
440   fields[2].resize(2);
441
442   // Fill with dummy values to ensure parallel indices with fields.
443   std::vector<int> values(fields.size(), 0);
444   for (size_t i = 1; i < fields.size(); ++i) {
445     if (fields[i].empty()) {
446       DVLOG(3) << __func__ << " Invalid empty field (position:" << i << ")";
447       return false;
448     }
449
450     if (!base::StringToInt(fields[i], &values[i]) || values[i] < 0) {
451       DVLOG(3) << __func__ << " Invalid field value (" << values[i] << ")";
452       return false;
453     }
454   }
455
456   // The profile parameter value, represented by a single digit decimal, SHALL
457   // equal the value of seq_profile in the Sequence Header.
458   const int profile_idc = fields[1].size() == 1 ? values[1] : -1;
459   switch (profile_idc) {
460     case 0:
461       *profile = AV1PROFILE_PROFILE_MAIN;
462       break;
463     case 1:
464       *profile = AV1PROFILE_PROFILE_HIGH;
465       break;
466     case 2:
467       *profile = AV1PROFILE_PROFILE_PRO;
468       break;
469     default:
470       DVLOG(3) << __func__ << " Invalid profile (" << fields[1] << ")";
471       return false;
472   }
473
474   // The level parameter value SHALL equal the first level value indicated by
475   // seq_level_idx in the Sequence Header. Note: We validate that this field has
476   // the required leading zeros above.
477   *level_idc = values[2];
478   if (*level_idc > 31) {
479     DVLOG(3) << __func__ << " Invalid level (" << *level_idc << ")";
480     return false;
481   }
482
483   // The bitDepth parameter value SHALL equal the value of BitDepth variable as
484   // defined in [AV1] derived from the Sequence Header. Leading zeros required.
485   const int bit_depth = values[3];
486   if (fields[3].size() != 2 ||
487       (bit_depth != 8 && bit_depth != 10 && bit_depth != 12)) {
488     DVLOG(3) << __func__ << " Invalid bit-depth (" << fields[3] << ")";
489     return false;
490   }
491
492   if (values.size() <= 4)
493     return true;
494
495   // The monochrome parameter value, represented by a single digit decimal,
496   // SHALL equal the value of mono_chrome in the Sequence Header.
497   const int monochrome = values[4];
498   if (fields[4].size() != 1 || monochrome > 1) {
499     DVLOG(3) << __func__ << " Invalid monochrome (" << fields[4] << ")";
500     return false;
501   }
502
503   if (values.size() <= 5)
504     return true;
505
506   // The chromaSubsampling parameter value, represented by a three-digit
507   // decimal, SHALL have its first digit equal to subsampling_x and its second
508   // digit equal to subsampling_y. If both subsampling_x and subsampling_y are
509   // set to 1, then the third digit SHALL be equal to chroma_sample_position,
510   // otherwise it SHALL be set to 0.
511   if (fields[5].size() != 3) {
512     DVLOG(3) << __func__ << " Invalid chroma subsampling (" << fields[5] << ")";
513     return false;
514   }
515
516   const char subsampling_x = fields[5][0];
517   const char subsampling_y = fields[5][1];
518   const char chroma_sample_position = fields[5][2];
519   if ((subsampling_x < '0' || subsampling_x > '1') ||
520       (subsampling_y < '0' || subsampling_y > '1') ||
521       (chroma_sample_position < '0' || chroma_sample_position > '3')) {
522     DVLOG(3) << __func__ << " Invalid chroma subsampling (" << fields[5] << ")";
523     return false;
524   }
525
526   if (((subsampling_x == '0' || subsampling_y == '0') &&
527        chroma_sample_position != '0')) {
528     DVLOG(3) << __func__ << " Invalid chroma subsampling (" << fields[5] << ")";
529     return false;
530   }
531
532   if (values.size() <= 6)
533     return true;
534
535   // The colorPrimaries, transferCharacteristics, matrixCoefficients and
536   // videoFullRangeFlag parameter values SHALL equal the value of matching
537   // fields in the Sequence Header, if color_description_present_flag is set to
538   // 1, otherwise they SHOULD not be set, defaulting to the values below. The
539   // videoFullRangeFlag is represented by a single digit.
540   color_space->primaries = VideoColorSpace::GetPrimaryID(values[6]);
541   if (fields[6].size() != 2 ||
542       color_space->primaries == VideoColorSpace::PrimaryID::INVALID) {
543     DVLOG(3) << __func__ << " Invalid color primaries (" << fields[6] << ")";
544     return false;
545   }
546
547   if (values.size() <= 7)
548     return true;
549
550   color_space->transfer = VideoColorSpace::GetTransferID(values[7]);
551   if (fields[7].size() != 2 ||
552       color_space->transfer == VideoColorSpace::TransferID::INVALID) {
553     DVLOG(3) << __func__ << " Invalid transfer function (" << fields[7] << ")";
554     return false;
555   }
556
557   if (values.size() <= 8)
558     return true;
559
560   color_space->matrix = VideoColorSpace::GetMatrixID(values[8]);
561   if (fields[8].size() != 2 ||
562       color_space->matrix == VideoColorSpace::MatrixID::INVALID) {
563     // TODO(dalecurtis): AV1 allows a few matrices we don't support yet.
564     // https://crbug.com/854290
565     if (values[8] == 12 || values[8] == 13 || values[8] == 14) {
566       DVLOG(3) << __func__ << " Unsupported matrix coefficients (" << fields[8]
567                << ")";
568     } else {
569       DVLOG(3) << __func__ << " Invalid matrix coefficients (" << fields[8]
570                << ")";
571     }
572     return false;
573   }
574
575   if (values.size() <= 9)
576     return true;
577
578   const int video_full_range_flag = values[9];
579   if (fields[9].size() != 1 || video_full_range_flag > 1) {
580     DVLOG(3) << __func__ << " Invalid full range flag (" << fields[9] << ")";
581     return false;
582   }
583   color_space->range = video_full_range_flag == 1
584                            ? gfx::ColorSpace::RangeID::FULL
585                            : gfx::ColorSpace::RangeID::LIMITED;
586
587   return true;
588 }
589 #endif  // BUILDFLAG(ENABLE_AV1_DECODER)
590
591 bool ParseAVCCodecId(base::StringPiece codec_id,
592                      VideoCodecProfile* profile,
593                      uint8_t* level_idc) {
594   // Make sure we have avc1.xxxxxx or avc3.xxxxxx , where xxxxxx are hex digits
595   if (!base::StartsWith(codec_id, "avc1.", base::CompareCase::SENSITIVE) &&
596       !base::StartsWith(codec_id, "avc3.", base::CompareCase::SENSITIVE)) {
597     return false;
598   }
599   uint32_t elem = 0;
600   if (codec_id.size() != 11 ||
601       !base::HexStringToUInt(base::StringPiece(codec_id).substr(5), &elem)) {
602     DVLOG(4) << __func__ << ": invalid avc codec id (" << codec_id << ")";
603     return false;
604   }
605
606   uint8_t level_byte = elem & 0xFF;
607   uint8_t constraints_byte = (elem >> 8) & 0xFF;
608   uint8_t profile_idc = (elem >> 16) & 0xFF;
609
610   // Check that the lower two bits of |constraints_byte| are zero (those are
611   // reserved and must be zero according to ISO IEC 14496-10).
612   if (constraints_byte & 3) {
613     DVLOG(4) << __func__ << ": non-zero reserved bits in codec id " << codec_id;
614     return false;
615   }
616
617   VideoCodecProfile out_profile = VIDEO_CODEC_PROFILE_UNKNOWN;
618   // profile_idc values for each profile are taken from ISO IEC 14496-10 and
619   // https://en.wikipedia.org/wiki/H.264/MPEG-4_AVC#Profiles
620   switch (profile_idc) {
621     case 66:
622       out_profile = H264PROFILE_BASELINE;
623       break;
624     case 77:
625       out_profile = H264PROFILE_MAIN;
626       break;
627     case 83:
628       out_profile = H264PROFILE_SCALABLEBASELINE;
629       break;
630     case 86:
631       out_profile = H264PROFILE_SCALABLEHIGH;
632       break;
633     case 88:
634       out_profile = H264PROFILE_EXTENDED;
635       break;
636     case 100:
637       out_profile = H264PROFILE_HIGH;
638       break;
639     case 110:
640       out_profile = H264PROFILE_HIGH10PROFILE;
641       break;
642     case 118:
643       out_profile = H264PROFILE_MULTIVIEWHIGH;
644       break;
645     case 122:
646       out_profile = H264PROFILE_HIGH422PROFILE;
647       break;
648     case 128:
649       out_profile = H264PROFILE_STEREOHIGH;
650       break;
651     case 244:
652       out_profile = H264PROFILE_HIGH444PREDICTIVEPROFILE;
653       break;
654     default:
655       DVLOG(1) << "Warning: unrecognized AVC/H.264 profile " << profile_idc;
656       return false;
657   }
658
659   // TODO(servolk): Take into account also constraint set flags 3 through 5.
660   uint8_t constraint_set0_flag = (constraints_byte >> 7) & 1;
661   uint8_t constraint_set1_flag = (constraints_byte >> 6) & 1;
662   uint8_t constraint_set2_flag = (constraints_byte >> 5) & 1;
663   if (constraint_set2_flag && out_profile > H264PROFILE_EXTENDED) {
664     out_profile = H264PROFILE_EXTENDED;
665   }
666   if (constraint_set1_flag && out_profile > H264PROFILE_MAIN) {
667     out_profile = H264PROFILE_MAIN;
668   }
669   if (constraint_set0_flag && out_profile > H264PROFILE_BASELINE) {
670     out_profile = H264PROFILE_BASELINE;
671   }
672
673   if (level_idc)
674     *level_idc = level_byte;
675
676   if (profile)
677     *profile = out_profile;
678
679   return true;
680 }
681
682 #if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER) || BUILDFLAG(IS_TIZEN_TV)
683 std::string TranslateLegacyAvc1CodecIds(base::StringPiece codec_id) {
684   // Special handling for old, pre-RFC 6381 format avc1 strings, which are still
685   // being used by some HLS apps to preserve backward compatibility with older
686   // iOS devices. The old format was avc1.<profile>.<level>
687   // Where <profile> is H.264 profile_idc encoded as a decimal number, i.e.
688   // 66 is baseline profile (0x42)
689   // 77 is main profile (0x4d)
690   // 100 is high profile (0x64)
691   // And <level> is H.264 level multiplied by 10, also encoded as decimal number
692   // E.g. <level> 31 corresponds to H.264 level 3.1
693   // See, for example, http://qtdevseed.apple.com/qadrift/testcases/tc-0133.php
694   uint32_t level_start = 0;
695   std::string result;
696   if (base::StartsWith(codec_id, "avc1.66.", base::CompareCase::SENSITIVE)) {
697     level_start = 8;
698     result = "avc1.4200";
699   } else if (base::StartsWith(codec_id, "avc1.77.",
700                               base::CompareCase::SENSITIVE)) {
701     level_start = 8;
702     result = "avc1.4D00";
703   } else if (base::StartsWith(codec_id, "avc1.100.",
704                               base::CompareCase::SENSITIVE)) {
705     level_start = 9;
706     result = "avc1.6400";
707   }
708
709   uint32_t level = 0;
710   if (level_start > 0 &&
711       base::StringToUint(codec_id.substr(level_start), &level) && level < 256) {
712     // This is a valid legacy avc1 codec id - return the codec id translated
713     // into RFC 6381 format.
714     base::AppendHexEncodedByte(static_cast<uint8_t>(level), result);
715     return result;
716   }
717
718   // This is not a valid legacy avc1 codec id - return the original codec id.
719   return std::string(codec_id);
720 }
721 #endif
722
723 #if BUILDFLAG(ENABLE_PLATFORM_HEVC)
724 // The specification for HEVC codec id strings can be found in ISO IEC 14496-15
725 // dated 2012 or newer in the Annex E.3
726 bool ParseHEVCCodecId(base::StringPiece codec_id,
727                       VideoCodecProfile* profile,
728                       uint8_t* level_idc) {
729   if (!base::StartsWith(codec_id, "hev1.", base::CompareCase::SENSITIVE) &&
730       !base::StartsWith(codec_id, "hvc1.", base::CompareCase::SENSITIVE)) {
731     return false;
732   }
733
734   // HEVC codec id consists of:
735   const int kMaxHevcCodecIdLength =
736       5 +  // 'hev1.' or 'hvc1.' prefix (5 chars)
737       4 +  // profile, e.g. '.A12' (max 4 chars)
738       9 +  // profile_compatibility, dot + 32-bit hex number (max 9 chars)
739       5 +  // tier and level, e.g. '.H120' (max 5 chars)
740       18;  // up to 6 constraint bytes, bytes are dot-separated and hex-encoded.
741
742   if (codec_id.size() > kMaxHevcCodecIdLength) {
743     DVLOG(4) << __func__ << ": Codec id is too long (" << codec_id << ")";
744     return false;
745   }
746
747   std::vector<std::string> elem = base::SplitString(
748       codec_id, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
749   DCHECK(elem[0] == "hev1" || elem[0] == "hvc1");
750
751   if (elem.size() < 4) {
752     DVLOG(4) << __func__ << ": invalid HEVC codec id " << codec_id;
753     return false;
754   }
755
756   uint8_t general_profile_space = 0;
757   if (elem[1].size() > 0 &&
758       (elem[1][0] == 'A' || elem[1][0] == 'B' || elem[1][0] == 'C')) {
759     general_profile_space = 1 + (elem[1][0] - 'A');
760     elem[1].erase(0, 1);
761   }
762   DCHECK(general_profile_space >= 0 && general_profile_space <= 3);
763
764   unsigned general_profile_idc = 0;
765   if (!base::StringToUint(elem[1], &general_profile_idc) ||
766       general_profile_idc > 0x1f) {
767     DVLOG(4) << __func__ << ": invalid general_profile_idc=" << elem[1];
768     return false;
769   }
770
771   uint32_t general_profile_compatibility_flags = 0;
772   if (!base::HexStringToUInt(elem[2], &general_profile_compatibility_flags)) {
773     DVLOG(4) << __func__
774              << ": invalid general_profile_compatibility_flags=" << elem[2];
775     return false;
776   }
777
778   VideoCodecProfile out_profile = VIDEO_CODEC_PROFILE_UNKNOWN;
779   // Spec A.3.8
780   if (general_profile_idc == 11 ||
781       (general_profile_compatibility_flags & 2048)) {
782     out_profile = HEVCPROFILE_HIGH_THROUGHPUT_SCREEN_EXTENDED;
783   }
784   // Spec H.11.1.2
785   if (general_profile_idc == 10 ||
786       (general_profile_compatibility_flags & 1024)) {
787     out_profile = HEVCPROFILE_SCALABLE_REXT;
788   }
789   // Spec A.3.7
790   if (general_profile_idc == 9 || (general_profile_compatibility_flags & 512)) {
791     out_profile = HEVCPROFILE_SCREEN_EXTENDED;
792   }
793   // Spec I.11.1.1
794   if (general_profile_idc == 8 || (general_profile_compatibility_flags & 256)) {
795     out_profile = HEVCPROFILE_3D_MAIN;
796   }
797   // Spec H.11.1.1
798   if (general_profile_idc == 7 || (general_profile_compatibility_flags & 128)) {
799     out_profile = HEVCPROFILE_SCALABLE_MAIN;
800   }
801   // Spec G.11.1.1
802   if (general_profile_idc == 6 || (general_profile_compatibility_flags & 64)) {
803     out_profile = HEVCPROFILE_MULTIVIEW_MAIN;
804   }
805   // Spec A.3.6
806   if (general_profile_idc == 5 || (general_profile_compatibility_flags & 32)) {
807     out_profile = HEVCPROFILE_HIGH_THROUGHPUT;
808   }
809   // Spec A.3.5
810   if (general_profile_idc == 4 || (general_profile_compatibility_flags & 16)) {
811     out_profile = HEVCPROFILE_REXT;
812   }
813   // Spec A.3.3
814   // NOTICE: Do not change the order of below sections
815   if (general_profile_idc == 2 || (general_profile_compatibility_flags & 4)) {
816     out_profile = HEVCPROFILE_MAIN10;
817   }
818   // Spec A.3.2
819   // When general_profile_compatibility_flag[1] is equal to 1,
820   // general_profile_compatibility_flag[2] should be equal to 1 as well.
821   if (general_profile_idc == 1 || (general_profile_compatibility_flags & 2)) {
822     out_profile = HEVCPROFILE_MAIN;
823   }
824   // Spec A.3.4
825   // When general_profile_compatibility_flag[3] is equal to 1,
826   // general_profile_compatibility_flag[1] and
827   // general_profile_compatibility_flag[2] should be equal to 1 as well.
828   if (general_profile_idc == 3 || (general_profile_compatibility_flags & 8)) {
829     out_profile = HEVCPROFILE_MAIN_STILL_PICTURE;
830   }
831
832   if (out_profile == VIDEO_CODEC_PROFILE_UNKNOWN) {
833     DVLOG(1) << "Warning: unrecognized HEVC/H.265 general_profile_idc: "
834              << general_profile_idc << ", general_profile_compatibility_flags: "
835              << general_profile_compatibility_flags;
836     return false;
837   }
838
839   if (profile)
840     *profile = out_profile;
841
842   uint8_t general_tier_flag;
843   if (elem[3].size() > 0 && (elem[3][0] == 'L' || elem[3][0] == 'H')) {
844     general_tier_flag = (elem[3][0] == 'L') ? 0 : 1;
845     elem[3].erase(0, 1);
846   } else {
847     DVLOG(4) << __func__ << ": invalid general_tier_flag=" << elem[3];
848     return false;
849   }
850   DCHECK(general_tier_flag == 0 || general_tier_flag == 1);
851
852   unsigned general_level_idc = 0;
853   if (!base::StringToUint(elem[3], &general_level_idc) ||
854       general_level_idc > 0xff) {
855     DVLOG(4) << __func__ << ": invalid general_level_idc=" << elem[3];
856     return false;
857   }
858
859   if (level_idc)
860     *level_idc = static_cast<uint8_t>(general_level_idc);
861
862   uint8_t constraint_flags[6];
863   memset(constraint_flags, 0, sizeof(constraint_flags));
864
865   if (elem.size() > 10) {
866     DVLOG(4) << __func__ << ": unexpected number of trailing bytes in HEVC "
867              << "codec id " << codec_id;
868     return false;
869   }
870   for (size_t i = 4; i < elem.size(); ++i) {
871     unsigned constr_byte = 0;
872     if (!base::HexStringToUInt(elem[i], &constr_byte) || constr_byte > 0xFF) {
873       DVLOG(4) << __func__ << ": invalid constraint byte=" << elem[i];
874       return false;
875     }
876     constraint_flags[i - 4] = constr_byte;
877   }
878
879   return true;
880 }
881 #endif
882
883 #if BUILDFLAG(ENABLE_PLATFORM_VVC)
884 // The specification for VVC codec id strings can be found in ISO/IEC 14496-15
885 // 2022, annex E.6.
886 // In detail it would be:
887 // <sample entry FourCC>    ("vvi1: if config is inband, or "vvc1" otherwise.)
888 // .<general_profile_idc>   (base10)
889 // .<general_tier_flag>     ("L" or "H")
890 // <op_level_idc>           (base10. <= general_level_idc in SPS)
891 // .C<ptl_frame_only_constraint_flag><ptl_multi_layer_enabled_flag> (optional)
892 // <general_constraint_info)  (base32 with "=" might be omitted.)
893 // .S<general_sub_profile_idc1>  (Optional, base32 with "=" might be omitted.)
894 // <+general_sub_profile_
895 // .O<ols_idx>+<max_tid>   (Optional, base10 OlsIdx & MaxTid)
896 bool ParseVVCCodecId(base::StringPiece codec_id,
897                      VideoCodecProfile* profile,
898                      uint8_t* level_idc) {
899   if (!base::StartsWith(codec_id, "vvc1.", base::CompareCase::SENSITIVE) &&
900       !base::StartsWith(codec_id, "vvi1.", base::CompareCase::SENSITIVE)) {
901     return false;
902   }
903
904   std::vector<std::string> elem = base::SplitString(
905       codec_id, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
906   DCHECK(elem[0] == "vvc1" || elem[0] == "vvi1");
907
908   if (elem.size() < 3 || elem.size() > 6) {
909     DVLOG(4) << __func__ << ": invalid VVC codec id " << codec_id;
910     return false;
911   }
912
913   for (auto& item : elem) {
914     if (item.size() < 1 ||
915         ((item[0] == 'C' || item[0] == 'S' || item[0] == 'O') &&
916          item.size() < 2)) {
917       DVLOG(4) << __func__ << ": subelement of VVC codec id invalid.";
918       return false;
919     }
920     if (item[0] == 'O' && item.back() == '+') {
921       DVLOG(4) << __func__ << ": invalid OlxIdx and MaxTid string.";
922       return false;
923     }
924   }
925
926   unsigned general_profile_idc = 0;
927   if (!base::StringToUint(elem[1], &general_profile_idc) ||
928       general_profile_idc > 0x63) {
929     DVLOG(4) << __func__ << ": invalid general_profile_idc=" << elem[1];
930     return false;
931   }
932
933   VideoCodecProfile out_profile = VIDEO_CODEC_PROFILE_UNKNOWN;
934   switch (general_profile_idc) {
935     case 99:  // Spec A.3.5
936       out_profile = VVCPROFILE_MAIN16_444_STILL_PICTURE;
937       break;
938     case 98:  // Spec A.3.5
939       out_profile = VVCPROFILE_MAIN12_444_STILL_PICTURE;
940       break;
941     case 97:  // Spec A.3.2
942       out_profile = VVCPROFILE_MAIN10_444_STILL_PICTURE;
943       break;
944     case 66:  // Spec A.3.5
945       out_profile = VVCPROFILE_MAIN12_STILL_PICTURE;
946       break;
947     case 65:  // Spec A.3.1
948       out_profile = VVCPROFILE_MAIN10_STILL_PICTURE;
949       break;
950     case 49:  // Spec A.3.4
951       out_profile = VVCPROFILE_MULTILAYER_MAIN10_444;
952       break;
953     case 43:  // Spec A.3.5
954       out_profile = VVCPROFILE_MAIN16_444_INTRA;
955       break;
956     case 42:  // Spec A.3.5
957       out_profile = VVCPROFILE_MAIN12_444_INTRA;
958       break;
959     case 35:  // Spec A.3.5
960       out_profile = VVCPROFILE_MAIN16_444;
961       break;
962     case 34:  // Spec A.3.5
963       out_profile = VVCPROFILE_MAIN12_444;
964       break;
965     case 33:  // Spec A.3.2
966       out_profile = VVCPROFILE_MAIN10_444;
967       break;
968     case 17:  // Spec A.3.3
969       out_profile = VVCPROIFLE_MULTILAYER_MAIN10;
970       break;
971     case 10:  // Spec A.3.5
972       out_profile = VVCPROFILE_MAIN12_INTRA;
973       break;
974     case 2:  // Spec A.3.5
975       out_profile = VVCPROFILE_MAIN12;
976       break;
977     case 1:  // Spec A.3.1
978       out_profile = VVCPROFILE_MAIN10;
979       break;
980     default:
981       break;
982   }
983
984   if (out_profile == VIDEO_CODEC_PROFILE_UNKNOWN) {
985     DVLOG(1) << "Warning: unrecognized VVC/H.266 general_profile_idc: "
986              << general_profile_idc;
987     return false;
988   }
989
990   if (profile) {
991     *profile = out_profile;
992   }
993
994   uint8_t general_tier_flag;
995   if (elem[2][0] == 'L' || elem[2][0] == 'H') {
996     general_tier_flag = (elem[2][0] == 'L') ? 0 : 1;
997     elem[2].erase(0, 1);
998   } else {
999     DVLOG(4) << __func__ << ": invalid general_tier_flag=" << elem[2];
1000     return false;
1001   }
1002   DCHECK(general_tier_flag == 0 || general_tier_flag == 1);
1003
1004   unsigned general_level_idc = 0;
1005   if (!base::StringToUint(elem[2], &general_level_idc) ||
1006       general_level_idc > 0xff) {
1007     DVLOG(4) << __func__ << ": invalid general_level_idc=" << elem[2];
1008     return false;
1009   }
1010
1011   if (level_idc) {
1012     *level_idc = static_cast<uint8_t>(general_level_idc);
1013   }
1014
1015   // C-string, if existing, should proceed S-string and O-string.
1016   // Similarly, S-string should proceed O-string.
1017   bool trailing_valid = true;
1018   if (elem.size() == 4) {
1019     if (elem[3][0] != 'C' && elem[3][0] != 'S' && elem[3][0] != 'O') {
1020       trailing_valid = false;
1021     }
1022   } else if (elem.size() == 5) {
1023     if (!((elem[3][0] == 'C' && elem[4][0] == 'S') ||
1024           (elem[3][0] == 'C' && elem[4][0] == 'O') ||
1025           (elem[3][0] == 'S' && elem[4][0] == 'O'))) {
1026       trailing_valid = false;
1027     }
1028   } else if (elem.size() == 6) {
1029     if (elem[3][0] != 'C' || elem[4][0] != 'S' || elem[5][0] != 'O') {
1030       trailing_valid = false;
1031     }
1032   }
1033
1034   if (!trailing_valid) {
1035     DVLOG(4) << __func__ << ": invalid traing codec string.";
1036     return false;
1037   }
1038
1039   return true;
1040 }
1041 #endif
1042
1043 #if BUILDFLAG(ENABLE_PLATFORM_DOLBY_VISION)
1044 bool IsDolbyVisionAVCCodecId(base::StringPiece codec_id) {
1045   return base::StartsWith(codec_id, "dva1.", base::CompareCase::SENSITIVE) ||
1046          base::StartsWith(codec_id, "dvav.", base::CompareCase::SENSITIVE);
1047 }
1048
1049 bool IsDolbyVisionHEVCCodecId(base::StringPiece codec_id) {
1050   return base::StartsWith(codec_id, "dvh1.", base::CompareCase::SENSITIVE) ||
1051          base::StartsWith(codec_id, "dvhe.", base::CompareCase::SENSITIVE);
1052 }
1053
1054 // The specification for Dolby Vision codec id strings can be found in Dolby
1055 // Vision streams within the MPEG-DASH format:
1056 // https://professional.dolby.com/siteassets/content-creation/dolby-vision-for-content-creators/dolbyvisioninmpegdashspecification_v2_0_public_20190107.pdf
1057 bool ParseDolbyVisionCodecId(base::StringPiece codec_id,
1058                              VideoCodecProfile* profile,
1059                              uint8_t* level_idc) {
1060   if (!IsDolbyVisionAVCCodecId(codec_id) &&
1061       !IsDolbyVisionHEVCCodecId(codec_id)) {
1062     return false;
1063   }
1064
1065   const int kMaxDvCodecIdLength = 5     // FOURCC string
1066                                   + 1   // delimiting period
1067                                   + 2   // profile id as 2 digit string
1068                                   + 1   // delimiting period
1069                                   + 2;  // level id as 2 digit string.
1070
1071   if (codec_id.size() > kMaxDvCodecIdLength) {
1072     DVLOG(4) << __func__ << ": Codec id is too long (" << codec_id << ")";
1073     return false;
1074   }
1075
1076   std::vector<std::string> elem = base::SplitString(
1077       codec_id, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
1078   DCHECK(elem[0] == "dvh1" || elem[0] == "dvhe" || elem[0] == "dva1" ||
1079          elem[0] == "dvav");
1080
1081   if (elem.size() != 3) {
1082     DVLOG(4) << __func__ << ": invalid dolby vision codec id " << codec_id;
1083     return false;
1084   }
1085
1086   // Profile string should be two digits.
1087   unsigned profile_id = 0;
1088   if (elem[1].size() != 2 || !base::StringToUint(elem[1], &profile_id) ||
1089       profile_id > 9) {
1090     DVLOG(4) << __func__ << ": invalid format or profile_id=" << elem[1];
1091     return false;
1092   }
1093
1094   // Only profiles 0, 4, 5, 7, 8 and 9 are valid. Profile 0 and 9 are encoded
1095   // based on AVC while profile 4, 5, 7 and 8 are based on HEVC.
1096   switch (profile_id) {
1097     case 0:
1098     case 9:
1099       if (!IsDolbyVisionAVCCodecId(codec_id)) {
1100         DVLOG(4) << __func__
1101                  << ": codec id is mismatched with profile_id=" << profile_id;
1102         return false;
1103       }
1104       if (profile_id == 0)
1105         *profile = DOLBYVISION_PROFILE0;
1106       else if (profile_id == 9)
1107         *profile = DOLBYVISION_PROFILE9;
1108       break;
1109 #if BUILDFLAG(ENABLE_PLATFORM_HEVC)
1110     case 4:
1111     case 5:
1112     case 7:
1113     case 8:
1114       if (!IsDolbyVisionHEVCCodecId(codec_id)) {
1115         DVLOG(4) << __func__
1116                  << ": codec id is mismatched with profile_id=" << profile_id;
1117         return false;
1118       }
1119       if (profile_id == 4)
1120         *profile = DOLBYVISION_PROFILE4;
1121       else if (profile_id == 5)
1122         *profile = DOLBYVISION_PROFILE5;
1123       else if (profile_id == 7)
1124         *profile = DOLBYVISION_PROFILE7;
1125       else if (profile_id == 8)
1126         *profile = DOLBYVISION_PROFILE8;
1127       break;
1128 #endif
1129     default:
1130       DVLOG(4) << __func__
1131                << ": depecrated and not supported profile_id=" << profile_id;
1132       return false;
1133   }
1134
1135   // Level string should be two digits.
1136   unsigned level_id = 0;
1137   if (elem[2].size() != 2 || !base::StringToUint(elem[2], &level_id) ||
1138       level_id > 13 || level_id < 1) {
1139     DVLOG(4) << __func__ << ": invalid format level_id=" << elem[2];
1140     return false;
1141   }
1142
1143   *level_idc = level_id;
1144
1145   return true;
1146 }
1147 #endif
1148
1149 VideoCodec StringToVideoCodec(base::StringPiece codec_id) {
1150   VideoCodec codec = VideoCodec::kUnknown;
1151   VideoCodecProfile profile = VIDEO_CODEC_PROFILE_UNKNOWN;
1152   uint8_t level = 0;
1153   VideoColorSpace color_space;
1154   ParseCodec(codec_id, codec, profile, level, color_space);
1155   return codec;
1156 }
1157
1158 void ParseCodec(base::StringPiece codec_id,
1159                 VideoCodec& codec,
1160                 VideoCodecProfile& profile,
1161                 uint8_t& level,
1162                 VideoColorSpace& color_space) {
1163   std::vector<std::string> elem = base::SplitString(
1164       codec_id, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
1165   if (elem.empty()) {
1166     codec = VideoCodec::kUnknown;
1167     return;
1168   }
1169
1170   if (codec_id == "vp8" || codec_id == "vp8.0") {
1171     codec = VideoCodec::kVP8;
1172     return;
1173   }
1174   if (ParseNewStyleVp9CodecID(codec_id, &profile, &level, &color_space) ||
1175       ParseLegacyVp9CodecID(codec_id, &profile, &level)) {
1176     codec = VideoCodec::kVP9;
1177     return;
1178   }
1179
1180 #if BUILDFLAG(ENABLE_AV1_DECODER)
1181   if (ParseAv1CodecId(codec_id, &profile, &level, &color_space)) {
1182     codec = VideoCodec::kAV1;
1183     return;
1184   }
1185 #endif
1186
1187   if (codec_id == "theora") {
1188     codec = VideoCodec::kTheora;
1189     return;
1190   }
1191   if (ParseAVCCodecId(codec_id, &profile, &level)) {
1192     codec = VideoCodec::kH264;
1193     return;
1194   }
1195 #if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER) || BUILDFLAG(IS_TIZEN_TV)
1196   if (ParseAVCCodecId(TranslateLegacyAvc1CodecIds(codec_id), &profile,
1197                       &level)) {
1198     codec = VideoCodec::kH264;
1199     return;
1200   }
1201 #endif
1202 #if BUILDFLAG(ENABLE_PLATFORM_HEVC)
1203   if (ParseHEVCCodecId(codec_id, &profile, &level)) {
1204     codec = VideoCodec::kHEVC;
1205     return;
1206   }
1207 #endif
1208 #if BUILDFLAG(ENABLE_PLATFORM_DOLBY_VISION)
1209   if (ParseDolbyVisionCodecId(codec_id, &profile, &level)) {
1210     codec = VideoCodec::kDolbyVision;
1211     return;
1212   }
1213 #endif
1214   codec = VideoCodec::kUnknown;
1215 }
1216
1217 VideoCodec VideoCodecProfileToVideoCodec(VideoCodecProfile profile) {
1218   switch (profile) {
1219     case VIDEO_CODEC_PROFILE_UNKNOWN:
1220       return VideoCodec::kUnknown;
1221     case H264PROFILE_BASELINE:
1222     case H264PROFILE_MAIN:
1223     case H264PROFILE_EXTENDED:
1224     case H264PROFILE_HIGH:
1225     case H264PROFILE_HIGH10PROFILE:
1226     case H264PROFILE_HIGH422PROFILE:
1227     case H264PROFILE_HIGH444PREDICTIVEPROFILE:
1228     case H264PROFILE_SCALABLEBASELINE:
1229     case H264PROFILE_SCALABLEHIGH:
1230     case H264PROFILE_STEREOHIGH:
1231     case H264PROFILE_MULTIVIEWHIGH:
1232       return VideoCodec::kH264;
1233     case HEVCPROFILE_MAIN:
1234     case HEVCPROFILE_MAIN10:
1235     case HEVCPROFILE_MAIN_STILL_PICTURE:
1236     case HEVCPROFILE_REXT:
1237     case HEVCPROFILE_HIGH_THROUGHPUT:
1238     case HEVCPROFILE_MULTIVIEW_MAIN:
1239     case HEVCPROFILE_SCALABLE_MAIN:
1240     case HEVCPROFILE_3D_MAIN:
1241     case HEVCPROFILE_SCREEN_EXTENDED:
1242     case HEVCPROFILE_SCALABLE_REXT:
1243     case HEVCPROFILE_HIGH_THROUGHPUT_SCREEN_EXTENDED:
1244       return VideoCodec::kHEVC;
1245     case VP8PROFILE_ANY:
1246       return VideoCodec::kVP8;
1247     case VP9PROFILE_PROFILE0:
1248     case VP9PROFILE_PROFILE1:
1249     case VP9PROFILE_PROFILE2:
1250     case VP9PROFILE_PROFILE3:
1251       return VideoCodec::kVP9;
1252     case DOLBYVISION_PROFILE0:
1253     case DOLBYVISION_PROFILE4:
1254     case DOLBYVISION_PROFILE5:
1255     case DOLBYVISION_PROFILE7:
1256     case DOLBYVISION_PROFILE8:
1257     case DOLBYVISION_PROFILE9:
1258       return VideoCodec::kDolbyVision;
1259     case THEORAPROFILE_ANY:
1260       return VideoCodec::kTheora;
1261     case AV1PROFILE_PROFILE_MAIN:
1262     case AV1PROFILE_PROFILE_HIGH:
1263     case AV1PROFILE_PROFILE_PRO:
1264       return VideoCodec::kAV1;
1265     // TODO(crbugs.com/1417910): Update to VideoCodec::kVVC when
1266     // the production VVC decoder is enabled and corresponding
1267     // enum is allowed to be added.
1268     case VVCPROFILE_MAIN10:
1269     case VVCPROFILE_MAIN12:
1270     case VVCPROFILE_MAIN12_INTRA:
1271     case VVCPROIFLE_MULTILAYER_MAIN10:
1272     case VVCPROFILE_MAIN10_444:
1273     case VVCPROFILE_MAIN12_444:
1274     case VVCPROFILE_MAIN16_444:
1275     case VVCPROFILE_MAIN12_444_INTRA:
1276     case VVCPROFILE_MAIN16_444_INTRA:
1277     case VVCPROFILE_MULTILAYER_MAIN10_444:
1278     case VVCPROFILE_MAIN10_STILL_PICTURE:
1279     case VVCPROFILE_MAIN12_STILL_PICTURE:
1280     case VVCPROFILE_MAIN10_444_STILL_PICTURE:
1281     case VVCPROFILE_MAIN12_444_STILL_PICTURE:
1282     case VVCPROFILE_MAIN16_444_STILL_PICTURE:
1283       return VideoCodec::kUnknown;
1284   }
1285 }
1286
1287 std::ostream& operator<<(std::ostream& os, const VideoCodec& codec) {
1288   return os << GetCodecName(codec);
1289 }
1290
1291 }  // namespace media