MediaFormatReader.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  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. #if !defined(MediaFormatReader_h_)
  7. #define MediaFormatReader_h_
  8. #include "mozilla/Atomics.h"
  9. #include "mozilla/Maybe.h"
  10. #include "mozilla/TaskQueue.h"
  11. #include "mozilla/Monitor.h"
  12. #include "MediaEventSource.h"
  13. #include "MediaDataDemuxer.h"
  14. #include "MediaDecoderReader.h"
  15. #include "nsAutoPtr.h"
  16. #include "PDMFactory.h"
  17. namespace mozilla {
  18. #ifdef MOZ_EME
  19. class CDMProxy;
  20. #endif
  21. class MediaFormatReader final : public MediaDecoderReader
  22. {
  23. typedef TrackInfo::TrackType TrackType;
  24. public:
  25. MediaFormatReader(AbstractMediaDecoder* aDecoder,
  26. MediaDataDemuxer* aDemuxer,
  27. VideoFrameContainer* aVideoFrameContainer = nullptr);
  28. virtual ~MediaFormatReader();
  29. size_t SizeOfVideoQueueInFrames() override;
  30. size_t SizeOfAudioQueueInFrames() override;
  31. RefPtr<MediaDataPromise>
  32. RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold) override;
  33. RefPtr<MediaDataPromise> RequestAudioData() override;
  34. RefPtr<MetadataPromise> AsyncReadMetadata() override;
  35. void ReadUpdatedMetadata(MediaInfo* aInfo) override;
  36. RefPtr<SeekPromise>
  37. Seek(SeekTarget aTarget, int64_t aUnused) override;
  38. protected:
  39. void NotifyDataArrivedInternal() override;
  40. public:
  41. media::TimeIntervals GetBuffered() override;
  42. RefPtr<BufferedUpdatePromise> UpdateBufferedWithPromise() override;
  43. bool ForceZeroStartTime() const override;
  44. // For Media Resource Management
  45. void ReleaseResources() override;
  46. nsresult ResetDecode(TrackSet aTracks) override;
  47. RefPtr<ShutdownPromise> Shutdown() override;
  48. bool IsAsync() const override { return true; }
  49. bool VideoIsHardwareAccelerated() const override;
  50. bool IsWaitForDataSupported() const override { return true; }
  51. RefPtr<WaitForDataPromise> WaitForData(MediaData::Type aType) override;
  52. // MediaFormatReader supports demuxed-only mode.
  53. bool IsDemuxOnlySupported() const override { return true; }
  54. void SetDemuxOnly(bool aDemuxedOnly) override
  55. {
  56. if (OnTaskQueue()) {
  57. mDemuxOnly = aDemuxedOnly;
  58. return;
  59. }
  60. nsCOMPtr<nsIRunnable> r = NewRunnableMethod<bool>(
  61. this, &MediaDecoderReader::SetDemuxOnly, aDemuxedOnly);
  62. OwnerThread()->Dispatch(r.forget());
  63. }
  64. bool UseBufferingHeuristics() const override
  65. {
  66. return mTrackDemuxersMayBlock;
  67. }
  68. #ifdef MOZ_EME
  69. void SetCDMProxy(CDMProxy* aProxy) override;
  70. #endif
  71. // Returns a string describing the state of the decoder data.
  72. // Used for debugging purposes.
  73. void GetMozDebugReaderData(nsAString& aString);
  74. void SetVideoBlankDecode(bool aIsBlankDecode) override;
  75. private:
  76. nsresult InitInternal() override;
  77. bool HasVideo() const { return mVideo.mTrackDemuxer; }
  78. bool HasAudio() const { return mAudio.mTrackDemuxer; }
  79. bool IsWaitingOnCDMResource();
  80. bool InitDemuxer();
  81. // Notify the demuxer that new data has been received.
  82. // The next queued task calling GetBuffered() is guaranteed to have up to date
  83. // buffered ranges.
  84. void NotifyDemuxer();
  85. void ReturnOutput(MediaData* aData, TrackType aTrack);
  86. // Enqueues a task to call Update(aTrack) on the decoder task queue.
  87. // Lock for corresponding track must be held.
  88. void ScheduleUpdate(TrackType aTrack);
  89. void Update(TrackType aTrack);
  90. // Handle actions should more data be received.
  91. // Returns true if no more action is required.
  92. bool UpdateReceivedNewData(TrackType aTrack);
  93. // Called when new samples need to be demuxed.
  94. void RequestDemuxSamples(TrackType aTrack);
  95. // Handle demuxed samples by the input behavior.
  96. void HandleDemuxedSamples(TrackType aTrack,
  97. AbstractMediaDecoder::AutoNotifyDecoded& aA);
  98. // Decode any pending already demuxed samples.
  99. void DecodeDemuxedSamples(TrackType aTrack,
  100. MediaRawData* aSample);
  101. struct InternalSeekTarget {
  102. InternalSeekTarget(const media::TimeInterval& aTime, bool aDropTarget)
  103. : mTime(aTime)
  104. , mDropTarget(aDropTarget)
  105. , mWaiting(false)
  106. , mHasSeeked(false)
  107. {}
  108. media::TimeUnit Time() const { return mTime.mStart; }
  109. media::TimeUnit EndTime() const { return mTime.mEnd; }
  110. bool Contains(const media::TimeUnit& aTime) const
  111. {
  112. return mTime.Contains(aTime);
  113. }
  114. media::TimeInterval mTime;
  115. bool mDropTarget;
  116. bool mWaiting;
  117. bool mHasSeeked;
  118. };
  119. // Perform an internal seek to aTime. If aDropTarget is true then
  120. // the first sample past the target will be dropped.
  121. void InternalSeek(TrackType aTrack, const InternalSeekTarget& aTarget);
  122. // Drain the current decoder.
  123. void DrainDecoder(TrackType aTrack);
  124. void NotifyNewOutput(TrackType aTrack, MediaData* aSample);
  125. void NotifyInputExhausted(TrackType aTrack);
  126. void NotifyDrainComplete(TrackType aTrack);
  127. void NotifyError(TrackType aTrack, const MediaResult& aError);
  128. void NotifyWaitingForData(TrackType aTrack);
  129. void NotifyWaitingForKey(TrackType aTrack);
  130. void NotifyEndOfStream(TrackType aTrack);
  131. void ExtractCryptoInitData(nsTArray<uint8_t>& aInitData);
  132. // Initializes mLayersBackendType if possible.
  133. void InitLayersBackendType();
  134. // DecoderCallback proxies the MediaDataDecoderCallback calls to these
  135. // functions.
  136. void Output(TrackType aType, MediaData* aSample);
  137. void InputExhausted(TrackType aTrack);
  138. void Error(TrackType aTrack, const MediaResult& aError);
  139. void Reset(TrackType aTrack);
  140. void DrainComplete(TrackType aTrack);
  141. void DropDecodedSamples(TrackType aTrack);
  142. void WaitingForKey(TrackType aTrack);
  143. bool ShouldSkip(bool aSkipToNextKeyframe, media::TimeUnit aTimeThreshold);
  144. void SetVideoDecodeThreshold();
  145. size_t SizeOfQueue(TrackType aTrack);
  146. RefPtr<PDMFactory> mPlatform;
  147. class DecoderCallback : public MediaDataDecoderCallback {
  148. public:
  149. DecoderCallback(MediaFormatReader* aReader, TrackType aType)
  150. : mReader(aReader)
  151. , mType(aType)
  152. {
  153. }
  154. void Output(MediaData* aSample) override {
  155. mReader->Output(mType, aSample);
  156. }
  157. void InputExhausted() override {
  158. mReader->InputExhausted(mType);
  159. }
  160. void Error(const MediaResult& aError) override {
  161. mReader->Error(mType, aError);
  162. }
  163. void DrainComplete() override {
  164. mReader->DrainComplete(mType);
  165. }
  166. void ReleaseMediaResources() override {
  167. mReader->ReleaseResources();
  168. }
  169. bool OnReaderTaskQueue() override {
  170. return mReader->OnTaskQueue();
  171. }
  172. void WaitingForKey() override {
  173. mReader->WaitingForKey(mType);
  174. }
  175. private:
  176. MediaFormatReader* mReader;
  177. TrackType mType;
  178. };
  179. struct DecoderData {
  180. DecoderData(MediaFormatReader* aOwner,
  181. MediaData::Type aType,
  182. uint32_t aNumOfMaxError)
  183. : mOwner(aOwner)
  184. , mType(aType)
  185. , mMonitor("DecoderData")
  186. , mDescription("shutdown")
  187. , mUpdateScheduled(false)
  188. , mDemuxEOS(false)
  189. , mWaitingForData(false)
  190. , mWaitingForKey(false)
  191. , mReceivedNewData(false)
  192. , mOutputRequested(false)
  193. , mDecodePending(false)
  194. , mNeedDraining(false)
  195. , mDraining(false)
  196. , mDrainComplete(false)
  197. , mNumOfConsecutiveError(0)
  198. , mMaxConsecutiveError(aNumOfMaxError)
  199. , mNumSamplesInput(0)
  200. , mNumSamplesOutput(0)
  201. , mNumSamplesOutputTotal(0)
  202. , mNumSamplesSkippedTotal(0)
  203. , mSizeOfQueue(0)
  204. , mIsHardwareAccelerated(false)
  205. , mLastStreamSourceID(UINT32_MAX)
  206. , mIsBlankDecode(false)
  207. {}
  208. MediaFormatReader* mOwner;
  209. // Disambiguate Audio vs Video.
  210. MediaData::Type mType;
  211. RefPtr<MediaTrackDemuxer> mTrackDemuxer;
  212. // TaskQueue on which decoder can choose to decode.
  213. // Only non-null up until the decoder is created.
  214. RefPtr<TaskQueue> mTaskQueue;
  215. // Callback that receives output and error notifications from the decoder.
  216. nsAutoPtr<DecoderCallback> mCallback;
  217. // Monitor protecting mDescription and mDecoder.
  218. Monitor mMonitor;
  219. // The platform decoder.
  220. RefPtr<MediaDataDecoder> mDecoder;
  221. const char* mDescription;
  222. void ShutdownDecoder()
  223. {
  224. MonitorAutoLock mon(mMonitor);
  225. if (mDecoder) {
  226. mDecoder->Shutdown();
  227. }
  228. mDescription = "shutdown";
  229. mDecoder = nullptr;
  230. }
  231. // Only accessed from reader's task queue.
  232. bool mUpdateScheduled;
  233. bool mDemuxEOS;
  234. bool mWaitingForData;
  235. bool mWaitingForKey;
  236. bool mReceivedNewData;
  237. // Pending seek.
  238. MozPromiseRequestHolder<MediaTrackDemuxer::SeekPromise> mSeekRequest;
  239. // Queued demux samples waiting to be decoded.
  240. nsTArray<RefPtr<MediaRawData>> mQueuedSamples;
  241. MozPromiseRequestHolder<MediaTrackDemuxer::SamplesPromise> mDemuxRequest;
  242. // A WaitingPromise is pending if the demuxer is waiting for data or
  243. // if the decoder is waiting for a key.
  244. MozPromiseHolder<WaitForDataPromise> mWaitingPromise;
  245. bool HasWaitingPromise() const
  246. {
  247. MOZ_ASSERT(mOwner->OnTaskQueue());
  248. return !mWaitingPromise.IsEmpty();
  249. }
  250. bool IsWaiting() const
  251. {
  252. MOZ_ASSERT(mOwner->OnTaskQueue());
  253. return mWaitingForData || mWaitingForKey;
  254. }
  255. // MediaDataDecoder handler's variables.
  256. bool mOutputRequested;
  257. // Set to true once the MediaDataDecoder has been fed a compressed sample.
  258. // No more samples will be passed to the decoder while true.
  259. // mDecodePending is reset when:
  260. // 1- The decoder calls InputExhausted
  261. // 2- The decoder is Flushed or Reset.
  262. bool mDecodePending;
  263. bool mNeedDraining;
  264. bool mDraining;
  265. bool mDrainComplete;
  266. bool HasPendingDrain() const
  267. {
  268. return mDraining || mDrainComplete;
  269. }
  270. uint32_t mNumOfConsecutiveError;
  271. uint32_t mMaxConsecutiveError;
  272. Maybe<MediaResult> mError;
  273. bool HasFatalError() const
  274. {
  275. if (!mError.isSome()) {
  276. return false;
  277. }
  278. if (mError.ref() == NS_ERROR_DOM_MEDIA_DECODE_ERR) {
  279. // Allow decode errors to be non-fatal, but give up
  280. // if we have too many.
  281. return mNumOfConsecutiveError > mMaxConsecutiveError;
  282. } else if (mError.ref() == NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER) {
  283. // If the caller asked for a new decoder we shouldn't treat
  284. // it as fatal.
  285. return false;
  286. } else {
  287. // All other error types are fatal
  288. return true;
  289. }
  290. }
  291. // If set, all decoded samples prior mTimeThreshold will be dropped.
  292. // Used for internal seeking when a change of stream is detected or when
  293. // encountering data discontinuity.
  294. Maybe<InternalSeekTarget> mTimeThreshold;
  295. // Time of last sample returned.
  296. Maybe<media::TimeInterval> mLastSampleTime;
  297. // Decoded samples returned my mDecoder awaiting being returned to
  298. // state machine upon request.
  299. nsTArray<RefPtr<MediaData>> mOutput;
  300. uint64_t mNumSamplesInput;
  301. uint64_t mNumSamplesOutput;
  302. uint64_t mNumSamplesOutputTotal;
  303. uint64_t mNumSamplesSkippedTotal;
  304. // These get overridden in the templated concrete class.
  305. // Indicate if we have a pending promise for decoded frame.
  306. // Rejecting the promise will stop the reader from decoding ahead.
  307. virtual bool HasPromise() const = 0;
  308. virtual RefPtr<MediaDataPromise> EnsurePromise(const char* aMethodName) = 0;
  309. virtual void ResolvePromise(MediaData* aData, const char* aMethodName) = 0;
  310. virtual void RejectPromise(const MediaResult& aError,
  311. const char* aMethodName) = 0;
  312. // Clear track demuxer related data.
  313. void ResetDemuxer()
  314. {
  315. mDemuxRequest.DisconnectIfExists();
  316. mSeekRequest.DisconnectIfExists();
  317. mTrackDemuxer->Reset();
  318. mQueuedSamples.Clear();
  319. }
  320. // Flush the decoder if present and reset decoding related data.
  321. // Decoding will be suspended until mInputRequested is set again.
  322. // Following a flush, the decoder is ready to accept any new data.
  323. void Flush()
  324. {
  325. if (mDecoder) {
  326. mDecoder->Flush();
  327. }
  328. mOutputRequested = false;
  329. mDecodePending = false;
  330. mOutput.Clear();
  331. mNumSamplesInput = 0;
  332. mNumSamplesOutput = 0;
  333. mSizeOfQueue = 0;
  334. mDraining = false;
  335. mDrainComplete = false;
  336. }
  337. // Reset the state of the DecoderData, clearing all queued frames
  338. // (pending demuxed and decoded).
  339. // Decoding will be suspended until mInputRequested is set again.
  340. // The track demuxer is *not* reset.
  341. void ResetState()
  342. {
  343. MOZ_ASSERT(mOwner->OnTaskQueue());
  344. mDemuxEOS = false;
  345. mWaitingForData = false;
  346. mWaitingForKey = false;
  347. mQueuedSamples.Clear();
  348. mOutputRequested = false;
  349. mNeedDraining = false;
  350. mDecodePending = false;
  351. mDraining = false;
  352. mDrainComplete = false;
  353. mTimeThreshold.reset();
  354. mLastSampleTime.reset();
  355. mOutput.Clear();
  356. mNumSamplesInput = 0;
  357. mNumSamplesOutput = 0;
  358. mSizeOfQueue = 0;
  359. mNextStreamSourceID.reset();
  360. if (!HasFatalError()) {
  361. mError.reset();
  362. }
  363. }
  364. bool HasInternalSeekPending() const
  365. {
  366. return mTimeThreshold && !mTimeThreshold.ref().mHasSeeked;
  367. }
  368. // Used by the MDSM for logging purposes.
  369. Atomic<size_t> mSizeOfQueue;
  370. // Used by the MDSM to determine if video decoding is hardware accelerated.
  371. // This value is updated after a frame is successfully decoded.
  372. Atomic<bool> mIsHardwareAccelerated;
  373. // Sample format monitoring.
  374. uint32_t mLastStreamSourceID;
  375. Maybe<uint32_t> mNextStreamSourceID;
  376. media::TimeIntervals mTimeRanges;
  377. Maybe<media::TimeUnit> mLastTimeRangesEnd;
  378. // TrackInfo as first discovered during ReadMetadata.
  379. UniquePtr<TrackInfo> mOriginalInfo;
  380. RefPtr<SharedTrackInfo> mInfo;
  381. Maybe<media::TimeUnit> mFirstDemuxedSampleTime;
  382. // Use BlankDecoderModule or not.
  383. bool mIsBlankDecode;
  384. };
  385. class DecoderDataWithPromise : public DecoderData {
  386. public:
  387. DecoderDataWithPromise(MediaFormatReader* aOwner,
  388. MediaData::Type aType,
  389. uint32_t aNumOfMaxError)
  390. : DecoderData(aOwner, aType, aNumOfMaxError)
  391. , mHasPromise(false)
  392. {}
  393. bool HasPromise() const override
  394. {
  395. return mHasPromise;
  396. }
  397. RefPtr<MediaDataPromise> EnsurePromise(const char* aMethodName) override
  398. {
  399. MOZ_ASSERT(mOwner->OnTaskQueue());
  400. mHasPromise = true;
  401. return mPromise.Ensure(aMethodName);
  402. }
  403. void ResolvePromise(MediaData* aData, const char* aMethodName) override
  404. {
  405. MOZ_ASSERT(mOwner->OnTaskQueue());
  406. mPromise.Resolve(aData, aMethodName);
  407. mHasPromise = false;
  408. }
  409. void RejectPromise(const MediaResult& aError,
  410. const char* aMethodName) override
  411. {
  412. MOZ_ASSERT(mOwner->OnTaskQueue());
  413. mPromise.Reject(aError, aMethodName);
  414. mHasPromise = false;
  415. }
  416. private:
  417. MozPromiseHolder<MediaDataPromise> mPromise;
  418. Atomic<bool> mHasPromise;
  419. };
  420. DecoderDataWithPromise mAudio;
  421. DecoderDataWithPromise mVideo;
  422. // Returns true when the decoder for this track needs input.
  423. bool NeedInput(DecoderData& aDecoder);
  424. DecoderData& GetDecoderData(TrackType aTrack);
  425. // Demuxer objects.
  426. RefPtr<MediaDataDemuxer> mDemuxer;
  427. bool mDemuxerInitDone;
  428. void OnDemuxerInitDone(nsresult);
  429. void OnDemuxerInitFailed(const MediaResult& aError);
  430. MozPromiseRequestHolder<MediaDataDemuxer::InitPromise> mDemuxerInitRequest;
  431. void OnDemuxFailed(TrackType aTrack, const MediaResult& aError);
  432. void DoDemuxVideo();
  433. void OnVideoDemuxCompleted(RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples);
  434. void OnVideoDemuxFailed(const MediaResult& aError)
  435. {
  436. OnDemuxFailed(TrackType::kVideoTrack, aError);
  437. }
  438. void DoDemuxAudio();
  439. void OnAudioDemuxCompleted(RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples);
  440. void OnAudioDemuxFailed(const MediaResult& aError)
  441. {
  442. OnDemuxFailed(TrackType::kAudioTrack, aError);
  443. }
  444. void SkipVideoDemuxToNextKeyFrame(media::TimeUnit aTimeThreshold);
  445. MozPromiseRequestHolder<MediaTrackDemuxer::SkipAccessPointPromise> mSkipRequest;
  446. void VideoSkipReset(uint32_t aSkipped);
  447. void OnVideoSkipCompleted(uint32_t aSkipped);
  448. void OnVideoSkipFailed(MediaTrackDemuxer::SkipFailureHolder aFailure);
  449. // The last number of decoded output frames that we've reported to
  450. // MediaDecoder::NotifyDecoded(). We diff the number of output video
  451. // frames every time that DecodeVideoData() is called, and report the
  452. // delta there.
  453. uint64_t mLastReportedNumDecodedFrames;
  454. // Timestamp of the previous decoded keyframe, in microseconds.
  455. int64_t mPreviousDecodedKeyframeTime_us;
  456. // Default mLastDecodedKeyframeTime_us value, must be bigger than anything.
  457. static const int64_t sNoPreviousDecodedKeyframe = INT64_MAX;
  458. RefPtr<layers::KnowsCompositor> mKnowsCompositor;
  459. // Metadata objects
  460. // True if we've read the streams' metadata.
  461. bool mInitDone;
  462. MozPromiseHolder<MetadataPromise> mMetadataPromise;
  463. bool IsEncrypted() const;
  464. // Set to true if any of our track buffers may be blocking.
  465. bool mTrackDemuxersMayBlock;
  466. // Set the demuxed-only flag.
  467. Atomic<bool> mDemuxOnly;
  468. // Seeking objects.
  469. void SetSeekTarget(const SeekTarget& aTarget);
  470. media::TimeUnit DemuxStartTime();
  471. bool IsSeeking() const { return mPendingSeekTime.isSome(); }
  472. bool IsVideoSeeking() const
  473. {
  474. return IsSeeking() && mOriginalSeekTarget.IsVideoOnly();
  475. }
  476. void ScheduleSeek();
  477. void AttemptSeek();
  478. void OnSeekFailed(TrackType aTrack, const MediaResult& aError);
  479. void DoVideoSeek();
  480. void OnVideoSeekCompleted(media::TimeUnit aTime);
  481. void OnVideoSeekFailed(const MediaResult& aError);
  482. bool mSeekScheduled;
  483. void NotifyCompositorUpdated(RefPtr<layers::KnowsCompositor> aKnowsCompositor)
  484. {
  485. mKnowsCompositor = aKnowsCompositor;
  486. }
  487. void DoAudioSeek();
  488. void OnAudioSeekCompleted(media::TimeUnit aTime);
  489. void OnAudioSeekFailed(const MediaResult& aError);
  490. // The SeekTarget that was last given to Seek()
  491. SeekTarget mOriginalSeekTarget;
  492. // Temporary seek information while we wait for the data
  493. Maybe<media::TimeUnit> mFallbackSeekTime;
  494. Maybe<media::TimeUnit> mPendingSeekTime;
  495. MozPromiseHolder<SeekPromise> mSeekPromise;
  496. RefPtr<VideoFrameContainer> mVideoFrameContainer;
  497. layers::ImageContainer* GetImageContainer();
  498. #ifdef MOZ_EME
  499. RefPtr<CDMProxy> mCDMProxy;
  500. #endif
  501. RefPtr<GMPCrashHelper> mCrashHelper;
  502. void SetBlankDecode(TrackType aTrack, bool aIsBlankDecode);
  503. class DecoderFactory;
  504. UniquePtr<DecoderFactory> mDecoderFactory;
  505. MediaEventListener mCompositorUpdatedListener;
  506. };
  507. } // namespace mozilla
  508. #endif