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 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Mozilla code.
17 : *
18 : * The Initial Developer of the Original Code is the Mozilla Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 2007
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Chris Double <chris.double@double.co.nz>
24 : * Chris Pearce <chris@pearce.org.nz>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either the GNU General Public License Version 2 or later (the "GPL"), or
28 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 : #if !defined(nsWebMReader_h_)
40 : #define nsWebMReader_h_
41 :
42 : #include "mozilla/StandardInteger.h"
43 :
44 : #include "nsDeque.h"
45 : #include "nsBuiltinDecoderReader.h"
46 : #include "nsAutoRef.h"
47 : #include "nestegg/nestegg.h"
48 :
49 : #define VPX_DONT_DEFINE_STDINT_TYPES
50 : #include "vpx/vpx_codec.h"
51 :
52 : #ifdef MOZ_TREMOR
53 : #include "tremor/ivorbiscodec.h"
54 : #else
55 : #include "vorbis/codec.h"
56 : #endif
57 :
58 : class nsWebMBufferedState;
59 :
60 : // Holds a nestegg_packet, and its file offset. This is needed so we
61 : // know the offset in the file we've played up to, in order to calculate
62 : // whether it's likely we can play through to the end without needing
63 : // to stop to buffer, given the current download rate.
64 : class NesteggPacketHolder {
65 : public:
66 0 : NesteggPacketHolder(nestegg_packet* aPacket, PRInt64 aOffset)
67 0 : : mPacket(aPacket), mOffset(aOffset)
68 : {
69 0 : MOZ_COUNT_CTOR(NesteggPacketHolder);
70 0 : }
71 0 : ~NesteggPacketHolder() {
72 0 : MOZ_COUNT_DTOR(NesteggPacketHolder);
73 0 : nestegg_free_packet(mPacket);
74 0 : }
75 : nestegg_packet* mPacket;
76 : // Offset in bytes. This is the offset of the end of the Block
77 : // which contains the packet.
78 : PRInt64 mOffset;
79 : private:
80 : // Copy constructor and assignment operator not implemented. Don't use them!
81 : NesteggPacketHolder(const NesteggPacketHolder &aOther);
82 : NesteggPacketHolder& operator= (NesteggPacketHolder const& aOther);
83 : };
84 :
85 : // Thread and type safe wrapper around nsDeque.
86 0 : class PacketQueueDeallocator : public nsDequeFunctor {
87 0 : virtual void* operator() (void* anObject) {
88 0 : delete static_cast<NesteggPacketHolder*>(anObject);
89 0 : return nsnull;
90 : }
91 : };
92 :
93 : // Typesafe queue for holding nestegg packets. It has
94 : // ownership of the items in the queue and will free them
95 : // when destroyed.
96 : class PacketQueue : private nsDeque {
97 : public:
98 0 : PacketQueue()
99 0 : : nsDeque(new PacketQueueDeallocator())
100 0 : {}
101 :
102 0 : ~PacketQueue() {
103 0 : Reset();
104 0 : }
105 :
106 0 : inline PRInt32 GetSize() {
107 0 : return nsDeque::GetSize();
108 : }
109 :
110 0 : inline void Push(NesteggPacketHolder* aItem) {
111 0 : NS_ASSERTION(aItem, "NULL pushed to PacketQueue");
112 0 : nsDeque::Push(aItem);
113 0 : }
114 :
115 0 : inline void PushFront(NesteggPacketHolder* aItem) {
116 0 : NS_ASSERTION(aItem, "NULL pushed to PacketQueue");
117 0 : nsDeque::PushFront(aItem);
118 0 : }
119 :
120 0 : inline NesteggPacketHolder* PopFront() {
121 0 : return static_cast<NesteggPacketHolder*>(nsDeque::PopFront());
122 : }
123 :
124 0 : void Reset() {
125 0 : while (GetSize() > 0) {
126 0 : delete PopFront();
127 : }
128 0 : }
129 : };
130 :
131 : class nsWebMReader : public nsBuiltinDecoderReader
132 : {
133 : public:
134 : nsWebMReader(nsBuiltinDecoder* aDecoder);
135 : ~nsWebMReader();
136 :
137 : virtual nsresult Init(nsBuiltinDecoderReader* aCloneDonor);
138 : virtual nsresult ResetDecode();
139 : virtual bool DecodeAudioData();
140 :
141 : // If the Theora granulepos has not been captured, it may read several packets
142 : // until one with a granulepos has been captured, to ensure that all packets
143 : // read have valid time info.
144 : virtual bool DecodeVideoFrame(bool &aKeyframeSkip,
145 : PRInt64 aTimeThreshold);
146 :
147 0 : virtual bool HasAudio()
148 : {
149 0 : NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
150 0 : return mHasAudio;
151 : }
152 :
153 0 : virtual bool HasVideo()
154 : {
155 0 : NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
156 0 : return mHasVideo;
157 : }
158 :
159 : virtual nsresult ReadMetadata(nsVideoInfo* aInfo);
160 : virtual nsresult Seek(PRInt64 aTime, PRInt64 aStartTime, PRInt64 aEndTime, PRInt64 aCurrentTime);
161 : virtual nsresult GetBuffered(nsTimeRanges* aBuffered, PRInt64 aStartTime);
162 : virtual void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRInt64 aOffset);
163 :
164 : private:
165 : // Value passed to NextPacket to determine if we are reading a video or an
166 : // audio packet.
167 : enum TrackType {
168 : VIDEO = 0,
169 : AUDIO = 1
170 : };
171 :
172 : // Read a packet from the nestegg file. Returns NULL if all packets for
173 : // the particular track have been read. Pass VIDEO or AUDIO to indicate the
174 : // type of the packet we want to read.
175 : nsReturnRef<NesteggPacketHolder> NextPacket(TrackType aTrackType);
176 :
177 : // Returns an initialized ogg packet with data obtained from the WebM container.
178 : ogg_packet InitOggPacket(unsigned char* aData,
179 : size_t aLength,
180 : bool aBOS,
181 : bool aEOS,
182 : PRInt64 aGranulepos);
183 :
184 : // Decode a nestegg packet of audio data. Push the audio data on the
185 : // audio queue. Returns true when there's more audio to decode,
186 : // false if the audio is finished, end of file has been reached,
187 : // or an un-recoverable read error has occured. The reader's monitor
188 : // must be held during this call. This function will free the packet
189 : // so the caller must not use the packet after calling.
190 : bool DecodeAudioPacket(nestegg_packet* aPacket, PRInt64 aOffset);
191 :
192 : // Release context and set to null. Called when an error occurs during
193 : // reading metadata or destruction of the reader itself.
194 : void Cleanup();
195 :
196 : private:
197 : // libnestegg context for webm container. Access on state machine thread
198 : // or decoder thread only.
199 : nestegg* mContext;
200 :
201 : // VP8 decoder state
202 : vpx_codec_ctx_t mVP8;
203 :
204 : // Vorbis decoder state
205 : vorbis_info mVorbisInfo;
206 : vorbis_comment mVorbisComment;
207 : vorbis_dsp_state mVorbisDsp;
208 : vorbis_block mVorbisBlock;
209 : PRUint32 mPacketCount;
210 : PRUint32 mChannels;
211 :
212 : // Queue of video and audio packets that have been read but not decoded. These
213 : // must only be accessed from the state machine thread.
214 : PacketQueue mVideoPackets;
215 : PacketQueue mAudioPackets;
216 :
217 : // Index of video and audio track to play
218 : PRUint32 mVideoTrack;
219 : PRUint32 mAudioTrack;
220 :
221 : // Time in microseconds of the start of the first audio frame we've decoded.
222 : PRInt64 mAudioStartUsec;
223 :
224 : // Number of audio frames we've decoded since decoding began at mAudioStartMs.
225 : PRUint64 mAudioFrames;
226 :
227 : // Parser state and computed offset-time mappings. Shared by multiple
228 : // readers when decoder has been cloned. Main thread only.
229 : nsRefPtr<nsWebMBufferedState> mBufferedState;
230 :
231 : // Size of the frame initially present in the stream. The picture region
232 : // is defined as a ratio relative to this.
233 : nsIntSize mInitialFrame;
234 :
235 : // Picture region, as relative to the initial frame size.
236 : nsIntRect mPicture;
237 :
238 : // Value of the "media.webm.force_stereo_mode" pref, which we need off the
239 : // main thread.
240 : PRInt32 mForceStereoMode;
241 :
242 : // Booleans to indicate if we have audio and/or video data
243 : bool mHasVideo;
244 : bool mHasAudio;
245 :
246 : // Boolean which is set to true when the "media.webm.force_stereo_mode"
247 : // pref is explicitly set.
248 : bool mStereoModeForced;
249 : };
250 :
251 : #endif
|