diff options
Diffstat (limited to 'dom/media/webm/WebMDemuxer.h')
-rw-r--r-- | dom/media/webm/WebMDemuxer.h | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/dom/media/webm/WebMDemuxer.h b/dom/media/webm/WebMDemuxer.h new file mode 100644 index 000000000..6fff38e7d --- /dev/null +++ b/dom/media/webm/WebMDemuxer.h @@ -0,0 +1,292 @@ +/* -*- 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(WebMDemuxer_h_) +#define WebMDemuxer_h_ + +#include "nsTArray.h" +#include "MediaDataDemuxer.h" +#include "NesteggPacketHolder.h" +#include "mozilla/Move.h" + +typedef struct nestegg nestegg; + +namespace mozilla { + +class WebMBufferedState; + +// Queue for holding MediaRawData samples +class MediaRawDataQueue { + public: + uint32_t GetSize() { + return mQueue.size(); + } + + void Push(MediaRawData* aItem) { + mQueue.push_back(aItem); + } + + void Push(already_AddRefed<MediaRawData>&& aItem) { + mQueue.push_back(Move(aItem)); + } + + void PushFront(MediaRawData* aItem) { + mQueue.push_front(aItem); + } + + void PushFront(already_AddRefed<MediaRawData>&& aItem) { + mQueue.push_front(Move(aItem)); + } + + void PushFront(MediaRawDataQueue&& aOther) { + while (!aOther.mQueue.empty()) { + PushFront(aOther.Pop()); + } + } + + already_AddRefed<MediaRawData> PopFront() { + RefPtr<MediaRawData> result = mQueue.front().forget(); + mQueue.pop_front(); + return result.forget(); + } + + already_AddRefed<MediaRawData> Pop() { + RefPtr<MediaRawData> result = mQueue.back().forget(); + mQueue.pop_back(); + return result.forget(); + } + + void Reset() { + while (!mQueue.empty()) { + mQueue.pop_front(); + } + } + + MediaRawDataQueue& operator=(const MediaRawDataQueue& aOther) { + mQueue = aOther.mQueue; + return *this; + } + + const RefPtr<MediaRawData>& First() const { + return mQueue.front(); + } + + const RefPtr<MediaRawData>& Last() const { + return mQueue.back(); + } + +private: + std::deque<RefPtr<MediaRawData>> mQueue; +}; + +class WebMTrackDemuxer; + +class WebMDemuxer : public MediaDataDemuxer +{ +public: + explicit WebMDemuxer(MediaResource* aResource); + // Indicate if the WebMDemuxer is to be used with MediaSource. In which + // case the demuxer will stop reads to the last known complete block. + WebMDemuxer(MediaResource* aResource, bool aIsMediaSource); + + RefPtr<InitPromise> Init() override; + + bool HasTrackType(TrackInfo::TrackType aType) const override; + + uint32_t GetNumberTracks(TrackInfo::TrackType aType) const override; + + UniquePtr<TrackInfo> GetTrackInfo(TrackInfo::TrackType aType, size_t aTrackNumber) const; + + already_AddRefed<MediaTrackDemuxer> GetTrackDemuxer(TrackInfo::TrackType aType, + uint32_t aTrackNumber) override; + + bool IsSeekable() const override; + + bool IsSeekableOnlyInBufferedRanges() const override; + + UniquePtr<EncryptionInfo> GetCrypto() override; + + bool GetOffsetForTime(uint64_t aTime, int64_t* aOffset); + + // Demux next WebM packet and append samples to MediaRawDataQueue + bool GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSamples); + + nsresult Reset(TrackInfo::TrackType aType); + + // Pushes a packet to the front of the audio packet queue. + void PushAudioPacket(NesteggPacketHolder* aItem); + + // Pushes a packet to the front of the video packet queue. + void PushVideoPacket(NesteggPacketHolder* aItem); + + // Public accessor for nestegg callbacks + bool IsMediaSource() const + { + return mIsMediaSource; + } + + int64_t LastWebMBlockOffset() const + { + return mLastWebMBlockOffset; + } + + struct NestEggContext { + NestEggContext(WebMDemuxer* aParent, MediaResource* aResource) + : mParent(aParent) + , mResource(aResource) + , mContext(nullptr) {} + + ~NestEggContext(); + + int Init(); + + // Public accessor for nestegg callbacks + + bool IsMediaSource() const { return mParent->IsMediaSource(); } + MediaResourceIndex* GetResource() { return &mResource; } + + int64_t GetEndDataOffset() const + { + return (!mParent->IsMediaSource() || mParent->LastWebMBlockOffset() < 0) + ? mResource.GetLength() : mParent->LastWebMBlockOffset(); + } + + WebMDemuxer* mParent; + MediaResourceIndex mResource; + nestegg* mContext; + }; + +private: + friend class WebMTrackDemuxer; + + ~WebMDemuxer(); + void InitBufferedState(); + nsresult ReadMetadata(); + void NotifyDataArrived() override; + void NotifyDataRemoved() override; + void EnsureUpToDateIndex(); + media::TimeIntervals GetBuffered(); + nsresult SeekInternal(TrackInfo::TrackType aType, + const media::TimeUnit& aTarget); + CryptoTrack GetTrackCrypto(TrackInfo::TrackType aType, size_t aTrackNumber); + + // Read a packet from the nestegg file. Returns nullptr if all packets for + // the particular track have been read. Pass TrackInfo::kVideoTrack or + // TrackInfo::kVideoTrack to indicate the type of the packet we want to read. + RefPtr<NesteggPacketHolder> NextPacket(TrackInfo::TrackType aType); + + // Internal method that demuxes the next packet from the stream. The caller + // is responsible for making sure it doesn't get lost. + RefPtr<NesteggPacketHolder> DemuxPacket(TrackInfo::TrackType aType); + + // libnestegg audio and video context for webm container. + // Access on reader's thread only. + NestEggContext mVideoContext; + NestEggContext mAudioContext; + MediaResourceIndex& Resource(TrackInfo::TrackType aType) + { + return aType == TrackInfo::kVideoTrack + ? mVideoContext.mResource : mAudioContext.mResource; + } + nestegg* Context(TrackInfo::TrackType aType) const + { + return aType == TrackInfo::kVideoTrack + ? mVideoContext.mContext : mAudioContext.mContext; + } + + MediaInfo mInfo; + nsTArray<RefPtr<WebMTrackDemuxer>> mDemuxers; + + // Parser state and computed offset-time mappings. Shared by multiple + // readers when decoder has been cloned. Main thread only. + RefPtr<WebMBufferedState> mBufferedState; + RefPtr<MediaByteBuffer> mInitData; + + + // Queue of video and audio packets that have been read but not decoded. + WebMPacketQueue mVideoPackets; + WebMPacketQueue mAudioPackets; + + // Index of video and audio track to play + uint32_t mVideoTrack; + uint32_t mAudioTrack; + + // Nanoseconds to discard after seeking. + uint64_t mSeekPreroll; + + // Calculate the frame duration from the last decodeable frame using the + // previous frame's timestamp. In NS. + Maybe<int64_t> mLastAudioFrameTime; + Maybe<int64_t> mLastVideoFrameTime; + + // Codec ID of audio track + int mAudioCodec; + // Codec ID of video track + int mVideoCodec; + + // Booleans to indicate if we have audio and/or video data + bool mHasVideo; + bool mHasAudio; + bool mNeedReIndex; + + // The last complete block parsed by the WebMBufferedState. -1 if not set. + // We cache those values rather than retrieving them for performance reasons + // as nestegg only performs 1-byte read at a time. + int64_t mLastWebMBlockOffset; + const bool mIsMediaSource; + + Maybe<uint32_t> mLastSeenFrameWidth; + Maybe<uint32_t> mLastSeenFrameHeight; + // This will be populated only if a resolution change occurs, otherwise it + // will be left as null so the original metadata is used + RefPtr<SharedTrackInfo> mSharedVideoTrackInfo; + + EncryptionInfo mCrypto; +}; + +class WebMTrackDemuxer : public MediaTrackDemuxer +{ +public: + WebMTrackDemuxer(WebMDemuxer* aParent, + TrackInfo::TrackType aType, + uint32_t aTrackNumber); + + UniquePtr<TrackInfo> GetInfo() const override; + + RefPtr<SeekPromise> Seek(media::TimeUnit aTime) override; + + RefPtr<SamplesPromise> GetSamples(int32_t aNumSamples = 1) override; + + void Reset() override; + + nsresult GetNextRandomAccessPoint(media::TimeUnit* aTime) override; + + RefPtr<SkipAccessPointPromise> SkipToNextRandomAccessPoint(media::TimeUnit aTimeThreshold) override; + + media::TimeIntervals GetBuffered() override; + + int64_t GetEvictionOffset(const media::TimeUnit& aTime) override; + + void BreakCycles() override; + +private: + friend class WebMDemuxer; + ~WebMTrackDemuxer(); + void UpdateSamples(nsTArray<RefPtr<MediaRawData>>& aSamples); + void SetNextKeyFrameTime(); + RefPtr<MediaRawData> NextSample (); + RefPtr<WebMDemuxer> mParent; + TrackInfo::TrackType mType; + UniquePtr<TrackInfo> mInfo; + Maybe<media::TimeUnit> mNextKeyframeTime; + bool mNeedKeyframe; + + // Queued samples extracted by the demuxer, but not yet returned. + MediaRawDataQueue mSamples; +}; + +} // namespace mozilla + +#endif |