Bug 1131638 - Disable hardware decoding if too many frames are invalid. r=cpearce

This commit is contained in:
Matt Woodrow 2015-03-12 22:14:51 +13:00
parent 6db2c9ff04
commit bfed929c24
11 changed files with 83 additions and 1 deletions

View File

@ -260,6 +260,8 @@ public:
// decoding.
virtual bool VideoIsHardwareAccelerated() const { return false; }
virtual void DisableHardwareAcceleration() {}
protected:
virtual ~MediaDecoderReader();

View File

@ -239,6 +239,8 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
mDecodeToSeekTarget(false),
mCurrentTimeBeforeSeek(0),
mLastFrameStatus(MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED),
mCorruptFrames(30),
mDisabledHardwareAcceleration(false),
mDecodingFrozenAtStateDecoding(false),
mSentLoadedMetadataEvent(false),
mSentFirstFrameLoadedEvent(false)
@ -2891,6 +2893,19 @@ void MediaDecoderStateMachine::RenderVideoFrame(VideoData* aData,
if (aData->mImage && !aData->mImage->IsValid()) {
MediaDecoder::FrameStatistics& frameStats = mDecoder->GetFrameStatistics();
frameStats.NotifyCorruptFrame();
// If more than 10% of the last 30 frames have been corrupted, then try disabling
// hardware acceleration. We use 10 as the corrupt value because RollingMean<>
// only supports integer types.
mCorruptFrames.insert(10);
if (!mDisabledHardwareAcceleration &&
mReader->VideoIsHardwareAccelerated() &&
frameStats.GetPresentedFrames() > 30 &&
mCorruptFrames.mean() >= 1 /* 10% */) {
DecodeTaskQueue()->Dispatch(NS_NewRunnableMethod(mReader, &MediaDecoderReader::DisableHardwareAcceleration));
mDisabledHardwareAcceleration = true;
}
} else {
mCorruptFrames.insert(0);
}
container->SetCurrentFrame(ThebesIntSize(aData->mDisplay), aData->mImage,
aTarget);

View File

@ -90,6 +90,7 @@ hardware (via AudioStream).
#include "MediaDecoderOwner.h"
#include "MediaMetadataManager.h"
#include "MediaDecoderStateMachineScheduler.h"
#include "mozilla/RollingMean.h"
class nsITimer;
@ -1135,6 +1136,10 @@ protected:
MediaDecoderOwner::NextFrameStatus mLastFrameStatus;
mozilla::RollingMean<uint32_t, uint32_t> mCorruptFrames;
bool mDisabledHardwareAcceleration;
// mDecodingFrozenAtStateDecoding: turn on/off at
// SetDormant/Seek,Play.
bool mDecodingFrozenAtStateDecoding;

View File

@ -577,6 +577,26 @@ MP4Reader::GetNextKeyframeTime()
return mVideo.mTrackDemuxer->GetNextKeyframeTime();
}
void
MP4Reader::DisableHardwareAcceleration()
{
if (HasVideo() && !mIsEncrypted && mSharedDecoderManager) {
mPlatform->DisableHardwareAcceleration();
const VideoDecoderConfig& video = mDemuxer->VideoConfig();
if (!mSharedDecoderManager->Recreate(mPlatform, video, mLayersBackendType, mDecoder->GetImageContainer())) {
MonitorAutoLock mon(mVideo.mMonitor);
mVideo.mError = true;
if (mVideo.HasPromise()) {
mVideo.RejectPromise(DECODE_ERROR, __func__);
}
} else {
MonitorAutoLock lock(mVideo.mMonitor);
ScheduleUpdate(kVideo);
}
}
}
bool
MP4Reader::ShouldSkip(bool aSkipToNextKeyframe, int64_t aTimeThreshold)
{
@ -619,7 +639,9 @@ MP4Reader::RequestVideoData(bool aSkipToNextKeyframe,
MonitorAutoLock lock(mVideo.mMonitor);
nsRefPtr<VideoDataPromise> p = mVideo.mPromise.Ensure(__func__);
if (eos) {
if (mVideo.mError) {
mVideo.mPromise.Reject(DECODE_ERROR, __func__);
} else if (eos) {
mVideo.mPromise.Reject(END_OF_STREAM, __func__);
} else {
ScheduleUpdate(kVideo);

View File

@ -96,6 +96,8 @@ public:
virtual bool VideoIsHardwareAccelerated() const MOZ_OVERRIDE;
virtual void DisableHardwareAcceleration() MOZ_OVERRIDE;
private:
bool InitDemuxer();

View File

@ -135,6 +135,8 @@ public:
// Indicates if the video decoder requires AVCC format.
virtual bool DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig);
virtual void DisableHardwareAcceleration() {}
protected:
PlatformDecoderModule() {}
virtual ~PlatformDecoderModule() {}

View File

@ -93,6 +93,22 @@ SharedDecoderManager::CreateVideoDecoder(
return proxy.forget();
}
bool
SharedDecoderManager::Recreate(PlatformDecoderModule* aPDM,
const mp4_demuxer::VideoDecoderConfig& aConfig,
layers::LayersBackend aLayersBackend,
layers::ImageContainer* aImageContainer)
{
mDecoder->Flush();
mDecoder->Shutdown();
mDecoder = aPDM->CreateVideoDecoder(aConfig, aLayersBackend, aImageContainer, mTaskQueue, mCallback);
if (!mDecoder) {
return false;
}
nsresult rv = mDecoder->Init();
return rv == NS_OK;
}
void
SharedDecoderManager::Select(SharedDecoderProxy* aProxy)
{

View File

@ -40,6 +40,11 @@ public:
friend class SharedDecoderProxy;
friend class SharedDecoderCallback;
bool Recreate(PlatformDecoderModule* aPDM,
const mp4_demuxer::VideoDecoderConfig& aConfig,
layers::LayersBackend aLayersBackend,
layers::ImageContainer* aImageContainer);
private:
virtual ~SharedDecoderManager();
void DrainComplete();

View File

@ -37,6 +37,11 @@ public:
bool SupportsVideoMimeType(const char* aMimeType) MOZ_OVERRIDE;
bool SupportsAudioMimeType(const char* aMimeType) MOZ_OVERRIDE;
virtual void DisableHardwareAcceleration() MOZ_OVERRIDE
{
sDXVAEnabled = false;
}
// Accessors that report whether we have the required MFTs available
// on the system to play various codecs. Windows Vista doesn't have the
// H.264/AAC decoders if the "Platform Update Supplement for Windows Vista"

View File

@ -84,6 +84,12 @@ public:
void NotifyTimeRangesChanged();
virtual void DisableHardwareAcceleration() MOZ_OVERRIDE {
if (GetVideoReader()) {
GetVideoReader()->DisableHardwareAcceleration();
}
}
// We can't compute a proper start time since we won't necessarily
// have the first frame of the resource available. This does the same
// as chrome/blink and assumes that we always start at t=0.

View File

@ -48,6 +48,8 @@ public:
virtual TextureClient* GetTextureClient(CompositableClient* aClient) MOZ_OVERRIDE;
virtual uint8_t* GetBuffer() MOZ_OVERRIDE { return nullptr; }
virtual bool IsValid() MOZ_OVERRIDE;
private:
// Blocks the calling thread until the copy operation started in SetData()