TrackBuffersManager.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #ifndef MOZILLA_TRACKBUFFERSMANAGER_H_
  6. #define MOZILLA_TRACKBUFFERSMANAGER_H_
  7. #include "mozilla/Atomics.h"
  8. #include "mozilla/Maybe.h"
  9. #include "mozilla/Monitor.h"
  10. #include "AutoTaskQueue.h"
  11. #include "mozilla/dom/SourceBufferBinding.h"
  12. #include "MediaData.h"
  13. #include "MediaDataDemuxer.h"
  14. #include "MediaResult.h"
  15. #include "MediaSourceDecoder.h"
  16. #include "SourceBufferTask.h"
  17. #include "TimeUnits.h"
  18. #include "nsAutoPtr.h"
  19. #include "nsProxyRelease.h"
  20. #include "nsString.h"
  21. #include "nsTArray.h"
  22. namespace mozilla {
  23. class ContainerParser;
  24. class MediaByteBuffer;
  25. class MediaRawData;
  26. class MediaSourceDemuxer;
  27. class SourceBufferResource;
  28. class SourceBufferTaskQueue
  29. {
  30. public:
  31. SourceBufferTaskQueue()
  32. : mMonitor("SourceBufferTaskQueue")
  33. {}
  34. ~SourceBufferTaskQueue()
  35. {
  36. MOZ_ASSERT(mQueue.IsEmpty(), "All tasks must have been processed");
  37. }
  38. void Push(SourceBufferTask* aTask)
  39. {
  40. MonitorAutoLock mon(mMonitor);
  41. mQueue.AppendElement(aTask);
  42. }
  43. already_AddRefed<SourceBufferTask> Pop()
  44. {
  45. MonitorAutoLock mon(mMonitor);
  46. if (!mQueue.Length()) {
  47. return nullptr;
  48. }
  49. RefPtr<SourceBufferTask> task = Move(mQueue[0]);
  50. mQueue.RemoveElementAt(0);
  51. return task.forget();
  52. }
  53. nsTArray<SourceBufferTask>::size_type Length() const
  54. {
  55. MonitorAutoLock mon(mMonitor);
  56. return mQueue.Length();
  57. }
  58. private:
  59. mutable Monitor mMonitor;
  60. nsTArray<RefPtr<SourceBufferTask>> mQueue;
  61. };
  62. class TrackBuffersManager
  63. {
  64. public:
  65. NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TrackBuffersManager);
  66. enum class EvictDataResult : int8_t
  67. {
  68. NO_DATA_EVICTED,
  69. CANT_EVICT,
  70. BUFFER_FULL,
  71. };
  72. typedef TrackInfo::TrackType TrackType;
  73. typedef MediaData::Type MediaType;
  74. typedef nsTArray<RefPtr<MediaRawData>> TrackBuffer;
  75. typedef SourceBufferTask::AppendPromise AppendPromise;
  76. typedef SourceBufferTask::RangeRemovalPromise RangeRemovalPromise;
  77. // Interface for SourceBuffer
  78. TrackBuffersManager(MediaSourceDecoder* aParentDecoder,
  79. const nsACString& aType);
  80. // Queue a task to add data to the end of the input buffer and run the MSE
  81. // Buffer Append Algorithm
  82. // 3.5.5 Buffer Append Algorithm.
  83. // http://w3c.github.io/media-source/index.html#sourcebuffer-buffer-append
  84. RefPtr<AppendPromise> AppendData(MediaByteBuffer* aData,
  85. const SourceBufferAttributes& aAttributes);
  86. // Queue a task to abort any pending AppendData.
  87. // Does nothing at this stage.
  88. void AbortAppendData();
  89. // Queue a task to run MSE Reset Parser State Algorithm.
  90. // 3.5.2 Reset Parser State
  91. void ResetParserState(SourceBufferAttributes& aAttributes);
  92. // Queue a task to run the MSE range removal algorithm.
  93. // http://w3c.github.io/media-source/#sourcebuffer-coded-frame-removal
  94. RefPtr<RangeRemovalPromise> RangeRemoval(media::TimeUnit aStart,
  95. media::TimeUnit aEnd);
  96. // Schedule data eviction if necessary as the next call to AppendData will
  97. // add aSize bytes.
  98. // Eviction is done in two steps, first remove data up to aPlaybackTime
  99. // and if still more space is needed remove from the end.
  100. EvictDataResult EvictData(const media::TimeUnit& aPlaybackTime, int64_t aSize);
  101. // Returns the buffered range currently managed.
  102. // This may be called on any thread.
  103. // Buffered must conform to http://w3c.github.io/media-source/index.html#widl-SourceBuffer-buffered
  104. media::TimeIntervals Buffered() const;
  105. media::TimeUnit HighestStartTime() const;
  106. media::TimeUnit HighestEndTime() const;
  107. // Return the size of the data managed by this SourceBufferContentManager.
  108. int64_t GetSize() const;
  109. // Indicate that the MediaSource parent object got into "ended" state.
  110. void Ended();
  111. // The parent SourceBuffer is about to be destroyed.
  112. void Detach();
  113. int64_t EvictionThreshold() const;
  114. // Interface for MediaSourceDemuxer
  115. MediaInfo GetMetadata() const;
  116. const TrackBuffer& GetTrackBuffer(TrackInfo::TrackType aTrack) const;
  117. const media::TimeIntervals& Buffered(TrackInfo::TrackType) const;
  118. const media::TimeUnit& HighestStartTime(TrackInfo::TrackType) const;
  119. media::TimeIntervals SafeBuffered(TrackInfo::TrackType) const;
  120. bool IsEnded() const
  121. {
  122. return mEnded;
  123. }
  124. uint32_t Evictable(TrackInfo::TrackType aTrack) const;
  125. media::TimeUnit Seek(TrackInfo::TrackType aTrack,
  126. const media::TimeUnit& aTime,
  127. const media::TimeUnit& aFuzz);
  128. uint32_t SkipToNextRandomAccessPoint(TrackInfo::TrackType aTrack,
  129. const media::TimeUnit& aTimeThreadshold,
  130. const media::TimeUnit& aFuzz,
  131. bool& aFound);
  132. already_AddRefed<MediaRawData> GetSample(TrackInfo::TrackType aTrack,
  133. const media::TimeUnit& aFuzz,
  134. MediaResult& aResult);
  135. int32_t FindCurrentPosition(TrackInfo::TrackType aTrack,
  136. const media::TimeUnit& aFuzz) const;
  137. media::TimeUnit GetNextRandomAccessPoint(TrackInfo::TrackType aTrack,
  138. const media::TimeUnit& aFuzz);
  139. void AddSizeOfResources(MediaSourceDecoder::ResourceSizes* aSizes) const;
  140. private:
  141. typedef MozPromise<bool, MediaResult, /* IsExclusive = */ true> CodedFrameProcessingPromise;
  142. // for MediaSourceDemuxer::GetMozDebugReaderData
  143. friend class MediaSourceDemuxer;
  144. ~TrackBuffersManager();
  145. // All following functions run on the taskqueue.
  146. RefPtr<AppendPromise> DoAppendData(RefPtr<MediaByteBuffer> aData,
  147. SourceBufferAttributes aAttributes);
  148. void ScheduleSegmentParserLoop();
  149. void SegmentParserLoop();
  150. void InitializationSegmentReceived();
  151. void ShutdownDemuxers();
  152. void CreateDemuxerforMIMEType();
  153. void ResetDemuxingState();
  154. void NeedMoreData();
  155. void RejectAppend(const MediaResult& aRejectValue, const char* aName);
  156. // Will return a promise that will be resolved once all frames of the current
  157. // media segment have been processed.
  158. RefPtr<CodedFrameProcessingPromise> CodedFrameProcessing();
  159. void CompleteCodedFrameProcessing();
  160. // Called by ResetParserState.
  161. void CompleteResetParserState();
  162. RefPtr<RangeRemovalPromise>
  163. CodedFrameRemovalWithPromise(media::TimeInterval aInterval);
  164. bool CodedFrameRemoval(media::TimeInterval aInterval);
  165. void SetAppendState(SourceBufferAttributes::AppendState aAppendState);
  166. bool HasVideo() const
  167. {
  168. return mVideoTracks.mNumTracks > 0;
  169. }
  170. bool HasAudio() const
  171. {
  172. return mAudioTracks.mNumTracks > 0;
  173. }
  174. // The input buffer as per http://w3c.github.io/media-source/index.html#sourcebuffer-input-buffer
  175. RefPtr<MediaByteBuffer> mInputBuffer;
  176. // Buffer full flag as per https://w3c.github.io/media-source/#sourcebuffer-buffer-full-flag.
  177. // Accessed on both the main thread and the task queue.
  178. Atomic<bool> mBufferFull;
  179. bool mFirstInitializationSegmentReceived;
  180. // Set to true once a new segment is started.
  181. bool mNewMediaSegmentStarted;
  182. bool mActiveTrack;
  183. nsCString mType;
  184. // ContainerParser objects and methods.
  185. // Those are used to parse the incoming input buffer.
  186. // Recreate the ContainerParser and if aReuseInitData is true then
  187. // feed it with the previous init segment found.
  188. void RecreateParser(bool aReuseInitData);
  189. nsAutoPtr<ContainerParser> mParser;
  190. // Demuxer objects and methods.
  191. void AppendDataToCurrentInputBuffer(MediaByteBuffer* aData);
  192. RefPtr<MediaByteBuffer> mInitData;
  193. // Temporary input buffer to handle partial media segment header.
  194. // We store the current input buffer content into it should we need to
  195. // reinitialize the demuxer once we have some samples and a discontinuity is
  196. // detected.
  197. RefPtr<MediaByteBuffer> mPendingInputBuffer;
  198. RefPtr<SourceBufferResource> mCurrentInputBuffer;
  199. RefPtr<MediaDataDemuxer> mInputDemuxer;
  200. // Length already processed in current media segment.
  201. uint64_t mProcessedInput;
  202. Maybe<media::TimeUnit> mLastParsedEndTime;
  203. void OnDemuxerInitDone(nsresult);
  204. void OnDemuxerInitFailed(const MediaResult& aFailure);
  205. void OnDemuxerResetDone(nsresult);
  206. MozPromiseRequestHolder<MediaDataDemuxer::InitPromise> mDemuxerInitRequest;
  207. void OnDemuxFailed(TrackType aTrack, const MediaResult& aError);
  208. void DoDemuxVideo();
  209. void OnVideoDemuxCompleted(RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples);
  210. void OnVideoDemuxFailed(const MediaResult& aError)
  211. {
  212. mVideoTracks.mDemuxRequest.Complete();
  213. OnDemuxFailed(TrackType::kVideoTrack, aError);
  214. }
  215. void DoDemuxAudio();
  216. void OnAudioDemuxCompleted(RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples);
  217. void OnAudioDemuxFailed(const MediaResult& aError)
  218. {
  219. mAudioTracks.mDemuxRequest.Complete();
  220. OnDemuxFailed(TrackType::kAudioTrack, aError);
  221. }
  222. void DoEvictData(const media::TimeUnit& aPlaybackTime, int64_t aSizeToEvict);
  223. struct TrackData
  224. {
  225. TrackData()
  226. : mNumTracks(0)
  227. , mNeedRandomAccessPoint(true)
  228. , mSizeBuffer(0)
  229. {}
  230. uint32_t mNumTracks;
  231. // Definition of variables:
  232. // https://w3c.github.io/media-source/#track-buffers
  233. // Last decode timestamp variable that stores the decode timestamp of the
  234. // last coded frame appended in the current coded frame group.
  235. // The variable is initially unset to indicate that no coded frames have
  236. // been appended yet.
  237. Maybe<media::TimeUnit> mLastDecodeTimestamp;
  238. // Last frame duration variable that stores the coded frame duration of the
  239. // last coded frame appended in the current coded frame group.
  240. // The variable is initially unset to indicate that no coded frames have
  241. // been appended yet.
  242. Maybe<media::TimeUnit> mLastFrameDuration;
  243. // Highest end timestamp variable that stores the highest coded frame end
  244. // timestamp across all coded frames in the current coded frame group that
  245. // were appended to this track buffer.
  246. // The variable is initially unset to indicate that no coded frames have
  247. // been appended yet.
  248. Maybe<media::TimeUnit> mHighestEndTimestamp;
  249. // Highest presentation timestamp in track buffer.
  250. // Protected by global monitor, except when reading on the task queue as it
  251. // is only written there.
  252. media::TimeUnit mHighestStartTimestamp;
  253. // Longest frame duration seen since last random access point.
  254. // Only ever accessed when mLastDecodeTimestamp and mLastFrameDuration are
  255. // set.
  256. media::TimeUnit mLongestFrameDuration;
  257. // Need random access point flag variable that keeps track of whether the
  258. // track buffer is waiting for a random access point coded frame.
  259. // The variable is initially set to true to indicate that random access
  260. // point coded frame is needed before anything can be added to the track
  261. // buffer.
  262. bool mNeedRandomAccessPoint;
  263. RefPtr<MediaTrackDemuxer> mDemuxer;
  264. MozPromiseRequestHolder<MediaTrackDemuxer::SamplesPromise> mDemuxRequest;
  265. // Highest end timestamp of the last media segment demuxed.
  266. media::TimeUnit mLastParsedEndTime;
  267. // If set, position where the next contiguous frame will be inserted.
  268. // If a discontinuity is detected, it will be unset and recalculated upon
  269. // the next insertion.
  270. Maybe<uint32_t> mNextInsertionIndex;
  271. // Samples just demuxed, but not yet parsed.
  272. TrackBuffer mQueuedSamples;
  273. const TrackBuffer& GetTrackBuffer() const
  274. {
  275. MOZ_RELEASE_ASSERT(mBuffers.Length(),
  276. "TrackBuffer must have been created");
  277. return mBuffers.LastElement();
  278. }
  279. TrackBuffer& GetTrackBuffer()
  280. {
  281. MOZ_RELEASE_ASSERT(mBuffers.Length(),
  282. "TrackBuffer must have been created");
  283. return mBuffers.LastElement();
  284. }
  285. // We only manage a single track of each type at this time.
  286. nsTArray<TrackBuffer> mBuffers;
  287. // Track buffer ranges variable that represents the presentation time ranges
  288. // occupied by the coded frames currently stored in the track buffer.
  289. media::TimeIntervals mBufferedRanges;
  290. // Sanitized mBufferedRanges with a fuzz of half a sample's duration applied
  291. // This buffered ranges is the basis of what is exposed to the JS.
  292. media::TimeIntervals mSanitizedBufferedRanges;
  293. // Byte size of all samples contained in this track buffer.
  294. uint32_t mSizeBuffer;
  295. // TrackInfo of the first metadata received.
  296. RefPtr<SharedTrackInfo> mInfo;
  297. // TrackInfo of the last metadata parsed (updated with each init segment.
  298. RefPtr<SharedTrackInfo> mLastInfo;
  299. // If set, position of the next sample to be retrieved by GetSample().
  300. // If the position is equal to the TrackBuffer's length, it indicates that
  301. // we've reached EOS.
  302. Maybe<uint32_t> mNextGetSampleIndex;
  303. // Approximation of the next sample's decode timestamp.
  304. media::TimeUnit mNextSampleTimecode;
  305. // Approximation of the next sample's presentation timestamp.
  306. media::TimeUnit mNextSampleTime;
  307. struct EvictionIndex
  308. {
  309. EvictionIndex() { Reset(); }
  310. void Reset()
  311. {
  312. mEvictable = 0;
  313. mLastIndex = 0;
  314. }
  315. uint32_t mEvictable;
  316. uint32_t mLastIndex;
  317. };
  318. // Size of data that can be safely evicted during the next eviction
  319. // cycle.
  320. // We consider as evictable all frames up to the last keyframe prior to
  321. // mNextGetSampleIndex. If mNextGetSampleIndex isn't set, then we assume
  322. // that we can't yet evict data.
  323. // Protected by global monitor, except when reading on the task queue as it
  324. // is only written there.
  325. EvictionIndex mEvictionIndex;
  326. void ResetAppendState()
  327. {
  328. mLastDecodeTimestamp.reset();
  329. mLastFrameDuration.reset();
  330. mHighestEndTimestamp.reset();
  331. mNeedRandomAccessPoint = true;
  332. mNextInsertionIndex.reset();
  333. }
  334. void AddSizeOfResources(MediaSourceDecoder::ResourceSizes* aSizes) const;
  335. };
  336. void CheckSequenceDiscontinuity(const media::TimeUnit& aPresentationTime);
  337. void ProcessFrames(TrackBuffer& aSamples, TrackData& aTrackData);
  338. media::TimeInterval PresentationInterval(const TrackBuffer& aSamples) const;
  339. bool CheckNextInsertionIndex(TrackData& aTrackData,
  340. const media::TimeUnit& aSampleTime);
  341. void InsertFrames(TrackBuffer& aSamples,
  342. const media::TimeIntervals& aIntervals,
  343. TrackData& aTrackData);
  344. void UpdateHighestTimestamp(TrackData& aTrackData,
  345. const media::TimeUnit& aHighestTime);
  346. // Remove all frames and their dependencies contained in aIntervals.
  347. // Return the index at which frames were first removed or 0 if no frames
  348. // removed.
  349. uint32_t RemoveFrames(const media::TimeIntervals& aIntervals,
  350. TrackData& aTrackData,
  351. uint32_t aStartIndex);
  352. // Recalculate track's evictable amount.
  353. void ResetEvictionIndex(TrackData& aTrackData);
  354. void UpdateEvictionIndex(TrackData& aTrackData, uint32_t aCurrentIndex);
  355. // Find index of sample. Return a negative value if not found.
  356. uint32_t FindSampleIndex(const TrackBuffer& aTrackBuffer,
  357. const media::TimeInterval& aInterval);
  358. const MediaRawData* GetSample(TrackInfo::TrackType aTrack,
  359. uint32_t aIndex,
  360. const media::TimeUnit& aExpectedDts,
  361. const media::TimeUnit& aExpectedPts,
  362. const media::TimeUnit& aFuzz);
  363. void UpdateBufferedRanges();
  364. void RejectProcessing(const MediaResult& aRejectValue, const char* aName);
  365. void ResolveProcessing(bool aResolveValue, const char* aName);
  366. MozPromiseRequestHolder<CodedFrameProcessingPromise> mProcessingRequest;
  367. MozPromiseHolder<CodedFrameProcessingPromise> mProcessingPromise;
  368. // Trackbuffers definition.
  369. nsTArray<const TrackData*> GetTracksList() const;
  370. nsTArray<TrackData*> GetTracksList();
  371. TrackData& GetTracksData(TrackType aTrack)
  372. {
  373. switch(aTrack) {
  374. case TrackType::kVideoTrack:
  375. return mVideoTracks;
  376. case TrackType::kAudioTrack:
  377. default:
  378. return mAudioTracks;
  379. }
  380. }
  381. const TrackData& GetTracksData(TrackType aTrack) const
  382. {
  383. switch(aTrack) {
  384. case TrackType::kVideoTrack:
  385. return mVideoTracks;
  386. case TrackType::kAudioTrack:
  387. default:
  388. return mAudioTracks;
  389. }
  390. }
  391. TrackData mVideoTracks;
  392. TrackData mAudioTracks;
  393. // TaskQueue methods and objects.
  394. AbstractThread* GetTaskQueue() const
  395. {
  396. return mTaskQueue;
  397. }
  398. bool OnTaskQueue() const
  399. {
  400. return !GetTaskQueue() || GetTaskQueue()->IsCurrentThreadIn();
  401. }
  402. RefPtr<AutoTaskQueue> mTaskQueue;
  403. // SourceBuffer Queues and running context.
  404. SourceBufferTaskQueue mQueue;
  405. void QueueTask(SourceBufferTask* aTask);
  406. void ProcessTasks();
  407. // Set if the TrackBuffersManager is currently processing a task.
  408. // At this stage, this task is always a AppendBufferTask.
  409. RefPtr<SourceBufferTask> mCurrentTask;
  410. // Current SourceBuffer state for ongoing task.
  411. // Its content is returned to the SourceBuffer once the AppendBufferTask has
  412. // completed.
  413. UniquePtr<SourceBufferAttributes> mSourceBufferAttributes;
  414. // The current sourcebuffer append window. It's content is equivalent to
  415. // mSourceBufferAttributes.mAppendWindowStart/End
  416. media::TimeInterval mAppendWindow;
  417. // Strong references to external objects.
  418. nsMainThreadPtrHandle<MediaSourceDecoder> mParentDecoder;
  419. // Return public highest end time across all aTracks.
  420. // Monitor must be held.
  421. media::TimeUnit HighestEndTime(nsTArray<const media::TimeIntervals*>& aTracks) const;
  422. // Set to true if mediasource state changed to ended.
  423. Atomic<bool> mEnded;
  424. // Global size of this source buffer content.
  425. Atomic<int64_t> mSizeSourceBuffer;
  426. const int64_t mVideoEvictionThreshold;
  427. const int64_t mAudioEvictionThreshold;
  428. enum class EvictionState
  429. {
  430. NO_EVICTION_NEEDED,
  431. EVICTION_NEEDED,
  432. EVICTION_COMPLETED,
  433. };
  434. Atomic<EvictionState> mEvictionState;
  435. // Monitor to protect following objects accessed across multiple threads.
  436. mutable Monitor mMonitor;
  437. // Stable audio and video track time ranges.
  438. media::TimeIntervals mVideoBufferedRanges;
  439. media::TimeIntervals mAudioBufferedRanges;
  440. // MediaInfo of the first init segment read.
  441. MediaInfo mInfo;
  442. };
  443. } // namespace mozilla
  444. #endif /* MOZILLA_TRACKBUFFERSMANAGER_H_ */