예제 #1
0
void TrackUnionStream::EndTrack(uint32_t aIndex) {
  StreamTracks::Track* outputTrack =
      mTracks.FindTrack(mTrackMap[aIndex].mOutputTrackID);
  if (!outputTrack || outputTrack->IsEnded()) return;
  STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p ending track %d", this,
                               outputTrack->GetID()));
  outputTrack->SetEnded();
}
예제 #2
0
 void TrackUnionStream::EndTrack(uint32_t aIndex)
 {
   StreamTracks::Track* outputTrack = mTracks.FindTrack(mTrackMap[aIndex].mOutputTrackID);
   if (!outputTrack || outputTrack->IsEnded())
     return;
   STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p ending track %d", this, outputTrack->GetID()));
   for (uint32_t j = 0; j < mListeners.Length(); ++j) {
     MediaStreamListener* l = mListeners[j];
     StreamTime offset = outputTrack->GetSegment()->GetDuration();
     nsAutoPtr<MediaSegment> segment;
     segment = outputTrack->GetSegment()->CreateEmptyClone();
     l->NotifyQueuedTrackChanges(Graph(), outputTrack->GetID(), offset,
                                 TrackEventCommand::TRACK_EVENT_ENDED,
                                 *segment,
                                 mTrackMap[aIndex].mInputPort->GetSource(),
                                 mTrackMap[aIndex].mInputTrackID);
   }
   for (TrackBound<MediaStreamTrackListener>& b : mTrackListeners) {
     if (b.mTrackID == outputTrack->GetID()) {
       b.mListener->NotifyEnded();
     }
   }
   outputTrack->SetEnded();
 }
예제 #3
0
  void TrackUnionStream::CopyTrackData(StreamTracks::Track* aInputTrack,
                     uint32_t aMapIndex, GraphTime aFrom, GraphTime aTo,
                     bool* aOutputTrackFinished)
  {
    TrackMapEntry* map = &mTrackMap[aMapIndex];
    StreamTracks::Track* outputTrack = mTracks.FindTrack(map->mOutputTrackID);
    MOZ_ASSERT(outputTrack && !outputTrack->IsEnded(), "Can't copy to ended track");

    MediaSegment* segment = map->mSegment;
    MediaStream* source = map->mInputPort->GetSource();

    GraphTime next;
    *aOutputTrackFinished = false;
    for (GraphTime t = aFrom; t < aTo; t = next) {
      MediaInputPort::InputInterval interval = map->mInputPort->GetNextInputInterval(t);
      interval.mEnd = std::min(interval.mEnd, aTo);
      StreamTime inputEnd = source->GraphTimeToStreamTimeWithBlocking(interval.mEnd);
      StreamTime inputTrackEndPoint = STREAM_TIME_MAX;

      if (aInputTrack->IsEnded() &&
          aInputTrack->GetEnd() <= inputEnd) {
        inputTrackEndPoint = aInputTrack->GetEnd();
        *aOutputTrackFinished = true;
      }

      if (interval.mStart >= interval.mEnd) {
        break;
      }
      StreamTime ticks = interval.mEnd - interval.mStart;
      next = interval.mEnd;

      StreamTime outputStart = outputTrack->GetEnd();

      if (interval.mInputIsBlocked) {
        // Maybe the input track ended?
        segment->AppendNullData(ticks);
        STREAM_LOG(LogLevel::Verbose, ("TrackUnionStream %p appending %lld ticks of null data to track %d",
                   this, (long long)ticks, outputTrack->GetID()));
      } else if (InMutedCycle()) {
        segment->AppendNullData(ticks);
      } else {
        if (source->IsSuspended()) {
          segment->AppendNullData(aTo - aFrom);
        } else {
          MOZ_ASSERT(outputTrack->GetEnd() == GraphTimeToStreamTimeWithBlocking(interval.mStart),
                     "Samples missing");
          StreamTime inputStart = source->GraphTimeToStreamTimeWithBlocking(interval.mStart);
          segment->AppendSlice(*aInputTrack->GetSegment(),
                               std::min(inputTrackEndPoint, inputStart),
                               std::min(inputTrackEndPoint, inputEnd));
        }
      }
      ApplyTrackDisabling(outputTrack->GetID(), segment);
      for (uint32_t j = 0; j < mListeners.Length(); ++j) {
        MediaStreamListener* l = mListeners[j];
        // Separate Audio and Video.
        if (segment->GetType() == MediaSegment::AUDIO) {
          l->NotifyQueuedAudioData(Graph(), outputTrack->GetID(),
                                   outputStart,
                                   *static_cast<AudioSegment*>(segment),
                                   map->mInputPort->GetSource(),
                                   map->mInputTrackID);
        }
      }
      for (TrackBound<MediaStreamTrackListener>& b : mTrackListeners) {
        if (b.mTrackID != outputTrack->GetID()) {
          continue;
        }
        b.mListener->NotifyQueuedChanges(Graph(), outputStart, *segment);
      }
      outputTrack->GetSegment()->AppendFrom(segment);
    }
  }
예제 #4
0
  uint32_t TrackUnionStream::AddTrack(MediaInputPort* aPort, StreamTracks::Track* aTrack,
                    GraphTime aFrom)
  {
    STREAM_LOG(LogLevel::Verbose, ("TrackUnionStream %p adding track %d for "
                                   "input stream %p track %d, desired id %d",
                                   this, aTrack->GetID(), aPort->GetSource(),
                                   aTrack->GetID(),
                                   aPort->GetDestinationTrackId()));

    TrackID id;
    if (IsTrackIDExplicit(id = aPort->GetDestinationTrackId())) {
      MOZ_ASSERT(id >= mNextAvailableTrackID &&
                 mUsedTracks.BinaryIndexOf(id) == mUsedTracks.NoIndex,
                 "Desired destination id taken. Only provide a destination ID "
                 "if you can assure its availability, or we may not be able "
                 "to bind to the correct DOM-side track.");
#ifdef DEBUG
      for (size_t i = 0; mInputs[i] != aPort; ++i) {
        MOZ_ASSERT(mInputs[i]->GetSourceTrackId() != TRACK_ANY,
                   "You are adding a MediaInputPort with a track mapping "
                   "while there already exist generic MediaInputPorts for this "
                   "destination stream. This can lead to TrackID collisions!");
      }
#endif
      mUsedTracks.InsertElementSorted(id);
    } else if ((id = aTrack->GetID()) &&
               id > mNextAvailableTrackID &&
               mUsedTracks.BinaryIndexOf(id) == mUsedTracks.NoIndex) {
      // Input id available. Mark it used in mUsedTracks.
      mUsedTracks.InsertElementSorted(id);
    } else {
      // No desired destination id and Input id taken, allocate a new one.
      id = mNextAvailableTrackID;

      // Update mNextAvailableTrackID and prune any mUsedTracks members it now
      // covers.
      while (1) {
        if (!mUsedTracks.RemoveElementSorted(++mNextAvailableTrackID)) {
          // Not in use. We're done.
          break;
        }
      }
    }

    // Round up the track start time so the track, if anything, starts a
    // little later than the true time. This means we'll have enough
    // samples in our input stream to go just beyond the destination time.
    StreamTime outputStart = GraphTimeToStreamTimeWithBlocking(aFrom);

    nsAutoPtr<MediaSegment> segment;
    segment = aTrack->GetSegment()->CreateEmptyClone();
    for (uint32_t j = 0; j < mListeners.Length(); ++j) {
      MediaStreamListener* l = mListeners[j];
      l->NotifyQueuedTrackChanges(Graph(), id, outputStart,
                                  TrackEventCommand::TRACK_EVENT_CREATED,
                                  *segment,
                                  aPort->GetSource(), aTrack->GetID());
    }
    segment->AppendNullData(outputStart);
    StreamTracks::Track* track =
      &mTracks.AddTrack(id, outputStart, segment.forget());
    STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p added track %d for input stream %p track %d, start ticks %lld",
                                 this, track->GetID(), aPort->GetSource(), aTrack->GetID(),
                                 (long long)outputStart));

    TrackMapEntry* map = mTrackMap.AppendElement();
    map->mEndOfConsumedInputTicks = 0;
    map->mEndOfLastInputIntervalInInputStream = -1;
    map->mEndOfLastInputIntervalInOutputStream = -1;
    map->mInputPort = aPort;
    map->mInputTrackID = aTrack->GetID();
    map->mOutputTrackID = track->GetID();
    map->mSegment = aTrack->GetSegment()->CreateEmptyClone();

    for (int32_t i = mPendingDirectTrackListeners.Length() - 1; i >= 0; --i) {
      TrackBound<DirectMediaStreamTrackListener>& bound =
        mPendingDirectTrackListeners[i];
      if (bound.mTrackID != map->mOutputTrackID) {
        continue;
      }
      MediaStream* source = map->mInputPort->GetSource();
      map->mOwnedDirectListeners.AppendElement(bound.mListener);
      DisabledTrackMode currentMode = GetDisabledTrackMode(bound.mTrackID);
      if (currentMode != DisabledTrackMode::ENABLED) {
        bound.mListener->IncreaseDisabled(currentMode);
      }
      STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p adding direct listener "
                                   "%p for track %d. Forwarding to input "
                                   "stream %p track %d.",
                                   this, bound.mListener.get(), bound.mTrackID,
                                   source, map->mInputTrackID));
      source->AddDirectTrackListenerImpl(bound.mListener.forget(),
                                         map->mInputTrackID);
      mPendingDirectTrackListeners.RemoveElementAt(i);
    }

    return mTrackMap.Length() - 1;
  }
예제 #5
0
void TrackUnionStream::CopyTrackData(StreamTracks::Track* aInputTrack,
                                     uint32_t aMapIndex, GraphTime aFrom,
                                     GraphTime aTo,
                                     bool* aOutputTrackFinished) {
  TrackMapEntry* map = &mTrackMap[aMapIndex];
  TRACE_AUDIO_CALLBACK_COMMENT(
      "Input stream %p track %i -> TrackUnionStream %p track %i",
      map->mInputPort->GetSource(), map->mInputTrackID, this,
      map->mOutputTrackID);
  StreamTracks::Track* outputTrack = mTracks.FindTrack(map->mOutputTrackID);
  MOZ_ASSERT(outputTrack && !outputTrack->IsEnded(),
             "Can't copy to ended track");

  MediaSegment* segment = map->mSegment;
  MediaStream* source = map->mInputPort->GetSource();

  GraphTime next;
  *aOutputTrackFinished = false;
  for (GraphTime t = aFrom; t < aTo; t = next) {
    MediaInputPort::InputInterval interval =
        map->mInputPort->GetNextInputInterval(t);
    interval.mEnd = std::min(interval.mEnd, aTo);
    StreamTime inputEnd =
        source->GraphTimeToStreamTimeWithBlocking(interval.mEnd);

    if (aInputTrack->IsEnded() && aInputTrack->GetEnd() <= inputEnd) {
      *aOutputTrackFinished = true;
      break;
    }

    if (interval.mStart >= interval.mEnd) {
      break;
    }
    StreamTime ticks = interval.mEnd - interval.mStart;
    next = interval.mEnd;

    StreamTime outputStart = outputTrack->GetEnd();

    if (interval.mInputIsBlocked) {
      segment->AppendNullData(ticks);
      STREAM_LOG(
          LogLevel::Verbose,
          ("TrackUnionStream %p appending %lld ticks of null data to track %d",
           this, (long long)ticks, outputTrack->GetID()));
    } else if (InMutedCycle()) {
      segment->AppendNullData(ticks);
    } else {
      if (source->IsSuspended()) {
        segment->AppendNullData(aTo - aFrom);
      } else {
        MOZ_ASSERT(outputTrack->GetEnd() ==
                       GraphTimeToStreamTimeWithBlocking(interval.mStart),
                   "Samples missing");
        StreamTime inputStart =
            source->GraphTimeToStreamTimeWithBlocking(interval.mStart);
        segment->AppendSlice(*aInputTrack->GetSegment(), inputStart, inputEnd);
      }
    }
    ApplyTrackDisabling(outputTrack->GetID(), segment);
    for (TrackBound<MediaStreamTrackListener>& b : mTrackListeners) {
      if (b.mTrackID != outputTrack->GetID()) {
        continue;
      }
      b.mListener->NotifyQueuedChanges(Graph(), outputStart, *segment);
    }
    outputTrack->GetSegment()->AppendFrom(segment);
  }
}