Bug 1194612: P3. Ensure H264Converter is thread safe. r=alfredo
☠☠ backed out by 37dbde3bfc1b ☠ ☠
authorJean-Yves Avenard <jyavenard@mozilla.com>
Sat, 15 Aug 2015 18:20:42 +1000
changeset 257960 e6d2cb05222a15bc6cc5d55e41b9757dec3c1ecd
parent 257959 a2f27d3830878da23c519928a04c53ce20b0cfab
child 257961 dde632bce46c2395e2ed6f39ac1cf6e23f70f453
push id29238
push userryanvm@gmail.com
push dateMon, 17 Aug 2015 13:06:57 +0000
treeherdermozilla-central@a6eeb28458fd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersalfredo
bugs1194612
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1194612: P3. Ensure H264Converter is thread safe. r=alfredo
dom/media/platforms/wrappers/H264Converter.cpp
--- a/dom/media/platforms/wrappers/H264Converter.cpp
+++ b/dom/media/platforms/wrappers/H264Converter.cpp
@@ -37,28 +37,30 @@ H264Converter::H264Converter(PlatformDec
 
 H264Converter::~H264Converter()
 {
 }
 
 nsRefPtr<MediaDataDecoder::InitPromise>
 H264Converter::Init()
 {
+  MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   if (mDecoder) {
     return mDecoder->Init();
   }
 
   // We haven't been able to initialize a decoder due to a missing SPS/PPS.
   return MediaDataDecoder::InitPromise::CreateAndResolve(
            TrackType::kVideoTrack, __func__);
 }
 
 nsresult
 H264Converter::Input(MediaRawData* aSample)
 {
+  MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   if (!mNeedAVCC) {
     if (!mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample)) {
       return NS_ERROR_FAILURE;
     }
   } else {
     if (!mp4_demuxer::AnnexB::ConvertSampleToAVCC(aSample)) {
       return NS_ERROR_FAILURE;
     }
@@ -88,47 +90,51 @@ H264Converter::Input(MediaRawData* aSamp
   aSample->mExtraData = mCurrentConfig.mExtraData;
 
   return mDecoder->Input(aSample);
 }
 
 nsresult
 H264Converter::Flush()
 {
+  MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   if (mDecoder) {
     return mDecoder->Flush();
   }
   return mLastError;
 }
 
 nsresult
 H264Converter::Drain()
 {
+  MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   if (mDecoder) {
     return mDecoder->Drain();
   }
   mCallback->DrainComplete();
   return mLastError;
 }
 
 nsresult
 H264Converter::Shutdown()
 {
+  MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   if (mDecoder) {
     nsresult rv = mDecoder->Shutdown();
     mInitPromiseRequest.DisconnectIfExists();
     mDecoder = nullptr;
     return rv;
   }
   return NS_OK;
 }
 
 bool
 H264Converter::IsHardwareAccelerated(nsACString& aFailureReason) const
 {
+  MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   if (mDecoder) {
     return mDecoder->IsHardwareAccelerated(aFailureReason);
   }
   return MediaDataDecoder::IsHardwareAccelerated(aFailureReason);
 }
 
 nsresult
 H264Converter::CreateDecoder()
@@ -149,66 +155,71 @@ H264Converter::CreateDecoder()
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
 nsresult
 H264Converter::CreateDecoderAndInit(MediaRawData* aSample)
 {
+  MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   nsRefPtr<MediaByteBuffer> extra_data =
     mp4_demuxer::AnnexB::ExtractExtraData(aSample);
   if (!mp4_demuxer::AnnexB::HasSPS(extra_data)) {
     return NS_ERROR_NOT_INITIALIZED;
   }
   UpdateConfigFromExtraData(extra_data);
 
   nsresult rv = CreateDecoder();
 
   if (NS_SUCCEEDED(rv)) {
     mDecoderInitializing = true;
     // Queue the incoming sample.
     mMediaRawSamples.AppendElement(aSample);
 
     nsRefPtr<H264Converter> self = this;
 
-    // The mVideoTaskQueue is flushable which can't be used in MediaPromise. So
-    // we get the current AbstractThread instead of it. The MOZ_ASSERT above
-    // ensures we are running in AbstractThread so we won't get a nullptr.
     mInitPromiseRequest.Begin(mDecoder->Init()
-      ->Then(AbstractThread::GetCurrent(), __func__, this,
+      ->Then(AbstractThread::GetCurrent()->AsTaskQueue(), __func__, this,
              &H264Converter::OnDecoderInitDone,
              &H264Converter::OnDecoderInitFailed));
   }
   return rv;
 }
 
 void
 H264Converter::OnDecoderInitDone(const TrackType aTrackType)
 {
+  MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   mInitPromiseRequest.Complete();
+
   for (uint32_t i = 0 ; i < mMediaRawSamples.Length(); i++) {
     if (NS_FAILED(mDecoder->Input(mMediaRawSamples[i]))) {
       mCallback->Error();
     }
   }
   mMediaRawSamples.Clear();
   mDecoderInitializing = false;
 }
 
 void
 H264Converter::OnDecoderInitFailed(MediaDataDecoder::DecoderFailureReason aReason)
 {
+  MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   mInitPromiseRequest.Complete();
   mCallback->Error();
+  mLastError = NS_ERROR_FAILURE;
+  // So we don't attempt to reuse the failed decoder.
+  Shutdown();
 }
 
 nsresult
 H264Converter::CheckForSPSChange(MediaRawData* aSample)
 {
+  MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   nsRefPtr<MediaByteBuffer> extra_data =
     mp4_demuxer::AnnexB::ExtractExtraData(aSample);
   if (!mp4_demuxer::AnnexB::HasSPS(extra_data) ||
       mp4_demuxer::AnnexB::CompareExtraData(extra_data,
                                             mCurrentConfig.mExtraData)) {
         return NS_OK;
       }
   if (!mNeedAVCC) {
@@ -221,16 +232,17 @@ H264Converter::CheckForSPSChange(MediaRa
   mDecoder->Flush();
   Shutdown();
   return CreateDecoderAndInit(aSample);
 }
 
 void
 H264Converter::UpdateConfigFromExtraData(MediaByteBuffer* aExtraData)
 {
+  MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   mp4_demuxer::SPSData spsdata;
   if (mp4_demuxer::H264::DecodeSPSFromExtraData(aExtraData, spsdata) &&
       spsdata.pic_width > 0 && spsdata.pic_height > 0) {
     mp4_demuxer::H264::EnsureSPSIsSane(spsdata);
     mCurrentConfig.mImage.width = spsdata.pic_width;
     mCurrentConfig.mImage.height = spsdata.pic_height;
     mCurrentConfig.mDisplay.width = spsdata.display_width;
     mCurrentConfig.mDisplay.height = spsdata.display_height;