WebMDemuxer.h (9942B)
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 #ifndef WebMDemuxer_h_ 7 #define WebMDemuxer_h_ 8 9 #include <stdint.h> 10 11 #include <deque> 12 #include <utility> 13 14 #include "MediaDataDemuxer.h" 15 #include "MediaResource.h" 16 #include "NesteggPacketHolder.h" 17 #include "nsTArray.h" 18 19 typedef struct nestegg nestegg; 20 21 namespace mozilla { 22 23 class WebMBufferedState; 24 25 // Queue for holding MediaRawData samples 26 class MediaRawDataQueue { 27 typedef std::deque<RefPtr<MediaRawData>> ContainerType; 28 29 public: 30 uint32_t GetSize() { return mQueue.size(); } 31 32 void Push(MediaRawData* aItem) { mQueue.push_back(aItem); } 33 34 void Push(already_AddRefed<MediaRawData>&& aItem) { 35 mQueue.push_back(std::move(aItem)); 36 } 37 38 void PushFront(MediaRawData* aItem) { mQueue.push_front(aItem); } 39 40 void PushFront(already_AddRefed<MediaRawData>&& aItem) { 41 mQueue.push_front(std::move(aItem)); 42 } 43 44 void PushFront(MediaRawDataQueue&& aOther) { 45 while (!aOther.mQueue.empty()) { 46 PushFront(aOther.Pop()); 47 } 48 } 49 50 already_AddRefed<MediaRawData> PopFront() { 51 RefPtr<MediaRawData> result = std::move(mQueue.front()); 52 mQueue.pop_front(); 53 return result.forget(); 54 } 55 56 already_AddRefed<MediaRawData> Pop() { 57 RefPtr<MediaRawData> result = std::move(mQueue.back()); 58 mQueue.pop_back(); 59 return result.forget(); 60 } 61 62 void Reset() { 63 while (!mQueue.empty()) { 64 mQueue.pop_front(); 65 } 66 } 67 68 MediaRawDataQueue& operator=(const MediaRawDataQueue& aOther) = delete; 69 70 const RefPtr<MediaRawData>& First() const { return mQueue.front(); } 71 72 const RefPtr<MediaRawData>& Last() const { return mQueue.back(); } 73 74 // Methods for range-based for loops. 75 ContainerType::iterator begin() { return mQueue.begin(); } 76 77 ContainerType::const_iterator begin() const { return mQueue.begin(); } 78 79 ContainerType::iterator end() { return mQueue.end(); } 80 81 ContainerType::const_iterator end() const { return mQueue.end(); } 82 83 private: 84 ContainerType mQueue; 85 }; 86 87 class WebMTrackDemuxer; 88 89 DDLoggedTypeDeclNameAndBase(WebMDemuxer, MediaDataDemuxer); 90 DDLoggedTypeNameAndBase(WebMTrackDemuxer, MediaTrackDemuxer); 91 92 class WebMDemuxer : public MediaDataDemuxer, 93 public DecoderDoctorLifeLogger<WebMDemuxer> { 94 public: 95 explicit WebMDemuxer(MediaResource* aResource); 96 // Indicate if the WebMDemuxer is to be used with MediaSource. In which 97 // case the demuxer will stop reads to the last known complete block. 98 WebMDemuxer( 99 MediaResource* aResource, bool aIsMediaSource, 100 Maybe<media::TimeUnit> aFrameEndTimeBeforeRecreateDemuxer = Nothing()); 101 102 RefPtr<InitPromise> Init() override; 103 104 uint32_t GetNumberTracks(TrackInfo::TrackType aType) const override; 105 106 UniquePtr<TrackInfo> GetTrackInfo(TrackInfo::TrackType aType, 107 size_t aTrackNumber) const; 108 109 already_AddRefed<MediaTrackDemuxer> GetTrackDemuxer( 110 TrackInfo::TrackType aType, uint32_t aTrackNumber) override; 111 112 bool IsSeekable() const override; 113 114 bool IsSeekableOnlyInBufferedRanges() const override; 115 116 UniquePtr<EncryptionInfo> GetCrypto() override; 117 118 bool GetOffsetForTime(uint64_t aTime, int64_t* aOffset); 119 120 // Demux next WebM packet and append samples to MediaRawDataQueue 121 nsresult GetNextPacket(TrackInfo::TrackType aType, 122 MediaRawDataQueue* aSamples); 123 124 void Reset(TrackInfo::TrackType aType); 125 126 // Pushes a packet to the front of the audio packet queue. 127 void PushAudioPacket(NesteggPacketHolder* aItem); 128 129 // Pushes a packet to the front of the video packet queue. 130 void PushVideoPacket(NesteggPacketHolder* aItem); 131 132 // Public accessor for nestegg callbacks 133 bool IsMediaSource() const { return mIsMediaSource; } 134 135 struct NestEggContext { 136 NestEggContext(WebMDemuxer* aParent, MediaResource* aResource) 137 : mParent(aParent), mResource(aResource), mContext(nullptr) {} 138 139 ~NestEggContext(); 140 141 int Init(); 142 143 // Public accessor for nestegg callbacks 144 145 bool IsMediaSource() const { return mParent->IsMediaSource(); } 146 MediaResourceIndex* GetResource() { return &mResource; } 147 148 WebMDemuxer* mParent; 149 MediaResourceIndex mResource; 150 nestegg* mContext; 151 nsresult mLastIORV = NS_OK; 152 }; 153 154 protected: 155 virtual nsresult SetVideoCodecInfo(nestegg* aContext, int aTrackId); 156 virtual nsresult SetAudioCodecInfo(nestegg* aContext, int aTrackId, 157 const nestegg_audio_params& aParams); 158 virtual nsresult GetCodecPrivateData(nestegg* aContext, int aTrackId, 159 nsTArray<const unsigned char*>* aHeaders, 160 nsTArray<size_t>* aHeaderLens); 161 162 virtual bool CheckKeyFrameByExamineByteStream(const MediaRawData* aSample); 163 164 virtual ~WebMDemuxer(); 165 166 friend class WebMTrackDemuxer; 167 168 void InitBufferedState(); 169 int64_t FloorDefaultDurationToTimecodeScale(nestegg* aContext, 170 unsigned aTrackNumber); 171 nsresult ReadMetadata(); 172 void NotifyDataArrived() override; 173 void NotifyDataRemoved() override; 174 void EnsureUpToDateIndex(); 175 176 // A helper to catch bad intervals during `GetBuffered`. 177 // Verifies if the interval given by start and end is valid, returning true if 178 // it is, or false if not. Logs failure reason if the interval is invalid. 179 bool IsBufferedIntervalValid(uint64_t start, uint64_t end); 180 181 media::TimeIntervals GetBuffered(); 182 nsresult SeekInternal(TrackInfo::TrackType aType, 183 const media::TimeUnit& aTarget); 184 CryptoTrack GetTrackCrypto(TrackInfo::TrackType aType, size_t aTrackNumber); 185 186 // Read a packet from the nestegg file. 187 // Returns NS_ERROR_DOM_MEDIA_END_OF_STREAM if all packets for the 188 // particular track have been read. Pass TrackInfo::kVideoTrack or 189 // TrackInfo::kVideoTrack to indicate the type of the packet to read. 190 Result<RefPtr<NesteggPacketHolder>, nsresult> NextPacket( 191 TrackInfo::TrackType aType); 192 193 // Internal method that demuxes the next packet from the stream. The caller 194 // is responsible for making sure it doesn't get lost. 195 Result<RefPtr<NesteggPacketHolder>, nsresult> DemuxPacket( 196 TrackInfo::TrackType aType); 197 198 // libnestegg audio and video context for webm container. 199 // Access on reader's thread only. 200 NestEggContext mVideoContext; 201 NestEggContext mAudioContext; 202 MediaResourceIndex& Resource(TrackInfo::TrackType aType) { 203 return aType == TrackInfo::kVideoTrack ? mVideoContext.mResource 204 : mAudioContext.mResource; 205 } 206 const NestEggContext& CallbackContext(TrackInfo::TrackType aType) const { 207 return aType == TrackInfo::kVideoTrack ? mVideoContext : mAudioContext; 208 } 209 nestegg* Context(TrackInfo::TrackType aType) const { 210 return CallbackContext(aType).mContext; 211 } 212 213 MediaInfo mInfo; 214 nsTArray<RefPtr<WebMTrackDemuxer>> mDemuxers; 215 216 // Parser state and computed offset-time mappings. Shared by multiple 217 // readers when decoder has been cloned. Main thread only. 218 RefPtr<WebMBufferedState> mBufferedState; 219 RefPtr<MediaByteBuffer> mInitData; 220 221 // Queue of video and audio packets that have been read but not decoded. 222 WebMPacketQueue mVideoPackets; 223 WebMPacketQueue mAudioPackets; 224 225 // Index of video and audio track to play 226 uint32_t mVideoTrack; 227 uint32_t mAudioTrack; 228 229 // Nanoseconds to discard after seeking. 230 uint64_t mSeekPreroll; 231 232 // Calculate the frame duration from the last decodeable frame using the 233 // previous frame's timestamp. In microseconds. 234 Maybe<int64_t> mLastAudioFrameTime; 235 Maybe<int64_t> mLastVideoFrameTime; 236 237 Maybe<media::TimeUnit> mVideoFrameEndTimeBeforeReset; 238 239 // Codec ID of audio track 240 int mAudioCodec; 241 // Codec ID of video track 242 int mVideoCodec; 243 // Default durations of blocks for each track, in microseconds 244 int64_t mAudioDefaultDuration; 245 int64_t mVideoDefaultDuration; 246 247 // Booleans to indicate if we have audio and/or video data 248 bool mHasVideo; 249 bool mHasAudio; 250 bool mNeedReIndex; 251 252 const bool mIsMediaSource; 253 // Discard padding in WebM cannot occur more than once. This is set to true if 254 // a discard padding element has been found and processed, and the decoding is 255 // expected to error out if another discard padding element is found 256 // subsequently in the byte stream. 257 bool mProcessedDiscardPadding = false; 258 259 EncryptionInfo mCrypto; 260 }; 261 262 class WebMTrackDemuxer : public MediaTrackDemuxer, 263 public DecoderDoctorLifeLogger<WebMTrackDemuxer> { 264 public: 265 WebMTrackDemuxer(WebMDemuxer* aParent, TrackInfo::TrackType aType, 266 uint32_t aTrackNumber); 267 268 UniquePtr<TrackInfo> GetInfo() const override; 269 270 RefPtr<SeekPromise> Seek(const media::TimeUnit& aTime) override; 271 272 RefPtr<SamplesPromise> GetSamples(int32_t aNumSamples = 1) override; 273 274 void Reset() override; 275 276 nsresult GetNextRandomAccessPoint(media::TimeUnit* aTime) override; 277 278 RefPtr<SkipAccessPointPromise> SkipToNextRandomAccessPoint( 279 const media::TimeUnit& aTimeThreshold) override; 280 281 media::TimeIntervals GetBuffered() override; 282 283 int64_t GetEvictionOffset(const media::TimeUnit& aTime) override; 284 285 void BreakCycles() override; 286 287 private: 288 friend class WebMDemuxer; 289 ~WebMTrackDemuxer(); 290 void UpdateSamples(const nsTArray<RefPtr<MediaRawData>>& aSamples); 291 void SetNextKeyFrameTime(); 292 nsresult NextSample(RefPtr<MediaRawData>& aData); 293 RefPtr<WebMDemuxer> mParent; 294 TrackInfo::TrackType mType; 295 UniquePtr<TrackInfo> mInfo; 296 Maybe<media::TimeUnit> mNextKeyframeTime; 297 bool mNeedKeyframe; 298 299 // Queued samples extracted by the demuxer, but not yet returned. 300 MediaRawDataQueue mSamples; 301 }; 302 303 } // namespace mozilla 304 305 #endif