Bug 1014393 - WIP: separate MediaEncoders encoder and mux steps
MozReview-Commit-ID: 8jjMayZhDcN
--- 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;