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: ML 1.1/GPL 2.0/LGPL 2.1
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/
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
16 * The Original Code is Mozilla code.
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.
23 * Chris Double <chris.double@double.co.nz>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 Each video element has two threads. They are:
41 This thread owns the resources for downloading
42 and reading the video file. It goes through the file, decoding
43 the theora and vorbis data. It uses Oggplay to do the decoding.
45 Presentation Thread This thread goes through the data decoded by the
46 decode thread, generates the RGB buffer. If there is audio data it
47 queues it for playing. This thread owns the audio device - all
48 audio operations occur on this thread. The video data is actually
49 displayed by a timer that goes off at the right framerate
50 interval. This timer sends an Invalidate event to the frame.
52 Operations are performed in the threads by sending Events via the
53 Dispatch method on the thread.
55 The general sequence of events with this objects is:
57 1) The video element calls Load on nsVideoDecoder. This creates the
58 threads and starts the channel for downloading the file. It sends
59 an event to the decode thread to load the initial Ogg metadata.
60 These are the headers that give the video size, framerate, etc.
61 It returns immediately to the calling video element.
63 2) When the Ogg metadata has been loaded by the decode thread it will
64 call a method on the video element object to inform it that this step
65 is done, so it can do the required things by the video specification
68 It then queues an event to the decode thread to decode the first
71 3) When the first frame of Ogg data has been successfully decoded it
72 calls a method on the video element object to inform it that this
73 step has been done, once again so it can do the required things by
74 the video specification at this stage.
76 It then queues an event to the decode thread to enter the standard
77 decoding loop. This loop continuously reads data from the channel
78 and decodes it. It does this by reading the data, decoding it, and
79 if there is more data to decode, queues itself back to the thread.
81 The final step of the 'first frame event' is to notify a condition
82 variable that we have decoded the first frame. The presentation thread
83 uses this notification to know when to start displaying video.
85 4) At some point the video element calls Play() on the decoder object.
86 This queues an event to the presentation thread which goes through
87 the decoded data, displaying it if it is video, or playing it if it
90 Before starting this event will wait on the condition variable
91 indicating if the first frame has decoded.
93 Pausing is handled by stopping the presentation thread. Resuming is
94 handled by restarting the presentation thread. The decode thread never
95 gets too far ahead as it is throttled by the Oggplay library.
97 #if !defined(nsOggDecoder_h___)
98 #define nsOggDecoder_h___
100 #include "nsISupports.h"
101 #include "nsCOMPtr.h"
102 #include "nsIThread.h"
103 #include "nsIChannel.h"
104 #include "nsChannelReader.h"
105 #include "nsIObserver.h"
106 #include "nsIFrame.h"
107 #include "nsAutoPtr.h"
112 #include "gfxContext.h"
114 #include "oggplay/oggplay.h"
115 #include "nsVideoDecoder.h"
118 class nsVideoDecodeEvent
;
119 class nsVideoPresentationEvent
;
120 class nsChannelToPipeListener
;
122 class nsOggDecoder
: public nsVideoDecoder
124 friend class nsVideoDecodeEvent
;
125 friend class nsVideoPresentationEvent
;
126 friend class nsChannelToPipeListener
;
140 // Returns the current video frame width and height.
141 // If there is no video frame, returns the given default size.
142 nsIntSize
GetVideoSize(nsIntSize defaultSize
);
143 double GetVideoFramerate();
145 float GetCurrentTime();
147 // Start downloading the video at the given URI. Decode
148 // the downloaded data up to the point of the first frame
150 nsresult
Load(nsIURI
* aURI
);
152 // Start playback of a video. 'Load' must have previously been
156 // Stop playback of a video, and stop download of video stream.
159 // Seek to the time position in (seconds) from the start of the video.
160 nsresult
Seek(float time
);
162 nsresult
PlaybackRateChanged();
166 void SetVolume(float volume
);
169 void GetCurrentURI(nsIURI
** aURI
);
171 virtual void UpdateBytesDownloaded(PRUint32 aBytes
);
175 * The following methods must only be called on the presentation
179 // Find and render the first frame of video data. Call on
180 // presentation thread only.
181 void DisplayFirstFrame();
183 // Process one frame of video/audio data.
184 // Call on presentation thread only.
185 PRBool
StepDisplay();
187 // Process audio or video from one track of the Ogg stream.
188 // Call on presentation thread only.
189 void ProcessTrack(int aTrackNumber
, OggPlayCallbackInfo
* aTrackInfo
);
191 // Return the time in seconds that the video display is
192 // synchronised to. This can be based on the current time of
193 // the audio buffer if available, or the system clock. Call
194 // on presentation thread only.
195 double GetSyncTime();
197 // Return true if the video is currently paused. Call on the
198 // presentation thread only.
201 // Process the video/audio data. Call on presentation thread only.
202 void HandleVideoData(int track_num
, OggPlayVideoData
* video_data
);
203 void HandleAudioData(OggPlayAudioData
* audio_data
, int size
);
205 // Pause the audio. Call on presentation thread only.
208 // Initializes and opens the audio stream. Call from the
209 // presentation thread only.
210 void OpenAudioStream();
212 // Closes and releases resources used by the audio stream.
213 // Call from the presentation thread only.
214 void CloseAudioStream();
216 // Initializes the resources owned by the presentation thread,.
217 // Call from the presentation thread only.
218 void StartPresentationThread();
221 * The following methods must only be called on the decode
225 // Loads the header information from the ogg resource and
226 // stores the information about framerate, etc in member
227 // variables. Must be called from the decoder thread only.
228 void LoadOggHeaders();
230 // Loads the First frame of the video data, making it available
231 // in the RGB buffer. Must be called from the decoder thread only.
232 void LoadFirstFrame();
234 // Decode some data from the media file. This is placed in a
235 // buffer that is used by the presentation thread. Must
236 // be called from the decoder thread only.
237 PRBool
StepDecoding();
239 // Ensure that there is enough data buffered from the video
240 // that we can have a reasonable playback experience. Must
241 // be called from the decoder thread only.
245 * The following methods must only be called on the main
249 // Called when the metadata from the Ogg file has been read.
250 // Call on the main thread only.
251 void MetadataLoaded();
253 // Called when the first frame has been loaded.
254 // Call on the main thread only.
255 void FirstFrameLoaded();
257 // Called when the video file has completed downloading.
258 // Call on the main thread only.
259 void ResourceLoaded();
261 // Called when the video has completed playing.
262 // Call on the main thread only.
263 void PlaybackCompleted();
265 // Return the current number of bytes loaded from the video file.
266 // This is used for progress events.
267 virtual PRUint32
GetBytesLoaded();
269 // Return the size of the video file in bytes.
270 // This is used for progress events.
271 virtual PRUint32
GetTotalBytes();
273 // Buffering of data has stopped. Inform the element on the main
275 void BufferingStopped();
277 // Buffering of data has started. Inform the element on the main
279 void BufferingStarted();
282 // Starts the threads and timers that handle displaying the playing
283 // video and invalidating the frame. Called on the main thread only.
284 void StartPlaybackThreads();
287 * The following member variables can be accessed from the
288 * decoding thread only.
291 // Total number of bytes downloaded so far.
292 PRUint32 mBytesDownloaded
;
295 * The following members should be accessed on the main thread only
297 nsCOMPtr
<nsIChannel
> mChannel
;
298 nsCOMPtr
<nsChannelToPipeListener
> mListener
;
300 // The URI of the current resource
301 nsCOMPtr
<nsIURI
> mURI
;
303 // The audio stream resource. It should only be accessed from
304 // the presentation thread.
305 nsAutoPtr
<nsAudioStream
> mAudioStream
;
307 // The time that the next video frame should be displayed in
308 // seconds. This is referenced from 0.0 which is the initial start
309 // of the video stream.
310 double mVideoNextFrameTime
;
312 // A load of the media resource is currently in progress. It is
313 // complete when the media metadata is loaded.
314 PRPackedBool mLoadInProgress
;
316 // A boolean that indicates that once the load has completed loading
317 // the metadata then it should start playing.
318 PRPackedBool mPlayAfterLoad
;
320 // True if we are registered with the observer service for shutdown.
321 PRPackedBool mNotifyOnShutdown
;
324 * The following member variables can be accessed from any thread.
327 // Threads to handle decoding of Ogg data. Methods on these are
328 // called from the main thread only, but they can be read from other
329 // threads safely to see if they have been created/set.
330 nsCOMPtr
<nsIThread
> mDecodeThread
;
331 nsCOMPtr
<nsIThread
> mPresentationThread
;
333 // Events for doing the Ogg decoding, displaying and repainting on
334 // different threads. These are created on the main thread and are
335 // dispatched to other threads. Threads only access them to dispatch
336 // the event to other threads.
337 nsCOMPtr
<nsVideoDecodeEvent
> mDecodeEvent
;
338 nsCOMPtr
<nsVideoPresentationEvent
> mPresentationEvent
;
340 // The time of the current frame from the video stream in
341 // seconds. This is referenced from 0.0 which is the initial start
342 // of the video stream. Set by the presentation thread, and
343 // read-only from the main thread to get the current time value.
344 float mVideoCurrentFrameTime
;
346 // Volume that playback should start at. 0.0 = muted. 1.0 = full
347 // volume. Readable/Writeable from the main thread. Read from the
348 // audio thread when it is first started to get the initial volume
350 double mInitialVolume
;
352 // Audio data. These are initially set on the Decoder thread when
353 // the metadata is loaded. They are read from the presentation
354 // thread after this.
356 PRInt32 mAudioChannels
;
359 // Video data. Initially set on the Decoder thread when the metadata
360 // is loaded. Read from the presentation thread after this.
363 // liboggplay State. Passed to liboggplay functions on any
364 // thread. liboggplay handles a lock internally for this.
367 // OggPlay object used to read data from a channel. Created on main
368 // thread. Passed to liboggplay and the locking for multithreaded
369 // access is handled by that library.
370 nsChannelReader
* mReader
;
372 // True if the video playback is paused. Read/Write from the main
373 // thread. Read from the decoder thread to not buffer data if
375 PRPackedBool mPaused
;
377 // True if the first frame of data has been loaded. This member,
378 // along with the condition variable and lock is used by threads
379 // that need to wait for the first frame to be loaded before
380 // performing some action. In particular it is used for 'autoplay' to
381 // start playback on loading of the first frame.
382 PRPackedBool mFirstFrameLoaded
;
383 PRCondVar
* mFirstFrameCondVar
;
384 PRLock
* mFirstFrameLock
;
386 // System time in seconds since video start, or last pause/resume.
387 // Used for synching video framerate to the system clock if there is
388 // no audio hardware or no audio track. Written by main thread, read
389 // by presentation thread to handle frame rate synchronisation.
390 double mSystemSyncSeconds
;
392 // The media resource has been completely loaded into the pipe. No
393 // need to attempt to buffer if it starves. Written on the main
394 // thread, read from the decoding thread.
395 PRPackedBool mResourceLoaded
;
397 // PR_TRUE if the metadata for the video has been loaded. Written on
398 // the main thread, read from the decoding thread.
399 PRPackedBool mMetadataLoaded
;