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