123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #ifndef MOZILLA_TRACKBUFFERSMANAGER_H_
- #define MOZILLA_TRACKBUFFERSMANAGER_H_
- #include "mozilla/Atomics.h"
- #include "mozilla/Maybe.h"
- #include "mozilla/Monitor.h"
- #include "AutoTaskQueue.h"
- #include "mozilla/dom/SourceBufferBinding.h"
- #include "MediaData.h"
- #include "MediaDataDemuxer.h"
- #include "MediaResult.h"
- #include "MediaSourceDecoder.h"
- #include "SourceBufferTask.h"
- #include "TimeUnits.h"
- #include "nsAutoPtr.h"
- #include "nsProxyRelease.h"
- #include "nsString.h"
- #include "nsTArray.h"
- namespace mozilla {
- class ContainerParser;
- class MediaByteBuffer;
- class MediaRawData;
- class MediaSourceDemuxer;
- class SourceBufferResource;
- class SourceBufferTaskQueue
- {
- public:
- SourceBufferTaskQueue()
- : mMonitor("SourceBufferTaskQueue")
- {}
- ~SourceBufferTaskQueue()
- {
- MOZ_ASSERT(mQueue.IsEmpty(), "All tasks must have been processed");
- }
- void Push(SourceBufferTask* aTask)
- {
- MonitorAutoLock mon(mMonitor);
- mQueue.AppendElement(aTask);
- }
- already_AddRefed<SourceBufferTask> Pop()
- {
- MonitorAutoLock mon(mMonitor);
- if (!mQueue.Length()) {
- return nullptr;
- }
- RefPtr<SourceBufferTask> task = Move(mQueue[0]);
- mQueue.RemoveElementAt(0);
- return task.forget();
- }
- nsTArray<SourceBufferTask>::size_type Length() const
- {
- MonitorAutoLock mon(mMonitor);
- return mQueue.Length();
- }
- private:
- mutable Monitor mMonitor;
- nsTArray<RefPtr<SourceBufferTask>> mQueue;
- };
- class TrackBuffersManager
- {
- public:
- NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TrackBuffersManager);
- enum class EvictDataResult : int8_t
- {
- NO_DATA_EVICTED,
- CANT_EVICT,
- BUFFER_FULL,
- };
- typedef TrackInfo::TrackType TrackType;
- typedef MediaData::Type MediaType;
- typedef nsTArray<RefPtr<MediaRawData>> TrackBuffer;
- typedef SourceBufferTask::AppendPromise AppendPromise;
- typedef SourceBufferTask::RangeRemovalPromise RangeRemovalPromise;
- // Interface for SourceBuffer
- TrackBuffersManager(MediaSourceDecoder* aParentDecoder,
- const nsACString& aType);
- // Queue a task to add data to the end of the input buffer and run the MSE
- // Buffer Append Algorithm
- // 3.5.5 Buffer Append Algorithm.
- // http://w3c.github.io/media-source/index.html#sourcebuffer-buffer-append
- RefPtr<AppendPromise> AppendData(MediaByteBuffer* aData,
- const SourceBufferAttributes& aAttributes);
- // Queue a task to abort any pending AppendData.
- // Does nothing at this stage.
- void AbortAppendData();
- // Queue a task to run MSE Reset Parser State Algorithm.
- // 3.5.2 Reset Parser State
- void ResetParserState(SourceBufferAttributes& aAttributes);
- // Queue a task to run the MSE range removal algorithm.
- // http://w3c.github.io/media-source/#sourcebuffer-coded-frame-removal
- RefPtr<RangeRemovalPromise> RangeRemoval(media::TimeUnit aStart,
- media::TimeUnit aEnd);
- // Schedule data eviction if necessary as the next call to AppendData will
- // add aSize bytes.
- // Eviction is done in two steps, first remove data up to aPlaybackTime
- // and if still more space is needed remove from the end.
- EvictDataResult EvictData(const media::TimeUnit& aPlaybackTime, int64_t aSize);
- // Returns the buffered range currently managed.
- // This may be called on any thread.
- // Buffered must conform to http://w3c.github.io/media-source/index.html#widl-SourceBuffer-buffered
- media::TimeIntervals Buffered() const;
- media::TimeUnit HighestStartTime() const;
- media::TimeUnit HighestEndTime() const;
- // Return the size of the data managed by this SourceBufferContentManager.
- int64_t GetSize() const;
- // Indicate that the MediaSource parent object got into "ended" state.
- void Ended();
- // The parent SourceBuffer is about to be destroyed.
- void Detach();
- int64_t EvictionThreshold() const;
- // Interface for MediaSourceDemuxer
- MediaInfo GetMetadata() const;
- const TrackBuffer& GetTrackBuffer(TrackInfo::TrackType aTrack) const;
- const media::TimeIntervals& Buffered(TrackInfo::TrackType) const;
- const media::TimeUnit& HighestStartTime(TrackInfo::TrackType) const;
- media::TimeIntervals SafeBuffered(TrackInfo::TrackType) const;
- bool IsEnded() const
- {
- return mEnded;
- }
- uint32_t Evictable(TrackInfo::TrackType aTrack) const;
- media::TimeUnit Seek(TrackInfo::TrackType aTrack,
- const media::TimeUnit& aTime,
- const media::TimeUnit& aFuzz);
- uint32_t SkipToNextRandomAccessPoint(TrackInfo::TrackType aTrack,
- const media::TimeUnit& aTimeThreadshold,
- const media::TimeUnit& aFuzz,
- bool& aFound);
- already_AddRefed<MediaRawData> GetSample(TrackInfo::TrackType aTrack,
- const media::TimeUnit& aFuzz,
- MediaResult& aResult);
- int32_t FindCurrentPosition(TrackInfo::TrackType aTrack,
- const media::TimeUnit& aFuzz) const;
- media::TimeUnit GetNextRandomAccessPoint(TrackInfo::TrackType aTrack,
- const media::TimeUnit& aFuzz);
- void AddSizeOfResources(MediaSourceDecoder::ResourceSizes* aSizes) const;
- private:
- typedef MozPromise<bool, MediaResult, /* IsExclusive = */ true> CodedFrameProcessingPromise;
- // for MediaSourceDemuxer::GetMozDebugReaderData
- friend class MediaSourceDemuxer;
- ~TrackBuffersManager();
- // All following functions run on the taskqueue.
- RefPtr<AppendPromise> DoAppendData(RefPtr<MediaByteBuffer> aData,
- SourceBufferAttributes aAttributes);
- void ScheduleSegmentParserLoop();
- void SegmentParserLoop();
- void InitializationSegmentReceived();
- void ShutdownDemuxers();
- void CreateDemuxerforMIMEType();
- void ResetDemuxingState();
- void NeedMoreData();
- void RejectAppend(const MediaResult& aRejectValue, const char* aName);
- // Will return a promise that will be resolved once all frames of the current
- // media segment have been processed.
- RefPtr<CodedFrameProcessingPromise> CodedFrameProcessing();
- void CompleteCodedFrameProcessing();
- // Called by ResetParserState.
- void CompleteResetParserState();
- RefPtr<RangeRemovalPromise>
- CodedFrameRemovalWithPromise(media::TimeInterval aInterval);
- bool CodedFrameRemoval(media::TimeInterval aInterval);
- void SetAppendState(SourceBufferAttributes::AppendState aAppendState);
- bool HasVideo() const
- {
- return mVideoTracks.mNumTracks > 0;
- }
- bool HasAudio() const
- {
- return mAudioTracks.mNumTracks > 0;
- }
- // The input buffer as per http://w3c.github.io/media-source/index.html#sourcebuffer-input-buffer
- RefPtr<MediaByteBuffer> mInputBuffer;
- // Buffer full flag as per https://w3c.github.io/media-source/#sourcebuffer-buffer-full-flag.
- // Accessed on both the main thread and the task queue.
- Atomic<bool> mBufferFull;
- bool mFirstInitializationSegmentReceived;
- // Set to true once a new segment is started.
- bool mNewMediaSegmentStarted;
- bool mActiveTrack;
- nsCString mType;
- // ContainerParser objects and methods.
- // Those are used to parse the incoming input buffer.
- // Recreate the ContainerParser and if aReuseInitData is true then
- // feed it with the previous init segment found.
- void RecreateParser(bool aReuseInitData);
- nsAutoPtr<ContainerParser> mParser;
- // Demuxer objects and methods.
- void AppendDataToCurrentInputBuffer(MediaByteBuffer* aData);
- RefPtr<MediaByteBuffer> mInitData;
- // Temporary input buffer to handle partial media segment header.
- // We store the current input buffer content into it should we need to
- // reinitialize the demuxer once we have some samples and a discontinuity is
- // detected.
- RefPtr<MediaByteBuffer> mPendingInputBuffer;
- RefPtr<SourceBufferResource> mCurrentInputBuffer;
- RefPtr<MediaDataDemuxer> mInputDemuxer;
- // Length already processed in current media segment.
- uint64_t mProcessedInput;
- Maybe<media::TimeUnit> mLastParsedEndTime;
- void OnDemuxerInitDone(nsresult);
- void OnDemuxerInitFailed(const MediaResult& aFailure);
- void OnDemuxerResetDone(nsresult);
- MozPromiseRequestHolder<MediaDataDemuxer::InitPromise> mDemuxerInitRequest;
- void OnDemuxFailed(TrackType aTrack, const MediaResult& aError);
- void DoDemuxVideo();
- void OnVideoDemuxCompleted(RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples);
- void OnVideoDemuxFailed(const MediaResult& aError)
- {
- mVideoTracks.mDemuxRequest.Complete();
- OnDemuxFailed(TrackType::kVideoTrack, aError);
- }
- void DoDemuxAudio();
- void OnAudioDemuxCompleted(RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples);
- void OnAudioDemuxFailed(const MediaResult& aError)
- {
- mAudioTracks.mDemuxRequest.Complete();
- OnDemuxFailed(TrackType::kAudioTrack, aError);
- }
- void DoEvictData(const media::TimeUnit& aPlaybackTime, int64_t aSizeToEvict);
- struct TrackData
- {
- TrackData()
- : mNumTracks(0)
- , mNeedRandomAccessPoint(true)
- , mSizeBuffer(0)
- {}
- uint32_t mNumTracks;
- // Definition of variables:
- // https://w3c.github.io/media-source/#track-buffers
- // Last decode timestamp variable that stores the decode timestamp of the
- // last coded frame appended in the current coded frame group.
- // The variable is initially unset to indicate that no coded frames have
- // been appended yet.
- Maybe<media::TimeUnit> mLastDecodeTimestamp;
- // Last frame duration variable that stores the coded frame duration of the
- // last coded frame appended in the current coded frame group.
- // The variable is initially unset to indicate that no coded frames have
- // been appended yet.
- Maybe<media::TimeUnit> mLastFrameDuration;
- // Highest end timestamp variable that stores the highest coded frame end
- // timestamp across all coded frames in the current coded frame group that
- // were appended to this track buffer.
- // The variable is initially unset to indicate that no coded frames have
- // been appended yet.
- Maybe<media::TimeUnit> mHighestEndTimestamp;
- // Highest presentation timestamp in track buffer.
- // Protected by global monitor, except when reading on the task queue as it
- // is only written there.
- media::TimeUnit mHighestStartTimestamp;
- // Longest frame duration seen since last random access point.
- // Only ever accessed when mLastDecodeTimestamp and mLastFrameDuration are
- // set.
- media::TimeUnit mLongestFrameDuration;
- // Need random access point flag variable that keeps track of whether the
- // track buffer is waiting for a random access point coded frame.
- // The variable is initially set to true to indicate that random access
- // point coded frame is needed before anything can be added to the track
- // buffer.
- bool mNeedRandomAccessPoint;
- RefPtr<MediaTrackDemuxer> mDemuxer;
- MozPromiseRequestHolder<MediaTrackDemuxer::SamplesPromise> mDemuxRequest;
- // Highest end timestamp of the last media segment demuxed.
- media::TimeUnit mLastParsedEndTime;
- // If set, position where the next contiguous frame will be inserted.
- // If a discontinuity is detected, it will be unset and recalculated upon
- // the next insertion.
- Maybe<uint32_t> mNextInsertionIndex;
- // Samples just demuxed, but not yet parsed.
- TrackBuffer mQueuedSamples;
- const TrackBuffer& GetTrackBuffer() const
- {
- MOZ_RELEASE_ASSERT(mBuffers.Length(),
- "TrackBuffer must have been created");
- return mBuffers.LastElement();
- }
- TrackBuffer& GetTrackBuffer()
- {
- MOZ_RELEASE_ASSERT(mBuffers.Length(),
- "TrackBuffer must have been created");
- return mBuffers.LastElement();
- }
- // We only manage a single track of each type at this time.
- nsTArray<TrackBuffer> mBuffers;
- // Track buffer ranges variable that represents the presentation time ranges
- // occupied by the coded frames currently stored in the track buffer.
- media::TimeIntervals mBufferedRanges;
- // Sanitized mBufferedRanges with a fuzz of half a sample's duration applied
- // This buffered ranges is the basis of what is exposed to the JS.
- media::TimeIntervals mSanitizedBufferedRanges;
- // Byte size of all samples contained in this track buffer.
- uint32_t mSizeBuffer;
- // TrackInfo of the first metadata received.
- RefPtr<SharedTrackInfo> mInfo;
- // TrackInfo of the last metadata parsed (updated with each init segment.
- RefPtr<SharedTrackInfo> mLastInfo;
- // If set, position of the next sample to be retrieved by GetSample().
- // If the position is equal to the TrackBuffer's length, it indicates that
- // we've reached EOS.
- Maybe<uint32_t> mNextGetSampleIndex;
- // Approximation of the next sample's decode timestamp.
- media::TimeUnit mNextSampleTimecode;
- // Approximation of the next sample's presentation timestamp.
- media::TimeUnit mNextSampleTime;
- struct EvictionIndex
- {
- EvictionIndex() { Reset(); }
- void Reset()
- {
- mEvictable = 0;
- mLastIndex = 0;
- }
- uint32_t mEvictable;
- uint32_t mLastIndex;
- };
- // Size of data that can be safely evicted during the next eviction
- // cycle.
- // We consider as evictable all frames up to the last keyframe prior to
- // mNextGetSampleIndex. If mNextGetSampleIndex isn't set, then we assume
- // that we can't yet evict data.
- // Protected by global monitor, except when reading on the task queue as it
- // is only written there.
- EvictionIndex mEvictionIndex;
- void ResetAppendState()
- {
- mLastDecodeTimestamp.reset();
- mLastFrameDuration.reset();
- mHighestEndTimestamp.reset();
- mNeedRandomAccessPoint = true;
- mNextInsertionIndex.reset();
- }
- void AddSizeOfResources(MediaSourceDecoder::ResourceSizes* aSizes) const;
- };
- void CheckSequenceDiscontinuity(const media::TimeUnit& aPresentationTime);
- void ProcessFrames(TrackBuffer& aSamples, TrackData& aTrackData);
- media::TimeInterval PresentationInterval(const TrackBuffer& aSamples) const;
- bool CheckNextInsertionIndex(TrackData& aTrackData,
- const media::TimeUnit& aSampleTime);
- void InsertFrames(TrackBuffer& aSamples,
- const media::TimeIntervals& aIntervals,
- TrackData& aTrackData);
- void UpdateHighestTimestamp(TrackData& aTrackData,
- const media::TimeUnit& aHighestTime);
- // Remove all frames and their dependencies contained in aIntervals.
- // Return the index at which frames were first removed or 0 if no frames
- // removed.
- uint32_t RemoveFrames(const media::TimeIntervals& aIntervals,
- TrackData& aTrackData,
- uint32_t aStartIndex);
- // Recalculate track's evictable amount.
- void ResetEvictionIndex(TrackData& aTrackData);
- void UpdateEvictionIndex(TrackData& aTrackData, uint32_t aCurrentIndex);
- // Find index of sample. Return a negative value if not found.
- uint32_t FindSampleIndex(const TrackBuffer& aTrackBuffer,
- const media::TimeInterval& aInterval);
- const MediaRawData* GetSample(TrackInfo::TrackType aTrack,
- uint32_t aIndex,
- const media::TimeUnit& aExpectedDts,
- const media::TimeUnit& aExpectedPts,
- const media::TimeUnit& aFuzz);
- void UpdateBufferedRanges();
- void RejectProcessing(const MediaResult& aRejectValue, const char* aName);
- void ResolveProcessing(bool aResolveValue, const char* aName);
- MozPromiseRequestHolder<CodedFrameProcessingPromise> mProcessingRequest;
- MozPromiseHolder<CodedFrameProcessingPromise> mProcessingPromise;
- // Trackbuffers definition.
- nsTArray<const TrackData*> GetTracksList() const;
- nsTArray<TrackData*> GetTracksList();
- TrackData& GetTracksData(TrackType aTrack)
- {
- switch(aTrack) {
- case TrackType::kVideoTrack:
- return mVideoTracks;
- case TrackType::kAudioTrack:
- default:
- return mAudioTracks;
- }
- }
- const TrackData& GetTracksData(TrackType aTrack) const
- {
- switch(aTrack) {
- case TrackType::kVideoTrack:
- return mVideoTracks;
- case TrackType::kAudioTrack:
- default:
- return mAudioTracks;
- }
- }
- TrackData mVideoTracks;
- TrackData mAudioTracks;
- // TaskQueue methods and objects.
- AbstractThread* GetTaskQueue() const
- {
- return mTaskQueue;
- }
- bool OnTaskQueue() const
- {
- return !GetTaskQueue() || GetTaskQueue()->IsCurrentThreadIn();
- }
- RefPtr<AutoTaskQueue> mTaskQueue;
- // SourceBuffer Queues and running context.
- SourceBufferTaskQueue mQueue;
- void QueueTask(SourceBufferTask* aTask);
- void ProcessTasks();
- // Set if the TrackBuffersManager is currently processing a task.
- // At this stage, this task is always a AppendBufferTask.
- RefPtr<SourceBufferTask> mCurrentTask;
- // Current SourceBuffer state for ongoing task.
- // Its content is returned to the SourceBuffer once the AppendBufferTask has
- // completed.
- UniquePtr<SourceBufferAttributes> mSourceBufferAttributes;
- // The current sourcebuffer append window. It's content is equivalent to
- // mSourceBufferAttributes.mAppendWindowStart/End
- media::TimeInterval mAppendWindow;
- // Strong references to external objects.
- nsMainThreadPtrHandle<MediaSourceDecoder> mParentDecoder;
- // Return public highest end time across all aTracks.
- // Monitor must be held.
- media::TimeUnit HighestEndTime(nsTArray<const media::TimeIntervals*>& aTracks) const;
- // Set to true if mediasource state changed to ended.
- Atomic<bool> mEnded;
- // Global size of this source buffer content.
- Atomic<int64_t> mSizeSourceBuffer;
- const int64_t mVideoEvictionThreshold;
- const int64_t mAudioEvictionThreshold;
- enum class EvictionState
- {
- NO_EVICTION_NEEDED,
- EVICTION_NEEDED,
- EVICTION_COMPLETED,
- };
- Atomic<EvictionState> mEvictionState;
- // Monitor to protect following objects accessed across multiple threads.
- mutable Monitor mMonitor;
- // Stable audio and video track time ranges.
- media::TimeIntervals mVideoBufferedRanges;
- media::TimeIntervals mAudioBufferedRanges;
- // MediaInfo of the first init segment read.
- MediaInfo mInfo;
- };
- } // namespace mozilla
- #endif /* MOZILLA_TRACKBUFFERSMANAGER_H_ */
|