зеркало из https://github.com/mozilla/pjs.git
Bug 479863. Stop buffering media elements by default, implement 'autobuffer' attribute to control buffering. r=doublec
--HG-- extra : rebase_source : 5fa0b63da981fdfcf7b1555174b6d1122bf2ae97
This commit is contained in:
Родитель
ead1765b83
Коммит
40b4e3e4e9
|
@ -115,6 +115,9 @@ GK_ATOM(attribute, "attribute")
|
|||
GK_ATOM(attributeSet, "attribute-set")
|
||||
GK_ATOM(aural, "aural")
|
||||
GK_ATOM(_auto, "auto")
|
||||
#ifdef MOZ_MEDIA
|
||||
GK_ATOM(autobuffer, "autobuffer")
|
||||
#endif
|
||||
GK_ATOM(autocheck, "autocheck")
|
||||
GK_ATOM(autocomplete, "autocomplete")
|
||||
#ifdef MOZ_MEDIA
|
||||
|
|
|
@ -311,6 +311,11 @@ protected:
|
|||
*/
|
||||
void ChangeDelayLoadStatus(PRBool aDelay);
|
||||
|
||||
/**
|
||||
* If we suspended downloading after the first frame, unsuspend now.
|
||||
*/
|
||||
void StopSuspendingAfterFirstFrame();
|
||||
|
||||
/**
|
||||
* Called when our channel is redirected to another channel.
|
||||
* Updates our mChannel reference to aNewChannel.
|
||||
|
@ -435,4 +440,12 @@ protected:
|
|||
// PR_TRUE when we've got a task queued to call SelectResource(),
|
||||
// or while we're running SelectResource().
|
||||
PRPackedBool mIsRunningSelectResource;
|
||||
|
||||
// PR_TRUE if we suspended the decoder because we were paused,
|
||||
// autobuffer and autoplay were not set, and we loaded the first frame.
|
||||
PRPackedBool mSuspendedAfterFirstFrame;
|
||||
|
||||
// PR_TRUE if we are allowed to suspend the decoder because we were paused,
|
||||
// autobuffer and autoplay were not set, and we loaded the first frame.
|
||||
PRPackedBool mAllowSuspendAfterFirstFrame;
|
||||
};
|
||||
|
|
|
@ -296,6 +296,7 @@ NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
|
|||
NS_IMPL_URI_ATTR(nsHTMLMediaElement, Src, src)
|
||||
NS_IMPL_BOOL_ATTR(nsHTMLMediaElement, Controls, controls)
|
||||
NS_IMPL_BOOL_ATTR(nsHTMLMediaElement, Autoplay, autoplay)
|
||||
NS_IMPL_BOOL_ATTR(nsHTMLMediaElement, Autobuffer, autobuffer)
|
||||
|
||||
/* readonly attribute nsIDOMHTMLMediaElement mozAutoplayEnabled; */
|
||||
NS_IMETHODIMP nsHTMLMediaElement::GetMozAutoplayEnabled(PRBool *aAutoplayEnabled)
|
||||
|
@ -382,6 +383,8 @@ void nsHTMLMediaElement::AbortExistingLoads()
|
|||
mLoadedFirstFrame = PR_FALSE;
|
||||
mAutoplaying = PR_TRUE;
|
||||
mIsLoadingFromSrcAttribute = PR_FALSE;
|
||||
mSuspendedAfterFirstFrame = PR_FALSE;
|
||||
mAllowSuspendAfterFirstFrame = PR_TRUE;
|
||||
|
||||
// TODO: The playback rate must be set to the default playback rate.
|
||||
|
||||
|
@ -646,6 +649,8 @@ NS_IMETHODIMP nsHTMLMediaElement::GetCurrentTime(float *aCurrentTime)
|
|||
|
||||
NS_IMETHODIMP nsHTMLMediaElement::SetCurrentTime(float aCurrentTime)
|
||||
{
|
||||
StopSuspendingAfterFirstFrame();
|
||||
|
||||
if (!mDecoder)
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
|
||||
|
@ -772,7 +777,9 @@ nsHTMLMediaElement::nsHTMLMediaElement(nsINodeInfo *aNodeInfo, PRBool aFromParse
|
|||
mIsRunningLoadMethod(PR_FALSE),
|
||||
mIsLoadingFromSrcAttribute(PR_FALSE),
|
||||
mDelayingLoadEvent(PR_FALSE),
|
||||
mIsRunningSelectResource(PR_FALSE)
|
||||
mIsRunningSelectResource(PR_FALSE),
|
||||
mSuspendedAfterFirstFrame(PR_FALSE),
|
||||
mAllowSuspendAfterFirstFrame(PR_TRUE)
|
||||
{
|
||||
RegisterFreezableElement();
|
||||
}
|
||||
|
@ -790,8 +797,21 @@ nsHTMLMediaElement::~nsHTMLMediaElement()
|
|||
}
|
||||
}
|
||||
|
||||
void nsHTMLMediaElement::StopSuspendingAfterFirstFrame()
|
||||
{
|
||||
mAllowSuspendAfterFirstFrame = PR_FALSE;
|
||||
if (!mSuspendedAfterFirstFrame)
|
||||
return;
|
||||
mSuspendedAfterFirstFrame = PR_FALSE;
|
||||
if (mDecoder) {
|
||||
mDecoder->Resume();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsHTMLMediaElement::Play()
|
||||
{
|
||||
StopSuspendingAfterFirstFrame();
|
||||
|
||||
if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_EMPTY) {
|
||||
nsresult rv = Load();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -859,16 +879,23 @@ nsresult nsHTMLMediaElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
|
|||
nsresult rv =
|
||||
nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue,
|
||||
aNotify);
|
||||
if (aNotify &&
|
||||
aNameSpaceID == kNameSpaceID_None &&
|
||||
aName == nsGkAtoms::src &&
|
||||
mLoadWaitStatus == WAITING_FOR_SRC_OR_SOURCE)
|
||||
{
|
||||
// A previous load algorithm instance is waiting on a src
|
||||
// addition, resume the load. It is waiting at "step 1 of the load
|
||||
// algorithm".
|
||||
mLoadWaitStatus = NOT_WAITING;
|
||||
QueueSelectResourceTask();
|
||||
if (aNotify && aNameSpaceID == kNameSpaceID_None) {
|
||||
if (aName == nsGkAtoms::src) {
|
||||
if (mLoadWaitStatus == WAITING_FOR_SRC_OR_SOURCE) {
|
||||
// A previous load algorithm instance is waiting on a src
|
||||
// addition, resume the load. It is waiting at "step 1 of the load
|
||||
// algorithm".
|
||||
mLoadWaitStatus = NOT_WAITING;
|
||||
QueueSelectResourceTask();
|
||||
}
|
||||
} else if (aName == nsGkAtoms::autoplay) {
|
||||
StopSuspendingAfterFirstFrame();
|
||||
if (mReadyState == nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA) {
|
||||
NotifyAutoplayDataReady();
|
||||
}
|
||||
} else if (aName == nsGkAtoms::autobuffer) {
|
||||
StopSuspendingAfterFirstFrame();
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
@ -1217,6 +1244,15 @@ void nsHTMLMediaElement::FirstFrameLoaded()
|
|||
{
|
||||
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA);
|
||||
ChangeDelayLoadStatus(PR_FALSE);
|
||||
|
||||
NS_ASSERTION(!mSuspendedAfterFirstFrame, "Should not have already suspended");
|
||||
|
||||
if (mDecoder && mAllowSuspendAfterFirstFrame && mPaused &&
|
||||
!HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay) &&
|
||||
!HasAttr(kNameSpaceID_None, nsGkAtoms::autobuffer)) {
|
||||
mSuspendedAfterFirstFrame = PR_TRUE;
|
||||
mDecoder->Suspend();
|
||||
}
|
||||
}
|
||||
|
||||
void nsHTMLMediaElement::ResourceLoaded()
|
||||
|
|
|
@ -213,13 +213,16 @@ public:
|
|||
virtual void Shutdown();
|
||||
|
||||
// Suspend any media downloads that are in progress. Called by the
|
||||
// media element when it is sent to the bfcache. Call on the main
|
||||
// thread only.
|
||||
// media element when it is sent to the bfcache, or when we need
|
||||
// to throttle the download. Call on the main thread only. This can
|
||||
// be called multiple times, there's an internal "suspend count".
|
||||
virtual void Suspend() = 0;
|
||||
|
||||
// Resume any media downloads that have been suspended. Called by the
|
||||
// media element when it is restored from the bfcache. Call on the
|
||||
// main thread only.
|
||||
// media element when it is restored from the bfcache, or when we need
|
||||
// to stop throttling the download. Call on the main thread only.
|
||||
// The download will only actually resume once as many Resume calls
|
||||
// have been made as Suspend calls.
|
||||
virtual void Resume() = 0;
|
||||
|
||||
// Returns a weak reference to the media element we're decoding for,
|
||||
|
|
|
@ -46,6 +46,7 @@ include $(topsrcdir)/config/rules.mk
|
|||
_TEST_FILES = \
|
||||
can_play_type_ogg.js \
|
||||
can_play_type_wave.js \
|
||||
test_autobuffer.html \
|
||||
test_autoplay.html \
|
||||
test_can_play_type.html \
|
||||
test_constants.html \
|
||||
|
@ -64,6 +65,7 @@ _TEST_FILES += \
|
|||
dynamic_redirect.sjs \
|
||||
test_access_control.html \
|
||||
file_access_controls.html \
|
||||
test_autobuffer2.html \
|
||||
test_bug448534.html \
|
||||
test_bug461281.html \
|
||||
test_bug468190.html \
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=479863
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 479863</title>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=479863">Mozilla Bug 479863</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
|
||||
<video id='v1' onerror="event.stopPropagation();"></video><audio id='a1' onerror="ev
|
||||
ent.stopPropagation();"></audio>
|
||||
<video id='v2' onerror="event.stopPropagation();" autobuffer></video><audio id='a2' on
|
||||
error="event.stopPropagation();" autobuffer></audio>
|
||||
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
var v1 = document.getElementById('v1');
|
||||
var a1 = document.getElementById('a1');
|
||||
var v2 = document.getElementById('v2');
|
||||
var a2 = document.getElementById('a2');
|
||||
ok(!v1.autobuffer, "v1.autobuffer should be false by default");
|
||||
ok(!a1.autobuffer, "v1.autobuffer should be false by default");
|
||||
ok(v2.autobuffer, "v2.autobuffer should be true");
|
||||
ok(a2.autobuffer, "v2.autobuffer should be true");
|
||||
|
||||
v1.autobuffer = true;
|
||||
a1.autobuffer = true;
|
||||
ok(v1.autobuffer, "video.autobuffer not true");
|
||||
ok(a1.autobuffer, "audio.autobuffer not true");
|
||||
is(v1.getAttribute("autobuffer"), "", "video autobuffer attribute not set");
|
||||
is(a1.getAttribute("autobuffer"), "", "video autobuffer attribute not set");
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,73 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=479863
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 479863</title>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="use_large_cache.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=479863">Mozilla Bug 479863</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
|
||||
<script type="application/javascript">
|
||||
var stalls = { v1:false, v2:false, v3:false, v4:false, v5:false, v6:false };
|
||||
var loads = { v1:false, v2:false, v3:false, v4:false, v5:false, v6:false };
|
||||
var totalLoadEvents = 0;
|
||||
var expectedLoadEvents = 6;
|
||||
|
||||
function loaded(event) {
|
||||
loads[event.target.id] = true;
|
||||
++totalLoadEvents;
|
||||
if (totalLoadEvents == expectedLoadEvents) {
|
||||
ok(stalls.v1, "v1 should stall");
|
||||
// We might get accidental stalls on very slow machines, so lets not test these
|
||||
// ok(!stalls.v2, "v2 should not stall");
|
||||
// ok(!stalls.v3, "v3 should not stall");
|
||||
ok(stalls.v4, "v4 should stall");
|
||||
ok(stalls.v5, "v5 should stall");
|
||||
ok(stalls.v6, "v6 should stall");
|
||||
ok(loads.v1, "v1 should load after setting autobuffer");
|
||||
ok(loads.v2, "v2 should load");
|
||||
ok(loads.v3, "v3 should load");
|
||||
ok(loads.v4, "v4 should load after calling play()");
|
||||
ok(loads.v5, "v5 should load after seeking");
|
||||
ok(loads.v6, "v6 should load after setting autoplay");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
function stalled(event) {
|
||||
stalls[event.target.id] = true;
|
||||
if (event.target.id == "v1") {
|
||||
event.target.autobuffer = true;
|
||||
} else if (event.target.id == "v4") {
|
||||
event.target.play();
|
||||
} else if (event.target.id == "v5") {
|
||||
event.target.currentTime = 0.1;
|
||||
} else if (event.target.id == "v6") {
|
||||
event.target.autoplay = true;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<video id='v1' src="seek.ogv" onstalled="stalled(event)" onload="loaded(event)"></video>
|
||||
<video id='v2' src="seek.ogv" onstalled="stalled(event)" onload="loaded(event)" autobuffer></video>
|
||||
<video id='v3' src="seek.ogv" onstalled="stalled(event)" onload="loaded(event)" autoplay></video>
|
||||
<video id='v4' src="seek.ogv" onstalled="stalled(event)" onload="loaded(event)"></video>
|
||||
<video id='v5' src="seek.ogv" onstalled="stalled(event)" onload="loaded(event)"></video>
|
||||
<video id='v6' src="seek.ogv" onstalled="stalled(event)" onload="loaded(event)"></video>
|
||||
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -21,9 +21,11 @@ ok(v2.autoplay, "v2.autoplay should be true");
|
|||
ok(a2.autoplay, "v2.autoplay should be true");
|
||||
|
||||
v1.autoplay = true;
|
||||
v1.autoplay = true;
|
||||
a1.autoplay = true;
|
||||
ok(v1.autoplay, "video.autoplay not true");
|
||||
ok(v1.autoplay, "audio.autoplay not true");
|
||||
ok(a1.autoplay, "audio.autoplay not true");
|
||||
is(v1.getAttribute("autoplay"), "", "video autoplay attribute not set");
|
||||
is(a1.getAttribute("autoplay"), "", "video autoplay attribute not set");
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
#endif
|
||||
%}
|
||||
|
||||
[scriptable, uuid(0ccf2f96-af4c-4af2-b684-b28f3369827f)]
|
||||
[scriptable, uuid(23fb201a-556d-4054-9885-6437e8910296)]
|
||||
interface nsIDOMHTMLMediaElement : nsIDOMHTMLElement
|
||||
{
|
||||
// error state
|
||||
|
@ -90,6 +90,7 @@ interface nsIDOMHTMLMediaElement : nsIDOMHTMLElement
|
|||
readonly attribute boolean ended;
|
||||
readonly attribute boolean mozAutoplayEnabled;
|
||||
attribute boolean autoplay;
|
||||
attribute boolean autobuffer;
|
||||
void play();
|
||||
void pause();
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче