1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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/. */
7 #include "MediaMIMETypes.h"
9 #include "nsContentTypeParser.h"
10 #include "mozilla/dom/MediaCapabilitiesBinding.h"
15 static bool StartsWith(const nsACString
& string
, const char (&prefix
)[N
]) {
16 if (N
- 1 > string
.Length()) {
19 return memcmp(string
.Data(), prefix
, N
- 1) == 0;
22 bool MediaMIMEType::HasApplicationMajorType() const {
23 return StartsWith(mMIMEType
, "application/");
26 bool MediaMIMEType::HasAudioMajorType() const {
27 return StartsWith(mMIMEType
, "audio/");
30 bool MediaMIMEType::HasVideoMajorType() const {
31 return StartsWith(mMIMEType
, "video/");
34 size_t MediaMIMEType::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf
) const {
35 return mMIMEType
.SizeOfExcludingThisIfUnshared(aMallocSizeOf
);
38 MediaMIMEType::MediaMIMEType(const nsACString
& aType
) : mMIMEType(aType
) {}
40 Maybe
<MediaMIMEType
> MakeMediaMIMEType(const nsAString
& aType
) {
41 nsContentTypeParser
parser(aType
);
43 nsresult rv
= parser
.GetType(mime
);
44 if (!NS_SUCCEEDED(rv
) || mime
.IsEmpty()) {
48 NS_ConvertUTF16toUTF8 mime8
{mime
};
49 if (!IsMediaMIMEType(mime8
)) {
53 return Some(MediaMIMEType(mime8
));
56 Maybe
<MediaMIMEType
> MakeMediaMIMEType(const nsACString
& aType
) {
57 return MakeMediaMIMEType(NS_ConvertUTF8toUTF16(aType
));
60 Maybe
<MediaMIMEType
> MakeMediaMIMEType(const char* aType
) {
64 return MakeMediaMIMEType(nsDependentCString(aType
));
67 bool MediaCodecs::Contains(const nsAString
& aCodec
) const {
68 for (const auto& myCodec
: Range()) {
69 if (myCodec
== aCodec
) {
76 bool MediaCodecs::ContainsAll(const MediaCodecs
& aCodecs
) const {
77 const auto& codecsToTest
= aCodecs
.Range();
78 for (const auto& codecToTest
: codecsToTest
) {
79 if (!Contains(codecToTest
)) {
86 bool MediaCodecs::ContainsPrefix(const nsAString
& aCodecPrefix
) const {
87 const size_t prefixLength
= aCodecPrefix
.Length();
88 for (const auto& myCodec
: Range()) {
89 if (myCodec
.Length() >= prefixLength
&&
90 memcmp(myCodec
.Data(), aCodecPrefix
.Data(),
91 prefixLength
* sizeof(char16_t
)) == 0) {
98 size_t MediaCodecs::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf
) const {
99 return mCodecs
.SizeOfExcludingThisIfUnshared(aMallocSizeOf
);
102 static int32_t GetParameterAsNumber(const nsContentTypeParser
& aParser
,
103 const char* aParameter
,
104 const int32_t aErrorReturn
) {
105 nsAutoString parameterString
;
106 nsresult rv
= aParser
.GetParameter(aParameter
, parameterString
);
107 if (NS_FAILED_impl(rv
)) {
110 int32_t number
= parameterString
.ToInteger(&rv
);
111 if (MOZ_UNLIKELY(NS_FAILED_impl(rv
))) {
117 MediaExtendedMIMEType::MediaExtendedMIMEType(
118 const nsACString
& aOriginalString
, const nsACString
& aMIMEType
,
119 bool aHaveCodecs
, const nsAString
& aCodecs
, int32_t aWidth
, int32_t aHeight
,
120 double aFramerate
, int32_t aBitrate
)
121 : mOriginalString(aOriginalString
),
122 mMIMEType(aMIMEType
),
123 mHaveCodecs(aHaveCodecs
),
127 mFramerate(aFramerate
),
128 mBitrate(aBitrate
) {}
130 MediaExtendedMIMEType::MediaExtendedMIMEType(
131 const nsACString
& aOriginalString
, const nsACString
& aMIMEType
,
132 bool aHaveCodecs
, const nsAString
& aCodecs
, int32_t aChannels
,
133 int32_t aSamplerate
, int32_t aBitrate
)
134 : mOriginalString(aOriginalString
),
135 mMIMEType(aMIMEType
),
136 mHaveCodecs(aHaveCodecs
),
138 mChannels(aChannels
),
139 mSamplerate(aSamplerate
),
140 mBitrate(aBitrate
) {}
142 MediaExtendedMIMEType::MediaExtendedMIMEType(const MediaMIMEType
& aType
)
143 : mOriginalString(aType
.AsString()), mMIMEType(aType
) {}
145 MediaExtendedMIMEType::MediaExtendedMIMEType(MediaMIMEType
&& aType
)
146 : mOriginalString(aType
.AsString()), mMIMEType(std::move(aType
)) {}
148 Maybe
<MediaExtendedMIMEType
> MakeMediaExtendedMIMEType(const nsAString
& aType
) {
149 nsContentTypeParser
parser(aType
);
151 nsresult rv
= parser
.GetType(mime
);
152 if (!NS_SUCCEEDED(rv
) || mime
.IsEmpty()) {
156 NS_ConvertUTF16toUTF8 mime8
{mime
};
157 if (!IsMediaMIMEType(mime8
)) {
162 rv
= parser
.GetParameter("codecs", codecs
);
163 bool haveCodecs
= NS_SUCCEEDED(rv
);
165 int32_t width
= GetParameterAsNumber(parser
, "width", -1);
166 int32_t height
= GetParameterAsNumber(parser
, "height", -1);
167 double framerate
= GetParameterAsNumber(parser
, "framerate", -1);
168 int32_t bitrate
= GetParameterAsNumber(parser
, "bitrate", -1);
170 return Some(MediaExtendedMIMEType(NS_ConvertUTF16toUTF8(aType
), mime8
,
171 haveCodecs
, codecs
, width
, height
,
172 framerate
, bitrate
));
175 Maybe
<MediaExtendedMIMEType
> MakeMediaExtendedMIMEType(
176 const dom::VideoConfiguration
& aConfig
) {
177 if (aConfig
.mContentType
.IsEmpty()) {
180 nsContentTypeParser
parser(aConfig
.mContentType
);
182 nsresult rv
= parser
.GetType(mime
);
183 if (!NS_SUCCEEDED(rv
) || mime
.IsEmpty()) {
187 NS_ConvertUTF16toUTF8 mime8
{mime
};
188 if (!IsMediaMIMEType(mime8
)) {
193 rv
= parser
.GetParameter("codecs", codecs
);
194 bool haveCodecs
= NS_SUCCEEDED(rv
);
196 if (!std::isfinite(aConfig
.mFramerate
) || aConfig
.mFramerate
<= 0.0) {
200 return Some(MediaExtendedMIMEType(
201 NS_ConvertUTF16toUTF8(aConfig
.mContentType
), mime8
, haveCodecs
, codecs
,
202 aConfig
.mWidth
, aConfig
.mHeight
, aConfig
.mFramerate
, aConfig
.mBitrate
));
205 Maybe
<MediaExtendedMIMEType
> MakeMediaExtendedMIMEType(
206 const dom::AudioConfiguration
& aConfig
) {
207 if (aConfig
.mContentType
.IsEmpty()) {
210 nsContentTypeParser
parser(aConfig
.mContentType
);
212 nsresult rv
= parser
.GetType(mime
);
213 if (!NS_SUCCEEDED(rv
) || mime
.IsEmpty()) {
217 NS_ConvertUTF16toUTF8 mime8
{mime
};
218 if (!IsMediaMIMEType(mime8
)) {
223 rv
= parser
.GetParameter("codecs", codecs
);
224 bool haveCodecs
= NS_SUCCEEDED(rv
);
226 int32_t channels
= 2; // use a stereo config if not known.
227 if (aConfig
.mChannels
.WasPassed()) {
228 // A channels string was passed. Make sure it is valid.
230 double value
= aConfig
.mChannels
.Value().ToDouble(&error
);
231 if (NS_FAILED(error
)) {
234 // Value is a channel configuration such as 5.1. We want to treat this as 6.
236 double fp
= value
- channels
;
237 // round up as .1 and .2 aren't exactly expressible in binary.
238 channels
+= (fp
* 10) + .5;
241 return Some(MediaExtendedMIMEType(
242 NS_ConvertUTF16toUTF8(aConfig
.mContentType
), mime8
, haveCodecs
, codecs
,
244 aConfig
.mSamplerate
.WasPassed() ? aConfig
.mSamplerate
.Value() : 48000,
245 aConfig
.mBitrate
.WasPassed() ? aConfig
.mBitrate
.Value() : 131072));
248 size_t MediaExtendedMIMEType::SizeOfExcludingThis(
249 MallocSizeOf aMallocSizeOf
) const {
250 return mOriginalString
.SizeOfExcludingThisIfUnshared(aMallocSizeOf
) +
251 mMIMEType
.SizeOfExcludingThis(aMallocSizeOf
) +
252 mCodecs
.SizeOfExcludingThis(aMallocSizeOf
);
255 Maybe
<MediaExtendedMIMEType
> MakeMediaExtendedMIMEType(
256 const nsACString
& aType
) {
257 return MakeMediaExtendedMIMEType(NS_ConvertUTF8toUTF16(aType
));
260 Maybe
<MediaExtendedMIMEType
> MakeMediaExtendedMIMEType(const char* aType
) {
264 return MakeMediaExtendedMIMEType(nsDependentCString(aType
));
267 } // namespace mozilla