ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

avi_decoder.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "common/stream.h"
00024 #include "common/system.h"
00025 #include "common/textconsole.h"
00026 
00027 #include "audio/audiostream.h"
00028 #include "audio/mixer.h"
00029 
00030 #include "video/avi_decoder.h"
00031 
00032 // Audio Codecs
00033 #include "audio/decoders/adpcm.h"
00034 #include "audio/decoders/mp3.h"
00035 #include "audio/decoders/raw.h"
00036 
00037 // Video Codecs
00038 #include "image/codecs/codec.h"
00039 
00040 namespace Video {
00041 
00042 #define UNKNOWN_HEADER(a) error("Unknown header found -- \'%s\'", tag2str(a))
00043 
00044 // IDs used throughout the AVI files
00045 // that will be handled by this player
00046 #define ID_RIFF MKTAG('R','I','F','F')
00047 #define ID_AVI  MKTAG('A','V','I',' ')
00048 #define ID_LIST MKTAG('L','I','S','T')
00049 #define ID_HDRL MKTAG('h','d','r','l')
00050 #define ID_AVIH MKTAG('a','v','i','h')
00051 #define ID_STRL MKTAG('s','t','r','l')
00052 #define ID_STRH MKTAG('s','t','r','h')
00053 #define ID_VIDS MKTAG('v','i','d','s')
00054 #define ID_AUDS MKTAG('a','u','d','s')
00055 #define ID_MIDS MKTAG('m','i','d','s')
00056 #define ID_TXTS MKTAG('t','x','t','s')
00057 #define ID_JUNK MKTAG('J','U','N','K')
00058 #define ID_JUNQ MKTAG('J','U','N','Q')
00059 #define ID_DMLH MKTAG('d','m','l','h')
00060 #define ID_STRF MKTAG('s','t','r','f')
00061 #define ID_MOVI MKTAG('m','o','v','i')
00062 #define ID_REC  MKTAG('r','e','c',' ')
00063 #define ID_VEDT MKTAG('v','e','d','t')
00064 #define ID_IDX1 MKTAG('i','d','x','1')
00065 #define ID_STRD MKTAG('s','t','r','d')
00066 #define ID_INFO MKTAG('I','N','F','O')
00067 #define ID_ISFT MKTAG('I','S','F','T')
00068 #define ID_DISP MKTAG('D','I','S','P')
00069 #define ID_PRMI MKTAG('P','R','M','I')
00070 #define ID_STRN MKTAG('s','t','r','n')
00071 
00072 // Stream Types
00073 enum {
00074     kStreamTypePaletteChange = MKTAG16('p', 'c'),
00075     kStreamTypeAudio         = MKTAG16('w', 'b')
00076 };
00077 
00078 
00079 AVIDecoder::AVIDecoder() :
00080         _frameRateOverride(0) {
00081     initCommon();
00082 }
00083 
00084 AVIDecoder::AVIDecoder(const Common::Rational &frameRateOverride) :
00085         _frameRateOverride(frameRateOverride) {
00086     initCommon();
00087 }
00088 
00089 AVIDecoder::~AVIDecoder() {
00090     close();
00091 }
00092 
00093 AVIDecoder::AVIAudioTrack *AVIDecoder::createAudioTrack(AVIStreamHeader sHeader, PCMWaveFormat wvInfo) {
00094     return new AVIAudioTrack(sHeader, wvInfo, getSoundType());
00095 }
00096 
00097 bool AVIDecoder::seekToFrame(uint frame) {
00098     if (!isSeekable())
00099         return false;
00100 
00101     // If we didn't find a video track, we can't seek by frame (of course)
00102     if (_videoTracks.empty())
00103         return false;
00104 
00105     AVIVideoTrack *track = static_cast<AVIVideoTrack *>(_videoTracks.front().track);
00106     Audio::Timestamp time = track->getFrameTime(frame);
00107 
00108     if (time < 0)
00109         return false;
00110 
00111     return seek(time);
00112 }
00113 
00114 void AVIDecoder::initCommon() {
00115     _decodedHeader = false;
00116     _foundMovieList = false;
00117     _movieListStart = 0;
00118     _movieListEnd = 0;
00119     _fileStream = 0;
00120     _videoTrackCounter = _audioTrackCounter = 0;
00121     _lastAddedTrack = nullptr;
00122     memset(&_header, 0, sizeof(_header));
00123     _transparencyTrack.track = nullptr;
00124 }
00125 
00126 bool AVIDecoder::isSeekable() const {
00127     // Only videos with an index can seek
00128     // Anyone else who wants to seek is crazy.
00129     return isVideoLoaded() && !_indexEntries.empty();
00130 }
00131 
00132 const Graphics::Surface *AVIDecoder::decodeNextFrame() {
00133     AVIVideoTrack *track = nullptr;
00134     bool isReversed = false;
00135     int frameNum = 0;
00136 
00137     // Check whether the video is playing in revese
00138     for (int idx = _videoTracks.size() - 1; idx >= 0; --idx) {
00139         track = static_cast<AVIVideoTrack *>(_videoTracks[idx].track);
00140         isReversed |= track->isReversed();
00141     }
00142 
00143     if (isReversed) {
00144         // For reverse mode we need to keep seeking to just before the
00145         // desired frame prior to actually decoding a frame
00146         frameNum = getCurFrame();
00147         seekIntern(track->getFrameTime(frameNum));
00148     }
00149 
00150     // Decode the next frame
00151     const Graphics::Surface *frame = VideoDecoder::decodeNextFrame();
00152 
00153     if (isReversed) {
00154         // In reverse mode, set next frame to be the prior frame number
00155         for (int idx = _videoTracks.size() - 1; idx >= 0; --idx) {
00156             track = static_cast<AVIVideoTrack *>(_videoTracks[idx].track);
00157             track->setCurFrame(frameNum - 1);
00158             findNextVideoTrack();
00159         }
00160     }
00161 
00162     return frame;
00163 }
00164 
00165 const Graphics::Surface *AVIDecoder::decodeNextTransparency() {
00166     if (!_transparencyTrack.track)
00167         return nullptr;
00168 
00169     AVIVideoTrack *track = static_cast<AVIVideoTrack *>(_transparencyTrack.track);
00170     return track->decodeNextFrame();
00171 }
00172 
00173 bool AVIDecoder::parseNextChunk() {
00174     uint32 tag = _fileStream->readUint32BE();
00175     uint32 size = _fileStream->readUint32LE();
00176 
00177     if (_fileStream->eos())
00178         return false;
00179 
00180     debug(6, "Decoding tag %s", tag2str(tag));
00181 
00182     switch (tag) {
00183     case ID_LIST:
00184         handleList(size);
00185         break;
00186     case ID_AVIH:
00187         _header.size = size;
00188         _header.microSecondsPerFrame = _fileStream->readUint32LE();
00189         _header.maxBytesPerSecond = _fileStream->readUint32LE();
00190         _header.padding = _fileStream->readUint32LE();
00191         _header.flags = _fileStream->readUint32LE();
00192         _header.totalFrames = _fileStream->readUint32LE();
00193         _header.initialFrames = _fileStream->readUint32LE();
00194         _header.streams = _fileStream->readUint32LE();
00195         _header.bufferSize = _fileStream->readUint32LE();
00196         _header.width = _fileStream->readUint32LE();
00197         _header.height = _fileStream->readUint32LE();
00198         // Ignore 16 bytes of reserved data
00199         _fileStream->skip(16);
00200         break;
00201     case ID_STRH:
00202         handleStreamHeader(size);
00203         break;
00204     case ID_STRD: // Extra stream info, safe to ignore
00205     case ID_VEDT: // Unknown, safe to ignore
00206     case ID_JUNK: // Alignment bytes, should be ignored
00207     case ID_JUNQ: // Same as JUNK, safe to ignore
00208     case ID_ISFT: // Metadata, safe to ignore
00209     case ID_DISP: // Metadata, should be safe to ignore
00210     case ID_DMLH: // OpenDML extension, contains an extra total frames field, safe to ignore
00211         skipChunk(size);
00212         break;
00213     case ID_STRN: // Metadata, safe to ignore
00214         readStreamName(size);
00215         break;
00216     case ID_IDX1:
00217         readOldIndex(size);
00218         break;
00219     default:
00220         error("Unknown tag \'%s\' found", tag2str(tag));
00221     }
00222 
00223     return true;
00224 }
00225 
00226 void AVIDecoder::skipChunk(uint32 size) {
00227     // Make sure we're aligned on a word boundary
00228     _fileStream->skip(size + (size & 1));
00229 }
00230 
00231 void AVIDecoder::handleList(uint32 listSize) {
00232     uint32 listType = _fileStream->readUint32BE();
00233     listSize -= 4; // Subtract away listType's 4 bytes
00234     uint32 curPos = _fileStream->pos();
00235 
00236     debug(7, "Found LIST of type %s", tag2str(listType));
00237 
00238     switch (listType) {
00239     case ID_MOVI: // Movie List
00240         // We found the movie block
00241         _foundMovieList = true;
00242         _movieListStart = curPos;
00243         _movieListEnd = _movieListStart + listSize + (listSize & 1);
00244         _fileStream->skip(listSize);
00245         return;
00246     case ID_HDRL: // Header List
00247         // Mark the header as decoded
00248         _decodedHeader = true;
00249         break;
00250     case ID_INFO: // Metadata
00251     case ID_PRMI: // Adobe Premiere metadata, safe to ignore
00252         // Ignore metadata
00253         _fileStream->skip(listSize);
00254         return;
00255     case ID_STRL: // Stream list
00256     default:      // (Just hope we can parse it!)
00257         break;
00258     }
00259 
00260     while ((_fileStream->pos() - curPos) < listSize)
00261         parseNextChunk();
00262 }
00263 
00264 void AVIDecoder::handleStreamHeader(uint32 size) {
00265     AVIStreamHeader sHeader;
00266     sHeader.size = size;
00267     sHeader.streamType = _fileStream->readUint32BE();
00268 
00269     if (sHeader.streamType == ID_MIDS)
00270         error("Unhandled MIDI/Text stream");
00271 
00272     if (sHeader.streamType == ID_TXTS)
00273         warning("Unsupported Text stream detected");
00274 
00275     sHeader.streamHandler = _fileStream->readUint32BE();
00276     sHeader.flags = _fileStream->readUint32LE();
00277     sHeader.priority = _fileStream->readUint16LE();
00278     sHeader.language = _fileStream->readUint16LE();
00279     sHeader.initialFrames = _fileStream->readUint32LE();
00280     sHeader.scale = _fileStream->readUint32LE();
00281     sHeader.rate = _fileStream->readUint32LE();
00282     sHeader.start = _fileStream->readUint32LE();
00283     sHeader.length = _fileStream->readUint32LE();
00284     sHeader.bufferSize = _fileStream->readUint32LE();
00285     sHeader.quality = _fileStream->readUint32LE();
00286     sHeader.sampleSize = _fileStream->readUint32LE();
00287 
00288     _fileStream->skip(sHeader.size - 48); // Skip over the remainder of the chunk (frame)
00289 
00290     if (_fileStream->readUint32BE() != ID_STRF)
00291         error("Could not find STRF tag");
00292 
00293     uint32 strfSize = _fileStream->readUint32LE();
00294     uint32 startPos = _fileStream->pos();
00295 
00296     if (sHeader.streamType == ID_VIDS) {
00297         if (_frameRateOverride != 0) {
00298             sHeader.rate = _frameRateOverride.getNumerator();
00299             sHeader.scale = _frameRateOverride.getDenominator();
00300         }
00301 
00302         BitmapInfoHeader bmInfo;
00303         bmInfo.size = _fileStream->readUint32LE();
00304         bmInfo.width = _fileStream->readUint32LE();
00305         bmInfo.height = _fileStream->readUint32LE();
00306         bmInfo.planes = _fileStream->readUint16LE();
00307         bmInfo.bitCount = _fileStream->readUint16LE();
00308         bmInfo.compression = _fileStream->readUint32BE();
00309         bmInfo.sizeImage = _fileStream->readUint32LE();
00310         bmInfo.xPelsPerMeter = _fileStream->readUint32LE();
00311         bmInfo.yPelsPerMeter = _fileStream->readUint32LE();
00312         bmInfo.clrUsed = _fileStream->readUint32LE();
00313         bmInfo.clrImportant = _fileStream->readUint32LE();
00314 
00315         if (bmInfo.clrUsed == 0)
00316             bmInfo.clrUsed = 256;
00317 
00318         byte *initialPalette = 0;
00319 
00320         if (bmInfo.bitCount == 8) {
00321             initialPalette = new byte[256 * 3];
00322             memset(initialPalette, 0, 256 * 3);
00323 
00324             byte *palette = initialPalette;
00325             for (uint32 i = 0; i < bmInfo.clrUsed; i++) {
00326                 palette[i * 3 + 2] = _fileStream->readByte();
00327                 palette[i * 3 + 1] = _fileStream->readByte();
00328                 palette[i * 3] = _fileStream->readByte();
00329                 _fileStream->readByte();
00330             }
00331         }
00332 
00333         addTrack(new AVIVideoTrack(_header.totalFrames, sHeader, bmInfo, initialPalette));
00334     } else if (sHeader.streamType == ID_AUDS) {
00335         PCMWaveFormat wvInfo;
00336         wvInfo.tag = _fileStream->readUint16LE();
00337         wvInfo.channels = _fileStream->readUint16LE();
00338         wvInfo.samplesPerSec = _fileStream->readUint32LE();
00339         wvInfo.avgBytesPerSec = _fileStream->readUint32LE();
00340         wvInfo.blockAlign = _fileStream->readUint16LE();
00341         wvInfo.size = _fileStream->readUint16LE();
00342 
00343         // AVI seems to treat the sampleSize as including the second
00344         // channel as well, so divide for our sake.
00345         if (wvInfo.channels == 2)
00346             sHeader.sampleSize /= 2;
00347 
00348         AVIAudioTrack *track = createAudioTrack(sHeader, wvInfo);
00349         track->createAudioStream();
00350         addTrack(track);
00351     }
00352 
00353     // Ensure that we're at the end of the chunk
00354     _fileStream->seek(startPos + strfSize);
00355 }
00356 
00357 void AVIDecoder::addTrack(Track *track, bool isExternal) {
00358     VideoDecoder::addTrack(track, isExternal);
00359     _lastAddedTrack = track;
00360 }
00361 
00362 void AVIDecoder::readStreamName(uint32 size) {
00363     if (!_lastAddedTrack) {
00364         skipChunk(size);
00365     } else {
00366         // Get in the name
00367         assert(size > 0 && size < 64);
00368         char buffer[64];
00369         _fileStream->read(buffer, size);
00370         if (size & 1)
00371             _fileStream->skip(1);
00372 
00373         // Apply it to the most recently read stream
00374         assert(_lastAddedTrack);
00375         AVIVideoTrack *vidTrack = dynamic_cast<AVIVideoTrack *>(_lastAddedTrack);
00376         AVIAudioTrack *audTrack = dynamic_cast<AVIAudioTrack *>(_lastAddedTrack);
00377         if (vidTrack)
00378             vidTrack->getName() = Common::String(buffer);
00379         else if (audTrack)
00380             audTrack->getName() = Common::String(buffer);
00381     }
00382 }
00383 
00384 bool AVIDecoder::loadStream(Common::SeekableReadStream *stream) {
00385     close();
00386 
00387     uint32 riffTag = stream->readUint32BE();
00388     if (riffTag != ID_RIFF) {
00389         warning("Failed to find RIFF header");
00390         return false;
00391     }
00392 
00393     int32 fileSize = stream->readUint32LE();
00394     uint32 riffType = stream->readUint32BE();
00395 
00396     if (riffType != ID_AVI) {
00397         warning("RIFF not an AVI file");
00398         return false;
00399     }
00400 
00401     _fileStream = stream;
00402 
00403     // Go through all chunks in the file
00404     while (_fileStream->pos() < fileSize && parseNextChunk())
00405         ;
00406 
00407     if (!_decodedHeader) {
00408         warning("Failed to parse AVI header");
00409         close();
00410         return false;
00411     }
00412 
00413     if (!_foundMovieList) {
00414         warning("Failed to find 'MOVI' list");
00415         close();
00416         return false;
00417     }
00418 
00419     // Create the status entries
00420     uint32 index = 0;
00421     for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++, index++) {
00422         TrackStatus status;
00423         status.track = *it;
00424         status.index = index;
00425         status.chunkSearchOffset = _movieListStart;
00426 
00427         if ((*it)->getTrackType() == Track::kTrackTypeAudio) {
00428             _audioTracks.push_back(status);
00429         } else if (_videoTracks.empty()) {
00430             _videoTracks.push_back(status);
00431         } else {
00432             // Secondary video track. For now we assume it will always be a
00433             // transparency information track
00434             status.chunkSearchOffset = getVideoTrackOffset(index);
00435             assert(!_transparencyTrack.track);
00436             assert(status.chunkSearchOffset != 0);
00437 
00438             // Copy the track status information into the transparency track field
00439             _transparencyTrack = status;
00440         }
00441     }
00442 
00443     // If there is a transparency track, remove it from the video decoder's track list.
00444     // This is to stop it being included in calls like getFrameCount
00445     if (_transparencyTrack.track)
00446         eraseTrack(_transparencyTrack.track);
00447 
00448     // Check if this is a special Duck Truemotion video
00449     checkTruemotion1();
00450 
00451     return true;
00452 }
00453 
00454 void AVIDecoder::close() {
00455     VideoDecoder::close();
00456 
00457     delete _fileStream;
00458     _fileStream = 0;
00459     _decodedHeader = false;
00460     _foundMovieList = false;
00461     _movieListStart = 0;
00462     _movieListEnd = 0;
00463 
00464     _indexEntries.clear();
00465     memset(&_header, 0, sizeof(_header));
00466 
00467     _videoTracks.clear();
00468     _audioTracks.clear();
00469 
00470     delete _transparencyTrack.track;
00471     _transparencyTrack.track = nullptr;
00472 }
00473 
00474 void AVIDecoder::readNextPacket() {
00475     // Shouldn't get this unless called on a non-open video
00476     if (_videoTracks.empty())
00477         return;
00478 
00479     // Handle the video first
00480     for (uint idx = 0; idx < _videoTracks.size(); ++idx)
00481         handleNextPacket(_videoTracks[idx]);
00482 
00483     // Handle any transparency track
00484     if (_transparencyTrack.track)
00485         handleNextPacket(_transparencyTrack);
00486 
00487     // Handle audio tracks next
00488     for (uint idx = 0; idx < _audioTracks.size(); ++idx)
00489         handleNextPacket(_audioTracks[idx]);
00490 }
00491 
00492 void AVIDecoder::handleNextPacket(TrackStatus &status) {
00493     // If there's no more to search, bail out
00494     if (status.chunkSearchOffset + 8 >= _movieListEnd) {
00495         if (status.track->getTrackType() == Track::kTrackTypeVideo) {
00496             // Horrible AVI video has a premature end
00497             // Force the frame to be the last frame
00498             debug(7, "Forcing end of AVI video");
00499             ((AVIVideoTrack *)status.track)->forceTrackEnd();
00500         }
00501 
00502         return;
00503     }
00504 
00505     // See if audio needs to be buffered and break out if not
00506     if (status.track->getTrackType() == Track::kTrackTypeAudio && !shouldQueueAudio(status))
00507         return;
00508 
00509     // Seek to where we shall start searching
00510     _fileStream->seek(status.chunkSearchOffset);
00511     bool isReversed = false;
00512     AVIVideoTrack *videoTrack = nullptr;
00513 
00514     for (;;) {
00515         // If there's no more to search, bail out
00516         if ((uint32)_fileStream->pos() + 8 >= _movieListEnd) {
00517             if (status.track->getTrackType() == Track::kTrackTypeVideo) {
00518                 // Horrible AVI video has a premature end
00519                 // Force the frame to be the last frame
00520                 debug(7, "Forcing end of AVI video");
00521                 ((AVIVideoTrack *)status.track)->forceTrackEnd();
00522             }
00523 
00524             break;
00525         }
00526 
00527         uint32 nextTag = _fileStream->readUint32BE();
00528         uint32 size = _fileStream->readUint32LE();
00529 
00530         if (nextTag == ID_LIST) {
00531             // A list of audio/video chunks
00532             if (_fileStream->readUint32BE() != ID_REC)
00533                 error("Expected 'rec ' LIST");
00534 
00535             continue;
00536         } else if (nextTag == ID_JUNK || nextTag == ID_IDX1) {
00537             skipChunk(size);
00538             continue;
00539         }
00540 
00541         // Only accept chunks for this stream
00542         uint32 streamIndex = getStreamIndex(nextTag);
00543         if (streamIndex != status.index) {
00544             skipChunk(size);
00545             continue;
00546         }
00547 
00548         Common::SeekableReadStream *chunk = 0;
00549 
00550         if (size != 0) {
00551             chunk = _fileStream->readStream(size);
00552             _fileStream->skip(size & 1);
00553         }
00554 
00555         if (status.track->getTrackType() == Track::kTrackTypeAudio) {
00556             if (getStreamType(nextTag) != kStreamTypeAudio)
00557                 error("Invalid audio track tag '%s'", tag2str(nextTag));
00558 
00559             assert(chunk);
00560             ((AVIAudioTrack *)status.track)->queueSound(chunk);
00561 
00562             // Break out if we have enough audio
00563             if (!shouldQueueAudio(status))
00564                 break;
00565         } else {
00566             videoTrack = (AVIVideoTrack *)status.track;
00567             isReversed = videoTrack->isReversed();
00568 
00569             if (getStreamType(nextTag) == kStreamTypePaletteChange) {
00570                 // Palette Change
00571                 videoTrack->loadPaletteFromChunk(chunk);
00572             } else {
00573                 // Otherwise, assume it's a compressed frame
00574                 videoTrack->decodeFrame(chunk);
00575                 break;
00576             }
00577         }
00578     }
00579 
00580     if (!isReversed) {
00581         // Start us off in this position next time
00582         status.chunkSearchOffset = _fileStream->pos();
00583     }
00584 }
00585 
00586 bool AVIDecoder::shouldQueueAudio(TrackStatus& status) {
00587     // Sanity check:
00588     if (status.track->getTrackType() != Track::kTrackTypeAudio)
00589         return false;
00590 
00591     // If video is done, make sure that the rest of the audio is queued
00592     // (I guess this is also really a sanity check)
00593     AVIVideoTrack *videoTrack = (AVIVideoTrack *)_videoTracks[0].track;
00594     if (videoTrack->endOfTrack())
00595         return true;
00596 
00597     // Being three frames ahead should be enough for any video.
00598     return ((AVIAudioTrack *)status.track)->getCurChunk() < (uint32)(videoTrack->getCurFrame() + 3);
00599 }
00600 
00601 bool AVIDecoder::rewind() {
00602     if (!VideoDecoder::rewind())
00603         return false;
00604 
00605     for (uint32 i = 0; i < _videoTracks.size(); i++)
00606         _videoTracks[i].chunkSearchOffset = getVideoTrackOffset(_videoTracks[i].index);
00607 
00608     for (uint32 i = 0; i < _audioTracks.size(); i++)
00609         _audioTracks[i].chunkSearchOffset = _movieListStart;
00610 
00611     return true;
00612 }
00613 
00614 uint AVIDecoder::getVideoTrackOffset(uint trackIndex, uint frameNumber) {
00615     if (trackIndex == _videoTracks.front().index && frameNumber == 0)
00616         return _movieListStart;
00617 
00618     OldIndex *entry = _indexEntries.find(trackIndex, frameNumber);
00619     assert(entry);
00620     return entry->offset;
00621 }
00622 
00623 bool AVIDecoder::seekIntern(const Audio::Timestamp &time) {
00624     uint frame;
00625 
00626     // Can't seek beyond the end
00627     if (time > getDuration())
00628         return false;
00629 
00630     // Get our video
00631     AVIVideoTrack *videoTrack = (AVIVideoTrack *)_videoTracks[0].track;
00632     uint32 videoIndex = _videoTracks[0].index;
00633 
00634     if (time == getDuration()) {
00635         videoTrack->setCurFrame(videoTrack->getFrameCount() - 1);
00636 
00637         if (!videoTrack->isReversed()) {
00638             // Since we're at the end, just mark the tracks as over
00639             for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++)
00640                 if ((*it)->getTrackType() == Track::kTrackTypeAudio)
00641                     ((AVIAudioTrack *)*it)->resetStream();
00642 
00643             return true;
00644         }
00645 
00646         frame = videoTrack->getFrameCount() - 1;
00647     } else {
00648         // Get the frame we should be on at this time
00649         frame = videoTrack->getFrameAtTime(time);
00650     }
00651 
00652     // Reset any palette, if necessary
00653     videoTrack->useInitialPalette();
00654 
00655     int lastKeyFrame = -1;
00656     int frameIndex = -1;
00657     uint curFrame = 0;
00658 
00659     // Go through and figure out where we should be
00660     // If there's a palette, we need to find the palette too
00661     for (uint32 i = 0; i < _indexEntries.size(); i++) {
00662         const OldIndex &index = _indexEntries[i];
00663 
00664         // We don't care about RECs
00665         if (index.id == ID_REC)
00666             continue;
00667 
00668         // We're only looking at entries for this track
00669         if (getStreamIndex(index.id) != videoIndex)
00670             continue;
00671 
00672         uint16 streamType = getStreamType(index.id);
00673 
00674         if (streamType == kStreamTypePaletteChange) {
00675             // We need to handle any palette change we see since there's no
00676             // flag to tell if this is a "key" palette.
00677             // Decode the palette
00678             _fileStream->seek(_indexEntries[i].offset + 8);
00679             Common::SeekableReadStream *chunk = 0;
00680 
00681             if (_indexEntries[i].size != 0)
00682                 chunk = _fileStream->readStream(_indexEntries[i].size);
00683 
00684             videoTrack->loadPaletteFromChunk(chunk);
00685         } else {
00686             // Check to see if this is a keyframe
00687             // The first frame has to be a keyframe
00688             if ((_indexEntries[i].flags & AVIIF_INDEX) || curFrame == 0)
00689                 lastKeyFrame = i;
00690 
00691             // Did we find the target frame?
00692             if (frame == curFrame) {
00693                 frameIndex = i;
00694                 break;
00695             }
00696 
00697             curFrame++;
00698         }
00699     }
00700 
00701     if (frameIndex < 0) // This shouldn't happen.
00702         return false;
00703 
00704     // Update all the audio tracks
00705     for (uint32 i = 0; i < _audioTracks.size(); i++) {
00706         AVIAudioTrack *audioTrack = (AVIAudioTrack *)_audioTracks[i].track;
00707 
00708         // Recreate the audio stream
00709         audioTrack->resetStream();
00710 
00711         // Set the chunk index for the track
00712         audioTrack->setCurChunk(frame);
00713 
00714         uint32 chunksFound = 0;
00715         for (uint32 j = 0; j < _indexEntries.size(); j++) {
00716             const OldIndex &index = _indexEntries[j];
00717 
00718             // Continue ignoring RECs
00719             if (index.id == ID_REC)
00720                 continue;
00721 
00722             if (getStreamIndex(index.id) == _audioTracks[i].index) {
00723                 if (chunksFound == frame) {
00724                     _fileStream->seek(index.offset + 8);
00725                     Common::SeekableReadStream *audioChunk = _fileStream->readStream(index.size);
00726                     audioTrack->queueSound(audioChunk);
00727                     _audioTracks[i].chunkSearchOffset = (j == _indexEntries.size() - 1) ? _movieListEnd : _indexEntries[j + 1].offset;
00728                     break;
00729                 }
00730 
00731                 chunksFound++;
00732             }
00733         }
00734 
00735         // Skip any audio to bring us to the right time
00736         audioTrack->skipAudio(time, videoTrack->getFrameTime(frame));
00737     }
00738 
00739     // Decode from keyFrame to curFrame - 1
00740     for (int i = lastKeyFrame; i < frameIndex; i++) {
00741         if (_indexEntries[i].id == ID_REC)
00742             continue;
00743 
00744         if (getStreamIndex(_indexEntries[i].id) != videoIndex)
00745             continue;
00746 
00747         uint16 streamType = getStreamType(_indexEntries[i].id);
00748 
00749         // Ignore palettes, they were already handled
00750         if (streamType == kStreamTypePaletteChange)
00751             continue;
00752 
00753         // Frame, hopefully
00754         _fileStream->seek(_indexEntries[i].offset + 8);
00755         Common::SeekableReadStream *chunk = 0;
00756 
00757         if (_indexEntries[i].size != 0)
00758             chunk = _fileStream->readStream(_indexEntries[i].size);
00759 
00760         videoTrack->decodeFrame(chunk);
00761     }
00762 
00763     // Update any transparency track if present
00764     if (_transparencyTrack.track)
00765         seekTransparencyFrame(frame);
00766 
00767     // Set the video track's frame
00768     videoTrack->setCurFrame(frame - 1);
00769 
00770     // Set the video track's search offset to the right spot
00771     _videoTracks[0].chunkSearchOffset = _indexEntries[frameIndex].offset;
00772     return true;
00773 }
00774 
00775 void AVIDecoder::seekTransparencyFrame(int frame) {
00776     TrackStatus &status = _transparencyTrack;
00777     AVIVideoTrack *transTrack = static_cast<AVIVideoTrack *>(status.track);
00778 
00779     // Find the index entry for the frame
00780     int indexFrame = frame;
00781     OldIndex *entry = nullptr;
00782     do {
00783         entry = _indexEntries.find(status.index, indexFrame);
00784     } while (!entry && indexFrame-- > 0);
00785     assert(entry);
00786 
00787     // Set it's frame number
00788     transTrack->setCurFrame(indexFrame - 1);
00789 
00790     // Read in the frame
00791     Common::SeekableReadStream *chunk = nullptr;
00792     _fileStream->seek(entry->offset + 8);
00793     status.chunkSearchOffset = entry->offset;
00794 
00795     if (entry->size != 0)
00796         chunk = _fileStream->readStream(entry->size);
00797     transTrack->decodeFrame(chunk);
00798 
00799     if (indexFrame < (int)frame) {
00800         while (status.chunkSearchOffset < _movieListEnd && indexFrame++ < (int)frame) {
00801             // There was no index entry for the desired frame, so an earlier one was decoded.
00802             // We now have to sequentially skip frames until we get to the desired frame
00803             _fileStream->readUint32BE();
00804             uint32 size = _fileStream->readUint32LE() - 8;
00805             _fileStream->skip(size & 1);
00806             status.chunkSearchOffset = _fileStream->pos();
00807         }
00808     }
00809 
00810     transTrack->setCurFrame(frame - 1);
00811 }
00812 
00813 byte AVIDecoder::getStreamIndex(uint32 tag) {
00814     char string[3];
00815     WRITE_BE_UINT16(string, tag >> 16);
00816     string[2] = 0;
00817     return strtol(string, 0, 16);
00818 }
00819 
00820 void AVIDecoder::readOldIndex(uint32 size) {
00821     uint32 entryCount = size / 16;
00822 
00823     debug(7, "Old Index: %d entries", entryCount);
00824 
00825     if (entryCount == 0)
00826         return;
00827 
00828     // Read the first index separately
00829     OldIndex firstEntry;
00830     firstEntry.id = _fileStream->readUint32BE();
00831     firstEntry.flags = _fileStream->readUint32LE();
00832     firstEntry.offset = _fileStream->readUint32LE();
00833     firstEntry.size = _fileStream->readUint32LE();
00834 
00835     // Check if the offset is already absolute
00836     // If it's absolute, the offset will equal the start of the movie list
00837     bool isAbsolute = firstEntry.offset == _movieListStart;
00838 
00839     debug(6, "Old index is %s", isAbsolute ? "absolute" : "relative");
00840 
00841     if (!isAbsolute)
00842         firstEntry.offset += _movieListStart - 4;
00843 
00844     debug(7, "Index 0: Tag '%s', Offset = %d, Size = %d (Flags = %d)", tag2str(firstEntry.id), firstEntry.offset, firstEntry.size, firstEntry.flags);
00845     _indexEntries.push_back(firstEntry);
00846 
00847     for (uint32 i = 1; i < entryCount; i++) {
00848         OldIndex indexEntry;
00849         indexEntry.id = _fileStream->readUint32BE();
00850         indexEntry.flags = _fileStream->readUint32LE();
00851         indexEntry.offset = _fileStream->readUint32LE();
00852         indexEntry.size = _fileStream->readUint32LE();
00853 
00854         // Adjust to absolute, if necessary
00855         if (!isAbsolute)
00856             indexEntry.offset += _movieListStart - 4;
00857 
00858         _indexEntries.push_back(indexEntry);
00859         debug(7, "Index %d: Tag '%s', Offset = %d, Size = %d (Flags = %d)", i, tag2str(indexEntry.id), indexEntry.offset, indexEntry.size, indexEntry.flags);
00860     }
00861 }
00862 
00863 void AVIDecoder::checkTruemotion1() {
00864     // If we got here from loadStream(), we know the track is valid
00865     assert(!_videoTracks.empty());
00866 
00867     TrackStatus &status = _videoTracks[0];
00868     AVIVideoTrack *track = (AVIVideoTrack *)status.track;
00869 
00870     // Ignore non-truemotion tracks
00871     if (!track->isTruemotion1())
00872         return;
00873 
00874     // Read the next video packet
00875     handleNextPacket(status);
00876 
00877     const Graphics::Surface *frame = track->decodeNextFrame();
00878     if (!frame) {
00879         rewind();
00880         return;
00881     }
00882 
00883     // Fill in the width/height based on the frame's width/height
00884     _header.width = frame->w;
00885     _header.height = frame->h;
00886     track->forceDimensions(frame->w, frame->h);
00887 
00888     // Rewind us back to the beginning
00889     rewind();
00890 }
00891 
00892 VideoDecoder::AudioTrack *AVIDecoder::getAudioTrack(int index) {
00893     // AVI audio track indexes are relative to the first track
00894     Track *track = getTrack(index);
00895 
00896     if (!track || track->getTrackType() != Track::kTrackTypeAudio)
00897         return 0;
00898 
00899     return (AudioTrack *)track;
00900 }
00901 
00902 AVIDecoder::AVIVideoTrack::AVIVideoTrack(int frameCount, const AVIStreamHeader &streamHeader, const BitmapInfoHeader &bitmapInfoHeader, byte *initialPalette)
00903         : _frameCount(frameCount), _vidsHeader(streamHeader), _bmInfo(bitmapInfoHeader), _initialPalette(initialPalette) {
00904     _videoCodec = createCodec();
00905     _lastFrame = 0;
00906     _curFrame = -1;
00907     _reversed = false;
00908 
00909     useInitialPalette();
00910 }
00911 
00912 AVIDecoder::AVIVideoTrack::~AVIVideoTrack() {
00913     delete _videoCodec;
00914     delete[] _initialPalette;
00915 }
00916 
00917 void AVIDecoder::AVIVideoTrack::decodeFrame(Common::SeekableReadStream *stream) {
00918     if (stream) {
00919         if (_videoCodec)
00920             _lastFrame = _videoCodec->decodeFrame(*stream);
00921     } else {
00922         // Empty frame
00923         _lastFrame = 0;
00924     }
00925 
00926     delete stream;
00927 
00928     if (!_reversed) {
00929         _curFrame++;
00930     } else {
00931         _curFrame--;
00932     }
00933 }
00934 
00935 Graphics::PixelFormat AVIDecoder::AVIVideoTrack::getPixelFormat() const {
00936     if (_videoCodec)
00937         return _videoCodec->getPixelFormat();
00938 
00939     return Graphics::PixelFormat();
00940 }
00941 
00942 void AVIDecoder::AVIVideoTrack::loadPaletteFromChunk(Common::SeekableReadStream *chunk) {
00943     assert(chunk);
00944     byte firstEntry = chunk->readByte();
00945     uint16 numEntries = chunk->readByte();
00946     chunk->readUint16LE(); // Reserved
00947 
00948     // 0 entries means all colors are going to be changed
00949     if (numEntries == 0)
00950         numEntries = 256;
00951 
00952     for (uint16 i = firstEntry; i < numEntries + firstEntry; i++) {
00953         _palette[i * 3] = chunk->readByte();
00954         _palette[i * 3 + 1] = chunk->readByte();
00955         _palette[i * 3 + 2] = chunk->readByte();
00956         chunk->readByte(); // Flags that don't serve us any purpose
00957     }
00958 
00959     delete chunk;
00960     _dirtyPalette = true;
00961 }
00962 
00963 void AVIDecoder::AVIVideoTrack::useInitialPalette() {
00964     _dirtyPalette = false;
00965 
00966     if (_initialPalette) {
00967         memcpy(_palette, _initialPalette, sizeof(_palette));
00968         _dirtyPalette = true;
00969     }
00970 }
00971 
00972 bool AVIDecoder::AVIVideoTrack::isTruemotion1() const {
00973     return _bmInfo.compression == MKTAG('D', 'U', 'C', 'K') || _bmInfo.compression == MKTAG('d', 'u', 'c', 'k');
00974 }
00975 
00976 void AVIDecoder::AVIVideoTrack::forceDimensions(uint16 width, uint16 height) {
00977     _bmInfo.width = width;
00978     _bmInfo.height = height;
00979 }
00980 
00981 bool AVIDecoder::AVIVideoTrack::rewind() {
00982     _curFrame = -1;
00983 
00984     useInitialPalette();
00985 
00986     delete _videoCodec;
00987     _videoCodec = createCodec();
00988     _lastFrame = 0;
00989     return true;
00990 }
00991 
00992 Image::Codec *AVIDecoder::AVIVideoTrack::createCodec() {
00993     return Image::createBitmapCodec(_bmInfo.compression, _bmInfo.width, _bmInfo.height, _bmInfo.bitCount);
00994 }
00995 
00996 void AVIDecoder::AVIVideoTrack::forceTrackEnd() {
00997     _curFrame = _frameCount - 1;
00998 }
00999 
01000 const byte *AVIDecoder::AVIVideoTrack::getPalette() const {
01001     if (_videoCodec && _videoCodec->containsPalette())
01002         return _videoCodec->getPalette();
01003 
01004     _dirtyPalette = false;
01005     return _palette;
01006 }
01007 
01008 bool AVIDecoder::AVIVideoTrack::hasDirtyPalette() const {
01009     if (_videoCodec && _videoCodec->containsPalette())
01010         return _videoCodec->hasDirtyPalette();
01011 
01012     return _dirtyPalette;
01013 }
01014 
01015 bool AVIDecoder::AVIVideoTrack::setReverse(bool reverse) {
01016     if (isRewindable()) {
01017         // Track is rewindable, so reversing is allowed
01018         _reversed = reverse;
01019         return true;
01020     }
01021 
01022     return !reverse;
01023 }
01024 
01025 bool AVIDecoder::AVIVideoTrack::endOfTrack() const {
01026     if (_reversed)
01027         return _curFrame < -1;
01028 
01029     return _curFrame >= (getFrameCount() - 1);
01030 }
01031 
01032 bool AVIDecoder::AVIVideoTrack::canDither() const {
01033     return _videoCodec && _videoCodec->canDither(Image::Codec::kDitherTypeVFW);
01034 }
01035 
01036 void AVIDecoder::AVIVideoTrack::setDither(const byte *palette) {
01037     assert(_videoCodec);
01038     _videoCodec->setDither(Image::Codec::kDitherTypeVFW, palette);
01039 }
01040 
01041 AVIDecoder::AVIAudioTrack::AVIAudioTrack(const AVIStreamHeader &streamHeader, const PCMWaveFormat &waveFormat, Audio::Mixer::SoundType soundType) :
01042         AudioTrack(soundType),
01043         _audsHeader(streamHeader),
01044         _wvInfo(waveFormat),
01045         _audioStream(0),
01046         _packetStream(0),
01047         _curChunk(0) {
01048 }
01049 
01050 AVIDecoder::AVIAudioTrack::~AVIAudioTrack() {
01051     delete _audioStream;
01052 }
01053 
01054 void AVIDecoder::AVIAudioTrack::queueSound(Common::SeekableReadStream *stream) {
01055     if (_packetStream)
01056         _packetStream->queuePacket(stream);
01057     else
01058         delete stream;
01059 
01060     _curChunk++;
01061 }
01062 
01063 void AVIDecoder::AVIAudioTrack::skipAudio(const Audio::Timestamp &time, const Audio::Timestamp &frameTime) {
01064     Audio::Timestamp timeDiff = time.convertToFramerate(_wvInfo.samplesPerSec) - frameTime.convertToFramerate(_wvInfo.samplesPerSec);
01065     int skipFrames = timeDiff.totalNumberOfFrames();
01066 
01067     if (skipFrames <= 0)
01068         return;
01069 
01070     Audio::AudioStream *audioStream = getAudioStream();
01071     if (!audioStream)
01072         return;
01073 
01074     if (audioStream->isStereo())
01075         skipFrames *= 2;
01076 
01077     int16 *tempBuffer = new int16[skipFrames];
01078     audioStream->readBuffer(tempBuffer, skipFrames);
01079     delete[] tempBuffer;
01080 }
01081 
01082 void AVIDecoder::AVIAudioTrack::resetStream() {
01083     delete _audioStream;
01084     createAudioStream();
01085     _curChunk = 0;
01086 }
01087 
01088 bool AVIDecoder::AVIAudioTrack::rewind() {
01089     resetStream();
01090     return true;
01091 }
01092 
01093 void AVIDecoder::AVIAudioTrack::createAudioStream() {
01094     _packetStream = 0;
01095 
01096     switch (_wvInfo.tag) {
01097     case kWaveFormatPCM: {
01098         byte flags = 0;
01099         if (_audsHeader.sampleSize == 2)
01100             flags |= Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN;
01101         else
01102             flags |= Audio::FLAG_UNSIGNED;
01103 
01104         if (_wvInfo.channels == 2)
01105             flags |= Audio::FLAG_STEREO;
01106 
01107         _packetStream = Audio::makePacketizedRawStream(_wvInfo.samplesPerSec, flags);
01108         break;
01109     }
01110     case kWaveFormatMSADPCM:
01111         _packetStream = Audio::makePacketizedADPCMStream(Audio::kADPCMMS, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign);
01112         break;
01113     case kWaveFormatMSIMAADPCM:
01114         _packetStream = Audio::makePacketizedADPCMStream(Audio::kADPCMMSIma, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign);
01115         break;
01116     case kWaveFormatDK3:
01117         _packetStream = Audio::makePacketizedADPCMStream(Audio::kADPCMDK3, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign);
01118         break;
01119     case kWaveFormatMP3:
01120 #ifdef USE_MAD
01121         _packetStream = Audio::makePacketizedMP3Stream(_wvInfo.channels, _wvInfo.samplesPerSec);
01122 #else
01123         warning("AVI MP3 stream found, but no libmad support compiled in");
01124 #endif
01125         break;
01126     case kWaveFormatNone:
01127         break;
01128     default:
01129         warning("Unsupported AVI audio format %d", _wvInfo.tag);
01130         break;
01131     }
01132 
01133     if (_packetStream)
01134         _audioStream = _packetStream;
01135     else
01136         _audioStream = Audio::makeNullAudioStream();
01137 }
01138 
01139 AVIDecoder::TrackStatus::TrackStatus() : track(0), chunkSearchOffset(0) {
01140 }
01141 
01142 AVIDecoder::OldIndex *AVIDecoder::IndexEntries::find(uint index, uint frameNumber) {
01143     for (uint idx = 0, frameCtr = 0; idx < size(); ++idx) {
01144         if ((*this)[idx].id != ID_REC &&
01145                 AVIDecoder::getStreamIndex((*this)[idx].id) == index) {
01146             if (frameCtr++ == frameNumber)
01147                 return &(*this)[idx];
01148         }
01149     }
01150 
01151     return nullptr;
01152 }
01153 
01154 } // End of namespace Video


Generated on Sat Dec 14 2019 05:00:53 for ResidualVM by doxygen 1.7.1
curved edge   curved edge