|
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(WebMReader_h_) |
|
7 #define WebMReader_h_ |
|
8 |
|
9 #include <stdint.h> |
|
10 |
|
11 #include "nsDeque.h" |
|
12 #include "MediaDecoderReader.h" |
|
13 #include "nsAutoRef.h" |
|
14 #include "nestegg/nestegg.h" |
|
15 |
|
16 #define VPX_DONT_DEFINE_STDINT_TYPES |
|
17 #include "vpx/vpx_codec.h" |
|
18 |
|
19 #ifdef MOZ_TREMOR |
|
20 #include "tremor/ivorbiscodec.h" |
|
21 #else |
|
22 #include "vorbis/codec.h" |
|
23 #endif |
|
24 |
|
25 #ifdef MOZ_OPUS |
|
26 #include "OpusParser.h" |
|
27 #endif |
|
28 |
|
29 namespace mozilla { |
|
30 |
|
31 class WebMBufferedState; |
|
32 |
|
33 // Holds a nestegg_packet, and its file offset. This is needed so we |
|
34 // know the offset in the file we've played up to, in order to calculate |
|
35 // whether it's likely we can play through to the end without needing |
|
36 // to stop to buffer, given the current download rate. |
|
37 class NesteggPacketHolder { |
|
38 public: |
|
39 NesteggPacketHolder(nestegg_packet* aPacket, int64_t aOffset) |
|
40 : mPacket(aPacket), mOffset(aOffset) |
|
41 { |
|
42 MOZ_COUNT_CTOR(NesteggPacketHolder); |
|
43 } |
|
44 ~NesteggPacketHolder() { |
|
45 MOZ_COUNT_DTOR(NesteggPacketHolder); |
|
46 nestegg_free_packet(mPacket); |
|
47 } |
|
48 nestegg_packet* mPacket; |
|
49 // Offset in bytes. This is the offset of the end of the Block |
|
50 // which contains the packet. |
|
51 int64_t mOffset; |
|
52 private: |
|
53 // Copy constructor and assignment operator not implemented. Don't use them! |
|
54 NesteggPacketHolder(const NesteggPacketHolder &aOther); |
|
55 NesteggPacketHolder& operator= (NesteggPacketHolder const& aOther); |
|
56 }; |
|
57 |
|
58 // Thread and type safe wrapper around nsDeque. |
|
59 class PacketQueueDeallocator : public nsDequeFunctor { |
|
60 virtual void* operator() (void* anObject) { |
|
61 delete static_cast<NesteggPacketHolder*>(anObject); |
|
62 return nullptr; |
|
63 } |
|
64 }; |
|
65 |
|
66 // Typesafe queue for holding nestegg packets. It has |
|
67 // ownership of the items in the queue and will free them |
|
68 // when destroyed. |
|
69 class WebMPacketQueue : private nsDeque { |
|
70 public: |
|
71 WebMPacketQueue() |
|
72 : nsDeque(new PacketQueueDeallocator()) |
|
73 {} |
|
74 |
|
75 ~WebMPacketQueue() { |
|
76 Reset(); |
|
77 } |
|
78 |
|
79 inline int32_t GetSize() { |
|
80 return nsDeque::GetSize(); |
|
81 } |
|
82 |
|
83 inline void Push(NesteggPacketHolder* aItem) { |
|
84 NS_ASSERTION(aItem, "NULL pushed to WebMPacketQueue"); |
|
85 nsDeque::Push(aItem); |
|
86 } |
|
87 |
|
88 inline void PushFront(NesteggPacketHolder* aItem) { |
|
89 NS_ASSERTION(aItem, "NULL pushed to WebMPacketQueue"); |
|
90 nsDeque::PushFront(aItem); |
|
91 } |
|
92 |
|
93 inline NesteggPacketHolder* PopFront() { |
|
94 return static_cast<NesteggPacketHolder*>(nsDeque::PopFront()); |
|
95 } |
|
96 |
|
97 void Reset() { |
|
98 while (GetSize() > 0) { |
|
99 delete PopFront(); |
|
100 } |
|
101 } |
|
102 }; |
|
103 |
|
104 class WebMReader : public MediaDecoderReader |
|
105 { |
|
106 public: |
|
107 WebMReader(AbstractMediaDecoder* aDecoder); |
|
108 ~WebMReader(); |
|
109 |
|
110 virtual nsresult Init(MediaDecoderReader* aCloneDonor); |
|
111 virtual nsresult ResetDecode(); |
|
112 virtual bool DecodeAudioData(); |
|
113 |
|
114 // If the Theora granulepos has not been captured, it may read several packets |
|
115 // until one with a granulepos has been captured, to ensure that all packets |
|
116 // read have valid time info. |
|
117 virtual bool DecodeVideoFrame(bool &aKeyframeSkip, |
|
118 int64_t aTimeThreshold); |
|
119 |
|
120 virtual bool HasAudio() |
|
121 { |
|
122 NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); |
|
123 return mHasAudio; |
|
124 } |
|
125 |
|
126 virtual bool HasVideo() |
|
127 { |
|
128 NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); |
|
129 return mHasVideo; |
|
130 } |
|
131 |
|
132 virtual nsresult ReadMetadata(MediaInfo* aInfo, |
|
133 MetadataTags** aTags); |
|
134 virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime); |
|
135 virtual nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime); |
|
136 virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset); |
|
137 |
|
138 protected: |
|
139 // Value passed to NextPacket to determine if we are reading a video or an |
|
140 // audio packet. |
|
141 enum TrackType { |
|
142 VIDEO = 0, |
|
143 AUDIO = 1 |
|
144 }; |
|
145 |
|
146 // Read a packet from the nestegg file. Returns nullptr if all packets for |
|
147 // the particular track have been read. Pass VIDEO or AUDIO to indicate the |
|
148 // type of the packet we want to read. |
|
149 nsReturnRef<NesteggPacketHolder> NextPacket(TrackType aTrackType); |
|
150 |
|
151 // Pushes a packet to the front of the video packet queue. |
|
152 virtual void PushVideoPacket(NesteggPacketHolder* aItem); |
|
153 |
|
154 // Returns an initialized ogg packet with data obtained from the WebM container. |
|
155 ogg_packet InitOggPacket(unsigned char* aData, |
|
156 size_t aLength, |
|
157 bool aBOS, |
|
158 bool aEOS, |
|
159 int64_t aGranulepos); |
|
160 |
|
161 #ifdef MOZ_OPUS |
|
162 // Setup opus decoder |
|
163 bool InitOpusDecoder(); |
|
164 #endif |
|
165 |
|
166 // Decode a nestegg packet of audio data. Push the audio data on the |
|
167 // audio queue. Returns true when there's more audio to decode, |
|
168 // false if the audio is finished, end of file has been reached, |
|
169 // or an un-recoverable read error has occured. The reader's monitor |
|
170 // must be held during this call. The caller is responsible for freeing |
|
171 // aPacket. |
|
172 bool DecodeAudioPacket(nestegg_packet* aPacket, int64_t aOffset); |
|
173 |
|
174 // Release context and set to null. Called when an error occurs during |
|
175 // reading metadata or destruction of the reader itself. |
|
176 void Cleanup(); |
|
177 |
|
178 private: |
|
179 // libnestegg context for webm container. Access on state machine thread |
|
180 // or decoder thread only. |
|
181 nestegg* mContext; |
|
182 |
|
183 // VP8 decoder state |
|
184 vpx_codec_ctx_t mVPX; |
|
185 |
|
186 // Vorbis decoder state |
|
187 vorbis_info mVorbisInfo; |
|
188 vorbis_comment mVorbisComment; |
|
189 vorbis_dsp_state mVorbisDsp; |
|
190 vorbis_block mVorbisBlock; |
|
191 uint32_t mPacketCount; |
|
192 uint32_t mChannels; |
|
193 |
|
194 |
|
195 #ifdef MOZ_OPUS |
|
196 // Opus decoder state |
|
197 nsAutoPtr<OpusParser> mOpusParser; |
|
198 OpusMSDecoder *mOpusDecoder; |
|
199 int mSkip; // Number of samples left to trim before playback. |
|
200 uint64_t mSeekPreroll; // Number of nanoseconds that must be discarded after seeking. |
|
201 #endif |
|
202 |
|
203 // Queue of video and audio packets that have been read but not decoded. These |
|
204 // must only be accessed from the state machine thread. |
|
205 WebMPacketQueue mVideoPackets; |
|
206 WebMPacketQueue mAudioPackets; |
|
207 |
|
208 // Index of video and audio track to play |
|
209 uint32_t mVideoTrack; |
|
210 uint32_t mAudioTrack; |
|
211 |
|
212 // Time in microseconds of the start of the first audio frame we've decoded. |
|
213 int64_t mAudioStartUsec; |
|
214 |
|
215 // Number of audio frames we've decoded since decoding began at mAudioStartMs. |
|
216 uint64_t mAudioFrames; |
|
217 |
|
218 // Number of microseconds that must be discarded from the start of the Stream. |
|
219 uint64_t mCodecDelay; |
|
220 |
|
221 // Parser state and computed offset-time mappings. Shared by multiple |
|
222 // readers when decoder has been cloned. Main thread only. |
|
223 nsRefPtr<WebMBufferedState> mBufferedState; |
|
224 |
|
225 // Size of the frame initially present in the stream. The picture region |
|
226 // is defined as a ratio relative to this. |
|
227 nsIntSize mInitialFrame; |
|
228 |
|
229 // Picture region, as relative to the initial frame size. |
|
230 nsIntRect mPicture; |
|
231 |
|
232 // Codec ID of audio track |
|
233 int mAudioCodec; |
|
234 // Codec ID of video track |
|
235 int mVideoCodec; |
|
236 |
|
237 // Booleans to indicate if we have audio and/or video data |
|
238 bool mHasVideo; |
|
239 bool mHasAudio; |
|
240 }; |
|
241 |
|
242 } // namespace mozilla |
|
243 |
|
244 #endif |