mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
f739744839
The basic idea in this patch is to create an MediaDecoderOwner interface which nsHTMLMediaElement would implement, and put everything needed by nsMediaDeocder on that interface. In addition to that, there are a number of other cleanup patches which enables us to eliminate many of the nsHTMLMediaElement.h #includes in the media code.
295 lines
7.4 KiB
C++
295 lines
7.4 KiB
C++
/* -*- 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 "MediaDecoderOwner.h"
|
|
#include "MediaResource.h"
|
|
#include "mozilla/Preferences.h"
|
|
|
|
#include "nsError.h"
|
|
|
|
using namespace mozilla;
|
|
|
|
// Number of milliseconds between progress events as defined by spec
|
|
static const uint32_t PROGRESS_MS = 350;
|
|
|
|
// Number of milliseconds of no data before a stall event is fired as defined by spec
|
|
static const uint32_t STALL_MS = 3000;
|
|
|
|
// Number of estimated seconds worth of data we need to have buffered
|
|
// ahead of the current playback position before we allow the media decoder
|
|
// to report that it can play through the entire media without the decode
|
|
// catching up with the download. Having this margin make the
|
|
// nsMediaDecoder::CanPlayThrough() calculation more stable in the case of
|
|
// fluctuating bitrates.
|
|
static const int64_t CAN_PLAY_THROUGH_MARGIN = 10;
|
|
|
|
nsMediaDecoder::nsMediaDecoder() :
|
|
mOwner(nullptr),
|
|
mFrameBufferLength(0),
|
|
mPinnedForSeek(false),
|
|
mShuttingDown(false)
|
|
{
|
|
MOZ_COUNT_CTOR(nsMediaDecoder);
|
|
MediaMemoryReporter::AddMediaDecoder(this);
|
|
}
|
|
|
|
nsMediaDecoder::~nsMediaDecoder()
|
|
{
|
|
MOZ_COUNT_DTOR(nsMediaDecoder);
|
|
MediaMemoryReporter::RemoveMediaDecoder(this);
|
|
}
|
|
|
|
bool nsMediaDecoder::Init(MediaDecoderOwner* aOwner)
|
|
{
|
|
mOwner = aOwner;
|
|
mVideoFrameContainer = aOwner->GetVideoFrameContainer();
|
|
return true;
|
|
}
|
|
|
|
void nsMediaDecoder::Shutdown()
|
|
{
|
|
StopProgress();
|
|
mOwner = nullptr;
|
|
}
|
|
|
|
MediaDecoderOwner* nsMediaDecoder::GetMediaOwner() const
|
|
{
|
|
return mOwner;
|
|
}
|
|
|
|
nsresult nsMediaDecoder::RequestFrameBufferLength(uint32_t aLength)
|
|
{
|
|
if (aLength < FRAMEBUFFER_LENGTH_MIN || aLength > FRAMEBUFFER_LENGTH_MAX) {
|
|
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
|
}
|
|
|
|
mFrameBufferLength = aLength;
|
|
return NS_OK;
|
|
}
|
|
|
|
static void ProgressCallback(nsITimer* aTimer, void* aClosure)
|
|
{
|
|
nsMediaDecoder* decoder = static_cast<nsMediaDecoder*>(aClosure);
|
|
decoder->Progress(true);
|
|
}
|
|
|
|
void nsMediaDecoder::Progress(bool aTimer)
|
|
{
|
|
if (!mOwner)
|
|
return;
|
|
|
|
TimeStamp now = TimeStamp::Now();
|
|
|
|
if (!aTimer) {
|
|
mDataTime = now;
|
|
}
|
|
|
|
// If PROGRESS_MS has passed since the last progress event fired and more
|
|
// data has arrived since then, fire another progress event.
|
|
if ((mProgressTime.IsNull() ||
|
|
now - mProgressTime >= TimeDuration::FromMilliseconds(PROGRESS_MS)) &&
|
|
!mDataTime.IsNull() &&
|
|
now - mDataTime <= TimeDuration::FromMilliseconds(PROGRESS_MS)) {
|
|
mOwner->DispatchAsyncEvent(NS_LITERAL_STRING("progress"));
|
|
mProgressTime = now;
|
|
}
|
|
|
|
if (!mDataTime.IsNull() &&
|
|
now - mDataTime >= TimeDuration::FromMilliseconds(STALL_MS)) {
|
|
mOwner->DownloadStalled();
|
|
// Null it out
|
|
mDataTime = TimeStamp();
|
|
}
|
|
}
|
|
|
|
nsresult nsMediaDecoder::StartProgress()
|
|
{
|
|
if (mProgressTimer)
|
|
return NS_OK;
|
|
|
|
mProgressTimer = do_CreateInstance("@mozilla.org/timer;1");
|
|
return mProgressTimer->InitWithFuncCallback(ProgressCallback,
|
|
this,
|
|
PROGRESS_MS,
|
|
nsITimer::TYPE_REPEATING_SLACK);
|
|
}
|
|
|
|
nsresult nsMediaDecoder::StopProgress()
|
|
{
|
|
if (!mProgressTimer)
|
|
return NS_OK;
|
|
|
|
nsresult rv = mProgressTimer->Cancel();
|
|
mProgressTimer = nullptr;
|
|
|
|
return rv;
|
|
}
|
|
|
|
void nsMediaDecoder::FireTimeUpdate()
|
|
{
|
|
if (!mOwner)
|
|
return;
|
|
mOwner->FireTimeUpdate(true);
|
|
}
|
|
|
|
void nsMediaDecoder::PinForSeek()
|
|
{
|
|
MediaResource* resource = GetResource();
|
|
if (!resource || mPinnedForSeek) {
|
|
return;
|
|
}
|
|
mPinnedForSeek = true;
|
|
resource->Pin();
|
|
}
|
|
|
|
void nsMediaDecoder::UnpinForSeek()
|
|
{
|
|
MediaResource* resource = GetResource();
|
|
if (!resource || !mPinnedForSeek) {
|
|
return;
|
|
}
|
|
mPinnedForSeek = false;
|
|
resource->Unpin();
|
|
}
|
|
|
|
bool nsMediaDecoder::CanPlayThrough()
|
|
{
|
|
Statistics stats = GetStatistics();
|
|
if (!stats.mDownloadRateReliable || !stats.mPlaybackRateReliable) {
|
|
return false;
|
|
}
|
|
int64_t bytesToDownload = stats.mTotalBytes - stats.mDownloadPosition;
|
|
int64_t bytesToPlayback = stats.mTotalBytes - stats.mPlaybackPosition;
|
|
double timeToDownload = bytesToDownload / stats.mDownloadRate;
|
|
double timeToPlay = bytesToPlayback / stats.mPlaybackRate;
|
|
|
|
if (timeToDownload > timeToPlay) {
|
|
// Estimated time to download is greater than the estimated time to play.
|
|
// We probably can't play through without having to stop to buffer.
|
|
return false;
|
|
}
|
|
|
|
// Estimated time to download is less than the estimated time to play.
|
|
// We can probably play through without having to buffer, but ensure that
|
|
// we've got a reasonable amount of data buffered after the current
|
|
// playback position, so that if the bitrate of the media fluctuates, or if
|
|
// our download rate or decode rate estimation is otherwise inaccurate,
|
|
// we don't suddenly discover that we need to buffer. This is particularly
|
|
// required near the start of the media, when not much data is downloaded.
|
|
int64_t readAheadMargin =
|
|
static_cast<int64_t>(stats.mPlaybackRate * CAN_PLAY_THROUGH_MARGIN);
|
|
return stats.mTotalBytes == stats.mDownloadPosition ||
|
|
stats.mDownloadPosition > stats.mPlaybackPosition + readAheadMargin;
|
|
}
|
|
|
|
#ifdef MOZ_RAW
|
|
bool
|
|
nsMediaDecoder::IsRawEnabled()
|
|
{
|
|
return Preferences::GetBool("media.raw.enabled");
|
|
}
|
|
#endif
|
|
|
|
#ifdef MOZ_OGG
|
|
bool
|
|
nsMediaDecoder::IsOpusEnabled()
|
|
{
|
|
#ifdef MOZ_OPUS
|
|
return Preferences::GetBool("media.opus.enabled");
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
bool
|
|
nsMediaDecoder::IsOggEnabled()
|
|
{
|
|
return Preferences::GetBool("media.ogg.enabled");
|
|
}
|
|
#endif
|
|
|
|
#ifdef MOZ_WAVE
|
|
bool
|
|
nsMediaDecoder::IsWaveEnabled()
|
|
{
|
|
return Preferences::GetBool("media.wave.enabled");
|
|
}
|
|
#endif
|
|
|
|
#ifdef MOZ_WEBM
|
|
bool
|
|
nsMediaDecoder::IsWebMEnabled()
|
|
{
|
|
return Preferences::GetBool("media.webm.enabled");
|
|
}
|
|
#endif
|
|
|
|
#ifdef MOZ_GSTREAMER
|
|
bool
|
|
nsMediaDecoder::IsGStreamerEnabled()
|
|
{
|
|
return Preferences::GetBool("media.gstreamer.enabled");
|
|
}
|
|
#endif
|
|
|
|
#ifdef MOZ_WIDGET_GONK
|
|
bool
|
|
nsMediaDecoder::IsOmxEnabled()
|
|
{
|
|
return Preferences::GetBool("media.omx.enabled", false);
|
|
}
|
|
#endif
|
|
|
|
#ifdef MOZ_MEDIA_PLUGINS
|
|
bool
|
|
nsMediaDecoder::IsMediaPluginsEnabled()
|
|
{
|
|
return Preferences::GetBool("media.plugins.enabled");
|
|
}
|
|
#endif
|
|
|
|
#ifdef MOZ_DASH
|
|
bool
|
|
nsMediaDecoder::IsDASHEnabled()
|
|
{
|
|
return Preferences::GetBool("media.dash.enabled");
|
|
}
|
|
#endif
|
|
|
|
namespace mozilla {
|
|
|
|
MediaMemoryReporter* MediaMemoryReporter::sUniqueInstance;
|
|
|
|
NS_MEMORY_REPORTER_IMPLEMENT(MediaDecodedVideoMemory,
|
|
"explicit/media/decoded-video",
|
|
KIND_HEAP,
|
|
UNITS_BYTES,
|
|
MediaMemoryReporter::GetDecodedVideoMemory,
|
|
"Memory used by decoded video frames.")
|
|
|
|
NS_MEMORY_REPORTER_IMPLEMENT(MediaDecodedAudioMemory,
|
|
"explicit/media/decoded-audio",
|
|
KIND_HEAP,
|
|
UNITS_BYTES,
|
|
MediaMemoryReporter::GetDecodedAudioMemory,
|
|
"Memory used by decoded audio chunks.")
|
|
|
|
MediaMemoryReporter::MediaMemoryReporter()
|
|
: mMediaDecodedVideoMemory(new NS_MEMORY_REPORTER_NAME(MediaDecodedVideoMemory))
|
|
, mMediaDecodedAudioMemory(new NS_MEMORY_REPORTER_NAME(MediaDecodedAudioMemory))
|
|
{
|
|
NS_RegisterMemoryReporter(mMediaDecodedVideoMemory);
|
|
NS_RegisterMemoryReporter(mMediaDecodedAudioMemory);
|
|
}
|
|
|
|
MediaMemoryReporter::~MediaMemoryReporter()
|
|
{
|
|
NS_UnregisterMemoryReporter(mMediaDecodedVideoMemory);
|
|
NS_UnregisterMemoryReporter(mMediaDecodedAudioMemory);
|
|
}
|
|
|
|
} // namespace mozilla
|