Beispiel #1
0
Video::AVIDecoder::AVIVideoTrack &AVIDecoder::getVideoTrack() {
	for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++)
		if ((*it)->getTrackType() == Track::kTrackTypeVideo)
			return *dynamic_cast<AVIVideoTrack *>(*it);

	error("Could not find video track");
}
Beispiel #2
0
bool AVIDecoder::loadStream(Common::SeekableReadStream *stream) {
	close();

	uint32 riffTag = stream->readUint32BE();
	if (riffTag != ID_RIFF) {
		warning("Failed to find RIFF header");
		return false;
	}

	int32 fileSize = stream->readUint32LE();
	uint32 riffType = stream->readUint32BE();

	if (riffType != ID_AVI) {
		warning("RIFF not an AVI file");
		return false;
	}

	_fileStream = stream;

	// Go through all chunks in the file
	while (_fileStream->pos() < fileSize && parseNextChunk())
		;

	if (!_decodedHeader) {
		warning("Failed to parse AVI header");
		close();
		return false;
	}

	if (!_foundMovieList) {
		warning("Failed to find 'MOVI' list");
		close();
		return false;
	}

	// Create the status entries
	uint32 index = 0;
	for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++, index++) {
		TrackStatus status;
		status.track = *it;
		status.index = index;
		status.chunkSearchOffset = _movieListStart;

		if ((*it)->getTrackType() == Track::kTrackTypeVideo)
			_videoTracks.push_back(status);
		else
			_audioTracks.push_back(status);
	}

	if (_videoTracks.size() != 1) {
		close();
		return false;
	}

	// Check if this is a special Duck Truemotion video
	checkTruemotion1();

	return true;
}
Beispiel #3
0
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();
}
Beispiel #4
0
void AVIDecoder::checkTruemotion1() {
	AVIVideoTrack *track = 0;

	for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++) {
		if ((*it)->getTrackType() == Track::kTrackTypeVideo) {
			if (track) {
				// Multiple tracks; isn't going to be truemotion 1
				return;
			}

			track = (AVIVideoTrack *)*it;
		}
	}

	// No track found?
	if (!track)
		return;

	// Ignore non-truemotion tracks
	if (!track->isTruemotion1())
		return;

	// Search for a non-empty frame
	const Graphics::Surface *frame = 0;
	for (int i = 0; i < 10 && !frame; i++)
		frame = decodeNextFrame();

	if (!frame) {
		// Probably shouldn't happen
		rewind();
		return;
	}

	// Fill in the width/height based on the frame's width/height
	_header.width = frame->w;
	_header.height = frame->h;
	track->forceDimensions(frame->w, frame->h);

	// Rewind us back to the beginning
	rewind();
}
Beispiel #5
0
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;
}
Beispiel #6
0
void QuickTimeDecoder::updateAudioBuffer() {
	// Updates the audio buffers for all audio tracks
	for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++)
		if ((*it)->getTrackType() == VideoDecoder::Track::kTrackTypeAudio)
			((AudioTrackHandler *)*it)->updateBuffer();
}
Beispiel #7
0
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;
}
Beispiel #8
0
bool AVIDecoder::loadStream(Common::SeekableReadStream *stream) {
	close();

	uint32 riffTag = stream->readUint32BE();
	if (riffTag != ID_RIFF) {
		warning("Failed to find RIFF header");
		return false;
	}

	int32 fileSize = stream->readUint32LE();
	uint32 riffType = stream->readUint32BE();

	if (riffType != ID_AVI) {
		warning("RIFF not an AVI file");
		return false;
	}

	_fileStream = stream;

	// Go through all chunks in the file
	while (_fileStream->pos() < fileSize && parseNextChunk())
		;

	if (!_decodedHeader) {
		warning("Failed to parse AVI header");
		close();
		return false;
	}

	if (!_foundMovieList) {
		warning("Failed to find 'MOVI' list");
		close();
		return false;
	}

	// Create the status entries
	uint32 index = 0;
	for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++, index++) {
		TrackStatus status;
		status.track = *it;
		status.index = index;
		status.chunkSearchOffset = _movieListStart;

		if ((*it)->getTrackType() == Track::kTrackTypeAudio) {
			_audioTracks.push_back(status);
		} else if (_videoTracks.empty()) {
			_videoTracks.push_back(status);
		} else {
			// Secondary video track. For now we assume it will always be a
			// transparency information track
			status.chunkSearchOffset = getVideoTrackOffset(index);
			assert(!_transparencyTrack.track);
			assert(status.chunkSearchOffset != 0);

			// Copy the track status information into the transparency track field
			_transparencyTrack = status;
		}
	}

	// If there is a transparency track, remove it from the video decoder's track list.
	// This is to stop it being included in calls like getFrameCount
	if (_transparencyTrack.track)
		eraseTrack(_transparencyTrack.track);

	// Check if this is a special Duck Truemotion video
	checkTruemotion1();

	return true;
}
Beispiel #9
0
void MPEGPSDecoder::readNextPacket() {
	if (_stream->eos())
		return;

	for (;;) {
		int32 startCode;
		uint32 pts, dts;
		int size = readNextPacketHeader(startCode, pts, dts);

		if (size < 0) {
			// End of stream
			for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++)
				if ((*it)->getTrackType() == Track::kTrackTypeVideo)
					((MPEGVideoTrack *)*it)->setEndOfTrack();
			return;
		}

		MPEGStream *stream = 0;
		Common::SeekableReadStream *packet = _stream->readStream(size);

		if (_streamMap.contains(startCode)) {
			// We already found the stream
			stream = _streamMap[startCode];
		} else {
			// We haven't seen this before

			if (startCode == 0x1BD) {
				// Private stream 1
				PrivateStreamType streamType = detectPrivateStreamType(packet);

				packet->seek(0);

				switch (streamType) {
				case kPrivateStreamPS2Audio: {
					// PS2 Audio stream
					PS2AudioTrack *audioTrack = new PS2AudioTrack(packet);
					stream = audioTrack;
					_streamMap[startCode] = audioTrack;
					addTrack(audioTrack);
					break;
				}
				default:
					// Unknown (silently ignore)
					break;
				}
			} if (startCode >= 0x1E0 && startCode <= 0x1EF) {
				// Video stream
				// TODO: Multiple video streams
			} else if (startCode >= 0x1C0 && startCode <= 0x1DF) {
#ifdef USE_MAD
				// MPEG Audio stream
				MPEGAudioTrack *audioTrack = new MPEGAudioTrack(packet);
				stream = audioTrack;
				_streamMap[startCode] = audioTrack;
				addTrack(audioTrack);
#endif
			}
		}

		if (stream) {
			bool done = stream->sendPacket(packet, pts, dts);

			if (done && stream->getStreamType() == MPEGStream::kStreamTypeVideo)
				return;
		} else {
			delete packet;
		}
	}
}