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"
|
2017-06-20 18:56:55 +03:00
|
|
|
|
2019-11-14 01:40:05 +03:00
|
|
|
#include "AudioDeviceInfo.h"
|
2018-11-23 18:02:03 +03:00
|
|
|
#include "DOMMediaStream.h"
|
2019-08-06 12:25:45 +03:00
|
|
|
#include "DecoderBenchmark.h"
|
2012-08-21 08:06:46 +04:00
|
|
|
#include "ImageContainer.h"
|
2017-06-20 18:56:55 +03:00
|
|
|
#include "Layers.h"
|
|
|
|
#include "MediaDecoderStateMachine.h"
|
2017-07-19 12:01:32 +03:00
|
|
|
#include "MediaFormatReader.h"
|
2012-11-14 23:45:13 +04:00
|
|
|
#include "MediaResource.h"
|
2017-06-20 18:56:55 +03:00
|
|
|
#include "MediaShutdownManager.h"
|
2016-05-27 09:33:48 +03:00
|
|
|
#include "VideoFrameContainer.h"
|
2017-06-20 18:56:55 +03:00
|
|
|
#include "VideoUtils.h"
|
|
|
|
#include "mozilla/AbstractThread.h"
|
2018-11-20 01:51:12 +03:00
|
|
|
#include "mozilla/dom/DOMTypes.h"
|
2017-06-20 18:56:55 +03:00
|
|
|
#include "mozilla/FloatingPoint.h"
|
|
|
|
#include "mozilla/MathAlgorithms.h"
|
2012-11-14 23:45:13 +04:00
|
|
|
#include "mozilla/Preferences.h"
|
2019-07-26 04:10:23 +03:00
|
|
|
#include "mozilla/StaticPrefs_media.h"
|
2013-11-26 04:01:31 +04:00
|
|
|
#include "mozilla/StaticPtr.h"
|
2017-06-20 18:56:55 +03:00
|
|
|
#include "mozilla/Telemetry.h"
|
2017-12-06 01:36:50 +03:00
|
|
|
#include "Visibility.h"
|
2017-11-15 09:58:03 +03:00
|
|
|
#include "mozilla/Unused.h"
|
2017-06-20 18:56:55 +03:00
|
|
|
#include "nsComponentManagerUtils.h"
|
2017-07-18 11:36:01 +03:00
|
|
|
#include "nsContentUtils.h"
|
2017-06-20 18:56:55 +03:00
|
|
|
#include "nsError.h"
|
|
|
|
#include "nsIMemoryReporter.h"
|
|
|
|
#include "nsPrintfCString.h"
|
|
|
|
#include "nsTArray.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include <limits>
|
2012-11-14 23:45:13 +04:00
|
|
|
|
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 {
|
|
|
|
|
2014-04-23 13:29:04 +04:00
|
|
|
// avoid redefined macro in unified build
|
2017-03-24 06:17:17 +03:00
|
|
|
#undef LOG
|
|
|
|
#undef DUMP
|
2014-04-23 13:29:04 +04:00
|
|
|
|
2015-11-15 16:49:01 +03:00
|
|
|
LazyLogModule gMediaDecoderLog("MediaDecoder");
|
2017-10-13 08:31:59 +03:00
|
|
|
#define LOG(x, ...) \
|
|
|
|
DDMOZ_LOG(gMediaDecoderLog, LogLevel::Debug, x, ##__VA_ARGS__)
|
2009-09-30 01:32:44 +04:00
|
|
|
|
2017-10-27 09:58:33 +03:00
|
|
|
#define DUMP(x, ...) printf_stderr(x "\n", ##__VA_ARGS__)
|
2016-04-22 09:18:26 +03:00
|
|
|
|
2017-03-01 06:36:17 +03:00
|
|
|
#define NS_DispatchToMainThread(...) CompileError_UseAbstractMainThreadInstead
|
|
|
|
|
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 {
|
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
|
|
|
|
2017-01-27 15:20:37 +03: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;
|
|
|
|
}
|
|
|
|
}
|
2018-11-20 01:51:12 +03:00
|
|
|
|
|
|
|
static RefPtr<MediaMemoryPromise> GetSizes() {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
DecodersArray& decoders = Decoders();
|
|
|
|
|
|
|
|
// if we don't have any decoder, we can bail
|
|
|
|
if (decoders.IsEmpty()) {
|
|
|
|
// and release the instance that was created by calling Decoders()
|
|
|
|
sUniqueInstance = nullptr;
|
|
|
|
return MediaMemoryPromise::CreateAndResolve(MediaMemoryInfo(), __func__);
|
|
|
|
}
|
|
|
|
|
|
|
|
RefPtr<MediaDecoder::ResourceSizes> resourceSizes =
|
|
|
|
new MediaDecoder::ResourceSizes(MediaMemoryTracker::MallocSizeOf);
|
|
|
|
|
|
|
|
size_t videoSize = 0;
|
|
|
|
size_t audioSize = 0;
|
|
|
|
|
|
|
|
for (auto&& decoder : decoders) {
|
|
|
|
videoSize += decoder->SizeOfVideoQueue();
|
|
|
|
audioSize += decoder->SizeOfAudioQueue();
|
|
|
|
decoder->AddSizeOfResources(resourceSizes);
|
|
|
|
}
|
|
|
|
|
|
|
|
return resourceSizes->Promise()->Then(
|
|
|
|
SystemGroup::AbstractMainThreadFor(TaskCategory::Performance), __func__,
|
|
|
|
[videoSize, audioSize](size_t resourceSize) {
|
|
|
|
return MediaMemoryPromise::CreateAndResolve(
|
|
|
|
MediaMemoryInfo(videoSize, audioSize, resourceSize), __func__);
|
|
|
|
},
|
|
|
|
[](size_t) {
|
|
|
|
return MediaMemoryPromise::CreateAndReject(NS_ERROR_FAILURE,
|
|
|
|
__func__);
|
|
|
|
});
|
|
|
|
}
|
2012-11-14 23:45:13 +04:00
|
|
|
};
|
|
|
|
|
2018-11-23 08:23:48 +03:00
|
|
|
// When media is looping back to the head position, the spec [1] mentions that
|
|
|
|
// MediaElement should dispatch `seeking` first, `timeupdate`, and `seeked` in
|
|
|
|
// the end. This guard should be created before we fire `timeupdate` so that it
|
|
|
|
// can ensure the event order.
|
|
|
|
// [1]
|
|
|
|
// https://html.spec.whatwg.org/multipage/media.html#playing-the-media-resource:attr-media-loop-2
|
|
|
|
// https://html.spec.whatwg.org/multipage/media.html#seeking:dom-media-seek
|
|
|
|
class MOZ_RAII SeekEventsGuard {
|
|
|
|
public:
|
|
|
|
explicit SeekEventsGuard(MediaDecoderOwner* aOwner, bool aIsLoopingBack)
|
|
|
|
: mOwner(aOwner), mIsLoopingBack(aIsLoopingBack) {
|
|
|
|
MOZ_ASSERT(mOwner);
|
|
|
|
if (mIsLoopingBack) {
|
|
|
|
mOwner->SeekStarted();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
~SeekEventsGuard() {
|
|
|
|
MOZ_ASSERT(mOwner);
|
|
|
|
if (mIsLoopingBack) {
|
|
|
|
mOwner->SeekCompleted();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
MediaDecoderOwner* mOwner;
|
|
|
|
bool mIsLoopingBack;
|
|
|
|
};
|
|
|
|
|
2013-11-26 04:01:31 +04:00
|
|
|
StaticRefPtr<MediaMemoryTracker> MediaMemoryTracker::sUniqueInstance;
|
|
|
|
|
2018-11-20 01:51:12 +03:00
|
|
|
RefPtr<MediaMemoryPromise> GetMediaMemorySizes() {
|
|
|
|
return MediaMemoryTracker::GetSizes();
|
|
|
|
}
|
|
|
|
|
2015-11-15 16:49:01 +03:00
|
|
|
LazyLogModule gMediaTimerLog("MediaTimer");
|
2015-05-01 05:04:59 +03:00
|
|
|
|
2017-04-17 11:58:44 +03:00
|
|
|
constexpr TimeUnit MediaDecoder::DEFAULT_NEXT_FRAME_AVAILABLE_BUFFERED;
|
|
|
|
|
2017-11-08 10:34:19 +03:00
|
|
|
void MediaDecoder::InitStatics() {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
// Eagerly init gMediaDecoderLog to work around bug 1415441.
|
|
|
|
MOZ_LOG(gMediaDecoderLog, LogLevel::Info, ("MediaDecoder::InitStatics"));
|
|
|
|
}
|
|
|
|
|
2014-04-27 11:06:00 +04:00
|
|
|
NS_IMPL_ISUPPORTS(MediaMemoryTracker, nsIMemoryReporter)
|
2013-01-18 09:43:20 +04:00
|
|
|
|
2017-03-11 14:56:17 +03:00
|
|
|
void MediaDecoder::NotifyOwnerActivityChanged(bool aIsDocumentVisible,
|
2017-03-17 07:51:11 +03:00
|
|
|
Visibility aElementVisibility,
|
2017-03-12 09:02:04 +03:00
|
|
|
bool aIsElementInTree) {
|
2013-06-10 16:22:05 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2017-08-01 00:29:07 +03:00
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
2017-03-17 07:51:11 +03:00
|
|
|
SetElementVisibility(aIsDocumentVisible, aElementVisibility,
|
|
|
|
aIsElementInTree);
|
2016-11-08 05:23:12 +03:00
|
|
|
|
2017-03-10 11:29:59 +03:00
|
|
|
NotifyCompositor();
|
2015-01-28 17:31:31 +03:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void MediaDecoder::Pause() {
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2017-08-01 00:29:07 +03:00
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
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) {
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-08-01 00:29:07 +03:00
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
2015-04-30 03:27:32 +03:00
|
|
|
mVolume = aVolume;
|
2008-07-30 10:50:14 +04:00
|
|
|
}
|
|
|
|
|
2019-11-14 01:40:05 +03:00
|
|
|
RefPtr<GenericPromise> MediaDecoder::SetSink(AudioDeviceInfo* aSinkDevice) {
|
2018-10-12 11:44:47 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
2019-11-14 01:40:05 +03:00
|
|
|
mSinkDevice = aSinkDevice;
|
|
|
|
return GetStateMachine()->InvokeSetSink(aSinkDevice);
|
2018-10-12 11:44:47 +03:00
|
|
|
}
|
|
|
|
|
2019-11-14 01:40:09 +03:00
|
|
|
void MediaDecoder::SetOutputCaptured(bool aCaptured) {
|
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().");
|
2017-08-01 00:29:07 +03:00
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
Bug 1172394 - Refactor how DecodedStream is set up. r=padenot
This patch removes the responsibility of js-facing MediaStreamTracks from the
MediaDecoder stack, and moves the machinery for setting up DecodedStream to
higher order functions like state mirroring and watchables.
OutputStreamManager is completely gone, since it was designed to manage
MediaStreamTracks across multiple output streams for a single decoder,
on main thread. HTMLMediaElement took over its task in the previous patch.
The MediaDecoderStateMachine now has three control points for capturing:
- mOutputCaptured, which, if true, will capture all decoded data into
mOutputTracks. If this is set, but mOutputTracks is empty, we are still
waiting for tracks, and DecodedStream will not play any data. When tracks are
set, a new DecodedStream is created that will play data through
SourceMediaTracks piped into mOutputTracks.
- mOutputTracks, which is the set of tracks data is captured into, for
forwarding to all the output tracks the media element is managing. This set of
tracks is managed by the MediaDecoder owner, and must contain one audio track
if the decoder is decoding audio, and one video track if the decoder is
decoding video. It may be empty since output can be captured before metadata
is loaded, or playback has ended.
- mOutputPrincipal, which is the principal of the decoded data. All data sent
into SourceMediaTracks is tagged with this principal.
Differential Revision: https://phabricator.services.mozilla.com/D52042
--HG--
extra : moz-landing-system : lando
2019-11-14 01:40:07 +03:00
|
|
|
mOutputCaptured = aCaptured;
|
2019-11-14 01:40:09 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void MediaDecoder::AddOutputTrack(RefPtr<ProcessedMediaTrack> aTrack) {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
MOZ_ASSERT(mDecoderStateMachine, "Must be called after Load().");
|
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
Bug 1172394 - Refactor how DecodedStream is set up. r=padenot
This patch removes the responsibility of js-facing MediaStreamTracks from the
MediaDecoder stack, and moves the machinery for setting up DecodedStream to
higher order functions like state mirroring and watchables.
OutputStreamManager is completely gone, since it was designed to manage
MediaStreamTracks across multiple output streams for a single decoder,
on main thread. HTMLMediaElement took over its task in the previous patch.
The MediaDecoderStateMachine now has three control points for capturing:
- mOutputCaptured, which, if true, will capture all decoded data into
mOutputTracks. If this is set, but mOutputTracks is empty, we are still
waiting for tracks, and DecodedStream will not play any data. When tracks are
set, a new DecodedStream is created that will play data through
SourceMediaTracks piped into mOutputTracks.
- mOutputTracks, which is the set of tracks data is captured into, for
forwarding to all the output tracks the media element is managing. This set of
tracks is managed by the MediaDecoder owner, and must contain one audio track
if the decoder is decoding audio, and one video track if the decoder is
decoding video. It may be empty since output can be captured before metadata
is loaded, or playback has ended.
- mOutputPrincipal, which is the principal of the decoded data. All data sent
into SourceMediaTracks is tagged with this principal.
Differential Revision: https://phabricator.services.mozilla.com/D52042
--HG--
extra : moz-landing-system : lando
2019-11-14 01:40:07 +03:00
|
|
|
nsTArray<RefPtr<ProcessedMediaTrack>> tracks = mOutputTracks;
|
|
|
|
tracks.AppendElement(std::move(aTrack));
|
|
|
|
mOutputTracks = tracks;
|
2012-04-30 07:12:42 +04:00
|
|
|
}
|
|
|
|
|
2019-11-14 01:40:09 +03:00
|
|
|
void MediaDecoder::RemoveOutputTrack(
|
|
|
|
const RefPtr<ProcessedMediaTrack>& aTrack) {
|
2015-07-24 15:28:17 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
MOZ_ASSERT(mDecoderStateMachine, "Must be called after Load().");
|
2017-08-01 00:29:07 +03:00
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
Bug 1172394 - Refactor how DecodedStream is set up. r=padenot
This patch removes the responsibility of js-facing MediaStreamTracks from the
MediaDecoder stack, and moves the machinery for setting up DecodedStream to
higher order functions like state mirroring and watchables.
OutputStreamManager is completely gone, since it was designed to manage
MediaStreamTracks across multiple output streams for a single decoder,
on main thread. HTMLMediaElement took over its task in the previous patch.
The MediaDecoderStateMachine now has three control points for capturing:
- mOutputCaptured, which, if true, will capture all decoded data into
mOutputTracks. If this is set, but mOutputTracks is empty, we are still
waiting for tracks, and DecodedStream will not play any data. When tracks are
set, a new DecodedStream is created that will play data through
SourceMediaTracks piped into mOutputTracks.
- mOutputTracks, which is the set of tracks data is captured into, for
forwarding to all the output tracks the media element is managing. This set of
tracks is managed by the MediaDecoder owner, and must contain one audio track
if the decoder is decoding audio, and one video track if the decoder is
decoding video. It may be empty since output can be captured before metadata
is loaded, or playback has ended.
- mOutputPrincipal, which is the principal of the decoded data. All data sent
into SourceMediaTracks is tagged with this principal.
Differential Revision: https://phabricator.services.mozilla.com/D52042
--HG--
extra : moz-landing-system : lando
2019-11-14 01:40:07 +03:00
|
|
|
nsTArray<RefPtr<ProcessedMediaTrack>> tracks = mOutputTracks;
|
|
|
|
if (tracks.RemoveElement(aTrack)) {
|
|
|
|
mOutputTracks = tracks;
|
|
|
|
}
|
2015-07-24 15:28:17 +03:00
|
|
|
}
|
|
|
|
|
2019-11-14 01:40:09 +03:00
|
|
|
void MediaDecoder::SetOutputTracksPrincipal(
|
|
|
|
const RefPtr<nsIPrincipal>& aPrincipal) {
|
2019-07-09 00:15:10 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
MOZ_ASSERT(mDecoderStateMachine, "Must be called after Load().");
|
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
Bug 1172394 - Refactor how DecodedStream is set up. r=padenot
This patch removes the responsibility of js-facing MediaStreamTracks from the
MediaDecoder stack, and moves the machinery for setting up DecodedStream to
higher order functions like state mirroring and watchables.
OutputStreamManager is completely gone, since it was designed to manage
MediaStreamTracks across multiple output streams for a single decoder,
on main thread. HTMLMediaElement took over its task in the previous patch.
The MediaDecoderStateMachine now has three control points for capturing:
- mOutputCaptured, which, if true, will capture all decoded data into
mOutputTracks. If this is set, but mOutputTracks is empty, we are still
waiting for tracks, and DecodedStream will not play any data. When tracks are
set, a new DecodedStream is created that will play data through
SourceMediaTracks piped into mOutputTracks.
- mOutputTracks, which is the set of tracks data is captured into, for
forwarding to all the output tracks the media element is managing. This set of
tracks is managed by the MediaDecoder owner, and must contain one audio track
if the decoder is decoding audio, and one video track if the decoder is
decoding video. It may be empty since output can be captured before metadata
is loaded, or playback has ended.
- mOutputPrincipal, which is the principal of the decoded data. All data sent
into SourceMediaTracks is tagged with this principal.
Differential Revision: https://phabricator.services.mozilla.com/D52042
--HG--
extra : moz-landing-system : lando
2019-11-14 01:40:07 +03:00
|
|
|
mOutputPrincipal = MakePrincipalHandle(aPrincipal);
|
2019-07-09 00:15:10 +03:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
double MediaDecoder::GetDuration() {
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-08-01 00:29:07 +03:00
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
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
|
|
|
|
2016-07-13 11:35:37 +03:00
|
|
|
bool MediaDecoder::IsInfinite() const {
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-08-01 00:29:07 +03:00
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
2017-08-01 09:15:29 +03:00
|
|
|
return mozilla::IsInfinite<double>(mDuration);
|
2011-08-01 22:11:20 +04:00
|
|
|
}
|
|
|
|
|
2016-08-12 10:04:49 +03:00
|
|
|
#define INIT_MIRROR(name, val) \
|
2017-06-07 07:14:11 +03:00
|
|
|
name(mOwner->AbstractMainThread(), val, "MediaDecoder::" #name " (Mirror)")
|
2016-08-12 10:04:49 +03:00
|
|
|
#define INIT_CANONICAL(name, val) \
|
2017-06-07 07:14:11 +03:00
|
|
|
name(mOwner->AbstractMainThread(), val, "MediaDecoder::" #name " (Canonical)")
|
2016-08-12 10:04:49 +03:00
|
|
|
|
2017-06-07 07:14:11 +03:00
|
|
|
MediaDecoder::MediaDecoder(MediaDecoderInit& aInit)
|
|
|
|
: mWatchManager(this, aInit.mOwner->AbstractMainThread()),
|
2015-10-15 05:38:14 +03:00
|
|
|
mLogicalPosition(0.0),
|
|
|
|
mDuration(std::numeric_limits<double>::quiet_NaN()),
|
2017-06-07 07:14:11 +03:00
|
|
|
mOwner(aInit.mOwner),
|
|
|
|
mAbstractMainThread(aInit.mOwner->AbstractMainThread()),
|
2015-12-03 10:59:30 +03:00
|
|
|
mFrameStats(new FrameStatistics()),
|
2019-08-06 12:25:45 +03:00
|
|
|
mDecoderBenchmark(new DecoderBenchmark()),
|
2017-06-07 07:14:11 +03:00
|
|
|
mVideoFrameContainer(aInit.mOwner->GetVideoFrameContainer()),
|
2017-06-07 09:10:26 +03:00
|
|
|
mMinimizePreroll(aInit.mMinimizePreroll),
|
2015-10-15 05:38:14 +03:00
|
|
|
mFiredMetadataLoaded(false),
|
2017-03-12 08:56:43 +03:00
|
|
|
mIsDocumentVisible(false),
|
2019-04-26 02:03:04 +03:00
|
|
|
mElementVisibility(Visibility::Untracked),
|
2017-03-12 09:02:04 +03:00
|
|
|
mIsElementInTree(false),
|
2016-08-25 05:10:05 +03:00
|
|
|
mForcedHidden(false),
|
2017-06-07 09:10:26 +03:00
|
|
|
mHasSuspendTaint(aInit.mHasSuspendTaint),
|
|
|
|
mPlaybackRate(aInit.mPlaybackRate),
|
2018-11-23 08:07:45 +03:00
|
|
|
mLogicallySeeking(false, "MediaDecoder::mLogicallySeeking"),
|
2016-08-12 10:04:49 +03:00
|
|
|
INIT_MIRROR(mBuffered, TimeIntervals()),
|
2017-03-28 13:13:22 +03:00
|
|
|
INIT_MIRROR(mCurrentPosition, TimeUnit::Zero()),
|
2016-08-12 10:04:49 +03:00
|
|
|
INIT_MIRROR(mStateMachineDuration, NullableTimeUnit()),
|
|
|
|
INIT_MIRROR(mIsAudioDataAudible, false),
|
2017-06-07 09:10:26 +03:00
|
|
|
INIT_CANONICAL(mVolume, aInit.mVolume),
|
|
|
|
INIT_CANONICAL(mPreservesPitch, aInit.mPreservesPitch),
|
2017-06-08 07:03:10 +03:00
|
|
|
INIT_CANONICAL(mLooping, aInit.mLooping),
|
2019-11-14 01:40:05 +03:00
|
|
|
INIT_CANONICAL(mSinkDevice, nullptr),
|
2019-11-22 03:07:04 +03:00
|
|
|
INIT_CANONICAL(mSecondaryVideoContainer, nullptr),
|
Bug 1172394 - Refactor how DecodedStream is set up. r=padenot
This patch removes the responsibility of js-facing MediaStreamTracks from the
MediaDecoder stack, and moves the machinery for setting up DecodedStream to
higher order functions like state mirroring and watchables.
OutputStreamManager is completely gone, since it was designed to manage
MediaStreamTracks across multiple output streams for a single decoder,
on main thread. HTMLMediaElement took over its task in the previous patch.
The MediaDecoderStateMachine now has three control points for capturing:
- mOutputCaptured, which, if true, will capture all decoded data into
mOutputTracks. If this is set, but mOutputTracks is empty, we are still
waiting for tracks, and DecodedStream will not play any data. When tracks are
set, a new DecodedStream is created that will play data through
SourceMediaTracks piped into mOutputTracks.
- mOutputTracks, which is the set of tracks data is captured into, for
forwarding to all the output tracks the media element is managing. This set of
tracks is managed by the MediaDecoder owner, and must contain one audio track
if the decoder is decoding audio, and one video track if the decoder is
decoding video. It may be empty since output can be captured before metadata
is loaded, or playback has ended.
- mOutputPrincipal, which is the principal of the decoded data. All data sent
into SourceMediaTracks is tagged with this principal.
Differential Revision: https://phabricator.services.mozilla.com/D52042
--HG--
extra : moz-landing-system : lando
2019-11-14 01:40:07 +03:00
|
|
|
INIT_CANONICAL(mOutputCaptured, false),
|
|
|
|
INIT_CANONICAL(mOutputTracks, nsTArray<RefPtr<ProcessedMediaTrack>>()),
|
|
|
|
INIT_CANONICAL(mOutputPrincipal, PRINCIPAL_HANDLE_NONE),
|
2016-08-12 10:04:49 +03:00
|
|
|
INIT_CANONICAL(mPlayState, PLAY_STATE_LOADING),
|
2019-07-09 00:15:10 +03:00
|
|
|
mSameOriginMedia(false),
|
2017-07-20 09:13:37 +03:00
|
|
|
mVideoDecodingOberver(
|
|
|
|
new BackgroundVideoDecodingPermissionObserver(this)),
|
|
|
|
mIsBackgroundVideoDecodingAllowed(false),
|
2015-11-25 02:52:48 +03:00
|
|
|
mTelemetryReported(false),
|
2017-06-26 12:10:47 +03:00
|
|
|
mContainerType(aInit.mContainerType) {
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-29 08:03:36 +03:00
|
|
|
MOZ_ASSERT(mAbstractMainThread);
|
2013-01-18 09:43:20 +04:00
|
|
|
MediaMemoryTracker::AddMediaDecoder(this);
|
2015-04-01 04:44:36 +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-05-08 03:04:22 +03:00
|
|
|
// readyState
|
2015-04-29 05:02:31 +03:00
|
|
|
mWatchManager.Watch(mPlayState, &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
|
|
|
|
2017-01-27 15:20:37 +03:00
|
|
|
mWatchManager.Watch(mIsAudioDataAudible,
|
|
|
|
&MediaDecoder::NotifyAudibleStateChanged);
|
2016-01-21 05:27:38 +03:00
|
|
|
|
2017-07-20 09:13:37 +03:00
|
|
|
mVideoDecodingOberver->RegisterEvent();
|
2008-10-19 11:39:21 +04:00
|
|
|
}
|
|
|
|
|
2016-08-12 10:04:49 +03:00
|
|
|
#undef INIT_MIRROR
|
|
|
|
#undef INIT_CANONICAL
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void MediaDecoder::Shutdown() {
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2017-08-01 00:29:07 +03:00
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
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();
|
|
|
|
|
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();
|
2017-07-13 06:18:07 +03:00
|
|
|
mOnEncrypted.Disconnect();
|
2017-07-13 09:49:23 +03:00
|
|
|
mOnWaitingForKey.Disconnect();
|
2017-07-13 10:02:06 +03:00
|
|
|
mOnDecodeWarning.Disconnect();
|
2017-10-06 10:48:38 +03:00
|
|
|
mOnNextFrameStatus.Disconnect();
|
2019-11-22 15:52:48 +03:00
|
|
|
mOnSecondaryVideoContainerInstalled.Disconnect();
|
2019-08-06 12:25:45 +03:00
|
|
|
mOnStoreDecoderBenchmark.Disconnect();
|
2015-12-03 10:59:44 +03:00
|
|
|
|
2016-05-04 11:13:25 +03:00
|
|
|
mDecoderStateMachine->BeginShutdown()->Then(
|
2016-11-29 08:03:36 +03:00
|
|
|
mAbstractMainThread, __func__, this, &MediaDecoder::FinishShutdown,
|
2016-05-04 11:13:25 +03:00
|
|
|
&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;
|
2019-11-22 03:07:04 +03:00
|
|
|
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
|
|
|
|
"MediaDecoder::Shutdown", [self]() { self->ShutdownInternal(); });
|
2016-11-29 08:03:36 +03:00
|
|
|
mAbstractMainThread->Dispatch(r.forget());
|
2009-05-19 03:08:08 +04:00
|
|
|
}
|
|
|
|
|
2008-10-19 11:39:21 +04:00
|
|
|
ChangeState(PLAY_STATE_SHUTDOWN);
|
2017-07-20 09:13:37 +03:00
|
|
|
mVideoDecodingOberver->UnregisterEvent();
|
|
|
|
mVideoDecodingOberver = nullptr;
|
2016-07-29 09:44:22 +03:00
|
|
|
mOwner = nullptr;
|
2008-07-30 10:50:14 +04:00
|
|
|
}
|
|
|
|
|
2017-02-03 12:12:38 +03:00
|
|
|
void MediaDecoder::NotifyXPCOMShutdown() {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2018-11-15 15:48:02 +03:00
|
|
|
// NotifyXPCOMShutdown will clear its reference to mDecoder. So we must ensure
|
|
|
|
// that this MediaDecoder stays alive until completion.
|
|
|
|
RefPtr<MediaDecoder> kungFuDeathGrip = this;
|
2017-02-03 12:12:38 +03:00
|
|
|
if (auto owner = GetOwner()) {
|
|
|
|
owner->NotifyXPCOMShutdown();
|
2018-11-15 15:48:02 +03:00
|
|
|
} else if (!IsShutdown()) {
|
2017-02-03 12:12:38 +03:00
|
|
|
Shutdown();
|
|
|
|
}
|
2018-11-15 15:48:02 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(IsShutdown());
|
2017-02-03 12:12:38 +03:00
|
|
|
}
|
|
|
|
|
2012-11-14 23:46:40 +04:00
|
|
|
MediaDecoder::~MediaDecoder() {
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(IsShutdown());
|
2013-01-18 09:43:20 +04:00
|
|
|
MediaMemoryTracker::RemoveMediaDecoder(this);
|
2008-07-30 10:50:14 +04:00
|
|
|
}
|
|
|
|
|
2017-12-01 05:33:44 +03:00
|
|
|
void MediaDecoder::OnPlaybackEvent(MediaPlaybackEvent&& aEvent) {
|
|
|
|
switch (aEvent.mType) {
|
|
|
|
case MediaPlaybackEvent::PlaybackEnded:
|
2015-12-01 04:34:02 +03:00
|
|
|
PlaybackEnded();
|
|
|
|
break;
|
2017-12-01 05:33:44 +03:00
|
|
|
case MediaPlaybackEvent::SeekStarted:
|
2016-08-03 12:18:54 +03:00
|
|
|
SeekingStarted();
|
|
|
|
break;
|
2017-12-01 05:33:44 +03:00
|
|
|
case MediaPlaybackEvent::Invalidate:
|
2015-12-01 04:34:02 +03:00
|
|
|
Invalidate();
|
|
|
|
break;
|
2017-12-01 05:33:44 +03:00
|
|
|
case MediaPlaybackEvent::EnterVideoSuspend:
|
2017-01-20 06:47:53 +03:00
|
|
|
GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozentervideosuspend"));
|
2018-12-20 23:01:46 +03:00
|
|
|
mIsVideoDecodingSuspended = true;
|
2016-07-04 07:35:21 +03:00
|
|
|
break;
|
2017-12-01 05:33:44 +03:00
|
|
|
case MediaPlaybackEvent::ExitVideoSuspend:
|
2017-01-20 06:47:53 +03:00
|
|
|
GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozexitvideosuspend"));
|
2018-12-20 23:01:46 +03:00
|
|
|
mIsVideoDecodingSuspended = false;
|
2016-07-04 07:35:21 +03:00
|
|
|
break;
|
2017-12-01 05:33:44 +03:00
|
|
|
case MediaPlaybackEvent::StartVideoSuspendTimer:
|
2017-03-08 16:28:01 +03:00
|
|
|
GetOwner()->DispatchAsyncEvent(
|
|
|
|
NS_LITERAL_STRING("mozstartvideosuspendtimer"));
|
|
|
|
break;
|
2017-12-01 05:33:44 +03:00
|
|
|
case MediaPlaybackEvent::CancelVideoSuspendTimer:
|
2017-03-08 16:28:01 +03:00
|
|
|
GetOwner()->DispatchAsyncEvent(
|
|
|
|
NS_LITERAL_STRING("mozcancelvideosuspendtimer"));
|
2017-03-27 13:12:58 +03:00
|
|
|
break;
|
2017-12-01 05:33:44 +03:00
|
|
|
case MediaPlaybackEvent::VideoOnlySeekBegin:
|
2017-04-07 11:11:34 +03:00
|
|
|
GetOwner()->DispatchAsyncEvent(
|
|
|
|
NS_LITERAL_STRING("mozvideoonlyseekbegin"));
|
|
|
|
break;
|
2017-12-01 05:33:44 +03:00
|
|
|
case MediaPlaybackEvent::VideoOnlySeekCompleted:
|
2017-03-27 13:12:58 +03:00
|
|
|
GetOwner()->DispatchAsyncEvent(
|
|
|
|
NS_LITERAL_STRING("mozvideoonlyseekcompleted"));
|
2017-08-07 08:23:43 +03:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2015-12-01 04:34:02 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-20 23:01:46 +03:00
|
|
|
bool MediaDecoder::IsVideoDecodingSuspended() const {
|
|
|
|
return mIsVideoDecodingSuspended;
|
|
|
|
}
|
|
|
|
|
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());
|
2019-01-02 16:05:23 +03:00
|
|
|
Document* doc = GetOwner()->GetDocument();
|
2016-09-19 13:38:06 +03:00
|
|
|
if (!doc) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
DecoderDoctorDiagnostics diags;
|
|
|
|
diags.StoreEvent(doc, aEvent, __func__);
|
|
|
|
}
|
|
|
|
|
2017-10-06 10:48:38 +03:00
|
|
|
static const char* NextFrameStatusToStr(
|
|
|
|
MediaDecoderOwner::NextFrameStatus aStatus) {
|
|
|
|
switch (aStatus) {
|
|
|
|
case MediaDecoderOwner::NEXT_FRAME_AVAILABLE:
|
|
|
|
return "NEXT_FRAME_AVAILABLE";
|
|
|
|
case MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE:
|
|
|
|
return "NEXT_FRAME_UNAVAILABLE";
|
|
|
|
case MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING:
|
|
|
|
return "NEXT_FRAME_UNAVAILABLE_BUFFERING";
|
|
|
|
case MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_SEEKING:
|
|
|
|
return "NEXT_FRAME_UNAVAILABLE_SEEKING";
|
|
|
|
case MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED:
|
|
|
|
return "NEXT_FRAME_UNINITIALIZED";
|
|
|
|
}
|
|
|
|
return "UNKNOWN";
|
|
|
|
}
|
|
|
|
|
|
|
|
void MediaDecoder::OnNextFrameStatus(
|
|
|
|
MediaDecoderOwner::NextFrameStatus aStatus) {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
|
|
|
if (mNextFrameStatus != aStatus) {
|
|
|
|
LOG("Changed mNextFrameStatus to %s", NextFrameStatusToStr(aStatus));
|
|
|
|
mNextFrameStatus = aStatus;
|
|
|
|
UpdateReadyState();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-22 15:52:48 +03:00
|
|
|
void MediaDecoder::OnSecondaryVideoContainerInstalled(
|
|
|
|
const RefPtr<VideoFrameContainer>& aSecondaryVideoContainer) {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
GetOwner()->OnSecondaryVideoContainerInstalled(aSecondaryVideoContainer);
|
|
|
|
}
|
|
|
|
|
2019-08-06 12:25:45 +03:00
|
|
|
void MediaDecoder::OnStoreDecoderBenchmark(const VideoInfo& aInfo) {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
|
|
|
int32_t videoFrameRate = aInfo.GetFrameRate().ref();
|
|
|
|
|
|
|
|
if (mFrameStats && videoFrameRate) {
|
|
|
|
DecoderBenchmarkInfo benchmarkInfo{
|
|
|
|
aInfo.mMimeType,
|
|
|
|
aInfo.mDisplay.width,
|
|
|
|
aInfo.mDisplay.height,
|
|
|
|
videoFrameRate,
|
|
|
|
BitDepthForColorDepth(aInfo.mColorDepth),
|
|
|
|
};
|
|
|
|
|
|
|
|
LOG("Store benchmark: Video width=%d, height=%d, frameRate=%d, content "
|
|
|
|
"type = %s\n",
|
|
|
|
benchmarkInfo.mWidth, benchmarkInfo.mHeight, benchmarkInfo.mFrameRate,
|
|
|
|
benchmarkInfo.mContentType.BeginReading());
|
|
|
|
|
|
|
|
mDecoderBenchmark->Store(benchmarkInfo, mFrameStats);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-14 01:40:14 +03:00
|
|
|
void MediaDecoder::ShutdownInternal() {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2019-11-22 03:07:04 +03:00
|
|
|
mVideoFrameContainer = nullptr;
|
|
|
|
mSecondaryVideoContainer = nullptr;
|
2019-11-14 01:40:14 +03:00
|
|
|
MediaShutdownManager::Instance().Unregister(this);
|
|
|
|
}
|
|
|
|
|
2015-12-03 10:59:44 +03:00
|
|
|
void MediaDecoder::FinishShutdown() {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
SetStateMachine(nullptr);
|
2019-11-14 01:40:14 +03:00
|
|
|
ShutdownInternal();
|
2015-12-03 10:59:44 +03:00
|
|
|
}
|
|
|
|
|
2015-10-14 06:46:27 +03:00
|
|
|
nsresult MediaDecoder::InitializeStateMachine() {
|
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!");
|
2017-08-01 00:29:07 +03:00
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
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() {
|
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(
|
2016-11-29 08:03:36 +03:00
|
|
|
mAbstractMainThread, this, &MediaDecoder::OnMetadataUpdate);
|
2015-11-23 05:35:18 +03:00
|
|
|
mMetadataLoadedListener = mDecoderStateMachine->MetadataLoadedEvent().Connect(
|
2016-11-29 08:03:36 +03:00
|
|
|
mAbstractMainThread, this, &MediaDecoder::MetadataLoaded);
|
2017-01-27 15:20:37 +03:00
|
|
|
mFirstFrameLoadedListener =
|
|
|
|
mDecoderStateMachine->FirstFrameLoadedEvent().Connect(
|
|
|
|
mAbstractMainThread, this, &MediaDecoder::FirstFrameLoaded);
|
2015-11-30 08:06:19 +03:00
|
|
|
|
2015-12-01 04:34:02 +03:00
|
|
|
mOnPlaybackEvent = mDecoderStateMachine->OnPlaybackEvent().Connect(
|
2016-11-29 08:03:36 +03:00
|
|
|
mAbstractMainThread, this, &MediaDecoder::OnPlaybackEvent);
|
2016-09-10 17:51:13 +03:00
|
|
|
mOnPlaybackErrorEvent = mDecoderStateMachine->OnPlaybackErrorEvent().Connect(
|
2016-11-29 08:03:36 +03:00
|
|
|
mAbstractMainThread, this, &MediaDecoder::OnPlaybackErrorEvent);
|
2016-09-19 13:38:06 +03:00
|
|
|
mOnDecoderDoctorEvent = mDecoderStateMachine->OnDecoderDoctorEvent().Connect(
|
2016-11-29 08:03:36 +03:00
|
|
|
mAbstractMainThread, this, &MediaDecoder::OnDecoderDoctorEvent);
|
2015-12-02 10:42:32 +03:00
|
|
|
mOnMediaNotSeekable = mDecoderStateMachine->OnMediaNotSeekable().Connect(
|
2016-11-29 08:03:36 +03:00
|
|
|
mAbstractMainThread, this, &MediaDecoder::OnMediaNotSeekable);
|
2017-10-06 10:48:38 +03:00
|
|
|
mOnNextFrameStatus = mDecoderStateMachine->OnNextFrameStatus().Connect(
|
|
|
|
mAbstractMainThread, this, &MediaDecoder::OnNextFrameStatus);
|
2019-11-22 15:52:48 +03:00
|
|
|
mOnSecondaryVideoContainerInstalled =
|
|
|
|
mDecoderStateMachine->OnSecondaryVideoContainerInstalled().Connect(
|
|
|
|
mAbstractMainThread, this,
|
|
|
|
&MediaDecoder::OnSecondaryVideoContainerInstalled);
|
2019-08-06 12:25:45 +03:00
|
|
|
mOnStoreDecoderBenchmark = mReader->OnStoreDecoderBenchmark().Connect(
|
2019-08-13 10:15:25 +03:00
|
|
|
mAbstractMainThread, this, &MediaDecoder::OnStoreDecoderBenchmark);
|
2017-07-13 06:18:07 +03:00
|
|
|
|
|
|
|
mOnEncrypted = mReader->OnEncrypted().Connect(
|
|
|
|
mAbstractMainThread, GetOwner(), &MediaDecoderOwner::DispatchEncrypted);
|
2017-07-13 09:49:23 +03:00
|
|
|
mOnWaitingForKey = mReader->OnWaitingForKey().Connect(
|
|
|
|
mAbstractMainThread, GetOwner(), &MediaDecoderOwner::NotifyWaitingForKey);
|
2017-07-13 10:02:06 +03:00
|
|
|
mOnDecodeWarning = mReader->OnDecodeWarning().Connect(
|
|
|
|
mAbstractMainThread, GetOwner(), &MediaDecoderOwner::DecodeWarning);
|
2014-08-05 18:55:02 +04:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void MediaDecoder::Play() {
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2015-01-28 17:31:31 +03:00
|
|
|
|
2017-08-01 00:29:07 +03:00
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
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) {
|
2018-05-02 18:27:27 +03:00
|
|
|
return;
|
2014-09-01 08:52:39 +04:00
|
|
|
}
|
2015-07-23 13:39:09 +03:00
|
|
|
|
2015-03-05 04:33:40 +03:00
|
|
|
if (IsEnded()) {
|
2018-04-30 20:58:11 +03:00
|
|
|
Seek(0, SeekTarget::PrevSyncPoint);
|
2018-05-02 18:27:27 +03:00
|
|
|
return;
|
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;
|
2018-05-02 18:27:27 +03:00
|
|
|
return;
|
2008-10-19 11:39:21 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
ChangeState(PLAY_STATE_PLAYING);
|
2008-07-30 10:50:14 +04:00
|
|
|
}
|
|
|
|
|
2017-04-17 13:49:55 +03:00
|
|
|
void MediaDecoder::Seek(double aTime, SeekTarget::Type aSeekType) {
|
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
|
|
|
|
2017-08-01 00:29:07 +03:00
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
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
|
|
|
|
2019-02-27 16:12:08 +03:00
|
|
|
auto time = TimeUnit::FromSeconds(aTime);
|
2014-03-28 16:31:29 +04:00
|
|
|
|
2015-05-08 03:04:22 +03:00
|
|
|
mLogicalPosition = aTime;
|
2015-05-07 18:19:46 +03:00
|
|
|
mLogicallySeeking = true;
|
2019-02-27 16:12:08 +03:00
|
|
|
SeekTarget target = SeekTarget(time, aSeekType);
|
2017-04-17 13:49:55 +03:00
|
|
|
CallSeek(target);
|
2015-05-07 18:19:46 +03:00
|
|
|
|
|
|
|
if (mPlayState == PLAY_STATE_ENDED) {
|
2017-01-20 06:47:53 +03:00
|
|
|
ChangeState(GetOwner()->GetPaused() ? PLAY_STATE_PAUSED
|
|
|
|
: PLAY_STATE_PLAYING);
|
2008-10-19 11:39:21 +04:00
|
|
|
}
|
2015-05-07 18:19:46 +03:00
|
|
|
}
|
2008-10-19 11:39:21 +04:00
|
|
|
|
2020-01-09 20:10:08 +03:00
|
|
|
void MediaDecoder::SetDelaySeekMode(bool aShouldDelaySeek) {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
LOG("SetDelaySeekMode, shouldDelaySeek=%d", aShouldDelaySeek);
|
|
|
|
if (mShouldDelaySeek == aShouldDelaySeek) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mShouldDelaySeek = aShouldDelaySeek;
|
|
|
|
if (!mShouldDelaySeek && mDelayedSeekTarget) {
|
|
|
|
Seek(mDelayedSeekTarget->GetTime().ToSeconds(),
|
|
|
|
mDelayedSeekTarget->GetType());
|
|
|
|
mDelayedSeekTarget.reset();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-09 22:27:39 +03:00
|
|
|
void MediaDecoder::DiscardOngoingSeekIfExists() {
|
2015-07-01 00:39:41 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-08-01 00:29:07 +03:00
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
2015-05-07 18:19:46 +03:00
|
|
|
mSeekRequest.DisconnectIfExists();
|
2016-06-09 22:27:39 +03:00
|
|
|
}
|
|
|
|
|
2017-04-17 13:49:55 +03:00
|
|
|
void MediaDecoder::CallSeek(const SeekTarget& aTarget) {
|
2016-06-09 22:27:39 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-08-01 00:29:07 +03:00
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
2020-01-09 20:10:08 +03:00
|
|
|
if (mShouldDelaySeek) {
|
|
|
|
LOG("Delay seek to %f and store it to delayed seek target",
|
|
|
|
mDelayedSeekTarget->GetTime().ToSeconds());
|
|
|
|
mDelayedSeekTarget = Some(aTarget);
|
|
|
|
return;
|
|
|
|
}
|
2016-06-09 22:27:39 +03:00
|
|
|
DiscardOngoingSeekIfExists();
|
2017-01-11 11:33:29 +03:00
|
|
|
mDecoderStateMachine->InvokeSeek(aTarget)
|
2016-11-29 08:03:36 +03:00
|
|
|
->Then(mAbstractMainThread, __func__, this, &MediaDecoder::OnSeekResolved,
|
2017-01-11 11:33:29 +03:00
|
|
|
&MediaDecoder::OnSeekRejected)
|
|
|
|
->Track(mSeekRequest);
|
2008-10-19 11:39:21 +04:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
double MediaDecoder::GetCurrentTime() {
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-08-01 00:29:07 +03:00
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
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
|
|
|
void MediaDecoder::OnMetadataUpdate(TimedMetadata&& aMetadata) {
|
2015-09-07 06:38:34 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-08-01 00:29:07 +03:00
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
2017-05-18 11:35:49 +03:00
|
|
|
MetadataLoaded(MakeUnique<MediaInfo>(*aMetadata.mInfo),
|
2018-11-20 18:10:31 +03:00
|
|
|
UniquePtr<MetadataTags>(std::move(aMetadata.mTags)),
|
2015-09-07 06:38:34 +03:00
|
|
|
MediaDecoderEventVisibility::Observable);
|
2018-05-30 22:15:35 +03:00
|
|
|
FirstFrameLoaded(std::move(aMetadata.mInfo),
|
2015-09-07 06:38:34 +03:00
|
|
|
MediaDecoderEventVisibility::Observable);
|
|
|
|
}
|
|
|
|
|
2017-05-18 11:35:49 +03:00
|
|
|
void MediaDecoder::MetadataLoaded(
|
|
|
|
UniquePtr<MediaInfo> aInfo, UniquePtr<MetadataTags> aTags,
|
2015-09-22 08:57:24 +03:00
|
|
|
MediaDecoderEventVisibility aEventVisibility) {
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-08-01 00:29:07 +03:00
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2010-08-25 17:10:00 +04:00
|
|
|
|
2017-03-24 06:17:17 +03:00
|
|
|
LOG("MetadataLoaded, channels=%u rate=%u hasAudio=%d hasVideo=%d",
|
|
|
|
aInfo->mAudio.mChannels, aInfo->mAudio.mRate, aInfo->HasAudio(),
|
|
|
|
aInfo->HasVideo());
|
2014-08-21 04:13:00 +04:00
|
|
|
|
2016-11-02 09:41:04 +03:00
|
|
|
mMediaSeekable = aInfo->mMediaSeekable;
|
2016-11-02 12:16:59 +03:00
|
|
|
mMediaSeekableOnlyInBufferedRanges =
|
|
|
|
aInfo->mMediaSeekableOnlyInBufferedRanges;
|
2017-05-18 11:35:49 +03:00
|
|
|
mInfo = aInfo.release();
|
2014-07-04 07:55:06 +04:00
|
|
|
|
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;
|
2018-05-30 22:15:35 +03:00
|
|
|
GetOwner()->MetadataLoaded(mInfo, std::move(aTags));
|
2008-07-30 10:50:14 +04:00
|
|
|
}
|
2017-01-20 06:47:53 +03:00
|
|
|
// Invalidate() will end up calling GetOwner()->UpdateMediaSize with the last
|
2016-01-12 13:09:37 +03:00
|
|
|
// dimensions retrieved from the video frame container. The video frame
|
|
|
|
// container contains more up to date dimensions than aInfo.
|
2017-01-20 06:47:53 +03:00
|
|
|
// So we call Invalidate() after calling GetOwner()->MetadataLoaded to ensure
|
2016-01-12 13:09:37 +03:00
|
|
|
// the media element has the latest dimensions.
|
|
|
|
Invalidate();
|
2015-11-25 02:52:48 +03:00
|
|
|
|
|
|
|
EnsureTelemetryReported();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MediaDecoder::EnsureTelemetryReported() {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-08-01 00:29:07 +03:00
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
2015-11-25 02:52:48 +03:00
|
|
|
|
|
|
|
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;
|
2017-09-04 12:27:43 +03:00
|
|
|
if (mInfo->HasAudio() &&
|
|
|
|
!mInfo->mAudio.GetAsAudioInfo()->mMimeType.IsEmpty()) {
|
2015-11-25 02:52:48 +03:00
|
|
|
codecs.AppendElement(mInfo->mAudio.GetAsAudioInfo()->mMimeType);
|
|
|
|
}
|
2017-09-04 12:27:43 +03:00
|
|
|
if (mInfo->HasVideo() &&
|
|
|
|
!mInfo->mVideo.GetAsVideoInfo()->mMimeType.IsEmpty()) {
|
2015-11-25 02:52:48 +03:00
|
|
|
codecs.AppendElement(mInfo->mVideo.GetAsVideoInfo()->mMimeType);
|
|
|
|
}
|
|
|
|
if (codecs.IsEmpty()) {
|
2017-06-26 12:11:48 +03:00
|
|
|
codecs.AppendElement(nsPrintfCString(
|
|
|
|
"resource; %s", ContainerType().OriginalString().Data()));
|
2015-11-25 02:52:48 +03:00
|
|
|
}
|
|
|
|
for (const nsCString& codec : codecs) {
|
2017-03-24 06:17:17 +03:00
|
|
|
LOG("Telemetry MEDIA_CODEC_USED= '%s'", codec.get());
|
2017-02-15 22:15:15 +03:00
|
|
|
Telemetry::Accumulate(Telemetry::HistogramID::MEDIA_CODEC_USED, codec);
|
2015-11-25 02:52:48 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
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());
|
2017-08-01 00:29:07 +03:00
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
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());
|
2017-08-01 00:29:07 +03:00
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
2014-11-06 12:52:44 +03:00
|
|
|
|
2017-03-24 06:17:17 +03:00
|
|
|
LOG("FirstFrameLoaded, channels=%u rate=%u hasAudio=%d hasVideo=%d "
|
2017-08-17 06:52:29 +03:00
|
|
|
"mPlayState=%s transportSeekable=%d",
|
2017-03-24 06:17:17 +03:00
|
|
|
aInfo->mAudio.mChannels, aInfo->mAudio.mRate, aInfo->HasAudio(),
|
2017-08-23 19:08:41 +03:00
|
|
|
aInfo->HasVideo(), PlayStateStr(), IsTransportSeekable());
|
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
|
|
|
|
|
|
|
// 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
|
|
|
|
2017-01-20 06:47:53 +03:00
|
|
|
// GetOwner()->FirstFrameLoaded() might call us back. Put it at the bottom of
|
2016-10-21 09:27:27 +03:00
|
|
|
// this function to avoid unexpected shutdown from reentrant calls.
|
|
|
|
if (aEventVisibility != MediaDecoderEventVisibility::Suppressed) {
|
2017-01-20 06:47:53 +03:00
|
|
|
GetOwner()->FirstFrameLoaded();
|
2016-10-21 09:27:27 +03:00
|
|
|
}
|
2008-07-30 10:50:14 +04:00
|
|
|
}
|
|
|
|
|
2017-11-17 06:07:30 +03:00
|
|
|
void MediaDecoder::NetworkError(const MediaResult& aError) {
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2017-11-17 06:07:30 +03:00
|
|
|
GetOwner()->NetworkError(aError);
|
2008-11-06 23:53:20 +03:00
|
|
|
}
|
|
|
|
|
2016-09-10 17:51:13 +03:00
|
|
|
void MediaDecoder::DecodeError(const MediaResult& aError) {
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2017-01-20 06:47:53 +03:00
|
|
|
GetOwner()->DecodeError(aError);
|
2009-09-22 04:08:13 +04:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void MediaDecoder::UpdateSameOriginStatus(bool aSameOrigin) {
|
2015-07-01 00:39:41 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-08-01 00:29:07 +03:00
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
2013-07-24 13:55:23 +04:00
|
|
|
mSameOriginMedia = aSameOrigin;
|
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
bool MediaDecoder::IsSeeking() const {
|
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
|
|
|
}
|
|
|
|
|
2016-02-08 07:28:15 +03:00
|
|
|
bool MediaDecoder::OwnerHasError() const {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2017-01-20 06:47:53 +03:00
|
|
|
return GetOwner()->HasError();
|
2016-02-08 07:28:15 +03:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
bool MediaDecoder::IsEnded() const {
|
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() {
|
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
|
|
|
|
2017-04-05 17:57:25 +03:00
|
|
|
if (mLogicallySeeking || mPlayState == PLAY_STATE_LOADING ||
|
|
|
|
mPlayState == PLAY_STATE_ENDED) {
|
2017-03-24 06:17:17 +03:00
|
|
|
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
|
|
|
|
2017-03-24 06:17:17 +03:00
|
|
|
LOG("MediaDecoder::PlaybackEnded");
|
2016-11-24 09:58:50 +03:00
|
|
|
|
2009-04-01 05:07:10 +04:00
|
|
|
ChangeState(PLAY_STATE_ENDED);
|
2013-10-02 07:05:34 +04:00
|
|
|
InvalidateWithFlags(VideoFrameContainer::INVALIDATE_FORCE);
|
2017-01-20 06:47:53 +03:00
|
|
|
GetOwner()->PlaybackEnded();
|
2008-07-30 10:50:14 +04:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void MediaDecoder::NotifyPrincipalChanged() {
|
2015-07-01 00:39:41 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2017-08-01 00:29:07 +03:00
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
2017-01-20 06:47:53 +03:00
|
|
|
GetOwner()->NotifyDecoderPrincipalChanged();
|
2012-04-30 07:12:42 +04:00
|
|
|
}
|
|
|
|
|
2016-11-14 12:00:53 +03:00
|
|
|
void MediaDecoder::OnSeekResolved() {
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2017-08-01 00:29:07 +03:00
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
2017-12-19 12:56:52 +03:00
|
|
|
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();
|
2018-11-23 08:23:48 +03:00
|
|
|
mSeekRequest.Complete();
|
2014-04-01 07:39:04 +04:00
|
|
|
|
2017-01-20 06:47:53 +03:00
|
|
|
GetOwner()->SeekCompleted();
|
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;
|
2019-08-29 17:30:06 +03:00
|
|
|
|
|
|
|
GetOwner()->SeekAborted();
|
2016-06-09 22:27:39 +03:00
|
|
|
}
|
|
|
|
|
2016-08-03 12:18:54 +03:00
|
|
|
void MediaDecoder::SeekingStarted() {
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2017-01-20 06:47:53 +03:00
|
|
|
GetOwner()->SeekStarted();
|
2008-10-19 11:39:21 +04:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void MediaDecoder::ChangeState(PlayState aState) {
|
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.");
|
2017-08-01 00:29:07 +03:00
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
2008-10-19 11:39:21 +04:00
|
|
|
|
|
|
|
if (mNextState == aState) {
|
|
|
|
mNextState = PLAY_STATE_PAUSED;
|
|
|
|
}
|
|
|
|
|
Bug 1407810 - Use DDLogger in media stack - r=jwwang
Mostly-mechanical additions:
- Log constructions&destructions, usually by just inheriting from
DecoderDoctorLifeLogger, otherwise with explicit log commands (for internal
classes for which DecoderDoctorTraits can't be specialized),
- Log links between most objects, e.g.: Media element -> decoder -> state
machine -> reader -> demuxer -> resource, etc.
And logging some important properties and events (JS events, duration change,
frames being decoded, etc.)
More will be added later on, from just converting MOZ_LOGs, and as needed.
MozReview-Commit-ID: KgNhHSz35t0
--HG--
extra : rebase_source : dd7206e350e32671adc6f3b9e54ebf777251de2c
2017-10-10 09:55:27 +03:00
|
|
|
if (mPlayState != aState) {
|
|
|
|
DDLOG(DDLogCategory::Property, "play_state", ToPlayStateStr(aState));
|
|
|
|
}
|
2008-10-19 11:39:21 +04:00
|
|
|
mPlayState = aState;
|
|
|
|
}
|
2008-10-23 12:02:18 +04:00
|
|
|
|
2018-11-23 08:23:48 +03:00
|
|
|
bool MediaDecoder::IsLoopingBack(double aPrevPos, double aCurPos) const {
|
|
|
|
// If current position is early than previous position and we didn't do seek,
|
|
|
|
// that means we looped back to the start position.
|
|
|
|
return mLooping && !mSeekRequest.Exists() && aCurPos < aPrevPos;
|
|
|
|
}
|
|
|
|
|
2016-11-03 10:59:02 +03:00
|
|
|
void MediaDecoder::UpdateLogicalPositionInternal() {
|
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
|
|
|
|
2017-04-17 12:04:39 +03:00
|
|
|
double currentPosition = CurrentPosition().ToSeconds();
|
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;
|
2018-11-23 08:23:48 +03:00
|
|
|
SeekEventsGuard guard(GetOwner(),
|
|
|
|
IsLoopingBack(mLogicalPosition, currentPosition));
|
2015-05-08 03:04:22 +03:00
|
|
|
mLogicalPosition = currentPosition;
|
Bug 1407810 - Use DDLogger in media stack - r=jwwang
Mostly-mechanical additions:
- Log constructions&destructions, usually by just inheriting from
DecoderDoctorLifeLogger, otherwise with explicit log commands (for internal
classes for which DecoderDoctorTraits can't be specialized),
- Log links between most objects, e.g.: Media element -> decoder -> state
machine -> reader -> demuxer -> resource, etc.
And logging some important properties and events (JS events, duration change,
frames being decoded, etc.)
More will be added later on, from just converting MOZ_LOGs, and as needed.
MozReview-Commit-ID: KgNhHSz35t0
--HG--
extra : rebase_source : dd7206e350e32671adc6f3b9e54ebf777251de2c
2017-10-10 09:55:27 +03:00
|
|
|
DDLOG(DDLogCategory::Property, "currentTime", mLogicalPosition);
|
2015-05-08 03:04:22 +03:00
|
|
|
|
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() {
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2017-08-01 00:29:07 +03:00
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
2015-10-19 08:55:38 +03:00
|
|
|
|
2015-06-09 21:40:03 +03:00
|
|
|
double oldDuration = mDuration;
|
2017-08-01 09:15:29 +03:00
|
|
|
|
|
|
|
// Use the explicit duration if we have one.
|
|
|
|
// Otherwise use the duration mirrored from MDSM.
|
2017-08-01 10:06:13 +03:00
|
|
|
if (mExplicitDuration.isSome()) {
|
|
|
|
mDuration = mExplicitDuration.ref();
|
2015-06-10 01:16:27 +03:00
|
|
|
} else if (mStateMachineDuration.Ref().isSome()) {
|
|
|
|
mDuration = mStateMachineDuration.Ref().ref().ToSeconds();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mDuration == oldDuration || IsNaN(mDuration)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-24 06:17:17 +03:00
|
|
|
LOG("Duration changed to %f", mDuration);
|
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.
|
2017-08-01 10:06:13 +03:00
|
|
|
if (mFiredMetadataLoaded &&
|
|
|
|
(!mozilla::IsInfinite<double>(mDuration) || mExplicitDuration.isSome())) {
|
2017-01-20 06:47:53 +03:00
|
|
|
GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
|
2010-04-02 07:03:07 +04:00
|
|
|
}
|
2015-06-04 21:08:48 +03:00
|
|
|
|
2017-04-17 12:04:39 +03:00
|
|
|
if (CurrentPosition() > TimeUnit::FromSeconds(mDuration)) {
|
2015-06-10 01:16:27 +03:00
|
|
|
Seek(mDuration, SeekTarget::Accurate);
|
2015-06-04 21:08:48 +03:00
|
|
|
}
|
2010-04-02 07:03:07 +04:00
|
|
|
}
|
|
|
|
|
2017-07-12 10:37:02 +03:00
|
|
|
already_AddRefed<KnowsCompositor> MediaDecoder::GetCompositor() {
|
2017-03-10 11:29:59 +03:00
|
|
|
MediaDecoderOwner* owner = GetOwner();
|
2019-01-02 16:05:23 +03:00
|
|
|
Document* ownerDoc = owner ? owner->GetDocument() : nullptr;
|
2017-03-10 11:29:59 +03:00
|
|
|
RefPtr<LayerManager> layerManager =
|
2017-07-12 10:37:02 +03:00
|
|
|
ownerDoc ? nsContentUtils::LayerManagerForDocument(ownerDoc) : nullptr;
|
|
|
|
RefPtr<KnowsCompositor> knows =
|
2017-08-07 13:15:22 +03:00
|
|
|
layerManager ? layerManager->AsKnowsCompositor() : nullptr;
|
2017-12-05 13:56:20 +03:00
|
|
|
return knows ? knows->GetForMedia().forget() : nullptr;
|
2017-07-12 10:37:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void MediaDecoder::NotifyCompositor() {
|
|
|
|
RefPtr<KnowsCompositor> knowsCompositor = GetCompositor();
|
|
|
|
if (knowsCompositor) {
|
2017-07-12 11:28:19 +03:00
|
|
|
nsCOMPtr<nsIRunnable> r =
|
|
|
|
NewRunnableMethod<already_AddRefed<KnowsCompositor>&&>(
|
2017-07-19 12:01:32 +03:00
|
|
|
"MediaFormatReader::UpdateCompositor", mReader,
|
|
|
|
&MediaFormatReader::UpdateCompositor, knowsCompositor.forget());
|
2017-11-15 09:58:03 +03:00
|
|
|
Unused << mReader->OwnerThread()->Dispatch(r.forget());
|
2017-03-10 11:29:59 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-11 14:56:17 +03:00
|
|
|
void MediaDecoder::SetElementVisibility(bool aIsDocumentVisible,
|
2017-03-17 07:51:11 +03:00
|
|
|
Visibility aElementVisibility,
|
2017-03-12 09:02:04 +03:00
|
|
|
bool aIsElementInTree) {
|
2016-04-12 08:48:06 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-03-11 14:56:17 +03:00
|
|
|
mIsDocumentVisible = aIsDocumentVisible;
|
2017-03-17 07:51:11 +03:00
|
|
|
mElementVisibility = aElementVisibility;
|
2017-03-12 09:02:04 +03:00
|
|
|
mIsElementInTree = aIsElementInTree;
|
2017-03-10 11:52:03 +03:00
|
|
|
UpdateVideoDecodeMode();
|
2016-08-25 05:10:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void MediaDecoder::SetForcedHidden(bool aForcedHidden) {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
mForcedHidden = aForcedHidden;
|
2017-03-10 11:52:03 +03:00
|
|
|
UpdateVideoDecodeMode();
|
2016-04-12 08:48:06 +03:00
|
|
|
}
|
|
|
|
|
2017-03-08 14:28:13 +03:00
|
|
|
void MediaDecoder::SetSuspendTaint(bool aTainted) {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
mHasSuspendTaint = aTainted;
|
2017-03-10 11:52:03 +03:00
|
|
|
UpdateVideoDecodeMode();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MediaDecoder::UpdateVideoDecodeMode() {
|
2017-08-01 00:29:07 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
AbstractThread::AutoEnter context(mAbstractMainThread);
|
|
|
|
|
2017-03-10 11:52:03 +03:00
|
|
|
// The MDSM may yet be set.
|
|
|
|
if (!mDecoderStateMachine) {
|
2017-07-24 08:21:35 +03:00
|
|
|
LOG("UpdateVideoDecodeMode(), early return because we don't have MDSM.");
|
2017-03-10 11:52:03 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-12-18 22:46:16 +03:00
|
|
|
// Seeking is required when leaving suspend mode.
|
|
|
|
if (!mMediaSeekable) {
|
|
|
|
LOG("UpdateVideoDecodeMode(), set Normal because the media is not "
|
|
|
|
"seekable");
|
|
|
|
mDecoderStateMachine->SetVideoDecodeMode(VideoDecodeMode::Normal);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-10 11:52:03 +03:00
|
|
|
// If mHasSuspendTaint is set, never suspend the video decoder.
|
|
|
|
if (mHasSuspendTaint) {
|
2017-07-24 08:21:35 +03:00
|
|
|
LOG("UpdateVideoDecodeMode(), set Normal because the element has been "
|
|
|
|
"tainted.");
|
2017-03-10 11:52:03 +03:00
|
|
|
mDecoderStateMachine->SetVideoDecodeMode(VideoDecodeMode::Normal);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-11-22 03:07:04 +03:00
|
|
|
// If mSecondaryVideoContainer is set, never suspend the video decoder.
|
|
|
|
if (mSecondaryVideoContainer.Ref()) {
|
2019-03-02 01:36:53 +03:00
|
|
|
LOG("UpdateVideoDecodeMode(), set Normal because the element is cloning "
|
|
|
|
"itself visually to another video container.");
|
|
|
|
mDecoderStateMachine->SetVideoDecodeMode(VideoDecodeMode::Normal);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-12 09:02:04 +03:00
|
|
|
// Don't suspend elements that is not in tree.
|
|
|
|
if (!mIsElementInTree) {
|
2017-07-24 08:21:35 +03:00
|
|
|
LOG("UpdateVideoDecodeMode(), set Normal because the element is not in "
|
|
|
|
"tree.");
|
2017-03-12 09:02:04 +03:00
|
|
|
mDecoderStateMachine->SetVideoDecodeMode(VideoDecodeMode::Normal);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-10 11:52:03 +03:00
|
|
|
// If mForcedHidden is set, suspend the video decoder anyway.
|
2017-03-11 14:56:17 +03:00
|
|
|
if (mForcedHidden) {
|
2017-07-24 08:21:35 +03:00
|
|
|
LOG("UpdateVideoDecodeMode(), set Suspend because the element is forced to "
|
|
|
|
"be suspended.");
|
2017-03-11 14:56:17 +03:00
|
|
|
mDecoderStateMachine->SetVideoDecodeMode(VideoDecodeMode::Suspend);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-07-20 09:13:37 +03:00
|
|
|
// Resume decoding in the advance, even the element is in the background.
|
|
|
|
if (mIsBackgroundVideoDecodingAllowed) {
|
2017-07-24 08:21:35 +03:00
|
|
|
LOG("UpdateVideoDecodeMode(), set Normal because the tab is in background "
|
|
|
|
"and hovered.");
|
2017-07-20 09:13:37 +03:00
|
|
|
mDecoderStateMachine->SetVideoDecodeMode(VideoDecodeMode::Normal);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-12-20 23:02:24 +03:00
|
|
|
// If the element is in-tree with UNTRACKED visibility, that means the element
|
|
|
|
// is not close enough to the viewport so we have not start to update its
|
|
|
|
// visibility. In this case, it's equals to invisible.
|
2019-04-26 02:03:04 +03:00
|
|
|
if (mIsElementInTree && mElementVisibility == Visibility::Untracked) {
|
2018-12-20 23:02:24 +03:00
|
|
|
LOG("UpdateVideoDecodeMode(), set Suspend because element hasn't be "
|
|
|
|
"updated visibility state.");
|
|
|
|
mDecoderStateMachine->SetVideoDecodeMode(VideoDecodeMode::Suspend);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-10 11:52:03 +03:00
|
|
|
// Otherwise, depends on the owner's visibility state.
|
2017-03-11 14:56:17 +03:00
|
|
|
// A element is visible only if its document is visible and the element
|
|
|
|
// itself is visible.
|
2017-03-17 07:51:11 +03:00
|
|
|
if (mIsDocumentVisible &&
|
2019-04-26 02:03:04 +03:00
|
|
|
mElementVisibility == Visibility::ApproximatelyVisible) {
|
2017-07-24 08:21:35 +03:00
|
|
|
LOG("UpdateVideoDecodeMode(), set Normal because the element visible.");
|
2017-03-10 11:52:03 +03:00
|
|
|
mDecoderStateMachine->SetVideoDecodeMode(VideoDecodeMode::Normal);
|
|
|
|
} else {
|
2017-07-24 08:21:35 +03:00
|
|
|
LOG("UpdateVideoDecodeMode(), set Suspend because the element is not "
|
|
|
|
"visible.");
|
2017-03-10 11:52:03 +03:00
|
|
|
mDecoderStateMachine->SetVideoDecodeMode(VideoDecodeMode::Suspend);
|
|
|
|
}
|
2017-03-08 14:28:13 +03:00
|
|
|
}
|
|
|
|
|
2017-12-06 01:22:36 +03:00
|
|
|
void MediaDecoder::SetIsBackgroundVideoDecodingAllowed(bool aAllowed) {
|
|
|
|
mIsBackgroundVideoDecodingAllowed = aAllowed;
|
|
|
|
UpdateVideoDecodeMode();
|
|
|
|
}
|
|
|
|
|
2017-03-08 14:28:13 +03:00
|
|
|
bool MediaDecoder::HasSuspendTaint() const {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
return mHasSuspendTaint;
|
|
|
|
}
|
|
|
|
|
2019-11-22 03:07:04 +03:00
|
|
|
void MediaDecoder::SetSecondaryVideoContainer(
|
|
|
|
RefPtr<VideoFrameContainer> aSecondaryVideoContainer) {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
|
|
|
if (mSecondaryVideoContainer.Ref() == aSecondaryVideoContainer) {
|
|
|
|
return;
|
2019-03-02 01:36:53 +03:00
|
|
|
}
|
2019-11-22 03:07:04 +03:00
|
|
|
mSecondaryVideoContainer = std::move(aSecondaryVideoContainer);
|
|
|
|
UpdateVideoDecodeMode();
|
2019-03-02 01:36:53 +03:00
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
bool MediaDecoder::IsMediaSeekable() {
|
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() {
|
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(
|
2017-04-17 11:35:04 +03:00
|
|
|
TimeUnit::Zero(), IsInfinite() ? TimeUnit::FromInfinity()
|
|
|
|
: TimeUnit::FromSeconds(GetDuration())));
|
2011-08-09 14:10:48 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void MediaDecoder::SetFragmentEndTime(double aTime) {
|
2012-11-17 05:37:46 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2011-08-25 03:42:23 +04:00
|
|
|
if (mDecoderStateMachine) {
|
2017-01-27 15:20:37 +03:00
|
|
|
mDecoderStateMachine->DispatchSetFragmentEndTime(
|
2017-04-17 11:35:04 +03:00
|
|
|
TimeUnit::FromSeconds(aTime));
|
2011-08-25 03:42:23 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-22 08:57:24 +03:00
|
|
|
void MediaDecoder::SetPlaybackRate(double aPlaybackRate) {
|
2015-07-01 00:39:41 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-08-01 00:29:07 +03:00
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
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;
|
|
|
|
}
|
|
|
|
|
2017-01-20 06:47:53 +03:00
|
|
|
if (oldRate == 0 && !GetOwner()->GetPaused()) {
|
2016-09-22 12:02:48 +03:00
|
|
|
// 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) {
|
2015-07-01 00:39:41 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-08-01 00:29:07 +03:00
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
2015-05-02 00:27:29 +03:00
|
|
|
mPreservesPitch = aPreservesPitch;
|
2012-11-22 14:38:28 +04:00
|
|
|
}
|
|
|
|
|
2017-06-08 07:03:10 +03:00
|
|
|
void MediaDecoder::SetLooping(bool aLooping) {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-08-01 00:29:07 +03:00
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
2017-06-08 07:03:10 +03:00
|
|
|
mLooping = aLooping;
|
|
|
|
}
|
|
|
|
|
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());
|
|
|
|
mCurrentPosition.Connect(aObject->CanonicalCurrentPosition());
|
|
|
|
mIsAudioDataAudible.Connect(aObject->CanonicalIsAudioDataAudible());
|
|
|
|
}
|
|
|
|
|
|
|
|
void MediaDecoder::DisconnectMirrors() {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
mStateMachineDuration.DisconnectIfConnected();
|
|
|
|
mBuffered.DisconnectIfConnected();
|
|
|
|
mCurrentPosition.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);
|
2016-07-15 10:35:41 +03:00
|
|
|
if (aStateMachine) {
|
Bug 1407810 - Use DDLogger in media stack - r=jwwang
Mostly-mechanical additions:
- Log constructions&destructions, usually by just inheriting from
DecoderDoctorLifeLogger, otherwise with explicit log commands (for internal
classes for which DecoderDoctorTraits can't be specialized),
- Log links between most objects, e.g.: Media element -> decoder -> state
machine -> reader -> demuxer -> resource, etc.
And logging some important properties and events (JS events, duration change,
frames being decoded, etc.)
More will be added later on, from just converting MOZ_LOGs, and as needed.
MozReview-Commit-ID: KgNhHSz35t0
--HG--
extra : rebase_source : dd7206e350e32671adc6f3b9e54ebf777251de2c
2017-10-10 09:55:27 +03:00
|
|
|
mDecoderStateMachine = aStateMachine;
|
|
|
|
DDLINKCHILD("decoder state machine", mDecoderStateMachine.get());
|
2016-07-15 10:35:41 +03:00
|
|
|
ConnectMirrors(aStateMachine);
|
2017-03-10 11:52:03 +03:00
|
|
|
UpdateVideoDecodeMode();
|
Bug 1407810 - Use DDLogger in media stack - r=jwwang
Mostly-mechanical additions:
- Log constructions&destructions, usually by just inheriting from
DecoderDoctorLifeLogger, otherwise with explicit log commands (for internal
classes for which DecoderDoctorTraits can't be specialized),
- Log links between most objects, e.g.: Media element -> decoder -> state
machine -> reader -> demuxer -> resource, etc.
And logging some important properties and events (JS events, duration change,
frames being decoded, etc.)
More will be added later on, from just converting MOZ_LOGs, and as needed.
MozReview-Commit-ID: KgNhHSz35t0
--HG--
extra : rebase_source : dd7206e350e32671adc6f3b9e54ebf777251de2c
2017-10-10 09:55:27 +03:00
|
|
|
} else if (mDecoderStateMachine) {
|
|
|
|
DDUNLINKCHILD(mDecoderStateMachine.get());
|
|
|
|
mDecoderStateMachine = nullptr;
|
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() {
|
2017-01-27 15:20:37 +03:00
|
|
|
return mVideoFrameContainer ? mVideoFrameContainer->GetImageContainer()
|
|
|
|
: nullptr;
|
2012-11-14 23:45:13 +04:00
|
|
|
}
|
|
|
|
|
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.
|
2017-01-27 15:20:37 +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
|
|
|
}
|
|
|
|
|
2017-01-27 15:20:37 +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;
|
|
|
|
}
|
|
|
|
|
2017-01-27 15:20:37 +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;
|
|
|
|
}
|
|
|
|
|
2017-11-30 05:51:56 +03:00
|
|
|
void MediaDecoder::NotifyReaderDataArrived() {
|
2015-06-18 00:22:10 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2017-11-15 09:58:03 +03:00
|
|
|
|
2017-11-30 05:51:56 +03:00
|
|
|
nsresult rv = mReader->OwnerThread()->Dispatch(
|
|
|
|
NewRunnableMethod("MediaFormatReader::NotifyDataArrived", mReader.get(),
|
|
|
|
&MediaFormatReader::NotifyDataArrived));
|
2017-11-15 09:58:03 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
|
2017-12-21 07:12:42 +03:00
|
|
|
Unused << rv;
|
2012-11-07 02:33:02 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Provide access to the state machine object
|
2017-01-27 15:20:37 +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() {
|
2015-07-01 00:39:41 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2017-01-20 06:47:53 +03:00
|
|
|
GetOwner()->FireTimeUpdate(true);
|
2012-11-14 23:45:13 +04:00
|
|
|
}
|
|
|
|
|
2017-08-04 12:38:20 +03:00
|
|
|
bool MediaDecoder::CanPlayThrough() {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
2017-12-01 09:34:58 +03:00
|
|
|
return CanPlayThroughImpl();
|
2017-08-04 12:38:20 +03:00
|
|
|
}
|
|
|
|
|
2014-07-30 10:53:34 +04:00
|
|
|
RefPtr<SetCDMPromise> MediaDecoder::SetCDMProxy(CDMProxy* aProxy) {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-11-03 15:14:17 +03:00
|
|
|
return InvokeAsync<RefPtr<CDMProxy>>(mReader->OwnerThread(), mReader.get(),
|
|
|
|
__func__,
|
|
|
|
&MediaFormatReader::SetCDMProxy, aProxy);
|
2014-07-30 10:53:34 +04:00
|
|
|
}
|
|
|
|
|
2019-06-28 07:09:05 +03:00
|
|
|
bool MediaDecoder::IsOpusEnabled() { return StaticPrefs::media_opus_enabled(); }
|
2012-11-14 23:45:13 +04:00
|
|
|
|
2019-06-28 07:09:05 +03:00
|
|
|
bool MediaDecoder::IsOggEnabled() { return StaticPrefs::media_ogg_enabled(); }
|
2012-11-14 23:45:13 +04:00
|
|
|
|
2019-06-28 07:09:05 +03:00
|
|
|
bool MediaDecoder::IsWaveEnabled() { return StaticPrefs::media_wave_enabled(); }
|
2012-11-14 23:45:13 +04:00
|
|
|
|
2019-06-28 07:09:05 +03:00
|
|
|
bool MediaDecoder::IsWebMEnabled() { return StaticPrefs::media_webm_enabled(); }
|
2012-11-14 23:45:13 +04:00
|
|
|
|
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) {
|
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(
|
2017-03-01 06:36:17 +03:00
|
|
|
// Don't use SystemGroup::AbstractMainThreadFor() for
|
|
|
|
// handleReport->Callback() will run scripts.
|
2016-11-29 08:03:36 +03:00
|
|
|
AbstractThread::MainThread(), __func__,
|
2015-08-21 01:10:33 +03:00
|
|
|
[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 */ });
|
|
|
|
|
2017-01-27 15:20:37 +03:00
|
|
|
int64_t video = 0;
|
|
|
|
int64_t audio = 0;
|
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
|
|
|
|
2016-07-28 12:21:09 +03:00
|
|
|
MediaDecoderOwner* MediaDecoder::GetOwner() const {
|
2013-05-04 14:12:41 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
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
|
|
|
}
|
|
|
|
|
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.
|
2017-04-17 12:04:39 +03:00
|
|
|
auto currentPosition = CurrentPosition();
|
2017-01-27 15:20:37 +03:00
|
|
|
media::TimeInterval interval(
|
2017-04-17 11:58:44 +03:00
|
|
|
currentPosition, currentPosition + DEFAULT_NEXT_FRAME_AVAILABLE_BUFFERED);
|
2015-12-02 03:50:21 +03:00
|
|
|
return GetBuffered().Contains(interval)
|
2017-01-27 15:20:37 +03:00
|
|
|
? MediaDecoderOwner::NEXT_FRAME_AVAILABLE
|
|
|
|
: MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE;
|
2015-12-02 03:50:21 +03:00
|
|
|
}
|
|
|
|
|
2019-05-27 19:15:33 +03:00
|
|
|
void MediaDecoder::GetDebugInfo(dom::MediaDecoderDebugInfo& aInfo) {
|
|
|
|
aInfo.mInstance = NS_ConvertUTF8toUTF16(nsPrintfCString("%p", this));
|
|
|
|
aInfo.mChannels = mInfo ? mInfo->mAudio.mChannels : 0;
|
|
|
|
aInfo.mRate = mInfo ? mInfo->mAudio.mRate : 0;
|
|
|
|
aInfo.mHasAudio = mInfo ? mInfo->HasAudio() : false;
|
|
|
|
aInfo.mHasVideo = mInfo ? mInfo->HasVideo() : false;
|
|
|
|
aInfo.mPlayState = NS_ConvertUTF8toUTF16(PlayStateStr());
|
|
|
|
aInfo.mContainerType =
|
|
|
|
NS_ConvertUTF8toUTF16(ContainerType().Type().AsString());
|
|
|
|
mReader->GetDebugInfo(aInfo.mReader);
|
|
|
|
}
|
|
|
|
|
|
|
|
RefPtr<GenericPromise> MediaDecoder::RequestDebugInfo(
|
|
|
|
MediaDecoderDebugInfo& aInfo) {
|
2019-05-07 15:07:27 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2019-05-27 19:15:33 +03:00
|
|
|
GetDebugInfo(aInfo);
|
2019-05-07 15:07:27 +03:00
|
|
|
|
|
|
|
if (!GetStateMachine()) {
|
|
|
|
return GenericPromise::CreateAndResolve(true, __func__);
|
|
|
|
}
|
|
|
|
|
2019-05-27 19:15:33 +03:00
|
|
|
return GetStateMachine()
|
|
|
|
->RequestDebugInfo(aInfo.mStateMachine)
|
|
|
|
->Then(
|
|
|
|
SystemGroup::AbstractMainThreadFor(TaskCategory::Other), __func__,
|
|
|
|
[]() { return GenericPromise::CreateAndResolve(true, __func__); },
|
|
|
|
[]() {
|
2019-10-18 04:49:06 +03:00
|
|
|
MOZ_ASSERT_UNREACHABLE("Unexpected RequestDebugInfo() rejection");
|
2019-05-27 19:15:33 +03:00
|
|
|
return GenericPromise::CreateAndResolve(false, __func__);
|
|
|
|
});
|
2017-08-15 08:07:13 +03:00
|
|
|
}
|
|
|
|
|
2016-01-21 05:27:38 +03:00
|
|
|
void MediaDecoder::NotifyAudibleStateChanged() {
|
2016-11-24 06:59:18 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2017-01-20 06:47:53 +03:00
|
|
|
GetOwner()->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() {
|
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() {
|
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
|
2017-03-24 06:17:17 +03:00
|
|
|
#undef DUMP
|
|
|
|
#undef LOG
|
2017-03-01 06:36:17 +03:00
|
|
|
#undef NS_DispatchToMainThread
|