200 lines
7.6 KiB
C++
200 lines
7.6 KiB
C++
/* 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 "MediaDecoderStateMachineBase.h"
|
|
|
|
#include "MediaDecoder.h"
|
|
#include "mozilla/ProfilerMarkers.h"
|
|
#include "mozilla/TaskQueue.h"
|
|
#include "nsThreadUtils.h"
|
|
|
|
namespace mozilla {
|
|
|
|
#define INIT_MIRROR(name, val) \
|
|
name(mTaskQueue, val, "MediaDecoderStateMachineBase::" #name " (Mirror)")
|
|
#define INIT_CANONICAL(name, val) \
|
|
name(mTaskQueue, val, "MediaDecoderStateMachineBase::" #name " (Canonical)")
|
|
#define FMT(x, ...) "Decoder=%p " x, mDecoderID, ##__VA_ARGS__
|
|
#define LOG(x, ...) \
|
|
DDMOZ_LOG(gMediaDecoderLog, LogLevel::Debug, "Decoder=%p " x, mDecoderID, \
|
|
##__VA_ARGS__)
|
|
#define LOGV(x, ...) \
|
|
DDMOZ_LOG(gMediaDecoderLog, LogLevel::Verbose, "Decoder=%p " x, mDecoderID, \
|
|
##__VA_ARGS__)
|
|
#define LOGW(x, ...) NS_WARNING(nsPrintfCString(FMT(x, ##__VA_ARGS__)).get())
|
|
#define LOGE(x, ...) \
|
|
NS_DebugBreak(NS_DEBUG_WARNING, \
|
|
nsPrintfCString(FMT(x, ##__VA_ARGS__)).get(), nullptr, \
|
|
__FILE__, __LINE__)
|
|
|
|
MediaDecoderStateMachineBase::MediaDecoderStateMachineBase(
|
|
MediaDecoder* aDecoder, MediaFormatReader* aReader)
|
|
: mDecoderID(aDecoder),
|
|
mAbstractMainThread(aDecoder->AbstractMainThread()),
|
|
mFrameStats(&aDecoder->GetFrameStatistics()),
|
|
mVideoFrameContainer(aDecoder->GetVideoFrameContainer()),
|
|
mTaskQueue(TaskQueue::Create(GetMediaThreadPool(MediaThreadType::MDSM),
|
|
"MDSM::mTaskQueue",
|
|
/* aSupportsTailDispatch = */ true)),
|
|
mReader(new ReaderProxy(mTaskQueue, aReader)),
|
|
mPlaybackRate(1.0),
|
|
INIT_MIRROR(mBuffered, media::TimeIntervals()),
|
|
INIT_MIRROR(mPlayState, MediaDecoder::PLAY_STATE_LOADING),
|
|
INIT_MIRROR(mVolume, 1.0),
|
|
INIT_MIRROR(mPreservesPitch, true),
|
|
INIT_MIRROR(mLooping, false),
|
|
INIT_MIRROR(mSecondaryVideoContainer, nullptr),
|
|
INIT_CANONICAL(mDuration, media::NullableTimeUnit()),
|
|
INIT_CANONICAL(mCurrentPosition, media::TimeUnit::Zero()),
|
|
INIT_CANONICAL(mIsAudioDataAudible, false),
|
|
mMinimizePreroll(aDecoder->GetMinimizePreroll()),
|
|
mIsLiveStream(false),
|
|
mWatchManager(this, mTaskQueue) {}
|
|
|
|
MediaEventSource<void>& MediaDecoderStateMachineBase::OnMediaNotSeekable()
|
|
const {
|
|
return mReader->OnMediaNotSeekable();
|
|
}
|
|
|
|
AbstractCanonical<media::TimeIntervals>*
|
|
MediaDecoderStateMachineBase::CanonicalBuffered() const {
|
|
return mReader->CanonicalBuffered();
|
|
}
|
|
|
|
void MediaDecoderStateMachineBase::DispatchSetFragmentEndTime(
|
|
const media::TimeUnit& aEndTime) {
|
|
OwnerThread()->DispatchStateChange(NewRunnableMethod<media::TimeUnit>(
|
|
"MediaDecoderStateMachineBase::SetFragmentEndTime", this,
|
|
&MediaDecoderStateMachineBase::SetFragmentEndTime, aEndTime));
|
|
}
|
|
|
|
void MediaDecoderStateMachineBase::DispatchCanPlayThrough(
|
|
bool aCanPlayThrough) {
|
|
OwnerThread()->DispatchStateChange(NewRunnableMethod<bool>(
|
|
"MediaDecoderStateMachineBase::SetCanPlayThrough", this,
|
|
&MediaDecoderStateMachineBase::SetCanPlayThrough, aCanPlayThrough));
|
|
}
|
|
|
|
void MediaDecoderStateMachineBase::DispatchIsLiveStream(bool aIsLiveStream) {
|
|
OwnerThread()->DispatchStateChange(NewRunnableMethod<bool>(
|
|
"MediaDecoderStateMachineBase::SetIsLiveStream", this,
|
|
&MediaDecoderStateMachineBase::SetIsLiveStream, aIsLiveStream));
|
|
}
|
|
|
|
void MediaDecoderStateMachineBase::DispatchSetPlaybackRate(
|
|
double aPlaybackRate) {
|
|
OwnerThread()->DispatchStateChange(NewRunnableMethod<double>(
|
|
"MediaDecoderStateMachineBase::SetPlaybackRate", this,
|
|
&MediaDecoderStateMachineBase::SetPlaybackRate, aPlaybackRate));
|
|
}
|
|
|
|
nsresult MediaDecoderStateMachineBase::Init(MediaDecoder* aDecoder) {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
// Dispatch initialization that needs to happen on that task queue.
|
|
nsCOMPtr<nsIRunnable> r = NewRunnableMethod<RefPtr<MediaDecoder>>(
|
|
"MediaDecoderStateMachineBase::InitializationTask", this,
|
|
&MediaDecoderStateMachineBase::InitializationTask, aDecoder);
|
|
mTaskQueue->DispatchStateChange(r.forget());
|
|
|
|
// Connect mirrors.
|
|
aDecoder->CanonicalPlayState().ConnectMirror(&mPlayState);
|
|
aDecoder->CanonicalVolume().ConnectMirror(&mVolume);
|
|
aDecoder->CanonicalPreservesPitch().ConnectMirror(&mPreservesPitch);
|
|
aDecoder->CanonicalLooping().ConnectMirror(&mLooping);
|
|
aDecoder->CanonicalSecondaryVideoContainer().ConnectMirror(
|
|
&mSecondaryVideoContainer);
|
|
|
|
nsresult rv = mReader->Init();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
mMetadataManager.Connect(mReader->TimedMetadataEvent(), OwnerThread());
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
void MediaDecoderStateMachineBase::InitializationTask(MediaDecoder* aDecoder) {
|
|
MOZ_ASSERT(OnTaskQueue());
|
|
|
|
// Connect mirrors.
|
|
mBuffered.Connect(mReader->CanonicalBuffered());
|
|
mReader->SetCanonicalDuration(mDuration);
|
|
|
|
// Initialize watchers.
|
|
mWatchManager.Watch(mBuffered,
|
|
&MediaDecoderStateMachineBase::BufferedRangeUpdated);
|
|
mWatchManager.Watch(mVolume, &MediaDecoderStateMachineBase::VolumeChanged);
|
|
mWatchManager.Watch(mPreservesPitch,
|
|
&MediaDecoderStateMachineBase::PreservesPitchChanged);
|
|
mWatchManager.Watch(mPlayState,
|
|
&MediaDecoderStateMachineBase::PlayStateChanged);
|
|
mWatchManager.Watch(mLooping, &MediaDecoderStateMachineBase::LoopingChanged);
|
|
mWatchManager.Watch(
|
|
mSecondaryVideoContainer,
|
|
&MediaDecoderStateMachineBase::UpdateSecondaryVideoContainer);
|
|
}
|
|
|
|
RefPtr<ShutdownPromise> MediaDecoderStateMachineBase::BeginShutdown() {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
return InvokeAsync(
|
|
OwnerThread(), __func__,
|
|
[self = RefPtr<MediaDecoderStateMachineBase>(this), this]() {
|
|
mWatchManager.Shutdown();
|
|
mBuffered.DisconnectIfConnected();
|
|
mPlayState.DisconnectIfConnected();
|
|
mVolume.DisconnectIfConnected();
|
|
mPreservesPitch.DisconnectIfConnected();
|
|
mLooping.DisconnectIfConnected();
|
|
mSecondaryVideoContainer.DisconnectIfConnected();
|
|
return Shutdown();
|
|
});
|
|
}
|
|
|
|
RefPtr<MediaDecoder::SeekPromise> MediaDecoderStateMachineBase::InvokeSeek(
|
|
const SeekTarget& aTarget) {
|
|
return InvokeAsync(OwnerThread(), __func__,
|
|
[self = RefPtr<MediaDecoderStateMachineBase>(this),
|
|
target = aTarget]() { return self->Seek(target); });
|
|
}
|
|
|
|
bool MediaDecoderStateMachineBase::OnTaskQueue() const {
|
|
return OwnerThread()->IsCurrentThreadIn();
|
|
}
|
|
|
|
void MediaDecoderStateMachineBase::DecodeError(const MediaResult& aError) {
|
|
MOZ_ASSERT(OnTaskQueue());
|
|
if (aError != NS_ERROR_DOM_MEDIA_EXTERNAL_ENGINE_NOT_SUPPORTED_ERR) {
|
|
LOGE("Decode error: %s", aError.Description().get());
|
|
}
|
|
PROFILER_MARKER_TEXT("MDSMBase::DecodeError", MEDIA_PLAYBACK, {},
|
|
aError.Description());
|
|
// Notify the decode error and MediaDecoder will shut down MDSM.
|
|
mOnPlaybackErrorEvent.Notify(aError);
|
|
#ifdef DEBUG
|
|
mHasNotifiedPlaybackError = true;
|
|
#endif
|
|
}
|
|
|
|
RefPtr<SetCDMPromise> MediaDecoderStateMachineBase::SetCDMProxy(
|
|
CDMProxy* aProxy) {
|
|
return mReader->SetCDMProxy(aProxy);
|
|
}
|
|
|
|
void MediaDecoderStateMachineBase::SetIsLiveStream(bool aIsLiveStream) {
|
|
mIsLiveStream = aIsLiveStream;
|
|
}
|
|
|
|
bool MediaDecoderStateMachineBase::IsLiveStream() const {
|
|
return mIsLiveStream;
|
|
}
|
|
|
|
#undef INIT_MIRROR
|
|
#undef INIT_CANONICAL
|
|
#undef FMT
|
|
#undef LOG
|
|
#undef LOGV
|
|
#undef LOGW
|
|
#undef LOGE
|
|
|
|
} // namespace mozilla
|