nsresult ISOMediaWriter::RunState() { nsresult rv; switch (mState) { case MUXING_HEAD: { rv = mControl->GenerateFtyp(); NS_ENSURE_SUCCESS(rv, rv); rv = mControl->GenerateMoov(); NS_ENSURE_SUCCESS(rv, rv); mState = MUXING_FRAG; break; } case MUXING_FRAG: { rv = mControl->GenerateMoof(mType); NS_ENSURE_SUCCESS(rv, rv); bool EOS; if (ReadyToRunState(EOS) && EOS) { mState = MUXING_DONE; } break; } case MUXING_DONE: { break; } } mBlobReady = true; return NS_OK; }
nsresult ISOMediaWriter::WriteEncodedTrack(const EncodedFrameContainer& aData, uint32_t aFlags) { // Muxing complete, it doesn't allowed to reentry again. if (mState == MUXING_DONE) { MOZ_ASSERT(false); return NS_ERROR_FAILURE; } FragmentBuffer* frag = nullptr; uint32_t len = aData.GetEncodedFrames().Length(); if (!len) { // no frame? why bother to WriteEncodedTrack return NS_OK; } for (uint32_t i = 0; i < len; i++) { nsRefPtr<EncodedFrame> frame(aData.GetEncodedFrames()[i]); EncodedFrame::FrameType type = frame->GetFrameType(); if (type == EncodedFrame::AAC_AUDIO_FRAME || type == EncodedFrame::AAC_CSD || type == EncodedFrame::AMR_AUDIO_FRAME || type == EncodedFrame::AMR_AUDIO_CSD) { frag = mAudioFragmentBuffer; } else if (type == EncodedFrame::AVC_I_FRAME || type == EncodedFrame::AVC_P_FRAME || type == EncodedFrame::AVC_B_FRAME || type == EncodedFrame::AVC_CSD) { frag = mVideoFragmentBuffer; } else { MOZ_ASSERT(0); return NS_ERROR_FAILURE; } frag->AddFrame(frame); } // Encoder should send CSD (codec specific data) frame before sending the // audio/video frames. When CSD data is ready, it is sufficient to generate a // moov data. If encoder doesn't send CSD yet, muxer needs to wait before // generating anything. if (mType & Audio_Track && (!mAudioFragmentBuffer || !mAudioFragmentBuffer->HasCSD())) { return NS_OK; } if (mType & Video_Track && (!mVideoFragmentBuffer || !mVideoFragmentBuffer->HasCSD())) { return NS_OK; } // Only one FrameType in EncodedFrameContainer so it doesn't need to be // inside the for-loop. if (frag && (aFlags & END_OF_STREAM)) { frag->SetEndOfStream(); } nsresult rv; bool EOS; if (ReadyToRunState(EOS)) { // TODO: // The MediaEncoder doesn't use nsRunnable, so thread will be // stocked on that part and the new added nsRunnable won't get to run // before MediaEncoder completing. Before MediaEncoder change, it needs // to call RunState directly. // https://bugzilla.mozilla.org/show_bug.cgi?id=950429 rv = RunState(); NS_ENSURE_SUCCESS(rv, rv); } return NS_OK; }
nsresult ISOMediaWriter::WriteEncodedTrack(const EncodedFrameContainer& aData, uint32_t aFlags) { PROFILER_LABEL("ISOMediaWriter", "WriteEncodedTrack", js::ProfileEntry::Category::OTHER); // Muxing complete, it doesn't allowed to reentry again. if (mState == MUXING_DONE) { MOZ_ASSERT(false); return NS_ERROR_FAILURE; } FragmentBuffer* frag = nullptr; uint32_t len = aData.GetEncodedFrames().Length(); if (!len) { // no frame? why bother to WriteEncodedTrack return NS_OK; } for (uint32_t i = 0; i < len; i++) { nsRefPtr<EncodedFrame> frame(aData.GetEncodedFrames()[i]); EncodedFrame::FrameType type = frame->GetFrameType(); if (type == EncodedFrame::AAC_AUDIO_FRAME || type == EncodedFrame::AAC_CSD || type == EncodedFrame::AMR_AUDIO_FRAME || type == EncodedFrame::AMR_AUDIO_CSD) { frag = mAudioFragmentBuffer; } else if (type == EncodedFrame::AVC_I_FRAME || type == EncodedFrame::AVC_P_FRAME || type == EncodedFrame::AVC_B_FRAME || type == EncodedFrame::AVC_CSD) { frag = mVideoFragmentBuffer; } else { MOZ_ASSERT(0); return NS_ERROR_FAILURE; } frag->AddFrame(frame); } // Encoder should send CSD (codec specific data) frame before sending the // audio/video frames. When CSD data is ready, it is sufficient to generate a // moov data. If encoder doesn't send CSD yet, muxer needs to wait before // generating anything. if (mType & Audio_Track && (!mAudioFragmentBuffer || !mAudioFragmentBuffer->HasCSD())) { return NS_OK; } if (mType & Video_Track && (!mVideoFragmentBuffer || !mVideoFragmentBuffer->HasCSD())) { return NS_OK; } // Only one FrameType in EncodedFrameContainer so it doesn't need to be // inside the for-loop. if (frag && (aFlags & END_OF_STREAM)) { frag->SetEndOfStream(); } nsresult rv; bool EOS; if (ReadyToRunState(EOS)) { // Because track encoder won't generate new data after EOS, it needs to make // sure the state reaches MUXING_DONE when EOS is signaled. do { rv = RunState(); } while (EOS && mState != MUXING_DONE); NS_ENSURE_SUCCESS(rv, rv); } return NS_OK; }