Bug 963238: Support isTypeSupported() in MediaRecorder, and throw on invalid mimetypes at construction r=cpearce,khuey

MozReview-Commit-ID: LPIJMSgXwxf
This commit is contained in:
Randell Jesup 2016-03-06 22:48:16 -05:00
parent 882c0cc882
commit f2f3650e43
7 changed files with 165 additions and 0 deletions

View File

@ -27,6 +27,8 @@
#include "nsProxyRelease.h"
#include "nsTArray.h"
#include "GeckoProfiler.h"
#include "nsContentTypeParser.h"
#include "nsCharSeparatedTokenizer.h"
#ifdef LOG
#undef LOG
@ -971,6 +973,11 @@ MediaRecorder::Constructor(const GlobalObject& aGlobal,
return nullptr;
}
if (!IsTypeSupported(aInitDict.mMimeType)) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
RefPtr<MediaRecorder> object = new MediaRecorder(aStream, ownerWindow);
object->SetOptions(aInitDict);
return object.forget();
@ -1005,6 +1012,11 @@ MediaRecorder::Constructor(const GlobalObject& aGlobal,
return nullptr;
}
if (!IsTypeSupported(aInitDict.mMimeType)) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
RefPtr<MediaRecorder> object = new MediaRecorder(aSrcAudioNode,
aSrcOutput,
ownerWindow);
@ -1035,6 +1047,107 @@ MediaRecorder::SetOptions(const MediaRecorderOptions& aInitDict)
}
}
static char const *const gWebMAudioEncoderCodecs[3] = {
"vorbis",
"opus",
// no VP9 yet
nullptr,
};
static char const *const gWebMVideoEncoderCodecs[5] = {
"vorbis",
"opus",
"vp8",
"vp8.0",
// no VP9 yet
nullptr,
};
static char const *const gOggAudioEncoderCodecs[2] = {
"opus",
// we could support vorbis here too, but don't
nullptr,
};
template <class String>
static bool
CodecListContains(char const *const * aCodecs, const String& aCodec)
{
for (int32_t i = 0; aCodecs[i]; ++i) {
if (aCodec.EqualsASCII(aCodecs[i]))
return true;
}
return false;
}
/* static */
bool
MediaRecorder::IsTypeSupported(GlobalObject& aGlobal, const nsAString& aMIMEType)
{
return IsTypeSupported(aMIMEType);
}
/* static */
bool
MediaRecorder::IsTypeSupported(const nsAString& aMIMEType)
{
char const* const* codeclist = nullptr;
if (aMIMEType.IsEmpty()) {
return true;
}
nsContentTypeParser parser(aMIMEType);
nsAutoString mimeType;
nsresult rv = parser.GetType(mimeType);
if (NS_FAILED(rv)) {
return false;
}
// effectively a 'switch (mimeType) {'
if (mimeType.EqualsLiteral(AUDIO_OGG)) {
if (MediaDecoder::IsOggEnabled() && MediaDecoder::IsOpusEnabled()) {
codeclist = gOggAudioEncoderCodecs;
}
}
#ifdef MOZ_WEBM_ENCODER
else if (mimeType.EqualsLiteral(VIDEO_WEBM) &&
MediaEncoder::IsWebMEncoderEnabled()) {
codeclist = gWebMVideoEncoderCodecs;
}
#endif
#ifdef MOZ_OMX_ENCODER
// We're working on MP4 encoder support for desktop
else if (mimeType.EqualsLiteral(VIDEO_MP4) ||
mimeType.EqualsLiteral(AUDIO_3GPP) ||
mimeType.EqualsLiteral(AUDIO_3GPP2)) {
if (MediaEncoder::IsOMXEncoderEnabled()) {
// XXX check codecs for MP4/3GPP
return true;
}
}
#endif
// codecs don't matter if we don't support the container
if (!codeclist) {
return false;
}
// now filter on codecs, and if needed rescind support
nsAutoString codecstring;
rv = parser.GetParameter("codecs", codecstring);
nsTArray<nsString> codecs;
if (!ParseCodecsString(codecstring, codecs)) {
return false;
}
for (const nsString& codec : codecs) {
if (!CodecListContains(codeclist, codec)) {
// Totally unsupported codec
return false;
}
}
return true;
}
nsresult
MediaRecorder::CreateAndDispatchBlobEvent(already_AddRefed<nsIDOMBlob>&& aBlob)
{

View File

@ -22,6 +22,7 @@ class ErrorResult;
class MediaInputPort;
struct MediaRecorderOptions;
class MediaStream;
class GlobalObject;
namespace dom {
@ -78,6 +79,9 @@ public:
// Return the current encoding MIME type selected by the MediaEncoder.
void GetMimeType(nsString &aMimeType);
static bool IsTypeSupported(GlobalObject& aGlobal, const nsAString& aType);
static bool IsTypeSupported(const nsAString& aType);
// Construct a recorder with a DOM media stream object as its source.
static already_AddRefed<MediaRecorder>
Constructor(const GlobalObject& aGlobal,

View File

@ -732,6 +732,12 @@ tags=msg capturestream
tags=msg capturestream
[test_mediarecorder_unsupported_src.html]
tags=msg
[test_mediarecorder_webm_support.html]
skip-if = os == 'android' || arch == 'arm' || arch == 'arm64'
tags=msg
[test_mediarecorder_mp4_support.html]
skip-if = toolkit != 'gonk' || android_version < '17' # Android/Gonk before SDK version 17 does not have the OMX Encoder API.
tags=msg
[test_mediarecorder_record_getdata_afterstart.html]
tags=msg capturestream
[test_mediatrack_consuming_mediaresource.html]

View File

@ -0,0 +1,16 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Media Recording - test mp4 MIME support</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
ok(MediaRecorder.isTypeSupported('video/mp4'), 'Should support video/mp4');
</script>
</head>
</html>

View File

@ -10,7 +10,15 @@
<pre id="test">
<script class="testbody" type="text/javascript">
function startTest() {
// also do general checks on mimetype support for audio-only
ok(MediaRecorder.isTypeSupported("audio/ogg"), 'Should support audio/ogg');
ok(MediaRecorder.isTypeSupported('audio/ogg; codecs="opus"'), 'Should support audio/ogg+opus');
ok(!MediaRecorder.isTypeSupported('audio/ogg; codecs="foobar"'), 'Should not support audio/ogg + unknown_codec');
ok(!MediaRecorder.isTypeSupported("video/webm"), 'Should not support video/webm');
ok(!MediaRecorder.isTypeSupported("video/mp4"), 'Should not support video/mp4');
navigator.mozGetUserMedia({audio: false, video: true, fake: true},
function(stream) {

View File

@ -0,0 +1,16 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Media Recording - test WebM MIME support</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
ok(MediaRecorder.isTypeSupported('video/webm'), 'Should support video/webm');
ok(MediaRecorder.isTypeSupported('video/webm; codecs="vp8, vorbis"'), 'Should support video/webm + vp8/vorbis');
ok(!MediaRecorder.isTypeSupported('video/webm; codecs="vp9, vorbis"'), 'Should not support video/webm + vp9/vorbis');
</script>
</head>
</html>

View File

@ -47,6 +47,8 @@ interface MediaRecorder : EventTarget {
[Throws]
void requestData();
static boolean isTypeSupported(DOMString type);
};
dictionary MediaRecorderOptions {