mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
403 lines
14 KiB
C++
403 lines
14 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: ML 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is Mozilla code.
|
|
*
|
|
* The Initial Developer of the Original Code is the Mozilla Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 2007
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Chris Double <chris.double@double.co.nz>
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
/*
|
|
Each video element has two threads. They are:
|
|
Decode Thread
|
|
This thread owns the resources for downloading
|
|
and reading the video file. It goes through the file, decoding
|
|
the theora and vorbis data. It uses Oggplay to do the decoding.
|
|
|
|
Presentation Thread This thread goes through the data decoded by the
|
|
decode thread, generates the RGB buffer. If there is audio data it
|
|
queues it for playing. This thread owns the audio device - all
|
|
audio operations occur on this thread. The video data is actually
|
|
displayed by a timer that goes off at the right framerate
|
|
interval. This timer sends an Invalidate event to the frame.
|
|
|
|
Operations are performed in the threads by sending Events via the
|
|
Dispatch method on the thread.
|
|
|
|
The general sequence of events with this objects is:
|
|
|
|
1) The video element calls Load on nsVideoDecoder. This creates the
|
|
threads and starts the channel for downloading the file. It sends
|
|
an event to the decode thread to load the initial Ogg metadata.
|
|
These are the headers that give the video size, framerate, etc.
|
|
It returns immediately to the calling video element.
|
|
|
|
2) When the Ogg metadata has been loaded by the decode thread it will
|
|
call a method on the video element object to inform it that this step
|
|
is done, so it can do the required things by the video specification
|
|
at this stage.
|
|
|
|
It then queues an event to the decode thread to decode the first
|
|
frame of Ogg data.
|
|
|
|
3) When the first frame of Ogg data has been successfully decoded it
|
|
calls a method on the video element object to inform it that this
|
|
step has been done, once again so it can do the required things by
|
|
the video specification at this stage.
|
|
|
|
It then queues an event to the decode thread to enter the standard
|
|
decoding loop. This loop continuously reads data from the channel
|
|
and decodes it. It does this by reading the data, decoding it, and
|
|
if there is more data to decode, queues itself back to the thread.
|
|
|
|
The final step of the 'first frame event' is to notify a condition
|
|
variable that we have decoded the first frame. The presentation thread
|
|
uses this notification to know when to start displaying video.
|
|
|
|
4) At some point the video element calls Play() on the decoder object.
|
|
This queues an event to the presentation thread which goes through
|
|
the decoded data, displaying it if it is video, or playing it if it
|
|
is audio.
|
|
|
|
Before starting this event will wait on the condition variable
|
|
indicating if the first frame has decoded.
|
|
|
|
Pausing is handled by stopping the presentation thread. Resuming is
|
|
handled by restarting the presentation thread. The decode thread never
|
|
gets too far ahead as it is throttled by the Oggplay library.
|
|
*/
|
|
#if !defined(nsOggDecoder_h___)
|
|
#define nsOggDecoder_h___
|
|
|
|
#include "nsISupports.h"
|
|
#include "nsCOMPtr.h"
|
|
#include "nsIThread.h"
|
|
#include "nsIChannel.h"
|
|
#include "nsChannelReader.h"
|
|
#include "nsIObserver.h"
|
|
#include "nsIFrame.h"
|
|
#include "nsAutoPtr.h"
|
|
#include "nsSize.h"
|
|
#include "prlock.h"
|
|
#include "prcvar.h"
|
|
#include "prlog.h"
|
|
#include "gfxContext.h"
|
|
#include "gfxRect.h"
|
|
#include "oggplay/oggplay.h"
|
|
#include "nsVideoDecoder.h"
|
|
|
|
class nsAudioStream;
|
|
class nsVideoDecodeEvent;
|
|
class nsVideoPresentationEvent;
|
|
class nsChannelToPipeListener;
|
|
|
|
class nsOggDecoder : public nsVideoDecoder
|
|
{
|
|
friend class nsVideoDecodeEvent;
|
|
friend class nsVideoPresentationEvent;
|
|
friend class nsChannelToPipeListener;
|
|
|
|
// ISupports
|
|
NS_DECL_ISUPPORTS
|
|
|
|
// nsIObserver
|
|
NS_DECL_NSIOBSERVER
|
|
|
|
public:
|
|
nsOggDecoder();
|
|
PRBool Init();
|
|
void Shutdown();
|
|
~nsOggDecoder();
|
|
|
|
// Returns the current video frame width and height.
|
|
// If there is no video frame, returns the given default size.
|
|
nsIntSize GetVideoSize(nsIntSize defaultSize);
|
|
double GetVideoFramerate();
|
|
|
|
float GetCurrentTime();
|
|
|
|
// Start downloading the video at the given URI. Decode
|
|
// the downloaded data up to the point of the first frame
|
|
// of data.
|
|
nsresult Load(nsIURI* aURI);
|
|
|
|
// Start playback of a video. 'Load' must have previously been
|
|
// called.
|
|
nsresult Play();
|
|
|
|
// Stop playback of a video, and stop download of video stream.
|
|
virtual void Stop();
|
|
|
|
// Seek to the time position in (seconds) from the start of the video.
|
|
nsresult Seek(float time);
|
|
|
|
nsresult PlaybackRateChanged();
|
|
|
|
void Pause();
|
|
float GetVolume();
|
|
void SetVolume(float volume);
|
|
float GetDuration();
|
|
|
|
void GetCurrentURI(nsIURI** aURI);
|
|
|
|
virtual void UpdateBytesDownloaded(PRUint32 aBytes);
|
|
|
|
protected:
|
|
/******
|
|
* The following methods must only be called on the presentation
|
|
* thread.
|
|
******/
|
|
|
|
// Find and render the first frame of video data. Call on
|
|
// presentation thread only.
|
|
void DisplayFirstFrame();
|
|
|
|
// Process one frame of video/audio data.
|
|
// Call on presentation thread only.
|
|
PRBool StepDisplay();
|
|
|
|
// Process audio or video from one track of the Ogg stream.
|
|
// Call on presentation thread only.
|
|
void ProcessTrack(int aTrackNumber, OggPlayCallbackInfo* aTrackInfo);
|
|
|
|
// Return the time in seconds that the video display is
|
|
// synchronised to. This can be based on the current time of
|
|
// the audio buffer if available, or the system clock. Call
|
|
// on presentation thread only.
|
|
double GetSyncTime();
|
|
|
|
// Return true if the video is currently paused. Call on the
|
|
// presentation thread only.
|
|
PRBool IsPaused();
|
|
|
|
// Process the video/audio data. Call on presentation thread only.
|
|
void HandleVideoData(int track_num, OggPlayVideoData* video_data);
|
|
void HandleAudioData(OggPlayAudioData* audio_data, int size);
|
|
|
|
// Pause the audio. Call on presentation thread only.
|
|
void DoPause();
|
|
|
|
// Initializes and opens the audio stream. Call from the
|
|
// presentation thread only.
|
|
void OpenAudioStream();
|
|
|
|
// Closes and releases resources used by the audio stream.
|
|
// Call from the presentation thread only.
|
|
void CloseAudioStream();
|
|
|
|
// Initializes the resources owned by the presentation thread,.
|
|
// Call from the presentation thread only.
|
|
void StartPresentationThread();
|
|
|
|
/******
|
|
* The following methods must only be called on the decode
|
|
* thread.
|
|
******/
|
|
|
|
// Loads the header information from the ogg resource and
|
|
// stores the information about framerate, etc in member
|
|
// variables. Must be called from the decoder thread only.
|
|
void LoadOggHeaders();
|
|
|
|
// Loads the First frame of the video data, making it available
|
|
// in the RGB buffer. Must be called from the decoder thread only.
|
|
void LoadFirstFrame();
|
|
|
|
// Decode some data from the media file. This is placed in a
|
|
// buffer that is used by the presentation thread. Must
|
|
// be called from the decoder thread only.
|
|
PRBool StepDecoding();
|
|
|
|
// Ensure that there is enough data buffered from the video
|
|
// that we can have a reasonable playback experience. Must
|
|
// be called from the decoder thread only.
|
|
void BufferData();
|
|
|
|
/******
|
|
* The following methods must only be called on the main
|
|
* thread.
|
|
******/
|
|
|
|
// Called when the metadata from the Ogg file has been read.
|
|
// Call on the main thread only.
|
|
void MetadataLoaded();
|
|
|
|
// Called when the first frame has been loaded.
|
|
// Call on the main thread only.
|
|
void FirstFrameLoaded();
|
|
|
|
// Called when the video file has completed downloading.
|
|
// Call on the main thread only.
|
|
void ResourceLoaded();
|
|
|
|
// Called when the video has completed playing.
|
|
// Call on the main thread only.
|
|
void PlaybackCompleted();
|
|
|
|
// Return the current number of bytes loaded from the video file.
|
|
// This is used for progress events.
|
|
virtual PRUint32 GetBytesLoaded();
|
|
|
|
// Return the size of the video file in bytes.
|
|
// This is used for progress events.
|
|
virtual PRUint32 GetTotalBytes();
|
|
|
|
// Buffering of data has stopped. Inform the element on the main
|
|
// thread.
|
|
void BufferingStopped();
|
|
|
|
// Buffering of data has started. Inform the element on the main
|
|
// thread.
|
|
void BufferingStarted();
|
|
|
|
private:
|
|
// Starts the threads and timers that handle displaying the playing
|
|
// video and invalidating the frame. Called on the main thread only.
|
|
void StartPlaybackThreads();
|
|
|
|
/******
|
|
* The following member variables can be accessed from the
|
|
* decoding thread only.
|
|
******/
|
|
|
|
// Total number of bytes downloaded so far.
|
|
PRUint32 mBytesDownloaded;
|
|
|
|
/******
|
|
* The following members should be accessed on the main thread only
|
|
******/
|
|
nsCOMPtr<nsIChannel> mChannel;
|
|
nsCOMPtr<nsChannelToPipeListener> mListener;
|
|
|
|
// The URI of the current resource
|
|
nsCOMPtr<nsIURI> mURI;
|
|
|
|
// The audio stream resource. It should only be accessed from
|
|
// the presentation thread.
|
|
nsAutoPtr<nsAudioStream> mAudioStream;
|
|
|
|
// The time that the next video frame should be displayed in
|
|
// seconds. This is referenced from 0.0 which is the initial start
|
|
// of the video stream.
|
|
double mVideoNextFrameTime;
|
|
|
|
// A load of the media resource is currently in progress. It is
|
|
// complete when the media metadata is loaded.
|
|
PRPackedBool mLoadInProgress;
|
|
|
|
// A boolean that indicates that once the load has completed loading
|
|
// the metadata then it should start playing.
|
|
PRPackedBool mPlayAfterLoad;
|
|
|
|
// True if we are registered with the observer service for shutdown.
|
|
PRPackedBool mNotifyOnShutdown;
|
|
|
|
/******
|
|
* The following member variables can be accessed from any thread.
|
|
******/
|
|
|
|
// Threads to handle decoding of Ogg data. Methods on these are
|
|
// called from the main thread only, but they can be read from other
|
|
// threads safely to see if they have been created/set.
|
|
nsCOMPtr<nsIThread> mDecodeThread;
|
|
nsCOMPtr<nsIThread> mPresentationThread;
|
|
|
|
// Events for doing the Ogg decoding, displaying and repainting on
|
|
// different threads. These are created on the main thread and are
|
|
// dispatched to other threads. Threads only access them to dispatch
|
|
// the event to other threads.
|
|
nsCOMPtr<nsVideoDecodeEvent> mDecodeEvent;
|
|
nsCOMPtr<nsVideoPresentationEvent> mPresentationEvent;
|
|
|
|
// The time of the current frame from the video stream in
|
|
// seconds. This is referenced from 0.0 which is the initial start
|
|
// of the video stream. Set by the presentation thread, and
|
|
// read-only from the main thread to get the current time value.
|
|
float mVideoCurrentFrameTime;
|
|
|
|
// Volume that playback should start at. 0.0 = muted. 1.0 = full
|
|
// volume. Readable/Writeable from the main thread. Read from the
|
|
// audio thread when it is first started to get the initial volume
|
|
// level.
|
|
double mInitialVolume;
|
|
|
|
// Audio data. These are initially set on the Decoder thread when
|
|
// the metadata is loaded. They are read from the presentation
|
|
// thread after this.
|
|
PRInt32 mAudioRate;
|
|
PRInt32 mAudioChannels;
|
|
PRInt32 mAudioTrack;
|
|
|
|
// Video data. Initially set on the Decoder thread when the metadata
|
|
// is loaded. Read from the presentation thread after this.
|
|
PRInt32 mVideoTrack;
|
|
|
|
// liboggplay State. Passed to liboggplay functions on any
|
|
// thread. liboggplay handles a lock internally for this.
|
|
OggPlay* mPlayer;
|
|
|
|
// OggPlay object used to read data from a channel. Created on main
|
|
// thread. Passed to liboggplay and the locking for multithreaded
|
|
// access is handled by that library.
|
|
nsChannelReader* mReader;
|
|
|
|
// True if the video playback is paused. Read/Write from the main
|
|
// thread. Read from the decoder thread to not buffer data if
|
|
// paused.
|
|
PRPackedBool mPaused;
|
|
|
|
// True if the first frame of data has been loaded. This member,
|
|
// along with the condition variable and lock is used by threads
|
|
// that need to wait for the first frame to be loaded before
|
|
// performing some action. In particular it is used for 'autoplay' to
|
|
// start playback on loading of the first frame.
|
|
PRPackedBool mFirstFrameLoaded;
|
|
PRCondVar* mFirstFrameCondVar;
|
|
PRLock* mFirstFrameLock;
|
|
|
|
// System time in seconds since video start, or last pause/resume.
|
|
// Used for synching video framerate to the system clock if there is
|
|
// no audio hardware or no audio track. Written by main thread, read
|
|
// by presentation thread to handle frame rate synchronisation.
|
|
double mSystemSyncSeconds;
|
|
|
|
// The media resource has been completely loaded into the pipe. No
|
|
// need to attempt to buffer if it starves. Written on the main
|
|
// thread, read from the decoding thread.
|
|
PRPackedBool mResourceLoaded;
|
|
|
|
// PR_TRUE if the metadata for the video has been loaded. Written on
|
|
// the main thread, read from the decoding thread.
|
|
PRPackedBool mMetadataLoaded;
|
|
};
|
|
|
|
#endif
|