diff options
Diffstat (limited to 'video/avi_decoder.cpp')
-rw-r--r-- | video/avi_decoder.cpp | 589 |
1 files changed, 482 insertions, 107 deletions
diff --git a/video/avi_decoder.cpp b/video/avi_decoder.cpp index 6fe9c773b8..36fe83fa19 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,11 @@ 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_INFO MKTAG('I','N','F','O') +#define ID_ISFT MKTAG('I','S','F','T') +#define ID_DISP MKTAG('D','I','S','P') +#define ID_PRMI MKTAG('P','R','M','I') +#define ID_STRN MKTAG('s','t','r','n') // Codec tags #define ID_RLE MKTAG('R','L','E',' ') @@ -75,49 +79,63 @@ 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); - return (c >= 'a' && c <= 'f') ? c - 'a' + 10 : c - '0'; +// Stream Types +enum { + kStreamTypePaletteChange = MKTAG16('p', 'c'), + kStreamTypeRawVideo = MKTAG16('d', 'b'), + kStreamTypeAudio = MKTAG16('w', 'b') +}; + + +AVIDecoder::AVIDecoder(Audio::Mixer::SoundType soundType) : _frameRateOverride(0), _soundType(soundType) { + initCommon(); } -static byte getStreamIndex(uint32 tag) { - return char2num((tag >> 24) & 0xFF) << 4 | char2num((tag >> 16) & 0xFF); +AVIDecoder::AVIDecoder(const Common::Rational &frameRateOverride, Audio::Mixer::SoundType soundType) + : _frameRateOverride(frameRateOverride), _soundType(soundType) { + initCommon(); +} + +AVIDecoder::~AVIDecoder() { + close(); } -static uint16 getStreamType(uint32 tag) { - return tag & 0xffff; +AVIDecoder::AVIAudioTrack *AVIDecoder::createAudioTrack(AVIStreamHeader sHeader, PCMWaveFormat wvInfo) { + return new AVIAudioTrack(sHeader, wvInfo, _soundType); } -AVIDecoder::AVIDecoder(Audio::Mixer::SoundType soundType) : _soundType(soundType) { +void AVIDecoder::initCommon() { _decodedHeader = false; + _foundMovieList = false; + _movieListStart = 0; + _movieListEnd = 0; _fileStream = 0; - memset(&_ixInfo, 0, sizeof(_ixInfo)); memset(&_header, 0, sizeof(_header)); } -AVIDecoder::~AVIDecoder() { - close(); +bool AVIDecoder::isSeekable() const { + // Only videos with an index can seek + // Anyone else who wants to seek is crazy. + return isVideoLoaded() && !_indexEntries.empty(); } -void AVIDecoder::runHandle(uint32 tag) { - assert(_fileStream); +bool AVIDecoder::parseNextChunk() { + uint32 tag = _fileStream->readUint32BE(); + uint32 size = _fileStream->readUint32LE(); + if (_fileStream->eos()) - return; + return false; 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(); + handleList(size); break; case ID_AVIH: - _header.size = _fileStream->readUint32LE(); + _header.size = size; _header.microSecondsPerFrame = _fileStream->readUint32LE(); _header.maxBytesPerSecond = _fileStream->readUint32LE(); _header.padding = _fileStream->readUint32LE(); @@ -132,50 +150,67 @@ void AVIDecoder::runHandle(uint32 tag) { _fileStream->skip(16); break; case ID_STRH: - handleStreamHeader(); + handleStreamHeader(size); 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_ISFT: // Metadata, safe to ignore + case ID_DISP: // Metadata, should be safe to ignore + case ID_STRN: // Metadata, safe to ignore + skipChunk(size); + break; case ID_IDX1: - _ixInfo.size = _fileStream->readUint32LE(); - _ixInfo.indices = new OldIndex::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); - } + readOldIndex(size); break; default: error("Unknown tag \'%s\' found", tag2str(tag)); } + + return true; } -void AVIDecoder::handleList() { - uint32 listSize = _fileStream->readUint32LE() - 4; // Subtract away listType's 4 bytes +void AVIDecoder::skipChunk(uint32 size) { + // Make sure we're aligned on a word boundary + _fileStream->skip(size + (size & 1)); +} + +void AVIDecoder::handleList(uint32 listSize) { uint32 listType = _fileStream->readUint32BE(); + listSize -= 4; // Subtract away listType's 4 bytes 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) + switch (listType) { + case ID_MOVI: // Movie List + // We found the movie block + _foundMovieList = true; + _movieListStart = curPos; + _movieListEnd = _movieListStart + listSize + (listSize & 1); + _fileStream->skip(listSize); + return; + case ID_HDRL: // Header List + // Mark the header as decoded _decodedHeader = true; + break; + case ID_INFO: // Metadata + case ID_PRMI: // Unknown metadata, should be safe to ignore + // Ignore metadata + _fileStream->skip(listSize); + return; + case ID_STRL: // Stream list + default: // (Just hope we can parse it!) + break; + } + + while ((_fileStream->pos() - curPos) < listSize) + parseNextChunk(); } -void AVIDecoder::handleStreamHeader() { +void AVIDecoder::handleStreamHeader(uint32 size) { AVIStreamHeader sHeader; - sHeader.size = _fileStream->readUint32LE(); + sHeader.size = size; sHeader.streamType = _fileStream->readUint32BE(); if (sHeader.streamType == ID_MIDS || sHeader.streamType == ID_TXTS) @@ -203,6 +238,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(); @@ -222,21 +262,22 @@ void AVIDecoder::handleStreamHeader() { if (sHeader.streamHandler == 0) sHeader.streamHandler = bmInfo.compression; - AVIVideoTrack *track = new AVIVideoTrack(_header.totalFrames, sHeader, bmInfo); + byte *initialPalette = 0; if (bmInfo.bitCount == 8) { - byte *palette = const_cast<byte *>(track->getPalette()); + initialPalette = new byte[256 * 3]; + memset(initialPalette, 0, 256 * 3); + + byte *palette = initialPalette; 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(); _fileStream->readByte(); } - - track->markPaletteDirty(); } - addTrack(track); + addTrack(new AVIVideoTrack(_header.totalFrames, sHeader, bmInfo, initialPalette)); } else if (sHeader.streamType == ID_AUDS) { PCMWaveFormat wvInfo; wvInfo.tag = _fileStream->readUint16LE(); @@ -251,7 +292,7 @@ void AVIDecoder::handleStreamHeader() { if (wvInfo.channels == 2) sHeader.sampleSize /= 2; - addTrack(new AVIAudioTrack(sHeader, wvInfo, _soundType)); + addTrack(createAudioTrack(sHeader, wvInfo)); } // Ensure that we're at the end of the chunk @@ -261,30 +302,41 @@ void AVIDecoder::handleStreamHeader() { bool AVIDecoder::loadStream(Common::SeekableReadStream *stream) { close(); - _fileStream = stream; - _decodedHeader = false; + uint32 riffTag = stream->readUint32BE(); + if (riffTag != ID_RIFF) { + warning("Failed to find RIFF header"); + return false; + } - // Read chunks until we have decoded the header - while (!_decodedHeader) - runHandle(_fileStream->readUint32BE()); + /* uint32 fileSize = */ stream->readUint32LE(); + uint32 riffType = stream->readUint32BE(); - uint32 nextTag = _fileStream->readUint32BE(); + if (riffType != ID_AVI) { + warning("RIFF not an AVI file"); + return false; + } - // Throw out any JUNK section - if (nextTag == ID_JUNK) { - runHandle(ID_JUNK); - nextTag = _fileStream->readUint32BE(); + _fileStream = stream; + + // Go through all chunks in the file + while (parseNextChunk()) + ; + + if (!_decodedHeader) { + warning("Failed to parse AVI header"); + close(); + 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"); + if (!_foundMovieList) { + warning("Failed to find 'MOVI' list"); + close(); + return false; } + // Seek back to the start of the MOVI list + _fileStream->seek(_movieListStart); + return true; } @@ -294,33 +346,46 @@ void AVIDecoder::close() { delete _fileStream; _fileStream = 0; _decodedHeader = false; + _foundMovieList = false; + _movieListStart = 0; + _movieListEnd = 0; - delete[] _ixInfo.indices; - memset(&_ixInfo, 0, sizeof(_ixInfo)); + _indexEntries.clear(); memset(&_header, 0, sizeof(_header)); } void AVIDecoder::readNextPacket() { + if ((uint32)_fileStream->pos() >= _movieListEnd) { + // Ugh, reached the end premature. + forceVideoEnd(); + return; + } + uint32 nextTag = _fileStream->readUint32BE(); + uint32 size = _fileStream->readUint32LE(); - if (_fileStream->eos()) + if (_fileStream->eos()) { + // Also premature end. + forceVideoEnd(); return; + } 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"); + size -= 4; // subtract list type + // Decode chunks in the list - while (_fileStream->pos() < startPos + (int32)listSize) + while (_fileStream->pos() < startPos + (int32)size) readNextPacket(); return; } else if (nextTag == ID_JUNK || nextTag == ID_IDX1) { - runHandle(nextTag); + skipChunk(size); return; } @@ -329,16 +394,15 @@ void AVIDecoder::readNextPacket() { if (!track) error("Cannot get track from tag '%s'", tag2str(nextTag)); - uint32 chunkSize = _fileStream->readUint32LE(); Common::SeekableReadStream *chunk = 0; - if (chunkSize != 0) { - chunk = _fileStream->readStream(chunkSize); - _fileStream->skip(chunkSize & 1); + if (size != 0) { + chunk = _fileStream->readStream(size); + _fileStream->skip(size & 1); } if (track->getTrackType() == Track::kTrackTypeAudio) { - if (getStreamType(nextTag) != MKTAG16('w', 'b')) + if (getStreamType(nextTag) != kStreamTypeAudio) error("Invalid audio track tag '%s'", tag2str(nextTag)); assert(chunk); @@ -346,29 +410,10 @@ void AVIDecoder::readNextPacket() { } else { AVIVideoTrack *videoTrack = (AVIVideoTrack *)track; - if (getStreamType(nextTag) == MKTAG16('p', 'c')) { + if (getStreamType(nextTag) == kStreamTypePaletteChange) { // Palette Change - assert(chunk); - byte firstEntry = chunk->readByte(); - uint16 numEntries = chunk->readByte(); - chunk->readUint16LE(); // Reserved - - // 0 entries means all colors are going to be changed - if (numEntries == 0) - numEntries = 256; - - byte *palette = const_cast<byte *>(videoTrack->getPalette()); - - for (uint16 i = firstEntry; i < numEntries + firstEntry; i++) { - palette[i * 3] = chunk->readByte(); - palette[i * 3 + 1] = chunk->readByte(); - palette[i * 3 + 2] = chunk->readByte(); - chunk->readByte(); // Flags that don't serve us any purpose - } - - delete chunk; - videoTrack->markPaletteDirty(); - } else if (getStreamType(nextTag) == MKTAG16('d', 'b')) { + videoTrack->loadPaletteFromChunk(chunk); + } else if (getStreamType(nextTag) == kStreamTypeRawVideo) { // TODO: Check if this really is uncompressed. Many videos // falsely put compressed data in here. error("Uncompressed AVI frame found"); @@ -379,17 +424,273 @@ void AVIDecoder::readNextPacket() { } } -AVIDecoder::AVIVideoTrack::AVIVideoTrack(int frameCount, const AVIStreamHeader &streamHeader, const BitmapInfoHeader &bitmapInfoHeader) - : _frameCount(frameCount), _vidsHeader(streamHeader), _bmInfo(bitmapInfoHeader) { - memset(_palette, 0, sizeof(_palette)); +bool AVIDecoder::rewind() { + if (!VideoDecoder::rewind()) + return false; + + _fileStream->seek(_movieListStart); + return true; +} + +bool AVIDecoder::seekIntern(const Audio::Timestamp &time) { + // Can't seek beyond the end + if (time > getDuration()) + return false; + + // Track down our video track (optionally audio too). + // We only support seeking with one track right now. + AVIVideoTrack *videoTrack = 0; + AVIAudioTrack *audioTrack = 0; + int videoIndex = -1; + int audioIndex = -1; + uint trackID = 0; + + for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++, trackID++) { + if ((*it)->getTrackType() == Track::kTrackTypeVideo) { + if (videoTrack) { + // Already have one + // -> Not supported + return false; + } + + videoTrack = (AVIVideoTrack *)*it; + videoIndex = trackID; + } else if ((*it)->getTrackType() == Track::kTrackTypeAudio) { + if (audioTrack) { + // Already have one + // -> Not supported + return false; + } + + audioTrack = (AVIAudioTrack *)*it; + audioIndex = trackID; + } + } + + // Need a video track to go forwards + // If there isn't a video track, why would anyone be using AVI then? + if (!videoTrack) + return false; + + // If we seek directly to the end, just mark the tracks as over + if (time == getDuration()) { + videoTrack->setCurFrame(videoTrack->getFrameCount() - 1); + + if (audioTrack) + audioTrack->resetStream(); + + return true; + } + + // Get the frame we should be on at this time + uint frame = videoTrack->getFrameAtTime(time); + + // Reset any palette, if necessary + videoTrack->useInitialPalette(); + + int lastKeyFrame = -1; + int frameIndex = -1; + int lastRecord = -1; + uint curFrame = 0; + + // Go through and figure out where we should be + // If there's a palette, we need to find the palette too + for (uint32 i = 0; i < _indexEntries.size(); i++) { + const OldIndex &index = _indexEntries[i]; + + if (index.id == ID_REC) { + // Keep track of any records we find + lastRecord = i; + } else { + if (getStreamIndex(index.id) != videoIndex) + continue; + + uint16 streamType = getStreamType(index.id); + + if (streamType == kStreamTypePaletteChange) { + // We need to handle any palette change we see since there's no + // flag to tell if this is a "key" palette. + // Decode the palette + _fileStream->seek(_indexEntries[i].offset + 8); + Common::SeekableReadStream *chunk = 0; + + if (_indexEntries[i].size != 0) + chunk = _fileStream->readStream(_indexEntries[i].size); + + videoTrack->loadPaletteFromChunk(chunk); + } else { + // Check to see if this is a keyframe + // The first frame has to be a keyframe + if ((_indexEntries[i].flags & AVIIF_INDEX) || curFrame == 0) + lastKeyFrame = i; + + // Did we find the target frame? + if (frame == curFrame) { + frameIndex = i; + break; + } + + curFrame++; + } + } + } + + if (frameIndex < 0) // This shouldn't happen. + return false; + + if (audioTrack) { + // We need to find where the start of audio should be. + // Which is exactly 'initialFrames' audio chunks back from where + // our found frame is. + + // Recreate the audio stream + audioTrack->resetStream(); + + uint framesNeeded = _header.initialFrames; + uint startAudioChunk = 0; + int startAudioSearch = (lastRecord < 0) ? (frameIndex - 1) : (lastRecord - 1); + + for (int i = startAudioSearch; i >= 0; i--) { + if (getStreamIndex(_indexEntries[i].id) != audioIndex) + continue; + + assert(getStreamType(_indexEntries[i].id) == kStreamTypeAudio); + + framesNeeded--; + + if (framesNeeded == 0) { + startAudioChunk = i; + break; + } + } + + // Now go forward and queue them all + for (int i = startAudioChunk; i <= startAudioSearch; i++) { + if (_indexEntries[i].id == ID_REC) + continue; + + if (getStreamIndex(_indexEntries[i].id) != audioIndex) + continue; + + assert(getStreamType(_indexEntries[i].id) == kStreamTypeAudio); + + _fileStream->seek(_indexEntries[i].offset + 8); + Common::SeekableReadStream *chunk = _fileStream->readStream(_indexEntries[i].size); + audioTrack->queueSound(chunk); + } + + // Skip any audio to bring us to the right time + audioTrack->skipAudio(time, videoTrack->getFrameTime(frame)); + } + + // Decode from keyFrame to curFrame - 1 + for (int i = lastKeyFrame; i < frameIndex; i++) { + if (_indexEntries[i].id == ID_REC) + continue; + + if (getStreamIndex(_indexEntries[i].id) != videoIndex) + continue; + + uint16 streamType = getStreamType(_indexEntries[i].id); + + // Ignore palettes, they were already handled + if (streamType == kStreamTypePaletteChange) + continue; + + // Frame, hopefully + _fileStream->seek(_indexEntries[i].offset + 8); + Common::SeekableReadStream *chunk = 0; + + if (_indexEntries[i].size != 0) + chunk = _fileStream->readStream(_indexEntries[i].size); + + videoTrack->decodeFrame(chunk); + } + + // Seek to the right spot + // To the beginning of the last record, or frame if that doesn't exist + if (lastRecord >= 0) + _fileStream->seek(_indexEntries[lastRecord].offset); + else + _fileStream->seek(_indexEntries[frameIndex].offset); + + videoTrack->setCurFrame((int)frame - 1); + + return true; +} + +byte AVIDecoder::getStreamIndex(uint32 tag) const { + char string[3]; + WRITE_BE_UINT16(string, tag >> 16); + string[2] = 0; + return strtol(string, 0, 16); +} + +void AVIDecoder::readOldIndex(uint32 size) { + uint32 entryCount = size / 16; + + debug(0, "Old Index: %d entries", entryCount); + + if (entryCount == 0) + return; + + // Read the first index separately + OldIndex firstEntry; + firstEntry.id = _fileStream->readUint32BE(); + firstEntry.flags = _fileStream->readUint32LE(); + firstEntry.offset = _fileStream->readUint32LE(); + firstEntry.size = _fileStream->readUint32LE(); + + // Check if the offset is already absolute + // If it's absolute, the offset will equal the start of the movie list + bool isAbsolute = firstEntry.offset == _movieListStart; + + debug(1, "Old index is %s", isAbsolute ? "absolute" : "relative"); + + if (!isAbsolute) + firstEntry.offset += _movieListStart - 4; + + debug(0, "Index 0: Tag '%s', Offset = %d, Size = %d (Flags = %d)", tag2str(firstEntry.id), firstEntry.offset, firstEntry.size, firstEntry.flags); + _indexEntries.push_back(firstEntry); + + for (uint32 i = 1; i < entryCount; i++) { + OldIndex indexEntry; + indexEntry.id = _fileStream->readUint32BE(); + indexEntry.flags = _fileStream->readUint32LE(); + indexEntry.offset = _fileStream->readUint32LE(); + indexEntry.size = _fileStream->readUint32LE(); + + // Adjust to absolute, if necessary + if (!isAbsolute) + indexEntry.offset += _movieListStart - 4; + + _indexEntries.push_back(indexEntry); + debug(0, "Index %d: Tag '%s', Offset = %d, Size = %d (Flags = %d)", i, tag2str(indexEntry.id), indexEntry.offset, indexEntry.size, indexEntry.flags); + } +} + +void AVIDecoder::forceVideoEnd() { + // Horrible AVI video has a premature end + // Force the frame to be the last frame + debug(0, "Forcing end of AVI video"); + + for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++) + if ((*it)->getTrackType() == Track::kTrackTypeVideo) + ((AVIVideoTrack *)*it)->forceTrackEnd(); +} + +AVIDecoder::AVIVideoTrack::AVIVideoTrack(int frameCount, const AVIStreamHeader &streamHeader, const BitmapInfoHeader &bitmapInfoHeader, byte *initialPalette) + : _frameCount(frameCount), _vidsHeader(streamHeader), _bmInfo(bitmapInfoHeader), _initialPalette(initialPalette) { _videoCodec = createCodec(); - _dirtyPalette = false; _lastFrame = 0; _curFrame = -1; + + useInitialPalette(); } AVIDecoder::AVIVideoTrack::~AVIVideoTrack() { delete _videoCodec; + delete[] _initialPalette; } void AVIDecoder::AVIVideoTrack::decodeFrame(Common::SeekableReadStream *stream) { @@ -412,6 +713,47 @@ Graphics::PixelFormat AVIDecoder::AVIVideoTrack::getPixelFormat() const { return Graphics::PixelFormat(); } +void AVIDecoder::AVIVideoTrack::loadPaletteFromChunk(Common::SeekableReadStream *chunk) { + assert(chunk); + byte firstEntry = chunk->readByte(); + uint16 numEntries = chunk->readByte(); + chunk->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] = chunk->readByte(); + _palette[i * 3 + 1] = chunk->readByte(); + _palette[i * 3 + 2] = chunk->readByte(); + chunk->readByte(); // Flags that don't serve us any purpose + } + + delete chunk; + _dirtyPalette = true; +} + +void AVIDecoder::AVIVideoTrack::useInitialPalette() { + _dirtyPalette = false; + + if (_initialPalette) { + memcpy(_palette, _initialPalette, sizeof(_palette)); + _dirtyPalette = true; + } +} + +bool AVIDecoder::AVIVideoTrack::rewind() { + _curFrame = -1; + + useInitialPalette(); + + delete _videoCodec; + _videoCodec = createCodec(); + _lastFrame = 0; + return true; +} + Codec *AVIDecoder::AVIVideoTrack::createCodec() { switch (_vidsHeader.streamHandler) { case ID_CRAM: @@ -428,6 +770,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)); } @@ -435,6 +781,10 @@ Codec *AVIDecoder::AVIVideoTrack::createCodec() { return 0; } +void AVIDecoder::AVIVideoTrack::forceTrackEnd() { + _curFrame = _frameCount - 1; +} + AVIDecoder::AVIAudioTrack::AVIAudioTrack(const AVIStreamHeader &streamHeader, const PCMWaveFormat &waveFormat, Audio::Mixer::SoundType soundType) : _audsHeader(streamHeader), _wvInfo(waveFormat), _soundType(soundType) { _audStream = createAudioStream(); @@ -469,6 +819,31 @@ void AVIDecoder::AVIAudioTrack::queueSound(Common::SeekableReadStream *stream) { } } +void AVIDecoder::AVIAudioTrack::skipAudio(const Audio::Timestamp &time, const Audio::Timestamp &frameTime) { + Audio::Timestamp timeDiff = time.convertToFramerate(_wvInfo.samplesPerSec) - frameTime.convertToFramerate(_wvInfo.samplesPerSec); + int skipFrames = timeDiff.totalNumberOfFrames(); + + if (skipFrames <= 0) + return; + + if (_audStream->isStereo()) + skipFrames *= 2; + + int16 *tempBuffer = new int16[skipFrames]; + _audStream->readBuffer(tempBuffer, skipFrames); + delete[] tempBuffer; +} + +void AVIDecoder::AVIAudioTrack::resetStream() { + delete _audStream; + _audStream = createAudioStream(); +} + +bool AVIDecoder::AVIAudioTrack::rewind() { + resetStream(); + return true; +} + Audio::AudioStream *AVIDecoder::AVIAudioTrack::getAudioStream() const { return _audStream; } |