Bug 1448863: Stop sync dispatching in Decode. r?jesup draft
authorByron Campen [:bwc] <docfaraday@gmail.com>
Mon, 26 Mar 2018 10:19:31 -0500
changeset 778046 ab9bb493baeb68023db76f51e39dbacd1b5762b1
parent 770611 7b55d395bb63165c20a9230f82b3b14da09bcd2d
push id105377
push userbcampen@mozilla.com
push dateThu, 05 Apr 2018 19:18:40 +0000
reviewersjesup
bugs1448863
milestone61.0a1
Bug 1448863: Stop sync dispatching in Decode. r?jesup MozReview-Commit-ID: 3EK0zAsFpHz
media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp
media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h
media/webrtc/webrtc.mozbuild
--- a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp
+++ b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp
@@ -765,24 +765,18 @@ WebrtcGmpVideoDecoder::GmpInitDone(GMPVi
   }
 
   // now release any frames that got queued waiting for InitDone
   if (!mQueuedFrames.IsEmpty()) {
     // So we're safe to call Decode_g(), which asserts it's empty
     nsTArray<UniquePtr<GMPDecodeData>> temp;
     temp.SwapElements(mQueuedFrames);
     for (auto& queued : temp) {
-      int rv = Decode_g(queued->mImage,
-                        queued->mMissingFrames,
-                        nullptr,
-                        nullptr,
-                        queued->mRenderTimeMs);
-      if (rv) {
-        return rv;
-      }
+      Decode_g(RefPtr<WebrtcGmpVideoDecoder>(this),
+               nsAutoPtr<GMPDecodeData>(queued.release()));
     }
   }
 
   return WEBRTC_VIDEO_CODEC_OK;
 }
 
 void
 WebrtcGmpVideoDecoder::Close_g()
@@ -800,114 +794,116 @@ WebrtcGmpVideoDecoder::Close_g()
 
 int32_t
 WebrtcGmpVideoDecoder::Decode(const webrtc::EncodedImage& aInputImage,
                               bool aMissingFrames,
                               const webrtc::RTPFragmentationHeader* aFragmentation,
                               const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
                               int64_t aRenderTimeMs)
 {
-  int32_t ret;
   MOZ_ASSERT(mGMPThread);
   MOZ_ASSERT(!NS_IsMainThread());
-  // Would be really nice to avoid this sync dispatch, but it would require a
-  // copy of the frame, since it doesn't appear to actually have a refcount.
-  // Passing 'this' is safe since this is synchronous.
-  mozilla::SyncRunnable::DispatchToThread(mGMPThread,
-                WrapRunnableRet(&ret, this,
-                                &WebrtcGmpVideoDecoder::Decode_g,
-                                aInputImage,
-                                aMissingFrames,
-                                aFragmentation,
-                                aCodecSpecificInfo,
-                                aRenderTimeMs));
-
-  return ret;
-}
-
-int32_t
-WebrtcGmpVideoDecoder::Decode_g(const webrtc::EncodedImage& aInputImage,
-                                bool aMissingFrames,
-                                const webrtc::RTPFragmentationHeader* aFragmentation,
-                                const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
-                                int64_t aRenderTimeMs)
-{
-  if (!mGMP) {
-    if (mInitting) {
-      // InitDone hasn't been called yet (race)
-      GMPDecodeData *data = new GMPDecodeData(aInputImage,
-                                              aMissingFrames,
-                                              aRenderTimeMs);
-      mQueuedFrames.AppendElement(data);
-      return WEBRTC_VIDEO_CODEC_OK;
-    }
-    // destroyed via Terminate(), failed to init, or just not initted yet
-    LOGD(("GMP Decode: not initted yet"));
-    return WEBRTC_VIDEO_CODEC_ERROR;
-  }
-  MOZ_ASSERT(mQueuedFrames.IsEmpty());
-  MOZ_ASSERT(mHost);
-
   if (!aInputImage._length) {
     return WEBRTC_VIDEO_CODEC_ERROR;
   }
 
+  nsAutoPtr<GMPDecodeData> decodeData(new GMPDecodeData(aInputImage,
+                                                        aMissingFrames,
+                                                        aRenderTimeMs));
+
+  mGMPThread->Dispatch(WrapRunnableNM(&WebrtcGmpVideoDecoder::Decode_g,
+                                      RefPtr<WebrtcGmpVideoDecoder>(this),
+                                      decodeData),
+                       NS_DISPATCH_NORMAL);
+
+  return WEBRTC_VIDEO_CODEC_OK;
+}
+
+/* static */
+// Using nsAutoPtr because WrapRunnable doesn't support move semantics
+void
+WebrtcGmpVideoDecoder::Decode_g(const RefPtr<WebrtcGmpVideoDecoder>& aThis,
+                                nsAutoPtr<GMPDecodeData> aDecodeData)
+{
+  if (!aThis->mGMP) {
+    if (aThis->mInitting) {
+      // InitDone hasn't been called yet (race)
+      aThis->mQueuedFrames.AppendElement(aDecodeData.forget());
+      return;
+    }
+    // destroyed via Terminate(), failed to init, or just not initted yet
+    LOGD(("GMP Decode: not initted yet"));
+    return;
+  }
+
+  MOZ_ASSERT(aThis->mQueuedFrames.IsEmpty());
+  MOZ_ASSERT(aThis->mHost);
+
   GMPVideoFrame* ftmp = nullptr;
-  GMPErr err = mHost->CreateFrame(kGMPEncodedVideoFrame, &ftmp);
+  GMPErr err = aThis->mHost->CreateFrame(kGMPEncodedVideoFrame, &ftmp);
   if (err != GMPNoErr) {
-    return WEBRTC_VIDEO_CODEC_ERROR;
+    LOG(LogLevel::Error, ("%s: CreateFrame failed (%u)!",
+        __PRETTY_FUNCTION__, static_cast<unsigned>(err)));
+    return;
   }
 
   GMPUniquePtr<GMPVideoEncodedFrame> frame(static_cast<GMPVideoEncodedFrame*>(ftmp));
-  err = frame->CreateEmptyFrame(aInputImage._length);
+  err = frame->CreateEmptyFrame(aDecodeData->mImage._length);
   if (err != GMPNoErr) {
-    return WEBRTC_VIDEO_CODEC_ERROR;
+    LOG(LogLevel::Error, ("%s: CreateEmptyFrame failed (%u)!",
+        __PRETTY_FUNCTION__, static_cast<unsigned>(err)));
+    return;
   }
 
   // XXX At this point, we only will get mode1 data (a single length and a buffer)
   // Session_info.cc/etc code needs to change to support mode 0.
   *(reinterpret_cast<uint32_t*>(frame->Buffer())) = frame->Size();
 
   // XXX It'd be wonderful not to have to memcpy the encoded data!
-  memcpy(frame->Buffer()+4, aInputImage._buffer+4, frame->Size()-4);
+  memcpy(frame->Buffer()+4, aDecodeData->mImage._buffer+4, frame->Size()-4);
 
-  frame->SetEncodedWidth(aInputImage._encodedWidth);
-  frame->SetEncodedHeight(aInputImage._encodedHeight);
-  frame->SetTimeStamp((aInputImage._timeStamp * 1000ll)/90); // rounds down
-  frame->SetCompleteFrame(aInputImage._completeFrame);
+  frame->SetEncodedWidth(aDecodeData->mImage._encodedWidth);
+  frame->SetEncodedHeight(aDecodeData->mImage._encodedHeight);
+  frame->SetTimeStamp((aDecodeData->mImage._timeStamp * 1000ll)/90); // rounds down
+  frame->SetCompleteFrame(aDecodeData->mImage._completeFrame);
   frame->SetBufferType(GMP_BufferLength32);
 
   GMPVideoFrameType ft;
-  int32_t ret = WebrtcFrameTypeToGmpFrameType(aInputImage._frameType, &ft);
+  int32_t ret = WebrtcFrameTypeToGmpFrameType(aDecodeData->mImage._frameType, &ft);
   if (ret != WEBRTC_VIDEO_CODEC_OK) {
-    return ret;
+    LOG(LogLevel::Error, ("%s: WebrtcFrameTypeToGmpFrameType failed (%u)!",
+        __PRETTY_FUNCTION__, static_cast<unsigned>(ret)));
+    return;
   }
 
   // Bug XXXXXX: Set codecSpecific info
   GMPCodecSpecificInfo info;
   memset(&info, 0, sizeof(info));
   info.mCodecType = kGMPVideoCodecH264;
   info.mCodecSpecific.mH264.mSimulcastIdx = 0;
   nsTArray<uint8_t> codecSpecificInfo;
   codecSpecificInfo.AppendElements((uint8_t*)&info, sizeof(GMPCodecSpecificInfo));
 
-  LOGD(("GMP Decode: %" PRIu64 ", len %zu%s", frame->TimeStamp(), aInputImage._length,
-        ft == kGMPKeyFrame ? ", KeyFrame" : ""));
-  nsresult rv = mGMP->Decode(Move(frame),
-                             aMissingFrames,
-                             codecSpecificInfo,
-                             aRenderTimeMs);
+  LOGD(("GMP Decode: %" PRIu64 ", len %zu%s", frame->TimeStamp(),
+        aDecodeData->mImage._length, ft == kGMPKeyFrame ? ", KeyFrame" : ""));
+
+  nsresult rv = aThis->mGMP->Decode(Move(frame),
+                                    aDecodeData->mMissingFrames,
+                                    codecSpecificInfo,
+                                    aDecodeData->mRenderTimeMs);
   if (NS_FAILED(rv)) {
-    return WEBRTC_VIDEO_CODEC_ERROR;
+    LOG(LogLevel::Error, ("%s: Decode failed (rv=%u)!",
+        __PRETTY_FUNCTION__, static_cast<unsigned>(rv)));
   }
-  if(mDecoderStatus != GMPNoErr){
-    mDecoderStatus = GMPNoErr;
-    return WEBRTC_VIDEO_CODEC_ERROR;
+
+  if(aThis->mDecoderStatus != GMPNoErr){
+    aThis->mDecoderStatus = GMPNoErr;
+    LOG(LogLevel::Error, ("%s: Decoder status is bad (%u)!",
+        __PRETTY_FUNCTION__, static_cast<unsigned>(aThis->mDecoderStatus)));
   }
-  return WEBRTC_VIDEO_CODEC_OK;
 }
 
 int32_t
 WebrtcGmpVideoDecoder::RegisterDecodeCompleteCallback( webrtc::DecodedImageCallback* aCallback)
 {
   MutexAutoLock lock(mCallbackMutex);
   mCallback = aCallback;
 
--- a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h
+++ b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h
@@ -464,21 +464,18 @@ private:
       mInitDone->Dispatch(result, errorOut);
     }
 
   private:
     RefPtr<WebrtcGmpVideoDecoder> mDecoder;
     RefPtr<GmpInitDoneRunnable> mInitDone;
   };
 
-  virtual int32_t Decode_g(const webrtc::EncodedImage& aInputImage,
-                           bool aMissingFrames,
-                           const webrtc::RTPFragmentationHeader* aFragmentation,
-                           const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
-                           int64_t aRenderTimeMs);
+  static void Decode_g(const RefPtr<WebrtcGmpVideoDecoder>& aThis,
+                       nsAutoPtr<GMPDecodeData> aDecodeData);
 
   nsCOMPtr<mozIGeckoMediaPluginService> mMPS;
   nsCOMPtr<nsIThread> mGMPThread;
   GMPVideoDecoderProxy* mGMP; // Addref is held for us
   // Used to handle a race where Release() is called while init is in progress
   bool mInitting;
   // Frames queued for decode while mInitting is true
   nsTArray<UniquePtr<GMPDecodeData>> mQueuedFrames;
--- a/media/webrtc/webrtc.mozbuild
+++ b/media/webrtc/webrtc.mozbuild
@@ -1,25 +1,29 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 if CONFIG['MOZ_WEBRTC']:
     DEFINES['HAVE_UINT64_T'] = True
+
     if CONFIG['OS_TARGET'] != 'WINNT':
         DEFINES['WEBRTC_POSIX'] = True
         DEFINES['WEBRTC_BUILD_LIBEVENT'] = True
 
     if CONFIG['OS_TARGET'] == 'Linux':
         DEFINES['WEBRTC_LINUX'] = True
     elif CONFIG['OS_TARGET'] == 'Darwin':
         DEFINES['WEBRTC_MAC'] = True
     elif CONFIG['OS_TARGET'] == 'WINNT':
         DEFINES['WEBRTC_WIN'] = True
         DEFINES['HAVE_WINSOCK2_H'] = True
     elif CONFIG['OS_TARGET'] in ('DragonFly', 'FreeBSD', 'NetBSD', 'OpenBSD'):
         DEFINES['WEBRTC_BSD'] = True
     elif CONFIG['OS_TARGET'] == 'Android':
         DEFINES['WEBRTC_ANDROID'] = True
 
+    if CONFIG['CC_TYPE'] in ('msvc', 'clang-cl'):
+        DEFINES['__PRETTY_FUNCTION__'] = '__FUNCSIG__'
+
     if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
         CXXFLAGS += ['-Wno-error=shadow']