2013-01-18 09:43:20 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2012-05-21 15:12:37 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2009-09-30 01:32:44 +04:00
|
|
|
|
2012-11-14 23:46:40 +04:00
|
|
|
#include "MediaDecoder.h"
|
2013-02-16 07:55:36 +04:00
|
|
|
#include "mozilla/FloatingPoint.h"
|
|
|
|
#include "mozilla/MathAlgorithms.h"
|
2008-11-10 04:38:02 +03:00
|
|
|
#include <limits>
|
2008-07-30 10:50:14 +04:00
|
|
|
#include "nsIObserver.h"
|
2008-10-19 11:39:21 +04:00
|
|
|
#include "nsTArray.h"
|
2010-04-27 12:53:44 +04:00
|
|
|
#include "VideoUtils.h"
|
2012-11-14 23:46:40 +04:00
|
|
|
#include "MediaDecoderStateMachine.h"
|
2012-08-21 08:06:46 +04:00
|
|
|
#include "ImageContainer.h"
|
2012-11-14 23:45:13 +04:00
|
|
|
#include "MediaResource.h"
|
2016-05-27 09:33:48 +03:00
|
|
|
#include "VideoFrameContainer.h"
|
2012-11-14 23:45:13 +04:00
|
|
|
#include "nsError.h"
|
|
|
|
#include "mozilla/Preferences.h"
|
2013-11-26 04:01:31 +04:00
|
|
|
#include "mozilla/StaticPtr.h"
|
2013-09-06 00:25:17 +04:00
|
|
|
#include "nsIMemoryReporter.h"
|
|
|
|
#include "nsComponentManagerUtils.h"
|
2013-01-15 16:22:03 +04:00
|
|
|
#include <algorithm>
|
2013-12-18 07:59:11 +04:00
|
|
|
#include "MediaShutdownManager.h"
|
2014-04-10 21:39:20 +04:00
|
|
|
#include "AudioChannelService.h"
|
2014-07-04 07:55:06 +04:00
|
|
|
#include "mozilla/dom/AudioTrack.h"
|
|
|
|
#include "mozilla/dom/AudioTrackList.h"
|
|
|
|
#include "mozilla/dom/HTMLMediaElement.h"
|
2016-06-09 22:27:39 +03:00
|
|
|
#include "mozilla/dom/Promise.h"
|
2014-07-04 07:55:06 +04:00
|
|
|
#include "mozilla/dom/VideoTrack.h"
|
|
|
|
#include "mozilla/dom/VideoTrackList.h"
|
2015-11-25 02:52:48 +03:00
|
|
|
#include "nsPrintfCString.h"
|
|
|
|
#include "mozilla/Telemetry.h"
|
2016-11-16 01:35:36 +03:00
|
|
|
#include "GMPCrashHelper.h"
|
2016-11-08 05:23:12 +03:00
|
|
|
#include "Layers.h"
|
|
|
|
#include "mozilla/layers/ShadowLayers.h"
|
2012-11-14 23:45:13 +04:00
|
|
|
|
2016-03-10 01:45:27 +03:00
|
|
|
#ifdef MOZ_ANDROID_OMX
|
|
|
|
#include "AndroidBridge.h"
|
|
|
|
#endif
|
|
|
|
|
2012-11-16 07:25:26 +04:00
|
|
|
using namespace mozilla::dom;
|
2015-05-28 22:13:56 +03:00
|
|
|
using namespace mozilla::layers;
|
|
|
|
using namespace mozilla::media;
|
2012-11-14 23:45:13 +04:00
|
|
|
|
2012-11-14 23:45:33 +04:00
|
|
|
namespace mozilla {
|
|
|
|
|
2015-12-18 11:51:16 +03:00
|
|
|
// The amount of instability we tollerate in calls to
|
2015-06-03 01:29:50 +03:00
|
|
|
// MediaDecoder::UpdateEstimatedMediaDuration(); changes of duration
|
|
|
|
// less than this are ignored, as they're assumed to be the result of
|
|
|
|
// instability in the duration estimation.
|
|
|
|
static const uint64_t ESTIMATED_DURATION_FUZZ_FACTOR_USECS = USECS_PER_S / 2;
|
|
|
|
|
2014-04-23 13:29:04 +04:00
|
|
|
// avoid redefined macro in unified build
|
|
|
|
#undef DECODER_LOG
|
2016-04-22 09:18:26 +03:00
|
|
|
#undef DUMP_LOG
|
2014-04-23 13:29:04 +04:00
|
|
|
|
2015-11-15 16:49:01 +03:00
|
|
|
LazyLogModule gMediaDecoderLog("MediaDecoder");
|
2014-08-21 04:13:00 +04:00
|
|
|
#define DECODER_LOG(x, ...) \
|
2015-06-04 01:25:57 +03:00
|
|
|
MOZ_LOG(gMediaDecoderLog, LogLevel::Debug, ("Decoder=%p " x, this, ##__VA_ARGS__))
|
2009-09-30 01:32:44 +04:00
|
|
|
|
2016-04-22 09:18:26 +03:00
|
|
|
#define DUMP_LOG(x, ...) \
|
|
|
|
NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Decoder=%p " x, this, ##__VA_ARGS__).get(), nullptr, nullptr, -1)
|
|
|
|
|
2015-06-30 10:58:05 +03:00
|
|
|
static const char*
|
|
|
|
ToPlayStateStr(MediaDecoder::PlayState aState)
|
|
|
|
{
|
|
|
|
switch (aState) {
|
|
|
|
case MediaDecoder::PLAY_STATE_START: return "START";
|
|
|
|
case MediaDecoder::PLAY_STATE_LOADING: return "LOADING";
|
|
|
|
case MediaDecoder::PLAY_STATE_PAUSED: return "PAUSED";
|
|
|
|
case MediaDecoder::PLAY_STATE_PLAYING: return "PLAYING";
|
|
|
|
case MediaDecoder::PLAY_STATE_ENDED: return "ENDED";
|
|
|
|
case MediaDecoder::PLAY_STATE_SHUTDOWN: return "SHUTDOWN";
|
|
|
|
default: MOZ_ASSERT_UNREACHABLE("Invalid playState.");
|
|
|
|
}
|
|
|
|
return "UNKNOWN";
|
|
|
|
}
|
2014-08-21 04:13:00 +04:00
|
|
|
|
2013-12-08 09:39:47 +04:00
|
|
|
class MediaMemoryTracker : public nsIMemoryReporter
|
2012-11-14 23:45:13 +04:00
|
|
|
{
|
2014-06-24 20:36:43 +04:00
|
|
|
virtual ~MediaMemoryTracker();
|
|
|
|
|
2013-12-08 09:39:47 +04:00
|
|
|
NS_DECL_THREADSAFE_ISUPPORTS
|
|
|
|
NS_DECL_NSIMEMORYREPORTER
|
2013-11-26 04:01:31 +04:00
|
|
|
|
2014-03-06 01:31:04 +04:00
|
|
|
MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf);
|
|
|
|
|
2013-01-18 09:43:20 +04:00
|
|
|
MediaMemoryTracker();
|
2013-11-07 09:35:30 +04:00
|
|
|
void InitMemoryReporter();
|
|
|
|
|
2013-11-26 04:01:31 +04:00
|
|
|
static StaticRefPtr<MediaMemoryTracker> sUniqueInstance;
|
2012-11-14 23:45:13 +04:00
|
|
|
|
2013-01-18 09:43:20 +04:00
|
|
|
static MediaMemoryTracker* UniqueInstance() {
|
2012-11-14 23:45:13 +04:00
|
|
|
if (!sUniqueInstance) {
|
2013-01-18 09:43:20 +04:00
|
|
|
sUniqueInstance = new MediaMemoryTracker();
|
2013-11-07 09:35:30 +04:00
|
|
|
sUniqueInstance->InitMemoryReporter();
|
2012-11-14 23:45:13 +04:00
|
|
|
}
|
|
|
|
return sUniqueInstance;
|
|
|
|
}
|
|
|
|
|
2012-11-14 23:46:40 +04:00
|
|
|
typedef nsTArray<MediaDecoder*> DecodersArray;
|
2012-11-14 23:45:13 +04:00
|
|
|
static DecodersArray& Decoders() {
|
|
|
|
return UniqueInstance()->mDecoders;
|
|
|
|
}
|
|
|
|
|
|
|
|
DecodersArray mDecoders;
|
|
|
|
|
|
|
|
public:
|
2013-01-18 09:43:20 +04:00
|
|
|
static void AddMediaDecoder(MediaDecoder* aDecoder)
|
|
|
|
{
|
2012-11-14 23:45:13 +04:00
|
|
|
Decoders().AppendElement(aDecoder);
|
|
|
|
}
|
|
|
|
|
2013-01-18 09:43:20 +04:00
|
|
|
static void RemoveMediaDecoder(MediaDecoder* aDecoder)
|
|
|
|
{
|
2012-11-14 23:45:13 +04:00
|
|
|
DecodersArray& decoders = Decoders();
|
|
|
|
decoders.RemoveElement(aDecoder);
|
|
|
|
if (decoders.IsEmpty()) {
|
|
|
|
sUniqueInstance = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-11-26 04:01:31 +04:00
|
|
|
StaticRefPtr<MediaMemoryTracker> MediaMemoryTracker::sUniqueInstance;
|
|
|
|
|
2015-09-22 18:39:12 +03:00
|
|
|
#if defined(PR_LOGGING)
|
2015-11-15 16:49:01 +03:00
|
|
|
LazyLogModule gMediaTimerLog("MediaTimer");
|
|
|
|
LazyLogModule gMediaSampleLog("MediaSample");
|
2015-09-22 18:39:12 +03:00
|
|
|
#endif
|
2015-05-01 05:04:59 +03:00
|
|
|
|
2015-04-07 20:59:44 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::InitStatics()
|
|
|
|
{
|
2015-07-01 00:39:41 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2015-04-07 20:59:44 +03:00
|
|
|
}
|
|
|
|
|
2014-04-27 11:06:00 +04:00
|
|
|
NS_IMPL_ISUPPORTS(MediaMemoryTracker, nsIMemoryReporter)
|
2013-01-18 09:43:20 +04:00
|
|
|
|
2015-07-01 06:46:38 +03:00
|
|
|
NS_IMPL_ISUPPORTS0(MediaDecoder)
|
2008-10-19 11:39:21 +04:00
|
|
|
|
2015-11-16 02:50:55 +03:00
|
|
|
|
|
|
|
void
|
|
|
|
MediaDecoder::ResourceCallback::Connect(MediaDecoder* aDecoder)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
mDecoder = aDecoder;
|
2016-08-01 09:39:39 +03:00
|
|
|
mTimer = do_CreateInstance("@mozilla.org/timer;1");
|
2015-11-16 02:50:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaDecoder::ResourceCallback::Disconnect()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
if (mDecoder) {
|
|
|
|
mDecoder = nullptr;
|
|
|
|
mTimer->Cancel();
|
|
|
|
mTimer = nullptr;
|
|
|
|
}
|
2015-11-16 02:50:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
MediaDecoderOwner*
|
|
|
|
MediaDecoder::ResourceCallback::GetMediaOwner() const
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-07-29 09:44:22 +03:00
|
|
|
return mDecoder ? mDecoder->mOwner : nullptr;
|
2015-11-16 02:50:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaDecoder::ResourceCallback::SetInfinite(bool aInfinite)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
if (mDecoder) {
|
|
|
|
mDecoder->SetInfinite(aInfinite);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaDecoder::ResourceCallback::NotifyNetworkError()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
if (mDecoder) {
|
|
|
|
mDecoder->NetworkError();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaDecoder::ResourceCallback::NotifyDecodeError()
|
|
|
|
{
|
|
|
|
RefPtr<ResourceCallback> self = this;
|
|
|
|
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
|
|
|
|
if (self->mDecoder) {
|
2016-09-10 17:51:13 +03:00
|
|
|
self->mDecoder->DecodeError(NS_ERROR_DOM_MEDIA_FATAL_ERR);
|
2015-11-16 02:50:55 +03:00
|
|
|
}
|
|
|
|
});
|
|
|
|
AbstractThread::MainThread()->Dispatch(r.forget());
|
|
|
|
}
|
|
|
|
|
2016-08-01 09:39:39 +03:00
|
|
|
/* static */ void
|
|
|
|
MediaDecoder::ResourceCallback::TimerCallback(nsITimer* aTimer, void* aClosure)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
ResourceCallback* thiz = static_cast<ResourceCallback*>(aClosure);
|
|
|
|
MOZ_ASSERT(thiz->mDecoder);
|
|
|
|
thiz->mDecoder->NotifyDataArrived();
|
|
|
|
thiz->mTimerArmed = false;
|
|
|
|
}
|
|
|
|
|
2015-11-16 02:50:55 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::ResourceCallback::NotifyDataArrived()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-08-01 09:39:39 +03:00
|
|
|
if (!mDecoder || mTimerArmed) {
|
|
|
|
return;
|
2015-11-16 02:50:55 +03:00
|
|
|
}
|
2016-08-01 09:39:39 +03:00
|
|
|
// In situations where these notifications come from stochastic network
|
|
|
|
// activity, we can save significant computation by throttling the
|
|
|
|
// calls to MediaDecoder::NotifyDataArrived() which will update the buffer
|
|
|
|
// ranges of the reader.
|
|
|
|
mTimerArmed = true;
|
|
|
|
mTimer->InitWithFuncCallback(
|
|
|
|
TimerCallback, this, sDelay, nsITimer::TYPE_ONE_SHOT);
|
2015-11-16 02:50:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaDecoder::ResourceCallback::NotifyBytesDownloaded()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
if (mDecoder) {
|
|
|
|
mDecoder->NotifyBytesDownloaded();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaDecoder::ResourceCallback::NotifyDataEnded(nsresult aStatus)
|
|
|
|
{
|
|
|
|
RefPtr<ResourceCallback> self = this;
|
|
|
|
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
|
|
|
|
if (!self->mDecoder) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
self->mDecoder->NotifyDownloadEnded(aStatus);
|
|
|
|
if (NS_SUCCEEDED(aStatus)) {
|
|
|
|
HTMLMediaElement* element = self->GetMediaOwner()->GetMediaElement();
|
|
|
|
if (element) {
|
|
|
|
element->DownloadSuspended();
|
|
|
|
}
|
|
|
|
// NotifySuspendedStatusChanged will tell the element that download
|
|
|
|
// has been suspended "by the cache", which is true since we never
|
|
|
|
// download anything. The element can then transition to HAVE_ENOUGH_DATA.
|
|
|
|
self->mDecoder->NotifySuspendedStatusChanged();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
AbstractThread::MainThread()->Dispatch(r.forget());
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaDecoder::ResourceCallback::NotifyPrincipalChanged()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
if (mDecoder) {
|
|
|
|
mDecoder->NotifyPrincipalChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaDecoder::ResourceCallback::NotifySuspendedStatusChanged()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
if (mDecoder) {
|
|
|
|
mDecoder->NotifySuspendedStatusChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaDecoder::ResourceCallback::NotifyBytesConsumed(int64_t aBytes,
|
|
|
|
int64_t aOffset)
|
|
|
|
{
|
|
|
|
RefPtr<ResourceCallback> self = this;
|
|
|
|
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
|
|
|
|
if (self->mDecoder) {
|
|
|
|
self->mDecoder->NotifyBytesConsumed(aBytes, aOffset);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
AbstractThread::MainThread()->Dispatch(r.forget());
|
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
2016-04-12 08:48:06 +03:00
|
|
|
MediaDecoder::NotifyOwnerActivityChanged(bool aIsVisible)
|
2013-06-10 16:22:05 +04:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2016-04-12 08:48:06 +03:00
|
|
|
SetElementVisibility(aIsVisible);
|
2016-11-08 05:23:12 +03:00
|
|
|
|
|
|
|
MediaDecoderOwner* owner = GetOwner();
|
|
|
|
NS_ENSURE_TRUE_VOID(owner);
|
|
|
|
|
|
|
|
dom::HTMLMediaElement* element = owner->GetMediaElement();
|
|
|
|
NS_ENSURE_TRUE_VOID(element);
|
|
|
|
|
|
|
|
RefPtr<LayerManager> layerManager =
|
|
|
|
nsContentUtils::LayerManagerForDocument(element->OwnerDoc());
|
2017-01-19 02:40:06 +03:00
|
|
|
if (layerManager) {
|
|
|
|
RefPtr<KnowsCompositor> knowsCompositor = layerManager->AsShadowForwarder();
|
|
|
|
mCompositorUpdatedEvent.Notify(knowsCompositor);
|
|
|
|
}
|
2015-01-28 17:31:31 +03:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::Pause()
|
2008-07-30 10:50:14 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2016-07-13 11:48:27 +03:00
|
|
|
if (mPlayState == PLAY_STATE_LOADING || IsEnded()) {
|
2008-10-19 11:39:21 +04:00
|
|
|
mNextState = PLAY_STATE_PAUSED;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ChangeState(PLAY_STATE_PAUSED);
|
|
|
|
}
|
2008-07-30 10:50:14 +04:00
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::SetVolume(double aVolume)
|
2008-10-19 11:39:21 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2015-04-30 03:27:32 +03:00
|
|
|
mVolume = aVolume;
|
2008-07-30 10:50:14 +04:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::AddOutputStream(ProcessedMediaStream* aStream,
|
|
|
|
bool aFinishWhenEnded)
|
2012-04-30 07:12:42 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2015-05-28 09:16:29 +03:00
|
|
|
MOZ_ASSERT(mDecoderStateMachine, "Must be called after Load().");
|
2015-05-28 09:17:30 +03:00
|
|
|
mDecoderStateMachine->AddOutputStream(aStream, aFinishWhenEnded);
|
2012-04-30 07:12:42 +04:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::RemoveOutputStream(MediaStream* aStream)
|
2015-07-24 15:28:17 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
MOZ_ASSERT(mDecoderStateMachine, "Must be called after Load().");
|
|
|
|
mDecoderStateMachine->RemoveOutputStream(aStream);
|
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
double
|
|
|
|
MediaDecoder::GetDuration()
|
2008-07-30 10:50:14 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2015-06-09 21:40:03 +03:00
|
|
|
return mDuration;
|
2008-10-19 11:39:21 +04:00
|
|
|
}
|
2008-07-30 10:50:14 +04:00
|
|
|
|
2015-06-09 22:41:24 +03:00
|
|
|
AbstractCanonical<media::NullableTimeUnit>*
|
|
|
|
MediaDecoder::CanonicalDurationOrNull()
|
2012-11-19 19:11:21 +04:00
|
|
|
{
|
2015-06-09 22:41:24 +03:00
|
|
|
MOZ_ASSERT(mDecoderStateMachine);
|
|
|
|
return mDecoderStateMachine->CanonicalDuration();
|
2012-11-19 19:11:21 +04:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::SetInfinite(bool aInfinite)
|
2011-08-01 22:11:20 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2011-08-01 22:11:20 +04:00
|
|
|
mInfiniteStream = aInfinite;
|
2015-06-10 01:16:27 +03:00
|
|
|
DurationChanged();
|
2011-08-01 22:11:20 +04:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
bool
|
2016-07-13 11:35:37 +03:00
|
|
|
MediaDecoder::IsInfinite() const
|
2011-08-01 22:11:20 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2011-08-01 22:11:20 +04:00
|
|
|
return mInfiniteStream;
|
|
|
|
}
|
|
|
|
|
2016-08-12 10:04:49 +03:00
|
|
|
#define INIT_MIRROR(name, val) \
|
|
|
|
name(AbstractThread::MainThread(), val, "MediaDecoder::" #name " (Mirror)")
|
|
|
|
#define INIT_CANONICAL(name, val) \
|
|
|
|
name(AbstractThread::MainThread(), val, "MediaDecoder::" #name " (Canonical)")
|
|
|
|
|
2015-10-15 06:36:21 +03:00
|
|
|
MediaDecoder::MediaDecoder(MediaDecoderOwner* aOwner)
|
2015-10-15 05:38:14 +03:00
|
|
|
: mWatchManager(this, AbstractThread::MainThread())
|
|
|
|
, mLogicalPosition(0.0)
|
|
|
|
, mDuration(std::numeric_limits<double>::quiet_NaN())
|
2015-11-16 02:50:55 +03:00
|
|
|
, mResourceCallback(new ResourceCallback())
|
2015-10-15 05:38:14 +03:00
|
|
|
, mCDMProxyPromise(mCDMProxyPromiseHolder.Ensure(__func__))
|
|
|
|
, mIgnoreProgressData(false)
|
|
|
|
, mInfiniteStream(false)
|
2015-10-15 06:36:21 +03:00
|
|
|
, mOwner(aOwner)
|
2015-12-03 10:59:30 +03:00
|
|
|
, mFrameStats(new FrameStatistics())
|
2015-10-15 06:36:21 +03:00
|
|
|
, mVideoFrameContainer(aOwner->GetVideoFrameContainer())
|
2015-10-15 05:38:14 +03:00
|
|
|
, mPlaybackStatistics(new MediaChannelStatistics())
|
|
|
|
, mPinnedForSeek(false)
|
|
|
|
, mMinimizePreroll(false)
|
|
|
|
, mMediaTracksConstructed(false)
|
|
|
|
, mFiredMetadataLoaded(false)
|
2016-08-25 05:10:05 +03:00
|
|
|
, mElementVisible(!aOwner->IsHidden())
|
|
|
|
, mForcedHidden(false)
|
2016-08-12 10:04:49 +03:00
|
|
|
, INIT_MIRROR(mStateMachineIsShutdown, true)
|
|
|
|
, INIT_MIRROR(mBuffered, TimeIntervals())
|
2016-11-10 11:35:48 +03:00
|
|
|
, INIT_MIRROR(mNextFrameStatus, MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE)
|
2016-08-12 10:04:49 +03:00
|
|
|
, INIT_MIRROR(mCurrentPosition, 0)
|
|
|
|
, INIT_MIRROR(mStateMachineDuration, NullableTimeUnit())
|
|
|
|
, INIT_MIRROR(mPlaybackPosition, 0)
|
|
|
|
, INIT_MIRROR(mIsAudioDataAudible, false)
|
|
|
|
, INIT_CANONICAL(mVolume, 0.0)
|
|
|
|
, INIT_CANONICAL(mPreservesPitch, true)
|
|
|
|
, INIT_CANONICAL(mEstimatedDuration, NullableTimeUnit())
|
|
|
|
, INIT_CANONICAL(mExplicitDuration, Maybe<double>())
|
|
|
|
, INIT_CANONICAL(mPlayState, PLAY_STATE_LOADING)
|
|
|
|
, INIT_CANONICAL(mNextState, PLAY_STATE_PAUSED)
|
|
|
|
, INIT_CANONICAL(mLogicallySeeking, false)
|
|
|
|
, INIT_CANONICAL(mSameOriginMedia, false)
|
|
|
|
, INIT_CANONICAL(mMediaPrincipalHandle, PRINCIPAL_HANDLE_NONE)
|
|
|
|
, INIT_CANONICAL(mPlaybackBytesPerSecond, 0.0)
|
|
|
|
, INIT_CANONICAL(mPlaybackRateReliable, true)
|
|
|
|
, INIT_CANONICAL(mDecoderPosition, 0)
|
|
|
|
, INIT_CANONICAL(mIsVisible, !aOwner->IsHidden())
|
2015-11-25 02:52:48 +03:00
|
|
|
, mTelemetryReported(false)
|
2017-01-04 11:18:37 +03:00
|
|
|
, mIsMediaElement(!!aOwner->GetMediaElement())
|
|
|
|
, mElement(aOwner->GetMediaElement())
|
2008-10-19 11:39:21 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2013-01-18 09:43:20 +04:00
|
|
|
MediaMemoryTracker::AddMediaDecoder(this);
|
2015-04-01 04:44:36 +03:00
|
|
|
|
2014-04-10 21:39:20 +04:00
|
|
|
mAudioChannel = AudioChannelService::GetDefaultAudioChannel();
|
2015-11-16 02:50:55 +03:00
|
|
|
mResourceCallback->Connect(this);
|
2015-03-19 05:01:12 +03:00
|
|
|
|
2015-05-08 03:04:22 +03:00
|
|
|
//
|
2015-04-25 06:35:06 +03:00
|
|
|
// Initialize watchers.
|
2015-05-08 03:04:22 +03:00
|
|
|
//
|
|
|
|
|
2015-06-10 01:31:46 +03:00
|
|
|
// mDuration
|
|
|
|
mWatchManager.Watch(mStateMachineDuration, &MediaDecoder::DurationChanged);
|
|
|
|
|
2015-06-30 00:27:16 +03:00
|
|
|
// mStateMachineIsShutdown
|
|
|
|
mWatchManager.Watch(mStateMachineIsShutdown, &MediaDecoder::ShutdownBitChanged);
|
|
|
|
|
2015-05-08 03:04:22 +03:00
|
|
|
// readyState
|
2015-04-29 05:02:31 +03:00
|
|
|
mWatchManager.Watch(mPlayState, &MediaDecoder::UpdateReadyState);
|
|
|
|
mWatchManager.Watch(mNextFrameStatus, &MediaDecoder::UpdateReadyState);
|
2015-12-02 03:05:26 +03:00
|
|
|
// ReadyState computation depends on MediaDecoder::CanPlayThrough, which
|
|
|
|
// depends on the download rate.
|
|
|
|
mWatchManager.Watch(mBuffered, &MediaDecoder::UpdateReadyState);
|
2015-05-08 03:04:22 +03:00
|
|
|
|
|
|
|
// mLogicalPosition
|
|
|
|
mWatchManager.Watch(mCurrentPosition, &MediaDecoder::UpdateLogicalPosition);
|
|
|
|
mWatchManager.Watch(mPlayState, &MediaDecoder::UpdateLogicalPosition);
|
|
|
|
mWatchManager.Watch(mLogicallySeeking, &MediaDecoder::UpdateLogicalPosition);
|
2015-07-20 09:34:18 +03:00
|
|
|
|
|
|
|
// mIgnoreProgressData
|
|
|
|
mWatchManager.Watch(mLogicallySeeking, &MediaDecoder::SeekingChanged);
|
2008-07-30 10:50:14 +04:00
|
|
|
|
2016-01-21 05:27:38 +03:00
|
|
|
mWatchManager.Watch(mIsAudioDataAudible, &MediaDecoder::NotifyAudibleStateChanged);
|
|
|
|
|
2013-12-18 07:59:11 +04:00
|
|
|
MediaShutdownManager::Instance().Register(this);
|
2008-10-19 11:39:21 +04:00
|
|
|
}
|
|
|
|
|
2016-08-12 10:04:49 +03:00
|
|
|
#undef INIT_MIRROR
|
|
|
|
#undef INIT_CANONICAL
|
|
|
|
|
2016-05-04 11:13:25 +03:00
|
|
|
void
|
2015-09-22 08:57:24 +03:00
|
|
|
MediaDecoder::Shutdown()
|
2008-07-30 10:50:14 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2016-05-04 11:13:25 +03:00
|
|
|
|
2016-07-15 10:44:02 +03:00
|
|
|
// Unwatch all watch targets to prevent further notifications.
|
|
|
|
mWatchManager.Shutdown();
|
|
|
|
|
2015-11-16 02:50:55 +03:00
|
|
|
mResourceCallback->Disconnect();
|
|
|
|
|
2015-09-27 13:39:37 +03:00
|
|
|
mCDMProxyPromiseHolder.RejectIfExists(true, __func__);
|
|
|
|
|
2016-07-28 09:28:26 +03:00
|
|
|
DiscardOngoingSeekIfExists();
|
|
|
|
|
2009-05-19 03:08:08 +04:00
|
|
|
// This changes the decoder state to SHUTDOWN and does other things
|
|
|
|
// necessary to unblock the state machine thread if it's blocked, so
|
|
|
|
// the asynchronous shutdown in nsDestroyStateMachine won't deadlock.
|
2010-04-27 12:53:44 +04:00
|
|
|
if (mDecoderStateMachine) {
|
2015-09-07 06:39:46 +03:00
|
|
|
mTimedMetadataListener.Disconnect();
|
2015-11-23 05:35:18 +03:00
|
|
|
mMetadataLoadedListener.Disconnect();
|
|
|
|
mFirstFrameLoadedListener.Disconnect();
|
2015-12-01 04:34:02 +03:00
|
|
|
mOnPlaybackEvent.Disconnect();
|
2016-09-10 17:51:13 +03:00
|
|
|
mOnPlaybackErrorEvent.Disconnect();
|
2016-09-19 13:38:06 +03:00
|
|
|
mOnDecoderDoctorEvent.Disconnect();
|
2015-12-02 10:42:32 +03:00
|
|
|
mOnMediaNotSeekable.Disconnect();
|
2015-12-03 10:59:44 +03:00
|
|
|
|
2016-05-04 11:13:25 +03:00
|
|
|
mDecoderStateMachine->BeginShutdown()
|
|
|
|
->Then(AbstractThread::MainThread(), __func__, this,
|
|
|
|
&MediaDecoder::FinishShutdown,
|
|
|
|
&MediaDecoder::FinishShutdown);
|
|
|
|
} else {
|
2016-05-05 05:29:06 +03:00
|
|
|
// Ensure we always unregister asynchronously in order not to disrupt
|
|
|
|
// the hashtable iterating in MediaShutdownManager::Shutdown().
|
2016-05-04 11:13:25 +03:00
|
|
|
RefPtr<MediaDecoder> self = this;
|
|
|
|
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([self] () {
|
2016-05-22 16:39:55 +03:00
|
|
|
self->mVideoFrameContainer = nullptr;
|
2016-05-04 11:13:25 +03:00
|
|
|
MediaShutdownManager::Instance().Unregister(self);
|
|
|
|
});
|
|
|
|
AbstractThread::MainThread()->Dispatch(r.forget());
|
2009-05-19 03:08:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Force any outstanding seek and byterange requests to complete
|
|
|
|
// to prevent shutdown from deadlocking.
|
2012-02-15 08:35:01 +04:00
|
|
|
if (mResource) {
|
|
|
|
mResource->Close();
|
2009-09-22 04:03:42 +04:00
|
|
|
}
|
2009-05-19 03:08:08 +04:00
|
|
|
|
2008-10-19 11:39:21 +04:00
|
|
|
ChangeState(PLAY_STATE_SHUTDOWN);
|
2016-07-29 09:44:22 +03:00
|
|
|
mOwner = nullptr;
|
2008-07-30 10:50:14 +04:00
|
|
|
}
|
|
|
|
|
2012-11-14 23:46:40 +04:00
|
|
|
MediaDecoder::~MediaDecoder()
|
2008-07-30 10:50:14 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(IsShutdown());
|
|
|
|
mResourceCallback->Disconnect();
|
2013-01-18 09:43:20 +04:00
|
|
|
MediaMemoryTracker::RemoveMediaDecoder(this);
|
2010-08-05 11:40:35 +04:00
|
|
|
UnpinForSeek();
|
2008-07-30 10:50:14 +04:00
|
|
|
}
|
|
|
|
|
2015-12-01 04:34:02 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::OnPlaybackEvent(MediaEventType aEvent)
|
|
|
|
{
|
|
|
|
switch (aEvent) {
|
|
|
|
case MediaEventType::PlaybackStarted:
|
|
|
|
mPlaybackStatistics->Start();
|
|
|
|
break;
|
|
|
|
case MediaEventType::PlaybackStopped:
|
|
|
|
mPlaybackStatistics->Stop();
|
|
|
|
ComputePlaybackRate();
|
|
|
|
break;
|
|
|
|
case MediaEventType::PlaybackEnded:
|
|
|
|
PlaybackEnded();
|
|
|
|
break;
|
2016-08-03 12:18:54 +03:00
|
|
|
case MediaEventType::SeekStarted:
|
|
|
|
SeekingStarted();
|
|
|
|
break;
|
2015-12-01 04:34:02 +03:00
|
|
|
case MediaEventType::Invalidate:
|
|
|
|
Invalidate();
|
|
|
|
break;
|
2016-07-04 07:35:21 +03:00
|
|
|
case MediaEventType::EnterVideoSuspend:
|
|
|
|
mOwner->DispatchAsyncEvent(NS_LITERAL_STRING("mozentervideosuspend"));
|
|
|
|
break;
|
|
|
|
case MediaEventType::ExitVideoSuspend:
|
|
|
|
mOwner->DispatchAsyncEvent(NS_LITERAL_STRING("mozexitvideosuspend"));
|
|
|
|
break;
|
2015-12-01 04:34:02 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-10 17:51:13 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::OnPlaybackErrorEvent(const MediaResult& aError)
|
|
|
|
{
|
|
|
|
DecodeError(aError);
|
|
|
|
}
|
|
|
|
|
2016-09-19 13:38:06 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::OnDecoderDoctorEvent(DecoderDoctorEvent aEvent)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
// OnDecoderDoctorEvent is disconnected at shutdown time.
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2016-09-19 13:38:06 +03:00
|
|
|
HTMLMediaElement* element = mOwner->GetMediaElement();
|
|
|
|
if (!element) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
nsIDocument* doc = element->OwnerDoc();
|
|
|
|
if (!doc) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
DecoderDoctorDiagnostics diags;
|
|
|
|
diags.StoreEvent(doc, aEvent, __func__);
|
|
|
|
}
|
|
|
|
|
2016-05-04 11:13:25 +03:00
|
|
|
void
|
2015-12-03 10:59:44 +03:00
|
|
|
MediaDecoder::FinishShutdown()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
mDecoderStateMachine->BreakCycles();
|
|
|
|
SetStateMachine(nullptr);
|
2016-05-22 16:39:55 +03:00
|
|
|
mVideoFrameContainer = nullptr;
|
2016-05-04 11:13:25 +03:00
|
|
|
MediaShutdownManager::Instance().Unregister(this);
|
2015-12-03 10:59:44 +03:00
|
|
|
}
|
|
|
|
|
2015-11-16 02:50:55 +03:00
|
|
|
MediaResourceCallback*
|
|
|
|
MediaDecoder::GetResourceCallback() const
|
|
|
|
{
|
|
|
|
return mResourceCallback;
|
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
nsresult
|
|
|
|
MediaDecoder::OpenResource(nsIStreamListener** aStreamListener)
|
2008-09-07 03:47:28 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2009-09-15 06:30:44 +04:00
|
|
|
if (aStreamListener) {
|
2012-07-30 18:20:58 +04:00
|
|
|
*aStreamListener = nullptr;
|
2009-09-15 06:30:44 +04:00
|
|
|
}
|
2015-09-27 15:12:14 +03:00
|
|
|
return mResource->Open(aStreamListener);
|
2012-09-18 00:45:38 +04:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
nsresult
|
2015-10-14 06:46:27 +03:00
|
|
|
MediaDecoder::Load(nsIStreamListener** aStreamListener)
|
2012-09-18 00:45:38 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2015-07-20 09:29:10 +03:00
|
|
|
MOZ_ASSERT(mResource, "Can't load without a MediaResource");
|
2012-09-18 00:45:38 +04:00
|
|
|
|
2013-07-24 13:55:23 +04:00
|
|
|
nsresult rv = OpenResource(aStreamListener);
|
2012-09-18 00:45:38 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2008-10-19 11:39:21 +04:00
|
|
|
|
2015-04-02 20:49:01 +03:00
|
|
|
SetStateMachine(CreateStateMachine());
|
|
|
|
NS_ENSURE_TRUE(GetStateMachine(), NS_ERROR_FAILURE);
|
2010-04-27 12:53:44 +04:00
|
|
|
|
2015-10-14 06:46:27 +03:00
|
|
|
return InitializeStateMachine();
|
2012-09-18 00:45:38 +04:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
nsresult
|
2015-10-14 06:46:27 +03:00
|
|
|
MediaDecoder::InitializeStateMachine()
|
2012-09-18 00:45:38 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2012-12-13 23:42:45 +04:00
|
|
|
NS_ASSERTION(mDecoderStateMachine, "Cannot initialize null state machine!");
|
2012-09-18 00:45:38 +04:00
|
|
|
|
2016-04-01 18:10:44 +03:00
|
|
|
nsresult rv = mDecoderStateMachine->Init(this);
|
2014-08-21 04:13:00 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2014-08-05 18:55:02 +04:00
|
|
|
|
|
|
|
// If some parameters got set before the state machine got created,
|
|
|
|
// set them now
|
|
|
|
SetStateMachineParameters();
|
2008-10-19 11:39:21 +04:00
|
|
|
|
2015-07-23 13:39:09 +03:00
|
|
|
return NS_OK;
|
2010-08-25 12:45:45 +04:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::SetStateMachineParameters()
|
2014-08-05 18:55:02 +04:00
|
|
|
{
|
2015-07-01 00:39:41 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-09-21 13:06:49 +03:00
|
|
|
if (mPlaybackRate != 1 && mPlaybackRate != 0) {
|
|
|
|
mDecoderStateMachine->DispatchSetPlaybackRate(mPlaybackRate);
|
|
|
|
}
|
2015-09-07 06:38:34 +03:00
|
|
|
mTimedMetadataListener = mDecoderStateMachine->TimedMetadataEvent().Connect(
|
|
|
|
AbstractThread::MainThread(), this, &MediaDecoder::OnMetadataUpdate);
|
2015-11-23 05:35:18 +03:00
|
|
|
mMetadataLoadedListener = mDecoderStateMachine->MetadataLoadedEvent().Connect(
|
|
|
|
AbstractThread::MainThread(), this, &MediaDecoder::MetadataLoaded);
|
|
|
|
mFirstFrameLoadedListener = mDecoderStateMachine->FirstFrameLoadedEvent().Connect(
|
|
|
|
AbstractThread::MainThread(), this, &MediaDecoder::FirstFrameLoaded);
|
2015-11-30 08:06:19 +03:00
|
|
|
|
2015-12-01 04:34:02 +03:00
|
|
|
mOnPlaybackEvent = mDecoderStateMachine->OnPlaybackEvent().Connect(
|
|
|
|
AbstractThread::MainThread(), this, &MediaDecoder::OnPlaybackEvent);
|
2016-09-10 17:51:13 +03:00
|
|
|
mOnPlaybackErrorEvent = mDecoderStateMachine->OnPlaybackErrorEvent().Connect(
|
|
|
|
AbstractThread::MainThread(), this, &MediaDecoder::OnPlaybackErrorEvent);
|
2016-09-19 13:38:06 +03:00
|
|
|
mOnDecoderDoctorEvent = mDecoderStateMachine->OnDecoderDoctorEvent().Connect(
|
|
|
|
AbstractThread::MainThread(), this, &MediaDecoder::OnDecoderDoctorEvent);
|
2015-12-02 10:42:32 +03:00
|
|
|
mOnMediaNotSeekable = mDecoderStateMachine->OnMediaNotSeekable().Connect(
|
|
|
|
AbstractThread::MainThread(), this, &MediaDecoder::OnMediaNotSeekable);
|
2014-08-05 18:55:02 +04:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::SetMinimizePrerollUntilPlaybackStarts()
|
2014-04-01 07:43:57 +04:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2015-07-01 00:39:41 +03:00
|
|
|
DECODER_LOG("SetMinimizePrerollUntilPlaybackStarts()");
|
2014-04-01 07:43:57 +04:00
|
|
|
mMinimizePreroll = true;
|
2015-05-02 02:34:57 +03:00
|
|
|
|
|
|
|
// This needs to be called before we init the state machine, otherwise it will
|
|
|
|
// have no effect.
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!mDecoderStateMachine);
|
2014-04-01 07:43:57 +04:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
nsresult
|
|
|
|
MediaDecoder::Play()
|
2008-07-30 10:50:14 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2015-01-28 17:31:31 +03:00
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
NS_ASSERTION(mDecoderStateMachine != nullptr, "Should have state machine.");
|
2016-09-22 12:02:48 +03:00
|
|
|
if (mPlaybackRate == 0) {
|
2014-09-01 08:52:39 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2015-07-23 13:39:09 +03:00
|
|
|
|
2015-03-05 04:33:40 +03:00
|
|
|
if (IsEnded()) {
|
|
|
|
return Seek(0, SeekTarget::PrevSyncPoint);
|
2015-05-07 18:19:46 +03:00
|
|
|
} else if (mPlayState == PLAY_STATE_LOADING) {
|
2008-10-19 11:39:21 +04:00
|
|
|
mNextState = PLAY_STATE_PLAYING;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
ChangeState(PLAY_STATE_PLAYING);
|
|
|
|
return NS_OK;
|
2008-07-30 10:50:14 +04:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
nsresult
|
2016-06-09 22:27:39 +03:00
|
|
|
MediaDecoder::Seek(double aTime, SeekTarget::Type aSeekType, dom::Promise* aPromise /*=nullptr*/)
|
2008-07-30 10:50:14 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2015-05-07 18:19:46 +03:00
|
|
|
|
2015-02-10 01:34:50 +03:00
|
|
|
MOZ_ASSERT(aTime >= 0.0, "Cannot seek to a negative value.");
|
2011-08-09 14:10:48 +04:00
|
|
|
|
2016-01-25 14:15:27 +03:00
|
|
|
int64_t timeUsecs = TimeUnit::FromSeconds(aTime).ToMicroseconds();
|
2014-03-28 16:31:29 +04:00
|
|
|
|
2015-05-08 03:04:22 +03:00
|
|
|
mLogicalPosition = aTime;
|
2008-10-19 11:39:21 +04:00
|
|
|
|
2015-05-07 18:19:46 +03:00
|
|
|
mLogicallySeeking = true;
|
|
|
|
SeekTarget target = SeekTarget(timeUsecs, aSeekType);
|
2016-06-09 22:27:39 +03:00
|
|
|
CallSeek(target, aPromise);
|
2015-05-07 18:19:46 +03:00
|
|
|
|
|
|
|
if (mPlayState == PLAY_STATE_ENDED) {
|
2010-08-05 11:40:35 +04:00
|
|
|
PinForSeek();
|
2015-10-19 08:55:38 +03:00
|
|
|
ChangeState(mOwner->GetPaused() ? PLAY_STATE_PAUSED : PLAY_STATE_PLAYING);
|
2008-10-19 11:39:21 +04:00
|
|
|
}
|
2015-05-07 18:19:46 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2008-10-19 11:39:21 +04:00
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
2016-06-09 22:27:39 +03:00
|
|
|
MediaDecoder::AsyncResolveSeekDOMPromiseIfExists()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
if (mSeekDOMPromise) {
|
|
|
|
RefPtr<dom::Promise> promise = mSeekDOMPromise;
|
|
|
|
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
|
2016-08-09 12:15:13 +03:00
|
|
|
promise->MaybeResolveWithUndefined();
|
2016-06-09 22:27:39 +03:00
|
|
|
});
|
|
|
|
AbstractThread::MainThread()->Dispatch(r.forget());
|
|
|
|
mSeekDOMPromise = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaDecoder::AsyncRejectSeekDOMPromiseIfExists()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
if (mSeekDOMPromise) {
|
|
|
|
RefPtr<dom::Promise> promise = mSeekDOMPromise;
|
|
|
|
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
|
2016-08-17 05:02:10 +03:00
|
|
|
promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
|
2016-06-09 22:27:39 +03:00
|
|
|
});
|
|
|
|
AbstractThread::MainThread()->Dispatch(r.forget());
|
|
|
|
mSeekDOMPromise = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaDecoder::DiscardOngoingSeekIfExists()
|
2015-05-07 18:19:46 +03:00
|
|
|
{
|
2015-07-01 00:39:41 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2015-05-07 18:19:46 +03:00
|
|
|
mSeekRequest.DisconnectIfExists();
|
2016-06-09 22:27:39 +03:00
|
|
|
AsyncRejectSeekDOMPromiseIfExists();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaDecoder::CallSeek(const SeekTarget& aTarget, dom::Promise* aPromise)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
DiscardOngoingSeekIfExists();
|
|
|
|
|
|
|
|
mSeekDOMPromise = aPromise;
|
2017-01-11 11:33:29 +03:00
|
|
|
mDecoderStateMachine->InvokeSeek(aTarget)
|
|
|
|
->Then(AbstractThread::MainThread(), __func__, this,
|
|
|
|
&MediaDecoder::OnSeekResolved, &MediaDecoder::OnSeekRejected)
|
|
|
|
->Track(mSeekRequest);
|
2008-10-19 11:39:21 +04:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
double
|
|
|
|
MediaDecoder::GetCurrentTime()
|
2008-10-19 11:39:21 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2015-05-08 03:04:22 +03:00
|
|
|
return mLogicalPosition;
|
2008-07-30 10:50:14 +04:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
already_AddRefed<nsIPrincipal>
|
|
|
|
MediaDecoder::GetCurrentPrincipal()
|
2008-07-30 10:50:14 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2012-07-30 18:20:58 +04:00
|
|
|
return mResource ? mResource->GetCurrentPrincipal() : nullptr;
|
2008-07-30 10:50:14 +04:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::OnMetadataUpdate(TimedMetadata&& aMetadata)
|
2015-09-07 06:38:34 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
RemoveMediaTracks();
|
|
|
|
MetadataLoaded(nsAutoPtr<MediaInfo>(new MediaInfo(*aMetadata.mInfo)),
|
|
|
|
Move(aMetadata.mTags),
|
|
|
|
MediaDecoderEventVisibility::Observable);
|
|
|
|
FirstFrameLoaded(Move(aMetadata.mInfo),
|
|
|
|
MediaDecoderEventVisibility::Observable);
|
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::MetadataLoaded(nsAutoPtr<MediaInfo> aInfo,
|
|
|
|
nsAutoPtr<MetadataTags> aTags,
|
|
|
|
MediaDecoderEventVisibility aEventVisibility)
|
2010-08-25 17:10:00 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2010-08-25 17:10:00 +04:00
|
|
|
|
2014-08-21 04:13:00 +04:00
|
|
|
DECODER_LOG("MetadataLoaded, channels=%u rate=%u hasAudio=%d hasVideo=%d",
|
|
|
|
aInfo->mAudio.mChannels, aInfo->mAudio.mRate,
|
|
|
|
aInfo->HasAudio(), aInfo->HasVideo());
|
|
|
|
|
2016-11-02 09:41:04 +03:00
|
|
|
mMediaSeekable = aInfo->mMediaSeekable;
|
2016-11-02 12:16:59 +03:00
|
|
|
mMediaSeekableOnlyInBufferedRanges = aInfo->mMediaSeekableOnlyInBufferedRanges;
|
2014-11-06 11:17:05 +03:00
|
|
|
mInfo = aInfo.forget();
|
2014-07-04 07:55:06 +04:00
|
|
|
ConstructMediaTracks();
|
|
|
|
|
2015-10-19 08:55:38 +03:00
|
|
|
// Make sure the element and the frame (if any) are told about
|
|
|
|
// our new size.
|
|
|
|
if (aEventVisibility != MediaDecoderEventVisibility::Suppressed) {
|
|
|
|
mFiredMetadataLoaded = true;
|
|
|
|
mOwner->MetadataLoaded(mInfo, nsAutoPtr<const MetadataTags>(aTags.forget()));
|
2008-07-30 10:50:14 +04:00
|
|
|
}
|
2016-01-12 13:09:37 +03:00
|
|
|
// Invalidate() will end up calling mOwner->UpdateMediaSize with the last
|
|
|
|
// dimensions retrieved from the video frame container. The video frame
|
|
|
|
// container contains more up to date dimensions than aInfo.
|
|
|
|
// So we call Invalidate() after calling mOwner->MetadataLoaded to ensure
|
|
|
|
// the media element has the latest dimensions.
|
|
|
|
Invalidate();
|
2015-11-25 02:52:48 +03:00
|
|
|
|
|
|
|
EnsureTelemetryReported();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaDecoder::EnsureTelemetryReported()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
|
|
|
if (mTelemetryReported || !mInfo) {
|
|
|
|
// Note: sometimes we get multiple MetadataLoaded calls (for example
|
|
|
|
// for chained ogg). So we ensure we don't report duplicate results for
|
|
|
|
// these resources.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsTArray<nsCString> codecs;
|
|
|
|
if (mInfo->HasAudio() && !mInfo->mAudio.GetAsAudioInfo()->mMimeType.IsEmpty()) {
|
|
|
|
codecs.AppendElement(mInfo->mAudio.GetAsAudioInfo()->mMimeType);
|
|
|
|
}
|
|
|
|
if (mInfo->HasVideo() && !mInfo->mVideo.GetAsVideoInfo()->mMimeType.IsEmpty()) {
|
|
|
|
codecs.AppendElement(mInfo->mVideo.GetAsVideoInfo()->mMimeType);
|
|
|
|
}
|
|
|
|
if (codecs.IsEmpty()) {
|
Bug 1331289 - Use MediaContainerType in MediaResource, SourceBuffer, TrackBuffersManager, and dependencies - r=jya
Continuing the work of replacing MIME strings with MediaContainerType, starting
from MediaResource and following the dependencies.
Most changes are mechanical: Just change ns*String into MediaContainerType, and
MIME string literals into MEDIAMIMETYPE("a/b").
Some checks for empty/invalid strings and lowercase comparisons can go, thanks
to the always-valid always-lowercase-MIME invariants of MediaContainerType.
One special case in is MediaSourceResource, which used to have an empty string
as its type (because its own type is not relevant, but its SourceBuffers carry
types). Because the inherited GetContentType *must* be overridden, and must
return a MediaContainerType, we needed a valid type even though it should not
be seen in the real world. I've chosen "application/x.mediasource" for that.
MozReview-Commit-ID: 1aCH75Kh2e6
--HG--
extra : rebase_source : 0d9cd9b69c264e5dcfc3845f80ee107f4bcbcd9a
2016-12-28 10:59:02 +03:00
|
|
|
codecs.AppendElement(nsPrintfCString("resource; %s",
|
|
|
|
mResource->GetContentType().OriginalString().Data()));
|
2015-11-25 02:52:48 +03:00
|
|
|
}
|
|
|
|
for (const nsCString& codec : codecs) {
|
|
|
|
DECODER_LOG("Telemetry MEDIA_CODEC_USED= '%s'", codec.get());
|
|
|
|
Telemetry::Accumulate(Telemetry::ID::MEDIA_CODEC_USED, codec);
|
|
|
|
}
|
|
|
|
|
|
|
|
mTelemetryReported = true;
|
2014-11-06 12:52:44 +03:00
|
|
|
}
|
|
|
|
|
2015-03-05 04:32:54 +03:00
|
|
|
const char*
|
|
|
|
MediaDecoder::PlayStateStr()
|
|
|
|
{
|
2015-07-01 00:39:41 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-07-11 12:42:34 +03:00
|
|
|
return ToPlayStateStr(mPlayState);
|
2015-03-05 04:32:54 +03:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
|
|
|
|
MediaDecoderEventVisibility aEventVisibility)
|
2014-11-06 12:52:44 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2014-11-06 12:52:44 +03:00
|
|
|
|
2016-10-20 10:20:25 +03:00
|
|
|
DECODER_LOG("FirstFrameLoaded, channels=%u rate=%u hasAudio=%d hasVideo=%d mPlayState=%s",
|
2014-11-06 12:52:44 +03:00
|
|
|
aInfo->mAudio.mChannels, aInfo->mAudio.mRate,
|
2016-10-20 10:20:25 +03:00
|
|
|
aInfo->HasAudio(), aInfo->HasVideo(), PlayStateStr());
|
2014-11-06 12:52:44 +03:00
|
|
|
|
2014-11-06 11:17:05 +03:00
|
|
|
mInfo = aInfo.forget();
|
2009-01-15 23:26:51 +03:00
|
|
|
|
2015-10-19 08:55:38 +03:00
|
|
|
Invalidate();
|
2008-10-19 11:39:21 +04:00
|
|
|
|
2011-11-30 09:05:49 +04:00
|
|
|
// This can run cache callbacks.
|
2012-02-15 08:35:01 +04:00
|
|
|
mResource->EnsureCacheUpToDate();
|
2011-11-30 09:05:49 +04:00
|
|
|
|
2008-10-19 11:39:21 +04:00
|
|
|
// The element can run javascript via events
|
2010-04-02 07:03:07 +04:00
|
|
|
// before reaching here, so only change the
|
2008-10-19 11:39:21 +04:00
|
|
|
// state if we're still set to the original
|
|
|
|
// loading state.
|
2016-10-20 10:20:25 +03:00
|
|
|
if (mPlayState == PLAY_STATE_LOADING) {
|
2015-05-07 18:19:46 +03:00
|
|
|
ChangeState(mNextState);
|
2008-10-19 11:39:21 +04:00
|
|
|
}
|
2009-01-15 23:26:51 +03:00
|
|
|
|
2011-11-30 09:05:49 +04:00
|
|
|
// Run NotifySuspendedStatusChanged now to give us a chance to notice
|
|
|
|
// that autoplay should run.
|
|
|
|
NotifySuspendedStatusChanged();
|
2016-10-21 09:27:27 +03:00
|
|
|
|
|
|
|
// mOwner->FirstFrameLoaded() might call us back. Put it at the bottom of
|
|
|
|
// this function to avoid unexpected shutdown from reentrant calls.
|
|
|
|
if (aEventVisibility != MediaDecoderEventVisibility::Suppressed) {
|
|
|
|
mOwner->FirstFrameLoaded();
|
|
|
|
}
|
2008-07-30 10:50:14 +04:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::NetworkError()
|
2008-11-06 23:53:20 +03:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2015-10-19 08:55:38 +03:00
|
|
|
mOwner->NetworkError();
|
2008-11-06 23:53:20 +03:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
2016-09-10 17:51:13 +03:00
|
|
|
MediaDecoder::DecodeError(const MediaResult& aError)
|
2009-09-22 04:08:13 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2016-09-10 17:56:09 +03:00
|
|
|
mOwner->DecodeError(aError);
|
2009-09-22 04:08:13 +04:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::UpdateSameOriginStatus(bool aSameOrigin)
|
2013-07-24 13:55:23 +04:00
|
|
|
{
|
2015-07-01 00:39:41 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2013-07-24 13:55:23 +04:00
|
|
|
mSameOriginMedia = aSameOrigin;
|
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
bool
|
|
|
|
MediaDecoder::IsSeeking() const
|
2008-07-30 10:50:14 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2015-05-07 18:19:46 +03:00
|
|
|
return mLogicallySeeking;
|
2008-12-14 21:02:54 +03:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
bool
|
2016-02-08 07:28:15 +03:00
|
|
|
MediaDecoder::OwnerHasError() const
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2016-07-28 12:21:09 +03:00
|
|
|
return mOwner->HasError();
|
2016-02-08 07:28:15 +03:00
|
|
|
}
|
|
|
|
|
2016-06-29 02:42:07 +03:00
|
|
|
class MediaElementGMPCrashHelper : public GMPCrashHelper
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
explicit MediaElementGMPCrashHelper(HTMLMediaElement* aElement)
|
|
|
|
: mElement(aElement)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread()); // WeakPtr isn't thread safe.
|
|
|
|
}
|
|
|
|
already_AddRefed<nsPIDOMWindowInner> GetPluginCrashedEventTarget() override
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread()); // WeakPtr isn't thread safe.
|
|
|
|
if (!mElement) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return do_AddRef(mElement->OwnerDoc()->GetInnerWindow());
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
WeakPtr<HTMLMediaElement> mElement;
|
|
|
|
};
|
|
|
|
|
|
|
|
already_AddRefed<GMPCrashHelper>
|
|
|
|
MediaDecoder::GetCrashHelper()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
return mOwner->GetMediaElement() ?
|
|
|
|
MakeAndAddRef<MediaElementGMPCrashHelper>(mOwner->GetMediaElement()) : nullptr;
|
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
bool
|
|
|
|
MediaDecoder::IsEnded() const
|
2015-03-05 04:33:40 +03:00
|
|
|
{
|
2015-07-01 00:39:41 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-07-12 09:34:06 +03:00
|
|
|
return mPlayState == PLAY_STATE_ENDED;
|
2008-10-19 11:39:21 +04:00
|
|
|
}
|
|
|
|
|
2016-07-13 11:45:30 +03:00
|
|
|
bool
|
|
|
|
MediaDecoder::IsShutdown() const
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-07-13 11:48:27 +03:00
|
|
|
return mPlayState == PLAY_STATE_SHUTDOWN;
|
2016-07-13 11:45:30 +03:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::PlaybackEnded()
|
2008-10-19 11:39:21 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2012-07-31 16:17:22 +04:00
|
|
|
|
2016-07-28 10:16:32 +03:00
|
|
|
if (mLogicallySeeking || mPlayState == PLAY_STATE_LOADING) {
|
2016-11-24 09:58:50 +03:00
|
|
|
DECODER_LOG("MediaDecoder::PlaybackEnded bailed out, "
|
|
|
|
"mLogicallySeeking=%d mPlayState=%s",
|
|
|
|
mLogicallySeeking.Ref(), ToPlayStateStr(mPlayState));
|
2008-12-09 03:43:56 +03:00
|
|
|
return;
|
2014-09-02 22:07:00 +04:00
|
|
|
}
|
2008-12-09 03:43:56 +03:00
|
|
|
|
2016-11-24 09:58:50 +03:00
|
|
|
DECODER_LOG("MediaDecoder::PlaybackEnded");
|
|
|
|
|
2009-04-01 05:07:10 +04:00
|
|
|
ChangeState(PLAY_STATE_ENDED);
|
2013-10-02 07:05:34 +04:00
|
|
|
InvalidateWithFlags(VideoFrameContainer::INVALIDATE_FORCE);
|
2015-10-19 08:55:38 +03:00
|
|
|
mOwner->PlaybackEnded();
|
2011-08-01 22:11:20 +04:00
|
|
|
|
2012-11-09 09:52:53 +04:00
|
|
|
// This must be called after |mOwner->PlaybackEnded()| call above, in order
|
2011-08-01 22:11:20 +04:00
|
|
|
// to fire the required durationchange.
|
|
|
|
if (IsInfinite()) {
|
2011-09-30 03:34:37 +04:00
|
|
|
SetInfinite(false);
|
2011-08-01 22:11:20 +04:00
|
|
|
}
|
2008-07-30 10:50:14 +04:00
|
|
|
}
|
|
|
|
|
2015-09-10 11:37:26 +03:00
|
|
|
MediaStatistics
|
2012-11-14 23:46:40 +04:00
|
|
|
MediaDecoder::GetStatistics()
|
2008-07-30 10:50:14 +04:00
|
|
|
{
|
2015-09-15 05:04:50 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
MOZ_ASSERT(mResource);
|
2009-04-01 04:52:56 +04:00
|
|
|
|
2015-09-15 05:04:50 +03:00
|
|
|
MediaStatistics result;
|
|
|
|
result.mDownloadRate = mResource->GetDownloadRate(&result.mDownloadRateReliable);
|
|
|
|
result.mDownloadPosition = mResource->GetCachedDataEnd(mDecoderPosition);
|
|
|
|
result.mTotalBytes = mResource->GetLength();
|
|
|
|
result.mPlaybackRate = mPlaybackBytesPerSecond;
|
|
|
|
result.mPlaybackRateReliable = mPlaybackRateReliable;
|
|
|
|
result.mDecoderPosition = mDecoderPosition;
|
|
|
|
result.mPlaybackPosition = mPlaybackPosition;
|
2009-02-05 11:02:21 +03:00
|
|
|
return result;
|
2009-02-05 11:02:21 +03:00
|
|
|
}
|
|
|
|
|
2015-09-15 05:04:50 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::ComputePlaybackRate()
|
2009-02-05 11:02:21 +03:00
|
|
|
{
|
2015-09-15 05:04:50 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
MOZ_ASSERT(mResource);
|
2010-04-02 07:03:07 +04:00
|
|
|
|
2015-09-15 05:04:50 +03:00
|
|
|
int64_t length = mResource->GetLength();
|
2015-06-09 21:40:03 +03:00
|
|
|
if (!IsNaN(mDuration) && !mozilla::IsInfinite<double>(mDuration) && length >= 0) {
|
2015-09-15 05:04:50 +03:00
|
|
|
mPlaybackRateReliable = true;
|
|
|
|
mPlaybackBytesPerSecond = length / mDuration;
|
|
|
|
return;
|
2009-04-01 04:52:56 +04:00
|
|
|
}
|
2015-09-15 05:04:50 +03:00
|
|
|
|
|
|
|
bool reliable = false;
|
|
|
|
mPlaybackBytesPerSecond = mPlaybackStatistics->GetRateAtLastStop(&reliable);
|
|
|
|
mPlaybackRateReliable = reliable;
|
2009-04-01 04:52:56 +04:00
|
|
|
}
|
2009-02-05 11:02:21 +03:00
|
|
|
|
2015-09-15 05:04:50 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::UpdatePlaybackRate()
|
2009-04-01 04:52:56 +04:00
|
|
|
{
|
2015-07-01 00:39:41 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2015-09-15 05:04:50 +03:00
|
|
|
MOZ_ASSERT(mResource);
|
|
|
|
|
|
|
|
ComputePlaybackRate();
|
|
|
|
uint32_t rate = mPlaybackBytesPerSecond;
|
|
|
|
|
|
|
|
if (mPlaybackRateReliable) {
|
2009-05-19 03:05:13 +04:00
|
|
|
// Avoid passing a zero rate
|
2013-01-15 16:22:03 +04:00
|
|
|
rate = std::max(rate, 1u);
|
2015-09-15 05:04:50 +03:00
|
|
|
} else {
|
2009-04-01 04:52:56 +04:00
|
|
|
// Set a minimum rate of 10,000 bytes per second ... sometimes we just
|
|
|
|
// don't have good data
|
2013-01-15 16:22:03 +04:00
|
|
|
rate = std::max(rate, 10000u);
|
2009-02-05 11:02:21 +03:00
|
|
|
}
|
2015-09-15 05:04:50 +03:00
|
|
|
|
2012-02-15 08:35:01 +04:00
|
|
|
mResource->SetPlaybackRate(rate);
|
2009-02-05 11:02:21 +03:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::NotifySuspendedStatusChanged()
|
2009-02-05 11:02:21 +03:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2015-10-19 08:55:38 +03:00
|
|
|
if (mResource) {
|
2014-09-24 11:25:00 +04:00
|
|
|
bool suspended = mResource->IsSuspendedByCache();
|
2012-11-09 09:52:53 +04:00
|
|
|
mOwner->NotifySuspendedByCache(suspended);
|
2012-11-07 02:33:02 +04:00
|
|
|
}
|
2008-07-30 10:50:14 +04:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::NotifyBytesDownloaded()
|
2008-07-30 10:50:14 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2015-10-19 08:55:38 +03:00
|
|
|
UpdatePlaybackRate();
|
|
|
|
mOwner->DownloadProgressed();
|
2008-07-30 10:50:14 +04:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::NotifyDownloadEnded(nsresult aStatus)
|
2008-07-30 10:50:14 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2015-10-19 08:55:38 +03:00
|
|
|
|
2014-08-21 04:13:00 +04:00
|
|
|
DECODER_LOG("NotifyDownloadEnded, status=%x", aStatus);
|
|
|
|
|
2010-09-03 04:03:03 +04:00
|
|
|
if (aStatus == NS_BINDING_ABORTED) {
|
|
|
|
// Download has been cancelled by user.
|
2015-10-19 08:55:38 +03:00
|
|
|
mOwner->LoadAborted();
|
2008-12-09 03:43:56 +03:00
|
|
|
return;
|
2010-09-03 04:03:03 +04:00
|
|
|
}
|
2008-12-09 03:43:56 +03:00
|
|
|
|
2015-09-27 15:12:14 +03:00
|
|
|
UpdatePlaybackRate();
|
2009-02-05 11:02:21 +03:00
|
|
|
|
|
|
|
if (NS_SUCCEEDED(aStatus)) {
|
2014-09-24 11:25:00 +04:00
|
|
|
// A final progress event will be fired by the MediaResource calling
|
|
|
|
// DownloadSuspended on the element.
|
2014-09-24 11:25:00 +04:00
|
|
|
// Also NotifySuspendedStatusChanged() will be called to update readyState
|
|
|
|
// if download ended with success.
|
2014-09-24 11:25:00 +04:00
|
|
|
} else if (aStatus != NS_BASE_STREAM_CLOSED) {
|
2009-02-05 11:02:21 +03:00
|
|
|
NetworkError();
|
|
|
|
}
|
2009-02-05 11:02:21 +03:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::NotifyPrincipalChanged()
|
2012-04-30 07:12:42 +04:00
|
|
|
{
|
2015-07-01 00:39:41 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2016-02-02 08:14:13 +03:00
|
|
|
nsCOMPtr<nsIPrincipal> newPrincipal = GetCurrentPrincipal();
|
|
|
|
mMediaPrincipalHandle = MakePrincipalHandle(newPrincipal);
|
2015-10-19 08:55:38 +03:00
|
|
|
mOwner->NotifyDecoderPrincipalChanged();
|
2012-04-30 07:12:42 +04:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::NotifyBytesConsumed(int64_t aBytes, int64_t aOffset)
|
2009-02-05 11:02:21 +03:00
|
|
|
{
|
2014-05-12 03:20:00 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2015-07-20 09:34:18 +03:00
|
|
|
|
2015-11-16 02:51:22 +03:00
|
|
|
if (mIgnoreProgressData) {
|
2014-05-12 03:20:00 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-07-20 10:20:56 +03:00
|
|
|
MOZ_ASSERT(mDecoderStateMachine);
|
2013-09-18 07:37:23 +04:00
|
|
|
if (aOffset >= mDecoderPosition) {
|
2014-06-22 08:43:00 +04:00
|
|
|
mPlaybackStatistics->AddBytes(aBytes);
|
2009-02-05 11:02:21 +03:00
|
|
|
}
|
2013-09-18 07:37:23 +04:00
|
|
|
mDecoderPosition = aOffset + aBytes;
|
2009-02-05 11:02:21 +03:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
2016-11-14 12:00:53 +03:00
|
|
|
MediaDecoder::OnSeekResolved()
|
2009-05-31 14:02:17 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2015-04-16 00:00:41 +03:00
|
|
|
mSeekRequest.Complete();
|
2010-04-02 07:03:07 +04:00
|
|
|
|
2009-05-31 14:02:17 +04:00
|
|
|
{
|
|
|
|
// An additional seek was requested while the current seek was
|
|
|
|
// in operation.
|
2015-05-07 18:19:46 +03:00
|
|
|
UnpinForSeek();
|
|
|
|
mLogicallySeeking = false;
|
2009-05-31 14:02:17 +04:00
|
|
|
}
|
|
|
|
|
2016-04-18 13:57:47 +03:00
|
|
|
// Ensure logical position is updated after seek.
|
2016-11-03 10:59:02 +03:00
|
|
|
UpdateLogicalPositionInternal();
|
2014-04-01 07:39:04 +04:00
|
|
|
|
2016-11-03 10:59:02 +03:00
|
|
|
mOwner->SeekCompleted();
|
|
|
|
AsyncResolveSeekDOMPromiseIfExists();
|
2009-05-31 14:02:17 +04:00
|
|
|
}
|
|
|
|
|
2016-06-09 22:27:39 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::OnSeekRejected()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
mSeekRequest.Complete();
|
|
|
|
mLogicallySeeking = false;
|
|
|
|
AsyncRejectSeekDOMPromiseIfExists();
|
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
2016-08-03 12:18:54 +03:00
|
|
|
MediaDecoder::SeekingStarted()
|
2008-10-19 11:39:21 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2016-08-03 12:18:54 +03:00
|
|
|
mOwner->SeekStarted();
|
2008-10-19 11:39:21 +04:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::ChangeState(PlayState aState)
|
2008-10-19 11:39:21 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-07-13 11:48:27 +03:00
|
|
|
MOZ_ASSERT(!IsShutdown(), "SHUTDOWN is the final state.");
|
2008-10-19 11:39:21 +04:00
|
|
|
|
|
|
|
if (mNextState == aState) {
|
|
|
|
mNextState = PLAY_STATE_PAUSED;
|
|
|
|
}
|
|
|
|
|
2016-07-11 12:42:34 +03:00
|
|
|
DECODER_LOG("ChangeState %s => %s", PlayStateStr(), ToPlayStateStr(aState));
|
2008-10-19 11:39:21 +04:00
|
|
|
mPlayState = aState;
|
2013-09-23 13:53:36 +04:00
|
|
|
|
2014-07-04 07:55:06 +04:00
|
|
|
if (mPlayState == PLAY_STATE_PLAYING) {
|
|
|
|
ConstructMediaTracks();
|
2015-03-05 04:33:40 +03:00
|
|
|
} else if (IsEnded()) {
|
2014-07-04 07:55:06 +04:00
|
|
|
RemoveMediaTracks();
|
|
|
|
}
|
2008-10-19 11:39:21 +04:00
|
|
|
}
|
2008-10-23 12:02:18 +04:00
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
2016-11-03 10:59:02 +03:00
|
|
|
MediaDecoder::UpdateLogicalPositionInternal()
|
2008-10-23 12:02:18 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2008-10-23 12:02:18 +04:00
|
|
|
|
2015-05-08 03:04:22 +03:00
|
|
|
double currentPosition = static_cast<double>(CurrentPosition()) / static_cast<double>(USECS_PER_S);
|
2016-08-08 06:49:51 +03:00
|
|
|
if (mPlayState == PLAY_STATE_ENDED) {
|
|
|
|
currentPosition = std::max(currentPosition, mDuration);
|
|
|
|
}
|
2015-05-08 03:04:22 +03:00
|
|
|
bool logicalPositionChanged = mLogicalPosition != currentPosition;
|
|
|
|
mLogicalPosition = currentPosition;
|
|
|
|
|
2008-10-23 12:02:18 +04:00
|
|
|
// Invalidate the frame so any video data is displayed.
|
|
|
|
// Do this before the timeupdate event so that if that
|
|
|
|
// event runs JavaScript that queries the media size, the
|
|
|
|
// frame has reflowed and the size updated beforehand.
|
|
|
|
Invalidate();
|
|
|
|
|
2016-11-03 10:59:02 +03:00
|
|
|
if (logicalPositionChanged) {
|
2010-09-10 09:49:26 +04:00
|
|
|
FireTimeUpdate();
|
2008-10-23 12:02:18 +04:00
|
|
|
}
|
|
|
|
}
|
2008-11-10 04:38:02 +03:00
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::DurationChanged()
|
2010-04-02 07:03:07 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2015-10-19 08:55:38 +03:00
|
|
|
|
2015-06-09 21:40:03 +03:00
|
|
|
double oldDuration = mDuration;
|
2015-06-10 01:16:27 +03:00
|
|
|
if (IsInfinite()) {
|
|
|
|
mDuration = std::numeric_limits<double>::infinity();
|
|
|
|
} else if (mExplicitDuration.Ref().isSome()) {
|
|
|
|
mDuration = mExplicitDuration.Ref().ref();
|
|
|
|
} else if (mStateMachineDuration.Ref().isSome()) {
|
|
|
|
mDuration = mStateMachineDuration.Ref().ref().ToSeconds();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mDuration == oldDuration || IsNaN(mDuration)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
DECODER_LOG("Duration changed to %f", mDuration);
|
|
|
|
|
2010-07-20 05:29:27 +04:00
|
|
|
// Duration has changed so we should recompute playback rate
|
|
|
|
UpdatePlaybackRate();
|
|
|
|
|
2015-06-10 01:16:27 +03:00
|
|
|
// See https://www.w3.org/Bugs/Public/show_bug.cgi?id=28822 for a discussion
|
|
|
|
// of whether we should fire durationchange on explicit infinity.
|
2015-10-19 08:55:38 +03:00
|
|
|
if (mFiredMetadataLoaded &&
|
2015-06-10 01:16:27 +03:00
|
|
|
(!mozilla::IsInfinite<double>(mDuration) || mExplicitDuration.Ref().isSome())) {
|
2015-01-19 07:11:43 +03:00
|
|
|
mOwner->DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
|
2010-04-02 07:03:07 +04:00
|
|
|
}
|
2015-06-04 21:08:48 +03:00
|
|
|
|
2015-06-10 01:16:27 +03:00
|
|
|
if (CurrentPosition() > TimeUnit::FromSeconds(mDuration).ToMicroseconds()) {
|
|
|
|
Seek(mDuration, SeekTarget::Accurate);
|
2015-06-04 21:08:48 +03:00
|
|
|
}
|
2010-04-02 07:03:07 +04:00
|
|
|
}
|
|
|
|
|
2016-04-12 08:48:06 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::SetElementVisibility(bool aIsVisible)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-08-25 05:10:05 +03:00
|
|
|
mElementVisible = aIsVisible;
|
|
|
|
mIsVisible = !mForcedHidden && mElementVisible;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaDecoder::SetForcedHidden(bool aForcedHidden)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
mForcedHidden = aForcedHidden;
|
|
|
|
SetElementVisibility(mElementVisible);
|
2016-04-12 08:48:06 +03:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::UpdateEstimatedMediaDuration(int64_t aDuration)
|
2013-05-03 11:48:37 +04:00
|
|
|
{
|
2015-06-17 02:11:06 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
2013-09-10 04:45:33 +04:00
|
|
|
if (mPlayState <= PLAY_STATE_LOADING) {
|
|
|
|
return;
|
|
|
|
}
|
2015-06-03 01:29:50 +03:00
|
|
|
|
|
|
|
// The duration is only changed if its significantly different than the
|
|
|
|
// the current estimate, as the incoming duration is an estimate and so
|
|
|
|
// often is unstable as more data is read and the estimate is updated.
|
|
|
|
// Can result in a durationchangeevent. aDuration is in microseconds.
|
|
|
|
if (mEstimatedDuration.Ref().isSome() &&
|
|
|
|
mozilla::Abs(mEstimatedDuration.Ref().ref().ToMicroseconds() - aDuration) < ESTIMATED_DURATION_FUZZ_FACTOR_USECS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mEstimatedDuration = Some(TimeUnit::FromMicroseconds(aDuration));
|
2013-05-03 11:48:37 +04:00
|
|
|
}
|
|
|
|
|
2014-06-23 14:08:34 +04:00
|
|
|
bool
|
|
|
|
MediaDecoder::IsTransportSeekable()
|
2008-11-10 04:38:02 +03:00
|
|
|
{
|
2015-09-16 05:44:35 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2014-06-23 14:08:34 +04:00
|
|
|
return GetResource()->IsTransportSeekable();
|
2008-11-10 04:38:02 +03:00
|
|
|
}
|
2009-01-07 06:33:42 +03:00
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
bool
|
|
|
|
MediaDecoder::IsMediaSeekable()
|
2012-11-19 19:11:21 +04:00
|
|
|
{
|
2015-09-21 08:49:01 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2012-12-13 23:42:45 +04:00
|
|
|
NS_ENSURE_TRUE(GetStateMachine(), false);
|
2012-11-30 17:17:54 +04:00
|
|
|
return mMediaSeekable;
|
2012-11-19 19:11:21 +04:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
media::TimeIntervals
|
|
|
|
MediaDecoder::GetSeekable()
|
2011-08-09 14:10:48 +04:00
|
|
|
{
|
2015-07-01 00:39:41 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-08-25 04:36:51 +03:00
|
|
|
|
|
|
|
if (IsNaN(GetDuration())) {
|
|
|
|
// We do not have a duration yet, we can't determine the seekable range.
|
|
|
|
return TimeIntervals();
|
|
|
|
}
|
|
|
|
|
2012-11-30 17:17:54 +04:00
|
|
|
// We can seek in buffered range if the media is seekable. Also, we can seek
|
|
|
|
// in unbuffered ranges if the transport level is seekable (local file or the
|
2016-02-04 07:31:21 +03:00
|
|
|
// server supports range requests, etc.) or in cue-less WebMs
|
2016-11-02 12:16:59 +03:00
|
|
|
if (mMediaSeekableOnlyInBufferedRanges) {
|
2016-02-04 07:31:21 +03:00
|
|
|
return GetBuffered();
|
|
|
|
} else if (!IsMediaSeekable()) {
|
2015-05-18 09:15:47 +03:00
|
|
|
return media::TimeIntervals();
|
2012-12-07 17:30:03 +04:00
|
|
|
} else if (!IsTransportSeekable()) {
|
2015-05-18 09:15:47 +03:00
|
|
|
return GetBuffered();
|
2012-11-30 17:17:54 +04:00
|
|
|
} else {
|
2015-05-18 09:15:47 +03:00
|
|
|
return media::TimeIntervals(
|
|
|
|
media::TimeInterval(media::TimeUnit::FromMicroseconds(0),
|
|
|
|
IsInfinite() ?
|
|
|
|
media::TimeUnit::FromInfinity() :
|
|
|
|
media::TimeUnit::FromSeconds(GetDuration())));
|
2011-08-09 14:10:48 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::SetFragmentEndTime(double aTime)
|
2011-08-25 03:42:23 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2011-08-25 03:42:23 +04:00
|
|
|
if (mDecoderStateMachine) {
|
2015-06-29 22:00:03 +03:00
|
|
|
mDecoderStateMachine->DispatchSetFragmentEndTime(static_cast<int64_t>(aTime * USECS_PER_S));
|
2011-08-25 03:42:23 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::Suspend()
|
2009-01-22 02:54:40 +03:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2012-02-15 08:35:01 +04:00
|
|
|
if (mResource) {
|
|
|
|
mResource->Suspend(true);
|
2009-01-22 02:54:40 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
2016-01-12 03:04:32 +03:00
|
|
|
MediaDecoder::Resume()
|
2009-01-22 02:54:40 +03:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2012-02-15 08:35:01 +04:00
|
|
|
if (mResource) {
|
|
|
|
mResource->Resume();
|
2009-01-22 02:54:40 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::SetLoadInBackground(bool aLoadInBackground)
|
2009-04-10 05:28:24 +04:00
|
|
|
{
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2012-02-15 08:35:01 +04:00
|
|
|
if (mResource) {
|
2014-12-23 04:16:05 +03:00
|
|
|
mResource->SetLoadInBackground(aLoadInBackground);
|
2009-04-10 05:28:24 +04:00
|
|
|
}
|
|
|
|
}
|
2010-04-27 12:53:45 +04:00
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::SetPlaybackRate(double aPlaybackRate)
|
2012-11-22 14:38:28 +04:00
|
|
|
{
|
2015-07-01 00:39:41 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-09-22 12:02:48 +03:00
|
|
|
|
|
|
|
double oldRate = mPlaybackRate;
|
2015-05-01 21:39:42 +03:00
|
|
|
mPlaybackRate = aPlaybackRate;
|
2016-09-22 12:02:48 +03:00
|
|
|
if (aPlaybackRate == 0) {
|
2012-11-22 14:38:28 +04:00
|
|
|
Pause();
|
2016-09-21 13:06:49 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-09-22 12:02:48 +03:00
|
|
|
|
|
|
|
if (oldRate == 0 && !mOwner->GetPaused()) {
|
|
|
|
// PlaybackRate is no longer null.
|
|
|
|
// Restart the playback if the media was playing.
|
|
|
|
Play();
|
2012-11-22 14:38:28 +04:00
|
|
|
}
|
2016-09-21 13:06:49 +03:00
|
|
|
|
|
|
|
if (mDecoderStateMachine) {
|
|
|
|
mDecoderStateMachine->DispatchSetPlaybackRate(aPlaybackRate);
|
|
|
|
}
|
2012-11-22 14:38:28 +04:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::SetPreservesPitch(bool aPreservesPitch)
|
2012-11-22 14:38:28 +04:00
|
|
|
{
|
2015-07-01 00:39:41 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2015-05-02 00:27:29 +03:00
|
|
|
mPreservesPitch = aPreservesPitch;
|
2012-11-22 14:38:28 +04:00
|
|
|
}
|
|
|
|
|
2016-07-15 10:35:41 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::ConnectMirrors(MediaDecoderStateMachine* aObject)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
MOZ_ASSERT(aObject);
|
|
|
|
mStateMachineDuration.Connect(aObject->CanonicalDuration());
|
|
|
|
mBuffered.Connect(aObject->CanonicalBuffered());
|
|
|
|
mStateMachineIsShutdown.Connect(aObject->CanonicalIsShutdown());
|
|
|
|
mNextFrameStatus.Connect(aObject->CanonicalNextFrameStatus());
|
|
|
|
mCurrentPosition.Connect(aObject->CanonicalCurrentPosition());
|
|
|
|
mPlaybackPosition.Connect(aObject->CanonicalPlaybackOffset());
|
|
|
|
mIsAudioDataAudible.Connect(aObject->CanonicalIsAudioDataAudible());
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaDecoder::DisconnectMirrors()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
mStateMachineDuration.DisconnectIfConnected();
|
|
|
|
mBuffered.DisconnectIfConnected();
|
|
|
|
mStateMachineIsShutdown.DisconnectIfConnected();
|
|
|
|
mNextFrameStatus.DisconnectIfConnected();
|
|
|
|
mCurrentPosition.DisconnectIfConnected();
|
|
|
|
mPlaybackPosition.DisconnectIfConnected();
|
|
|
|
mIsAudioDataAudible.DisconnectIfConnected();
|
|
|
|
}
|
|
|
|
|
2015-04-02 20:49:01 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::SetStateMachine(MediaDecoderStateMachine* aStateMachine)
|
|
|
|
{
|
2015-07-01 00:39:41 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2015-04-02 20:49:01 +03:00
|
|
|
MOZ_ASSERT_IF(aStateMachine, !mDecoderStateMachine);
|
|
|
|
mDecoderStateMachine = aStateMachine;
|
2016-07-15 10:35:41 +03:00
|
|
|
if (aStateMachine) {
|
|
|
|
ConnectMirrors(aStateMachine);
|
2015-04-01 04:44:36 +03:00
|
|
|
} else {
|
2016-07-15 10:35:41 +03:00
|
|
|
DisconnectMirrors();
|
2015-04-01 04:44:36 +03:00
|
|
|
}
|
2015-04-02 20:49:01 +03:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
ImageContainer*
|
|
|
|
MediaDecoder::GetImageContainer()
|
2012-11-14 23:45:13 +04:00
|
|
|
{
|
|
|
|
return mVideoFrameContainer ? mVideoFrameContainer->GetImageContainer() : nullptr;
|
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::InvalidateWithFlags(uint32_t aFlags)
|
2013-10-02 07:05:34 +04:00
|
|
|
{
|
|
|
|
if (mVideoFrameContainer) {
|
|
|
|
mVideoFrameContainer->InvalidateWithFlags(aFlags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::Invalidate()
|
2012-11-14 23:45:13 +04:00
|
|
|
{
|
|
|
|
if (mVideoFrameContainer) {
|
|
|
|
mVideoFrameContainer->Invalidate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-07 02:33:02 +04:00
|
|
|
// Constructs the time ranges representing what segments of the media
|
|
|
|
// are buffered and playable.
|
2015-09-22 08:57:24 +03:00
|
|
|
media::TimeIntervals
|
|
|
|
MediaDecoder::GetBuffered() {
|
2015-07-01 00:39:41 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2015-06-18 00:22:10 +03:00
|
|
|
return mBuffered.Ref();
|
2012-11-07 02:33:02 +04:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
size_t
|
|
|
|
MediaDecoder::SizeOfVideoQueue() {
|
2015-07-01 00:39:41 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2012-11-07 02:33:02 +04:00
|
|
|
if (mDecoderStateMachine) {
|
2014-03-20 01:33:12 +04:00
|
|
|
return mDecoderStateMachine->SizeOfVideoQueue();
|
2012-11-07 02:33:02 +04:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
size_t
|
|
|
|
MediaDecoder::SizeOfAudioQueue() {
|
2015-07-01 00:39:41 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2012-11-07 02:33:02 +04:00
|
|
|
if (mDecoderStateMachine) {
|
2014-01-23 07:14:45 +04:00
|
|
|
return mDecoderStateMachine->SizeOfAudioQueue();
|
2012-11-07 02:33:02 +04:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-08-21 01:10:33 +03:00
|
|
|
void MediaDecoder::AddSizeOfResources(ResourceSizes* aSizes) {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
if (GetResource()) {
|
|
|
|
aSizes->mByteSize += GetResource()->SizeOfIncludingThis(aSizes->mMallocSizeOf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
2015-11-11 12:59:16 +03:00
|
|
|
MediaDecoder::NotifyDataArrived() {
|
2015-06-18 00:22:10 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2015-11-18 04:00:56 +03:00
|
|
|
mDataArrivedEvent.Notify();
|
2012-11-07 02:33:02 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Provide access to the state machine object
|
2015-09-22 08:57:24 +03:00
|
|
|
MediaDecoderStateMachine*
|
|
|
|
MediaDecoder::GetStateMachine() const {
|
2015-09-27 15:12:14 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2012-11-07 02:33:02 +04:00
|
|
|
return mDecoderStateMachine;
|
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::FireTimeUpdate()
|
2012-11-14 23:45:13 +04:00
|
|
|
{
|
2015-07-01 00:39:41 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2012-11-14 23:45:13 +04:00
|
|
|
mOwner->FireTimeUpdate(true);
|
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::PinForSeek()
|
2012-11-14 23:45:13 +04:00
|
|
|
{
|
2015-07-01 00:39:41 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2012-11-14 23:45:13 +04:00
|
|
|
MediaResource* resource = GetResource();
|
|
|
|
if (!resource || mPinnedForSeek) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mPinnedForSeek = true;
|
|
|
|
resource->Pin();
|
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::UnpinForSeek()
|
2012-11-14 23:45:13 +04:00
|
|
|
{
|
2015-07-01 00:39:41 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2012-11-14 23:45:13 +04:00
|
|
|
MediaResource* resource = GetResource();
|
|
|
|
if (!resource || !mPinnedForSeek) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mPinnedForSeek = false;
|
|
|
|
resource->Unpin();
|
|
|
|
}
|
|
|
|
|
2015-09-10 11:37:26 +03:00
|
|
|
bool
|
|
|
|
MediaDecoder::CanPlayThrough()
|
2012-11-14 23:45:13 +04:00
|
|
|
{
|
2015-09-10 11:40:52 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2015-03-19 05:01:12 +03:00
|
|
|
NS_ENSURE_TRUE(mDecoderStateMachine, false);
|
2016-08-15 09:54:10 +03:00
|
|
|
return GetStatistics().CanPlayThrough();
|
2012-11-14 23:45:13 +04:00
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<MediaDecoder::CDMProxyPromise>
|
2015-09-27 13:39:37 +03:00
|
|
|
MediaDecoder::RequestCDMProxy() const
|
|
|
|
{
|
|
|
|
return mCDMProxyPromise;
|
|
|
|
}
|
|
|
|
|
2015-09-27 13:59:08 +03:00
|
|
|
void
|
2014-07-30 10:53:34 +04:00
|
|
|
MediaDecoder::SetCDMProxy(CDMProxy* aProxy)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-06-29 07:09:24 +03:00
|
|
|
MOZ_ASSERT(aProxy);
|
2015-09-27 13:39:37 +03:00
|
|
|
|
2016-05-10 01:28:38 +03:00
|
|
|
mCDMProxyPromiseHolder.ResolveIfExists(aProxy, __func__);
|
2014-07-30 10:53:34 +04:00
|
|
|
}
|
|
|
|
|
2012-11-14 23:45:13 +04:00
|
|
|
bool
|
2012-11-14 23:46:40 +04:00
|
|
|
MediaDecoder::IsOpusEnabled()
|
2012-11-14 23:45:13 +04:00
|
|
|
{
|
|
|
|
return Preferences::GetBool("media.opus.enabled");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2012-11-14 23:46:40 +04:00
|
|
|
MediaDecoder::IsOggEnabled()
|
2012-11-14 23:45:13 +04:00
|
|
|
{
|
|
|
|
return Preferences::GetBool("media.ogg.enabled");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2012-11-14 23:46:40 +04:00
|
|
|
MediaDecoder::IsWaveEnabled()
|
2012-11-14 23:45:13 +04:00
|
|
|
{
|
|
|
|
return Preferences::GetBool("media.wave.enabled");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2012-11-14 23:46:40 +04:00
|
|
|
MediaDecoder::IsWebMEnabled()
|
2012-11-14 23:45:13 +04:00
|
|
|
{
|
|
|
|
return Preferences::GetBool("media.webm.enabled");
|
|
|
|
}
|
|
|
|
|
2014-07-17 05:32:56 +04:00
|
|
|
#ifdef MOZ_ANDROID_OMX
|
2012-11-14 23:45:13 +04:00
|
|
|
bool
|
2016-03-10 01:45:27 +03:00
|
|
|
MediaDecoder::IsAndroidMediaPluginEnabled()
|
2012-11-14 23:45:13 +04:00
|
|
|
{
|
2016-03-10 01:45:27 +03:00
|
|
|
return AndroidBridge::Bridge() &&
|
|
|
|
AndroidBridge::Bridge()->GetAPIVersion() < 16 &&
|
|
|
|
Preferences::GetBool("media.plugins.enabled");
|
2012-11-14 23:45:13 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-11-07 09:35:30 +04:00
|
|
|
NS_IMETHODIMP
|
|
|
|
MediaMemoryTracker::CollectReports(nsIHandleReportCallback* aHandleReport,
|
2014-05-21 10:06:54 +04:00
|
|
|
nsISupports* aData, bool aAnonymize)
|
2013-01-18 09:43:20 +04:00
|
|
|
{
|
2013-11-07 09:35:30 +04:00
|
|
|
int64_t video = 0, audio = 0;
|
2015-08-21 01:10:33 +03:00
|
|
|
|
|
|
|
// NB: When resourceSizes' ref count goes to 0 the promise will report the
|
|
|
|
// resources memory and finish the asynchronous memory report.
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<MediaDecoder::ResourceSizes> resourceSizes =
|
2015-08-21 01:10:33 +03:00
|
|
|
new MediaDecoder::ResourceSizes(MediaMemoryTracker::MallocSizeOf);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIHandleReportCallback> handleReport = aHandleReport;
|
|
|
|
nsCOMPtr<nsISupports> data = aData;
|
|
|
|
|
|
|
|
resourceSizes->Promise()->Then(
|
|
|
|
AbstractThread::MainThread(), __func__,
|
|
|
|
[handleReport, data] (size_t size) {
|
|
|
|
handleReport->Callback(
|
|
|
|
EmptyCString(), NS_LITERAL_CSTRING("explicit/media/resources"),
|
|
|
|
KIND_HEAP, UNITS_BYTES, size,
|
|
|
|
NS_LITERAL_CSTRING("Memory used by media resources including "
|
|
|
|
"streaming buffers, caches, etc."),
|
|
|
|
data);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIMemoryReporterManager> imgr =
|
|
|
|
do_GetService("@mozilla.org/memory-reporter-manager;1");
|
|
|
|
|
|
|
|
if (imgr) {
|
|
|
|
imgr->EndReport();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
[] (size_t) { /* unused reject function */ });
|
|
|
|
|
2013-11-07 09:35:30 +04:00
|
|
|
DecodersArray& decoders = Decoders();
|
|
|
|
for (size_t i = 0; i < decoders.Length(); ++i) {
|
2014-03-06 01:31:04 +04:00
|
|
|
MediaDecoder* decoder = decoders[i];
|
2014-03-20 01:33:12 +04:00
|
|
|
video += decoder->SizeOfVideoQueue();
|
2014-03-06 01:31:04 +04:00
|
|
|
audio += decoder->SizeOfAudioQueue();
|
2015-08-21 01:10:33 +03:00
|
|
|
decoder->AddSizeOfResources(resourceSizes);
|
2013-11-07 09:35:30 +04:00
|
|
|
}
|
2013-01-18 09:43:20 +04:00
|
|
|
|
2016-08-24 08:23:45 +03:00
|
|
|
MOZ_COLLECT_REPORT(
|
|
|
|
"explicit/media/decoded/video", KIND_HEAP, UNITS_BYTES, video,
|
|
|
|
"Memory used by decoded video frames.");
|
|
|
|
|
|
|
|
MOZ_COLLECT_REPORT(
|
|
|
|
"explicit/media/decoded/audio", KIND_HEAP, UNITS_BYTES, audio,
|
|
|
|
"Memory used by decoded audio chunks.");
|
2014-04-13 22:08:10 +04:00
|
|
|
|
2013-11-07 09:35:30 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2013-01-18 09:43:20 +04:00
|
|
|
|
2013-05-04 14:12:41 +04:00
|
|
|
MediaDecoderOwner*
|
2016-07-28 12:21:09 +03:00
|
|
|
MediaDecoder::GetOwner() const
|
2013-05-04 14:12:41 +04:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-01-04 11:18:37 +03:00
|
|
|
// Check object lifetime when mOwner points to a media element.
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!mOwner || !mIsMediaElement || mElement);
|
2015-10-28 09:17:28 +03:00
|
|
|
// mOwner is valid until shutdown.
|
2016-07-29 09:44:22 +03:00
|
|
|
return mOwner;
|
2013-05-04 14:12:41 +04:00
|
|
|
}
|
|
|
|
|
2014-07-04 07:55:06 +04:00
|
|
|
void
|
|
|
|
MediaDecoder::ConstructMediaTracks()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2014-07-04 07:55:06 +04:00
|
|
|
|
2016-07-27 05:31:14 +03:00
|
|
|
if (mMediaTracksConstructed || !mInfo) {
|
2014-07-04 07:55:06 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
HTMLMediaElement* element = mOwner->GetMediaElement();
|
|
|
|
if (!element) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mMediaTracksConstructed = true;
|
|
|
|
|
|
|
|
AudioTrackList* audioList = element->AudioTracks();
|
|
|
|
if (audioList && mInfo->HasAudio()) {
|
2015-04-14 08:15:46 +03:00
|
|
|
const TrackInfo& info = mInfo->mAudio;
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<AudioTrack> track = MediaTrackList::CreateAudioTrack(
|
2014-07-04 07:55:06 +04:00
|
|
|
info.mId, info.mKind, info.mLabel, info.mLanguage, info.mEnabled);
|
|
|
|
|
|
|
|
audioList->AddTrack(track);
|
|
|
|
}
|
|
|
|
|
|
|
|
VideoTrackList* videoList = element->VideoTracks();
|
|
|
|
if (videoList && mInfo->HasVideo()) {
|
2015-04-14 08:15:46 +03:00
|
|
|
const TrackInfo& info = mInfo->mVideo;
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<VideoTrack> track = MediaTrackList::CreateVideoTrack(
|
2014-07-04 07:55:06 +04:00
|
|
|
info.mId, info.mKind, info.mLabel, info.mLanguage);
|
|
|
|
|
|
|
|
videoList->AddTrack(track);
|
|
|
|
track->SetEnabledInternal(info.mEnabled, MediaTrack::FIRE_NO_EVENTS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaDecoder::RemoveMediaTracks()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2014-07-04 07:55:06 +04:00
|
|
|
|
|
|
|
HTMLMediaElement* element = mOwner->GetMediaElement();
|
|
|
|
if (!element) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
AudioTrackList* audioList = element->AudioTracks();
|
|
|
|
if (audioList) {
|
|
|
|
audioList->RemoveTracks();
|
|
|
|
}
|
|
|
|
|
|
|
|
VideoTrackList* videoList = element->VideoTracks();
|
|
|
|
if (videoList) {
|
|
|
|
videoList->RemoveTracks();
|
|
|
|
}
|
|
|
|
|
|
|
|
mMediaTracksConstructed = false;
|
|
|
|
}
|
|
|
|
|
2015-12-02 03:50:21 +03:00
|
|
|
MediaDecoderOwner::NextFrameStatus
|
|
|
|
MediaDecoder::NextFrameBufferedStatus()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
// Next frame hasn't been decoded yet.
|
|
|
|
// Use the buffered range to consider if we have the next frame available.
|
|
|
|
media::TimeUnit currentPosition =
|
|
|
|
media::TimeUnit::FromMicroseconds(CurrentPosition());
|
|
|
|
media::TimeInterval interval(currentPosition,
|
|
|
|
currentPosition + media::TimeUnit::FromMicroseconds(DEFAULT_NEXT_FRAME_AVAILABLE_BUFFERED));
|
|
|
|
return GetBuffered().Contains(interval)
|
|
|
|
? MediaDecoderOwner::NEXT_FRAME_AVAILABLE
|
|
|
|
: MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE;
|
|
|
|
}
|
|
|
|
|
2017-01-18 12:55:59 +03:00
|
|
|
nsCString
|
|
|
|
MediaDecoder::GetDebugInfo()
|
|
|
|
{
|
|
|
|
return nsPrintfCString(
|
|
|
|
"channels=%u rate=%u hasAudio=%d hasVideo=%d mPlayState=%s mdsm=%p",
|
|
|
|
mInfo ? mInfo->mAudio.mChannels : 0, mInfo ? mInfo->mAudio.mRate : 0,
|
|
|
|
mInfo ? mInfo->HasAudio() : 0, mInfo ? mInfo->HasVideo() : 0,
|
|
|
|
PlayStateStr(), GetStateMachine());
|
|
|
|
}
|
|
|
|
|
2016-04-22 09:18:26 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::DumpDebugInfo()
|
|
|
|
{
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2017-01-19 12:20:36 +03:00
|
|
|
nsCString str = GetDebugInfo();
|
2016-04-22 09:18:34 +03:00
|
|
|
|
2017-01-19 12:20:36 +03:00
|
|
|
nsAutoCString readerStr;
|
|
|
|
GetMozDebugReaderData(readerStr);
|
|
|
|
if (!readerStr.IsEmpty()) {
|
|
|
|
str += "\nreader data:\n";
|
|
|
|
str += readerStr;
|
2016-10-11 11:58:09 +03:00
|
|
|
}
|
2016-04-22 09:18:34 +03:00
|
|
|
|
2017-01-19 12:20:36 +03:00
|
|
|
if (!GetStateMachine()) {
|
|
|
|
DUMP_LOG("%s", str.get());
|
|
|
|
return;
|
2016-04-22 09:18:26 +03:00
|
|
|
}
|
2017-01-19 12:20:36 +03:00
|
|
|
|
|
|
|
GetStateMachine()->RequestDebugInfo()->Then(
|
|
|
|
AbstractThread::MainThread(), __func__,
|
|
|
|
[this, str] (const nsACString& aString) {
|
|
|
|
DUMP_LOG("%s", str.get());
|
|
|
|
DUMP_LOG("%s", aString.Data());
|
|
|
|
},
|
|
|
|
[this, str] () {
|
|
|
|
DUMP_LOG("%s", str.get());
|
|
|
|
});
|
2016-04-22 09:18:26 +03:00
|
|
|
}
|
|
|
|
|
2017-01-19 09:18:41 +03:00
|
|
|
RefPtr<MediaDecoder::DebugInfoPromise>
|
|
|
|
MediaDecoder::RequestDebugInfo()
|
|
|
|
{
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
|
|
|
|
|
|
|
auto str = GetDebugInfo();
|
|
|
|
if (!GetStateMachine()) {
|
|
|
|
return DebugInfoPromise::CreateAndResolve(str, __func__);
|
|
|
|
}
|
|
|
|
|
|
|
|
return GetStateMachine()->RequestDebugInfo()->Then(
|
|
|
|
AbstractThread::MainThread(), __func__,
|
|
|
|
[str] (const nsACString& aString) {
|
|
|
|
nsCString result = str + nsCString("\n") + aString;
|
|
|
|
return DebugInfoPromise::CreateAndResolve(result, __func__);
|
|
|
|
},
|
|
|
|
[str] () {
|
|
|
|
return DebugInfoPromise::CreateAndResolve(str, __func__);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-01-21 05:27:38 +03:00
|
|
|
void
|
|
|
|
MediaDecoder::NotifyAudibleStateChanged()
|
|
|
|
{
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2016-05-03 12:59:43 +03:00
|
|
|
mOwner->SetAudibleState(mIsAudioDataAudible);
|
2016-01-21 05:27:38 +03:00
|
|
|
}
|
|
|
|
|
2013-01-18 09:43:20 +04:00
|
|
|
MediaMemoryTracker::MediaMemoryTracker()
|
2013-11-07 09:35:30 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaMemoryTracker::InitMemoryReporter()
|
2012-11-14 23:45:13 +04:00
|
|
|
{
|
2015-08-21 01:10:33 +03:00
|
|
|
RegisterWeakAsyncMemoryReporter(this);
|
2012-11-14 23:45:13 +04:00
|
|
|
}
|
|
|
|
|
2013-01-18 09:43:20 +04:00
|
|
|
MediaMemoryTracker::~MediaMemoryTracker()
|
2012-11-14 23:45:13 +04:00
|
|
|
{
|
2013-11-07 09:35:30 +04:00
|
|
|
UnregisterWeakMemoryReporter(this);
|
2012-11-14 23:45:13 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace mozilla
|
2012-11-14 23:45:33 +04:00
|
|
|
|
2014-04-23 13:29:04 +04:00
|
|
|
// avoid redefined macro in unified build
|
|
|
|
#undef DECODER_LOG
|