From b43e99566ebad682d28e32fedae9606048284844 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Fri, 16 Oct 2009 18:05:56 +0000 Subject: Converting AVIPlayer into a class that inherits from VideoDecoder and adapt SCI to use this. Also, moving the codec and Codec class into their own folder. (Based on a patch by md5) svn-id: r45170 --- dists/msvc8/scummvm.vcproj | 11 +- dists/msvc9/scummvm.vcproj | 11 +- engines/sci/engine/kgraphics.cpp | 132 +++--------- graphics/module.mk | 4 +- graphics/video/avi_decoder.cpp | 399 +++++++++++++++++++++++++++++++++++++ graphics/video/avi_decoder.h | 227 +++++++++++++++++++++ graphics/video/avi_player.cpp | 383 ----------------------------------- graphics/video/avi_player.h | 241 ---------------------- graphics/video/codecs/codec.h | 43 ++++ graphics/video/codecs/msvideo1.cpp | 139 +++++++++++++ graphics/video/codecs/msvideo1.h | 51 +++++ graphics/video/msvideo1.cpp | 139 ------------- graphics/video/msvideo1.h | 52 ----- 13 files changed, 907 insertions(+), 925 deletions(-) create mode 100644 graphics/video/avi_decoder.cpp create mode 100644 graphics/video/avi_decoder.h delete mode 100644 graphics/video/avi_player.cpp delete mode 100644 graphics/video/avi_player.h create mode 100644 graphics/video/codecs/codec.h create mode 100644 graphics/video/codecs/msvideo1.cpp create mode 100644 graphics/video/codecs/msvideo1.h delete mode 100644 graphics/video/msvideo1.cpp delete mode 100644 graphics/video/msvideo1.h diff --git a/dists/msvc8/scummvm.vcproj b/dists/msvc8/scummvm.vcproj index a6a465844c..1fe48b0e9e 100644 --- a/dists/msvc8/scummvm.vcproj +++ b/dists/msvc8/scummvm.vcproj @@ -452,20 +452,23 @@ - - + + - - + + + + + diff --git a/dists/msvc9/scummvm.vcproj b/dists/msvc9/scummvm.vcproj index 41355c20cb..e0dd6cc9a7 100644 --- a/dists/msvc9/scummvm.vcproj +++ b/dists/msvc9/scummvm.vcproj @@ -453,20 +453,23 @@ - - + + - - + + + + + diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp index c558a83b1e..1dc3422923 100644 --- a/engines/sci/engine/kgraphics.cpp +++ b/engines/sci/engine/kgraphics.cpp @@ -24,7 +24,7 @@ */ #include "graphics/cursorman.h" -#include "graphics/video/avi_player.h" +#include "graphics/video/avi_decoder.h" #include "graphics/surface.h" #include "sci/sci.h" @@ -978,102 +978,6 @@ reg_t kDisplay(EngineState *s, int argc, reg_t *argv) { return s->r_acc; } -static reg_t kShowMovie_Windows(EngineState *s, int argc, reg_t *argv) { - Common::String filename = s->_segMan->getString(argv[1]); - - Graphics::AVIPlayer *player = new Graphics::AVIPlayer(g_system); - - if (!player->open(filename)) { - warning("Failed to open movie file %s", filename.c_str()); - return s->r_acc; - } - - uint32 startTime = g_system->getMillis(); - bool play = true; - - while (play && player->getCurFrame() < player->getFrameCount()) { - uint32 elapsed = g_system->getMillis() - startTime; - - if (elapsed >= player->getCurFrame() * 1000 / player->getFrameRate()) { - Graphics::Surface *surface = player->getNextFrame(); - - Palette *palette = NULL; - - if (player->dirtyPalette()) { - byte *rawPalette = player->getPalette(); - Palette *colors = new Palette(256); - - byte r, g, b; - - for (uint16 i = 0; i < 256; i++) { - r = rawPalette[i * 4]; - g = rawPalette[i * 4 + 1]; - b = rawPalette[i * 4 + 2]; - colors->setColor(i, r, g, b); - } - - palette->forceInto(s->gfx_state->driver->getMode()->palette); - } - - if (surface) { - // Allocate a pixmap - gfx_pixmap_t *pixmap = gfx_new_pixmap(surface->w, surface->h, 0, 0, 0); - assert(pixmap); - gfx_pixmap_alloc_index_data(pixmap); - - // Copy data from the surface - memcpy(pixmap->index_data, surface->pixels, surface->w * surface->h); - pixmap->xoffset = (g_system->getWidth() - surface->w) / 2; - pixmap->yoffset = (g_system->getHeight() - surface->h) / 2; - pixmap->palette = palette; - - // Copy the frame to the screen - gfx_xlate_pixmap(pixmap, s->gfx_state->driver->getMode()); - gfxop_draw_pixmap(s->gfx_state, pixmap, gfx_rect(0, 0, 320, 200), Common::Point(pixmap->xoffset, pixmap->yoffset)); - gfxop_update_box(s->gfx_state, gfx_rect(0, 0, 320, 200)); - gfx_free_pixmap(pixmap); - - // Surface is freed when the codec in the video is deleted - } - } - - Common::Event event; - while (g_system->getEventManager()->pollEvent(event)) { - switch (event.type) { - case Common::EVENT_QUIT: - play = false; - quit_vm(); - break; - default: - break; - } - } - - g_system->delayMillis(10); - } - - delete player; - - return s->r_acc; -} - -static reg_t kShowMovie_DOS(EngineState *s, int argc, reg_t *argv) { - Common::String filename = s->_segMan->getString(argv[0]); - int delay = argv[1].toUint16(); // Time between frames in ticks - - Graphics::SeqDecoder *seqDecoder = new Graphics::SeqDecoder(); - Graphics::VideoPlayer *player = new Graphics::VideoPlayer(seqDecoder); - if (seqDecoder->loadFile(filename.c_str(), delay)) - player->playVideo(); - else - warning("Failed to open movie file %s", filename.c_str()); - seqDecoder->closeFile(); - delete player; - delete seqDecoder; - - return s->r_acc; -} - reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) { // KQ6 Windows calls this with one argument. It doesn't seem // to have a purpose... @@ -1082,10 +986,38 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) { // The Windows and DOS versions use different video format as well // as a different argument set. - if (argv[0].toUint16() == 0) - return kShowMovie_Windows(s, argc, argv); + if (argv[0].toUint16() == 0) { + // Windows + + Common::String filename = s->_segMan->getString(argv[1]); + + Graphics::AviDecoder *aviDecoder = new Graphics::AviDecoder(g_system->getMixer()); + Graphics::VideoPlayer *player = new Graphics::VideoPlayer(aviDecoder); + if (aviDecoder->loadFile(filename.c_str())) + player->playVideo(); + else + warning("Failed to open movie file %s", filename.c_str()); + aviDecoder->closeFile(); + delete player; + delete aviDecoder; + } else { + // DOS - return kShowMovie_DOS(s, argc, argv); + Common::String filename = s->_segMan->getString(argv[0]); + int delay = argv[1].toUint16(); // Time between frames in ticks + + Graphics::SeqDecoder *seqDecoder = new Graphics::SeqDecoder(); + Graphics::VideoPlayer *player = new Graphics::VideoPlayer(seqDecoder); + if (seqDecoder->loadFile(filename.c_str(), delay)) + player->playVideo(); + else + warning("Failed to open movie file %s", filename.c_str()); + seqDecoder->closeFile(); + delete player; + delete seqDecoder; + } + + return s->r_acc; } reg_t kSetVideoMode(EngineState *s, int argc, reg_t *argv) { diff --git a/graphics/module.mk b/graphics/module.mk index d8eece0440..31156ab1ff 100644 --- a/graphics/module.mk +++ b/graphics/module.mk @@ -21,13 +21,13 @@ MODULE_OBJS := \ thumbnail.o \ VectorRenderer.o \ VectorRendererSpec.o \ - video/avi_player.o \ + video/avi_decoder.o \ video/dxa_decoder.o \ video/flic_decoder.o \ video/mpeg_player.o \ - video/msvideo1.o \ video/smk_decoder.o \ video/video_player.o \ + video/codecs/msvideo1.o \ video/coktelvideo/indeo3.o \ video/coktelvideo/coktelvideo.o diff --git a/graphics/video/avi_decoder.cpp b/graphics/video/avi_decoder.cpp new file mode 100644 index 0000000000..fa5494d9b9 --- /dev/null +++ b/graphics/video/avi_decoder.cpp @@ -0,0 +1,399 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "common/archive.h" +#include "common/endian.h" +#include "common/file.h" +#include "common/stream.h" +#include "common/events.h" + +#include "sound/audiostream.h" +#include "sound/mixer.h" + +#include "graphics/video/avi_decoder.h" + +// Codecs +#include "graphics/video/codecs/msvideo1.h" + +namespace Graphics { + +AviDecoder::AviDecoder(Audio::Mixer *mixer) : _mixer(mixer) { + _videoCodec = NULL; + _decodedHeader = false; + _audStream = NULL; + _fileStream = NULL; + _audHandle = new Audio::SoundHandle(); + memset(&_wvInfo, 0, sizeof(PCMWAVEFORMAT)); + memset(&_bmInfo, 0, sizeof(BITMAPINFOHEADER)); + memset(&_vidsHeader, 0, sizeof(AVIStreamHeader)); + memset(&_audsHeader, 0, sizeof(AVIStreamHeader)); + memset(&_ixInfo, 0, sizeof(AVIOLDINDEX)); +} + +AviDecoder::~AviDecoder() { + delete _audHandle; + closeFile(); +} + +void AviDecoder::runHandle(uint32 tag) { + assert (_fileStream); + if (_fileStream->eos()) + return; + + debug (3, "Decoding tag %s", tag2str(tag)); + + switch (tag) { + case ID_RIFF: + /*_filesize = */_fileStream->readUint32LE(); + if (_fileStream->readUint32BE() != ID_AVI) + error("RIFF file is not an AVI video"); + break; + case ID_LIST: + handleList(); + break; + case ID_AVIH: + _header.size = _fileStream->readUint32LE(); + _header.microSecondsPerFrame = _fileStream->readUint32LE(); + _header.maxBytesPerSecond = _fileStream->readUint32LE(); + _header.padding = _fileStream->readUint32LE(); + _header.flags = _fileStream->readUint32LE(); + _header.totalFrames = _fileStream->readUint32LE(); + _header.initialFrames = _fileStream->readUint32LE(); + _header.streams = _fileStream->readUint32LE(); + _header.bufferSize = _fileStream->readUint32LE(); + _header.width = _fileStream->readUint32LE(); + _header.height = _fileStream->readUint32LE(); + //Ignore 16 bytes of reserved data + _fileStream->skip(16); + break; + case ID_STRH: + handleStreamHeader(); + break; + case ID_STRD: // Extra stream info, safe to ignore + case ID_VEDT: // Unknown, safe to ignore + case ID_JUNK: // Alignment bytes, should be ignored + { + uint32 junkSize = _fileStream->readUint32LE(); + _fileStream->skip(junkSize + (junkSize & 1)); // Alignment + } break; + case ID_IDX1: + _ixInfo.size = _fileStream->readUint32LE(); + _ixInfo.indices = new AVIOLDINDEX::Index[_ixInfo.size / 16]; + debug (0, "%d Indices", (_ixInfo.size / 16)); + for (uint32 i = 0; i < (_ixInfo.size / 16); i++) { + _ixInfo.indices[i].id = _fileStream->readUint32BE(); + _ixInfo.indices[i].flags = _fileStream->readUint32LE(); + _ixInfo.indices[i].offset = _fileStream->readUint32LE(); + _ixInfo.indices[i].size = _fileStream->readUint32LE(); + debug (0, "Index %d == Tag \'%s\', Offset = %d, Size = %d", i, tag2str(_ixInfo.indices[i].id), _ixInfo.indices[i].offset, _ixInfo.indices[i].size); + } + break; + default: + error ("Unknown tag \'%s\' found", tag2str(tag)); + } +} + +void AviDecoder::handleList() { + uint32 listSize = _fileStream->readUint32LE() - 4; // Subtract away listType's 4 bytes + uint32 listType = _fileStream->readUint32BE(); + uint32 curPos = _fileStream->pos(); + + debug (0, "Found LIST of type %s", tag2str(listType)); + + while ((_fileStream->pos() - curPos) < listSize) + runHandle(_fileStream->readUint32BE()); + + // We now have all the header data + if (listType == ID_HDRL) + _decodedHeader = true; +} + +void AviDecoder::handleStreamHeader() { + AVIStreamHeader sHeader; + sHeader.size = _fileStream->readUint32LE(); + sHeader.streamType = _fileStream->readUint32BE(); + if (sHeader.streamType == ID_MIDS || sHeader.streamType == ID_TXTS) + error ("Unhandled MIDI/Text stream"); + sHeader.streamHandler = _fileStream->readUint32BE(); + sHeader.flags = _fileStream->readUint32LE(); + sHeader.priority = _fileStream->readUint16LE(); + sHeader.language = _fileStream->readUint16LE(); + sHeader.initialFrames = _fileStream->readUint32LE(); + sHeader.scale = _fileStream->readUint32LE(); + sHeader.rate = _fileStream->readUint32LE(); + sHeader.start = _fileStream->readUint32LE(); + sHeader.length = _fileStream->readUint32LE(); + sHeader.bufferSize = _fileStream->readUint32LE(); + sHeader.quality = _fileStream->readUint32LE(); + sHeader.sampleSize = _fileStream->readUint32LE(); + sHeader.frame.left = _fileStream->readSint16LE(); + sHeader.frame.top = _fileStream->readSint16LE(); + sHeader.frame.right = _fileStream->readSint16LE(); + sHeader.frame.bottom = _fileStream->readSint16LE(); + + if (_fileStream->readUint32BE() != ID_STRF) + error("Could not find STRF tag"); + /* uint32 strfSize = */ _fileStream->readUint32LE(); + + if (sHeader.streamType == ID_VIDS) { + _vidsHeader = sHeader; + + _bmInfo.size = _fileStream->readUint32LE(); + _bmInfo.width = _fileStream->readUint32LE(); + assert (_header.width == _bmInfo.width); + _bmInfo.height = _fileStream->readUint32LE(); + assert (_header.height == _bmInfo.height); + _bmInfo.planes = _fileStream->readUint16LE(); + _bmInfo.bitCount = _fileStream->readUint16LE(); + _bmInfo.compression = _fileStream->readUint32BE(); + _bmInfo.sizeImage = _fileStream->readUint32LE(); + _bmInfo.xPelsPerMeter = _fileStream->readUint32LE(); + _bmInfo.yPelsPerMeter = _fileStream->readUint32LE(); + _bmInfo.clrUsed = _fileStream->readUint32LE(); + _bmInfo.clrImportant = _fileStream->readUint32LE(); + + if (_bmInfo.bitCount == 8) { + if (_bmInfo.clrUsed == 0) + _bmInfo.clrUsed = 256; + + for (uint32 i = 0; i < _bmInfo.clrUsed; i++) { + _palette[i * 3 + 2] = _fileStream->readByte(); + _palette[i * 3 + 1] = _fileStream->readByte(); + _palette[i * 3] = _fileStream->readByte(); + /*_palette[i * 4 + 3] = */_fileStream->readByte(); + } + + setPalette(_palette); + } + } else if (sHeader.streamType == ID_AUDS) { + _audsHeader = sHeader; + + _wvInfo.tag = _fileStream->readUint16LE(); + _wvInfo.channels = _fileStream->readUint16LE(); + _wvInfo.samplesPerSec = _fileStream->readUint32LE(); + _wvInfo.avgBytesPerSec = _fileStream->readUint32LE(); + _wvInfo.blockAlign = _fileStream->readUint16LE(); + _wvInfo.size = _fileStream->readUint16LE(); + } +} + +bool AviDecoder::loadFile(const char *fileName) { + closeFile(); + + _fileStream = SearchMan.createReadStreamForMember(fileName); + if (!_fileStream) + return false; + + _decodedHeader = false; + // Seek to the first frame + _videoInfo.currentFrame = 0; + + + // Read chunks until we have decoded the header + while (!_decodedHeader) + runHandle(_fileStream->readUint32BE()); + + _videoFrameBuffer = new byte[_header.width * _header.height]; + memset(_videoFrameBuffer, 0, _header.width * _header.height); + + uint32 nextTag = _fileStream->readUint32BE(); + + // Throw out any JUNK section + if (nextTag == ID_JUNK) { + runHandle(ID_JUNK); + nextTag = _fileStream->readUint32BE(); + } + + // 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"); + + // Now, create the codec + _videoCodec = createCodec(); + + // Initialize the video stuff too + _audStream = createAudioStream(); + if (_audStream) + _mixer->playInputStream(Audio::Mixer::kPlainSoundType, _audHandle, _audStream); + + debug (0, "Frames = %d, Dimensions = %d x %d", _header.totalFrames, _header.width, _header.height); + debug (0, "Frame Rate = %d", getFrameRate()); + if (_header.flags & AVIF_ISINTERLEAVED) + debug (0, "Sound Rate = %d", AUDIO_RATE); + debug (0, "Video Codec = \'%s\'", tag2str(_vidsHeader.streamHandler)); + + _videoInfo.firstframeOffset = _fileStream->pos(); + _videoInfo.width = _header.width; + _videoInfo.height = _header.height; + _videoInfo.frameCount = _header.totalFrames; + // Our frameDelay is calculated in 1/100 ms, so we convert it here + _videoInfo.frameDelay = _header.microSecondsPerFrame / 10; + + return true; +} + +void AviDecoder::closeFile() { + if (!_fileStream) + return; + + delete _fileStream; + _fileStream = 0; + + delete[] _videoFrameBuffer; + _videoFrameBuffer = 0; + + // Deinitialize sound + _mixer->stopHandle(*_audHandle); + + _decodedHeader = false; + + delete _videoCodec; + delete[] _ixInfo.indices; +} + +Surface *AviDecoder::getNextFrame() { + uint32 nextTag = _fileStream->readUint32BE(); + + if (nextTag == ID_LIST) { + // A list of audio/video chunks + uint32 listSize = _fileStream->readUint32LE() - 4; + int32 startPos = _fileStream->pos(); + + if (_fileStream->readUint32BE() != ID_REC) + error ("Expected 'rec ' LIST"); + + // Decode chunks in the list and see if we get a frame + Surface *frame = NULL; + while (_fileStream->pos() < startPos + (int32)listSize) { + Surface *temp = getNextFrame(); + if (temp) + frame = temp; + } + + return frame; + } else if (getStreamType(nextTag) == 'wb') { + // Audio Chunk + uint32 chunkSize = _fileStream->readUint32LE(); + byte *data = new byte[chunkSize]; + _fileStream->read(data, chunkSize); + _audStream->queueBuffer(data, chunkSize); + _fileStream->skip(chunkSize & 1); // Alignment + } else if (getStreamType(nextTag) == 'dc' || getStreamType(nextTag) == 'id') { + // Compressed Frame + _videoInfo.currentFrame++; + uint32 chunkSize = _fileStream->readUint32LE(); + + if (chunkSize == 0) // Keep last frame on screen + return NULL; + + Common::SeekableReadStream *frameData = _fileStream->readStream(chunkSize); + Graphics::Surface *surface = _videoCodec->decodeImage(frameData); + delete frameData; + _fileStream->skip(chunkSize & 1); // Alignment + return surface; + } else if (getStreamType(nextTag) == 'pc') { + // Palette Change + _fileStream->readUint32LE(); // Chunk size, not needed here + byte firstEntry = _fileStream->readByte(); + uint16 numEntries = _fileStream->readByte(); + _fileStream->readUint16LE(); // Reserved + + // 0 entries means all colors are going to be changed + if (numEntries == 0) + numEntries = 256; + + for (uint16 i = firstEntry; i < numEntries + firstEntry; i++) { + _palette[i * 3] = _fileStream->readByte(); + _palette[i * 3 + 1] = _fileStream->readByte(); + _palette[i * 3 + 2] = _fileStream->readByte(); + _fileStream->readByte(); // Flags that don't serve us any purpose + } + + setPalette(_palette); + + // No alignment necessary. It's always even. + } else if (nextTag == ID_JUNK) { + runHandle(ID_JUNK); + } else + error ("Tag = \'%s\'", tag2str(nextTag)); + + return NULL; +} + +bool AviDecoder::decodeNextFrame() { + if (_videoInfo.currentFrame == 0) + _videoInfo.startTime = g_system->getMillis(); + + Surface *surface = NULL; + + while (!surface && _videoInfo.currentFrame < _videoInfo.frameCount) + surface = getNextFrame(); + + if (surface) + memcpy(_videoFrameBuffer, surface->pixels, _header.width * _header.height); + + return _videoInfo.currentFrame < _videoInfo.frameCount; +} + +Codec *AviDecoder::createCodec() { + switch (_vidsHeader.streamHandler) { + case ID_CRAM: + case ID_MSVC: + case ID_WHAM: + return new MSVideo1Decoder(_bmInfo.width, _bmInfo.height, _bmInfo.bitCount); + default: + warning ("Unknown/Unhandled compression format \'%s\'", tag2str(_vidsHeader.streamHandler)); + } + + return NULL; +} + +Audio::AppendableAudioStream *AviDecoder::createAudioStream() { + if (_wvInfo.tag == AVI_WAVE_FORMAT_PCM) + return Audio::makeAppendableAudioStream(AUDIO_RATE, Audio::Mixer::FLAG_UNSIGNED|Audio::Mixer::FLAG_AUTOFREE); + + if (_wvInfo.tag != 0) // No sound + warning ("Unsupported AVI audio format %d", _wvInfo.tag); + + return NULL; +} + +byte AviDecoder::char2num(char c) { + return (c >= 48 && c <= 57) ? c - 48 : 0; +} + +byte AviDecoder::getStreamNum(uint32 tag) { + return char2num((char)(tag >> 24)) * 16 + char2num((char)(tag >> 16)); +} + +uint16 AviDecoder::getStreamType(uint32 tag) { + return tag & 0xffff; +} + +} // End of namespace Graphics diff --git a/graphics/video/avi_decoder.h b/graphics/video/avi_decoder.h new file mode 100644 index 0000000000..85500302d0 --- /dev/null +++ b/graphics/video/avi_decoder.h @@ -0,0 +1,227 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef GRAPHICS_AVI_PLAYER_H +#define GRAPHICS_AVI_PLAYER_H + +#include "graphics/video/video_player.h" +#include "graphics/video/codecs/codec.h" +#include "sound/audiostream.h" +#include "sound/mixer.h" + +namespace Graphics { + +#define UNKNOWN_HEADER(a) error("Unknown header found -- \'%s\'", tag2str(a)) +#define AUDIO_RATE (_audsHeader.rate / _audsHeader.scale) + +// IDs used throughout the AVI files +// that will be handled by this player +#define ID_RIFF MKID_BE('RIFF') +#define ID_AVI MKID_BE('AVI ') +#define ID_LIST MKID_BE('LIST') +#define ID_HDRL MKID_BE('hdrl') +#define ID_AVIH MKID_BE('avih') +#define ID_STRL MKID_BE('strl') +#define ID_STRH MKID_BE('strh') +#define ID_VIDS MKID_BE('vids') +#define ID_AUDS MKID_BE('auds') +#define ID_MIDS MKID_BE('mids') +#define ID_TXTS MKID_BE('txts') +#define ID_JUNK MKID_BE('JUNK') +#define ID_STRF MKID_BE('strf') +#define ID_MOVI MKID_BE('movi') +#define ID_REC MKID_BE('rec ') +#define ID_VEDT MKID_BE('vedt') +#define ID_IDX1 MKID_BE('idx1') +#define ID_STRD MKID_BE('strd') +//#define ID_INFO MKID_BE('INFO') + +// Codec tags +#define ID_RLE MKID_BE('RLE ') +#define ID_CRAM MKID_BE('CRAM') +#define ID_MSVC MKID_BE('msvc') +#define ID_WHAM MKID_BE('WHAM') +#define ID_CVID MKID_BE('cvid') +#define ID_IV32 MKID_BE('iv32') + +struct BITMAPINFOHEADER { + uint32 size; + uint32 width; + uint32 height; + uint16 planes; + uint16 bitCount; + uint32 compression; + uint32 sizeImage; + uint32 xPelsPerMeter; + uint32 yPelsPerMeter; + uint32 clrUsed; + uint32 clrImportant; +}; + +struct WAVEFORMAT { + uint16 tag; + uint16 channels; + uint32 samplesPerSec; + uint32 avgBytesPerSec; + uint16 blockAlign; +}; + +struct PCMWAVEFORMAT : public WAVEFORMAT { + uint16 size; +}; + +struct WAVEFORMATEX : public WAVEFORMAT { + uint16 bitsPerSample; + uint16 size; +}; + +struct AVIOLDINDEX { + uint32 size; + struct Index { + uint32 id; + uint32 flags; + uint32 offset; + uint32 size; + } *indices; +}; + +// Index Flags +enum IndexFlags { + AVIIF_INDEX = 0x10 +}; + +enum WaveFormats { + AVI_WAVE_INVALIDFORMAT = 0, + AVI_WAVE_FORMAT_PCM = 1, + AVI_WAVE_FORMAT_1M08 = 1, + AVI_WAVE_FORMAT_1S08 = 2, + AVI_WAVE_FORMAT_1M16 = 4, + AVI_WAVE_FORMAT_1S16 = 8, + AVI_WAVE_FORMAT_2M08 = 16, + AVI_WAVE_FORMAT_2S08 = 32, + AVI_WAVE_FORMAT_2M16 = 64, + AVI_WAVE_FORMAT_2S16 = 128, + AVI_WAVE_FORMAT_4M08 = 256, + AVI_WAVE_FORMAT_4S08 = 512, + AVI_WAVE_FORMAT_4M16 = 1024, + AVI_WAVE_FORMAT_4S16 = 2048 +}; + +struct AVIHeader { + uint32 size; + uint32 microSecondsPerFrame; + uint32 maxBytesPerSecond; + uint32 padding; + uint32 flags; + uint32 totalFrames; + uint32 initialFrames; + uint32 streams; + uint32 bufferSize; + uint32 width; + uint32 height; +}; + +// Flags from the AVIHeader +enum AviFlags { + AVIF_HASINDEX = 0x00000010, + AVIF_MUSTUSEINDEX = 0x00000020, + AVIF_ISINTERLEAVED = 0x00000100, + AVIF_TRUSTCKTYPE = 0x00000800, + AVIF_WASCAPTUREFILE = 0x00010000, + AVIF_WASCOPYRIGHTED = 0x00020000 +}; + +struct AVIStreamHeader { + uint32 size; + uint32 streamType; + uint32 streamHandler; + uint32 flags; + uint16 priority; + uint16 language; + uint32 initialFrames; + uint32 scale; + uint32 rate; + uint32 start; + uint32 length; + uint32 bufferSize; + uint32 quality; + uint32 sampleSize; + Common::Rect frame; +}; + +class AviDecoder : public VideoDecoder { +public: + AviDecoder(Audio::Mixer *mixer); + virtual ~AviDecoder(); + + /** + * Load an AVI video file + * @param filename the filename to load + */ + bool loadFile(const char *fileName); + + /** + * Close an AVI video file + */ + void closeFile(); + + bool decodeNextFrame(); + + int32 getFrameRate() { return _vidsHeader.rate / _vidsHeader.scale; } +private: + Audio::Mixer *_mixer; + BITMAPINFOHEADER _bmInfo; + PCMWAVEFORMAT _wvInfo; + AVIOLDINDEX _ixInfo; + AVIHeader _header; + AVIStreamHeader _vidsHeader; + AVIStreamHeader _audsHeader; + byte _palette[3 * 256]; + + bool _decodedHeader; + + Codec *_videoCodec; + Codec *createCodec(); + + void runHandle(uint32 tag); + void handleList(); + void handleStreamHeader(); + void handlePalChange(); + + Audio::SoundHandle *_audHandle; + Audio::AppendableAudioStream *_audStream; + Audio::AppendableAudioStream *createAudioStream(); + + // Helper functions + static byte char2num(char c); + static byte getStreamNum(uint32 tag); + static uint16 getStreamType(uint32 tag); + + Surface *getNextFrame(); +}; + +} // End of namespace Graphics + +#endif diff --git a/graphics/video/avi_player.cpp b/graphics/video/avi_player.cpp deleted file mode 100644 index 3385aa6149..0000000000 --- a/graphics/video/avi_player.cpp +++ /dev/null @@ -1,383 +0,0 @@ -/* 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. - * - * $URL$ - * $Id$ - * - */ - -#include "common/endian.h" -#include "common/file.h" -#include "common/stream.h" -#include "common/events.h" - -#include "sound/audiostream.h" -#include "sound/mixer.h" - -#include "graphics/video/avi_player.h" - -// Codecs -#include "graphics/video/msvideo1.h" - -namespace Graphics { - -AVIPlayer::AVIPlayer(OSystem* syst) : _system(syst) { - _videoCodec = NULL; - _palette = NULL; - _decodedHeader = false; - _filesize = 0; - _curFrame = 0; - _audStream = NULL; - _dirtyPalette = false; - _stream = NULL; - _audHandle = new Audio::SoundHandle(); - memset(&_wvInfo, 0, sizeof(PCMWAVEFORMAT)); - memset(&_bmInfo, 0, sizeof(BITMAPINFOHEADER)); - memset(&_vidsHeader, 0, sizeof(AVIStreamHeader)); - memset(&_audsHeader, 0, sizeof(AVIStreamHeader)); - memset(&_ixInfo, 0, sizeof(AVIOLDINDEX)); -} - -AVIPlayer::~AVIPlayer() { - close(); - delete _audHandle; -} - -void AVIPlayer::runHandle(uint32 tag) { - assert (_stream); - if (_stream->eos()) - return; - - debug (3, "Decoding tag %s", tag2str(tag)); - - switch (tag) { - case ID_RIFF: - _filesize = _stream->readUint32LE(); - assert(_stream->readUint32BE() == ID_AVI); - break; - case ID_LIST: - handleList(); - break; - case ID_AVIH: - _header.size = _stream->readUint32LE(); - _header.microSecondsPerFrame = _stream->readUint32LE(); - _header.maxBytesPerSecond = _stream->readUint32LE(); - _header.padding = _stream->readUint32LE(); - _header.flags = _stream->readUint32LE(); - _header.totalFrames = _stream->readUint32LE(); - _header.initialFrames = _stream->readUint32LE(); - _header.streams = _stream->readUint32LE(); - _header.bufferSize = _stream->readUint32LE(); - _header.width = _stream->readUint32LE(); - _header.height = _stream->readUint32LE(); - //Ignore 16 bytes of reserved data - _stream->skip(16); - break; - case ID_STRH: - handleStreamHeader(); - break; - case ID_STRD: // Extra stream info, safe to ignore - case ID_VEDT: // Unknown, safe to ignore - case ID_JUNK: // Alignment bytes, should be ignored - { - uint32 junkSize = _stream->readUint32LE(); - _stream->skip(junkSize + (junkSize & 1)); // Alignment - } break; - case ID_IDX1: - _ixInfo.size = _stream->readUint32LE(); - _ixInfo.indices = new AVIOLDINDEX::Index[_ixInfo.size / 16]; - debug (0, "%d Indices", (_ixInfo.size / 16)); - for (uint32 i = 0; i < (_ixInfo.size / 16); i++) { - _ixInfo.indices[i].id = _stream->readUint32BE(); - _ixInfo.indices[i].flags = _stream->readUint32LE(); - _ixInfo.indices[i].offset = _stream->readUint32LE(); - _ixInfo.indices[i].size = _stream->readUint32LE(); - debug (0, "Index %d == Tag \'%s\', Offset = %d, Size = %d", i, tag2str(_ixInfo.indices[i].id), _ixInfo.indices[i].offset, _ixInfo.indices[i].size); - } - break; - default: error ("Unknown tag \'%s\' found", tag2str(tag)); - } -} - -void AVIPlayer::handleList() { - uint32 listSize = _stream->readUint32LE() - 4; // Subtract away listType's 4 bytes - uint32 listType = _stream->readUint32BE(); - uint32 curPos = _stream->pos(); - - debug (0, "Found LIST of type %s", tag2str(listType)); - - while ((_stream->pos() - curPos) < listSize) - runHandle(_stream->readUint32BE()); - - // We now have all the header data - if (listType == ID_HDRL) - _decodedHeader = true; -} - -void AVIPlayer::handleStreamHeader() { - AVIStreamHeader sHeader; - sHeader.size = _stream->readUint32LE(); - sHeader.streamType = _stream->readUint32BE(); - if (sHeader.streamType == ID_MIDS || sHeader.streamType == ID_TXTS) - error ("Unhandled MIDI/Text stream"); - sHeader.streamHandler = _stream->readUint32BE(); - sHeader.flags = _stream->readUint32LE(); - sHeader.priority = _stream->readUint16LE(); - sHeader.language = _stream->readUint16LE(); - sHeader.initialFrames = _stream->readUint32LE(); - sHeader.scale = _stream->readUint32LE(); - sHeader.rate = _stream->readUint32LE(); - sHeader.start = _stream->readUint32LE(); - sHeader.length = _stream->readUint32LE(); - sHeader.bufferSize = _stream->readUint32LE(); - sHeader.quality = _stream->readUint32LE(); - sHeader.sampleSize = _stream->readUint32LE(); - sHeader.frame.left = _stream->readSint16LE(); - sHeader.frame.top = _stream->readSint16LE(); - sHeader.frame.right = _stream->readSint16LE(); - sHeader.frame.bottom = _stream->readSint16LE(); - - assert (_stream->readUint32BE() == ID_STRF); - /* uint32 strfSize = */ _stream->readUint32LE(); - - if (sHeader.streamType == ID_VIDS) { - _vidsHeader = sHeader; - - _bmInfo.size = _stream->readUint32LE(); - _bmInfo.width = _stream->readUint32LE(); - assert (_header.width == _bmInfo.width); - _bmInfo.height = _stream->readUint32LE(); - assert (_header.height == _bmInfo.height); - _bmInfo.planes = _stream->readUint16LE(); - _bmInfo.bitCount = _stream->readUint16LE(); - _bmInfo.compression = _stream->readUint32BE(); - _bmInfo.sizeImage = _stream->readUint32LE(); - _bmInfo.xPelsPerMeter = _stream->readUint32LE(); - _bmInfo.yPelsPerMeter = _stream->readUint32LE(); - _bmInfo.clrUsed = _stream->readUint32LE(); - _bmInfo.clrImportant = _stream->readUint32LE(); - - if (_bmInfo.bitCount == 8) { - if (_bmInfo.clrUsed == 0) - _bmInfo.clrUsed = 256; - - _palette = (byte *)malloc(256 * 4); - - for (uint32 i = 0; i < _bmInfo.clrUsed; i++) { - _palette[i * 4 + 2] = _stream->readByte(); - _palette[i * 4 + 1] = _stream->readByte(); - _palette[i * 4] = _stream->readByte(); - _palette[i * 4 + 3] = _stream->readByte(); - } - - // Assign the palette to be dirty - _dirtyPalette = true; - } - } else if (sHeader.streamType == ID_AUDS) { - _audsHeader = sHeader; - - _wvInfo.tag = _stream->readUint16LE(); - _wvInfo.channels = _stream->readUint16LE(); - _wvInfo.samplesPerSec = _stream->readUint32LE(); - _wvInfo.avgBytesPerSec = _stream->readUint32LE(); - _wvInfo.blockAlign = _stream->readUint16LE(); - _wvInfo.size = _stream->readUint16LE(); - } -} - -bool AVIPlayer::open(Common::String filename) { - Common::File *file = new Common::File(); - - if (!file->open(filename.c_str())) - return false; - - open(file); - - return true; -} - -void AVIPlayer::open(Common::SeekableReadStream *stream) { - close(); - - assert(stream); - _stream = stream; - - _decodedHeader = false; - _curFrame = 0; - - // Read chunks until we have decoded the header - while (!_decodedHeader) - runHandle(_stream->readUint32BE()); - - uint32 nextTag = _stream->readUint32BE(); - - // Throw out any JUNK section - if (nextTag == ID_JUNK) { - runHandle(ID_JUNK); - nextTag = _stream->readUint32BE(); - } - - // Ignore the 'movi' LIST - if (nextTag == ID_LIST) { - _stream->readUint32BE(); // Skip size - if (_stream->readUint32BE() != ID_MOVI) - error ("Expected 'movi' LIST"); - } else - error ("Expected 'movi' LIST"); - - // Now, create the codec - _videoCodec = createCodec(); - - // Initialize the video stuff too - _audStream = createAudioStream(); - if (_audStream) - _system->getMixer()->playInputStream(Audio::Mixer::kPlainSoundType, _audHandle, _audStream); - - debug (0, "Frames = %d, Dimensions = %d x %d", _header.totalFrames, _header.width, _header.height); - debug (0, "Frame Rate = %d", getFrameRate()); - if (_header.flags & AVIF_ISINTERLEAVED) - debug (0, "Sound Rate = %d", AUDIO_RATE); - debug (0, "Video Codec = \'%s\'", tag2str(_vidsHeader.streamHandler)); -} - -void AVIPlayer::close() { - delete _stream; - - // Deinitialize sound - _system->getMixer()->stopHandle(*_audHandle); - - if (_palette) { - free(_palette); - _palette = NULL; - } - - _decodedHeader = false; - _filesize = 0; - - delete _videoCodec; - delete[] _ixInfo.indices; -} - -Surface *AVIPlayer::getNextFrame() { - uint32 nextTag = _stream->readUint32BE(); - - if (nextTag == ID_LIST) { - // A list of audio/video chunks - uint32 listSize = _stream->readUint32LE() - 4; - int32 startPos = _stream->pos(); - - if (_stream->readUint32BE() != ID_REC) - error ("Expected 'rec ' LIST"); - - // Decode chunks in the list and see if we get a frame - Surface *frame = NULL; - while (_stream->pos() < startPos + (int32)listSize) { - Surface *temp = getNextFrame(); - if (temp) - frame = temp; - } - - return frame; - } else if (getStreamType(nextTag) == 'wb') { - // Audio Chunk - uint32 chunkSize = _stream->readUint32LE(); - byte *data = new byte[chunkSize]; - _stream->read(data, chunkSize); - _audStream->queueBuffer(data, chunkSize); - _stream->skip(chunkSize & 1); // Alignment - } else if (getStreamType(nextTag) == 'dc' || getStreamType(nextTag) == 'id') { - // Compressed Frame - _curFrame++; - uint32 chunkSize = _stream->readUint32LE(); - - if (chunkSize == 0) // Keep last frame on screen - return NULL; - - Common::SeekableReadStream *frameData = _stream->readStream(chunkSize); - Graphics::Surface *surface = _videoCodec->decodeImage(frameData); - delete frameData; - _stream->skip(chunkSize & 1); // Alignment - return surface; - } else if (getStreamType(nextTag) == 'pc') { - // Palette Change - _stream->readUint32LE(); // Chunk size, not needed here - byte firstEntry = _stream->readByte(); - uint16 numEntries = _stream->readByte(); - _stream->readUint16LE(); // Reserved - - // 0 entries means all colors are going to be changed - if (numEntries == 0) - numEntries = 256; - - for (uint16 i = firstEntry; i < numEntries + firstEntry; i++) { - _palette[i * 4] = _stream->readByte(); - _palette[i * 4 + 1] = _stream->readByte(); - _palette[i * 4 + 2] = _stream->readByte(); - _stream->readByte(); // Flags that don't serve us any purpose - } - - // Mark the palette as dirty - _dirtyPalette = true; - - // No alignment necessary. It's always even. - } else if (nextTag == ID_JUNK) { - runHandle(ID_JUNK); - } else - error ("Tag = \'%s\'", tag2str(nextTag)); - - return NULL; -} - -Codec *AVIPlayer::createCodec() { - switch (_vidsHeader.streamHandler) { - case ID_CRAM: - case ID_MSVC: - case ID_WHAM: - return new MSVideo1Decoder(_bmInfo.width, _bmInfo.height, _bmInfo.bitCount); - default: - warning ("Unknown/Unhandled compression format \'%s\'", tag2str(_vidsHeader.streamHandler)); - } - - return NULL; -} - -Audio::AppendableAudioStream *AVIPlayer::createAudioStream() { - if (_wvInfo.tag == AVI_WAVE_FORMAT_PCM) - return Audio::makeAppendableAudioStream(AUDIO_RATE, Audio::Mixer::FLAG_UNSIGNED|Audio::Mixer::FLAG_AUTOFREE); - - if (_wvInfo.tag != 0) // No sound - warning ("Unsupported AVI audio format %d", _wvInfo.tag); - - return NULL; -} - -byte AVIPlayer::char2num(char c) { - return (c >= 48 && c <= 57) ? c - 48 : 0; -} - -byte AVIPlayer::getStreamNum(uint32 tag) { - return char2num((char)(tag >> 24)) * 16 + char2num((char)(tag >> 16)); -} - -uint16 AVIPlayer::getStreamType(uint32 tag) { - return tag & 0xffff; -} - -} // End of namespace JMP diff --git a/graphics/video/avi_player.h b/graphics/video/avi_player.h deleted file mode 100644 index 50abe18982..0000000000 --- a/graphics/video/avi_player.h +++ /dev/null @@ -1,241 +0,0 @@ -/* 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. - * - * $URL$ - * $Id$ - * - */ - -#ifndef GRAPHICS_AVI_PLAYER_H -#define GRAPHICS_AVI_PLAYER_H - -#include "common/file.h" -#include "common/system.h" -#include "common/rect.h" -#include "common/util.h" - -#include "sound/audiostream.h" -#include "sound/mixer.h" - -namespace Graphics { - -#define UNKNOWN_HEADER(a) error("Unknown header found -- \'%s\'", tag2str(a)) -#define AUDIO_RATE (_audsHeader.rate / _audsHeader.scale) - -// ID's That are used throughout the AVI files -// that will be handled by this player -#define ID_RIFF MKID_BE('RIFF') -#define ID_AVI MKID_BE('AVI ') -#define ID_LIST MKID_BE('LIST') -#define ID_HDRL MKID_BE('hdrl') -#define ID_AVIH MKID_BE('avih') -#define ID_STRL MKID_BE('strl') -#define ID_STRH MKID_BE('strh') -#define ID_VIDS MKID_BE('vids') -#define ID_AUDS MKID_BE('auds') -#define ID_MIDS MKID_BE('mids') -#define ID_TXTS MKID_BE('txts') -#define ID_JUNK MKID_BE('JUNK') -#define ID_STRF MKID_BE('strf') -#define ID_MOVI MKID_BE('movi') -#define ID_REC MKID_BE('rec ') -#define ID_VEDT MKID_BE('vedt') -#define ID_IDX1 MKID_BE('idx1') -#define ID_STRD MKID_BE('strd') -//#define ID_INFO MKID_BE('INFO') - -// Codec tags -#define ID_RLE MKID_BE('RLE ') -#define ID_CRAM MKID_BE('CRAM') -#define ID_MSVC MKID_BE('msvc') -#define ID_WHAM MKID_BE('WHAM') -#define ID_CVID MKID_BE('cvid') -#define ID_IV32 MKID_BE('iv32') - -struct BITMAPINFOHEADER { - uint32 size; - uint32 width; - uint32 height; - uint16 planes; - uint16 bitCount; - uint32 compression; - uint32 sizeImage; - uint32 xPelsPerMeter; - uint32 yPelsPerMeter; - uint32 clrUsed; - uint32 clrImportant; -}; - -struct WAVEFORMAT { - uint16 tag; - uint16 channels; - uint32 samplesPerSec; - uint32 avgBytesPerSec; - uint16 blockAlign; -}; - -struct PCMWAVEFORMAT : public WAVEFORMAT { - uint16 size; -}; - -struct WAVEFORMATEX : public WAVEFORMAT { - uint16 bitsPerSample; - uint16 size; -}; - -struct AVIOLDINDEX { - uint32 size; - struct Index { - uint32 id; - uint32 flags; - uint32 offset; - uint32 size; - } *indices; -}; - -// Index Flags -enum IndexFlags { - AVIIF_INDEX = 0x10 -}; - -enum WaveFormats { - AVI_WAVE_INVALIDFORMAT = 0, - AVI_WAVE_FORMAT_PCM = 1, - AVI_WAVE_FORMAT_1M08 = 1, - AVI_WAVE_FORMAT_1S08 = 2, - AVI_WAVE_FORMAT_1M16 = 4, - AVI_WAVE_FORMAT_1S16 = 8, - AVI_WAVE_FORMAT_2M08 = 16, - AVI_WAVE_FORMAT_2S08 = 32, - AVI_WAVE_FORMAT_2M16 = 64, - AVI_WAVE_FORMAT_2S16 = 128, - AVI_WAVE_FORMAT_4M08 = 256, - AVI_WAVE_FORMAT_4S08 = 512, - AVI_WAVE_FORMAT_4M16 = 1024, - AVI_WAVE_FORMAT_4S16 = 2048 -}; - -struct AVIHeader { - uint32 size; - uint32 microSecondsPerFrame; - uint32 maxBytesPerSecond; - uint32 padding; - uint32 flags; - uint32 totalFrames; - uint32 initialFrames; - uint32 streams; - uint32 bufferSize; - uint32 width; - uint32 height; -}; - -// Flags from the AVIHeader -enum AviFlags { - AVIF_HASINDEX = 0x00000010, - AVIF_MUSTUSEINDEX = 0x00000020, - AVIF_ISINTERLEAVED = 0x00000100, - AVIF_TRUSTCKTYPE = 0x00000800, - AVIF_WASCAPTUREFILE = 0x00010000, - AVIF_WASCOPYRIGHTED = 0x00020000 -}; - -struct AVIStreamHeader { - uint32 size; - uint32 streamType; - uint32 streamHandler; - uint32 flags; - uint16 priority; - uint16 language; - uint32 initialFrames; - uint32 scale; - uint32 rate; - uint32 start; - uint32 length; - uint32 bufferSize; - uint32 quality; - uint32 sampleSize; - Common::Rect frame; -}; - -class Codec { -public: - Codec() {} - virtual ~Codec() {} - virtual Graphics::Surface *decodeImage(Common::SeekableReadStream *stream) = 0; -}; - -class AVIPlayer { -public: - AVIPlayer(OSystem* syst); - ~AVIPlayer(); - - // Open/Load an AVI video from "filename" - bool open(Common::String filename); - - // Open/Load an AVI video from a stream - void open(Common::SeekableReadStream *stream); - - // Close the current AVI video and release any data - void close(); - - uint32 getFrameRate() { return _vidsHeader.rate / _vidsHeader.scale; } - byte *getPalette() { _dirtyPalette = false; return _palette; } - Surface *getNextFrame(); - bool dirtyPalette() { return _dirtyPalette; } - uint32 getCurFrame() { return _curFrame; } - uint32 getFrameCount() { return _header.totalFrames; } -private: - OSystem *_system; - Common::SeekableReadStream *_stream; - BITMAPINFOHEADER _bmInfo; - PCMWAVEFORMAT _wvInfo; - AVIOLDINDEX _ixInfo; - AVIHeader _header; - AVIStreamHeader _vidsHeader; - AVIStreamHeader _audsHeader; - byte *_palette; - - bool _decodedHeader; - uint32 _curFrame; - bool _dirtyPalette; - - Codec *_videoCodec; - Codec *createCodec(); - - void runHandle(uint32 tag); - void handleList(); - void handleStreamHeader(); - void handlePalChange(); - - Audio::SoundHandle *_audHandle; - Audio::AppendableAudioStream *_audStream; - Audio::AppendableAudioStream *createAudioStream(); - - uint32 _filesize; - - // Helper functions - static byte char2num(char c); - static byte getStreamNum(uint32 tag); - static uint16 getStreamType(uint32 tag); -}; - -} // End of namespace JMP - -#endif diff --git a/graphics/video/codecs/codec.h b/graphics/video/codecs/codec.h new file mode 100644 index 0000000000..2b8fd796dd --- /dev/null +++ b/graphics/video/codecs/codec.h @@ -0,0 +1,43 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef GRAPHICS_CODEC_H +#define GRAPHICS_CODEC_H + +#include "common/stream.h" +#include "graphics/surface.h" + +namespace Graphics { + +class Codec { +public: + Codec() {} + virtual ~Codec() {} + virtual Surface *decodeImage(Common::SeekableReadStream *stream) = 0; +}; + +} // End of namespace Graphics + +#endif diff --git a/graphics/video/codecs/msvideo1.cpp b/graphics/video/codecs/msvideo1.cpp new file mode 100644 index 0000000000..3717487c4f --- /dev/null +++ b/graphics/video/codecs/msvideo1.cpp @@ -0,0 +1,139 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + + // Based off ffmpeg's msvideo.cpp + +#include "graphics/video/codecs/msvideo1.h" + +namespace Graphics { + +#define CHECK_STREAM_PTR(n) \ + if ((stream->pos() + n) > stream->size() ) { \ + warning ("MS Video-1: Stream out of bounds (%d >= %d)", stream->pos() + n, stream->size()); \ + return; \ + } + +MSVideo1Decoder::MSVideo1Decoder(uint16 width, uint16 height, byte bitsPerPixel) : Codec() { + _surface = new Graphics::Surface(); + _surface->create(width, height, (bitsPerPixel == 8) ? 1 : 2); + _bitsPerPixel = bitsPerPixel; +} + +MSVideo1Decoder::~MSVideo1Decoder() { + _surface->free(); + delete _surface; +} + +void MSVideo1Decoder::decode8(Common::SeekableReadStream *stream) { + byte colors[8]; + byte *pixels = (byte *)_surface->pixels; + uint16 stride = _surface->w; + + int skipBlocks = 0; + uint16 blocks_wide = _surface->w / 4; + uint16 blocks_high = _surface->h / 4; + uint32 totalBlocks = blocks_wide * blocks_high; + uint32 blockInc = 4; + uint16 rowDec = stride + 4; + + for (uint16 block_y = blocks_high; block_y > 0; block_y--) { + uint32 blockPtr = (block_y * 4 - 1) * stride; + for (uint16 block_x = blocks_wide; block_x > 0; block_x--) { + // check if this block should be skipped + if (skipBlocks > 0) { + blockPtr += blockInc; + skipBlocks--; + totalBlocks--; + continue; + } + + uint32 pixelPtr = blockPtr; + + /* get the next two bytes in the encoded data stream */ + CHECK_STREAM_PTR(2); + byte byte_a = stream->readByte(); + byte byte_b = stream->readByte(); + + /* check if the decode is finished */ + if (byte_a == 0 && byte_b == 0 && totalBlocks == 0) { + return; + } else if ((byte_b & 0xFC) == 0x84) { + // skip code, but don't count the current block + skipBlocks = ((byte_b - 0x84) << 8) + byte_a - 1; + } else if (byte_b < 0x80) { + // 2-color encoding + uint16 flags = (byte_b << 8) | byte_a; + + CHECK_STREAM_PTR(2); + colors[0] = stream->readByte(); + colors[1] = stream->readByte(); + + for (byte pixel_y = 0; pixel_y < 4; pixel_y++) { + for (byte pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1) + pixels[pixelPtr++] = colors[(flags & 0x1) ^ 1]; + pixelPtr -= rowDec; + } + } else if (byte_b >= 0x90) { + // 8-color encoding + uint16 flags = (byte_b << 8) | byte_a; + + CHECK_STREAM_PTR(8); + for (byte i = 0; i < 8; i++) + colors[i] = stream->readByte(); + + for (byte pixel_y = 0; pixel_y < 4; pixel_y++) { + for (byte pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1) + pixels[pixelPtr++] = colors[((pixel_y & 0x2) << 1) + (pixel_x & 0x2) + ((flags & 0x1) ^ 1)]; + pixelPtr -= rowDec; + } + } else { + // 1-color encoding + colors[0] = byte_a; + + for (byte pixel_y = 0; pixel_y < 4; pixel_y++) { + for (byte pixel_x = 0; pixel_x < 4; pixel_x++) + pixels[pixelPtr++] = colors[0]; + pixelPtr -= rowDec; + } + } + + blockPtr += blockInc; + totalBlocks--; + } + } +} + +Graphics::Surface *MSVideo1Decoder::decodeImage(Common::SeekableReadStream *stream) { + if (_bitsPerPixel == 8) + decode8(stream); + else { + // decode16(stream); + error ("Unhandled MS Video-1 16bpp encoding"); + } + + return _surface; +} + +} // End of namespace JMP diff --git a/graphics/video/codecs/msvideo1.h b/graphics/video/codecs/msvideo1.h new file mode 100644 index 0000000000..7950ceb1f1 --- /dev/null +++ b/graphics/video/codecs/msvideo1.h @@ -0,0 +1,51 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef GRAPHICS_MSVIDEO1_H +#define GRAPHICS_MSVIDEO1_H + +#include "graphics/video/codecs/codec.h" + +namespace Graphics { + +class MSVideo1Decoder : public Codec { +public: + MSVideo1Decoder(uint16 width, uint16 height, byte bitsPerPixel); + ~MSVideo1Decoder(); + + Surface *decodeImage(Common::SeekableReadStream *stream); + +private: + byte _bitsPerPixel; + + Surface *_surface; + + void decode8(Common::SeekableReadStream *stream); + //void decode16(Common::SeekableReadStream *stream); +}; + +} // End of namespace Graphics + +#endif diff --git a/graphics/video/msvideo1.cpp b/graphics/video/msvideo1.cpp deleted file mode 100644 index 9e57f9a4ab..0000000000 --- a/graphics/video/msvideo1.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/* 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. - * - * $URL$ - * $Id$ - * - */ - - // Based off ffmpeg's msvideo.cpp - -#include "graphics/video/msvideo1.h" - -namespace Graphics { - -#define CHECK_STREAM_PTR(n) \ - if ((stream->pos() + n) > stream->size() ) { \ - warning ("MS Video-1: Stream out of bounds (%d >= %d)", stream->pos() + n, stream->size()); \ - return; \ - } - -MSVideo1Decoder::MSVideo1Decoder(uint16 width, uint16 height, byte bitsPerPixel) : Codec() { - _surface = new Graphics::Surface(); - _surface->create(width, height, (bitsPerPixel == 8) ? 1 : 2); - _bitsPerPixel = bitsPerPixel; -} - -MSVideo1Decoder::~MSVideo1Decoder() { - _surface->free(); - delete _surface; -} - -void MSVideo1Decoder::decode8(Common::SeekableReadStream *stream) { - byte colors[8]; - byte *pixels = (byte *)_surface->pixels; - uint16 stride = _surface->w; - - int skipBlocks = 0; - uint16 blocks_wide = _surface->w / 4; - uint16 blocks_high = _surface->h / 4; - uint32 totalBlocks = blocks_wide * blocks_high; - uint32 blockInc = 4; - uint16 rowDec = stride + 4; - - for (uint16 block_y = blocks_high; block_y > 0; block_y--) { - uint32 blockPtr = (block_y * 4 - 1) * stride; - for (uint16 block_x = blocks_wide; block_x > 0; block_x--) { - // check if this block should be skipped - if (skipBlocks > 0) { - blockPtr += blockInc; - skipBlocks--; - totalBlocks--; - continue; - } - - uint32 pixelPtr = blockPtr; - - /* get the next two bytes in the encoded data stream */ - CHECK_STREAM_PTR(2); - byte byte_a = stream->readByte(); - byte byte_b = stream->readByte(); - - /* check if the decode is finished */ - if (byte_a == 0 && byte_b == 0 && totalBlocks == 0) { - return; - } else if ((byte_b & 0xFC) == 0x84) { - // skip code, but don't count the current block - skipBlocks = ((byte_b - 0x84) << 8) + byte_a - 1; - } else if (byte_b < 0x80) { - // 2-color encoding - uint16 flags = (byte_b << 8) | byte_a; - - CHECK_STREAM_PTR(2); - colors[0] = stream->readByte(); - colors[1] = stream->readByte(); - - for (byte pixel_y = 0; pixel_y < 4; pixel_y++) { - for (byte pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1) - pixels[pixelPtr++] = colors[(flags & 0x1) ^ 1]; - pixelPtr -= rowDec; - } - } else if (byte_b >= 0x90) { - // 8-color encoding - uint16 flags = (byte_b << 8) | byte_a; - - CHECK_STREAM_PTR(8); - for (byte i = 0; i < 8; i++) - colors[i] = stream->readByte(); - - for (byte pixel_y = 0; pixel_y < 4; pixel_y++) { - for (byte pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1) - pixels[pixelPtr++] = colors[((pixel_y & 0x2) << 1) + (pixel_x & 0x2) + ((flags & 0x1) ^ 1)]; - pixelPtr -= rowDec; - } - } else { - // 1-color encoding - colors[0] = byte_a; - - for (byte pixel_y = 0; pixel_y < 4; pixel_y++) { - for (byte pixel_x = 0; pixel_x < 4; pixel_x++) - pixels[pixelPtr++] = colors[0]; - pixelPtr -= rowDec; - } - } - - blockPtr += blockInc; - totalBlocks--; - } - } -} - -Graphics::Surface *MSVideo1Decoder::decodeImage(Common::SeekableReadStream *stream) { - if (_bitsPerPixel == 8) - decode8(stream); - else { - // decode16(stream); - error ("Unhandled MS Video-1 16bpp encoding"); - } - - return _surface; -} - -} // End of namespace JMP diff --git a/graphics/video/msvideo1.h b/graphics/video/msvideo1.h deleted file mode 100644 index 676bc72c9f..0000000000 --- a/graphics/video/msvideo1.h +++ /dev/null @@ -1,52 +0,0 @@ -/* 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. - * - * $URL$ - * $Id$ - * - */ - -#ifndef GRAPHICS_MSVIDEO1_H -#define GRAPHICS_MSVIDEO1_H - -#include "graphics/video/avi_player.h" -#include "graphics/surface.h" - -namespace Graphics { - -class MSVideo1Decoder : public Codec { -public: - MSVideo1Decoder(uint16 width, uint16 height, byte bitsPerPixel); - ~MSVideo1Decoder(); - - Surface *decodeImage(Common::SeekableReadStream *stream); - -private: - byte _bitsPerPixel; - - Surface *_surface; - - void decode8(Common::SeekableReadStream *stream); - //void decode16(Common::SeekableReadStream *stream); -}; - -} - -#endif -- cgit v1.2.3