diff options
-rw-r--r-- | engines/sword25/fmv/theora_decoder.cpp | 107 | ||||
-rwxr-xr-x | engines/sword25/fmv/theora_decoder.h | 3 |
2 files changed, 40 insertions, 70 deletions
diff --git a/engines/sword25/fmv/theora_decoder.cpp b/engines/sword25/fmv/theora_decoder.cpp index f0a4fd7eab..b6647559d2 100644 --- a/engines/sword25/fmv/theora_decoder.cpp +++ b/engines/sword25/fmv/theora_decoder.cpp @@ -37,10 +37,14 @@ */ #include "sword25/fmv/theora_decoder.h" + #include "common/system.h" +#include "sound/decoders/raw.h" namespace Sword25 { +#define AUDIOFD_FRAGSIZE 10240 + TheoraDecoder::TheoraDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) : _mixer(mixer) { _fileStream = 0; _surface = 0; @@ -180,6 +184,7 @@ bool TheoraDecoder::load(Common::SeekableReadStream &stream) { debugN(1, "Ogg logical stream %lx is Theora %dx%d %.02f fps", _theoraOut.serialno, _theoraInfo.pic_width, _theoraInfo.pic_height, (double)_theoraInfo.fps_numerator / _theoraInfo.fps_denominator); + switch (_theoraInfo.pixel_fmt) { case TH_PF_420: debug(1, " 4:2:0 video"); @@ -231,6 +236,10 @@ bool TheoraDecoder::load(Common::SeekableReadStream &stream) { _mixer->playStream(_soundType, _audHandle, _audStream); } + _surface = new Graphics::Surface(); + + _surface->create(_theoraInfo.frame_width, _theoraInfo.frame_height, 3); + return true; } @@ -281,17 +290,17 @@ Graphics::Surface *TheoraDecoder::decodeNextFrame() { // if there's pending, decoded audio, grab it if ((ret = vorbis_synthesis_pcmout(&_vorbisDSP, &pcm)) > 0) { int count = _audiobufFill / 2; - int maxsamples = (audiofd_fragsize - _audiobufFill) / 2 / _vorbisInfo.channels; + int maxsamples = (AUDIOFD_FRAGSIZE - _audiobufFill) / 2 / _vorbisInfo.channels; for (i = 0; i < ret && i < maxsamples; i++) for (j = 0; j < _vorbisInfo.channels; j++) { - int val = CLIP(rint(pcm[j][i] * 32767.f), -32768, 32768); + int val = CLIP((int)rint(pcm[j][i] * 32767.f), -32768, 32768); _audiobuf[count++] = val; } vorbis_synthesis_read(&_vorbisDSP, i); _audiobufFill += i * _vorbisInfo.channels * 2; - if (_audiobufFill == audiofd_fragsize) + if (_audiobufFill == AUDIOFD_FRAGSIZE) _audiobufReady = true; if (_vorbisDSP.granulepos >= 0) @@ -331,26 +340,16 @@ Graphics::Surface *TheoraDecoder::decodeNextFrame() { _videobufTime = th_granule_time(_theoraDecode, _videobufGranulePos); _curFrame++; - // is it already too old to be useful? This is only actually - // useful cosmetically after a SIGSTOP. Note that we have to - // decode the frame even if we don't show it (for now) due to - // keyframing. Soon enough libtheora will be able to deal - // with non-keyframe seeks. - - if (_videobufTime >= get_time()) - _videobufReady = true; - else { - // If we are too slow, reduce the pp level. - _ppInc = _ppLevel > 0 ? -1 : 0; - dropped++; - } + _videobufReady = true; } } else break; } - if (!_videobufReady && !_audiobufReady && _fileStream->eos()) - break; + if (!_videobufReady && !_audiobufReady && _fileStream->eos()) { + close(); + return _surface; + } if (!_videobufReady || !_audiobufReady) { // no data yet for somebody. Grab another page @@ -361,61 +360,29 @@ Graphics::Surface *TheoraDecoder::decodeNextFrame() { } // If playback has begun, top audio buffer off immediately. - if (_stateFlag) - audio_write_nonblocking(); + if (_stateFlag) { + _audStream->queueBuffer((byte *)_audiobuf, AUDIOFD_FRAGSIZE, DisposeAfterUse::NO, Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN | Audio::FLAG_STEREO); + } // are we at or past time for this video frame? - if (_stateFlag && _videobufReady && _videobufTime <= get_time()) { - video_write(); - _videobufReady = false; - } + if (_stateFlag && _videobufReady) { + th_ycbcr_buffer yuv; + + th_decode_ycbcr_out(_theoraDecode, yuv); - if (_stateFlag && - (_audiobufReady || !_vorbisPacket) && - (_videobufReady || !_theoraPacket) && - !got_sigint) { - // we have an audio frame ready (which means the audio buffer is - // full), it's not time to play video, so wait until one of the - // audio buffer is ready or it's near time to play video - - // set up select wait on the audiobuffer and a timeout for video - struct timeval timeout; - fd_set writefs; - fd_set empty; - int n = 0; - - FD_ZERO(&writefs); - FD_ZERO(&empty); - if (audiofd >= 0) { - FD_SET(audiofd, &writefs); - n = audiofd + 1; + // TODO: YUV->RGB + switch (_theoraInfo.pixel_fmt) { + case TH_PF_420: + break; + case TH_PF_422: + break; + case TH_PF_444: + break; + default: + break; } - if (_theoraPacket) { - double tdiff; - long milliseconds; - tdiff = _videobufTime - get_time(); - - // If we have lots of extra time, increase the post-processing level. - if (tdiff > _theoraInfo.fps_denominator * 0.25 / _theoraInfo.fps_numerator) { - _ppInc = _ppLevel < _ppLevelMax ? 1 : 0; - } else if (tdiff < _theoraInfo.fps_denominator * 0.05 / _theoraInfo.fps_numerator) { - _ppInc = _ppLevel > 0 ? -1 : 0; - } - milliseconds = tdiff * 1000 - 5; - if (milliseconds > 500) - milliseconds = 500; - if (milliseconds > 0) { - timeout.tv_sec = milliseconds / 1000; - timeout.tv_usec = (milliseconds % 1000) * 1000; - - n = select(n, &empty, &writefs, &empty, &timeout); - if (n) - audio_calibrate_timer(0); - } - } else { - select(n, &empty, &writefs, &empty, NULL); - } + _videobufReady = false; } // if our buffers either don't exist or are ready to go, @@ -427,6 +394,8 @@ Graphics::Surface *TheoraDecoder::decodeNextFrame() { // same if we've run out of input if (_fileStream->eos()) _stateFlag = true; + + return _surface; } void TheoraDecoder::reset() { @@ -450,7 +419,7 @@ uint32 TheoraDecoder::getElapsedTime() const { return VideoDecoder::getElapsedTime(); } -Audio::QueuingAudioStream *AviDecoder::createAudioStream() { +Audio::QueuingAudioStream *TheoraDecoder::createAudioStream() { return Audio::makeQueuingAudioStream(_vorbisInfo.rate, _vorbisInfo.channels); } diff --git a/engines/sword25/fmv/theora_decoder.h b/engines/sword25/fmv/theora_decoder.h index cd526b6ba0..b6cf4567fc 100755 --- a/engines/sword25/fmv/theora_decoder.h +++ b/engines/sword25/fmv/theora_decoder.h @@ -56,6 +56,7 @@ public: */ bool load(Common::SeekableReadStream &stream); void close(); + void reset(); /** * Decode the next frame and return the frame's surface @@ -78,6 +79,7 @@ protected: private: void queuePage(ogg_page *page); int bufferData(); + Audio::QueuingAudioStream *createAudioStream(); private: Common::SeekableReadStream *_fileStream; @@ -89,7 +91,6 @@ private: Audio::Mixer::SoundType _soundType; Audio::SoundHandle *_audHandle; Audio::QueuingAudioStream *_audStream; - Audio::QueuingAudioStream *createAudioStream(); ogg_sync_state _oggSync; ogg_page _oggPage; |