From 9628c1371f2e003a7f22df0216892b8c515bb5e5 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Tue, 25 Aug 2015 15:33:23 +1000 Subject: [PATCH] Bug 1198094: P1. Limit rate at which InputExhausted could be called by mac decoder. r=rillian --- dom/media/platforms/apple/AppleVDADecoder.cpp | 34 ++++++++++++++----- dom/media/platforms/apple/AppleVDADecoder.h | 5 +++ dom/media/platforms/apple/AppleVTDecoder.cpp | 15 ++++---- 3 files changed, 38 insertions(+), 16 deletions(-) diff --git a/dom/media/platforms/apple/AppleVDADecoder.cpp b/dom/media/platforms/apple/AppleVDADecoder.cpp index c75105061f0c..a1ac4590913a 100644 --- a/dom/media/platforms/apple/AppleVDADecoder.cpp +++ b/dom/media/platforms/apple/AppleVDADecoder.cpp @@ -44,6 +44,7 @@ AppleVDADecoder::AppleVDADecoder(const VideoInfo& aConfig, , mIsShutDown(false) , mUseSoftwareImages(false) , mIs106(!nsCocoaFeatures::OnLionOrLater()) + , mQueuedSamples(0) , mMonitor("AppleVideoDecoder") , mIsFlushing(false) , mDecoder(nullptr) @@ -213,15 +214,13 @@ PlatformCallback(void* decompressionOutputRefCon, // FIXME: Distinguish between errors and empty flushed frames. if (status != noErr || !image) { NS_WARNING("AppleVDADecoder decoder returned no data"); - return; - } - MOZ_ASSERT(CFGetTypeID(image) == CVPixelBufferGetTypeID(), - "AppleVDADecoder returned an unexpected image type"); - - if (infoFlags & kVDADecodeInfo_FrameDropped) - { + image = nullptr; + } else if (infoFlags & kVDADecodeInfo_FrameDropped) { NS_WARNING(" ...frame dropped..."); - return; + image = nullptr; + } else { + MOZ_ASSERT(image || CFGetTypeID(image) == CVPixelBufferGetTypeID(), + "AppleVDADecoder returned an unexpected image type"); } AppleVDADecoder* decoder = @@ -278,6 +277,7 @@ AppleVDADecoder::DrainReorderedFrames() while (!mReorderQueue.IsEmpty()) { mCallback->Output(mReorderQueue.Pop().get()); } + mQueuedSamples = 0; } void @@ -286,6 +286,7 @@ AppleVDADecoder::ClearReorderedFrames() while (!mReorderQueue.IsEmpty()) { mReorderQueue.Pop(); } + mQueuedSamples = 0; } // Copy and return a decoded frame. @@ -308,6 +309,19 @@ AppleVDADecoder::OutputFrame(CFRefPtr aImage, aFrameRef.is_sync_point ? " keyframe" : "" ); + if (mQueuedSamples > mMaxRefFrames) { + // We had stopped requesting more input because we had received too much at + // the time. We can ask for more once again. + mCallback->InputExhausted(); + } + MOZ_ASSERT(mQueuedSamples); + mQueuedSamples--; + + if (!aImage) { + // Image was dropped by decoder. + return NS_OK; + } + // Where our resulting image will end up. nsRefPtr data; // Bounds. @@ -471,6 +485,8 @@ AppleVDADecoder::SubmitFrame(MediaRawData* aSample) &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + mQueuedSamples++; + OSStatus rv = VDADecoderDecode(mDecoder, 0, block, @@ -494,7 +510,7 @@ AppleVDADecoder::SubmitFrame(MediaRawData* aSample) } // Ask for more data. - if (!mInputIncoming) { + if (!mInputIncoming && mQueuedSamples <= mMaxRefFrames) { LOG("AppleVDADecoder task queue empty; requesting more data"); mCallback->InputExhausted(); } diff --git a/dom/media/platforms/apple/AppleVDADecoder.h b/dom/media/platforms/apple/AppleVDADecoder.h index 441f34c1caad..09f845f5f67e 100644 --- a/dom/media/platforms/apple/AppleVDADecoder.h +++ b/dom/media/platforms/apple/AppleVDADecoder.h @@ -122,6 +122,11 @@ protected: bool mUseSoftwareImages; bool mIs106; + // Number of times a sample was queued via Input(). Will be decreased upon + // the decoder's callback being invoked. + // This is used to calculate how many frames has been buffered by the decoder. + uint32_t mQueuedSamples; + // For wait on mIsFlushing during Shutdown() process. Monitor mMonitor; // Set on reader/decode thread calling Flush() to indicate that output is diff --git a/dom/media/platforms/apple/AppleVTDecoder.cpp b/dom/media/platforms/apple/AppleVTDecoder.cpp index a33476abf807..84e37dc3f162 100644 --- a/dom/media/platforms/apple/AppleVTDecoder.cpp +++ b/dom/media/platforms/apple/AppleVTDecoder.cpp @@ -167,14 +167,13 @@ PlatformCallback(void* decompressionOutputRefCon, // Validate our arguments. if (status != noErr || !image) { NS_WARNING("VideoToolbox decoder returned no data"); - return; - } - if (flags & kVTDecodeInfo_FrameDropped) { + image = nullptr; + } else if (flags & kVTDecodeInfo_FrameDropped) { NS_WARNING(" ...frame tagged as dropped..."); + } else { + MOZ_ASSERT(CFGetTypeID(image) == CVPixelBufferGetTypeID(), + "VideoToolbox returned an unexpected image type"); } - MOZ_ASSERT(CFGetTypeID(image) == CVPixelBufferGetTypeID(), - "VideoToolbox returned an unexpected image type"); - nsCOMPtr task = NS_NewRunnableMethodWithArgs, AppleVTDecoder::AppleFrameRef>( decoder, &AppleVTDecoder::OutputFrame, image, *frameRef); @@ -242,6 +241,8 @@ AppleVTDecoder::SubmitFrame(MediaRawData* aSample) return NS_ERROR_FAILURE; } + mQueuedSamples++; + VTDecodeFrameFlags decodeFlags = kVTDecodeFrame_EnableAsynchronousDecompression; rv = VTDecompressionSessionDecodeFrame(mSession, @@ -257,7 +258,7 @@ AppleVTDecoder::SubmitFrame(MediaRawData* aSample) } // Ask for more data. - if (!mInputIncoming) { + if (!mInputIncoming && mQueuedSamples <= mMaxRefFrames) { LOG("AppleVTDecoder task queue empty; requesting more data"); mCallback->InputExhausted(); }