Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(70)

Side by Side Diff: media/base/mime_util.cc

Issue 1677563003: Implemented parsing for H.264/AVC codec ids (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixed unit tests Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2012 The Chromium Authors. All rights reserved. 1 // Copyright 2012 The Chromium Authors. All rights reserved.
ddorwin 2016/02/17 19:31:20 This is going to conflict with Dale's CL to move m
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 <stddef.h> 5 #include <stddef.h>
6 #include <stdint.h> 6 #include <stdint.h>
7 7
8 #include <map> 8 #include <map>
9 9
10 #include "base/containers/hash_tables.h" 10 #include "base/containers/hash_tables.h"
11 #include "base/lazy_instance.h" 11 #include "base/lazy_instance.h"
12 #include "base/macros.h" 12 #include "base/macros.h"
13 #include "base/strings/string_number_conversions.h" 13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_split.h" 14 #include "base/strings/string_split.h"
15 #include "base/strings/string_util.h" 15 #include "base/strings/string_util.h"
16 #include "build/build_config.h" 16 #include "build/build_config.h"
17 #include "media/base/mime_util.h" 17 #include "media/base/mime_util.h"
18 #include "media/base/video_codecs.h"
18 #include "media/media_features.h" 19 #include "media/media_features.h"
19 20
20 #if defined(OS_ANDROID) 21 #if defined(OS_ANDROID)
21 #include "base/android/build_info.h" 22 #include "base/android/build_info.h"
22 #endif 23 #endif
23 24
24 namespace media { 25 namespace media {
25 26
26 // Singleton utility class for mime types. 27 // Singleton utility class for mime types.
27 class MimeUtil { 28 class MimeUtil {
28 public: 29 public:
29 enum Codec { 30 enum Codec {
30 INVALID_CODEC, 31 INVALID_CODEC,
31 PCM, 32 PCM,
32 MP3, 33 MP3,
33 AC3, 34 AC3,
34 EAC3, 35 EAC3,
35 MPEG2_AAC_LC, 36 MPEG2_AAC_LC,
36 MPEG2_AAC_MAIN, 37 MPEG2_AAC_MAIN,
37 MPEG2_AAC_SSR, 38 MPEG2_AAC_SSR,
38 MPEG4_AAC_LC, 39 MPEG4_AAC_LC,
39 MPEG4_AAC_SBR_v1, 40 MPEG4_AAC_SBR_v1,
40 MPEG4_AAC_SBR_PS_v2, 41 MPEG4_AAC_SBR_PS_v2,
41 VORBIS, 42 VORBIS,
42 OPUS, 43 OPUS,
43 H264_BASELINE, 44 H264,
44 H264_MAIN,
45 H264_HIGH,
46 HEVC_MAIN, 45 HEVC_MAIN,
ddorwin 2016/02/17 19:31:20 Should we remove _MAIN here too?
servolk 2016/02/17 19:49:54 Yes, I'm planning to do that in a separate CL whic
47 VP8, 46 VP8,
48 VP9, 47 VP9,
49 THEORA 48 THEORA
50 }; 49 };
51 50
52 bool IsSupportedMediaMimeType(const std::string& mime_type) const; 51 bool IsSupportedMediaMimeType(const std::string& mime_type) const;
53 52
54 void ParseCodecString(const std::string& codecs, 53 void ParseCodecString(const std::string& codecs,
55 std::vector<std::string>* codecs_out, 54 std::vector<std::string>* codecs_out,
56 bool strip); 55 bool strip);
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
141 switch (codec) { 140 switch (codec) {
142 case MimeUtil::INVALID_CODEC: 141 case MimeUtil::INVALID_CODEC:
143 return false; 142 return false;
144 143
145 case MimeUtil::PCM: 144 case MimeUtil::PCM:
146 case MimeUtil::MP3: 145 case MimeUtil::MP3:
147 case MimeUtil::MPEG4_AAC_LC: 146 case MimeUtil::MPEG4_AAC_LC:
148 case MimeUtil::MPEG4_AAC_SBR_v1: 147 case MimeUtil::MPEG4_AAC_SBR_v1:
149 case MimeUtil::MPEG4_AAC_SBR_PS_v2: 148 case MimeUtil::MPEG4_AAC_SBR_PS_v2:
150 case MimeUtil::VORBIS: 149 case MimeUtil::VORBIS:
151 case MimeUtil::H264_BASELINE: 150 case MimeUtil::H264:
152 case MimeUtil::H264_MAIN:
153 case MimeUtil::H264_HIGH:
154 case MimeUtil::VP8: 151 case MimeUtil::VP8:
155 return true; 152 return true;
156 153
157 case MimeUtil::AC3: 154 case MimeUtil::AC3:
158 case MimeUtil::EAC3: 155 case MimeUtil::EAC3:
159 // TODO(servolk): Revisit this for AC3/EAC3 support on AndroidTV 156 // TODO(servolk): Revisit this for AC3/EAC3 support on AndroidTV
160 return false; 157 return false;
161 158
162 case MimeUtil::MPEG2_AAC_LC: 159 case MimeUtil::MPEG2_AAC_LC:
163 case MimeUtil::MPEG2_AAC_MAIN: 160 case MimeUtil::MPEG2_AAC_MAIN:
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
288 const char* const codec_id; 285 const char* const codec_id;
289 MimeUtil::Codec codec; 286 MimeUtil::Codec codec;
290 }; 287 };
291 288
292 // List of codec IDs that provide enough information to determine the 289 // List of codec IDs that provide enough information to determine the
293 // codec and profile being requested. 290 // codec and profile being requested.
294 // 291 //
295 // The "mp4a" strings come from RFC 6381. 292 // The "mp4a" strings come from RFC 6381.
296 static const CodecIDMappings kUnambiguousCodecStringMap[] = { 293 static const CodecIDMappings kUnambiguousCodecStringMap[] = {
297 {"1", MimeUtil::PCM}, // We only allow this for WAV so it isn't ambiguous. 294 {"1", MimeUtil::PCM}, // We only allow this for WAV so it isn't ambiguous.
298 // avc1/avc3.XXXXXX may be unambiguous; handled by ParseH264CodecID(). 295 // avc1/avc3.XXXXXX may be unambiguous; handled by ParseAVCCodecId().
299 // hev1/hvc1.XXXXXX may be unambiguous; handled by ParseHEVCCodecID(). 296 // hev1/hvc1.XXXXXX may be unambiguous; handled by ParseHEVCCodecID().
300 {"mp3", MimeUtil::MP3}, 297 {"mp3", MimeUtil::MP3},
301 {"mp4a.66", MimeUtil::MPEG2_AAC_MAIN}, 298 {"mp4a.66", MimeUtil::MPEG2_AAC_MAIN},
302 {"mp4a.67", MimeUtil::MPEG2_AAC_LC}, 299 {"mp4a.67", MimeUtil::MPEG2_AAC_LC},
303 {"mp4a.68", MimeUtil::MPEG2_AAC_SSR}, 300 {"mp4a.68", MimeUtil::MPEG2_AAC_SSR},
304 {"mp4a.69", MimeUtil::MP3}, 301 {"mp4a.69", MimeUtil::MP3},
305 {"mp4a.6B", MimeUtil::MP3}, 302 {"mp4a.6B", MimeUtil::MP3},
306 {"mp4a.40.2", MimeUtil::MPEG4_AAC_LC}, 303 {"mp4a.40.2", MimeUtil::MPEG4_AAC_LC},
307 {"mp4a.40.02", MimeUtil::MPEG4_AAC_LC}, 304 {"mp4a.40.02", MimeUtil::MPEG4_AAC_LC},
308 {"mp4a.40.5", MimeUtil::MPEG4_AAC_SBR_v1}, 305 {"mp4a.40.5", MimeUtil::MPEG4_AAC_SBR_v1},
(...skipping 20 matching lines...) Expand all
329 {"vp9", MimeUtil::VP9}, 326 {"vp9", MimeUtil::VP9},
330 {"vp9.0", MimeUtil::VP9}, 327 {"vp9.0", MimeUtil::VP9},
331 {"theora", MimeUtil::THEORA}}; 328 {"theora", MimeUtil::THEORA}};
332 329
333 // List of codec IDs that are ambiguous and don't provide 330 // List of codec IDs that are ambiguous and don't provide
334 // enough information to determine the codec and profile. 331 // enough information to determine the codec and profile.
335 // The codec in these entries indicate the codec and profile 332 // The codec in these entries indicate the codec and profile
336 // we assume the user is trying to indicate. 333 // we assume the user is trying to indicate.
337 static const CodecIDMappings kAmbiguousCodecStringMap[] = { 334 static const CodecIDMappings kAmbiguousCodecStringMap[] = {
338 {"mp4a.40", MimeUtil::MPEG4_AAC_LC}, 335 {"mp4a.40", MimeUtil::MPEG4_AAC_LC},
339 {"avc1", MimeUtil::H264_BASELINE}, 336 {"avc1", MimeUtil::H264},
340 {"avc3", MimeUtil::H264_BASELINE}, 337 {"avc3", MimeUtil::H264},
341 // avc1/avc3.XXXXXX may be ambiguous; handled by ParseH264CodecID(). 338 // avc1/avc3.XXXXXX may be ambiguous; handled by ParseAVCCodecId().
342 }; 339 };
343 340
344 #if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER) 341 #if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)
345 static const char kHexString[] = "0123456789ABCDEF"; 342 static const char kHexString[] = "0123456789ABCDEF";
346 static char IntToHex(int i) { 343 static char IntToHex(int i) {
347 DCHECK_GE(i, 0) << i << " not a hex value"; 344 DCHECK_GE(i, 0) << i << " not a hex value";
348 DCHECK_LE(i, 15) << i << " not a hex value"; 345 DCHECK_LE(i, 15) << i << " not a hex value";
349 return kHexString[i]; 346 return kHexString[i];
350 } 347 }
351 348
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
525 return AreSupportedCodecs(it_media_format_map->second, codecs); 522 return AreSupportedCodecs(it_media_format_map->second, codecs);
526 } 523 }
527 524
528 void MimeUtil::RemoveProprietaryMediaTypesAndCodecsForTests() { 525 void MimeUtil::RemoveProprietaryMediaTypesAndCodecsForTests() {
529 for (size_t i = 0; i < arraysize(kFormatCodecMappings); ++i) 526 for (size_t i = 0; i < arraysize(kFormatCodecMappings); ++i)
530 if (kFormatCodecMappings[i].format_type == PROPRIETARY) 527 if (kFormatCodecMappings[i].format_type == PROPRIETARY)
531 media_format_map_.erase(kFormatCodecMappings[i].mime_type); 528 media_format_map_.erase(kFormatCodecMappings[i].mime_type);
532 allow_proprietary_codecs_ = false; 529 allow_proprietary_codecs_ = false;
533 } 530 }
534 531
535 static bool IsValidH264Level(const std::string& level_str) { 532 static bool IsValidH264Level(uint8_t level_idc) {
536 uint32_t level; 533 // Valid levels taken from Table A-1 in ISO/IEC 14496-10.
537 if (level_str.size() != 2 || !base::HexStringToUInt(level_str, &level)) 534 // Level_idc represents the standard level represented as decimal number
538 return false; 535 // multiplied by ten, e.g. level_idc==32 corresponds to level==3.2
539 536 return ((level_idc >= 10 && level_idc <= 13) ||
540 // Valid levels taken from Table A-1 in ISO-14496-10. 537 (level_idc >= 20 && level_idc <= 22) ||
541 // Essentially |level_str| is toHex(10 * level). 538 (level_idc >= 30 && level_idc <= 32) ||
542 return ((level >= 10 && level <= 13) || 539 (level_idc >= 40 && level_idc <= 42) ||
543 (level >= 20 && level <= 22) || 540 (level_idc >= 50 && level_idc <= 51));
544 (level >= 30 && level <= 32) ||
545 (level >= 40 && level <= 42) ||
546 (level >= 50 && level <= 51));
547 }
548
549 // Handle parsing H.264 codec IDs as outlined in RFC 6381 and ISO-14496-10.
550 // avc1.42x0yy - H.264 Baseline
551 // avc1.4Dx0yy - H.264 Main
552 // avc1.64x0yy - H.264 High
553 //
554 // avc1.xxxxxx & avc3.xxxxxx are considered ambiguous forms that are trying to
555 // signal H.264 Baseline. For example, the idc_level, profile_idc and
556 // constraint_set3_flag pieces may explicitly require decoder to conform to
557 // baseline profile at the specified level (see Annex A and constraint_set0 in
558 // ISO-14496-10).
559 static bool ParseH264CodecID(const std::string& codec_id,
560 MimeUtil::Codec* codec,
561 bool* is_ambiguous) {
562 // Make sure we have avc1.xxxxxx or avc3.xxxxxx , where xxxxxx are hex digits
563 if (!base::StartsWith(codec_id, "avc1.", base::CompareCase::SENSITIVE) &&
564 !base::StartsWith(codec_id, "avc3.", base::CompareCase::SENSITIVE)) {
565 return false;
566 }
567 if (codec_id.size() != 11 ||
568 !base::IsHexDigit(codec_id[5]) || !base::IsHexDigit(codec_id[6]) ||
569 !base::IsHexDigit(codec_id[7]) || !base::IsHexDigit(codec_id[8]) ||
570 !base::IsHexDigit(codec_id[9]) || !base::IsHexDigit(codec_id[10])) {
571 return false;
572 }
573
574 // Validate constraint flags and reserved bits.
575 if (!base::IsHexDigit(codec_id[7]) || codec_id[8] != '0') {
576 *codec = MimeUtil::H264_BASELINE;
577 *is_ambiguous = true;
578 return true;
579 }
580
581 // Extract the profile.
582 std::string profile = base::ToUpperASCII(codec_id.substr(5, 2));
583 if (profile == "42") {
584 *codec = MimeUtil::H264_BASELINE;
585 } else if (profile == "4D") {
586 *codec = MimeUtil::H264_MAIN;
587 } else if (profile == "64") {
588 *codec = MimeUtil::H264_HIGH;
589 } else {
590 *codec = MimeUtil::H264_BASELINE;
591 *is_ambiguous = true;
592 return true;
593 }
594
595 // Validate level.
596 *is_ambiguous = !IsValidH264Level(codec_id.substr(9));
597 return true;
598 } 541 }
599 542
600 #if BUILDFLAG(ENABLE_HEVC_DEMUXING) 543 #if BUILDFLAG(ENABLE_HEVC_DEMUXING)
601 // ISO/IEC FDIS 14496-15 standard section E.3 describes the syntax of codec ids 544 // ISO/IEC FDIS 14496-15 standard section E.3 describes the syntax of codec ids
602 // reserved for HEVC. According to that spec HEVC codec id must start with 545 // reserved for HEVC. According to that spec HEVC codec id must start with
603 // either "hev1." or "hvc1.". We don't yet support full parsing of HEVC codec 546 // either "hev1." or "hvc1.". We don't yet support full parsing of HEVC codec
604 // ids, but since no other codec id starts with those string we'll just treat 547 // ids, but since no other codec id starts with those string we'll just treat
605 // any string starting with "hev1." or "hvc1." as valid HEVC codec ids. 548 // any string starting with "hev1." or "hvc1." as valid HEVC codec ids.
606 // crbug.com/482761 549 // crbug.com/482761
607 static bool ParseHEVCCodecID(const std::string& codec_id, 550 static bool ParseHEVCCodecID(const std::string& codec_id,
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
645 } 588 }
646 589
647 // If |codec_id| is not in |string_to_codec_map_|, then we assume that it is 590 // If |codec_id| is not in |string_to_codec_map_|, then we assume that it is
648 // either H.264 or HEVC/H.265 codec ID because currently those are the only 591 // either H.264 or HEVC/H.265 codec ID because currently those are the only
649 // ones that are not added to the |string_to_codec_map_| and require parsing. 592 // ones that are not added to the |string_to_codec_map_| and require parsing.
650 #if BUILDFLAG(ENABLE_HEVC_DEMUXING) 593 #if BUILDFLAG(ENABLE_HEVC_DEMUXING)
651 if (ParseHEVCCodecID(codec_id, codec, is_ambiguous)) { 594 if (ParseHEVCCodecID(codec_id, codec, is_ambiguous)) {
652 return true; 595 return true;
653 } 596 }
654 #endif 597 #endif
655 return ParseH264CodecID(codec_id, codec, is_ambiguous); 598
599 VideoCodecProfile profile = VIDEO_CODEC_PROFILE_UNKNOWN;
600 uint8_t level_idc = 0;
601 if (ParseAVCCodecId(codec_id, &profile, &level_idc)) {
602 *codec = MimeUtil::H264;
603 *is_ambiguous =
604 (profile != H264PROFILE_BASELINE && profile != H264PROFILE_MAIN &&
605 profile != H264PROFILE_HIGH) ||
606 !IsValidH264Level(level_idc);
607 return true;
608 }
609
610 DVLOG(4) << __FUNCTION__ << ": Unrecognized codec id " << codec_id;
611 return false;
656 } 612 }
657 613
658 bool MimeUtil::IsCodecSupported(Codec codec) const { 614 bool MimeUtil::IsCodecSupported(Codec codec) const {
659 DCHECK_NE(codec, INVALID_CODEC); 615 DCHECK_NE(codec, INVALID_CODEC);
660 616
661 #if defined(OS_ANDROID) 617 #if defined(OS_ANDROID)
662 if (!IsCodecSupportedOnAndroid(codec)) 618 if (!IsCodecSupportedOnAndroid(codec))
663 return false; 619 return false;
664 #endif 620 #endif
665 621
666 return allow_proprietary_codecs_ || !IsCodecProprietary(codec); 622 return allow_proprietary_codecs_ || !IsCodecProprietary(codec);
667 } 623 }
668 624
669 bool MimeUtil::IsCodecProprietary(Codec codec) const { 625 bool MimeUtil::IsCodecProprietary(Codec codec) const {
670 switch (codec) { 626 switch (codec) {
671 case INVALID_CODEC: 627 case INVALID_CODEC:
672 case AC3: 628 case AC3:
673 case EAC3: 629 case EAC3:
674 case MP3: 630 case MP3:
675 case MPEG2_AAC_LC: 631 case MPEG2_AAC_LC:
676 case MPEG2_AAC_MAIN: 632 case MPEG2_AAC_MAIN:
677 case MPEG2_AAC_SSR: 633 case MPEG2_AAC_SSR:
678 case MPEG4_AAC_LC: 634 case MPEG4_AAC_LC:
679 case MPEG4_AAC_SBR_v1: 635 case MPEG4_AAC_SBR_v1:
680 case MPEG4_AAC_SBR_PS_v2: 636 case MPEG4_AAC_SBR_PS_v2:
681 case H264_BASELINE: 637 case H264:
682 case H264_MAIN:
683 case H264_HIGH:
684 case HEVC_MAIN: 638 case HEVC_MAIN:
685 return true; 639 return true;
686 640
687 case PCM: 641 case PCM:
688 case VORBIS: 642 case VORBIS:
689 case OPUS: 643 case OPUS:
690 case VP8: 644 case VP8:
691 case VP9: 645 case VP9:
692 case THEORA: 646 case THEORA:
693 return false; 647 return false;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
734 std::vector<std::string>* codecs_out, 688 std::vector<std::string>* codecs_out,
735 const bool strip) { 689 const bool strip) {
736 g_media_mime_util.Get().ParseCodecString(codecs, codecs_out, strip); 690 g_media_mime_util.Get().ParseCodecString(codecs, codecs_out, strip);
737 } 691 }
738 692
739 void RemoveProprietaryMediaTypesAndCodecsForTests() { 693 void RemoveProprietaryMediaTypesAndCodecsForTests() {
740 g_media_mime_util.Get().RemoveProprietaryMediaTypesAndCodecsForTests(); 694 g_media_mime_util.Get().RemoveProprietaryMediaTypesAndCodecsForTests();
741 } 695 }
742 696
743 } // namespace media 697 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698