Bug 1380237 - Tweak HLSDemuxer to handle audio format change. r=jya
authorJames Cheng <jacheng@mozilla.com>
Wed, 12 Jul 2017 15:12:06 +0800
changeset 368773 99000423060490d677f9b85611176d4ea04cc9fd
parent 368772 65d2aefe6c6b47bdd13b6880d63e45de889c8c3c
child 368774 e80a89b890ca46eb0004ad408704feedc71be156
push id32171
push userkwierso@gmail.com
push dateThu, 13 Jul 2017 22:51:35 +0000
treeherdermozilla-central@1afceff864d5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjya
bugs1380237
milestone56.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 1380237 - Tweak HLSDemuxer to handle audio format change. r=jya 1. Moving UpdateA/VInfo to HLSTrackDemuxer and related changes. 2. Handle audio format change by changing the stream id. MozReview-Commit-ID: IJmSvygZLVf
dom/media/hls/HLSDemuxer.cpp
dom/media/hls/HLSDemuxer.h
--- a/dom/media/hls/HLSDemuxer.cpp
+++ b/dom/media/hls/HLSDemuxer.cpp
@@ -123,17 +123,16 @@ private:
   ~HLSDemuxerCallbacksSupport() { }
   HLSDemuxer* mDemuxer;
 
 };
 
 HLSDemuxer::HLSDemuxer(int aPlayerId)
   : mTaskQueue(new AutoTaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK),
                                  /* aSupportsTailDispatch = */ false))
-  , mMutex("HLSDemuxer")
 {
   MOZ_ASSERT(NS_IsMainThread());
   HLSDemuxerCallbacksSupport::Init();
   mJavaCallbacks = GeckoHLSDemuxerWrapper::Callbacks::New();
   MOZ_ASSERT(mJavaCallbacks);
 
   mCallbackSupport = new HLSDemuxerCallbacksSupport(this);
   HLSDemuxerCallbacksSupport::AttachNative(mJavaCallbacks,
@@ -144,20 +143,24 @@ HLSDemuxer::HLSDemuxer(int aPlayerId)
 }
 
 void
 HLSDemuxer::OnInitialized(bool aHasAudio, bool aHasVideo)
 {
   MOZ_ASSERT(OnTaskQueue());
 
   if (aHasAudio) {
-    UpdateAudioInfo(0);
+    mAudioDemuxer = new HLSTrackDemuxer(this,
+                                        TrackInfo::TrackType::kAudioTrack,
+                                        MakeUnique<AudioInfo>());
   }
   if (aHasVideo) {
-    UpdateVideoInfo(0);
+    mVideoDemuxer = new HLSTrackDemuxer(this,
+                                        TrackInfo::TrackType::kVideoTrack,
+                                        MakeUnique<VideoInfo>());
   }
 
   mInitPromise.ResolveIfExists(NS_OK, __func__);
 }
 
 void
 HLSDemuxer::OnError(int aErrorCode)
 {
@@ -179,26 +182,24 @@ HLSDemuxer::Init()
 void HLSDemuxer::NotifyDataArrived()
 {
   HLS_DEBUG("HLSDemuxer", "NotifyDataArrived");
 }
 
 bool
 HLSDemuxer::HasTrackType(TrackType aType) const
 {
-  MutexAutoLock lock(mMutex);
   HLS_DEBUG("HLSDemuxer", "HasTrackType(%d)", aType);
-  switch (aType) {
-    case TrackType::kAudioTrack:
-      return mInfo.HasAudio();
-    case TrackType::kVideoTrack:
-      return mInfo.HasVideo();
-    default:
-      return false;
+  if (mAudioDemuxer && aType == TrackType::kAudioTrack) {
+    return mAudioDemuxer->IsTrackValid();
   }
+  if (mVideoDemuxer && aType == TrackType::kVideoTrack) {
+    return mVideoDemuxer->IsTrackValid();
+  }
+  return false;
 }
 
 uint32_t
 HLSDemuxer::GetNumberTracks(TrackType aType) const
 {
   switch (aType) {
     case TrackType::kAudioTrack:
       return mHLSDemuxerWrapper->GetNumberOfTracks(TrackType::kAudioTrack);
@@ -207,18 +208,22 @@ HLSDemuxer::GetNumberTracks(TrackType aT
     default:
       return 0;
   }
 }
 
 already_AddRefed<MediaTrackDemuxer>
 HLSDemuxer::GetTrackDemuxer(TrackType aType, uint32_t aTrackNumber)
 {
-  RefPtr<HLSTrackDemuxer> e = new HLSTrackDemuxer(this, aType);
-  mDemuxers.AppendElement(e);
+  RefPtr<HLSTrackDemuxer> e = nullptr;
+  if (aType == TrackInfo::TrackType::kAudioTrack) {
+    e = mAudioDemuxer;
+  } else {
+    e = mVideoDemuxer;
+  }
   return e.forget();
 }
 
 bool
 HLSDemuxer::IsSeekable() const
 {
   return !mHLSDemuxerWrapper->IsLiveStream();
 }
@@ -226,85 +231,23 @@ HLSDemuxer::IsSeekable() const
 UniquePtr<EncryptionInfo>
 HLSDemuxer::GetCrypto()
 {
   // TODO: Currently, our HLS implementation doesn't support encrypted content.
   // Return null at this stage.
   return nullptr;
 }
 
-TrackInfo*
-HLSDemuxer::GetTrackInfo(TrackType aTrack)
-{
-  MutexAutoLock lock(mMutex);
-  switch (aTrack) {
-    case TrackType::kAudioTrack: {
-      return &mInfo.mAudio;
-    }
-    case TrackType::kVideoTrack: {
-      return &mInfo.mVideo;
-    }
-    default:
-      return nullptr;
-  }
-}
-
 TimeUnit
 HLSDemuxer::GetNextKeyFrameTime()
 {
   MOZ_ASSERT(mHLSDemuxerWrapper);
   return TimeUnit::FromMicroseconds(mHLSDemuxerWrapper->GetNextKeyFrameTime());
 }
 
-void
-HLSDemuxer::UpdateAudioInfo(int index)
-{
-  MOZ_ASSERT(OnTaskQueue());
-  MOZ_ASSERT(mHLSDemuxerWrapper);
-  HLS_DEBUG("HLSDemuxer", "UpdateAudioInfo (%d)", index);
-  MutexAutoLock lock(mMutex);
-  jni::Object::LocalRef infoObj = mHLSDemuxerWrapper->GetAudioInfo(index);
-  if (infoObj) {
-    java::GeckoAudioInfo::LocalRef audioInfo(Move(infoObj));
-    mInfo.mAudio.mRate = audioInfo->Rate();
-    mInfo.mAudio.mChannels = audioInfo->Channels();
-    mInfo.mAudio.mProfile = audioInfo->Profile();
-    mInfo.mAudio.mBitDepth = audioInfo->BitDepth();
-    mInfo.mAudio.mMimeType = NS_ConvertUTF16toUTF8(audioInfo->MimeType()->ToString());
-    mInfo.mAudio.mDuration = TimeUnit::FromMicroseconds(audioInfo->Duration());
-    auto&& csd = audioInfo->CodecSpecificData()->GetElements();
-    mInfo.mAudio.mCodecSpecificConfig->Clear();
-    mInfo.mAudio.mCodecSpecificConfig->AppendElements(reinterpret_cast<uint8_t*>(&csd[0]),
-                                                      csd.Length());
-  }
-}
-
-void
-HLSDemuxer::UpdateVideoInfo(int index)
-{
-  MOZ_ASSERT(OnTaskQueue());
-  MOZ_ASSERT(mHLSDemuxerWrapper);
-  MutexAutoLock lock(mMutex);
-  jni::Object::LocalRef infoObj = mHLSDemuxerWrapper->GetVideoInfo(index);
-  if (infoObj) {
-    java::GeckoVideoInfo::LocalRef videoInfo(Move(infoObj));
-    mInfo.mVideo.mStereoMode = getStereoMode(videoInfo->StereoMode());
-    mInfo.mVideo.mRotation = getVideoInfoRotation(videoInfo->Rotation());
-    mInfo.mVideo.mImage.width = videoInfo->DisplayWidth();
-    mInfo.mVideo.mImage.height = videoInfo->DisplayHeight();
-    mInfo.mVideo.mDisplay.width = videoInfo->PictureWidth();
-    mInfo.mVideo.mDisplay.height = videoInfo->PictureHeight();
-    mInfo.mVideo.mMimeType = NS_ConvertUTF16toUTF8(videoInfo->MimeType()->ToString());
-    mInfo.mVideo.mDuration = TimeUnit::FromMicroseconds(videoInfo->Duration());
-    HLS_DEBUG("HLSDemuxer", "UpdateVideoInfo (%d) / I(%dx%d) / D(%dx%d)",
-     index, mInfo.mVideo.mImage.width, mInfo.mVideo.mImage.height,
-     mInfo.mVideo.mDisplay.width, mInfo.mVideo.mDisplay.height);
-  }
-}
-
 bool
 HLSDemuxer::OnTaskQueue() const
 {
   return mTaskQueue->IsCurrentThreadIn();
 }
 
 HLSDemuxer::~HLSDemuxer()
 {
@@ -316,26 +259,34 @@ HLSDemuxer::~HLSDemuxer()
   }
   if (mHLSDemuxerWrapper) {
     mHLSDemuxerWrapper->Destroy();
     mHLSDemuxerWrapper = nullptr;
   }
   mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
 }
 
-HLSTrackDemuxer::HLSTrackDemuxer(HLSDemuxer* aParent, TrackInfo::TrackType aType)
+HLSTrackDemuxer::HLSTrackDemuxer(HLSDemuxer* aParent,
+                                 TrackInfo::TrackType aType,
+                                 UniquePtr<TrackInfo> aTrackInfo)
   : mParent(aParent)
   , mType(aType)
+  , mMutex("HLSTrackDemuxer")
+  , mTrackInfo(Move(aTrackInfo))
 {
+  // Only support audio and video track currently.
+  MOZ_ASSERT(mType == TrackInfo::kVideoTrack || mType == TrackInfo::kAudioTrack);
+  UpdateMediaInfo(0);
 }
 
 UniquePtr<TrackInfo>
 HLSTrackDemuxer::GetInfo() const
 {
-  return mParent->GetTrackInfo(mType)->Clone();
+  MutexAutoLock lock(mMutex);
+  return mTrackInfo->Clone();
 }
 
 RefPtr<HLSTrackDemuxer::SeekPromise>
 HLSTrackDemuxer::Seek(const TimeUnit& aTime)
 {
   MOZ_ASSERT(mParent, "Called after BreackCycle()");
   return InvokeAsync<TimeUnit&&>(mParent->GetTaskQueue(),
                                  this,
@@ -426,16 +377,59 @@ HLSTrackDemuxer::DoGetSamples(int32_t aN
        samples->mSamples.LastElement()->mTime >= mNextKeyframeTime.value())) {
     // Only need to find NextKeyFrame for Video
     UpdateNextKeyFrameTime();
   }
 
   return SamplesPromise::CreateAndResolve(samples, __func__);
 }
 
+void
+HLSTrackDemuxer::UpdateMediaInfo(int index)
+{
+  MOZ_ASSERT(mParent->OnTaskQueue());
+  MOZ_ASSERT(mParent->mHLSDemuxerWrapper);
+  MutexAutoLock lock(mMutex);
+  jni::Object::LocalRef infoObj = nullptr;
+  if (mType == TrackType::kAudioTrack) {
+    infoObj = mParent->mHLSDemuxerWrapper->GetAudioInfo(index);
+    auto* audioInfo = mTrackInfo->GetAsAudioInfo();
+    if (infoObj && audioInfo) {
+      HLS_DEBUG("HLSTrackDemuxer", "Update audio info (%d)", index);
+      java::GeckoAudioInfo::LocalRef audioInfoObj(Move(infoObj));
+      audioInfo->mRate = audioInfoObj->Rate();
+      audioInfo->mChannels = audioInfoObj->Channels();
+      audioInfo->mProfile = audioInfoObj->Profile();
+      audioInfo->mBitDepth = audioInfoObj->BitDepth();
+      audioInfo->mMimeType = NS_ConvertUTF16toUTF8(audioInfoObj->MimeType()->ToString());
+      audioInfo->mDuration = TimeUnit::FromMicroseconds(audioInfoObj->Duration());
+      auto&& csd = audioInfoObj->CodecSpecificData()->GetElements();
+      audioInfo->mCodecSpecificConfig->Clear();
+      audioInfo->mCodecSpecificConfig->AppendElements(reinterpret_cast<uint8_t*>(&csd[0]),
+                                                      csd.Length());
+    }
+  } else {
+    infoObj = mParent->mHLSDemuxerWrapper->GetVideoInfo(index);
+    auto* videoInfo = mTrackInfo->GetAsVideoInfo();
+    if (infoObj && videoInfo) {
+      java::GeckoVideoInfo::LocalRef videoInfoObj(Move(infoObj));
+      videoInfo->mStereoMode = getStereoMode(videoInfoObj->StereoMode());
+      videoInfo->mRotation = getVideoInfoRotation(videoInfoObj->Rotation());
+      videoInfo->mImage.width = videoInfoObj->DisplayWidth();
+      videoInfo->mImage.height = videoInfoObj->DisplayHeight();
+      videoInfo->mDisplay.width = videoInfoObj->PictureWidth();
+      videoInfo->mDisplay.height = videoInfoObj->PictureHeight();
+      videoInfo->mMimeType = NS_ConvertUTF16toUTF8(videoInfoObj->MimeType()->ToString());
+      videoInfo->mDuration = TimeUnit::FromMicroseconds(videoInfoObj->Duration());
+      HLS_DEBUG("HLSTrackDemuxer", "Update video info (%d) / I(%dx%d) / D(%dx%d)",
+        index, videoInfo->mImage.width, videoInfo->mImage.height,
+        videoInfo->mDisplay.width, videoInfo->mDisplay.height);
+    }
+  }
+}
 
 CryptoSample
 HLSTrackDemuxer::ExtractCryptoSample(size_t aSampleSize,
                                      java::sdk::CryptoInfo::LocalRef aCryptoInfo)
 {
   if (!aCryptoInfo) {
     return CryptoSample{};
   }
@@ -524,25 +518,23 @@ HLSTrackDemuxer::ConvertToMediaRawData(j
 
   int32_t size = 0;
   ok &= NS_SUCCEEDED(info->Size(&size));
   if (!ok) {
     HLS_DEBUG("HLSTrackDemuxer", "Error occurred during extraction from Sample java object.");
     return nullptr;
   }
 
-  // Update streamSouceID & videoInfo for MFR.
-  if (mType == TrackInfo::kVideoTrack) {
-    auto sampleFormatIndex = aSample->FormatIndex();
-    if (mLastFormatIndex != sampleFormatIndex) {
-      mLastFormatIndex = sampleFormatIndex;
-      mParent->UpdateVideoInfo(mLastFormatIndex);
-      MutexAutoLock lock(mParent->mMutex);
-      mrd->mTrackInfo = new TrackInfoSharedPtr(mParent->mInfo.mVideo, ++sStreamSourceID);
-    }
+  // Update A/V stream souce ID & Audio/VideoInfo for MFR.
+  auto sampleFormatIndex = aSample->FormatIndex();
+  if (mLastFormatIndex != sampleFormatIndex) {
+    mLastFormatIndex = sampleFormatIndex;
+    UpdateMediaInfo(mLastFormatIndex);
+    MutexAutoLock lock(mMutex);
+    mrd->mTrackInfo = new TrackInfoSharedPtr(*mTrackInfo, ++sStreamSourceID);
   }
 
   // Write payload into MediaRawData
   UniquePtr<MediaRawDataWriter> writer(mrd->CreateWriter());
   if (!writer->SetSize(size)) {
     HLS_DEBUG("HLSTrackDemuxer", "Exit failed to allocate media buffer");
     return nullptr;
   }
--- a/dom/media/hls/HLSDemuxer.h
+++ b/dom/media/hls/HLSDemuxer.h
@@ -49,65 +49,68 @@ public:
   void NotifyDataArrived() override;
 
   AutoTaskQueue* GetTaskQueue() const { return mTaskQueue; }
   void OnInitialized(bool aHasAudio, bool aHasVideo);
   void OnError(int aErrorCode);
 
 private:
   media::TimeUnit GetNextKeyFrameTime();
-  void UpdateVideoInfo(int index);
-  void UpdateAudioInfo(int index);
+
   bool OnTaskQueue() const;
-  TrackInfo* GetTrackInfo(TrackInfo::TrackType);
   ~HLSDemuxer();
   friend class HLSTrackDemuxer;
 
   const RefPtr<AutoTaskQueue> mTaskQueue;
-  nsTArray<RefPtr<HLSTrackDemuxer>> mDemuxers;
+  RefPtr<HLSTrackDemuxer> mAudioDemuxer;
+  RefPtr<HLSTrackDemuxer> mVideoDemuxer;
 
   MozPromiseHolder<InitPromise> mInitPromise;
   RefPtr<HLSDemuxerCallbacksSupport> mCallbackSupport;
 
-  // Mutex to protect members below across multiple threads.
-  mutable Mutex mMutex;
-  MediaInfo mInfo;
-
   java::GeckoHLSDemuxerWrapper::Callbacks::GlobalRef mJavaCallbacks;
   java::GeckoHLSDemuxerWrapper::GlobalRef mHLSDemuxerWrapper;
 };
 
 class HLSTrackDemuxer : public MediaTrackDemuxer
 {
 public:
   HLSTrackDemuxer(HLSDemuxer* aParent,
-                  TrackInfo::TrackType aType);
+                  TrackInfo::TrackType aType,
+                  UniquePtr<TrackInfo> aTrackInfo);
   ~HLSTrackDemuxer();
   UniquePtr<TrackInfo> GetInfo() const override;
 
   RefPtr<SeekPromise> Seek(const media::TimeUnit& aTime) override;
 
   RefPtr<SamplesPromise> GetSamples(int32_t aNumSamples = 1) override;
 
+  void UpdateMediaInfo(int index);
+
   void Reset() override;
 
   nsresult GetNextRandomAccessPoint(media::TimeUnit* aTime) override;
 
   RefPtr<SkipAccessPointPromise> SkipToNextRandomAccessPoint(
     const media::TimeUnit& aTimeThreshold) override;
 
   media::TimeIntervals GetBuffered() override;
 
   void BreakCycles() override;
 
   bool GetSamplesMayBlock() const override
   {
     return false;
   }
 
+  bool IsTrackValid() const
+  {
+    MutexAutoLock lock(mMutex);
+    return mTrackInfo->IsValid();
+  }
 private:
   // Update the timestamp of the next keyframe if there's one.
   void UpdateNextKeyFrameTime();
 
   // Runs on HLSDemuxer's task queue.
   RefPtr<SeekPromise> DoSeek(const media::TimeUnit& aTime);
   RefPtr<SamplesPromise> DoGetSamples(int32_t aNumSamples);
   RefPtr<SkipAccessPointPromise> DoSkipToNextRandomAccessPoint(
@@ -118,13 +121,17 @@ private:
   RefPtr<MediaRawData> ConvertToMediaRawData(java::GeckoHLSSample::LocalRef aSample);
 
   RefPtr<HLSDemuxer> mParent;
   TrackInfo::TrackType mType;
   Maybe<media::TimeUnit> mNextKeyframeTime;
   int32_t mLastFormatIndex = -1;
   // Queued samples extracted by the demuxer, but not yet returned.
   RefPtr<MediaRawData> mQueuedSample;
+
+  // Mutex to protect members below across multiple threads.
+  mutable Mutex mMutex;
+  UniquePtr<TrackInfo> mTrackInfo;
 };
 
 } // namespace mozilla
 
 #endif