MediaSourceDemuxer.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* vim:set ts=2 sw=2 sts=2 et cindent: */
  3. /* This Source Code Form is subject to the terms of the Mozilla Public
  4. * License, v. 2.0. If a copy of the MPL was not distributed with this
  5. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6. #include <algorithm>
  7. #include <limits>
  8. #include <stdint.h>
  9. #include "MediaSourceDemuxer.h"
  10. #include "MediaSourceUtils.h"
  11. #include "SourceBufferList.h"
  12. #include "nsPrintfCString.h"
  13. #include "OpusDecoder.h"
  14. namespace mozilla {
  15. typedef TrackInfo::TrackType TrackType;
  16. using media::TimeUnit;
  17. using media::TimeIntervals;
  18. MediaSourceDemuxer::MediaSourceDemuxer()
  19. : mTaskQueue(new AutoTaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK),
  20. /* aSupportsTailDispatch = */ false))
  21. , mMonitor("MediaSourceDemuxer")
  22. {
  23. MOZ_ASSERT(NS_IsMainThread());
  24. }
  25. // Due to inaccuracies in determining buffer end
  26. // frames (Bug 1065207). This value is based on videos seen in the wild.
  27. const TimeUnit MediaSourceDemuxer::EOS_FUZZ = media::TimeUnit::FromMicroseconds(500000);
  28. RefPtr<MediaSourceDemuxer::InitPromise>
  29. MediaSourceDemuxer::Init()
  30. {
  31. return InvokeAsync(GetTaskQueue(), this, __func__,
  32. &MediaSourceDemuxer::AttemptInit);
  33. }
  34. RefPtr<MediaSourceDemuxer::InitPromise>
  35. MediaSourceDemuxer::AttemptInit()
  36. {
  37. MOZ_ASSERT(OnTaskQueue());
  38. if (ScanSourceBuffersForContent()) {
  39. return InitPromise::CreateAndResolve(NS_OK, __func__);
  40. }
  41. RefPtr<InitPromise> p = mInitPromise.Ensure(__func__);
  42. return p;
  43. }
  44. void
  45. MediaSourceDemuxer::AddSizeOfResources(MediaSourceDecoder::ResourceSizes* aSizes)
  46. {
  47. MOZ_ASSERT(NS_IsMainThread());
  48. // NB: The track buffers must only be accessed on the TaskQueue.
  49. RefPtr<MediaSourceDemuxer> self = this;
  50. RefPtr<MediaSourceDecoder::ResourceSizes> sizes = aSizes;
  51. nsCOMPtr<nsIRunnable> task =
  52. NS_NewRunnableFunction([self, sizes] () {
  53. for (TrackBuffersManager* manager : self->mSourceBuffers) {
  54. manager->AddSizeOfResources(sizes);
  55. }
  56. });
  57. GetTaskQueue()->Dispatch(task.forget());
  58. }
  59. void MediaSourceDemuxer::NotifyDataArrived()
  60. {
  61. RefPtr<MediaSourceDemuxer> self = this;
  62. nsCOMPtr<nsIRunnable> task =
  63. NS_NewRunnableFunction([self] () {
  64. if (self->mInitPromise.IsEmpty()) {
  65. return;
  66. }
  67. if (self->ScanSourceBuffersForContent()) {
  68. self->mInitPromise.ResolveIfExists(NS_OK, __func__);
  69. }
  70. });
  71. GetTaskQueue()->Dispatch(task.forget());
  72. }
  73. bool
  74. MediaSourceDemuxer::ScanSourceBuffersForContent()
  75. {
  76. MOZ_ASSERT(OnTaskQueue());
  77. if (mSourceBuffers.IsEmpty()) {
  78. return false;
  79. }
  80. MonitorAutoLock mon(mMonitor);
  81. bool haveEmptySourceBuffer = false;
  82. for (const auto& sourceBuffer : mSourceBuffers) {
  83. MediaInfo info = sourceBuffer->GetMetadata();
  84. if (!info.HasAudio() && !info.HasVideo()) {
  85. haveEmptySourceBuffer = true;
  86. }
  87. if (info.HasAudio() && !mAudioTrack) {
  88. mInfo.mAudio = info.mAudio;
  89. mAudioTrack = sourceBuffer;
  90. }
  91. if (info.HasVideo() && !mVideoTrack) {
  92. mInfo.mVideo = info.mVideo;
  93. mVideoTrack = sourceBuffer;
  94. }
  95. if (info.IsEncrypted() && !mInfo.IsEncrypted()) {
  96. mInfo.mCrypto = info.mCrypto;
  97. }
  98. }
  99. if (mInfo.HasAudio() && mInfo.HasVideo()) {
  100. // We have both audio and video. We can ignore non-ready source buffer.
  101. return true;
  102. }
  103. return !haveEmptySourceBuffer;
  104. }
  105. bool
  106. MediaSourceDemuxer::HasTrackType(TrackType aType) const
  107. {
  108. MonitorAutoLock mon(mMonitor);
  109. switch (aType) {
  110. case TrackType::kAudioTrack:
  111. return mInfo.HasAudio();
  112. case TrackType::kVideoTrack:
  113. return mInfo.HasVideo();
  114. default:
  115. return false;
  116. }
  117. }
  118. uint32_t
  119. MediaSourceDemuxer::GetNumberTracks(TrackType aType) const
  120. {
  121. return HasTrackType(aType) ? 1u : 0;
  122. }
  123. already_AddRefed<MediaTrackDemuxer>
  124. MediaSourceDemuxer::GetTrackDemuxer(TrackType aType, uint32_t aTrackNumber)
  125. {
  126. RefPtr<TrackBuffersManager> manager = GetManager(aType);
  127. if (!manager) {
  128. return nullptr;
  129. }
  130. RefPtr<MediaSourceTrackDemuxer> e =
  131. new MediaSourceTrackDemuxer(this, aType, manager);
  132. mDemuxers.AppendElement(e);
  133. return e.forget();
  134. }
  135. bool
  136. MediaSourceDemuxer::IsSeekable() const
  137. {
  138. return true;
  139. }
  140. UniquePtr<EncryptionInfo>
  141. MediaSourceDemuxer::GetCrypto()
  142. {
  143. MonitorAutoLock mon(mMonitor);
  144. auto crypto = MakeUnique<EncryptionInfo>();
  145. *crypto = mInfo.mCrypto;
  146. return crypto;
  147. }
  148. void
  149. MediaSourceDemuxer::AttachSourceBuffer(TrackBuffersManager* aSourceBuffer)
  150. {
  151. nsCOMPtr<nsIRunnable> task =
  152. NewRunnableMethod<TrackBuffersManager*>(
  153. this, &MediaSourceDemuxer::DoAttachSourceBuffer,
  154. aSourceBuffer);
  155. GetTaskQueue()->Dispatch(task.forget());
  156. }
  157. void
  158. MediaSourceDemuxer::DoAttachSourceBuffer(mozilla::TrackBuffersManager* aSourceBuffer)
  159. {
  160. MOZ_ASSERT(OnTaskQueue());
  161. mSourceBuffers.AppendElement(aSourceBuffer);
  162. ScanSourceBuffersForContent();
  163. }
  164. void
  165. MediaSourceDemuxer::DetachSourceBuffer(TrackBuffersManager* aSourceBuffer)
  166. {
  167. nsCOMPtr<nsIRunnable> task =
  168. NewRunnableMethod<TrackBuffersManager*>(
  169. this, &MediaSourceDemuxer::DoDetachSourceBuffer,
  170. aSourceBuffer);
  171. GetTaskQueue()->Dispatch(task.forget());
  172. }
  173. void
  174. MediaSourceDemuxer::DoDetachSourceBuffer(TrackBuffersManager* aSourceBuffer)
  175. {
  176. MOZ_ASSERT(OnTaskQueue());
  177. for (uint32_t i = 0; i < mSourceBuffers.Length(); i++) {
  178. if (mSourceBuffers[i].get() == aSourceBuffer) {
  179. mSourceBuffers.RemoveElementAt(i);
  180. }
  181. }
  182. if (aSourceBuffer == mAudioTrack) {
  183. mAudioTrack = nullptr;
  184. }
  185. if (aSourceBuffer == mVideoTrack) {
  186. mVideoTrack = nullptr;
  187. }
  188. ScanSourceBuffersForContent();
  189. }
  190. TrackInfo*
  191. MediaSourceDemuxer::GetTrackInfo(TrackType aTrack)
  192. {
  193. MonitorAutoLock mon(mMonitor);
  194. switch (aTrack) {
  195. case TrackType::kAudioTrack:
  196. return &mInfo.mAudio;
  197. case TrackType::kVideoTrack:
  198. return &mInfo.mVideo;
  199. default:
  200. return nullptr;
  201. }
  202. }
  203. TrackBuffersManager*
  204. MediaSourceDemuxer::GetManager(TrackType aTrack)
  205. {
  206. MonitorAutoLock mon(mMonitor);
  207. switch (aTrack) {
  208. case TrackType::kAudioTrack:
  209. return mAudioTrack;
  210. case TrackType::kVideoTrack:
  211. return mVideoTrack;
  212. default:
  213. return nullptr;
  214. }
  215. }
  216. MediaSourceDemuxer::~MediaSourceDemuxer()
  217. {
  218. mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
  219. }
  220. void
  221. MediaSourceDemuxer::GetMozDebugReaderData(nsAString& aString)
  222. {
  223. MonitorAutoLock mon(mMonitor);
  224. nsAutoCString result;
  225. result += nsPrintfCString("Dumping data for demuxer %p:\n", this);
  226. if (mAudioTrack) {
  227. result += nsPrintfCString("\tDumping Audio Track Buffer(%s): - mLastAudioTime: %f\n"
  228. "\t\tNumSamples:%u Size:%u Evictable:%u NextGetSampleIndex:%u NextInsertionIndex:%d\n",
  229. mAudioTrack->mAudioTracks.mInfo->mMimeType.get(),
  230. mAudioTrack->mAudioTracks.mNextSampleTime.ToSeconds(),
  231. mAudioTrack->mAudioTracks.mBuffers[0].Length(),
  232. mAudioTrack->mAudioTracks.mSizeBuffer,
  233. mAudioTrack->Evictable(TrackInfo::kAudioTrack),
  234. mAudioTrack->mAudioTracks.mNextGetSampleIndex.valueOr(-1),
  235. mAudioTrack->mAudioTracks.mNextInsertionIndex.valueOr(-1));
  236. result += nsPrintfCString("\t\tBuffered: ranges=%s\n",
  237. DumpTimeRanges(mAudioTrack->SafeBuffered(TrackInfo::kAudioTrack)).get());
  238. }
  239. if (mVideoTrack) {
  240. result += nsPrintfCString("\tDumping Video Track Buffer(%s) - mLastVideoTime: %f\n"
  241. "\t\tNumSamples:%u Size:%u Evictable:%u NextGetSampleIndex:%u NextInsertionIndex:%d\n",
  242. mVideoTrack->mVideoTracks.mInfo->mMimeType.get(),
  243. mVideoTrack->mVideoTracks.mNextSampleTime.ToSeconds(),
  244. mVideoTrack->mVideoTracks.mBuffers[0].Length(),
  245. mVideoTrack->mVideoTracks.mSizeBuffer,
  246. mVideoTrack->Evictable(TrackInfo::kVideoTrack),
  247. mVideoTrack->mVideoTracks.mNextGetSampleIndex.valueOr(-1),
  248. mVideoTrack->mVideoTracks.mNextInsertionIndex.valueOr(-1));
  249. result += nsPrintfCString("\t\tBuffered: ranges=%s\n",
  250. DumpTimeRanges(mVideoTrack->SafeBuffered(TrackInfo::kVideoTrack)).get());
  251. }
  252. aString += NS_ConvertUTF8toUTF16(result);
  253. }
  254. MediaSourceTrackDemuxer::MediaSourceTrackDemuxer(MediaSourceDemuxer* aParent,
  255. TrackInfo::TrackType aType,
  256. TrackBuffersManager* aManager)
  257. : mParent(aParent)
  258. , mManager(aManager)
  259. , mType(aType)
  260. , mMonitor("MediaSourceTrackDemuxer")
  261. , mReset(true)
  262. , mPreRoll(
  263. TimeUnit::FromMicroseconds(
  264. OpusDataDecoder::IsOpus(mParent->GetTrackInfo(mType)->mMimeType)
  265. ? 80000 : 0))
  266. {
  267. }
  268. UniquePtr<TrackInfo>
  269. MediaSourceTrackDemuxer::GetInfo() const
  270. {
  271. return mParent->GetTrackInfo(mType)->Clone();
  272. }
  273. RefPtr<MediaSourceTrackDemuxer::SeekPromise>
  274. MediaSourceTrackDemuxer::Seek(media::TimeUnit aTime)
  275. {
  276. MOZ_ASSERT(mParent, "Called after BreackCycle()");
  277. return InvokeAsync(mParent->GetTaskQueue(), this, __func__,
  278. &MediaSourceTrackDemuxer::DoSeek, aTime);
  279. }
  280. RefPtr<MediaSourceTrackDemuxer::SamplesPromise>
  281. MediaSourceTrackDemuxer::GetSamples(int32_t aNumSamples)
  282. {
  283. MOZ_ASSERT(mParent, "Called after BreackCycle()");
  284. return InvokeAsync(mParent->GetTaskQueue(), this, __func__,
  285. &MediaSourceTrackDemuxer::DoGetSamples, aNumSamples);
  286. }
  287. void
  288. MediaSourceTrackDemuxer::Reset()
  289. {
  290. MOZ_ASSERT(mParent, "Called after BreackCycle()");
  291. RefPtr<MediaSourceTrackDemuxer> self = this;
  292. nsCOMPtr<nsIRunnable> task =
  293. NS_NewRunnableFunction([self] () {
  294. self->mNextSample.reset();
  295. self->mReset = true;
  296. self->mManager->Seek(self->mType, TimeUnit(), TimeUnit());
  297. {
  298. MonitorAutoLock mon(self->mMonitor);
  299. self->mNextRandomAccessPoint =
  300. self->mManager->GetNextRandomAccessPoint(self->mType,
  301. MediaSourceDemuxer::EOS_FUZZ);
  302. }
  303. });
  304. mParent->GetTaskQueue()->Dispatch(task.forget());
  305. }
  306. nsresult
  307. MediaSourceTrackDemuxer::GetNextRandomAccessPoint(media::TimeUnit* aTime)
  308. {
  309. MonitorAutoLock mon(mMonitor);
  310. *aTime = mNextRandomAccessPoint;
  311. return NS_OK;
  312. }
  313. RefPtr<MediaSourceTrackDemuxer::SkipAccessPointPromise>
  314. MediaSourceTrackDemuxer::SkipToNextRandomAccessPoint(media::TimeUnit aTimeThreshold)
  315. {
  316. return InvokeAsync(mParent->GetTaskQueue(), this, __func__,
  317. &MediaSourceTrackDemuxer::DoSkipToNextRandomAccessPoint,
  318. aTimeThreshold);
  319. }
  320. media::TimeIntervals
  321. MediaSourceTrackDemuxer::GetBuffered()
  322. {
  323. return mManager->Buffered();
  324. }
  325. void
  326. MediaSourceTrackDemuxer::BreakCycles()
  327. {
  328. RefPtr<MediaSourceTrackDemuxer> self = this;
  329. nsCOMPtr<nsIRunnable> task =
  330. NS_NewRunnableFunction([self]() {
  331. self->mParent = nullptr;
  332. self->mManager = nullptr;
  333. } );
  334. mParent->GetTaskQueue()->Dispatch(task.forget());
  335. }
  336. RefPtr<MediaSourceTrackDemuxer::SeekPromise>
  337. MediaSourceTrackDemuxer::DoSeek(media::TimeUnit aTime)
  338. {
  339. TimeIntervals buffered = mManager->Buffered(mType);
  340. // Fuzz factor represents a +/- threshold. So when seeking it allows the gap
  341. // to be twice as big as the fuzz value. We only want to allow EOS_FUZZ gap.
  342. buffered.SetFuzz(MediaSourceDemuxer::EOS_FUZZ / 2);
  343. TimeUnit seekTime = std::max(aTime - mPreRoll, TimeUnit::FromMicroseconds(0));
  344. if (mManager->IsEnded() && seekTime >= buffered.GetEnd()) {
  345. // We're attempting to seek past the end time. Cap seekTime so that we seek
  346. // to the last sample instead.
  347. seekTime =
  348. std::max(mManager->HighestStartTime(mType) - mPreRoll,
  349. TimeUnit::FromMicroseconds(0));
  350. }
  351. if (!buffered.ContainsWithStrictEnd(seekTime)) {
  352. if (!buffered.ContainsWithStrictEnd(aTime)) {
  353. // We don't have the data to seek to.
  354. return SeekPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA,
  355. __func__);
  356. }
  357. // Theoretically we should reject the promise with WAITING_FOR_DATA,
  358. // however, to avoid unwanted regressions we assume that if at this time
  359. // we don't have the wanted data it won't come later.
  360. // Instead of using the pre-rolled time, use the earliest time available in
  361. // the interval.
  362. TimeIntervals::IndexType index = buffered.Find(aTime);
  363. MOZ_ASSERT(index != TimeIntervals::NoIndex);
  364. seekTime = buffered[index].mStart;
  365. }
  366. seekTime = mManager->Seek(mType, seekTime, MediaSourceDemuxer::EOS_FUZZ);
  367. MediaResult result = NS_OK;
  368. RefPtr<MediaRawData> sample =
  369. mManager->GetSample(mType,
  370. media::TimeUnit(),
  371. result);
  372. MOZ_ASSERT(NS_SUCCEEDED(result) && sample);
  373. mNextSample = Some(sample);
  374. mReset = false;
  375. {
  376. MonitorAutoLock mon(mMonitor);
  377. mNextRandomAccessPoint =
  378. mManager->GetNextRandomAccessPoint(mType, MediaSourceDemuxer::EOS_FUZZ);
  379. }
  380. return SeekPromise::CreateAndResolve(seekTime, __func__);
  381. }
  382. RefPtr<MediaSourceTrackDemuxer::SamplesPromise>
  383. MediaSourceTrackDemuxer::DoGetSamples(int32_t aNumSamples)
  384. {
  385. if (mReset) {
  386. // If a seek (or reset) was recently performed, we ensure that the data
  387. // we are about to retrieve is still available.
  388. TimeIntervals buffered = mManager->Buffered(mType);
  389. buffered.SetFuzz(MediaSourceDemuxer::EOS_FUZZ / 2);
  390. if (!buffered.Length() && mManager->IsEnded()) {
  391. return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_END_OF_STREAM,
  392. __func__);
  393. }
  394. if (!buffered.ContainsWithStrictEnd(TimeUnit::FromMicroseconds(0))) {
  395. return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA,
  396. __func__);
  397. }
  398. mReset = false;
  399. }
  400. RefPtr<MediaRawData> sample;
  401. if (mNextSample) {
  402. sample = mNextSample.ref();
  403. mNextSample.reset();
  404. } else {
  405. MediaResult result = NS_OK;
  406. sample = mManager->GetSample(mType, MediaSourceDemuxer::EOS_FUZZ, result);
  407. if (!sample) {
  408. if (result == NS_ERROR_DOM_MEDIA_END_OF_STREAM ||
  409. result == NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA) {
  410. return SamplesPromise::CreateAndReject(
  411. (result == NS_ERROR_DOM_MEDIA_END_OF_STREAM && mManager->IsEnded())
  412. ? NS_ERROR_DOM_MEDIA_END_OF_STREAM
  413. : NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, __func__);
  414. }
  415. return SamplesPromise::CreateAndReject(result, __func__);
  416. }
  417. }
  418. RefPtr<SamplesHolder> samples = new SamplesHolder;
  419. samples->mSamples.AppendElement(sample);
  420. if (mNextRandomAccessPoint.ToMicroseconds() <= sample->mTime) {
  421. MonitorAutoLock mon(mMonitor);
  422. mNextRandomAccessPoint =
  423. mManager->GetNextRandomAccessPoint(mType, MediaSourceDemuxer::EOS_FUZZ);
  424. }
  425. return SamplesPromise::CreateAndResolve(samples, __func__);
  426. }
  427. RefPtr<MediaSourceTrackDemuxer::SkipAccessPointPromise>
  428. MediaSourceTrackDemuxer::DoSkipToNextRandomAccessPoint(media::TimeUnit aTimeThreadshold)
  429. {
  430. uint32_t parsed = 0;
  431. // Ensure that the data we are about to skip to is still available.
  432. TimeIntervals buffered = mManager->Buffered(mType);
  433. buffered.SetFuzz(MediaSourceDemuxer::EOS_FUZZ / 2);
  434. if (buffered.ContainsWithStrictEnd(aTimeThreadshold)) {
  435. bool found;
  436. parsed = mManager->SkipToNextRandomAccessPoint(mType,
  437. aTimeThreadshold,
  438. MediaSourceDemuxer::EOS_FUZZ,
  439. found);
  440. if (found) {
  441. return SkipAccessPointPromise::CreateAndResolve(parsed, __func__);
  442. }
  443. }
  444. SkipFailureHolder holder(
  445. mManager->IsEnded() ? NS_ERROR_DOM_MEDIA_END_OF_STREAM :
  446. NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, parsed);
  447. return SkipAccessPointPromise::CreateAndReject(holder, __func__);
  448. }
  449. } // namespace mozilla