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;
}
예제 #3
0
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;
}