Bug 1329561 - MediaContentType is always valid - r?jya
MediaContentType can only be created through MakeMediaContentType(), which
returns a Maybe<MediaContentType>.
If the return value is Nothing, parsing failed.
Otherwise the contained MediaContentType object is guaranteed to be valid;
E.g., GetMIMEType() will always return a non-empty string.
Note that this interface will change a lot in the following bugs&patches, so
please don't worry about the 'Get' in the never-failing GetMIMEType(), it will
be gone soon!
MozReview-Commit-ID: IjGKkQ6RVd4
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -4468,18 +4468,21 @@ void HTMLMediaElement::UnbindFromTree(bo
RunInStableState(task);
}
/* static */
CanPlayStatus
HTMLMediaElement::GetCanPlay(const nsAString& aType,
DecoderDoctorDiagnostics* aDiagnostics)
{
- MediaContentType contentType{aType};
- return DecoderTraits::CanHandleContentType(contentType, aDiagnostics);
+ Maybe<MediaContentType> contentType = MakeMediaContentType(aType);
+ if (!contentType) {
+ return CANPLAY_NO;
+ }
+ return DecoderTraits::CanHandleContentType(*contentType, aDiagnostics);
}
NS_IMETHODIMP
HTMLMediaElement::CanPlayType(const nsAString& aType, nsAString& aResult)
{
DecoderDoctorDiagnostics diagnostics;
CanPlayStatus canPlay = GetCanPlay(aType, &diagnostics);
diagnostics.StoreFormatDiagnostics(
--- a/dom/media/DecoderTraits.cpp
+++ b/dom/media/DecoderTraits.cpp
@@ -139,18 +139,21 @@ IsMP4SupportedType(const MediaContentTyp
DecoderDoctorDiagnostics* aDiagnostics)
{
return MP4Decoder::CanHandleMediaType(aParsedType, aDiagnostics);
}
static bool
IsMP4SupportedType(const nsACString& aType,
DecoderDoctorDiagnostics* aDiagnostics)
{
- MediaContentType contentType{aType};
- return IsMP4SupportedType(contentType, aDiagnostics);
+ Maybe<MediaContentType> contentType = MakeMediaContentType(aType);
+ if (!contentType) {
+ return false;
+ }
+ return IsMP4SupportedType(*contentType, aDiagnostics);
}
#endif
/* static */ bool
DecoderTraits::IsMP4TypeAndEnabled(const nsACString& aType,
DecoderDoctorDiagnostics* aDiagnostics)
{
#ifdef MOZ_FMP4
@@ -188,17 +191,16 @@ IsFlacSupportedType(const nsACString& aT
return FlacDecoder::CanHandleMediaType(aType, aCodecs);
}
static
CanPlayStatus
CanHandleCodecsType(const MediaContentType& aType,
DecoderDoctorDiagnostics* aDiagnostics)
{
- MOZ_ASSERT(aType.IsValid());
// We should have been given a codecs string, though it may be empty.
MOZ_ASSERT(aType.HaveCodecs());
char const* const* codecList = nullptr;
if (IsOggTypeAndEnabled(aType.GetMIMEType())) {
if (IsOggSupportedType(aType.GetMIMEType(), aType.GetCodecs())) {
return CANPLAY_YES;
} else {
@@ -334,20 +336,16 @@ CanHandleMediaType(const MediaContentTyp
return CANPLAY_NO;
}
/* static */
CanPlayStatus
DecoderTraits::CanHandleContentType(const MediaContentType& aContentType,
DecoderDoctorDiagnostics* aDiagnostics)
{
- if (!aContentType.IsValid()) {
- return CANPLAY_NO;
- }
-
return CanHandleMediaType(aContentType, aDiagnostics);
}
/* static */
bool DecoderTraits::ShouldHandleMediaType(const char* aMIMEType,
DecoderDoctorDiagnostics* aDiagnostics)
{
if (IsWaveSupportedType(nsDependentCString(aMIMEType))) {
@@ -365,18 +363,21 @@ bool DecoderTraits::ShouldHandleMediaTyp
if (nsDependentCString(aMIMEType).EqualsASCII("video/quicktime")) {
RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
if (pluginHost &&
pluginHost->HavePluginForType(nsDependentCString(aMIMEType))) {
return false;
}
}
- MediaContentType parsed{nsDependentCString(aMIMEType)};
- return CanHandleMediaType(parsed, aDiagnostics)
+ Maybe<MediaContentType> parsed = MakeMediaContentType(aMIMEType);
+ if (!parsed) {
+ return false;
+ }
+ return CanHandleMediaType(*parsed, aDiagnostics)
!= CANPLAY_NO;
}
// Instantiates but does not initialize decoder.
static
already_AddRefed<MediaDecoder>
InstantiateDecoder(const nsACString& aType,
MediaDecoderOwner* aOwner,
--- a/dom/media/MediaContentType.cpp
+++ b/dom/media/MediaContentType.cpp
@@ -5,27 +5,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "MediaContentType.h"
#include "nsContentTypeParser.h"
namespace mozilla {
-MediaContentType::MediaContentType(const nsAString& aType)
-{
- Populate(aType);
-}
-
-MediaContentType::MediaContentType(const nsACString& aType)
-{
- NS_ConvertUTF8toUTF16 typeUTF16(aType);
- Populate(typeUTF16);
-}
-
static int32_t
GetParameterAsNumber(const nsContentTypeParser& aParser,
const char* aParameter,
const int32_t aErrorReturn)
{
nsAutoString parameterString;
nsresult rv = aParser.GetParameter(aParameter, parameterString);
if (NS_FAILED_impl(rv)) {
@@ -33,28 +22,59 @@ GetParameterAsNumber(const nsContentType
}
int32_t number = parameterString.ToInteger(&rv);
if (MOZ_UNLIKELY(NS_FAILED_impl(rv))) {
return aErrorReturn;
}
return number;
}
-void
+bool
MediaContentType::Populate(const nsAString& aType)
{
+ MOZ_ASSERT(NS_IsMainThread());
+
nsContentTypeParser parser(aType);
nsAutoString mime;
nsresult rv = parser.GetType(mime);
- if (NS_SUCCEEDED(rv)) {
- mMIMEType = NS_ConvertUTF16toUTF8(mime);
+ if (!NS_SUCCEEDED(rv) || mime.IsEmpty()) {
+ return false;
}
+ mMIMEType = NS_ConvertUTF16toUTF8(mime);
+
rv = parser.GetParameter("codecs", mCodecs);
mHaveCodecs = NS_SUCCEEDED(rv);
mWidth = GetParameterAsNumber(parser, "width", -1);
mHeight = GetParameterAsNumber(parser, "height", -1);
mFramerate = GetParameterAsNumber(parser, "framerate", -1);
mBitrate = GetParameterAsNumber(parser, "bitrate", -1);
+
+ return true;
+}
+
+Maybe<MediaContentType>
+MakeMediaContentType(const nsAString& aType)
+{
+ Maybe<MediaContentType> type{Some(MediaContentType{})};
+ if (!type->Populate(aType)) {
+ type.reset();
+ }
+ return type;
+}
+
+Maybe<MediaContentType>
+MakeMediaContentType(const nsACString& aType)
+{
+ return MakeMediaContentType(NS_ConvertUTF8toUTF16(aType));
+}
+
+Maybe<MediaContentType>
+MakeMediaContentType(const char* aType)
+{
+ if (!aType) {
+ return Nothing();
+ }
+ return MakeMediaContentType(nsDependentCString(aType));
}
} // namespace mozilla
--- a/dom/media/MediaContentType.h
+++ b/dom/media/MediaContentType.h
@@ -12,49 +12,47 @@
namespace mozilla {
// Structure containing pre-parsed content type parameters, e.g.:
// MIME type, optional codecs, etc.
class MediaContentType
{
public:
- // Parse UTF16 string to extract parameters.
- explicit MediaContentType(const nsAString& aType);
- // Parse UTF8 string to extract parameters.
- explicit MediaContentType(const nsACString& aType);
-
- bool IsValid() const { return !GetMIMEType().IsEmpty(); }
-
- // MIME type. Empty if construction arguments could not be parsed.
+ // MIME type. Guaranteed not to be empty.
const nsACString& GetMIMEType() const { return mMIMEType; }
// Was there an explicit 'codecs' parameter provided?
bool HaveCodecs() const { return mHaveCodecs; }
// Codecs. May be empty if not provided or explicitly provided as empty.
const nsAString& GetCodecs() const { return mCodecs; }
// Sizes and rates.
Maybe<int32_t> GetWidth() const { return GetMaybeNumber(mWidth); }
Maybe<int32_t> GetHeight() const { return GetMaybeNumber(mHeight); }
Maybe<int32_t> GetFramerate() const { return GetMaybeNumber(mFramerate); }
Maybe<int32_t> GetBitrate() const { return GetMaybeNumber(mBitrate); }
private:
- void Populate(const nsAString& aType);
+ friend Maybe<MediaContentType> MakeMediaContentType(const nsAString& aType);
+ bool Populate(const nsAString& aType);
Maybe<int32_t> GetMaybeNumber(int32_t aNumber) const
{
return (aNumber < 0) ? Maybe<int32_t>(Nothing()) : Some(int32_t(aNumber));
}
- nsCString mMIMEType; // UTF8 MIME type. Empty if parsing failed.
+ nsCString mMIMEType; // UTF8 MIME type.
bool mHaveCodecs; // If false, mCodecs must be empty.
nsString mCodecs;
int32_t mWidth; // -1 if not provided.
int32_t mHeight; // -1 if not provided.
int32_t mFramerate; // -1 if not provided.
int32_t mBitrate; // -1 if not provided.
};
+Maybe<MediaContentType> MakeMediaContentType(const nsAString& aType);
+Maybe<MediaContentType> MakeMediaContentType(const nsACString& aType);
+Maybe<MediaContentType> MakeMediaContentType(const char* aType);
+
} // namespace mozilla
#endif // MediaContentType_h_
--- a/dom/media/mediasource/MediaSource.cpp
+++ b/dom/media/mediasource/MediaSource.cpp
@@ -88,29 +88,29 @@ namespace dom {
/* static */
nsresult
MediaSource::IsTypeSupported(const nsAString& aType, DecoderDoctorDiagnostics* aDiagnostics)
{
if (aType.IsEmpty()) {
return NS_ERROR_DOM_TYPE_ERR;
}
- MediaContentType contentType{aType};
- if (!contentType.IsValid()) {
+ Maybe<MediaContentType> contentType = MakeMediaContentType(aType);
+ if (!contentType) {
return NS_ERROR_DOM_TYPE_ERR;
}
- if (DecoderTraits::CanHandleContentType(contentType, aDiagnostics)
+ if (DecoderTraits::CanHandleContentType(*contentType, aDiagnostics)
== CANPLAY_NO) {
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}
// Now we know that this media type could be played.
// MediaSource imposes extra restrictions, and some prefs.
- const nsACString& mimeType = contentType.GetMIMEType();
+ const nsACString& mimeType = contentType->GetMIMEType();
if (mimeType.EqualsASCII("video/mp4") || mimeType.EqualsASCII("audio/mp4")) {
if (!Preferences::GetBool("media.mediasource.mp4.enabled", false)) {
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}
return NS_OK;
}
if (mimeType.EqualsASCII("video/webm")) {
if (!(Preferences::GetBool("media.mediasource.webm.enabled", false) ||
@@ -232,22 +232,22 @@ MediaSource::AddSourceBuffer(const nsASt
if (mSourceBuffers->Length() >= MAX_SOURCE_BUFFERS) {
aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR);
return nullptr;
}
if (mReadyState != MediaSourceReadyState::Open) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return nullptr;
}
- MediaContentType contentType{aType};
- if (!contentType.IsValid()) {
+ Maybe<MediaContentType> contentType = MakeMediaContentType(aType);
+ if (!contentType) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
- const nsACString& mimeType = contentType.GetMIMEType();
+ const nsACString& mimeType = contentType->GetMIMEType();
RefPtr<SourceBuffer> sourceBuffer = new SourceBuffer(this, mimeType);
if (!sourceBuffer) {
aRv.Throw(NS_ERROR_FAILURE); // XXX need a better error here
return nullptr;
}
mSourceBuffers->Append(sourceBuffer);
MSE_DEBUG("sourceBuffer=%p", sourceBuffer.get());
return sourceBuffer.forget();