MediaSource.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  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. #include "MediaSource.h"
  6. #include "AsyncEventRunner.h"
  7. #include "DecoderTraits.h"
  8. #include "Benchmark.h"
  9. #include "DecoderDoctorDiagnostics.h"
  10. #include "MediaContentType.h"
  11. #include "MediaResult.h"
  12. #include "MediaSourceUtils.h"
  13. #include "SourceBuffer.h"
  14. #include "SourceBufferList.h"
  15. #include "mozilla/ErrorResult.h"
  16. #include "mozilla/FloatingPoint.h"
  17. #include "mozilla/Preferences.h"
  18. #include "mozilla/dom/BindingDeclarations.h"
  19. #include "mozilla/dom/HTMLMediaElement.h"
  20. #include "mozilla/mozalloc.h"
  21. #include "nsDebug.h"
  22. #include "nsError.h"
  23. #include "nsIRunnable.h"
  24. #include "nsIScriptObjectPrincipal.h"
  25. #include "nsPIDOMWindow.h"
  26. #include "nsString.h"
  27. #include "nsThreadUtils.h"
  28. #include "mozilla/Logging.h"
  29. #include "nsServiceManagerUtils.h"
  30. #include "mozilla/gfx/gfxVars.h"
  31. #include "mozilla/Sprintf.h"
  32. struct JSContext;
  33. class JSObject;
  34. mozilla::LogModule* GetMediaSourceLog()
  35. {
  36. static mozilla::LazyLogModule sLogModule("MediaSource");
  37. return sLogModule;
  38. }
  39. mozilla::LogModule* GetMediaSourceAPILog()
  40. {
  41. static mozilla::LazyLogModule sLogModule("MediaSource");
  42. return sLogModule;
  43. }
  44. #define MSE_DEBUG(arg, ...) MOZ_LOG(GetMediaSourceLog(), mozilla::LogLevel::Debug, ("MediaSource(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
  45. #define MSE_API(arg, ...) MOZ_LOG(GetMediaSourceAPILog(), mozilla::LogLevel::Debug, ("MediaSource(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
  46. // Arbitrary limit.
  47. static const unsigned int MAX_SOURCE_BUFFERS = 16;
  48. namespace mozilla {
  49. // Returns true if we should enable MSE webm regardless of preferences.
  50. // 1. If MP4/H264 isn't supported:
  51. // * N/KN editions (Europe and Korea) of Windows 7/8/8.1/10 without the
  52. // optional "Windows Media Feature Pack"
  53. // 2. If H264 hardware acceleration is not available.
  54. // 3. The CPU is considered to be fast enough
  55. static bool
  56. IsWebMForced(DecoderDoctorDiagnostics* aDiagnostics)
  57. {
  58. bool mp4supported =
  59. DecoderTraits::IsMP4TypeAndEnabled(NS_LITERAL_CSTRING("video/mp4"),
  60. aDiagnostics);
  61. bool hwsupported = gfx::gfxVars::CanUseHardwareVideoDecoding();
  62. return !mp4supported || !hwsupported || VP9Benchmark::IsVP9DecodeFast();
  63. }
  64. namespace dom {
  65. /* static */
  66. nsresult
  67. MediaSource::IsTypeSupported(const nsAString& aType, DecoderDoctorDiagnostics* aDiagnostics)
  68. {
  69. if (aType.IsEmpty()) {
  70. return NS_ERROR_DOM_TYPE_ERR;
  71. }
  72. MediaContentType contentType{aType};
  73. if (!contentType.IsValid()) {
  74. return NS_ERROR_DOM_TYPE_ERR;
  75. }
  76. if (DecoderTraits::CanHandleContentType(contentType, aDiagnostics)
  77. == CANPLAY_NO) {
  78. return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
  79. }
  80. // Now we know that this media type could be played.
  81. // MediaSource imposes extra restrictions, and some prefs.
  82. const nsACString& mimeType = contentType.GetMIMEType();
  83. if (mimeType.EqualsASCII("video/mp4") || mimeType.EqualsASCII("audio/mp4")) {
  84. if (!Preferences::GetBool("media.mediasource.mp4.enabled", false)) {
  85. return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
  86. }
  87. return NS_OK;
  88. }
  89. if (mimeType.EqualsASCII("video/webm") ||
  90. mimeType.EqualsASCII("video/x-matroska")) {
  91. if (!(Preferences::GetBool("media.mediasource.webm.enabled", false) ||
  92. IsWebMForced(aDiagnostics))) {
  93. return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
  94. }
  95. return NS_OK;
  96. }
  97. if (mimeType.EqualsASCII("audio/webm") ||
  98. mimeType.EqualsASCII("audio/x-matroska")) {
  99. if (!(Preferences::GetBool("media.mediasource.webm.enabled", false) ||
  100. Preferences::GetBool("media.mediasource.webm.audio.enabled", true))) {
  101. return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
  102. }
  103. return NS_OK;
  104. }
  105. return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
  106. }
  107. /* static */ already_AddRefed<MediaSource>
  108. MediaSource::Constructor(const GlobalObject& aGlobal,
  109. ErrorResult& aRv)
  110. {
  111. nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
  112. if (!window) {
  113. aRv.Throw(NS_ERROR_UNEXPECTED);
  114. return nullptr;
  115. }
  116. RefPtr<MediaSource> mediaSource = new MediaSource(window);
  117. return mediaSource.forget();
  118. }
  119. MediaSource::~MediaSource()
  120. {
  121. MOZ_ASSERT(NS_IsMainThread());
  122. MSE_API("");
  123. if (mDecoder) {
  124. mDecoder->DetachMediaSource();
  125. }
  126. }
  127. SourceBufferList*
  128. MediaSource::SourceBuffers()
  129. {
  130. MOZ_ASSERT(NS_IsMainThread());
  131. MOZ_ASSERT_IF(mReadyState == MediaSourceReadyState::Closed, mSourceBuffers->IsEmpty());
  132. return mSourceBuffers;
  133. }
  134. SourceBufferList*
  135. MediaSource::ActiveSourceBuffers()
  136. {
  137. MOZ_ASSERT(NS_IsMainThread());
  138. MOZ_ASSERT_IF(mReadyState == MediaSourceReadyState::Closed, mActiveSourceBuffers->IsEmpty());
  139. return mActiveSourceBuffers;
  140. }
  141. MediaSourceReadyState
  142. MediaSource::ReadyState()
  143. {
  144. MOZ_ASSERT(NS_IsMainThread());
  145. return mReadyState;
  146. }
  147. double
  148. MediaSource::Duration()
  149. {
  150. MOZ_ASSERT(NS_IsMainThread());
  151. if (mReadyState == MediaSourceReadyState::Closed) {
  152. return UnspecifiedNaN<double>();
  153. }
  154. MOZ_ASSERT(mDecoder);
  155. return mDecoder->GetDuration();
  156. }
  157. void
  158. MediaSource::SetDuration(double aDuration, ErrorResult& aRv)
  159. {
  160. MOZ_ASSERT(NS_IsMainThread());
  161. MSE_API("SetDuration(aDuration=%f, ErrorResult)", aDuration);
  162. if (aDuration < 0 || IsNaN(aDuration)) {
  163. aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
  164. return;
  165. }
  166. if (mReadyState != MediaSourceReadyState::Open ||
  167. mSourceBuffers->AnyUpdating()) {
  168. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  169. return;
  170. }
  171. DurationChange(aDuration, aRv);
  172. }
  173. void
  174. MediaSource::SetDuration(double aDuration)
  175. {
  176. MOZ_ASSERT(NS_IsMainThread());
  177. MSE_API("SetDuration(aDuration=%f)", aDuration);
  178. mDecoder->SetMediaSourceDuration(aDuration);
  179. }
  180. already_AddRefed<SourceBuffer>
  181. MediaSource::AddSourceBuffer(const nsAString& aType, ErrorResult& aRv)
  182. {
  183. MOZ_ASSERT(NS_IsMainThread());
  184. DecoderDoctorDiagnostics diagnostics;
  185. nsresult rv = IsTypeSupported(aType, &diagnostics);
  186. diagnostics.StoreFormatDiagnostics(GetOwner()
  187. ? GetOwner()->GetExtantDoc()
  188. : nullptr,
  189. aType, NS_SUCCEEDED(rv), __func__);
  190. MSE_API("AddSourceBuffer(aType=%s)%s",
  191. NS_ConvertUTF16toUTF8(aType).get(),
  192. rv == NS_OK ? "" : " [not supported]");
  193. if (NS_FAILED(rv)) {
  194. aRv.Throw(rv);
  195. return nullptr;
  196. }
  197. if (mSourceBuffers->Length() >= MAX_SOURCE_BUFFERS) {
  198. aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR);
  199. return nullptr;
  200. }
  201. if (mReadyState != MediaSourceReadyState::Open) {
  202. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  203. return nullptr;
  204. }
  205. MediaContentType contentType{aType};
  206. if (!contentType.IsValid()) {
  207. aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
  208. return nullptr;
  209. }
  210. const nsACString& mimeType = contentType.GetMIMEType();
  211. RefPtr<SourceBuffer> sourceBuffer = new SourceBuffer(this, mimeType);
  212. if (!sourceBuffer) {
  213. aRv.Throw(NS_ERROR_FAILURE); // XXX need a better error here
  214. return nullptr;
  215. }
  216. mSourceBuffers->Append(sourceBuffer);
  217. MSE_DEBUG("sourceBuffer=%p", sourceBuffer.get());
  218. return sourceBuffer.forget();
  219. }
  220. void
  221. MediaSource::SourceBufferIsActive(SourceBuffer* aSourceBuffer)
  222. {
  223. MOZ_ASSERT(NS_IsMainThread());
  224. mActiveSourceBuffers->ClearSimple();
  225. bool found = false;
  226. for (uint32_t i = 0; i < mSourceBuffers->Length(); i++) {
  227. SourceBuffer* sourceBuffer = mSourceBuffers->IndexedGetter(i, found);
  228. MOZ_ALWAYS_TRUE(found);
  229. if (sourceBuffer == aSourceBuffer) {
  230. mActiveSourceBuffers->Append(aSourceBuffer);
  231. } else if (sourceBuffer->IsActive()) {
  232. mActiveSourceBuffers->AppendSimple(sourceBuffer);
  233. }
  234. }
  235. }
  236. void
  237. MediaSource::RemoveSourceBuffer(SourceBuffer& aSourceBuffer, ErrorResult& aRv)
  238. {
  239. MOZ_ASSERT(NS_IsMainThread());
  240. SourceBuffer* sourceBuffer = &aSourceBuffer;
  241. MSE_API("RemoveSourceBuffer(aSourceBuffer=%p)", sourceBuffer);
  242. if (!mSourceBuffers->Contains(sourceBuffer)) {
  243. aRv.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
  244. return;
  245. }
  246. sourceBuffer->AbortBufferAppend();
  247. // TODO:
  248. // abort stream append loop (if running)
  249. // TODO:
  250. // For all sourceBuffer audioTracks, videoTracks, textTracks:
  251. // set sourceBuffer to null
  252. // remove sourceBuffer video, audio, text Tracks from MediaElement tracks
  253. // remove sourceBuffer video, audio, text Tracks and fire "removetrack" at affected lists
  254. // fire "removetrack" at modified MediaElement track lists
  255. // If removed enabled/selected, fire "change" at affected MediaElement list.
  256. if (mActiveSourceBuffers->Contains(sourceBuffer)) {
  257. mActiveSourceBuffers->Remove(sourceBuffer);
  258. }
  259. mSourceBuffers->Remove(sourceBuffer);
  260. // TODO: Free all resources associated with sourceBuffer
  261. }
  262. void
  263. MediaSource::EndOfStream(const Optional<MediaSourceEndOfStreamError>& aError, ErrorResult& aRv)
  264. {
  265. MOZ_ASSERT(NS_IsMainThread());
  266. MSE_API("EndOfStream(aError=%d)",
  267. aError.WasPassed() ? uint32_t(aError.Value()) : 0);
  268. if (mReadyState != MediaSourceReadyState::Open ||
  269. mSourceBuffers->AnyUpdating()) {
  270. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  271. return;
  272. }
  273. SetReadyState(MediaSourceReadyState::Ended);
  274. mSourceBuffers->Ended();
  275. if (!aError.WasPassed()) {
  276. DurationChange(mSourceBuffers->GetHighestBufferedEndTime(), aRv);
  277. // Notify reader that all data is now available.
  278. mDecoder->Ended(true);
  279. return;
  280. }
  281. switch (aError.Value()) {
  282. case MediaSourceEndOfStreamError::Network:
  283. mDecoder->NetworkError();
  284. break;
  285. case MediaSourceEndOfStreamError::Decode:
  286. mDecoder->DecodeError(NS_ERROR_DOM_MEDIA_FATAL_ERR);
  287. break;
  288. default:
  289. aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
  290. }
  291. }
  292. void
  293. MediaSource::EndOfStream(const MediaResult& aError)
  294. {
  295. MOZ_ASSERT(NS_IsMainThread());
  296. MSE_API("EndOfStream(aError=%d)", aError.Code());
  297. SetReadyState(MediaSourceReadyState::Ended);
  298. mSourceBuffers->Ended();
  299. mDecoder->DecodeError(aError);
  300. }
  301. /* static */ bool
  302. MediaSource::IsTypeSupported(const GlobalObject& aOwner, const nsAString& aType)
  303. {
  304. MOZ_ASSERT(NS_IsMainThread());
  305. DecoderDoctorDiagnostics diagnostics;
  306. nsresult rv = IsTypeSupported(aType, &diagnostics);
  307. nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aOwner.GetAsSupports());
  308. diagnostics.StoreFormatDiagnostics(window ? window->GetExtantDoc() : nullptr,
  309. aType, NS_SUCCEEDED(rv), __func__);
  310. #define this nullptr
  311. MSE_API("IsTypeSupported(aType=%s)%s ",
  312. NS_ConvertUTF16toUTF8(aType).get(), rv == NS_OK ? "OK" : "[not supported]");
  313. #undef this // don't ever remove this line !
  314. return NS_SUCCEEDED(rv);
  315. }
  316. /* static */ bool
  317. MediaSource::Enabled(JSContext* cx, JSObject* aGlobal)
  318. {
  319. return Preferences::GetBool("media.mediasource.enabled");
  320. }
  321. void
  322. MediaSource::SetLiveSeekableRange(double aStart, double aEnd, ErrorResult& aRv)
  323. {
  324. MOZ_ASSERT(NS_IsMainThread());
  325. // 1. If the readyState attribute is not "open" then throw an InvalidStateError
  326. // exception and abort these steps.
  327. if (mReadyState != MediaSourceReadyState::Open) {
  328. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  329. return;
  330. }
  331. // 2. If start is negative or greater than end, then throw a TypeError
  332. // exception and abort these steps.
  333. if (aStart < 0 || aStart > aEnd) {
  334. aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
  335. return;
  336. }
  337. // 3. Set live seekable range to be a new normalized TimeRanges object
  338. // containing a single range whose start position is start and end position is
  339. // end.
  340. mLiveSeekableRange =
  341. Some(media::TimeInterval(media::TimeUnit::FromSeconds(aStart),
  342. media::TimeUnit::FromSeconds(aEnd)));
  343. }
  344. void
  345. MediaSource::ClearLiveSeekableRange(ErrorResult& aRv)
  346. {
  347. MOZ_ASSERT(NS_IsMainThread());
  348. // 1. If the readyState attribute is not "open" then throw an InvalidStateError
  349. // exception and abort these steps.
  350. if (mReadyState != MediaSourceReadyState::Open) {
  351. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  352. return;
  353. }
  354. // 2. If live seekable range contains a range, then set live seekable range to
  355. // be a new empty TimeRanges object.
  356. mLiveSeekableRange.reset();
  357. }
  358. bool
  359. MediaSource::Attach(MediaSourceDecoder* aDecoder)
  360. {
  361. MOZ_ASSERT(NS_IsMainThread());
  362. MSE_DEBUG("Attach(aDecoder=%p) owner=%p", aDecoder, aDecoder->GetOwner());
  363. MOZ_ASSERT(aDecoder);
  364. MOZ_ASSERT(aDecoder->GetOwner());
  365. if (mReadyState != MediaSourceReadyState::Closed) {
  366. return false;
  367. }
  368. MOZ_ASSERT(!mMediaElement);
  369. mMediaElement = aDecoder->GetOwner()->GetMediaElement();
  370. MOZ_ASSERT(!mDecoder);
  371. mDecoder = aDecoder;
  372. mDecoder->AttachMediaSource(this);
  373. SetReadyState(MediaSourceReadyState::Open);
  374. return true;
  375. }
  376. void
  377. MediaSource::Detach()
  378. {
  379. MOZ_ASSERT(NS_IsMainThread());
  380. MSE_DEBUG("mDecoder=%p owner=%p",
  381. mDecoder.get(), mDecoder ? mDecoder->GetOwner() : nullptr);
  382. if (!mDecoder) {
  383. MOZ_ASSERT(mReadyState == MediaSourceReadyState::Closed);
  384. MOZ_ASSERT(mActiveSourceBuffers->IsEmpty() && mSourceBuffers->IsEmpty());
  385. return;
  386. }
  387. mMediaElement = nullptr;
  388. SetReadyState(MediaSourceReadyState::Closed);
  389. if (mActiveSourceBuffers) {
  390. mActiveSourceBuffers->Clear();
  391. }
  392. if (mSourceBuffers) {
  393. mSourceBuffers->Clear();
  394. }
  395. mDecoder->DetachMediaSource();
  396. mDecoder = nullptr;
  397. }
  398. MediaSource::MediaSource(nsPIDOMWindowInner* aWindow)
  399. : DOMEventTargetHelper(aWindow)
  400. , mDecoder(nullptr)
  401. , mPrincipal(nullptr)
  402. , mReadyState(MediaSourceReadyState::Closed)
  403. {
  404. MOZ_ASSERT(NS_IsMainThread());
  405. mSourceBuffers = new SourceBufferList(this);
  406. mActiveSourceBuffers = new SourceBufferList(this);
  407. nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow);
  408. if (sop) {
  409. mPrincipal = sop->GetPrincipal();
  410. }
  411. MSE_API("MediaSource(aWindow=%p) mSourceBuffers=%p mActiveSourceBuffers=%p",
  412. aWindow, mSourceBuffers.get(), mActiveSourceBuffers.get());
  413. }
  414. void
  415. MediaSource::SetReadyState(MediaSourceReadyState aState)
  416. {
  417. MOZ_ASSERT(NS_IsMainThread());
  418. MOZ_ASSERT(aState != mReadyState);
  419. MSE_DEBUG("SetReadyState(aState=%d) mReadyState=%d", aState, mReadyState);
  420. MediaSourceReadyState oldState = mReadyState;
  421. mReadyState = aState;
  422. if (mReadyState == MediaSourceReadyState::Open &&
  423. (oldState == MediaSourceReadyState::Closed ||
  424. oldState == MediaSourceReadyState::Ended)) {
  425. QueueAsyncSimpleEvent("sourceopen");
  426. if (oldState == MediaSourceReadyState::Ended) {
  427. // Notify reader that more data may come.
  428. mDecoder->Ended(false);
  429. }
  430. return;
  431. }
  432. if (mReadyState == MediaSourceReadyState::Ended &&
  433. oldState == MediaSourceReadyState::Open) {
  434. QueueAsyncSimpleEvent("sourceended");
  435. return;
  436. }
  437. if (mReadyState == MediaSourceReadyState::Closed &&
  438. (oldState == MediaSourceReadyState::Open ||
  439. oldState == MediaSourceReadyState::Ended)) {
  440. QueueAsyncSimpleEvent("sourceclose");
  441. return;
  442. }
  443. NS_WARNING("Invalid MediaSource readyState transition");
  444. }
  445. void
  446. MediaSource::DispatchSimpleEvent(const char* aName)
  447. {
  448. MOZ_ASSERT(NS_IsMainThread());
  449. MSE_API("Dispatch event '%s'", aName);
  450. DispatchTrustedEvent(NS_ConvertUTF8toUTF16(aName));
  451. }
  452. void
  453. MediaSource::QueueAsyncSimpleEvent(const char* aName)
  454. {
  455. MSE_DEBUG("Queuing event '%s'", aName);
  456. nsCOMPtr<nsIRunnable> event = new AsyncEventRunner<MediaSource>(this, aName);
  457. NS_DispatchToMainThread(event);
  458. }
  459. void
  460. MediaSource::DurationChange(double aNewDuration, ErrorResult& aRv)
  461. {
  462. MOZ_ASSERT(NS_IsMainThread());
  463. MSE_DEBUG("DurationChange(aNewDuration=%f)", aNewDuration);
  464. // 1. If the current value of duration is equal to new duration, then return.
  465. if (mDecoder->GetDuration() == aNewDuration) {
  466. return;
  467. }
  468. // 2. If new duration is less than the highest starting presentation timestamp
  469. // of any buffered coded frames for all SourceBuffer objects in sourceBuffers,
  470. // then throw an InvalidStateError exception and abort these steps.
  471. if (aNewDuration < mSourceBuffers->HighestStartTime()) {
  472. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  473. return;
  474. }
  475. // 3. Let highest end time be the largest track buffer ranges end time across
  476. // all the track buffers across all SourceBuffer objects in sourceBuffers.
  477. double highestEndTime = mSourceBuffers->HighestEndTime();
  478. // 4. If new duration is less than highest end time, then
  479. // 4.1 Update new duration to equal highest end time.
  480. aNewDuration =
  481. std::max(aNewDuration, highestEndTime);
  482. // 5. Update the media duration to new duration and run the HTMLMediaElement
  483. // duration change algorithm.
  484. mDecoder->SetMediaSourceDuration(aNewDuration);
  485. }
  486. void
  487. MediaSource::GetMozDebugReaderData(nsAString& aString)
  488. {
  489. mDecoder->GetMozDebugReaderData(aString);
  490. }
  491. nsPIDOMWindowInner*
  492. MediaSource::GetParentObject() const
  493. {
  494. return GetOwner();
  495. }
  496. JSObject*
  497. MediaSource::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
  498. {
  499. return MediaSourceBinding::Wrap(aCx, this, aGivenProto);
  500. }
  501. NS_IMPL_CYCLE_COLLECTION_INHERITED(MediaSource, DOMEventTargetHelper,
  502. mMediaElement,
  503. mSourceBuffers, mActiveSourceBuffers)
  504. NS_IMPL_ADDREF_INHERITED(MediaSource, DOMEventTargetHelper)
  505. NS_IMPL_RELEASE_INHERITED(MediaSource, DOMEventTargetHelper)
  506. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MediaSource)
  507. NS_INTERFACE_MAP_ENTRY(mozilla::dom::MediaSource)
  508. NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
  509. #undef MSE_DEBUG
  510. #undef MSE_API
  511. } // namespace dom
  512. } // namespace mozilla