Bug 1297265: P3. Rework Apple VT use of InputExhausted. r=cpearce draft
authorJean-Yves Avenard <jyavenard@mozilla.com>
Tue, 30 Aug 2016 15:18:25 +1000
changeset 407291 c922c40881d180b53f009f96b1d863e95a1fb046
parent 407290 ada851f013c3466bf0f6081dcd0c3f5328102a40
child 407292 0eb31c3fae3cd377aed647ba2701f0f40912716e
push id27921
push userbmo:jyavenard@mozilla.com
push dateTue, 30 Aug 2016 07:23:20 +0000
reviewerscpearce
bugs1297265
milestone51.0a1
Bug 1297265: P3. Rework Apple VT use of InputExhausted. r=cpearce The only time we need to use InputExhausted is for the initial video decoding or when a frame is dropped. MozReview-Commit-ID: IrHqZXJwQe1
dom/media/platforms/apple/AppleVTDecoder.cpp
dom/media/platforms/apple/AppleVTDecoder.h
--- a/dom/media/platforms/apple/AppleVTDecoder.cpp
+++ b/dom/media/platforms/apple/AppleVTDecoder.cpp
@@ -29,21 +29,19 @@ AppleVTDecoder::AppleVTDecoder(const Vid
                                MediaDataDecoderCallback* aCallback,
                                layers::ImageContainer* aImageContainer)
   : mExtraData(aConfig.mExtraData)
   , mCallback(aCallback)
   , mPictureWidth(aConfig.mImage.width)
   , mPictureHeight(aConfig.mImage.height)
   , mDisplayWidth(aConfig.mDisplay.width)
   , mDisplayHeight(aConfig.mDisplay.height)
-  , mQueuedSamples(0)
   , mTaskQueue(aTaskQueue)
   , mMaxRefFrames(mp4_demuxer::H264::ComputeMaxRefFrames(aConfig.mExtraData))
   , mImageContainer(aImageContainer)
-  , mInputIncoming(0)
   , mIsShutDown(false)
 #ifdef MOZ_WIDGET_UIKIT
   , mUseSoftwareImages(true)
 #else
   , mUseSoftwareImages(false)
 #endif
   , mIsFlushing(false)
   , mMonitor("AppleVideoDecoder")
@@ -83,34 +81,30 @@ AppleVTDecoder::Input(MediaRawData* aSam
 
   LOG("mp4 input sample %p pts %lld duration %lld us%s %d bytes",
       aSample,
       aSample->mTime,
       aSample->mDuration,
       aSample->mKeyframe ? " keyframe" : "",
       aSample->Size());
 
-  mInputIncoming++;
-
   mTaskQueue->Dispatch(NewRunnableMethod<RefPtr<MediaRawData>>(
     this, &AppleVTDecoder::ProcessDecode, aSample));
   return NS_OK;
 }
 
 nsresult
 AppleVTDecoder::Flush()
 {
   MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   mIsFlushing = true;
   nsCOMPtr<nsIRunnable> runnable =
     NewRunnableMethod(this, &AppleVTDecoder::ProcessFlush);
   SyncRunnable::DispatchToThread(mTaskQueue, runnable);
   mIsFlushing = false;
-  // All ProcessDecode() tasks should be done.
-  MOZ_ASSERT(mInputIncoming == 0);
 
   mSeekTargetThreshold.reset();
 
   return NS_OK;
 }
 
 nsresult
 AppleVTDecoder::Drain()
@@ -137,28 +131,21 @@ AppleVTDecoder::Shutdown()
   return NS_OK;
 }
 
 nsresult
 AppleVTDecoder::ProcessDecode(MediaRawData* aSample)
 {
   AssertOnTaskQueueThread();
 
-  mInputIncoming--;
-
   if (mIsFlushing) {
     return NS_OK;
   }
 
   auto rv = DoDecode(aSample);
-  // Ask for more data.
-  if (NS_SUCCEEDED(rv) && !mInputIncoming && mQueuedSamples <= mMaxRefFrames) {
-    LOG("%s task queue empty; requesting more data", GetDescriptionName());
-    mCallback->InputExhausted();
-  }
 
   return rv;
 }
 
 void
 AppleVTDecoder::ProcessShutdown()
 {
   if (mSession) {
@@ -208,27 +195,25 @@ AppleVTDecoder::CreateAppleFrameRef(cons
 
 void
 AppleVTDecoder::DrainReorderedFrames()
 {
   MonitorAutoLock mon(mMonitor);
   while (!mReorderQueue.IsEmpty()) {
     mCallback->Output(mReorderQueue.Pop().get());
   }
-  mQueuedSamples = 0;
 }
 
 void
 AppleVTDecoder::ClearReorderedFrames()
 {
   MonitorAutoLock mon(mMonitor);
   while (!mReorderQueue.IsEmpty()) {
     mReorderQueue.Pop();
   }
-  mQueuedSamples = 0;
 }
 
 void
 AppleVTDecoder::SetSeekThreshold(const media::TimeUnit& aTime)
 {
   LOG("SetSeekThreshold %lld", aTime.ToMicroseconds());
   mSeekTargetThreshold = Some(aTime);
 }
@@ -283,26 +268,20 @@ AppleVTDecoder::OutputFrame(CVPixelBuffe
   LOG("mp4 output frame %lld dts %lld pts %lld duration %lld us%s",
       aFrameRef.byte_offset,
       aFrameRef.decode_timestamp.ToMicroseconds(),
       aFrameRef.composition_timestamp.ToMicroseconds(),
       aFrameRef.duration.ToMicroseconds(),
       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.
+  if (!aImage) {
+    // Image was dropped by decoder or none return yet.
+    // We need more input to continue.
     mCallback->InputExhausted();
-  }
-  MOZ_ASSERT(mQueuedSamples);
-  mQueuedSamples--;
-
-  if (!aImage) {
-    // Image was dropped by decoder.
     return NS_OK;
   }
 
   bool useNullSample = false;
   if (mSeekTargetThreshold.isSome()) {
     if ((aFrameRef.composition_timestamp + aFrameRef.duration) < mSeekTargetThreshold.ref()) {
       useNullSample = true;
     } else {
@@ -405,18 +384,20 @@ AppleVTDecoder::OutputFrame(CVPixelBuffe
     mCallback->Error(MediaDataDecoderError::FATAL_ERROR);
     return NS_ERROR_FAILURE;
   }
 
   // Frames come out in DTS order but we need to output them
   // in composition order.
   MonitorAutoLock mon(mMonitor);
   mReorderQueue.Push(data);
-  while (mReorderQueue.Length() > mMaxRefFrames) {
+  if (mReorderQueue.Length() > mMaxRefFrames) {
     mCallback->Output(mReorderQueue.Pop().get());
+  } else {
+    mCallback->InputExhausted();
   }
   LOG("%llu decoded frames queued",
       static_cast<unsigned long long>(mReorderQueue.Length()));
 
   return NS_OK;
 }
 
 nsresult
@@ -475,18 +456,16 @@ AppleVTDecoder::DoDecode(MediaRawData* a
   }
   CMSampleTimingInfo timestamp = TimingInfoFromSample(aSample);
   rv = CMSampleBufferCreate(kCFAllocatorDefault, block, true, 0, 0, mFormat, 1, 1, &timestamp, 0, NULL, sample.receive());
   if (rv != noErr) {
     NS_ERROR("Couldn't create CMSampleBuffer");
     return NS_ERROR_FAILURE;
   }
 
-  mQueuedSamples++;
-
   VTDecodeFrameFlags decodeFlags =
     kVTDecodeFrame_EnableAsynchronousDecompression;
   rv = VTDecompressionSessionDecodeFrame(mSession,
                                          sample,
                                          decodeFlags,
                                          CreateAppleFrameRef(aSample),
                                          &infoFlags);
   if (rv != noErr && !(infoFlags & kVTDecodeInfo_FrameDropped)) {
--- a/dom/media/platforms/apple/AppleVTDecoder.h
+++ b/dom/media/platforms/apple/AppleVTDecoder.h
@@ -85,35 +85,27 @@ private:
 
   const RefPtr<MediaByteBuffer> mExtraData;
   MediaDataDecoderCallback* mCallback;
   const uint32_t mPictureWidth;
   const uint32_t mPictureHeight;
   const uint32_t mDisplayWidth;
   const uint32_t mDisplayHeight;
 
-  // 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.
-  Atomic<uint32_t> mQueuedSamples;
-
   // Method to set up the decompression session.
   nsresult InitializeSession();
   nsresult WaitForAsynchronousFrames();
   CFDictionaryRef CreateDecoderSpecification();
   CFDictionaryRef CreateDecoderExtensions();
   // Method to pass a frame to VideoToolbox for decoding.
   nsresult DoDecode(MediaRawData* aSample);
 
   const RefPtr<TaskQueue> mTaskQueue;
   const uint32_t mMaxRefFrames;
   const RefPtr<layers::ImageContainer> mImageContainer;
-  // Increased when Input is called, and decreased when ProcessFrame runs.
-  // Reaching 0 indicates that there's no pending Input.
-  Atomic<uint32_t> mInputIncoming;
   Atomic<bool> mIsShutDown;
   const bool mUseSoftwareImages;
 
   // Set on reader/decode thread calling Flush() to indicate that output is
   // not required and so input samples on mTaskQueue need not be processed.
   // Cleared on mTaskQueue in ProcessDrain().
   Atomic<bool> mIsFlushing;
   // Protects mReorderQueue.