Example #1
0
void
SourceBuffer::AppendData(LargeDataBuffer* aData, double aTimestampOffset,
                         uint32_t aUpdateID)
{
  if (!mUpdating || aUpdateID != mUpdateID) {
    // The buffer append algorithm has been interrupted by abort().
    //
    // If the sequence appendBuffer(), abort(), appendBuffer() occurs before
    // the first StopUpdating() runnable runs, then a second StopUpdating()
    // runnable will be scheduled, but still only one (the first) will queue
    // events.
    return;
  }

  MOZ_ASSERT(mMediaSource);
  MOZ_ASSERT(!mPendingAppend.Exists());

  if (!aData->Length()) {
    StopUpdating();
    return;
  }

  mPendingAppend.Begin(mTrackBuffer->AppendData(aData, aTimestampOffset * USECS_PER_S)
                       ->RefableThen(NS_GetCurrentThread(), __func__, this,
                                     &SourceBuffer::AppendDataCompletedWithSuccess,
                                     &SourceBuffer::AppendDataErrored));
}
Example #2
0
void
SourceBuffer::AppendDataCompletedWithSuccess(SourceBufferTask::AppendBufferResult aResult)
{
  MOZ_ASSERT(mUpdating);
  mPendingAppend.Complete();

  if (aResult.first()) {
    if (!mActive) {
      mActive = true;
      mMediaSource->SourceBufferIsActive(this);
    }
  }
  if (mActive) {
    // Tell our parent decoder that we have received new data.
    mMediaSource->GetDecoder()->NotifyDataArrived();
    // Send progress event.
    mMediaSource->GetDecoder()->NotifyBytesDownloaded();
  }

  mCurrentAttributes = aResult.second();

  CheckEndTime();

  StopUpdating();
}
Example #3
0
void
SourceBuffer::AppendDataCompletedWithSuccess(bool aHasActiveTracks)
{
    mPendingAppend.Complete();
    if (!mUpdating) {
        // The buffer append algorithm has been interrupted by abort().
        return;
    }

    if (aHasActiveTracks) {
        if (!mActive) {
            mActive = true;
            mMediaSource->SourceBufferIsActive(this);
            mMediaSource->QueueInitializationEvent();
            if (mIsUsingFormatReader) {
                mMediaSource->GetDecoder()->NotifyWaitingForResourcesStatusChanged();
            }
        }
    }
    if (mActive && mIsUsingFormatReader) {
        // Tell our parent decoder that we have received new data.
        // The information provided do not matter much so long as it is monotonically
        // increasing.
        mMediaSource->GetDecoder()->NotifyDataArrived(1, mReportedOffset++, /* aThrottleUpdates = */ false);
        // Send progress event.
        mMediaSource->GetDecoder()->NotifyBytesDownloaded();
    }

    CheckEndTime();

    StopUpdating();
}
Example #4
0
void
SourceBuffer::AppendDataCompletedWithSuccess(bool aHasActiveTracks)
{
  mPendingAppend.Complete();
  if (!mUpdating) {
    // The buffer append algorithm has been interrupted by abort().
    return;
  }

  if (aHasActiveTracks) {
    if (!mActive) {
      mActive = true;
      mMediaSource->SourceBufferIsActive(this);
    }
  }
  if (mActive) {
    // Tell our parent decoder that we have received new data.
    mMediaSource->GetDecoder()->NotifyDataArrived();
    // Send progress event.
    mMediaSource->GetDecoder()->NotifyBytesDownloaded();
  }

  CheckEndTime();

  StopUpdating();
}
void
SourceBuffer::Remove(double aStart, double aEnd, ErrorResult& aRv)
{
  if (!IsAttached() || mUpdating ||
      mMediaSource->ReadyState() != MediaSourceReadyState::Open) {
    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    return;
  }
  if (aStart < 0 || aStart > mMediaSource->Duration() ||
      aEnd <= aStart) {
    aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
    return;
  }
  StartUpdating();
  /// TODO: Run coded frame removal algorithm asynchronously (would call StopUpdating()).
  StopUpdating();
}
void
SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv)
{
  if (!IsAttached() || mUpdating) {
    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    return;
  }
  if (mMediaSource->ReadyState() == MediaSourceReadyState::Ended) {
    mMediaSource->SetReadyState(MediaSourceReadyState::Open);
  }
  // TODO: Run coded frame eviction algorithm.
  // TODO: Test buffer full flag.
  MSE_DEBUG("%p Append(ArrayBuffer=%u)", this, aLength);
  StartUpdating();
  // XXX: For future reference: NDA call must run on the main thread.
  mDecoder->NotifyDataArrived(reinterpret_cast<const char*>(aData),
                              aLength,
                              mDecoder->GetResource()->GetLength());
  // TODO: Run buffer append algorithm asynchronously (would call StopUpdating()).
  mDecoder->GetResource()->AppendData(aData, aLength);

  // Eviction uses a byte threshold. If the buffer is greater than the
  // number of bytes then data is evicted. The time range for this
  // eviction is reported back to the media source. It will then
  // evict data before that range across all SourceBuffer's it knows
  // about.
  const int evict_threshold = 1000000;
  bool evicted = mDecoder->GetResource()->EvictData(evict_threshold);
  if (evicted) {
    double start = 0.0;
    double end = 0.0;
    GetBufferedStartEndTime(&start, &end);

    // We notify that we've evicted from the time range 0 through to
    // the current start point.
    mMediaSource->NotifyEvicted(0.0, start);
  }
  StopUpdating();

  // Schedule the state machine thread to ensure playback starts
  // if required when data is appended.
  mMediaSource->GetDecoder()->ScheduleStateMachineThread();
}
Example #7
0
void
SourceBuffer::Remove(double aStart, double aEnd, ErrorResult& aRv)
{
  MOZ_ASSERT(NS_IsMainThread());
  MSE_API("SourceBuffer(%p)::Remove(aStart=%f, aEnd=%f)", this, aStart, aEnd);
  if (IsNaN(mMediaSource->Duration()) ||
      aStart < 0 || aStart > mMediaSource->Duration() ||
      aEnd <= aStart || IsNaN(aEnd)) {
    aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
    return;
  }
  if (!IsAttached() || mUpdating ||
      mMediaSource->ReadyState() != MediaSourceReadyState::Open) {
    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    return;
  }
  StartUpdating();
  /// TODO: Run coded frame removal algorithm asynchronously (would call StopUpdating()).
  StopUpdating();
}
Example #8
0
void
SourceBuffer::AppendDataCompletedWithSuccess(bool aGotMedia)
{
  mPendingAppend.Complete();
  if (!mUpdating) {
    // The buffer append algorithm has been interrupted by abort().
    return;
  }

  if (mTrackBuffer->HasInitSegment()) {
    if (!mActive) {
      mActive = true;
      mMediaSource->SourceBufferIsActive(this);
      mMediaSource->QueueInitializationEvent();
    }
  }

  if (aGotMedia) {
    CheckEndTime();
  }

  StopUpdating();
}
Example #9
0
void
SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv)
{
  MSE_DEBUG("SourceBuffer(%p)::AppendData(aLength=%u)", this, aLength);
  if (!IsAttached() || mUpdating) {
    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    return;
  }
  if (mMediaSource->ReadyState() == MediaSourceReadyState::Ended) {
    mMediaSource->SetReadyState(MediaSourceReadyState::Open);
  }
  // TODO: Run coded frame eviction algorithm.
  // TODO: Test buffer full flag.
  StartUpdating();
  // TODO: Run buffer append algorithm asynchronously (would call StopUpdating()).
  if (mParser->IsInitSegmentPresent(aData, aLength)) {
    MSE_DEBUG("SourceBuffer(%p)::AppendData: New initialization segment.", this);
    if (mDecoderInitialized) {
      // Existing decoder has been used, time for a new one.
      DiscardDecoder();
    }

    // If we've got a decoder here, it's not initialized, so we can use it
    // rather than creating a new one.
    if (!mDecoder && !InitNewDecoder()) {
      aRv.Throw(NS_ERROR_FAILURE); // XXX: Review error handling.
      return;
    }
    MSE_DEBUG("SourceBuffer(%p)::AppendData: Decoder marked as initialized.", this);
    mDecoderInitialized = true;
  } else if (!mDecoderInitialized) {
    MSE_DEBUG("SourceBuffer(%p)::AppendData: Non-init segment appended during initialization.");
    Optional<MediaSourceEndOfStreamError> decodeError(MediaSourceEndOfStreamError::Decode);
    ErrorResult dummy;
    mMediaSource->EndOfStream(decodeError, dummy);
    aRv.Throw(NS_ERROR_FAILURE);
    return;
  }
  // XXX: For future reference: NDA call must run on the main thread.
  mDecoder->NotifyDataArrived(reinterpret_cast<const char*>(aData),
                              aLength,
                              mDecoder->GetResource()->GetLength());
  mDecoder->GetResource()->AppendData(aData, aLength);

  // Eviction uses a byte threshold. If the buffer is greater than the
  // number of bytes then data is evicted. The time range for this
  // eviction is reported back to the media source. It will then
  // evict data before that range across all SourceBuffers it knows
  // about.
  // TODO: Make the eviction threshold smaller for audio-only streams.
  // TODO: Drive evictions off memory pressure notifications.
  const uint32_t evict_threshold = 75 * (1 << 20);
  bool evicted = mDecoder->GetResource()->EvictData(evict_threshold);
  if (evicted) {
    MSE_DEBUG("SourceBuffer(%p)::AppendBuffer Evict; current buffered start=%f",
              this, GetBufferedStart());

    // We notify that we've evicted from the time range 0 through to
    // the current start point.
    mMediaSource->NotifyEvicted(0.0, GetBufferedStart());
  }
  StopUpdating();

  // Schedule the state machine thread to ensure playback starts
  // if required when data is appended.
  mMediaSource->GetDecoder()->ScheduleStateMachineThread();

  mMediaSource->NotifyGotData();
}