MatroskaDecoder.cpp (6721B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "MatroskaDecoder.h" 8 9 #ifdef MOZ_AV1 10 # include "AOMDecoder.h" 11 #endif 12 #include "MediaContainerType.h" 13 #include "PDMFactory.h" 14 #include "PlatformDecoderModule.h" 15 #include "VideoUtils.h" 16 #include "mozilla/StaticPrefs_media.h" 17 #include "nsMimeTypes.h" 18 19 namespace mozilla { 20 21 /* static */ 22 bool MatroskaDecoder::IsMatroskaType(const MediaContainerType& aType) { 23 const auto& mimeType = aType.Type(); 24 return mimeType == MEDIAMIMETYPE(VIDEO_MATROSKA) || 25 mimeType == MEDIAMIMETYPE(VIDEO_MATROSKA_LEGACY) || 26 mimeType == MEDIAMIMETYPE(AUDIO_MATROSKA) || 27 mimeType == MEDIAMIMETYPE(AUDIO_MATROSKA_LEGACY); 28 } 29 30 /* static */ 31 nsTArray<UniquePtr<TrackInfo>> MatroskaDecoder::GetTracksInfo( 32 const MediaContainerType& aType, MediaResult& aError) { 33 nsTArray<UniquePtr<TrackInfo>> tracks; 34 35 aError = NS_OK; 36 37 const MediaCodecs& codecs = aType.ExtendedType().Codecs(); 38 if (codecs.IsEmpty()) { 39 return tracks; 40 } 41 42 // TODO : add more codec support. 43 for (const auto& codec : codecs.Range()) { 44 // Audio codecs 45 if (IsAACCodecString(codec)) { 46 tracks.AppendElement( 47 CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters( 48 "audio/mp4a-latm"_ns, aType)); 49 continue; 50 } 51 if (codec.EqualsLiteral("opus")) { 52 tracks.AppendElement( 53 CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters( 54 "audio/opus"_ns, aType)); 55 continue; 56 } 57 if (codec.EqualsLiteral("vorbis")) { 58 tracks.AppendElement( 59 CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters( 60 "audio/vorbis"_ns, aType)); 61 continue; 62 } 63 // Video codecs 64 if (IsAllowedH264Codec(codec)) { 65 auto trackInfo = 66 CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters( 67 "video/avc"_ns, aType); 68 uint8_t profile = 0, constraint = 0; 69 H264_LEVEL level; 70 MOZ_ALWAYS_TRUE( 71 ExtractH264CodecDetails(codec, profile, constraint, level, 72 H264CodecStringStrictness::Lenient)); 73 uint32_t width = aType.ExtendedType().GetWidth().refOr(1280); 74 uint32_t height = aType.ExtendedType().GetHeight().refOr(720); 75 trackInfo->GetAsVideoInfo()->mExtraData = 76 H264::CreateExtraData(profile, constraint, level, {width, height}); 77 tracks.AppendElement(std::move(trackInfo)); 78 continue; 79 } 80 if (StaticPrefs::media_hevc_enabled() && IsH265CodecString(codec)) { 81 auto trackInfo = 82 CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters( 83 "video/hevc"_ns, aType); 84 tracks.AppendElement(std::move(trackInfo)); 85 continue; 86 } 87 if (IsVP9CodecString(codec)) { 88 auto trackInfo = 89 CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters( 90 "video/vp9"_ns, aType); 91 tracks.AppendElement(std::move(trackInfo)); 92 continue; 93 } 94 if (IsVP8CodecString(codec)) { 95 auto trackInfo = 96 CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters( 97 "video/vp8"_ns, aType); 98 tracks.AppendElement(std::move(trackInfo)); 99 continue; 100 } 101 #ifdef MOZ_AV1 102 if (StaticPrefs::media_av1_enabled() && IsAV1CodecString(codec)) { 103 auto trackInfo = 104 CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters( 105 "video/av1"_ns, aType); 106 AOMDecoder::SetVideoInfo(trackInfo->GetAsVideoInfo(), codec); 107 tracks.AppendElement(std::move(trackInfo)); 108 continue; 109 } 110 #endif 111 aError = MediaResult( 112 NS_ERROR_DOM_MEDIA_FATAL_ERR, 113 RESULT_DETAIL("Unknown codec:%s", NS_ConvertUTF16toUTF8(codec).get())); 114 } 115 return tracks; 116 } 117 118 /* static */ 119 bool MatroskaDecoder::IsSupportedType(const MediaContainerType& aContainerType, 120 DecoderDoctorDiagnostics* aDiagnostics) { 121 if (!StaticPrefs::media_mkv_enabled() || !IsMatroskaType(aContainerType)) { 122 return false; 123 } 124 125 MediaResult rv = NS_OK; 126 auto tracks = GetTracksInfo(aContainerType, rv); 127 if (NS_FAILED(rv)) { 128 return false; 129 } 130 131 if (!tracks.IsEmpty()) { 132 // Look for exact match as we know the codecs used. 133 RefPtr<PDMFactory> platform = new PDMFactory(); 134 for (const auto& track : tracks) { 135 if (!track || 136 platform->Supports(SupportDecoderParams(*track), aDiagnostics) 137 .isEmpty()) { 138 return false; 139 } 140 } 141 return true; 142 } 143 144 // The container doesn't specify codecs, so we guess the content type. 145 // TODO : add more codec support. 146 if (aContainerType.Type() == MEDIAMIMETYPE(AUDIO_MATROSKA)) { 147 tracks.AppendElement( 148 CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters( 149 "audio/mp4a-latm"_ns, aContainerType)); 150 tracks.AppendElement( 151 CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters( 152 "audio/opus"_ns, aContainerType)); 153 tracks.AppendElement( 154 CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters( 155 "audio/vorbis"_ns, aContainerType)); 156 } else { 157 tracks.AppendElement( 158 CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters( 159 "video/avc"_ns, aContainerType)); 160 if (StaticPrefs::media_hevc_enabled()) { 161 tracks.AppendElement( 162 CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters( 163 "video/hevc"_ns, aContainerType)); 164 } 165 tracks.AppendElement( 166 CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters( 167 "video/vp8"_ns, aContainerType)); 168 tracks.AppendElement( 169 CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters( 170 "video/vp9"_ns, aContainerType)); 171 #ifdef MOZ_AV1 172 if (StaticPrefs::media_av1_enabled()) { 173 tracks.AppendElement( 174 CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters( 175 "video/av1"_ns, aContainerType)); 176 } 177 #endif 178 } 179 180 // Check that something is supported at least. 181 RefPtr<PDMFactory> platform = new PDMFactory(); 182 for (const auto& track : tracks) { 183 if (track && !platform->Supports(SupportDecoderParams(*track), aDiagnostics) 184 .isEmpty()) { 185 return true; 186 } 187 } 188 return false; 189 } 190 191 /* static */ 192 nsTArray<UniquePtr<TrackInfo>> MatroskaDecoder::GetTracksInfo( 193 const MediaContainerType& aType) { 194 MediaResult rv = NS_OK; 195 return GetTracksInfo(aType, rv); 196 } 197 198 } // namespace mozilla