void AVIDecoder::readStreamName(uint32 size) { if (!_lastAddedTrack) { skipChunk(size); } else { // Get in the name assert(size > 0 && size < 64); char buffer[64]; _fileStream->read(buffer, size); if (size & 1) _fileStream->skip(1); // Apply it to the most recently read stream assert(_lastAddedTrack); AVIVideoTrack *vidTrack = dynamic_cast<AVIVideoTrack *>(_lastAddedTrack); AVIAudioTrack *audTrack = dynamic_cast<AVIAudioTrack *>(_lastAddedTrack); if (vidTrack) vidTrack->getName() = Common::String(buffer); else if (audTrack) audTrack->getName() = Common::String(buffer); } }
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; }
bool AVIDecoder::seekIntern(const Audio::Timestamp &time) { // Can't seek beyond the end if (time > getDuration()) return false; // Get our video AVIVideoTrack *videoTrack = (AVIVideoTrack *)_videoTracks[0].track; uint32 videoIndex = _videoTracks[0].index; // If we seek directly to the end, just mark the tracks as over if (time == getDuration()) { videoTrack->setCurFrame(videoTrack->getFrameCount() - 1); for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++) if ((*it)->getTrackType() == Track::kTrackTypeAudio) ((AVIAudioTrack *)*it)->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; 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]; // We don't care about RECs if (index.id == ID_REC) continue; // We're only looking at entries for this track 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; // Update all the audio tracks for (uint32 i = 0; i < _audioTracks.size(); i++) { AVIAudioTrack *audioTrack = (AVIAudioTrack *)_audioTracks[i].track; // Recreate the audio stream audioTrack->resetStream(); // Set the chunk index for the track audioTrack->setCurChunk(frame); uint32 chunksFound = 0; for (uint32 j = 0; j < _indexEntries.size(); j++) { const OldIndex &index = _indexEntries[j]; // Continue ignoring RECs if (index.id == ID_REC) continue; if (getStreamIndex(index.id) == _audioTracks[i].index) { if (chunksFound == frame) { _fileStream->seek(index.offset + 8); Common::SeekableReadStream *audioChunk = _fileStream->readStream(index.size); audioTrack->queueSound(audioChunk); _audioTracks[i].chunkSearchOffset = (j == _indexEntries.size() - 1) ? _movieListEnd : _indexEntries[j + 1].offset; break; } chunksFound++; } } // 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); } // Set the video track's frame videoTrack->setCurFrame((int)frame - 1); // Set the video track's search offset to the right spot _videoTracks[0].chunkSearchOffset = _indexEntries[frameIndex].offset; return true; }
void AVIDecoder::handleStreamHeader(uint32 size) { AVIStreamHeader sHeader; sHeader.size = size; 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(); _fileStream->skip(sHeader.size - 48); // Skip over the remainder of the chunk (frame) if (_fileStream->readUint32BE() != ID_STRF) error("Could not find STRF tag"); uint32 strfSize = _fileStream->readUint32LE(); 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(); bmInfo.height = _fileStream->readUint32LE(); 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.clrUsed == 0) bmInfo.clrUsed = 256; byte *initialPalette = 0; if (bmInfo.bitCount == 8) { 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(); } } addTrack(new AVIVideoTrack(_header.totalFrames, sHeader, bmInfo, initialPalette)); } else if (sHeader.streamType == ID_AUDS) { PCMWaveFormat wvInfo; wvInfo.tag = _fileStream->readUint16LE(); wvInfo.channels = _fileStream->readUint16LE(); wvInfo.samplesPerSec = _fileStream->readUint32LE(); wvInfo.avgBytesPerSec = _fileStream->readUint32LE(); wvInfo.blockAlign = _fileStream->readUint16LE(); wvInfo.size = _fileStream->readUint16LE(); // AVI seems to treat the sampleSize as including the second // channel as well, so divide for our sake. if (wvInfo.channels == 2) sHeader.sampleSize /= 2; AVIAudioTrack *track = createAudioTrack(sHeader, wvInfo); track->createAudioStream(); addTrack(track); } // Ensure that we're at the end of the chunk _fileStream->seek(startPos + strfSize); }