Bug 1272877 - dispatch GetAsSourceSurface() to main thread to prevent assert; r=jesup draft
authorMunro Mengjue Chiang <mchiang@mozilla.com>
Tue, 23 Aug 2016 15:45:23 +0800
changeset 406722 a418c6baa2e2ecb52155dc9f7a1320b41acd3b6b
parent 405224 7da96726ab3f9664f3dc9efb9927e1cfc1337c40
child 529729 f50af844dc88d9c9213cd103b4ae42ae3cb5d098
push id27809
push usermchiang@mozilla.com
push dateMon, 29 Aug 2016 10:58:33 +0000
reviewersjesup
bugs1272877
milestone51.0a1
Bug 1272877 - dispatch GetAsSourceSurface() to main thread to prevent assert; r=jesup MozReview-Commit-ID: 7Y5cuNFw8sm
dom/media/encoder/VP8TrackEncoder.cpp
dom/media/encoder/VP8TrackEncoder.h
--- a/dom/media/encoder/VP8TrackEncoder.cpp
+++ b/dom/media/encoder/VP8TrackEncoder.cpp
@@ -9,16 +9,17 @@
 #include "libyuv.h"
 #include "mozilla/gfx/2D.h"
 #include "prsystem.h"
 #include "VideoSegment.h"
 #include "VideoUtils.h"
 #include "vpx/vp8cx.h"
 #include "vpx/vpx_encoder.h"
 #include "WebMWriter.h"
+#include "mozilla/media/MediaUtils.h"
 
 namespace mozilla {
 
 LazyLogModule gVP8TrackEncoderLog("VP8TrackEncoder");
 #define VP8LOG(msg, ...) MOZ_LOG(gVP8TrackEncoderLog, mozilla::LogLevel::Debug, \
                                   (msg, ##__VA_ARGS__))
 // Debug logging macro with object pointer and class name.
 
@@ -359,17 +360,17 @@ nsresult VP8TrackEncoder::PrepareRawFram
       VP8LOG("Converting an %s frame to I420 failed\n", yuvFormat.c_str());
       return NS_ERROR_FAILURE;
     }
 
     VP8LOG("Converted an %s frame to I420\n", yuvFormat.c_str());
   } else {
     // Not YCbCr at all. Try to get access to the raw data and convert.
 
-    RefPtr<SourceSurface> surf = img->GetAsSourceSurface();
+    RefPtr<SourceSurface> surf = GetSourceSurface(img.forget());
     if (!surf) {
       VP8LOG("Getting surface from %s image failed\n", Stringify(format).c_str());
       return NS_ERROR_FAILURE;
     }
 
     RefPtr<DataSourceSurface> data = surf->GetDataSurface();
     if (!data) {
       VP8LOG("Getting data surface from %s image with %s (%s) surface failed\n",
@@ -427,16 +428,47 @@ nsresult VP8TrackEncoder::PrepareRawFram
   mVPXImageWrapper->planes[VPX_PLANE_V] = cr;
   mVPXImageWrapper->stride[VPX_PLANE_Y] = mFrameWidth;
   mVPXImageWrapper->stride[VPX_PLANE_U] = halfWidth;
   mVPXImageWrapper->stride[VPX_PLANE_V] = halfWidth;
 
   return NS_OK;
 }
 
+void
+VP8TrackEncoder::ReplyGetSourceSurface(already_AddRefed<gfx::SourceSurface> aSurf)
+{
+  mSourceSurface = aSurf;
+}
+
+already_AddRefed<gfx::SourceSurface>
+VP8TrackEncoder::GetSourceSurface(already_AddRefed<Image> aImg)
+{
+  RefPtr<Image> img = aImg;
+  mSourceSurface = nullptr;
+  if (img) {
+    if (img->AsGLImage() && !NS_IsMainThread()) {
+      // GLImage::GetAsSourceSurface() only support main thread
+      RefPtr<Runnable> getsourcesurface_runnable =
+        media::NewRunnableFrom([this, img]() -> nsresult {
+          // Due to the parameter DISPATCH_SYNC, encoder thread will stock at
+          // MediaRecorder::Session::Extract(bool). There is no chance
+          // that TrackEncoder will be destroyed during this period. So
+          // there is no need to use RefPtr to hold TrackEncoder.
+          ReplyGetSourceSurface(img->GetAsSourceSurface());
+          return NS_OK;
+        });
+      NS_DispatchToMainThread(getsourcesurface_runnable, NS_DISPATCH_SYNC);
+    } else {
+      mSourceSurface = img->GetAsSourceSurface();
+    }
+  }
+  return mSourceSurface.forget();
+}
+
 // These two define value used in GetNextEncodeOperation to determine the
 // EncodeOperation for next target frame.
 #define I_FRAME_RATIO (0.5)
 #define SKIP_FRAME_RATIO (0.75)
 
 /**
  * Compares the elapsed time from the beginning of GetEncodedTrack and
  * the processed frame duration in mSourceSegment
--- a/dom/media/encoder/VP8TrackEncoder.h
+++ b/dom/media/encoder/VP8TrackEncoder.h
@@ -31,16 +31,17 @@ class VP8TrackEncoder : public VideoTrac
 public:
   explicit VP8TrackEncoder(TrackRate aTrackRate);
   virtual ~VP8TrackEncoder();
 
   already_AddRefed<TrackMetadataBase> GetMetadata() final override;
 
   nsresult GetEncodedTrack(EncodedFrameContainer& aData) final override;
 
+  void ReplyGetSourceSurface(already_AddRefed<gfx::SourceSurface> aSurf);
 protected:
   nsresult Init(int32_t aWidth, int32_t aHeight,
                 int32_t aDisplayWidth, int32_t aDisplayHeight) final override;
 
 private:
   // Calculate the target frame's encoded duration.
   StreamTime CalculateEncodedDuration(StreamTime aDurationCopied);
 
@@ -55,16 +56,18 @@ private:
   // Get the encoded data from encoder to aData.
   // Return value: false if the vpx_codec_get_cx_data returns null
   //               for EOS detection.
   bool GetEncodedPartitions(EncodedFrameContainer& aData);
 
   // Prepare the input data to the mVPXImageWrapper for encoding.
   nsresult PrepareRawFrame(VideoChunk &aChunk);
 
+  already_AddRefed<gfx::SourceSurface> GetSourceSurface(already_AddRefed<layers::Image> aImg);
+
   // Output frame rate.
   uint32_t mEncodedFrameRate;
   // Duration for the output frame, reciprocal to mEncodedFrameRate.
   StreamTime mEncodedFrameDuration;
   // Encoded timestamp.
   StreamTime mEncodedTimestamp;
   // Duration to the next encode frame.
   StreamTime mRemainingTicks;
@@ -83,13 +86,14 @@ private:
    */
   VideoSegment mSourceSegment;
 
   // VP8 relative members.
   // Codec context structure.
   nsAutoPtr<vpx_codec_ctx_t> mVPXContext;
   // Image Descriptor.
   nsAutoPtr<vpx_image_t> mVPXImageWrapper;
+  RefPtr<gfx::SourceSurface> mSourceSurface;
 };
 
 } // namespace mozilla
 
 #endif