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 #ifndef MediaMIMETypes_h_
8 #define MediaMIMETypes_h_
9 
10 #include "VideoUtils.h"
11 #include "mozilla/Maybe.h"
12 #include "nsString.h"
13 
14 namespace mozilla {
15 
16 namespace dom {
17 struct AudioConfiguration;
18 struct VideoConfiguration;
19 }  // namespace dom
20 
21 // Class containing pointing at a media MIME "type/subtype" string literal.
22 // See IsMediaMIMEType for restrictions.
23 // Mainly used to help construct a MediaMIMEType through the statically-checked
24 // MEDIAMIMETYPE macro, or to compare a MediaMIMEType to a literal.
25 class DependentMediaMIMEType {
26  public:
27   // Construction from a literal. Checked in debug builds.
28   // Use MEDIAMIMETYPE macro instead, for static checking.
29   template <size_t N>
DependentMediaMIMEType(const char (& aType)[N])30   explicit DependentMediaMIMEType(const char (&aType)[N])
31       : mMIMEType(aType, N - 1) {
32     MOZ_ASSERT(IsMediaMIMEType(aType, N - 1), "Invalid media MIME type");
33   }
34 
35   // MIME "type/subtype".
AsDependentString()36   const nsDependentCString& AsDependentString() const { return mMIMEType; }
37 
38  private:
39   nsDependentCString mMIMEType;
40 };
41 
42 // Instantiate a DependentMediaMIMEType from a literal. Statically checked.
43 #define MEDIAMIMETYPE(LIT)                                          \
44   static_cast<const DependentMediaMIMEType&>([]() {                 \
45     static_assert(IsMediaMIMEType(LIT), "Invalid media MIME type"); \
46     return DependentMediaMIMEType(LIT);                             \
47   }())
48 
49 // Class containing only pre-parsed lowercase media MIME type/subtype.
50 class MediaMIMEType {
51  public:
52   // Construction from a DependentMediaMIMEType, with its inherent checks.
53   // Implicit so MEDIAMIMETYPE can be used wherever a MediaMIMEType is expected.
MediaMIMEType(const DependentMediaMIMEType & aType)54   MOZ_IMPLICIT MediaMIMEType(const DependentMediaMIMEType& aType)
55       : mMIMEType(aType.AsDependentString()) {}
56 
57   // MIME "type/subtype", always lowercase.
AsString()58   const nsCString& AsString() const { return mMIMEType; }
59 
60   // Comparison with DependentMediaMIMEType.
61   // Useful to compare to MEDIAMIMETYPE literals.
62   bool operator==(const DependentMediaMIMEType& aOther) const {
63     return mMIMEType.Equals(aOther.AsDependentString());
64   }
65   bool operator!=(const DependentMediaMIMEType& aOther) const {
66     return !mMIMEType.Equals(aOther.AsDependentString());
67   }
68 
69   bool operator==(const MediaMIMEType& aOther) const {
70     return mMIMEType.Equals(aOther.mMIMEType);
71   }
72   bool operator!=(const MediaMIMEType& aOther) const {
73     return !mMIMEType.Equals(aOther.mMIMEType);
74   }
75 
76   // True if type starts with "application/".
77   bool HasApplicationMajorType() const;
78   // True if type starts with "audio/".
79   // Note that some audio content could be stored in a "video/..." container!
80   bool HasAudioMajorType() const;
81   // True if type starts with "video/".
82   // Note that this does not guarantee 100% that the content is actually video!
83   // (e.g., "video/webm" could contain a vorbis audio track.)
84   bool HasVideoMajorType() const;
85 
86   size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
87 
88  private:
89   friend Maybe<MediaMIMEType> MakeMediaMIMEType(const nsAString& aType);
90   friend class MediaExtendedMIMEType;
91   explicit MediaMIMEType(const nsACString& aType);
92 
93   nsCString mMIMEType;  // UTF8 MIME "type/subtype".
94 };
95 
96 Maybe<MediaMIMEType> MakeMediaMIMEType(const nsAString& aType);
97 Maybe<MediaMIMEType> MakeMediaMIMEType(const nsACString& aType);
98 Maybe<MediaMIMEType> MakeMediaMIMEType(const char* aType);
99 
100 // A list of case-sensitive codecs attached to a MediaExtendedMIMEType.
101 class MediaCodecs {
102  public:
103   MediaCodecs() = default;
104   // Construction from a comma-separated list of codecs. Unchecked.
MediaCodecs(const nsAString & aCodecs)105   explicit MediaCodecs(const nsAString& aCodecs) : mCodecs(aCodecs) {}
106   // Construction from a literal comma-separated list of codecs. Unchecked.
107   template <size_t N>
MediaCodecs(const char (& aCodecs)[N])108   explicit MediaCodecs(const char (&aCodecs)[N])
109       : mCodecs(NS_ConvertUTF8toUTF16(aCodecs, N - 1)) {}
110 
IsEmpty()111   bool IsEmpty() const { return mCodecs.IsEmpty(); }
AsString()112   const nsString& AsString() const { return mCodecs; }
113 
114   using RangeType =
115       const StringListRange<nsString,
116                             StringListRangeEmptyItems::ProcessEmptyItems>;
117 
118   // Produces a range object with begin()&end(), can be used in range-for loops.
119   // This will iterate through all codecs, even empty ones (except if the
120   // original list was an empty string). Iterators dereference to
121   // 'const nsDependentString', valid for as long as this MediaCodecs object.
Range()122   RangeType Range() const { return RangeType(mCodecs); };
123 
124   // Does this list of codecs contain the given aCodec?
125   bool Contains(const nsAString& aCodec) const;
126   // Does this list of codecs contain *all* the codecs in the given list?
127   bool ContainsAll(const MediaCodecs& aCodecs) const;
128 
129   // Does this list of codecs contain a codec starting with the given prefix?
130   bool ContainsPrefix(const nsAString& aCodecPrefix) const;
131 
132   template <size_t N>
133   bool operator==(const char (&aType)[N]) const {
134     return mCodecs.EqualsASCII(aType, N - 1);
135   }
136 
137   size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
138 
139  private:
140   // UTF16 comma-separated list of codecs.
141   // See http://www.rfc-editor.org/rfc/rfc4281.txt for the description
142   // of the 'codecs' parameter.
143   nsString mCodecs;
144 };
145 
146 // Class containing pre-parsed media MIME type parameters, e.g.:
147 // MIME type/subtype, optional codecs, etc.
148 class MediaExtendedMIMEType {
149  public:
150   explicit MediaExtendedMIMEType(const MediaMIMEType& aType);
151   explicit MediaExtendedMIMEType(MediaMIMEType&& aType);
152 
153   // MIME "type/subtype".
Type()154   const MediaMIMEType& Type() const { return mMIMEType; }
155 
156   // Was there an explicit 'codecs' parameter provided?
HaveCodecs()157   bool HaveCodecs() const { return mHaveCodecs; }
158   // Codecs. May be empty if not provided or explicitly provided as empty.
Codecs()159   const MediaCodecs& Codecs() const { return mCodecs; }
160 
161   // Sizes and rates.
GetWidth()162   Maybe<int32_t> GetWidth() const { return GetMaybeNumber(mWidth); }
GetHeight()163   Maybe<int32_t> GetHeight() const { return GetMaybeNumber(mHeight); }
GetFramerate()164   Maybe<double> GetFramerate() const { return GetMaybeNumber(mFramerate); }
GetBitrate()165   Maybe<int32_t> GetBitrate() const { return GetMaybeNumber(mBitrate); }
GetChannels()166   Maybe<int32_t> GetChannels() const { return GetMaybeNumber(mChannels); }
GetSamplerate()167   Maybe<int32_t> GetSamplerate() const { return GetMaybeNumber(mSamplerate); }
168 
169   // Original string. Note that "type/subtype" may not be lowercase,
170   // use Type().AsString() instead to get the normalized "type/subtype".
OriginalString()171   const nsCString& OriginalString() const { return mOriginalString; }
172 
173   size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
174 
175  private:
176   friend Maybe<MediaExtendedMIMEType> MakeMediaExtendedMIMEType(
177       const nsAString& aType);
178   friend Maybe<MediaExtendedMIMEType> MakeMediaExtendedMIMEType(
179       const dom::VideoConfiguration& aConfig);
180   friend Maybe<MediaExtendedMIMEType> MakeMediaExtendedMIMEType(
181       const dom::AudioConfiguration& aConfig);
182 
183   MediaExtendedMIMEType(const nsACString& aOriginalString,
184                         const nsACString& aMIMEType, bool aHaveCodecs,
185                         const nsAString& aCodecs, int32_t aWidth,
186                         int32_t aHeight, double aFramerate, int32_t aBitrate);
187   MediaExtendedMIMEType(const nsACString& aOriginalString,
188                         const nsACString& aMIMEType, bool aHaveCodecs,
189                         const nsAString& aCodecs, int32_t aChannels,
190                         int32_t aSamplerate, int32_t aBitrate);
191 
192   template <typename T>
GetMaybeNumber(T aNumber)193   Maybe<T> GetMaybeNumber(T aNumber) const {
194     return (aNumber < 0) ? Maybe<T>(Nothing()) : Some(T(aNumber));
195   }
196 
197   nsCString mOriginalString;  // Original full string.
198   MediaMIMEType mMIMEType;    // MIME type/subtype.
199   bool mHaveCodecs = false;   // If false, mCodecs must be empty.
200   MediaCodecs mCodecs;
201   // For video
202   int32_t mWidth = -1;     // -1 if not provided.
203   int32_t mHeight = -1;    // -1 if not provided.
204   double mFramerate = -1;  // -1 if not provided.
205   // For audio
206   int32_t mChannels = -1;    // -1 if not provided.
207   int32_t mSamplerate = -1;  // -1 if not provided.
208   // For both audio and video.
209   int32_t mBitrate = -1;  // -1 if not provided.
210 };
211 
212 Maybe<MediaExtendedMIMEType> MakeMediaExtendedMIMEType(const nsAString& aType);
213 Maybe<MediaExtendedMIMEType> MakeMediaExtendedMIMEType(const nsACString& aType);
214 Maybe<MediaExtendedMIMEType> MakeMediaExtendedMIMEType(const char* aType);
215 Maybe<MediaExtendedMIMEType> MakeMediaExtendedMIMEType(
216     const dom::VideoConfiguration& aConfig);
217 Maybe<MediaExtendedMIMEType> MakeMediaExtendedMIMEType(
218     const dom::AudioConfiguration& aConfig);
219 
220 }  // namespace mozilla
221 
222 #endif  // MediaMIMETypes_h_
223