Example #1
0
const Graphics::Surface *RlfAnimation::getFrameData(uint frameNumber) {
	assert(!_stream);
	assert(frameNumber < _frameCount);

	// Since this method is so expensive, first check to see if we can use
	// decodeNextFrame() it's cheap.
	if ((int)frameNumber == _nextFrame - 1) {
		return &_currentFrameBuffer;
	} else if (_nextFrame == (int)frameNumber) {
		return decodeNextFrame();
	}

	seekToFrame(frameNumber);
	return decodeNextFrame();
}
Example #2
0
void MoviePlayerSMK::nextFrame() {
	if (_vm->_interactiveVideo == TYPE_LOOPING && endOfVideo())
		rewind();

	if (!endOfVideo()) {
		decodeNextFrame();
		if (_vm->_interactiveVideo == TYPE_OMNITV) {
			copyFrameToBuffer(_vm->getBackBuf(), 465, 222, _vm->_screenWidth);
		} else if (_vm->_interactiveVideo == TYPE_LOOPING) {
			copyFrameToBuffer(_vm->getBackBuf(), (_vm->_screenWidth - getWidth()) / 2, (_vm->_screenHeight - getHeight()) / 2, _vm->_screenWidth);
		}
	} else if (_vm->_interactiveVideo == TYPE_OMNITV) {
		close();
		_vm->_interactiveVideo = 0;
		_vm->_variableArray[254] = 6747;
	}
}
Example #3
0
void MoviePlayerSMK::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) {
	uint h = getHeight();
	uint w = getWidth();

	const Graphics::Surface *surface = decodeNextFrame();
	byte *src = (byte *)surface->pixels;
	dst += y * pitch + x;

	do {
		memcpy(dst, src, w);
		dst += pitch;
		src += w;
	} while (--h);

	if (hasDirtyPalette())
		setSystemPalette();
}
Example #4
0
bool AudioDecoder::decodeNextFrame( Frame& frameBuffer, const size_t subStreamIndex )
{
	if( ! decodeNextFrame() )
		return false;

	AVCodecContext& avCodecContext = _inputStream->getAudioCodec().getAVCodecContext();

	const int output_nbChannels = 1;
	const int output_align = 1;
	size_t decodedSize = av_samples_get_buffer_size(NULL, output_nbChannels, _frame->nb_samples, avCodecContext.sample_fmt, output_align);
	
	size_t nbSubStreams = avCodecContext.channels;
	size_t bytePerSample = av_get_bytes_per_sample( (AVSampleFormat)_frame->format );

	if( subStreamIndex > nbSubStreams - 1 )
	{
		throw std::runtime_error( "The subStream doesn't exist");
	}

	if( decodedSize == 0 )
		return false;

	AudioFrame& audioBuffer = static_cast<AudioFrame&>( frameBuffer );
	audioBuffer.setNbSamples( _frame->nb_samples );
	audioBuffer.resize( decodedSize );

	// @todo manage cases with data of frame not only on data[0] (use _frame.linesize)
	unsigned char* src = _frame->data[0];
	unsigned char* dst = audioBuffer.getData();

	// offset
	src += subStreamIndex * bytePerSample;

	for( int sample = 0; sample < _frame->nb_samples; ++sample )
	{
		memcpy( dst, src, bytePerSample );
		dst += bytePerSample;
		src += bytePerSample * nbSubStreams;
	}

	return true;
}
Example #5
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();
}
Example #6
0
void MoviePlayerSMK::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) {
	uint h = getHeight();
	uint w = getWidth();

	const Graphics::Surface *surface = decodeNextFrame();

	if (!surface)
		return;

	const byte *src = (const byte *)surface->getPixels();
	dst += y * pitch + x;

	do {
		memcpy(dst, src, w);
		dst += pitch;
		src += w;
	} while (--h);

	if (hasDirtyPalette())
		g_system->getPaletteManager()->setPalette(getPalette(), 0, 256);
}
Example #7
0
void QuickTimeDecoder::seekToFrame(uint32 frame) {
	assert(_videoTrackIndex >= 0);
	assert(frame < _tracks[_videoTrackIndex]->frameCount);

	// Stop all audio (for now)
	stopAudio();

	// Track down the keyframe
	_curFrame = findKeyFrame(frame) - 1;
	while (_curFrame < (int32)frame - 1)
		decodeNextFrame();

	// Map out the starting point
	_nextFrameStartTime = 0;
	uint32 curFrame = 0;

	for (int32 i = 0; i < _tracks[_videoTrackIndex]->timeToSampleCount && curFrame < frame; i++) {
		for (int32 j = 0; j < _tracks[_videoTrackIndex]->timeToSample[i].count && curFrame < frame; j++) {
			curFrame++;
			_nextFrameStartTime += _tracks[_videoTrackIndex]->timeToSample[i].duration;
		}
	}

	// Adjust the video starting point
	const Audio::Timestamp curVideoTime(0, _nextFrameStartTime, _tracks[_videoTrackIndex]->timeScale);
	_startTime = g_system->getMillis() - curVideoTime.msecs();
	resetPauseStartTime();

	// Adjust the audio starting point
	if (_audioTrackIndex >= 0) {
		_audioStartOffset = curVideoTime;

		// Seek to the new audio location
		setAudioStreamPos(_audioStartOffset);

		// Restart the audio
		startAudio();
	}
}
Example #8
0
void MoviePlayer::copyFrameToBuffer(byte *dst, int dstType, uint x, uint y, uint pitch) {
	uint h = getHeight();
	uint w = getWidth();

	const Graphics::Surface *surface = decodeNextFrame();
	byte *src = (byte *)surface->pixels;

	if (hasDirtyPalette())
		_vm->setPaletteFromPtr(getPalette(), 256);

	if (_vm->_game.features & GF_16BIT_COLOR) {
		dst += y * pitch + x * 2;
		do {
			for (uint i = 0; i < w; i++) {
				uint16 color = READ_LE_UINT16(_vm->_hePalettes + _vm->_hePaletteSlot + 768 + src[i] * 2);
				switch (dstType) {
				case kDstScreen:
					WRITE_UINT16(dst + i * 2, color);
					break;
				case kDstResource:
					WRITE_LE_UINT16(dst + i * 2, color);
					break;
				default:
					error("copyFrameToBuffer: Unknown dstType %d", dstType);
				}
			}
			dst += pitch;
			src += w;
		} while (--h);
	} else {
		dst += y * pitch + x;
		do {
			memcpy(dst, src, w);
			dst += pitch;
			src += w;
		} while (--h);
	}
}
Example #9
0
bool AudioDecoder::decodeNextFrame( Frame& frameBuffer )
{
	if( ! decodeNextFrame() )
		return false;

	AVCodecContext& avCodecContext = _inputStream->getAudioCodec().getAVCodecContext();

	size_t decodedSize = av_samples_get_buffer_size( NULL, avCodecContext.channels, _frame->nb_samples, avCodecContext.sample_fmt, 1 );
	if( decodedSize == 0 )
		return false;

	AudioFrame& audioBuffer = static_cast<AudioFrame&>( frameBuffer );
	audioBuffer.setNbSamples( _frame->nb_samples );
	audioBuffer.resize( decodedSize );

	// @todo manage cases with data of frame not only on data[0] (use _frame.linesize)
	unsigned char* const src = _frame->data[0];
	unsigned char* dst = audioBuffer.getData();

	av_samples_copy( &dst, &src, 0, 0, _frame->nb_samples, avCodecContext.channels, avCodecContext.sample_fmt );

	return true;
}
Example #10
0
const Graphics::Surface *AviDecoder::decodeNextFrame() {
	uint32 nextTag = _fileStream->readUint32BE();

	if (_fileStream->eos())
		return NULL;

	if (_curFrame == -1)
		_startTime = g_system->getMillis();

	if (nextTag == ID_LIST) {
		// A list of audio/video chunks
		uint32 listSize = _fileStream->readUint32LE() - 4;
		int32 startPos = _fileStream->pos();

		if (_fileStream->readUint32BE() != ID_REC)
			error ("Expected 'rec ' LIST");

		// Decode chunks in the list and see if we get a frame
		const Graphics::Surface *frame = NULL;
		while (_fileStream->pos() < startPos + (int32)listSize) {
			const Graphics::Surface *temp = decodeNextFrame();
			if (temp)
				frame = temp;
		}

		return frame;
	} else if (getStreamType(nextTag) == 'wb') {
		// Audio Chunk
		uint32 chunkSize = _fileStream->readUint32LE();
		queueAudioBuffer(chunkSize);
		_fileStream->skip(chunkSize & 1); // Alignment
	} else if (getStreamType(nextTag) == 'dc' || getStreamType(nextTag) == 'id' ||
	           getStreamType(nextTag) == 'AM' || getStreamType(nextTag) == '32' ||
			   getStreamType(nextTag) == 'iv') {
		// Compressed Frame
		_curFrame++;
		uint32 chunkSize = _fileStream->readUint32LE();

		if (chunkSize == 0) // Keep last frame on screen
			return NULL;

		Common::SeekableReadStream *frameData = _fileStream->readStream(chunkSize);
		const Graphics::Surface *surface = _videoCodec->decodeImage(frameData);
		delete frameData;
		_fileStream->skip(chunkSize & 1); // Alignment
		return surface;
	} else if (getStreamType(nextTag) == 'pc') {
		// Palette Change
		_fileStream->readUint32LE(); // Chunk size, not needed here
		byte firstEntry = _fileStream->readByte();
		uint16 numEntries = _fileStream->readByte();
		_fileStream->readUint16LE(); // Reserved

		// 0 entries means all colors are going to be changed
		if (numEntries == 0)
			numEntries = 256;

		for (uint16 i = firstEntry; i < numEntries + firstEntry; i++) {
			_palette[i * 3] = _fileStream->readByte();
			_palette[i * 3 + 1] = _fileStream->readByte();
			_palette[i * 3 + 2] = _fileStream->readByte();
			_fileStream->readByte(); // Flags that don't serve us any purpose
		}

		_dirtyPalette = true;

		// No alignment necessary. It's always even.
	} else if (nextTag == ID_JUNK) {
		runHandle(ID_JUNK);
	} else if (nextTag == ID_IDX1) {
		runHandle(ID_IDX1);
	} else
		error("Tag = \'%s\', %d", tag2str(nextTag), _fileStream->pos());

	return NULL;
}
Example #11
0
static bool
mp3_decode_first_frame(struct mp3_data *data, struct tag **tag,
		       struct replay_gain_info **replay_gain_info_r)
{
	struct xing xing;
	struct lame lame;
	struct mad_bitptr ptr;
	int bitlen;
	enum mp3_action ret;

	/* stfu gcc */
	memset(&xing, 0, sizeof(struct xing));
	xing.flags = 0;

	while (true) {
		do {
			ret = decode_next_frame_header(data, tag,
						       replay_gain_info_r);
		} while (ret == DECODE_CONT);
		if (ret == DECODE_BREAK)
			return false;
		if (ret == DECODE_SKIP) continue;

		do {
			ret = decodeNextFrame(data);
		} while (ret == DECODE_CONT);
		if (ret == DECODE_BREAK)
			return false;
		if (ret == DECODE_OK) break;
	}

	ptr = data->stream.anc_ptr;
	bitlen = data->stream.anc_bitlen;

	mp3_filesize_to_song_length(data);

	/*
	 * if an xing tag exists, use that!
	 */
	if (parse_xing(&xing, &ptr, &bitlen)) {
		data->found_xing = true;
		data->mute_frame = MUTEFRAME_SKIP;

		if ((xing.flags & XING_FRAMES) && xing.frames) {
			mad_timer_t duration = data->frame.header.duration;
			mad_timer_multiply(&duration, xing.frames);
			data->total_time = ((float)mad_timer_count(duration, MAD_UNITS_MILLISECONDS)) / 1000;
			data->max_frames = xing.frames;
		}

		if (parse_lame(&lame, &ptr, &bitlen)) {
			if (gapless_playback &&
			    data->input_stream->seekable) {
				data->drop_start_samples = lame.encoder_delay +
				                           DECODERDELAY;
				data->drop_end_samples = lame.encoder_padding;
			}

			/* Album gain isn't currently used.  See comment in
			 * parse_lame() for details. -- jat */
			if (replay_gain_info_r && !*replay_gain_info_r &&
			    lame.track_gain) {
				*replay_gain_info_r = replay_gain_info_new();
				(*replay_gain_info_r)->tuples[REPLAY_GAIN_TRACK].gain = lame.track_gain;
				(*replay_gain_info_r)->tuples[REPLAY_GAIN_TRACK].peak = lame.peak;
			}
		}
	} 

	if (!data->max_frames)
		return false;

	if (data->max_frames > 8 * 1024 * 1024) {
		g_warning("mp3 file header indicates too many frames: %lu\n",
			  data->max_frames);
		return false;
	}

	data->frame_offsets = g_malloc(sizeof(long) * data->max_frames);
	data->times = g_malloc(sizeof(mad_timer_t) * data->max_frames);

	return true;
}
Example #12
0
static bool
mp3_read(struct mp3_data *data, struct replay_gain_info **replay_gain_info_r)
{
	struct decoder *decoder = data->decoder;
	enum mp3_action ret;
	enum decoder_command cmd;

	mp3_update_timer_next_frame(data);

	switch (data->mute_frame) {
	case MUTEFRAME_SKIP:
		data->mute_frame = MUTEFRAME_NONE;
		break;
	case MUTEFRAME_SEEK:
		if (data->elapsed_time >= data->seek_where)
			data->mute_frame = MUTEFRAME_NONE;
		break;
	case MUTEFRAME_NONE:
		cmd = mp3_synth_and_send(data,
					 replay_gain_info_r != NULL
					 ? *replay_gain_info_r : NULL);
		if (cmd == DECODE_COMMAND_SEEK) {
			unsigned long j;

			assert(data->input_stream->seekable);

			j = mp3_time_to_frame(data,
					      decoder_seek_where(decoder));
			if (j < data->highest_frame) {
				if (mp3_seek(data, data->frame_offsets[j])) {
					data->current_frame = j;
					decoder_command_finished(decoder);
				} else
					decoder_seek_error(decoder);
			} else {
				data->seek_where = decoder_seek_where(decoder);
				data->mute_frame = MUTEFRAME_SEEK;
				decoder_command_finished(decoder);
			}
		} else if (cmd != DECODE_COMMAND_NONE)
			return false;
	}

	while (true) {
		bool skip = false;

		do {
			struct tag *tag = NULL;

			ret = decode_next_frame_header(data, &tag,
						       replay_gain_info_r);

			if (tag != NULL) {
				decoder_tag(decoder, data->input_stream, tag);
				tag_free(tag);
			}
		} while (ret == DECODE_CONT);
		if (ret == DECODE_BREAK)
			return false;
		else if (ret == DECODE_SKIP)
			skip = true;

		if (data->mute_frame == MUTEFRAME_NONE) {
			do {
				ret = decodeNextFrame(data);
			} while (ret == DECODE_CONT);
			if (ret == DECODE_BREAK)
				return false;
		}

		if (!skip && ret == DECODE_OK)
			break;
	}

	return ret != DECODE_BREAK;
}
Example #13
0
void QuickTimeDecoder::seekToFrame(uint32 frame) {
	assert(_videoStreamIndex >= 0);
	assert(frame < _streams[_videoStreamIndex]->nb_frames);

	// Stop all audio (for now)
	stopAudio();

	// Track down the keyframe
	_curFrame = findKeyFrame(frame) - 1;
	while (_curFrame < (int32)frame - 1)
		decodeNextFrame();

	// Map out the starting point
	_nextFrameStartTime = 0;
	uint32 curFrame = 0;

	for (int32 i = 0; i < _streams[_videoStreamIndex]->stts_count && curFrame < frame; i++) {
		for (int32 j = 0; j < _streams[_videoStreamIndex]->stts_data[i].count && curFrame < frame; j++) {
			curFrame++;
			_nextFrameStartTime += _streams[_videoStreamIndex]->stts_data[i].duration;
		}
	}

	// Adjust the video starting point
	const Audio::Timestamp curVideoTime(0, _nextFrameStartTime, _streams[_videoStreamIndex]->time_scale);
	_startTime = g_system->getMillis() - curVideoTime.msecs();
	resetPauseStartTime();

	// Adjust the audio starting point
	if (_audioStreamIndex >= 0) {
		_audioStartOffset = curVideoTime;

		// Re-create the audio stream
		STSDEntry *entry = &_streams[_audioStreamIndex]->stsdEntries[0];
		_audStream = Audio::makeQueuingAudioStream(entry->sampleRate, entry->channels == 2);

		// First, we need to track down what audio sample we need
		Audio::Timestamp curAudioTime(0, _streams[_audioStreamIndex]->time_scale);
		uint sample = 0;
		bool done = false;
		for (int32 i = 0; i < _streams[_audioStreamIndex]->stts_count && !done; i++) {
			for (int32 j = 0; j < _streams[_audioStreamIndex]->stts_data[i].count; j++) {
				curAudioTime = curAudioTime.addFrames(_streams[_audioStreamIndex]->stts_data[i].duration);

				if (curAudioTime > curVideoTime) {
					done = true;
					break;
				}

				sample++;
			}
		}

		// Now to track down what chunk it's in
		_curAudioChunk = 0;
		uint32 totalSamples = 0;
		for (uint32 i = 0; i < _streams[_audioStreamIndex]->chunk_count; i++, _curAudioChunk++) {
			int sampleToChunkIndex = -1;

			for (uint32 j = 0; j < _streams[_audioStreamIndex]->sample_to_chunk_sz; j++)
				if (i >= _streams[_audioStreamIndex]->sample_to_chunk[j].first)
					sampleToChunkIndex = j;

			assert(sampleToChunkIndex >= 0);

			totalSamples += _streams[_audioStreamIndex]->sample_to_chunk[sampleToChunkIndex].count;

			if (sample < totalSamples) {
				totalSamples -= _streams[_audioStreamIndex]->sample_to_chunk[sampleToChunkIndex].count;
				break;
			}
		}
		
		// Reposition the audio stream
		readNextAudioChunk();
		if (sample != totalSamples) {
			// HACK: Skip a certain amount of samples from the stream
			// (There's got to be a better way to do this!)
			int16 *tempBuffer = new int16[sample - totalSamples];
			_audStream->readBuffer(tempBuffer, sample - totalSamples);
			delete[] tempBuffer;
			debug(3, "Skipping %d audio samples", sample - totalSamples);
		}
		
		// Restart the audio
		startAudio();
	}
}