2017-06-19 10:50:09 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
|
|
|
/* 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/. */
|
|
|
|
|
|
|
|
#include "ChannelMediaDecoder.h"
|
2017-08-03 09:05:28 +03:00
|
|
|
#include "DecoderTraits.h"
|
|
|
|
#include "MediaDecoderStateMachine.h"
|
|
|
|
#include "MediaFormatReader.h"
|
2017-10-04 21:57:11 +03:00
|
|
|
#include "BaseMediaResource.h"
|
2017-06-23 09:12:41 +03:00
|
|
|
#include "MediaShutdownManager.h"
|
2017-06-19 10:50:09 +03:00
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
2017-08-04 11:02:40 +03:00
|
|
|
extern LazyLogModule gMediaDecoderLog;
|
|
|
|
#define LOG(x, ...) \
|
|
|
|
MOZ_LOG( \
|
|
|
|
gMediaDecoderLog, LogLevel::Debug, ("Decoder=%p " x, this, ##__VA_ARGS__))
|
|
|
|
|
2017-06-20 13:10:56 +03:00
|
|
|
ChannelMediaDecoder::ResourceCallback::ResourceCallback(
|
|
|
|
AbstractThread* aMainThread)
|
|
|
|
: mAbstractMainThread(aMainThread)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aMainThread);
|
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
|
|
|
DecoderDoctorLogger::LogConstructionAndBase(
|
|
|
|
"ChannelMediaDecoder::ResourceCallback",
|
|
|
|
this,
|
|
|
|
static_cast<const MediaResourceCallback*>(this));
|
|
|
|
}
|
|
|
|
|
|
|
|
ChannelMediaDecoder::ResourceCallback::~ResourceCallback()
|
|
|
|
{
|
|
|
|
DecoderDoctorLogger::LogDestruction("ChannelMediaDecoder::ResourceCallback",
|
|
|
|
this);
|
2017-06-20 13:10:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ChannelMediaDecoder::ResourceCallback::Connect(ChannelMediaDecoder* aDecoder)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
mDecoder = aDecoder;
|
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
|
|
|
DecoderDoctorLogger::LinkParentAndChild(
|
|
|
|
"ChannelMediaDecoder::ResourceCallback", this, "decoder", mDecoder);
|
2017-10-16 09:15:40 +03:00
|
|
|
mTimer = NS_NewTimer(mAbstractMainThread->AsEventTarget());
|
2017-06-20 13:10:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ChannelMediaDecoder::ResourceCallback::Disconnect()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
if (mDecoder) {
|
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
|
|
|
DecoderDoctorLogger::UnlinkParentAndChild(
|
|
|
|
"ChannelMediaDecoder::ResourceCallback", this, mDecoder);
|
2017-06-20 13:10:56 +03:00
|
|
|
mDecoder = nullptr;
|
|
|
|
mTimer->Cancel();
|
|
|
|
mTimer = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-06 10:12:34 +03:00
|
|
|
AbstractThread*
|
|
|
|
ChannelMediaDecoder::ResourceCallback::AbstractMainThread() const
|
|
|
|
{
|
|
|
|
return mAbstractMainThread;
|
|
|
|
}
|
|
|
|
|
2017-06-20 13:10:56 +03:00
|
|
|
MediaDecoderOwner*
|
|
|
|
ChannelMediaDecoder::ResourceCallback::GetMediaOwner() const
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
return mDecoder ? mDecoder->GetOwner() : nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2017-11-17 06:07:30 +03:00
|
|
|
ChannelMediaDecoder::ResourceCallback::NotifyNetworkError(
|
|
|
|
const MediaResult& aError)
|
2017-06-20 13:10:56 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
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
|
|
|
DDLOGEX2("ChannelMediaDecoder::ResourceCallback",
|
|
|
|
this,
|
|
|
|
DDLogCategory::Log,
|
|
|
|
"network_error",
|
|
|
|
aError);
|
2017-06-20 13:10:56 +03:00
|
|
|
if (mDecoder) {
|
2017-11-17 06:07:30 +03:00
|
|
|
mDecoder->NetworkError(aError);
|
2017-06-20 13:10:56 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ void
|
|
|
|
ChannelMediaDecoder::ResourceCallback::TimerCallback(nsITimer* aTimer,
|
|
|
|
void* aClosure)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
ResourceCallback* thiz = static_cast<ResourceCallback*>(aClosure);
|
|
|
|
MOZ_ASSERT(thiz->mDecoder);
|
2017-11-30 05:51:56 +03:00
|
|
|
thiz->mDecoder->NotifyReaderDataArrived();
|
2017-06-20 13:10:56 +03:00
|
|
|
thiz->mTimerArmed = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ChannelMediaDecoder::ResourceCallback::NotifyDataArrived()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
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
|
|
|
DDLOGEX2("ChannelMediaDecoder::ResourceCallback",
|
|
|
|
this,
|
|
|
|
DDLogCategory::Log,
|
|
|
|
"data_arrived",
|
|
|
|
true);
|
|
|
|
|
2017-06-20 13:10:56 +03:00
|
|
|
if (!mDecoder) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mDecoder->DownloadProgressed();
|
|
|
|
|
|
|
|
if (mTimerArmed) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// 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;
|
2017-06-29 22:13:25 +03:00
|
|
|
mTimer->InitWithNamedFuncCallback(
|
|
|
|
TimerCallback, this, sDelay, nsITimer::TYPE_ONE_SHOT,
|
|
|
|
"ChannelMediaDecoder::ResourceCallback::TimerCallback");
|
2017-06-20 13:10:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ChannelMediaDecoder::ResourceCallback::NotifyDataEnded(nsresult aStatus)
|
|
|
|
{
|
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
|
|
|
DDLOGEX2("ChannelMediaDecoder::ResourceCallback",
|
|
|
|
this,
|
|
|
|
DDLogCategory::Log,
|
|
|
|
"data_ended",
|
|
|
|
aStatus);
|
2017-11-10 09:27:59 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-11-15 06:07:06 +03:00
|
|
|
if (mDecoder) {
|
|
|
|
mDecoder->NotifyDownloadEnded(aStatus);
|
2017-11-10 09:27:59 +03:00
|
|
|
}
|
2017-06-20 13:10:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ChannelMediaDecoder::ResourceCallback::NotifyPrincipalChanged()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
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
|
|
|
DDLOGEX2("ChannelMediaDecoder::ResourceCallback",
|
|
|
|
this,
|
|
|
|
DDLogCategory::Log,
|
|
|
|
"principal_changed",
|
|
|
|
true);
|
2017-06-20 13:10:56 +03:00
|
|
|
if (mDecoder) {
|
|
|
|
mDecoder->NotifyPrincipalChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2017-08-23 09:32:51 +03:00
|
|
|
ChannelMediaDecoder::ResourceCallback::NotifySuspendedStatusChanged(
|
|
|
|
bool aSuspendedByCache)
|
2017-06-20 13:10:56 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
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
|
|
|
DDLOGEX2("ChannelMediaDecoder::ResourceCallback",
|
|
|
|
this,
|
|
|
|
DDLogCategory::Log,
|
|
|
|
"suspended_status_changed",
|
|
|
|
aSuspendedByCache);
|
2017-08-23 09:32:51 +03:00
|
|
|
MediaDecoderOwner* owner = GetMediaOwner();
|
|
|
|
if (owner) {
|
|
|
|
AbstractThread::AutoEnter context(owner->AbstractMainThread());
|
|
|
|
owner->NotifySuspendedByCache(aSuspendedByCache);
|
2017-06-20 13:10:56 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-06 01:40:16 +03:00
|
|
|
void
|
|
|
|
ChannelMediaDecoder::ResourceCallback::NotifyBytesConsumed(int64_t aBytes,
|
|
|
|
int64_t aOffset)
|
|
|
|
{
|
|
|
|
RefPtr<ResourceCallback> self = this;
|
|
|
|
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
|
|
|
|
"ChannelMediaDecoder::ResourceCallback::NotifyBytesConsumed",
|
|
|
|
[=]() {
|
|
|
|
if (self->mDecoder) {
|
|
|
|
self->mDecoder->NotifyBytesConsumed(aBytes, aOffset);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
mAbstractMainThread->Dispatch(r.forget());
|
|
|
|
}
|
|
|
|
|
2017-06-19 10:50:09 +03:00
|
|
|
ChannelMediaDecoder::ChannelMediaDecoder(MediaDecoderInit& aInit)
|
|
|
|
: MediaDecoder(aInit)
|
2017-06-20 13:10:56 +03:00
|
|
|
, mResourceCallback(new ResourceCallback(aInit.mOwner->AbstractMainThread()))
|
2017-12-06 01:40:16 +03:00
|
|
|
, mWatchManager(this, aInit.mOwner->AbstractMainThread())
|
2017-06-20 13:10:56 +03:00
|
|
|
{
|
|
|
|
mResourceCallback->Connect(this);
|
2017-12-06 01:40:16 +03:00
|
|
|
|
|
|
|
// mIgnoreProgressData
|
|
|
|
mWatchManager.Watch(mLogicallySeeking, &ChannelMediaDecoder::SeekingChanged);
|
2017-06-20 13:10:56 +03:00
|
|
|
}
|
|
|
|
|
2017-10-16 23:55:26 +03:00
|
|
|
/* static */
|
|
|
|
already_AddRefed<ChannelMediaDecoder>
|
|
|
|
ChannelMediaDecoder::Create(MediaDecoderInit& aInit,
|
|
|
|
DecoderDoctorDiagnostics* aDiagnostics)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
RefPtr<ChannelMediaDecoder> decoder;
|
|
|
|
|
|
|
|
const MediaContainerType& type = aInit.mContainerType;
|
|
|
|
if (DecoderTraits::IsSupportedType(type)) {
|
|
|
|
decoder = new ChannelMediaDecoder(aInit);
|
|
|
|
return decoder.forget();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (DecoderTraits::IsHttpLiveStreamingType(type)) {
|
|
|
|
// We don't have an HLS decoder.
|
|
|
|
Telemetry::Accumulate(Telemetry::MEDIA_HLS_DECODER_SUCCESS, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2017-08-04 10:29:55 +03:00
|
|
|
bool
|
|
|
|
ChannelMediaDecoder::CanClone()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
return mResource && mResource->CanClone();
|
|
|
|
}
|
|
|
|
|
2017-08-03 12:39:55 +03:00
|
|
|
already_AddRefed<ChannelMediaDecoder>
|
|
|
|
ChannelMediaDecoder::Clone(MediaDecoderInit& aInit)
|
|
|
|
{
|
2017-08-15 08:52:17 +03:00
|
|
|
if (!mResource || !DecoderTraits::IsSupportedType(aInit.mContainerType)) {
|
2017-08-03 12:47:23 +03:00
|
|
|
return nullptr;
|
|
|
|
}
|
2017-08-15 08:52:17 +03:00
|
|
|
RefPtr<ChannelMediaDecoder> decoder = new ChannelMediaDecoder(aInit);
|
2017-08-03 12:47:23 +03:00
|
|
|
if (!decoder) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
nsresult rv = decoder->Load(mResource);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
decoder->Shutdown();
|
|
|
|
return nullptr;
|
|
|
|
}
|
2017-08-03 12:39:55 +03:00
|
|
|
return decoder.forget();
|
|
|
|
}
|
|
|
|
|
2017-08-03 09:05:28 +03:00
|
|
|
MediaDecoderStateMachine* ChannelMediaDecoder::CreateStateMachine()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
MediaFormatReaderInit init;
|
|
|
|
init.mVideoFrameContainer = GetVideoFrameContainer();
|
|
|
|
init.mKnowsCompositor = GetCompositor();
|
|
|
|
init.mCrashHelper = GetOwner()->CreateGMPCrashHelper();
|
|
|
|
init.mFrameStats = mFrameStats;
|
|
|
|
init.mResource = mResource;
|
2017-08-31 12:31:51 +03:00
|
|
|
init.mMediaDecoderOwnerID = mOwner;
|
2017-08-03 09:05:28 +03:00
|
|
|
mReader = DecoderTraits::CreateReader(ContainerType(), init);
|
|
|
|
return new MediaDecoderStateMachine(this, mReader);
|
|
|
|
}
|
|
|
|
|
2017-06-20 13:10:56 +03:00
|
|
|
void
|
|
|
|
ChannelMediaDecoder::Shutdown()
|
2017-06-19 10:50:09 +03:00
|
|
|
{
|
2017-12-06 01:40:16 +03:00
|
|
|
mWatchManager.Shutdown();
|
2017-06-20 13:10:56 +03:00
|
|
|
mResourceCallback->Disconnect();
|
|
|
|
MediaDecoder::Shutdown();
|
2017-08-07 13:09:56 +03:00
|
|
|
|
|
|
|
// Force any outstanding seek and byterange requests to complete
|
|
|
|
// to prevent shutdown from deadlocking.
|
|
|
|
if (mResource) {
|
|
|
|
mResource->Close();
|
|
|
|
}
|
2017-06-19 10:50:09 +03:00
|
|
|
}
|
|
|
|
|
2017-06-23 09:12:41 +03:00
|
|
|
nsresult
|
2017-06-23 10:39:57 +03:00
|
|
|
ChannelMediaDecoder::Load(nsIChannel* aChannel,
|
|
|
|
bool aIsPrivateBrowsing,
|
|
|
|
nsIStreamListener** aStreamListener)
|
2017-06-23 09:12:41 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-06-23 10:39:57 +03:00
|
|
|
MOZ_ASSERT(!mResource);
|
2017-09-05 12:39:57 +03:00
|
|
|
MOZ_ASSERT(aStreamListener);
|
2017-06-23 10:39:57 +03:00
|
|
|
|
|
|
|
mResource =
|
2017-08-04 09:52:22 +03:00
|
|
|
BaseMediaResource::Create(mResourceCallback, aChannel, aIsPrivateBrowsing);
|
2017-06-23 10:39:57 +03:00
|
|
|
if (!mResource) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
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
|
|
|
DDLINKCHILD("resource", mResource.get());
|
2017-06-23 09:12:41 +03:00
|
|
|
|
|
|
|
nsresult rv = MediaShutdownManager::Instance().Register(this);
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2017-09-05 12:39:57 +03:00
|
|
|
rv = mResource->Open(aStreamListener);
|
2017-06-23 09:12:41 +03:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
SetStateMachine(CreateStateMachine());
|
|
|
|
NS_ENSURE_TRUE(GetStateMachine(), NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
return InitializeStateMachine();
|
|
|
|
}
|
|
|
|
|
2017-06-23 10:39:57 +03:00
|
|
|
nsresult
|
2017-08-04 09:52:22 +03:00
|
|
|
ChannelMediaDecoder::Load(BaseMediaResource* aOriginal)
|
2017-06-23 10:39:57 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
MOZ_ASSERT(!mResource);
|
|
|
|
|
|
|
|
mResource = aOriginal->CloneData(mResourceCallback);
|
|
|
|
if (!mResource) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
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
|
|
|
DDLINKCHILD("resource", mResource.get());
|
2017-06-23 10:39:57 +03:00
|
|
|
|
|
|
|
nsresult rv = MediaShutdownManager::Instance().Register(this);
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
SetStateMachine(CreateStateMachine());
|
|
|
|
NS_ENSURE_TRUE(GetStateMachine(), NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
return InitializeStateMachine();
|
|
|
|
}
|
|
|
|
|
2017-08-04 11:02:40 +03:00
|
|
|
void
|
|
|
|
ChannelMediaDecoder::NotifyDownloadEnded(nsresult aStatus)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
|
|
|
|
|
|
|
LOG("NotifyDownloadEnded, status=%" PRIx32, static_cast<uint32_t>(aStatus));
|
|
|
|
|
2017-11-15 06:07:06 +03:00
|
|
|
MediaDecoderOwner* owner = GetOwner();
|
2017-11-15 06:24:22 +03:00
|
|
|
if (NS_SUCCEEDED(aStatus) || aStatus == NS_BASE_STREAM_CLOSED) {
|
2017-12-01 10:05:25 +03:00
|
|
|
UpdatePlaybackRate(ComputePlaybackRate());
|
2017-11-15 06:07:06 +03:00
|
|
|
owner->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.
|
|
|
|
owner->NotifySuspendedByCache(true);
|
2017-11-15 06:24:22 +03:00
|
|
|
} else if (aStatus == NS_BINDING_ABORTED) {
|
|
|
|
// Download has been cancelled by user.
|
|
|
|
owner->LoadAborted();
|
|
|
|
} else {
|
2017-11-17 06:07:30 +03:00
|
|
|
NetworkError(MediaResult(aStatus, "Download aborted"));
|
2017-08-04 11:02:40 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-06 01:40:16 +03:00
|
|
|
void
|
|
|
|
ChannelMediaDecoder::NotifyBytesConsumed(int64_t aBytes, int64_t aOffset)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
|
|
|
|
|
|
|
if (mIgnoreProgressData) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(GetStateMachine());
|
|
|
|
mDecoderPosition = aOffset + aBytes;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ChannelMediaDecoder::SeekingChanged()
|
|
|
|
{
|
|
|
|
// Stop updating the bytes downloaded for progress notifications when
|
|
|
|
// seeking to prevent wild changes to the progress notification.
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
mIgnoreProgressData = mLogicallySeeking;
|
|
|
|
}
|
|
|
|
|
2017-08-07 06:48:43 +03:00
|
|
|
bool
|
|
|
|
ChannelMediaDecoder::CanPlayThroughImpl()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
NS_ENSURE_TRUE(GetStateMachine(), false);
|
2017-12-01 10:05:25 +03:00
|
|
|
return GetStatistics(ComputePlaybackRate()).CanPlayThrough();
|
2017-08-07 06:48:43 +03:00
|
|
|
}
|
|
|
|
|
2017-08-17 10:20:40 +03:00
|
|
|
bool
|
|
|
|
ChannelMediaDecoder::IsLiveStream()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
return mResource->IsLiveStream();
|
|
|
|
}
|
|
|
|
|
2017-08-07 08:23:43 +03:00
|
|
|
void
|
2017-12-01 05:33:44 +03:00
|
|
|
ChannelMediaDecoder::OnPlaybackEvent(MediaPlaybackEvent&& aEvent)
|
2017-08-07 08:23:43 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-12-01 05:33:44 +03:00
|
|
|
switch (aEvent.mType) {
|
|
|
|
case MediaPlaybackEvent::PlaybackStarted:
|
2017-12-01 06:26:03 +03:00
|
|
|
mPlaybackPosition = aEvent.mData.as<int64_t>();
|
2017-08-07 08:23:43 +03:00
|
|
|
mPlaybackStatistics.Start();
|
|
|
|
break;
|
2017-12-01 06:26:03 +03:00
|
|
|
case MediaPlaybackEvent::PlaybackProgressed: {
|
|
|
|
int64_t newPos = aEvent.mData.as<int64_t>();
|
|
|
|
mPlaybackStatistics.AddBytes(newPos - mPlaybackPosition);
|
|
|
|
mPlaybackPosition = newPos;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case MediaPlaybackEvent::PlaybackStopped: {
|
|
|
|
int64_t newPos = aEvent.mData.as<int64_t>();
|
|
|
|
mPlaybackStatistics.AddBytes(newPos - mPlaybackPosition);
|
|
|
|
mPlaybackPosition = newPos;
|
2017-08-07 08:23:43 +03:00
|
|
|
mPlaybackStatistics.Stop();
|
|
|
|
break;
|
2017-12-01 06:26:03 +03:00
|
|
|
}
|
2017-08-07 08:23:43 +03:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2017-12-01 05:33:44 +03:00
|
|
|
MediaDecoder::OnPlaybackEvent(Move(aEvent));
|
2017-08-07 08:23:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ChannelMediaDecoder::DurationChanged()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
|
|
|
MediaDecoder::DurationChanged();
|
|
|
|
// Duration has changed so we should recompute playback rate
|
2017-12-01 10:05:25 +03:00
|
|
|
UpdatePlaybackRate(ComputePlaybackRate());
|
2017-08-07 08:23:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ChannelMediaDecoder::DownloadProgressed()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-11-30 06:21:14 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
2017-08-07 08:23:43 +03:00
|
|
|
AbstractThread::AutoEnter context(AbstractMainThread());
|
2017-11-30 06:21:14 +03:00
|
|
|
GetOwner()->DownloadProgressed();
|
2017-12-01 10:05:25 +03:00
|
|
|
auto rate = ComputePlaybackRate();
|
|
|
|
UpdatePlaybackRate(rate);
|
|
|
|
MediaStatistics stats = GetStatistics(rate);
|
2017-12-01 09:34:58 +03:00
|
|
|
GetStateMachine()->DispatchCanPlayThrough(stats.CanPlayThrough());
|
2017-12-01 09:36:35 +03:00
|
|
|
mResource->ThrottleReadahead(ShouldThrottleDownload(stats));
|
2017-08-07 08:23:43 +03:00
|
|
|
}
|
|
|
|
|
2017-12-01 10:05:25 +03:00
|
|
|
ChannelMediaDecoder::PlaybackRateInfo
|
2017-08-07 08:23:43 +03:00
|
|
|
ChannelMediaDecoder::ComputePlaybackRate()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
MOZ_ASSERT(mResource);
|
|
|
|
|
|
|
|
int64_t length = mResource->GetLength();
|
|
|
|
if (mozilla::IsFinite<double>(mDuration) && mDuration > 0 && length >= 0) {
|
2017-12-01 10:05:25 +03:00
|
|
|
return { uint32_t(length / mDuration), true };
|
2017-08-07 08:23:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
bool reliable = false;
|
2017-12-01 10:05:25 +03:00
|
|
|
uint32_t rate = mPlaybackStatistics.GetRate(&reliable);
|
|
|
|
return { rate, reliable };
|
2017-08-07 08:23:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2017-12-01 10:05:25 +03:00
|
|
|
ChannelMediaDecoder::UpdatePlaybackRate(const PlaybackRateInfo& aInfo)
|
2017-08-07 08:23:43 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
MOZ_ASSERT(mResource);
|
|
|
|
|
2017-12-01 10:05:25 +03:00
|
|
|
uint32_t rate = aInfo.mRate;
|
2017-08-07 08:23:43 +03:00
|
|
|
|
2017-12-01 10:05:25 +03:00
|
|
|
if (aInfo.mReliable) {
|
2017-08-07 08:23:43 +03:00
|
|
|
// Avoid passing a zero rate
|
|
|
|
rate = std::max(rate, 1u);
|
|
|
|
} else {
|
|
|
|
// Set a minimum rate of 10,000 bytes per second ... sometimes we just
|
|
|
|
// don't have good data
|
|
|
|
rate = std::max(rate, 10000u);
|
|
|
|
}
|
|
|
|
|
|
|
|
mResource->SetPlaybackRate(rate);
|
|
|
|
}
|
|
|
|
|
|
|
|
MediaStatistics
|
2017-12-01 10:05:25 +03:00
|
|
|
ChannelMediaDecoder::GetStatistics(const PlaybackRateInfo& aInfo)
|
2017-08-07 08:23:43 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
MOZ_ASSERT(mResource);
|
|
|
|
|
|
|
|
MediaStatistics result;
|
|
|
|
result.mDownloadRate =
|
|
|
|
mResource->GetDownloadRate(&result.mDownloadRateReliable);
|
2017-12-06 01:40:16 +03:00
|
|
|
result.mDownloadPosition = mResource->GetCachedDataEnd(mDecoderPosition);
|
2017-08-07 08:23:43 +03:00
|
|
|
result.mTotalBytes = mResource->GetLength();
|
2017-12-01 10:05:25 +03:00
|
|
|
result.mPlaybackRate = aInfo.mRate;
|
|
|
|
result.mPlaybackRateReliable = aInfo.mReliable;
|
2017-08-07 08:23:43 +03:00
|
|
|
result.mPlaybackPosition = mPlaybackPosition;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2017-12-01 09:36:35 +03:00
|
|
|
ChannelMediaDecoder::ShouldThrottleDownload(const MediaStatistics& aStats)
|
2017-08-07 08:23:43 +03:00
|
|
|
{
|
|
|
|
// We throttle the download if either the throttle override pref is set
|
|
|
|
// (so that we can always throttle in Firefox on mobile) or if the download
|
|
|
|
// is fast enough that there's no concern about playback being interrupted.
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
NS_ENSURE_TRUE(GetStateMachine(), false);
|
|
|
|
|
2017-12-01 09:36:35 +03:00
|
|
|
int64_t length = aStats.mTotalBytes;
|
2017-08-07 08:23:43 +03:00
|
|
|
if (length > 0 &&
|
|
|
|
length <= int64_t(MediaPrefs::MediaMemoryCacheMaxSize()) * 1024) {
|
|
|
|
// Don't throttle the download of small resources. This is to speed
|
|
|
|
// up seeking, as seeks into unbuffered ranges would require starting
|
|
|
|
// up a new HTTP transaction, which adds latency.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Preferences::GetBool("media.throttle-regardless-of-download-rate",
|
|
|
|
false)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-12-01 09:36:35 +03:00
|
|
|
if (!aStats.mDownloadRateReliable || !aStats.mPlaybackRateReliable) {
|
2017-08-07 08:23:43 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
uint32_t factor =
|
|
|
|
std::max(2u, Preferences::GetUint("media.throttle-factor", 2));
|
2017-12-01 09:36:35 +03:00
|
|
|
return aStats.mDownloadRate > factor * aStats.mPlaybackRate;
|
2017-08-07 08:23:43 +03:00
|
|
|
}
|
|
|
|
|
2017-08-24 12:35:24 +03:00
|
|
|
void
|
|
|
|
ChannelMediaDecoder::AddSizeOfResources(ResourceSizes* aSizes)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
if (mResource) {
|
|
|
|
aSizes->mByteSize += mResource->SizeOfIncludingThis(aSizes->mMallocSizeOf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-24 11:58:06 +03:00
|
|
|
already_AddRefed<nsIPrincipal>
|
|
|
|
ChannelMediaDecoder::GetCurrentPrincipal()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
return mResource ? mResource->GetCurrentPrincipal() : nullptr;
|
|
|
|
}
|
|
|
|
|
2017-08-23 19:06:23 +03:00
|
|
|
bool
|
|
|
|
ChannelMediaDecoder::IsTransportSeekable()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
return mResource->IsTransportSeekable();
|
|
|
|
}
|
|
|
|
|
2017-08-07 13:09:56 +03:00
|
|
|
void
|
|
|
|
ChannelMediaDecoder::SetLoadInBackground(bool aLoadInBackground)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
if (mResource) {
|
|
|
|
mResource->SetLoadInBackground(aLoadInBackground);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ChannelMediaDecoder::Suspend()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
if (mResource) {
|
|
|
|
mResource->Suspend(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ChannelMediaDecoder::Resume()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
if (mResource) {
|
|
|
|
mResource->Resume();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-24 13:08:37 +03:00
|
|
|
void
|
|
|
|
ChannelMediaDecoder::PinForSeek()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
if (!mResource || mPinnedForSeek) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mPinnedForSeek = true;
|
|
|
|
mResource->Pin();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ChannelMediaDecoder::UnpinForSeek()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
|
|
|
if (!mResource || !mPinnedForSeek) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mPinnedForSeek = false;
|
|
|
|
mResource->Unpin();
|
|
|
|
}
|
|
|
|
|
2017-08-09 06:06:29 +03:00
|
|
|
void
|
|
|
|
ChannelMediaDecoder::MetadataLoaded(
|
|
|
|
UniquePtr<MediaInfo> aInfo,
|
|
|
|
UniquePtr<MetadataTags> aTags,
|
|
|
|
MediaDecoderEventVisibility aEventVisibility)
|
|
|
|
{
|
|
|
|
MediaDecoder::MetadataLoaded(Move(aInfo), Move(aTags), aEventVisibility);
|
|
|
|
// Set mode to PLAYBACK after reading metadata.
|
|
|
|
mResource->SetReadMode(MediaCacheStream::MODE_PLAYBACK);
|
|
|
|
}
|
|
|
|
|
2017-10-25 08:57:39 +03:00
|
|
|
nsCString
|
|
|
|
ChannelMediaDecoder::GetDebugInfo()
|
|
|
|
{
|
|
|
|
auto&& str = MediaDecoder::GetDebugInfo();
|
|
|
|
if (mResource) {
|
|
|
|
AppendStringIfNotEmpty(str, mResource->GetDebugInfo());
|
|
|
|
}
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2017-06-19 10:50:09 +03:00
|
|
|
} // namespace mozilla
|
2017-08-04 11:02:40 +03:00
|
|
|
|
|
|
|
// avoid redefined macro in unified build
|
|
|
|
#undef LOG
|