OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/base/video_codecs.h" | 5 #include "media/base/video_codecs.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/strings/string_number_conversions.h" | 8 #include "base/strings/string_number_conversions.h" |
9 #include "base/strings/string_split.h" | 9 #include "base/strings/string_split.h" |
10 #include "base/strings/string_util.h" | 10 #include "base/strings/string_util.h" |
11 | 11 |
12 namespace media { | 12 namespace media { |
13 | 13 |
14 // The names come from src/third_party/ffmpeg/libavcodec/codec_desc.c | 14 // The names come from src/third_party/ffmpeg/libavcodec/codec_desc.c |
15 std::string GetCodecName(VideoCodec codec) { | 15 std::string GetCodecName(VideoCodec codec) { |
16 switch (codec) { | 16 switch (codec) { |
17 case kUnknownVideoCodec: | 17 case kUnknownVideoCodec: |
18 return "unknown"; | 18 return "unknown"; |
19 case kCodecH264: | 19 case kCodecH264: |
20 return "h264"; | 20 return "h264"; |
21 case kCodecHEVC: | 21 case kCodecHEVC: |
22 return "hevc"; | 22 return "hevc"; |
| 23 case kCodecDolbyVision: |
| 24 return "dolbyvision"; |
23 case kCodecVC1: | 25 case kCodecVC1: |
24 return "vc1"; | 26 return "vc1"; |
25 case kCodecMPEG2: | 27 case kCodecMPEG2: |
26 return "mpeg2video"; | 28 return "mpeg2video"; |
27 case kCodecMPEG4: | 29 case kCodecMPEG4: |
28 return "mpeg4"; | 30 return "mpeg4"; |
29 case kCodecTheora: | 31 case kCodecTheora: |
30 return "theora"; | 32 return "theora"; |
31 case kCodecVP8: | 33 case kCodecVP8: |
32 return "vp8"; | 34 return "vp8"; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
72 case VP8PROFILE_ANY: | 74 case VP8PROFILE_ANY: |
73 return "vp8"; | 75 return "vp8"; |
74 case VP9PROFILE_PROFILE0: | 76 case VP9PROFILE_PROFILE0: |
75 return "vp9 profile0"; | 77 return "vp9 profile0"; |
76 case VP9PROFILE_PROFILE1: | 78 case VP9PROFILE_PROFILE1: |
77 return "vp9 profile1"; | 79 return "vp9 profile1"; |
78 case VP9PROFILE_PROFILE2: | 80 case VP9PROFILE_PROFILE2: |
79 return "vp9 profile2"; | 81 return "vp9 profile2"; |
80 case VP9PROFILE_PROFILE3: | 82 case VP9PROFILE_PROFILE3: |
81 return "vp9 profile3"; | 83 return "vp9 profile3"; |
| 84 case DOLBYVISION_PROFILE0: |
| 85 return "dolby vision profile 0"; |
| 86 case DOLBYVISION_PROFILE4: |
| 87 return "dolby vision profile 4"; |
| 88 case DOLBYVISION_PROFILE5: |
| 89 return "dolby vision profile 5"; |
| 90 case DOLBYVISION_PROFILE7: |
| 91 return "dolby vision profile 7"; |
82 } | 92 } |
83 NOTREACHED(); | 93 NOTREACHED(); |
84 return ""; | 94 return ""; |
85 } | 95 } |
86 | 96 |
87 bool ParseNewStyleVp9CodecID(const std::string& codec_id, | 97 bool ParseNewStyleVp9CodecID(const std::string& codec_id, |
88 VideoCodecProfile* profile, | 98 VideoCodecProfile* profile, |
89 uint8_t* level_idc) { | 99 uint8_t* level_idc) { |
90 std::vector<std::string> fields = base::SplitString( | 100 std::vector<std::string> fields = base::SplitString( |
91 codec_id, ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); | 101 codec_id, ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); |
(...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
412 DVLOG(4) << __func__ << ": invalid constraint byte=" << elem[i]; | 422 DVLOG(4) << __func__ << ": invalid constraint byte=" << elem[i]; |
413 return false; | 423 return false; |
414 } | 424 } |
415 constraint_flags[i - 4] = constr_byte; | 425 constraint_flags[i - 4] = constr_byte; |
416 } | 426 } |
417 | 427 |
418 return true; | 428 return true; |
419 } | 429 } |
420 #endif | 430 #endif |
421 | 431 |
| 432 #if BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING) |
| 433 bool IsDolbyVisionAVCCodecId(const std::string& codec_id) { |
| 434 return base::StartsWith(codec_id, "dva1.", base::CompareCase::SENSITIVE) || |
| 435 base::StartsWith(codec_id, "dvav.", base::CompareCase::SENSITIVE); |
| 436 } |
| 437 |
| 438 bool IsDolbyVisionHEVCCodecId(const std::string& codec_id) { |
| 439 return base::StartsWith(codec_id, "dvh1.", base::CompareCase::SENSITIVE) || |
| 440 base::StartsWith(codec_id, "dvhe.", base::CompareCase::SENSITIVE); |
| 441 } |
| 442 |
| 443 // The specification for Dolby Vision codec id strings can be found in Dolby |
| 444 // Vision streams within the MPEG-DASH format. |
| 445 bool ParseDolbyVisionCodecId(const std::string& codec_id, |
| 446 VideoCodecProfile* profile, |
| 447 uint8_t* level_idc) { |
| 448 if (!IsDolbyVisionAVCCodecId(codec_id) && |
| 449 !IsDolbyVisionHEVCCodecId(codec_id)) { |
| 450 return false; |
| 451 } |
| 452 |
| 453 const int kMaxDvCodecIdLength = 5 // FOURCC string |
| 454 + 1 // delimiting period |
| 455 + 2 // profile id as 2 digit string |
| 456 + 1 // delimiting period |
| 457 + 2; // level id as 2 digit string. |
| 458 |
| 459 if (codec_id.size() > kMaxDvCodecIdLength) { |
| 460 DVLOG(4) << __func__ << ": Codec id is too long (" << codec_id << ")"; |
| 461 return false; |
| 462 } |
| 463 |
| 464 std::vector<std::string> elem = base::SplitString( |
| 465 codec_id, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); |
| 466 DCHECK(elem[0] == "dvh1" || elem[0] == "dvhe" || elem[0] == "dva1" || |
| 467 elem[0] == "dvav"); |
| 468 |
| 469 if (elem.size() != 3) { |
| 470 DVLOG(4) << __func__ << ": invalid dolby vision codec id " << codec_id; |
| 471 return false; |
| 472 } |
| 473 |
| 474 // Profile string should be two digits. |
| 475 unsigned profile_id = 0; |
| 476 if (elem[1].size() != 2 || !base::StringToUint(elem[1], &profile_id) || |
| 477 profile_id > 7) { |
| 478 DVLOG(4) << __func__ << ": invalid format or profile_id=" << elem[1]; |
| 479 return false; |
| 480 } |
| 481 |
| 482 // Only profiles 0, 4, 5 and 7 are valid. Profile 0 is encoded based on AVC |
| 483 // while profile 4, 5 and 7 are based on HEVC. |
| 484 switch (profile_id) { |
| 485 case 0: |
| 486 if (!IsDolbyVisionAVCCodecId(codec_id)) { |
| 487 DVLOG(4) << __func__ |
| 488 << ": codec id is mismatched with profile_id=" << profile_id; |
| 489 return false; |
| 490 } |
| 491 *profile = DOLBYVISION_PROFILE0; |
| 492 break; |
| 493 #if BUILDFLAG(ENABLE_HEVC_DEMUXING) |
| 494 case 4: |
| 495 case 5: |
| 496 case 7: |
| 497 if (!IsDolbyVisionHEVCCodecId(codec_id)) { |
| 498 DVLOG(4) << __func__ |
| 499 << ": codec id is mismatched with profile_id=" << profile_id; |
| 500 return false; |
| 501 } |
| 502 if (profile_id == 4) |
| 503 *profile = DOLBYVISION_PROFILE4; |
| 504 else if (profile_id == 5) |
| 505 *profile = DOLBYVISION_PROFILE5; |
| 506 else if (profile_id == 7) |
| 507 *profile = DOLBYVISION_PROFILE7; |
| 508 break; |
| 509 #endif |
| 510 default: |
| 511 DVLOG(4) << __func__ |
| 512 << ": depecrated and not supported profile_id=" << profile_id; |
| 513 return false; |
| 514 } |
| 515 |
| 516 // Level string should be two digits. |
| 517 unsigned level_id = 0; |
| 518 if (elem[2].size() != 2 || !base::StringToUint(elem[2], &level_id) || |
| 519 level_id > 9 || level_id < 1) { |
| 520 DVLOG(4) << __func__ << ": invalid format level_id=" << elem[2]; |
| 521 return false; |
| 522 } |
| 523 |
| 524 *level_idc = level_id; |
| 525 |
| 526 return true; |
| 527 } |
| 528 #endif |
| 529 |
422 VideoCodec StringToVideoCodec(const std::string& codec_id) { | 530 VideoCodec StringToVideoCodec(const std::string& codec_id) { |
423 std::vector<std::string> elem = base::SplitString( | 531 std::vector<std::string> elem = base::SplitString( |
424 codec_id, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); | 532 codec_id, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); |
425 if (elem.empty()) | 533 if (elem.empty()) |
426 return kUnknownVideoCodec; | 534 return kUnknownVideoCodec; |
427 VideoCodecProfile profile = VIDEO_CODEC_PROFILE_UNKNOWN; | 535 VideoCodecProfile profile = VIDEO_CODEC_PROFILE_UNKNOWN; |
428 uint8_t level = 0; | 536 uint8_t level = 0; |
429 if (codec_id == "vp8" || codec_id == "vp8.0") | 537 if (codec_id == "vp8" || codec_id == "vp8.0") |
430 return kCodecVP8; | 538 return kCodecVP8; |
431 if (ParseNewStyleVp9CodecID(codec_id, &profile, &level) || | 539 if (ParseNewStyleVp9CodecID(codec_id, &profile, &level) || |
432 ParseLegacyVp9CodecID(codec_id, &profile, &level)) { | 540 ParseLegacyVp9CodecID(codec_id, &profile, &level)) { |
433 return kCodecVP9; | 541 return kCodecVP9; |
434 } | 542 } |
435 if (codec_id == "theora") | 543 if (codec_id == "theora") |
436 return kCodecTheora; | 544 return kCodecTheora; |
437 if (ParseAVCCodecId(codec_id, &profile, &level)) | 545 if (ParseAVCCodecId(codec_id, &profile, &level)) |
438 return kCodecH264; | 546 return kCodecH264; |
439 #if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER) | 547 #if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER) |
440 if (ParseAVCCodecId(TranslateLegacyAvc1CodecIds(codec_id), &profile, &level)) | 548 if (ParseAVCCodecId(TranslateLegacyAvc1CodecIds(codec_id), &profile, &level)) |
441 return kCodecH264; | 549 return kCodecH264; |
442 #endif | 550 #endif |
443 #if BUILDFLAG(ENABLE_HEVC_DEMUXING) | 551 #if BUILDFLAG(ENABLE_HEVC_DEMUXING) |
444 if (ParseHEVCCodecId(codec_id, &profile, &level)) | 552 if (ParseHEVCCodecId(codec_id, &profile, &level)) |
445 return kCodecHEVC; | 553 return kCodecHEVC; |
446 #endif | 554 #endif |
| 555 #if BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING) |
| 556 if (ParseDolbyVisionCodecId(codec_id, &profile, &level)) |
| 557 return kCodecDolbyVision; |
| 558 #endif |
447 return kUnknownVideoCodec; | 559 return kUnknownVideoCodec; |
448 } | 560 } |
449 | 561 |
450 } // namespace media | 562 } // namespace media |
OLD | NEW |