Files
scummvm/video/mpegps_decoder.cpp
T

833 lines
21 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "audio/audiostream.h"
#include "audio/decoders/raw.h"
#include "common/endian.h"
#include "common/stream.h"
#include "common/system.h"
#include "common/textconsole.h"
#include "graphics/yuv_to_rgb.h"
#include "video/mpegps_decoder.h"
// The demuxing code is based on libav's demuxing code
namespace Video {
#define PACK_START_CODE 0x1BA
#define SYSTEM_HEADER_START_CODE 0x1BB
#define PROGRAM_STREAM_MAP 0x1BC
#define PRIVATE_STREAM_1 0x1BD
#define PADDING_STREAM 0x1BE
#define PRIVATE_STREAM_2 0x1BF
MPEGPSDecoder::MPEGPSDecoder() {
_stream = 0;
memset(_psmESType, 0, 256);
}
MPEGPSDecoder::~MPEGPSDecoder() {
close();
}
bool MPEGPSDecoder::loadStream(Common::SeekableReadStream *stream) {
close();
_stream = stream;
if (!addFirstVideoTrack()) {
close();
return false;
}
_stream->seek(0);
return true;
}
void MPEGPSDecoder::close() {
VideoDecoder::close();
delete _stream;
_stream = 0;
_streamMap.clear();
memset(_psmESType, 0, 256);
}
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;
}
}
}
#define MAX_SYNC_SIZE 100000
int MPEGPSDecoder::findNextStartCode(uint32 &size) {
size = MAX_SYNC_SIZE;
int32 state = 0xFF;
while (size > 0) {
byte v = _stream->readByte();
if (_stream->eos())
return -1;
size--;
if (state == 0x1)
return ((state << 8) | v) & 0xFFFFFF;
state = ((state << 8) | v) & 0xFFFFFF;
}
return -1;
}
int MPEGPSDecoder::readNextPacketHeader(int32 &startCode, uint32 &pts, uint32 &dts) {
for (;;) {
uint32 size;
startCode = findNextStartCode(size);
if (_stream->eos())
return -1;
if (startCode < 0)
continue;
uint32 lastSync = _stream->pos();
if (startCode == PACK_START_CODE || startCode == SYSTEM_HEADER_START_CODE)
continue;
int length = _stream->readUint16BE();
if (startCode == PADDING_STREAM || startCode == PRIVATE_STREAM_2) {
_stream->skip(length);
continue;
}
if (startCode == PROGRAM_STREAM_MAP) {
parseProgramStreamMap(length);
continue;
}
// Find matching stream
if (!((startCode >= 0x1C0 && startCode <= 0x1DF) ||
(startCode >= 0x1E0 && startCode <= 0x1EF) ||
startCode == 0x1BD || startCode == 0x1FD))
continue;
// Stuffing
byte c;
for (;;) {
if (length < 1) {
_stream->seek(lastSync);
continue;
}
c = _stream->readByte();
length--;
// XXX: for mpeg1, should test only bit 7
if (c != 0xFF)
break;
}
if ((c & 0xC0) == 0x40) {
// Buffer scale and size
_stream->readByte();
c = _stream->readByte();
length -= 2;
}
pts = 0xFFFFFFFF;
dts = 0xFFFFFFFF;
if ((c & 0xE0) == 0x20) {
dts = pts = readPTS(c);
length -= 4;
if (c & 0x10) {
dts = readPTS(-1);
length -= 5;
}
} else if ((c & 0xC0) == 0x80) {
// MPEG-2 PES
byte flags = _stream->readByte();
int headerLength = _stream->readByte();
length -= 2;
if (headerLength > length) {
_stream->seek(lastSync);
continue;
}
length -= headerLength;
if (flags & 0x80) {
dts = pts = readPTS(-1);
headerLength -= 5;
if (flags & 0x40) {
dts = readPTS(-1);
headerLength -= 5;
}
}
if (flags & 0x3F && headerLength == 0) {
flags &= 0xC0;
warning("Further flags set but no bytes left");
}
if (flags & 0x01) { // PES extension
byte pesExt =_stream->readByte();
headerLength--;
// Skip PES private data, program packet sequence
int skip = (pesExt >> 4) & 0xB;
skip += skip & 0x9;
if (pesExt & 0x40 || skip > headerLength) {
warning("pesExt %x is invalid", pesExt);
pesExt = skip = 0;
} else {
_stream->skip(skip);
headerLength -= skip;
}
if (pesExt & 0x01) { // PES extension 2
byte ext2Length = _stream->readByte();
headerLength--;
if ((ext2Length & 0x7F) != 0) {
byte idExt = _stream->readByte();
if ((idExt & 0x80) == 0)
startCode = (startCode & 0xFF) << 8;
headerLength--;
}
}
}
if (headerLength < 0) {
_stream->seek(lastSync);
continue;
}
_stream->skip(headerLength);
} else if (c != 0xF) {
continue;
}
if (length < 0) {
_stream->seek(lastSync);
continue;
}
return length;
}
}
uint32 MPEGPSDecoder::readPTS(int c) {
byte buf[5];
buf[0] = (c < 0) ? _stream->readByte() : c;
_stream->read(buf + 1, 4);
return ((buf[0] & 0x0E) << 29) | ((READ_BE_UINT16(buf + 1) >> 1) << 15) | (READ_BE_UINT16(buf + 3) >> 1);
}
void MPEGPSDecoder::parseProgramStreamMap(int length) {
_stream->readByte();
_stream->readByte();
// skip program stream info
_stream->skip(_stream->readUint16BE());
int esMapLength = _stream->readUint16BE();
while (esMapLength >= 4) {
byte type = _stream->readByte();
byte esID = _stream->readByte();
uint16 esInfoLength = _stream->readUint16BE();
// Remember mapping from stream id to stream type
_psmESType[esID] = type;
// Skip program stream info
_stream->skip(esInfoLength);
esMapLength -= 4 + esInfoLength;
}
_stream->readUint32BE(); // CRC32
}
bool MPEGPSDecoder::addFirstVideoTrack() {
for (;;) {
int32 startCode;
uint32 pts, dts;
int size = readNextPacketHeader(startCode, pts, dts);
// End of stream? We failed
if (size < 0)
return false;
if (startCode >= 0x1E0 && startCode <= 0x1EF) {
// Video stream
// Can be MPEG-1/2 or MPEG-4/h.264. We'll assume the former and
// I hope we never need the latter.
Common::SeekableReadStream *firstPacket = _stream->readStream(size);
MPEGVideoTrack *track = new MPEGVideoTrack(firstPacket, getDefaultHighColorFormat());
addTrack(track);
_streamMap[startCode] = track;
delete firstPacket;
break;
}
_stream->skip(size);
}
return true;
}
MPEGPSDecoder::PrivateStreamType MPEGPSDecoder::detectPrivateStreamType(Common::SeekableReadStream *packet) {
packet->seek(4);
if (packet->readUint32BE() == MKTAG('S', 'S', 'h', 'd'))
return kPrivateStreamPS2Audio;
return kPrivateStreamUnknown;
}
MPEGPSDecoder::MPEGVideoTrack::MPEGVideoTrack(Common::SeekableReadStream *firstPacket, const Graphics::PixelFormat &format) {
_endOfTrack = false;
_curFrame = -1;
_nextFrameStartTime = Audio::Timestamp(0, 27000000); // 27 MHz timer
findDimensions(firstPacket, format);
#ifdef USE_MPEG2
_mpegDecoder = mpeg2_init();
if (!_mpegDecoder)
error("Could not initialize libmpeg2");
_mpegInfo = mpeg2_info(_mpegDecoder);
#endif
}
MPEGPSDecoder::MPEGVideoTrack::~MPEGVideoTrack() {
#ifdef USE_MPEG2
mpeg2_close(_mpegDecoder);
#endif
_surface->free();
delete _surface;
}
uint16 MPEGPSDecoder::MPEGVideoTrack::getWidth() const {
return _surface->w;
}
uint16 MPEGPSDecoder::MPEGVideoTrack::getHeight() const {
return _surface->h;
}
Graphics::PixelFormat MPEGPSDecoder::MPEGVideoTrack::getPixelFormat() const {
return _surface->format;
}
const Graphics::Surface *MPEGPSDecoder::MPEGVideoTrack::decodeNextFrame() {
return _surface;
}
bool MPEGPSDecoder::MPEGVideoTrack::sendPacket(Common::SeekableReadStream *packet, uint32 pts, uint32 dts) {
#ifdef USE_MPEG2
// Decode as much as we can out of this packet
uint32 size = 0xFFFFFFFF;
mpeg2_state_t state;
bool foundFrame = false;
do {
state = mpeg2_parse(_mpegDecoder);
switch (state) {
case STATE_BUFFER:
size = packet->read(_buffer, BUFFER_SIZE);
mpeg2_buffer(_mpegDecoder, _buffer, _buffer + size);
break;
case STATE_SLICE:
case STATE_END:
foundFrame = true;
_curFrame++;
if (_mpegInfo->display_fbuf) {
const mpeg2_sequence_t *sequence = _mpegInfo->sequence;
_nextFrameStartTime = _nextFrameStartTime.addFrames(sequence->frame_period);
YUVToRGBMan.convert420(_surface, Graphics::YUVToRGBManager::kScaleITU, _mpegInfo->display_fbuf->buf[0],
_mpegInfo->display_fbuf->buf[1], _mpegInfo->display_fbuf->buf[2], sequence->picture_width,
sequence->picture_height, sequence->width, sequence->chroma_width);
}
break;
default:
break;
}
} while (size != 0);
#endif
delete packet;
#ifdef USE_MPEG2
return foundFrame;
#else
return true;
#endif
}
void MPEGPSDecoder::MPEGVideoTrack::findDimensions(Common::SeekableReadStream *firstPacket, const Graphics::PixelFormat &format) {
// First, check for the picture start code
if (firstPacket->readUint32BE() != 0x1B3)
error("Failed to detect MPEG sequence start");
// This is part of the bitstream, but there's really no purpose
// to use Common::BitStream just for this: 12 bits width, 12 bits
// height
uint16 width = firstPacket->readByte() << 4;
uint16 height = firstPacket->readByte();
width |= (height & 0xF0) >> 4;
height = ((height & 0xF) << 8) | firstPacket->readByte();
debug(0, "MPEG dimensions: %dx%d", width, height);
_surface = new Graphics::Surface();
_surface->create(width, height, format);
firstPacket->seek(0);
}
#ifdef USE_MAD
// The audio code here is almost entirely based on what we do in mp3.cpp
MPEGPSDecoder::MPEGAudioTrack::MPEGAudioTrack(Common::SeekableReadStream *firstPacket) {
// The MAD_BUFFER_GUARD must always contain zeros (the reason
// for this is that the Layer III Huffman decoder of libMAD
// may read a few bytes beyond the end of the input buffer).
memset(_buf + BUFFER_SIZE, 0, MAD_BUFFER_GUARD);
_state = MP3_STATE_INIT;
_audStream = 0;
// Find out our audio parameters
initStream(firstPacket);
while (_state != MP3_STATE_EOS)
readHeader(firstPacket);
_audStream = Audio::makeQueuingAudioStream(_frame.header.samplerate, MAD_NCHANNELS(&_frame.header) == 2);
deinitStream();
firstPacket->seek(0);
_state = MP3_STATE_INIT;
}
MPEGPSDecoder::MPEGAudioTrack::~MPEGAudioTrack() {
deinitStream();
delete _audStream;
}
static inline int scaleSample(mad_fixed_t sample) {
// round
sample += (1L << (MAD_F_FRACBITS - 16));
// clip
if (sample > MAD_F_ONE - 1)
sample = MAD_F_ONE - 1;
else if (sample < -MAD_F_ONE)
sample = -MAD_F_ONE;
// quantize and scale to not saturate when mixing a lot of channels
return sample >> (MAD_F_FRACBITS + 1 - 16);
}
bool MPEGPSDecoder::MPEGAudioTrack::sendPacket(Common::SeekableReadStream *packet, uint32 pts, uint32 dts) {
while (_state != MP3_STATE_EOS)
decodeMP3Data(packet);
_state = MP3_STATE_READY;
delete packet;
return true;
}
Audio::AudioStream *MPEGPSDecoder::MPEGAudioTrack::getAudioStream() const {
return _audStream;
}
void MPEGPSDecoder::MPEGAudioTrack::initStream(Common::SeekableReadStream *packet) {
if (_state != MP3_STATE_INIT)
deinitStream();
// Init MAD
mad_stream_init(&_stream);
mad_frame_init(&_frame);
mad_synth_init(&_synth);
// Reset the stream data
packet->seek(0, SEEK_SET);
// Update state
_state = MP3_STATE_READY;
// Read the first few sample bytes
readMP3Data(packet);
}
void MPEGPSDecoder::MPEGAudioTrack::deinitStream() {
if (_state == MP3_STATE_INIT)
return;
// Deinit MAD
mad_synth_finish(&_synth);
mad_frame_finish(&_frame);
mad_stream_finish(&_stream);
_state = MP3_STATE_EOS;
}
void MPEGPSDecoder::MPEGAudioTrack::readMP3Data(Common::SeekableReadStream *packet) {
uint32 remaining = 0;
// Give up immediately if we already used up all data in the stream
if (packet->eos()) {
_state = MP3_STATE_EOS;
return;
}
if (_stream.next_frame) {
// If there is still data in the MAD stream, we need to preserve it.
// Note that we use memmove, as we are reusing the same buffer,
// and hence the data regions we copy from and to may overlap.
remaining = _stream.bufend - _stream.next_frame;
assert(remaining < BUFFER_SIZE); // Paranoia check
memmove(_buf, _stream.next_frame, remaining);
}
memset(_buf + remaining, 0, BUFFER_SIZE - remaining);
// Try to read the next block
uint32 size = packet->read(_buf + remaining, BUFFER_SIZE - remaining);
if (size == 0) {
_state = MP3_STATE_EOS;
return;
}
// Feed the data we just read into the stream decoder
_stream.error = MAD_ERROR_NONE;
mad_stream_buffer(&_stream, _buf, size + remaining);
}
void MPEGPSDecoder::MPEGAudioTrack::readHeader(Common::SeekableReadStream *packet) {
if (_state != MP3_STATE_READY)
return;
// If necessary, load more data into the stream decoder
if (_stream.error == MAD_ERROR_BUFLEN)
readMP3Data(packet);
while (_state != MP3_STATE_EOS) {
_stream.error = MAD_ERROR_NONE;
// Decode the next header. Note: mad_frame_decode would do this for us, too.
// However, for seeking we don't want to decode the full frame (else it would
// be far too slow). Hence we perform this explicitly in a separate step.
if (mad_header_decode(&_frame.header, &_stream) == -1) {
if (_stream.error == MAD_ERROR_BUFLEN) {
readMP3Data(packet); // Read more data
continue;
} else if (MAD_RECOVERABLE(_stream.error)) {
debug(6, "MPEGAudioTrack::readHeader(): Recoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream));
continue;
} else {
warning("MPEGAudioTrack::readHeader(): Unrecoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream));
break;
}
}
break;
}
if (_stream.error != MAD_ERROR_NONE)
_state = MP3_STATE_EOS;
}
void MPEGPSDecoder::MPEGAudioTrack::decodeMP3Data(Common::SeekableReadStream *packet) {
if (_state == MP3_STATE_INIT)
initStream(packet);
if (_state == MP3_STATE_EOS)
return;
do {
// If necessary, load more data into the stream decoder
if (_stream.error == MAD_ERROR_BUFLEN)
readMP3Data(packet);
while (_state == MP3_STATE_READY) {
_stream.error = MAD_ERROR_NONE;
// Decode the next frame
if (mad_frame_decode(&_frame, &_stream) == -1) {
if (_stream.error == MAD_ERROR_BUFLEN) {
break; // Read more data
} else if (MAD_RECOVERABLE(_stream.error)) {
// Note: we will occasionally see MAD_ERROR_BADDATAPTR errors here.
// These are normal and expected (caused by our frame skipping (i.e. "seeking")
// code above).
debug(6, "MPEGAudioTrack::decodeMP3Data(): Recoverable error in mad_frame_decode (%s)", mad_stream_errorstr(&_stream));
continue;
} else {
warning("MPEGAudioTrack::decodeMP3Data(): Unrecoverable error in mad_frame_decode (%s)", mad_stream_errorstr(&_stream));
break;
}
}
// Synthesize PCM data
mad_synth_frame(&_synth, &_frame);
// Output it to our queue
if (_synth.pcm.length != 0) {
byte *buffer = (byte *)malloc(_synth.pcm.length * 2 * MAD_NCHANNELS(&_frame.header));
int16 *ptr = (int16 *)buffer;
for (int i = 0; i < _synth.pcm.length; i++) {
*ptr++ = (int16)scaleSample(_synth.pcm.samples[0][i]);
if (MAD_NCHANNELS(&_frame.header) == 2)
*ptr++ = (int16)scaleSample(_synth.pcm.samples[1][i]);
}
int flags = Audio::FLAG_16BITS;
if (_audStream->isStereo())
flags |= Audio::FLAG_STEREO;
#ifdef SCUMM_LITTLE_ENDIAN
flags |= Audio::FLAG_LITTLE_ENDIAN;
#endif
_audStream->queueBuffer(buffer, _synth.pcm.length * 2 * MAD_NCHANNELS(&_frame.header), DisposeAfterUse::YES, flags);
}
break;
}
} while (_state != MP3_STATE_EOS && _stream.error == MAD_ERROR_BUFLEN);
if (_stream.error != MAD_ERROR_NONE)
_state = MP3_STATE_EOS;
}
#endif
MPEGPSDecoder::PS2AudioTrack::PS2AudioTrack(Common::SeekableReadStream *firstPacket) {
firstPacket->seek(12); // unknown data (4), 'SShd', header size (4)
_soundType = firstPacket->readUint32LE();
if (_soundType == PS2_ADPCM)
error("Unhandled PS2 ADPCM sound in MPEG-PS video");
else if (_soundType != PS2_PCM)
error("Unknown PS2 sound type %x", _soundType);
uint32 sampleRate = firstPacket->readUint32LE();
_channels = firstPacket->readUint32LE();
_interleave = firstPacket->readUint32LE();
_blockBuffer = new byte[_interleave * _channels];
_blockPos = _blockUsed = 0;
_audStream = Audio::makeQueuingAudioStream(sampleRate, _channels == 2);
_isFirstPacket = true;
firstPacket->seek(0);
}
MPEGPSDecoder::PS2AudioTrack::~PS2AudioTrack() {
delete[] _blockBuffer;
delete _audStream;
}
bool MPEGPSDecoder::PS2AudioTrack::sendPacket(Common::SeekableReadStream *packet, uint32 pts, uint32 dts) {
packet->skip(4);
if (_isFirstPacket) {
// Skip over the header which we already parsed
packet->skip(4);
packet->skip(packet->readUint32LE());
if (packet->readUint32BE() != MKTAG('S', 'S', 'b', 'd'))
error("Failed to find 'SSbd' tag");
packet->readUint32LE(); // body size
_isFirstPacket = false;
}
uint32 size = packet->size() - packet->pos();
uint32 bytesPerChunk = _interleave * _channels;
uint32 sampleCount = calculateSampleCount(size);
byte *buffer = (byte *)malloc(sampleCount * 2);
int16 *ptr = (int16 *)buffer;
// Handle any full chunks first
while (size >= bytesPerChunk) {
packet->read(_blockBuffer + _blockPos, bytesPerChunk - _blockPos);
size -= bytesPerChunk - _blockPos;
_blockPos = 0;
for (uint32 i = _blockUsed; i < _interleave / 2; i++)
for (uint32 j = 0; j < _channels; j++)
*ptr++ = READ_UINT16(_blockBuffer + i * 2 + j * _interleave);
_blockUsed = 0;
}
// Then fallback on loading any leftover
if (size > 0) {
packet->read(_blockBuffer, size);
_blockPos = size;
if (size > (_channels - 1) * _interleave) {
_blockUsed = (size - (_channels - 1) * _interleave) / 2;
for (uint32 i = 0; i < _blockUsed; i++)
for (uint32 j = 0; j < _channels; j++)
*ptr++ = READ_UINT16(_blockBuffer + i * 2 + j * _interleave);
}
}
byte flags = Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN;
if (_audStream->isStereo())
flags |= Audio::FLAG_STEREO;
_audStream->queueBuffer((byte *)buffer, sampleCount * 2, DisposeAfterUse::YES, flags);
delete packet;
return true;
}
Audio::AudioStream *MPEGPSDecoder::PS2AudioTrack::getAudioStream() const {
return _audStream;
}
uint32 MPEGPSDecoder::PS2AudioTrack::calculateSampleCount(uint32 packetSize) const {
uint32 bytesPerChunk = _interleave * _channels, result = 0;
// If we have a partial block, subtract the remainder from the size. That
// gets put towards reading the partial block
if (_blockPos != 0) {
packetSize -= bytesPerChunk - _blockPos;
result += (_interleave / 2) - _blockUsed;
}
// Round the number of whole chunks down and then calculate how many samples that gives us
result += (packetSize / bytesPerChunk) * _interleave / 2;
// Total up anything we can get from the remainder
packetSize %= bytesPerChunk;
if (packetSize > (_channels - 1) * _interleave)
result += (packetSize - (_channels - 1) * _interleave) / 2;
return result * _channels;
}
} // End of namespace Video