SWORD25: Start of plugging audio to Theora decoder

svn-id: r53207
This commit is contained in:
Eugene Sandulenko 2010-08-04 21:13:43 +00:00
parent 9b3e26e7a2
commit 1e3b3af5c0
2 changed files with 51 additions and 18 deletions

View file

@ -41,17 +41,22 @@
namespace Sword25 { namespace Sword25 {
TheoraDecoder::TheoraDecoder() { TheoraDecoder::TheoraDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) : _mixer(mixer) {
_fileStream = 0; _fileStream = 0;
_surface = 0; _surface = 0;
_theoraPacket = 0; _theoraPacket = 0;
_vorbisPacket = 0; _vorbisPacket = 0;
_stateFlag = 0; _stateFlag = false;
_soundType = soundType;
_audStream = 0;
_audHandle = new Audio::SoundHandle();
} }
TheoraDecoder::~TheoraDecoder() { TheoraDecoder::~TheoraDecoder() {
close(); close();
delete _audHandle;
} }
void TheoraDecoder::queuePage(ogg_page *page) { void TheoraDecoder::queuePage(ogg_page *page) {
@ -102,7 +107,7 @@ bool TheoraDecoder::load(Common::SeekableReadStream &stream) {
if (!ogg_page_bos(&_oggPage)) { if (!ogg_page_bos(&_oggPage)) {
// don't leak the page; get it into the appropriate stream // don't leak the page; get it into the appropriate stream
queuePage(&_oggPage); queuePage(&_oggPage);
_stateFlag = 1; _stateFlag = true;
break; break;
} }
@ -220,8 +225,11 @@ bool TheoraDecoder::load(Common::SeekableReadStream &stream) {
} }
// open audio // open audio
if (_vorbisPacket) if (_vorbisPacket) {
open_audio(); _audStream = createAudioStream();
if (_audStream)
_mixer->playStream(_soundType, _audHandle, _audStream);
}
return true; return true;
} }
@ -233,6 +241,9 @@ void TheoraDecoder::close() {
vorbis_dsp_clear(&_vorbisDSP); vorbis_dsp_clear(&_vorbisDSP);
vorbis_comment_clear(&_vorbisComment); vorbis_comment_clear(&_vorbisComment);
vorbis_info_clear(&_vorbisInfo); vorbis_info_clear(&_vorbisInfo);
_mixer->stopHandle(*_audHandle);
_audStream = 0;
} }
if (_theoraPacket) { if (_theoraPacket) {
ogg_stream_clear(&_theoraOut); ogg_stream_clear(&_theoraOut);
@ -258,7 +269,7 @@ void TheoraDecoder::close() {
Graphics::Surface *TheoraDecoder::decodeNextFrame() { Graphics::Surface *TheoraDecoder::decodeNextFrame() {
int i, j; int i, j;
_stateFlag = 0; // playback has not begun _stateFlag = false; // playback has not begun
// we want a video and audio frame ready to go at all times. If // we want a video and audio frame ready to go at all times. If
// we have to buffer incoming, buffer the compressed data (ie, let // we have to buffer incoming, buffer the compressed data (ie, let
@ -281,7 +292,7 @@ Graphics::Surface *TheoraDecoder::decodeNextFrame() {
_audiobufFill += i * _vorbisInfo.channels * 2; _audiobufFill += i * _vorbisInfo.channels * 2;
if (_audiobufFill == audiofd_fragsize) if (_audiobufFill == audiofd_fragsize)
_audiobufReady = 1; _audiobufReady = true;
if (_vorbisDSP.granulepos >= 0) if (_vorbisDSP.granulepos >= 0)
_audiobufGranulePos = _vorbisDSP.granulepos - ret + i; _audiobufGranulePos = _vorbisDSP.granulepos - ret + i;
@ -327,7 +338,7 @@ Graphics::Surface *TheoraDecoder::decodeNextFrame() {
// with non-keyframe seeks. // with non-keyframe seeks.
if (_videobufTime >= get_time()) if (_videobufTime >= get_time())
_videobufReady = 1; _videobufReady = true;
else { else {
// If we are too slow, reduce the pp level. // If we are too slow, reduce the pp level.
_ppInc = _ppLevel > 0 ? -1 : 0; _ppInc = _ppLevel > 0 ? -1 : 0;
@ -350,12 +361,13 @@ Graphics::Surface *TheoraDecoder::decodeNextFrame() {
} }
// If playback has begun, top audio buffer off immediately. // If playback has begun, top audio buffer off immediately.
if (_stateFlag) audio_write_nonblocking(); if (_stateFlag)
audio_write_nonblocking();
// are we at or past time for this video frame? // are we at or past time for this video frame?
if (_stateFlag && _videobufReady && _videobufTime <= get_time()) { if (_stateFlag && _videobufReady && _videobufTime <= get_time()) {
video_write(); video_write();
_videobufReady = 0; _videobufReady = false;
} }
if (_stateFlag && if (_stateFlag &&
@ -410,11 +422,11 @@ Graphics::Surface *TheoraDecoder::decodeNextFrame() {
// we can begin playback // we can begin playback
if ((!_theoraPacket || _videobufReady) && if ((!_theoraPacket || _videobufReady) &&
(!_vorbisPacket || _audiobufReady)) (!_vorbisPacket || _audiobufReady))
_stateFlag = 1; _stateFlag = true;
// same if we've run out of input // same if we've run out of input
if (_fileStream->eos()) if (_fileStream->eos())
_stateFlag = 1; _stateFlag = true;
} }
void TheoraDecoder::reset() { void TheoraDecoder::reset() {
@ -422,13 +434,24 @@ void TheoraDecoder::reset() {
if (_fileStream) if (_fileStream)
_fileStream->seek(0); _fileStream->seek(0);
_videobufReady = 0; _videobufReady = false;
_videobufGranulePos = -1; _videobufGranulePos = -1;
_videobufTime = 0; _videobufTime = 0;
_audiobufFill = 0; _audiobufFill = 0;
_audiobufReady = 0; _audiobufReady = false;
_audiobufGranulePos = 0; _audiobufGranulePos = 0;
} }
uint32 TheoraDecoder::getElapsedTime() const {
if (_audStream)
return _mixer->getSoundElapsedTime(*_audHandle);
return VideoDecoder::getElapsedTime();
}
Audio::QueuingAudioStream *AviDecoder::createAudioStream() {
return Audio::makeQueuingAudioStream(_vorbisInfo.rate, _vorbisInfo.channels);
}
} // End of namespace Sword25 } // End of namespace Sword25

View file

@ -27,6 +27,8 @@
#define SWORD25_THEORADECODER_H #define SWORD25_THEORADECODER_H
#include "graphics/video/video_decoder.h" #include "graphics/video/video_decoder.h"
#include "sound/audiostream.h"
#include "sound/mixer.h"
#include <theora/theoradec.h> #include <theora/theoradec.h>
#include <vorbis/codec.h> #include <vorbis/codec.h>
@ -45,7 +47,7 @@ namespace Sword25 {
*/ */
class TheoraDecoder : public Graphics::FixedRateVideoDecoder { class TheoraDecoder : public Graphics::FixedRateVideoDecoder {
public: public:
TheoraDecoder(); TheoraDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType);
virtual ~TheoraDecoder(); virtual ~TheoraDecoder();
/** /**
@ -68,6 +70,8 @@ public:
uint32 getFrameCount() const { return _frameCount; } uint32 getFrameCount() const { return _frameCount; }
Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat(3, 8, 8, 8, 0, 0, 0, 0, 0); } Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat(3, 8, 8, 8, 0, 0, 0, 0, 0); }
uint32 getElapsedTime() const;
protected: protected:
Common::Rational getFrameRate() const { return _frameRate; } Common::Rational getFrameRate() const { return _frameRate; }
@ -81,6 +85,12 @@ private:
Common::Rational _frameRate; Common::Rational _frameRate;
uint32 _frameCount; uint32 _frameCount;
Audio::Mixer *_mixer;
Audio::Mixer::SoundType _soundType;
Audio::SoundHandle *_audHandle;
Audio::QueuingAudioStream *_audStream;
Audio::QueuingAudioStream *createAudioStream();
ogg_sync_state _oggSync; ogg_sync_state _oggSync;
ogg_page _oggPage; ogg_page _oggPage;
ogg_packet _oggPacket; ogg_packet _oggPacket;
@ -97,20 +107,20 @@ private:
int _theoraPacket; int _theoraPacket;
int _vorbisPacket; int _vorbisPacket;
int _stateFlag; bool _stateFlag;
int _ppLevelMax; int _ppLevelMax;
int _ppLevel; int _ppLevel;
int _ppInc; int _ppInc;
// single frame video buffering // single frame video buffering
int _videobufReady; bool _videobufReady;
ogg_int64_t _videobufGranulePos; ogg_int64_t _videobufGranulePos;
double _videobufTime; double _videobufTime;
// single audio fragment audio buffering // single audio fragment audio buffering
int _audiobufFill; int _audiobufFill;
int _audiobufReady; bool _audiobufReady;
ogg_int16_t *_audiobuf; ogg_int16_t *_audiobuf;
ogg_int64_t _audiobufGranulePos; // time position of last sample ogg_int64_t _audiobufGranulePos; // time position of last sample
}; };