Bug 1014393 - WIP: separate MediaEncoders encoder and mux steps
authorBryce Van Dyk <bvandyk@mozilla.com>
Mon, 27 Mar 2017 11:15:08 +1300
changeset 563900 badd75f177caf7bfab1e2c4e673b129723648e89
parent 563899 726c37387e96f5281542b80bcdac1f5176493fb9
child 563901 c6edd409b3ff346449ba39f8d0b6e698d9174a84
push id54457
push userbvandyk@mozilla.com
push dateTue, 18 Apr 2017 01:45:52 +0000
bugs1014393
milestone55.0a1
Bug 1014393 - WIP: separate MediaEncoders encoder and mux steps MozReview-Commit-ID: 8jjMayZhDcN
dom/media/encoder/MediaEncoder.cpp
dom/media/encoder/MediaEncoder.h
--- a/dom/media/encoder/MediaEncoder.cpp
+++ b/dom/media/encoder/MediaEncoder.cpp
@@ -270,24 +270,22 @@ MediaEncoder::GetEncodedData(nsTArray<ns
     }
 
     case ENCODE_TRACK: {
       LOG(LogLevel::Debug, ("ENCODE_TRACK TimeStamp = %f", GetEncodeTimeStamp()));
       EncodedFrameContainer encodedData;
       nsresult rv = NS_OK;
       // We're most likely to actually wait for a video frame, so do that first to minimize
       // capture offset/lipsync issues
-      rv = WriteEncodedDataToMuxer(mVideoEncoder.get());
+      rv = EncodeData();
       if (NS_FAILED(rv)) {
-        LOG(LogLevel::Error, ("Fail to write video encoder data to muxer"));
         break;
       }
-      rv = WriteEncodedDataToMuxer(mAudioEncoder.get());
+      rv = WriteEncodedDataToMuxer();
       if (NS_FAILED(rv)) {
-        LOG(LogLevel::Error, ("Error! Fail to write audio encoder data to muxer"));
         break;
       }
       LOG(LogLevel::Debug, ("Audio encoded TimeStamp = %f", GetEncodeTimeStamp()));
       LOG(LogLevel::Debug, ("Video encoded TimeStamp = %f", GetEncodeTimeStamp()));
       // In audio only or video only case, let unavailable track's flag to be true.
       bool isAudioCompleted = (mAudioEncoder && mAudioEncoder->IsEncodingComplete()) || !mAudioEncoder;
       bool isVideoCompleted = (mVideoEncoder && mVideoEncoder->IsEncodingComplete()) || !mVideoEncoder;
       rv = mWriter->GetContainerData(aOutputBufs,
@@ -316,43 +314,100 @@ MediaEncoder::GetEncodedData(nsTArray<ns
       break;
     default:
       MOZ_CRASH("Invalid encode state");
     }
   }
 }
 
 nsresult
-MediaEncoder::WriteEncodedDataToMuxer(TrackEncoder *aTrackEncoder)
+MediaEncoder::EncodeData()
 {
-  if (aTrackEncoder == nullptr) {
-    return NS_OK;
-  }
-  if (aTrackEncoder->IsEncodingComplete()) {
-    return NS_OK;
+  PROFILER_LABEL("MediaEncoder", "EncodeData",
+    js::ProfileEntry::Category::OTHER);
+  nsresult rv = NS_OK;
+
+  if (mVideoEncoder && !mVideoEncoder->IsEncodingComplete()) {
+    EncodedFrameContainer encodedVideoData;
+    rv = mVideoEncoder->GetEncodedTrack(encodedVideoData);
+    if (NS_FAILED(rv)) {
+      // Encoding might be canceled.
+      LOG(LogLevel::Error, ("Error! Fail to get encoded data from video "
+                            "encoder."));
+      mState = ENCODE_ERROR;
+      return rv;
+    }
+    for (uint32_t i = 0; i < encodedVideoData.GetEncodedFrames().Length(); i++) {
+      mEncodedVideoFrames.AppendElement(
+        encodedVideoData.GetEncodedFrames().ElementAt(i));
+    }
   }
 
+  if (mAudioEncoder && !mAudioEncoder->IsEncodingComplete()) {
+    EncodedFrameContainer encodedAudioData;
+    rv = mAudioEncoder->GetEncodedTrack(encodedAudioData);
+    if (NS_FAILED(rv)) {
+      // Encoding might be canceled.
+      LOG(LogLevel::Error, ("Error! Fail to get encoded data from audio "
+                            "encoder."));
+      mState = ENCODE_ERROR;
+      return rv;
+    }
+    for (uint32_t i = 0; i < encodedAudioData.GetEncodedFrames().Length(); i++) {
+      mEncodedAudioFrames.AppendElement(
+        encodedAudioData.GetEncodedFrames().ElementAt(i));
+    }
+  }
+  return rv;
+}
+
+nsresult
+MediaEncoder::WriteEncodedDataToMuxer()
+{
   PROFILER_LABEL("MediaEncoder", "WriteEncodedDataToMuxer",
     js::ProfileEntry::Category::OTHER);
 
-  EncodedFrameContainer encodedVideoData;
-  nsresult rv = aTrackEncoder->GetEncodedTrack(encodedVideoData);
-  if (NS_FAILED(rv)) {
-    // Encoding might be canceled.
-    LOG(LogLevel::Error, ("Error! Fail to get encoded data from video encoder."));
-    mState = ENCODE_ERROR;
-    return rv;
+  nsresult rv = NS_OK;
+
+  if(mVideoEncoder) {
+    EncodedFrameContainer encodedVideoData;
+    for (uint32_t i = 0; i < mEncodedVideoFrames.Length(); i++) {
+      encodedVideoData.AppendEncodedFrame(mEncodedVideoFrames.ElementAt(i));
+    }
+    mEncodedVideoFrames.Clear();
+
+    rv = mWriter->WriteEncodedTrack(encodedVideoData,
+                                    mVideoEncoder->IsEncodingComplete() ?
+                                    ContainerWriter::END_OF_STREAM : 0);
+    if (NS_FAILED(rv)) {
+      LOG(LogLevel::Error, ("Error! Fail to write encoded video track to the "
+                            "media container."));
+      mState = ENCODE_ERROR;
+      return rv;
+    }
   }
-  rv = mWriter->WriteEncodedTrack(encodedVideoData,
-                                  aTrackEncoder->IsEncodingComplete() ?
-                                  ContainerWriter::END_OF_STREAM : 0);
-  if (NS_FAILED(rv)) {
-    LOG(LogLevel::Error, ("Error! Fail to write encoded video track to the media container."));
-    mState = ENCODE_ERROR;
+
+  if(mAudioEncoder) {
+    EncodedFrameContainer encodedAudioData;
+    for (uint32_t i = 0; i < mEncodedAudioFrames.Length(); i++) {
+      encodedAudioData.AppendEncodedFrame(mEncodedAudioFrames.ElementAt(i));
+    }
+    mEncodedAudioFrames.Clear();
+
+    rv = mWriter->WriteEncodedTrack(encodedAudioData,
+                                    mAudioEncoder->IsEncodingComplete() ?
+                                    ContainerWriter::END_OF_STREAM : 0);
+    if (NS_FAILED(rv)) {
+      LOG(LogLevel::Error, ("Error! Fail to write encoded audio track to the "
+                            "media container."));
+      mState = ENCODE_ERROR;
+      return rv;
+    }
   }
+
   return rv;
 }
 
 nsresult
 MediaEncoder::CopyMetadataToMuxer(TrackEncoder *aTrackEncoder)
 {
   if (aTrackEncoder == nullptr) {
     return NS_OK;
--- a/dom/media/encoder/MediaEncoder.h
+++ b/dom/media/encoder/MediaEncoder.h
@@ -224,23 +224,27 @@ public :
    */
   size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
   MediaStreamVideoRecorderSink* GetVideoSink() {
     return mVideoSink.get();
   }
 
 private:
-  // Get encoded data from trackEncoder and write to muxer
-  nsresult WriteEncodedDataToMuxer(TrackEncoder *aTrackEncoder);
+  // Get the pending encoded data to muxer
+  nsresult WriteEncodedDataToMuxer();
   // Get metadata from trackEncoder and copy to muxer
   nsresult CopyMetadataToMuxer(TrackEncoder* aTrackEncoder);
+  // Process data pending in encoders
+  nsresult EncodeData();
   nsAutoPtr<ContainerWriter> mWriter;
   nsAutoPtr<AudioTrackEncoder> mAudioEncoder;
   nsAutoPtr<VideoTrackEncoder> mVideoEncoder;
+  nsTArray<RefPtr<EncodedFrame>> mEncodedAudioFrames;
+  nsTArray<RefPtr<EncodedFrame>> mEncodedVideoFrames;
   RefPtr<MediaStreamVideoRecorderSink> mVideoSink;
   TimeStamp mStartTime;
   nsString mMIMEType;
   int64_t mSizeOfBuffer;
   int mState;
   bool mShutdown;
   bool mDirectConnected;
   Atomic<int> mSuspended;