/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:set ts=2 sw=2 sts=2 et cindent: */ /* 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/. */ #if !defined(MP4Reader_h_) #define MP4Reader_h_ #include "MediaDecoderReader.h" #include "nsAutoPtr.h" #include "PlatformDecoderModule.h" #include "mp4_demuxer/mp4_demuxer.h" #include "MediaTaskQueue.h" #include #include "mozilla/Monitor.h" namespace mozilla { namespace dom { class TimeRanges; } typedef std::deque MP4SampleQueue; class MP4Stream; class MP4Reader MOZ_FINAL : public MediaDecoderReader { typedef mp4_demuxer::TrackType TrackType; public: explicit MP4Reader(AbstractMediaDecoder* aDecoder); virtual ~MP4Reader(); virtual nsresult Init(MediaDecoderReader* aCloneDonor) MOZ_OVERRIDE; virtual size_t SizeOfVideoQueueInFrames() MOZ_OVERRIDE; virtual size_t SizeOfAudioQueueInFrames() MOZ_OVERRIDE; virtual nsRefPtr RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold) MOZ_OVERRIDE; virtual nsRefPtr RequestAudioData() MOZ_OVERRIDE; virtual bool HasAudio() MOZ_OVERRIDE; virtual bool HasVideo() MOZ_OVERRIDE; // PreReadMetadata() is called by MediaDecoderStateMachine::DecodeMetadata() // before checking hardware resource. In Gonk, it requests hardware codec so // MediaDecoderStateMachine could go to DORMANT state if the hardware codec is // not available. virtual void PreReadMetadata() MOZ_OVERRIDE; virtual nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) MOZ_OVERRIDE; virtual void ReadUpdatedMetadata(MediaInfo* aInfo) MOZ_OVERRIDE; virtual nsRefPtr Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) MOZ_OVERRIDE; virtual bool IsMediaSeekable() MOZ_OVERRIDE; virtual int64_t GetEvictionOffset(double aTime) MOZ_OVERRIDE; virtual nsresult GetBuffered(dom::TimeRanges* aBuffered) MOZ_OVERRIDE; // For Media Resource Management virtual void SetIdle() MOZ_OVERRIDE; virtual bool IsWaitingMediaResources() MOZ_OVERRIDE; virtual bool IsDormantNeeded() MOZ_OVERRIDE; virtual void ReleaseMediaResources() MOZ_OVERRIDE; virtual void SetSharedDecoderManager(SharedDecoderManager* aManager) MOZ_OVERRIDE; virtual nsresult ResetDecode() MOZ_OVERRIDE; virtual nsRefPtr Shutdown() MOZ_OVERRIDE; private: bool InitDemuxer(); void ReturnOutput(MediaData* aData, TrackType aTrack); // Sends input to decoder for aTrack, and output to the state machine, // if necessary. void Update(TrackType aTrack); // Enqueues a task to call Update(aTrack) on the decoder task queue. // Lock for corresponding track must be held. void ScheduleUpdate(TrackType aTrack); void ExtractCryptoInitData(nsTArray& aInitData); // Initializes mLayersBackendType if possible. void InitLayersBackendType(); // Blocks until the demuxer produces an sample of specified type. // Returns nullptr on error on EOS. Caller must delete sample. mp4_demuxer::MP4Sample* PopSample(mp4_demuxer::TrackType aTrack); mp4_demuxer::MP4Sample* PopSampleLocked(mp4_demuxer::TrackType aTrack); bool SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint32_t& parsed); // DecoderCallback proxies the MediaDataDecoderCallback calls to these // functions. void Output(mp4_demuxer::TrackType aType, MediaData* aSample); void InputExhausted(mp4_demuxer::TrackType aTrack); void Error(mp4_demuxer::TrackType aTrack); void Flush(mp4_demuxer::TrackType aTrack); void DrainComplete(mp4_demuxer::TrackType aTrack); void UpdateIndex(); bool IsSupportedAudioMimeType(const char* aMimeType); bool IsSupportedVideoMimeType(const char* aMimeType); void NotifyResourcesStatusChanged(); void RequestCodecResource(); bool IsWaitingOnCodecResource(); virtual bool IsWaitingOnCDMResource() MOZ_OVERRIDE; size_t SizeOfQueue(TrackType aTrack); nsRefPtr mStream; int64_t mTimestampOffset; nsAutoPtr mDemuxer; nsRefPtr mPlatform; class DecoderCallback : public MediaDataDecoderCallback { public: DecoderCallback(MP4Reader* aReader, mp4_demuxer::TrackType aType) : mReader(aReader) , mType(aType) { } virtual void Output(MediaData* aSample) MOZ_OVERRIDE { mReader->Output(mType, aSample); } virtual void InputExhausted() MOZ_OVERRIDE { mReader->InputExhausted(mType); } virtual void Error() MOZ_OVERRIDE { mReader->Error(mType); } virtual void DrainComplete() MOZ_OVERRIDE { mReader->DrainComplete(mType); } virtual void NotifyResourcesStatusChanged() MOZ_OVERRIDE { mReader->NotifyResourcesStatusChanged(); } virtual void ReleaseMediaResources() MOZ_OVERRIDE { mReader->ReleaseMediaResources(); } private: MP4Reader* mReader; mp4_demuxer::TrackType mType; }; struct DecoderData { DecoderData(MediaData::Type aType, uint32_t aDecodeAhead) : mType(aType) , mMonitor(aType == MediaData::AUDIO_DATA ? "MP4 audio decoder data" : "MP4 video decoder data") , mNumSamplesInput(0) , mNumSamplesOutput(0) , mDecodeAhead(aDecodeAhead) , mActive(false) , mInputExhausted(false) , mError(false) , mIsFlushing(false) , mUpdateScheduled(false) , mDemuxEOS(false) , mDrainComplete(false) , mDiscontinuity(false) { } // The platform decoder. nsRefPtr mDecoder; // TaskQueue on which decoder can choose to decode. // Only non-null up until the decoder is created. nsRefPtr mTaskQueue; // Callback that receives output and error notifications from the decoder. nsAutoPtr mCallback; // Decoded samples returned my mDecoder awaiting being returned to // state machine upon request. nsTArray > mOutput; // Disambiguate Audio vs Video. MediaData::Type mType; // These get overriden in the templated concrete class. virtual bool HasPromise() = 0; virtual void RejectPromise(MediaDecoderReader::NotDecodedReason aReason, const char* aMethodName) = 0; // Monitor that protects all non-threadsafe state; the primitives // that follow. Monitor mMonitor; uint64_t mNumSamplesInput; uint64_t mNumSamplesOutput; uint32_t mDecodeAhead; // Whether this stream exists in the media. bool mActive; bool mInputExhausted; bool mError; bool mIsFlushing; bool mUpdateScheduled; bool mDemuxEOS; bool mDrainComplete; bool mDiscontinuity; }; template struct DecoderDataWithPromise : public DecoderData { DecoderDataWithPromise(MediaData::Type aType, uint32_t aDecodeAhead) : DecoderData(aType, aDecodeAhead) { mPromise.SetMonitor(&mMonitor); } MediaPromiseHolder mPromise; bool HasPromise() MOZ_OVERRIDE { return !mPromise.IsEmpty(); } void RejectPromise(MediaDecoderReader::NotDecodedReason aReason, const char* aMethodName) MOZ_OVERRIDE { mPromise.Reject(aReason, aMethodName); } }; DecoderDataWithPromise mAudio; DecoderDataWithPromise mVideo; // Queued samples extracted by the demuxer, but not yet sent to the platform // decoder. nsAutoPtr mQueuedVideoSample; // Returns true when the decoder for this track needs input. // aDecoder.mMonitor must be locked. bool NeedInput(DecoderData& aDecoder); // The last number of decoded output frames that we've reported to // MediaDecoder::NotifyDecoded(). We diff the number of output video // frames every time that DecodeVideoData() is called, and report the // delta there. uint64_t mLastReportedNumDecodedFrames; DecoderData& GetDecoderData(mp4_demuxer::TrackType aTrack); layers::LayersBackend mLayersBackendType; nsTArray> mInitDataEncountered; // True if we've read the streams' metadata. bool mDemuxerInitialized; // Synchronized by decoder monitor. bool mIsEncrypted; bool mIndexReady; Monitor mDemuxerMonitor; nsRefPtr mSharedDecoderManager; }; } // namespace mozilla #endif