michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=8 sts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: #if !defined(MediaDecoderReader_h_) michael@0: #define MediaDecoderReader_h_ michael@0: michael@0: #include "AbstractMediaDecoder.h" michael@0: #include "MediaInfo.h" michael@0: #include "MediaData.h" michael@0: #include "MediaQueue.h" michael@0: #include "AudioCompactor.h" michael@0: michael@0: namespace mozilla { michael@0: michael@0: namespace dom { michael@0: class TimeRanges; michael@0: } michael@0: michael@0: // Encapsulates the decoding and reading of media data. Reading can only be michael@0: // done on the decode thread. Never hold the decoder monitor when michael@0: // calling into this class. Unless otherwise specified, methods and fields of michael@0: // this class can only be accessed on the decode thread. michael@0: class MediaDecoderReader { michael@0: public: michael@0: MediaDecoderReader(AbstractMediaDecoder* aDecoder); michael@0: virtual ~MediaDecoderReader(); michael@0: michael@0: // Initializes the reader, returns NS_OK on success, or NS_ERROR_FAILURE michael@0: // on failure. michael@0: virtual nsresult Init(MediaDecoderReader* aCloneDonor) = 0; michael@0: michael@0: // True if this reader is waiting media resource allocation michael@0: virtual bool IsWaitingMediaResources() { return false; } michael@0: // True when this reader need to become dormant state michael@0: virtual bool IsDormantNeeded() { return false; } michael@0: // Release media resources they should be released in dormant state michael@0: virtual void ReleaseMediaResources() {}; michael@0: // Release the decoder during shutdown michael@0: virtual void ReleaseDecoder() {}; michael@0: michael@0: // Resets all state related to decoding, emptying all buffers etc. michael@0: virtual nsresult ResetDecode(); michael@0: michael@0: // Decodes an unspecified amount of audio data, enqueuing the audio data michael@0: // in mAudioQueue. Returns true when there's more audio to decode, michael@0: // false if the audio is finished, end of file has been reached, michael@0: // or an un-recoverable read error has occured. michael@0: virtual bool DecodeAudioData() = 0; michael@0: michael@0: // Reads and decodes one video frame. Packets with a timestamp less michael@0: // than aTimeThreshold will be decoded (unless they're not keyframes michael@0: // and aKeyframeSkip is true), but will not be added to the queue. michael@0: virtual bool DecodeVideoFrame(bool &aKeyframeSkip, michael@0: int64_t aTimeThreshold) = 0; michael@0: michael@0: virtual bool HasAudio() = 0; michael@0: virtual bool HasVideo() = 0; michael@0: michael@0: // Read header data for all bitstreams in the file. Fills aInfo with michael@0: // the data required to present the media, and optionally fills *aTags michael@0: // with tag metadata from the file. michael@0: // Returns NS_OK on success, or NS_ERROR_FAILURE on failure. michael@0: virtual nsresult ReadMetadata(MediaInfo* aInfo, michael@0: MetadataTags** aTags) = 0; michael@0: michael@0: // Stores the presentation time of the first frame we'd be able to play if michael@0: // we started playback at the current position. Returns the first video michael@0: // frame, if we have video. michael@0: virtual VideoData* FindStartTime(int64_t& aOutStartTime); michael@0: michael@0: // Moves the decode head to aTime microseconds. aStartTime and aEndTime michael@0: // denote the start and end times of the media in usecs, and aCurrentTime michael@0: // is the current playback position in microseconds. michael@0: virtual nsresult Seek(int64_t aTime, michael@0: int64_t aStartTime, michael@0: int64_t aEndTime, michael@0: int64_t aCurrentTime) = 0; michael@0: michael@0: // Called to move the reader into idle/active state. When the reader is michael@0: // created it is assumed to be active (i.e. not idle). When the media michael@0: // element is paused and we don't need to decode any more data, the state michael@0: // machine calls SetIdle() to inform the reader that its decoder won't be michael@0: // needed for a while. When we need to decode data again, the state machine michael@0: // calls SetActive() to activate the decoder. The reader can use these michael@0: // notifications to enter/exit a low power state when the decoder isn't michael@0: // needed, if desired. This is most useful on mobile. michael@0: virtual void SetIdle() { } michael@0: virtual void SetActive() { } michael@0: michael@0: // Tell the reader that the data decoded are not for direct playback, so it michael@0: // can accept more files, in particular those which have more channels than michael@0: // available in the audio output. michael@0: void SetIgnoreAudioOutputFormat() michael@0: { michael@0: mIgnoreAudioOutputFormat = true; michael@0: } michael@0: michael@0: protected: michael@0: // Queue of audio frames. This queue is threadsafe, and is accessed from michael@0: // the audio, decoder, state machine, and main threads. michael@0: MediaQueue mAudioQueue; michael@0: michael@0: // Queue of video frames. This queue is threadsafe, and is accessed from michael@0: // the decoder, state machine, and main threads. michael@0: MediaQueue mVideoQueue; michael@0: michael@0: // An adapter to the audio queue which first copies data to buffers with michael@0: // minimal allocation slop and then pushes them to the queue. This is michael@0: // useful for decoders working with formats that give awkward numbers of michael@0: // frames such as mp3. michael@0: AudioCompactor mAudioCompactor; michael@0: michael@0: public: michael@0: // Populates aBuffered with the time ranges which are buffered. aStartTime michael@0: // must be the presentation time of the first frame in the media, e.g. michael@0: // the media time corresponding to playback time/position 0. This function michael@0: // is called on the main, decode, and state machine threads. michael@0: // michael@0: // This base implementation in MediaDecoderReader estimates the time ranges michael@0: // buffered by interpolating the cached byte ranges with the duration michael@0: // of the media. Reader subclasses should override this method if they michael@0: // can quickly calculate the buffered ranges more accurately. michael@0: // michael@0: // The primary advantage of this implementation in the reader base class michael@0: // is that it's a fast approximation, which does not perform any I/O. michael@0: // michael@0: // The OggReader relies on this base implementation not performing I/O, michael@0: // since in FirefoxOS we can't do I/O on the main thread, where this is michael@0: // called. michael@0: virtual nsresult GetBuffered(dom::TimeRanges* aBuffered, michael@0: int64_t aStartTime); michael@0: michael@0: // Returns the number of bytes of memory allocated by structures/frames in michael@0: // the video queue. michael@0: size_t SizeOfVideoQueueInBytes() const; michael@0: michael@0: // Returns the number of bytes of memory allocated by structures/frames in michael@0: // the audio queue. michael@0: size_t SizeOfAudioQueueInBytes() const; michael@0: michael@0: // Only used by WebMReader and MediaOmxReader for now, so stub here rather michael@0: // than in every reader than inherits from MediaDecoderReader. michael@0: virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) {} michael@0: michael@0: virtual MediaQueue& AudioQueue() { return mAudioQueue; } michael@0: virtual MediaQueue& VideoQueue() { return mVideoQueue; } michael@0: michael@0: // Returns a pointer to the decoder. michael@0: AbstractMediaDecoder* GetDecoder() { michael@0: return mDecoder; michael@0: } michael@0: michael@0: AudioData* DecodeToFirstAudioData(); michael@0: VideoData* DecodeToFirstVideoData(); michael@0: michael@0: // Decodes samples until we reach frames required to play at time aTarget michael@0: // (usecs). This also trims the samples to start exactly at aTarget, michael@0: // by discarding audio samples and adjusting start times of video frames. michael@0: nsresult DecodeToTarget(int64_t aTarget); michael@0: michael@0: MediaInfo GetMediaInfo() { return mInfo; } michael@0: michael@0: protected: michael@0: michael@0: // Reference to the owning decoder object. michael@0: AbstractMediaDecoder* mDecoder; michael@0: michael@0: // Stores presentation info required for playback. michael@0: MediaInfo mInfo; michael@0: michael@0: // Whether we should accept media that we know we can't play michael@0: // directly, because they have a number of channel higher than michael@0: // what we support. michael@0: bool mIgnoreAudioOutputFormat; michael@0: }; michael@0: michael@0: } // namespace mozilla michael@0: michael@0: #endif