diff options
Diffstat (limited to 'video')
-rw-r--r-- | video/avi_decoder.cpp | 68 | ||||
-rw-r--r-- | video/avi_decoder.h | 7 | ||||
-rw-r--r-- | video/codecs/mpeg.cpp | 107 | ||||
-rw-r--r-- | video/codecs/mpeg.h | 98 | ||||
-rw-r--r-- | video/module.mk | 5 |
5 files changed, 264 insertions, 21 deletions
diff --git a/video/avi_decoder.cpp b/video/avi_decoder.cpp index 6fe9c773b8..ff728a8437 100644 --- a/video/avi_decoder.cpp +++ b/video/avi_decoder.cpp @@ -36,6 +36,7 @@ // Video Codecs #include "video/codecs/cinepak.h" #include "video/codecs/indeo3.h" +#include "video/codecs/mpeg.h" #include "video/codecs/msvideo1.h" #include "video/codecs/msrle.h" #include "video/codecs/truemotion1.h" @@ -64,8 +65,8 @@ namespace Video { #define ID_VEDT MKTAG('v','e','d','t') #define ID_IDX1 MKTAG('i','d','x','1') #define ID_STRD MKTAG('s','t','r','d') -#define ID_00AM MKTAG('0','0','A','M') //#define ID_INFO MKTAG('I','N','F','O') +#define ID_ISFT MKTAG('I','S','F','T') // Codec tags #define ID_RLE MKTAG('R','L','E',' ') @@ -75,6 +76,7 @@ namespace Video { #define ID_CVID MKTAG('c','v','i','d') #define ID_IV32 MKTAG('i','v','3','2') #define ID_DUCK MKTAG('D','U','C','K') +#define ID_MPG2 MKTAG('m','p','g','2') static byte char2num(char c) { c = tolower((byte)c); @@ -89,17 +91,27 @@ static uint16 getStreamType(uint32 tag) { return tag & 0xffff; } -AVIDecoder::AVIDecoder(Audio::Mixer::SoundType soundType) : _soundType(soundType) { - _decodedHeader = false; - _fileStream = 0; - memset(&_ixInfo, 0, sizeof(_ixInfo)); - memset(&_header, 0, sizeof(_header)); +AVIDecoder::AVIDecoder(Audio::Mixer::SoundType soundType) : _frameRateOverride(0), _soundType(soundType) { + initCommon(); +} + +AVIDecoder::AVIDecoder(const Common::Rational &frameRateOverride, Audio::Mixer::SoundType soundType) + : _frameRateOverride(frameRateOverride), _soundType(soundType) { + initCommon(); } AVIDecoder::~AVIDecoder() { close(); } +void AVIDecoder::initCommon() { + _decodedHeader = false; + _foundMovieList = false; + _fileStream = 0; + memset(&_ixInfo, 0, sizeof(_ixInfo)); + memset(&_header, 0, sizeof(_header)); +} + void AVIDecoder::runHandle(uint32 tag) { assert(_fileStream); if (_fileStream->eos()) @@ -137,6 +149,7 @@ void AVIDecoder::runHandle(uint32 tag) { case ID_STRD: // Extra stream info, safe to ignore case ID_VEDT: // Unknown, safe to ignore case ID_JUNK: // Alignment bytes, should be ignored + case ID_ISFT: // Metadata, safe to ignore { uint32 junkSize = _fileStream->readUint32LE(); _fileStream->skip(junkSize + (junkSize & 1)); // Alignment @@ -165,6 +178,13 @@ void AVIDecoder::handleList() { debug(0, "Found LIST of type %s", tag2str(listType)); + if (listType == ID_MOVI) { + // Found the 'movi' list + // We're done parsing everything + _foundMovieList = true; + return; + } + while ((_fileStream->pos() - curPos) < listSize) runHandle(_fileStream->readUint32BE()); @@ -203,6 +223,11 @@ void AVIDecoder::handleStreamHeader() { uint32 startPos = _fileStream->pos(); if (sHeader.streamType == ID_VIDS) { + if (_frameRateOverride != 0) { + sHeader.rate = _frameRateOverride.getNumerator(); + sHeader.scale = _frameRateOverride.getDenominator(); + } + BitmapInfoHeader bmInfo; bmInfo.size = _fileStream->readUint32LE(); bmInfo.width = _fileStream->readUint32LE(); @@ -263,26 +288,24 @@ bool AVIDecoder::loadStream(Common::SeekableReadStream *stream) { _fileStream = stream; _decodedHeader = false; + _foundMovieList = false; // Read chunks until we have decoded the header - while (!_decodedHeader) + while (!_decodedHeader && _fileStream->pos() < _fileStream->size()) runHandle(_fileStream->readUint32BE()); - uint32 nextTag = _fileStream->readUint32BE(); - - // Throw out any JUNK section - if (nextTag == ID_JUNK) { - runHandle(ID_JUNK); - nextTag = _fileStream->readUint32BE(); + if (_fileStream->pos() >= _fileStream->size()) { + warning("Failed to find AVI header"); + return false; } - // Ignore the 'movi' LIST - if (nextTag == ID_LIST) { - _fileStream->readUint32BE(); // Skip size - if (_fileStream->readUint32BE() != ID_MOVI) - error("Expected 'movi' LIST"); - } else { - error("Expected 'movi' LIST"); + // Then read until we find the movie list + while (!_foundMovieList && _fileStream->pos() < _fileStream->size()) + runHandle(_fileStream->readUint32BE()); + + if (_fileStream->pos() >= _fileStream->size()) { + warning("Failed to find AVI 'movi' LIST"); + return false; } return true; @@ -294,6 +317,7 @@ void AVIDecoder::close() { delete _fileStream; _fileStream = 0; _decodedHeader = false; + _foundMovieList = false; delete[] _ixInfo.indices; memset(&_ixInfo, 0, sizeof(_ixInfo)); @@ -428,6 +452,10 @@ Codec *AVIDecoder::AVIVideoTrack::createCodec() { case ID_DUCK: return new TrueMotion1Decoder(_bmInfo.width, _bmInfo.height); #endif +#ifdef USE_MPEG2 + case ID_MPG2: + return new MPEGDecoder(); +#endif default: warning("Unknown/Unhandled compression format \'%s\'", tag2str(_vidsHeader.streamHandler)); } diff --git a/video/avi_decoder.h b/video/avi_decoder.h index 34a67f4c28..6082232464 100644 --- a/video/avi_decoder.h +++ b/video/avi_decoder.h @@ -52,10 +52,13 @@ class Codec; * * Video decoder used in engines: * - sci + * - sword1 + * - sword2 */ class AVIDecoder : public VideoDecoder { public: AVIDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType); + AVIDecoder(const Common::Rational &frameRateOverride, Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType); virtual ~AVIDecoder(); bool loadStream(Common::SeekableReadStream *stream); @@ -219,9 +222,11 @@ private: AVIHeader _header; Common::SeekableReadStream *_fileStream; - bool _decodedHeader; + bool _decodedHeader, _foundMovieList; Audio::Mixer::SoundType _soundType; + Common::Rational _frameRateOverride; + void initCommon(); void runHandle(uint32 tag); void handleList(); diff --git a/video/codecs/mpeg.cpp b/video/codecs/mpeg.cpp new file mode 100644 index 0000000000..cb3c63fcfc --- /dev/null +++ b/video/codecs/mpeg.cpp @@ -0,0 +1,107 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/debug.h" +#include "common/stream.h" +#include "common/system.h" +#include "common/textconsole.h" +#include "graphics/surface.h" +#include "graphics/yuv_to_rgb.h" + +#include "video/codecs/mpeg.h" + +namespace Video { + +MPEGDecoder::MPEGDecoder() : Codec() { + _pixelFormat = g_system->getScreenFormat(); + _surface = 0; + + _mpegDecoder = mpeg2_init(); + + if (!_mpegDecoder) + error("Could not initialize libmpeg2"); + + _mpegInfo = mpeg2_info(_mpegDecoder); +} + +MPEGDecoder::~MPEGDecoder() { + mpeg2_close(_mpegDecoder); + + if (_surface) { + _surface->free(); + delete _surface; + } +} + +const Graphics::Surface *MPEGDecoder::decodeImage(Common::SeekableReadStream *stream) { + uint32 framePeriod; + decodePacket(stream, framePeriod); + return _surface; +} + +bool MPEGDecoder::decodePacket(Common::SeekableReadStream *packet, uint32 &framePeriod, Graphics::Surface *dst) { + // Decode as much as we can out of this packet + uint32 size = 0xFFFFFFFF; + mpeg2_state_t state; + bool foundFrame = false; + framePeriod = 0; + + do { + state = mpeg2_parse(_mpegDecoder); + + switch (state) { + case STATE_BUFFER: + size = packet->read(_buffer, BUFFER_SIZE); + mpeg2_buffer(_mpegDecoder, _buffer, _buffer + size); + break; + case STATE_SLICE: + case STATE_END: + if (_mpegInfo->display_fbuf) { + foundFrame = true; + const mpeg2_sequence_t *sequence = _mpegInfo->sequence; + + framePeriod += sequence->frame_period; + + if (!dst) { + // If no destination is specified, use our internal storage + if (!_surface) { + _surface = new Graphics::Surface(); + _surface->create(sequence->picture_width, sequence->picture_height, _pixelFormat); + } + + dst = _surface; + } + + YUVToRGBMan.convert420(dst, Graphics::YUVToRGBManager::kScaleITU, _mpegInfo->display_fbuf->buf[0], + _mpegInfo->display_fbuf->buf[1], _mpegInfo->display_fbuf->buf[2], sequence->picture_width, + sequence->picture_height, sequence->width, sequence->chroma_width); + } + break; + default: + break; + } + } while (size != 0); + + return foundFrame; +} + +} // End of namespace Video diff --git a/video/codecs/mpeg.h b/video/codecs/mpeg.h new file mode 100644 index 0000000000..0082844537 --- /dev/null +++ b/video/codecs/mpeg.h @@ -0,0 +1,98 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifdef USE_MPEG2 + +#ifndef VIDEO_CODECS_MPEG_H +#define VIDEO_CODECS_MPEG_H + +#include "video/codecs/codec.h" +#include "graphics/pixelformat.h" + +#if defined(__PLAYSTATION2__) + typedef uint8 uint8_t; + typedef uint16 uint16_t; + typedef uint32 uint32_t; +#elif defined(_WIN32_WCE) + typedef signed char int8_t; + typedef signed short int16_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; +#elif defined(_MSC_VER) + typedef signed char int8_t; + typedef signed short int16_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + #if !defined(SDL_COMPILEDVERSION) || (SDL_COMPILEDVERSION < 1210) + typedef signed long int32_t; + typedef unsigned long uint32_t; + #endif +#else +# include <inttypes.h> +#endif + +extern "C" { + #include <mpeg2dec/mpeg2.h> +} + +namespace Common { +class SeekableReadStream; +} + +namespace Graphics { +struct Surface; +} + +namespace Video { + +// MPEG 1/2 video decoder + +class MPEGDecoder : public Codec { +public: + MPEGDecoder(); + ~MPEGDecoder(); + + // Codec interface + const Graphics::Surface *decodeImage(Common::SeekableReadStream *stream); + Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; } + + // MPEGPSDecoder call + bool decodePacket(Common::SeekableReadStream *packet, uint32 &framePeriod, Graphics::Surface *dst = 0); + +private: + Graphics::PixelFormat _pixelFormat; + Graphics::Surface *_surface; + + enum { + BUFFER_SIZE = 4096 + }; + + byte _buffer[BUFFER_SIZE]; + mpeg2dec_t *_mpegDecoder; + const mpeg2_info_t *_mpegInfo; +}; + +} // End of namespace Video + +#endif // VIDEO_CODECS_MPEG_H + +#endif // USE_MPEG2 diff --git a/video/module.mk b/video/module.mk index 287e14ce18..a491947aaf 100644 --- a/video/module.mk +++ b/video/module.mk @@ -31,5 +31,10 @@ MODULE_OBJS += \ theora_decoder.o endif +ifdef USE_MPEG2 +MODULE_OBJS += \ + codecs/mpeg.o +endif + # Include common rules include $(srcdir)/rules.mk |