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

mpegps_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 "audio/audiostream.h"
00024 #include "audio/decoders/raw.h" // ResidualVM
00025 #include "audio/decoders/ac3.h"
00026 #include "audio/decoders/mp3.h"
00027 #include "common/debug.h"
00028 #include "common/endian.h"
00029 #include "common/stream.h"
00030 #include "common/memstream.h" // ResidualVM
00031 #include "common/system.h"
00032 #include "common/textconsole.h"
00033 
00034 #include "video/mpegps_decoder.h"
00035 #include "image/codecs/mpeg.h"
00036 
00037 // The demuxing code is based on libav's demuxing code
00038 
00039 namespace Video {
00040 
00041 // --------------------------------------------------------------------------
00042 // Decoder - This is the part that takes a packet and figures out what to do
00043 // with it.
00044 // --------------------------------------------------------------------------
00045 
00046 enum {
00047     kStartCodePack = 0x1BA,
00048     kStartCodeSystemHeader = 0x1BB,
00049     kStartCodeProgramStreamMap = 0x1BC,
00050     kStartCodePrivateStream1 = 0x1BD,
00051     kStartCodePaddingStream = 0x1BE,
00052     kStartCodePrivateStream2 = 0x1BF
00053 };
00054 
00055 MPEGPSDecoder::MPEGPSDecoder(double decibel) {
00056     _decibel = decibel;
00057     _demuxer = new MPEGPSDemuxer();
00058 }
00059 
00060 MPEGPSDecoder::~MPEGPSDecoder() {
00061     close();
00062     delete _demuxer;
00063 }
00064 
00065 bool MPEGPSDecoder::loadStream(Common::SeekableReadStream *stream) {
00066     close();
00067 
00068     if (!_demuxer->loadStream(stream)) {
00069         close();
00070         return false;
00071     }
00072 
00073     if (!addFirstVideoTrack()) {
00074         close();
00075         return false;
00076     }
00077 
00078     return true;
00079 }
00080 
00081 void MPEGPSDecoder::close() {
00082     VideoDecoder::close();
00083     _demuxer->close();
00084     _streamMap.clear();
00085 }
00086 
00087 MPEGPSDecoder::MPEGStream *MPEGPSDecoder::getStream(uint32 startCode, Common::SeekableReadStream *packet) {
00088     MPEGStream *stream = 0;
00089 
00090     if (_streamMap.contains(startCode)) {
00091         // We already found the stream
00092         stream = _streamMap[startCode];
00093     } else {
00094         // We haven't seen this before
00095 
00096         if (startCode == kStartCodePrivateStream1) {
00097             PrivateStreamType streamType = detectPrivateStreamType(packet);
00098             packet->seek(0);
00099 
00100             // TODO: Handling of these types (as needed)
00101             bool handled = false;
00102             const char *typeName;
00103 
00104             switch (streamType) {
00105             case kPrivateStreamAC3: {
00106                 typeName = "AC-3";
00107 
00108 #ifdef USE_A52
00109                 handled = true;
00110                 AC3AudioTrack *ac3Track = new AC3AudioTrack(*packet, _decibel, getSoundType());
00111                 stream = ac3Track;
00112                 _streamMap[startCode] = ac3Track;
00113                 addTrack(ac3Track);
00114 #endif
00115                 break;
00116             }
00117             case kPrivateStreamDTS:
00118                 typeName = "DTS";
00119                 break;
00120             case kPrivateStreamDVDPCM:
00121                 typeName = "DVD PCM";
00122                 break;
00123             // ResidualVM start
00124             case kPrivateStreamPS2Audio: {
00125                 typeName = "PS2 Audio";
00126 
00127                 handled = true;
00128                 PS2AudioTrack *audioTrack = new PS2AudioTrack(packet, getSoundType());
00129                 stream = audioTrack;
00130                 _streamMap[startCode] = audioTrack;
00131                 addTrack(audioTrack);
00132                 break;
00133             }
00134             // ResidualVM end
00135             default:
00136                 typeName = "Unknown";
00137                 break;
00138             }
00139 
00140             if (!handled) {
00141                 warning("Unhandled DVD private stream: %s", typeName);
00142 
00143                 // Make it 0 so we don't get the warning twice
00144                 _streamMap[startCode] = 0;
00145             }
00146         } else if (startCode >= 0x1E0 && startCode <= 0x1EF) {
00147             // Video stream
00148             // TODO: Multiple video streams
00149             warning("Found extra video stream 0x%04X", startCode);
00150             _streamMap[startCode] = 0;
00151         } else if (startCode >= 0x1C0 && startCode <= 0x1DF) {
00152 #ifdef USE_MAD
00153             // MPEG Audio stream
00154             MPEGAudioTrack *audioTrack = new MPEGAudioTrack(*packet, getSoundType());
00155             stream = audioTrack;
00156             _streamMap[startCode] = audioTrack;
00157             addTrack(audioTrack);
00158 #else
00159             warning("Found audio stream 0x%04X, but no MAD support compiled in", startCode);
00160             _streamMap[startCode] = 0;
00161 #endif
00162         } else {
00163             // Probably not relevant
00164             debug(0, "Found unhandled MPEG-PS stream type 0x%04x", startCode);
00165             _streamMap[startCode] = 0;
00166         }
00167     }
00168 
00169     return stream;
00170 }
00171 
00172 void MPEGPSDecoder::readNextPacket() {
00173     for (;;) {
00174         int32 startCode;
00175         uint32 pts, dts;
00176         Common::SeekableReadStream *packet = _demuxer->getNextPacket(getTime(), startCode, pts, dts);
00177 
00178         if (!packet) {
00179             // End of stream
00180             for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++)
00181                 if ((*it)->getTrackType() == Track::kTrackTypeVideo)
00182                     ((MPEGVideoTrack *)*it)->setEndOfTrack();
00183             return;
00184         }
00185 
00186         MPEGStream *stream = getStream(startCode, packet);
00187 
00188         if (stream) {
00189             packet->seek(0);
00190 
00191             bool done = stream->sendPacket(packet, pts, dts);
00192 
00193             if (done && stream->getStreamType() == MPEGStream::kStreamTypeVideo)
00194                 return;
00195         } else {
00196             delete packet;
00197         }
00198     }
00199 }
00200 
00201 bool MPEGPSDecoder::addFirstVideoTrack() {
00202     int32 startCode;
00203     uint32 pts, dts;
00204     Common::SeekableReadStream *packet = _demuxer->getFirstVideoPacket(startCode, pts, dts);
00205 
00206     if (!packet)
00207         return false;
00208 
00209     // Video stream
00210     // Can be MPEG-1/2 or MPEG-4/h.264. We'll assume the former and
00211     // I hope we never need the latter.
00212     MPEGVideoTrack *track = new MPEGVideoTrack(packet, getDefaultHighColorFormat());
00213     addTrack(track);
00214     _streamMap[startCode] = track;
00215 
00216     return true;
00217 }
00218 
00219 MPEGPSDecoder::PrivateStreamType MPEGPSDecoder::detectPrivateStreamType(Common::SeekableReadStream *packet) {
00220     uint32 dvdCode = packet->readUint32LE();
00221     if (packet->eos())
00222         return kPrivateStreamUnknown;
00223 
00224     uint32 ps2Header = packet->readUint32BE();
00225     if (!packet->eos() && ps2Header == MKTAG('S', 'S', 'h', 'd'))
00226         return kPrivateStreamPS2Audio;
00227 
00228     switch (dvdCode & 0xE0) {
00229     case 0x80:
00230         if ((dvdCode & 0xF8) == 0x88)
00231             return kPrivateStreamDTS;
00232 
00233         return kPrivateStreamAC3;
00234     case 0xA0:
00235         return kPrivateStreamDVDPCM;
00236     }
00237 
00238     return kPrivateStreamUnknown;
00239 }
00240 
00241 // --------------------------------------------------------------------------
00242 // Demuxer - This is the part that reads packets from the stream and delivers
00243 // them to the decoder.
00244 //
00245 // It will buffer a number of packets in advance, because otherwise it may
00246 // not encounter any audio packets until it's far too late to decode them.
00247 // Before I added this, there would be 9 or 10 frames of video before the
00248 // first audio packet, even though the timestamp indicated that the audio
00249 // should start slightly before the video.
00250 // --------------------------------------------------------------------------
00251 
00252 #define PREBUFFERED_PACKETS 150
00253 #define AUDIO_THRESHOLD     100
00254 
00255 MPEGPSDecoder::MPEGPSDemuxer::MPEGPSDemuxer() {
00256     _stream = 0;
00257 }
00258 
00259 MPEGPSDecoder::MPEGPSDemuxer::~MPEGPSDemuxer() {
00260     close();
00261 }
00262 
00263 bool MPEGPSDecoder::MPEGPSDemuxer::loadStream(Common::SeekableReadStream *stream) {
00264     close();
00265 
00266     _stream = stream;
00267 
00268     int queuedPackets = 0;
00269     while (queueNextPacket() && queuedPackets < PREBUFFERED_PACKETS) {
00270         queuedPackets++;
00271     }
00272 
00273     return true;
00274 }
00275 
00276 void MPEGPSDecoder::MPEGPSDemuxer::close() {
00277     delete _stream;
00278     _stream = 0;
00279 
00280     while (!_audioQueue.empty()) {
00281         Packet packet = _audioQueue.pop();
00282         delete packet._stream;
00283     }
00284 
00285     while (!_videoQueue.empty()) {
00286         Packet packet = _videoQueue.pop();
00287         delete packet._stream;
00288     }
00289 }
00290 
00291 Common::SeekableReadStream *MPEGPSDecoder::MPEGPSDemuxer::getFirstVideoPacket(int32 &startCode, uint32 &pts, uint32 &dts) {
00292     if (_videoQueue.empty())
00293         return nullptr;
00294     Packet packet = _videoQueue.front();
00295     startCode = packet._startCode;
00296     pts = packet._pts;
00297     dts = packet._dts;
00298     return packet._stream;
00299 }
00300 
00301 Common::SeekableReadStream *MPEGPSDecoder::MPEGPSDemuxer::getNextPacket(uint32 currentTime, int32 &startCode, uint32 &pts, uint32 &dts) {
00302     queueNextPacket();
00303 
00304     // The idea here is to prioritize the delivery of audio packets,
00305     // because when the decoder wants a frame it will keep asking until it
00306     // gets a frame. There is nothing like that in the decoder to ensure
00307     // speedy delivery of audio.
00308 
00309     if (!_audioQueue.empty()) {
00310         Packet packet = _audioQueue.front();
00311         bool usePacket = false;
00312 
00313         if (packet._pts == 0xFFFFFFFF) {
00314             // No timestamp? Use it just in case. This could be a 
00315             // bad idea, but in my tests all audio packets have a
00316             // time stamp.
00317             usePacket = true;
00318         } else {
00319             uint32 packetTime = packet._pts / 90;
00320             if (packetTime <= currentTime || packetTime - currentTime < AUDIO_THRESHOLD || _videoQueue.empty()) {
00321                 // The packet is overdue, or will be soon.
00322                 //
00323                 // TODO: We should pad or trim the first audio
00324                 // packet based on the timestamp to get the
00325                 // audio to start at the exact desired time.
00326                 // But for some reason it seems to work well
00327                 // enough anyway. For now.
00328                 usePacket = true;
00329             }
00330         }
00331 
00332         if (usePacket) {
00333             _audioQueue.pop();
00334             startCode = packet._startCode;
00335             pts = packet._pts;
00336             dts = packet._dts;
00337             return packet._stream;
00338         }
00339     }
00340 
00341     if (!_videoQueue.empty()) {
00342         Packet packet = _videoQueue.pop();
00343         startCode = packet._startCode;
00344         pts = packet._pts;
00345         dts = packet._dts;
00346         return packet._stream;
00347     }
00348 
00349     return nullptr;
00350 }
00351 
00352 bool MPEGPSDecoder::MPEGPSDemuxer::queueNextPacket() {
00353     if (_stream->eos())
00354         return false;
00355 
00356     for (;;) {
00357         int32 startCode;
00358         uint32 pts, dts;
00359         int size = readNextPacketHeader(startCode, pts, dts);
00360 
00361         if (size < 0) {
00362             // End of stream
00363             return false;
00364         }
00365 
00366         Common::SeekableReadStream *stream = _stream->readStream(size);
00367 
00368         if (startCode == kStartCodePrivateStream1 || (startCode >= 0x1C0 && startCode <= 0x1DF)) {
00369             // Audio packet
00370             _audioQueue.push(Packet(stream, startCode, pts, dts));
00371             return true;
00372         }
00373 
00374         if (startCode >= 0x1E0 && startCode <= 0x1EF) {
00375             // Video packet
00376             _videoQueue.push(Packet(stream, startCode, pts, dts));
00377             return true;
00378         }
00379 
00380         delete _stream;
00381     }
00382 }
00383 
00384 int MPEGPSDecoder::MPEGPSDemuxer::readNextPacketHeader(int32 &startCode, uint32 &pts, uint32 &dts) {
00385     for (;;) {
00386         uint32 size;
00387         startCode = findNextStartCode(size);
00388 
00389         if (_stream->eos())
00390             return -1;
00391 
00392         if (startCode < 0)
00393             continue;
00394 
00395         uint32 lastSync = _stream->pos();
00396 
00397         if (startCode == kStartCodePack || startCode == kStartCodeSystemHeader)
00398             continue;
00399 
00400         int length = _stream->readUint16BE();
00401 
00402         if (startCode == kStartCodePaddingStream || startCode == kStartCodePrivateStream2) {
00403             _stream->skip(length);
00404             continue;
00405         }
00406 
00407         if (startCode == kStartCodeProgramStreamMap) {
00408             parseProgramStreamMap(length);
00409             continue;
00410         }
00411 
00412         // Find matching stream
00413         if (!((startCode >= 0x1C0 && startCode <= 0x1DF) ||
00414                 (startCode >= 0x1E0 && startCode <= 0x1EF) ||
00415                 startCode == kStartCodePrivateStream1 || startCode == 0x1FD))
00416             continue;
00417 
00418         // Stuffing
00419         byte c;
00420         for (;;) {
00421             if (length < 1) {
00422                 _stream->seek(lastSync);
00423                 continue;
00424             }
00425 
00426             c = _stream->readByte();
00427             length--;
00428 
00429             // XXX: for mpeg1, should test only bit 7
00430             if (c != 0xFF)
00431                 break;
00432         }
00433 
00434         if ((c & 0xC0) == 0x40) {
00435             // Buffer scale and size
00436             _stream->readByte();
00437             c = _stream->readByte();
00438             length -= 2;
00439         }
00440 
00441         pts = 0xFFFFFFFF;
00442         dts = 0xFFFFFFFF;
00443 
00444         if ((c & 0xE0) == 0x20) {
00445             dts = pts = readPTS(c);
00446             length -= 4;
00447 
00448             if (c & 0x10) {
00449                 dts = readPTS(-1);
00450                 length -= 5;
00451             }
00452         } else if ((c & 0xC0) == 0x80) {
00453             // MPEG-2 PES
00454             byte flags = _stream->readByte();
00455             int headerLength = _stream->readByte();
00456             length -= 2;
00457 
00458             if (headerLength > length) {
00459                 _stream->seek(lastSync);
00460                 continue;
00461             }
00462 
00463             length -= headerLength;
00464 
00465             if (flags & 0x80) {
00466                 dts = pts = readPTS(-1);
00467                 headerLength -= 5;
00468 
00469                 if (flags & 0x40) {
00470                     dts = readPTS(-1);
00471                     headerLength -= 5;
00472                 }
00473             }
00474 
00475             if (flags & 0x3F && headerLength == 0) {
00476                 flags &= 0xC0;
00477                 warning("Further flags set but no bytes left");
00478             }
00479 
00480             if (flags & 0x01) { // PES extension
00481                 byte pesExt =_stream->readByte();
00482                 headerLength--;
00483 
00484                 // Skip PES private data, program packet sequence
00485                 int skip = (pesExt >> 4) & 0xB;
00486                 skip += skip & 0x9;
00487 
00488                 if (pesExt & 0x40 || skip > headerLength) {
00489                     warning("pesExt %x is invalid", pesExt);
00490                     pesExt = skip = 0;
00491                 } else {
00492                     _stream->skip(skip);
00493                     headerLength -= skip;
00494                 }
00495 
00496                 if (pesExt & 0x01) { // PES extension 2
00497                     byte ext2Length = _stream->readByte();
00498                     headerLength--;
00499 
00500                     if ((ext2Length & 0x7F) != 0) {
00501                         byte idExt = _stream->readByte();
00502 
00503                         if ((idExt & 0x80) == 0)
00504                             startCode = (startCode & 0xFF) << 8;
00505 
00506                         headerLength--;
00507                     }
00508                 }
00509             }
00510 
00511             if (headerLength < 0) {
00512                 _stream->seek(lastSync);
00513                 continue;
00514             }
00515 
00516             _stream->skip(headerLength);
00517         } else if (c != 0xF) {
00518             continue;
00519         }
00520 
00521         if (length < 0) {
00522             _stream->seek(lastSync);
00523             continue;
00524         }
00525 
00526         return length;
00527     }
00528 }
00529 
00530 #define MAX_SYNC_SIZE 100000
00531 
00532 int MPEGPSDecoder::MPEGPSDemuxer::findNextStartCode(uint32 &size) {
00533     size = MAX_SYNC_SIZE;
00534     int32 state = 0xFF;
00535 
00536     while (size > 0) {
00537         byte v = _stream->readByte();
00538 
00539         if (_stream->eos())
00540             return -1;
00541 
00542         size--;
00543 
00544         if (state == 0x1)
00545             return ((state << 8) | v) & 0xFFFFFF;
00546 
00547         state = ((state << 8) | v) & 0xFFFFFF;
00548     }
00549 
00550     return -1;
00551 }
00552 
00553 uint32 MPEGPSDecoder::MPEGPSDemuxer::readPTS(int c) {
00554     byte buf[5];
00555 
00556     buf[0] = (c < 0) ? _stream->readByte() : c;
00557     _stream->read(buf + 1, 4);
00558 
00559     return ((buf[0] & 0x0E) << 29) | ((READ_BE_UINT16(buf + 1) >> 1) << 15) | (READ_BE_UINT16(buf + 3) >> 1);
00560 }
00561 
00562 void MPEGPSDecoder::MPEGPSDemuxer::parseProgramStreamMap(int length) {
00563     _stream->readByte();
00564     _stream->readByte();
00565 
00566     // skip program stream info
00567     _stream->skip(_stream->readUint16BE());
00568 
00569     int esMapLength = _stream->readUint16BE();
00570 
00571     while (esMapLength >= 4) {
00572         _stream->readByte(); // type
00573         _stream->readByte(); // esID
00574         uint16 esInfoLength = _stream->readUint16BE();
00575 
00576         // Skip program stream info
00577         _stream->skip(esInfoLength);
00578 
00579         esMapLength -= 4 + esInfoLength;
00580     }
00581 
00582     _stream->readUint32BE(); // CRC32
00583 }
00584 
00585 // --------------------------------------------------------------------------
00586 // Video track
00587 // --------------------------------------------------------------------------
00588 
00589 MPEGPSDecoder::MPEGVideoTrack::MPEGVideoTrack(Common::SeekableReadStream *firstPacket, const Graphics::PixelFormat &format) {
00590     _surface = 0;
00591     _endOfTrack = false;
00592     _curFrame = -1;
00593     _framePts = 0xFFFFFFFF;
00594     _nextFrameStartTime = Audio::Timestamp(0, 27000000); // 27 MHz timer
00595 
00596     findDimensions(firstPacket, format);
00597 
00598 #ifdef USE_MPEG2
00599     _mpegDecoder = new Image::MPEGDecoder();
00600 #endif
00601 }
00602 
00603 MPEGPSDecoder::MPEGVideoTrack::~MPEGVideoTrack() {
00604 #ifdef USE_MPEG2
00605     delete _mpegDecoder;
00606 #endif
00607 
00608     if (_surface) {
00609         _surface->free();
00610         delete _surface;
00611     }
00612 }
00613 
00614 uint16 MPEGPSDecoder::MPEGVideoTrack::getWidth() const {
00615     return _surface ? _surface->w : 0;
00616 }
00617 
00618 uint16 MPEGPSDecoder::MPEGVideoTrack::getHeight() const {
00619     return _surface ? _surface->h : 0;
00620 }
00621 
00622 Graphics::PixelFormat MPEGPSDecoder::MPEGVideoTrack::getPixelFormat() const {
00623     if (!_surface)
00624         return Graphics::PixelFormat();
00625 
00626     return _surface->format;
00627 }
00628 
00629 const Graphics::Surface *MPEGPSDecoder::MPEGVideoTrack::decodeNextFrame() {
00630     return _surface;
00631 }
00632 
00633 bool MPEGPSDecoder::MPEGVideoTrack::sendPacket(Common::SeekableReadStream *packet, uint32 pts, uint32 dts) {
00634 #ifdef USE_MPEG2
00635     if (pts != 0xFFFFFFFF) {
00636         _framePts = pts;
00637     }
00638 
00639     uint32 framePeriod;
00640     bool foundFrame = _mpegDecoder->decodePacket(*packet, framePeriod, _surface);
00641 
00642     if (foundFrame) {
00643         _curFrame++;
00644 
00645         // If there has been a timestamp since the previous frame, use that for
00646         // syncing. Usually it will be the timestamp from the current packet,
00647         // but it might not be.
00648 
00649         if (_framePts != 0xFFFFFFFF) {
00650             _nextFrameStartTime = Audio::Timestamp(_framePts / 90, 27000000);
00651         } else {
00652             _nextFrameStartTime = _nextFrameStartTime.addFrames(framePeriod);
00653         }
00654 
00655         _framePts = 0xFFFFFFFF;
00656     }
00657 #endif
00658 
00659     delete packet;
00660 
00661 #ifdef USE_MPEG2
00662     return foundFrame;
00663 #else
00664     return true;
00665 #endif
00666 }
00667 
00668 void MPEGPSDecoder::MPEGVideoTrack::findDimensions(Common::SeekableReadStream *firstPacket, const Graphics::PixelFormat &format) {
00669     // First, check for the picture start code
00670     if (firstPacket->readUint32BE() != 0x1B3)
00671         error("Failed to detect MPEG sequence start");
00672 
00673     // This is part of the bitstream, but there's really no purpose
00674     // to use Common::BitStream just for this: 12 bits width, 12 bits
00675     // height
00676     uint16 width = firstPacket->readByte() << 4;
00677     uint16 height = firstPacket->readByte();
00678     width |= (height & 0xF0) >> 4;
00679     height = ((height & 0x0F) << 8) | firstPacket->readByte();
00680 
00681     debug(0, "MPEG dimensions: %dx%d", width, height);
00682 
00683     _surface = new Graphics::Surface();
00684     _surface->create(width, height, format);
00685 
00686     firstPacket->seek(0);
00687 }
00688 
00689 // --------------------------------------------------------------------------
00690 // Audio track
00691 // --------------------------------------------------------------------------
00692 
00693 #ifdef USE_MAD
00694 
00695 // The audio code here is almost entirely based on what we do in mp3.cpp
00696 
00697 MPEGPSDecoder::MPEGAudioTrack::MPEGAudioTrack(Common::SeekableReadStream &firstPacket, Audio::Mixer::SoundType soundType) :
00698         AudioTrack(soundType) {
00699     _audStream = Audio::makePacketizedMP3Stream(firstPacket);
00700 }
00701 
00702 MPEGPSDecoder::MPEGAudioTrack::~MPEGAudioTrack() {
00703     delete _audStream;
00704 }
00705 
00706 bool MPEGPSDecoder::MPEGAudioTrack::sendPacket(Common::SeekableReadStream *packet, uint32 pts, uint32 dts) {
00707     _audStream->queuePacket(packet);
00708     return true;
00709 }
00710 
00711 Audio::AudioStream *MPEGPSDecoder::MPEGAudioTrack::getAudioStream() const {
00712     return _audStream;
00713 }
00714 
00715 #endif
00716 
00717 #ifdef USE_A52
00718 
00719 MPEGPSDecoder::AC3AudioTrack::AC3AudioTrack(Common::SeekableReadStream &firstPacket, double decibel, Audio::Mixer::SoundType soundType) :
00720         AudioTrack(soundType) {
00721     _audStream = Audio::makeAC3Stream(firstPacket, decibel);
00722     if (!_audStream)
00723         error("Could not create AC-3 stream");
00724 }
00725 
00726 MPEGPSDecoder::AC3AudioTrack::~AC3AudioTrack() {
00727     delete _audStream;
00728 }
00729 
00730 bool MPEGPSDecoder::AC3AudioTrack::sendPacket(Common::SeekableReadStream *packet, uint32 pts, uint32 dts) {
00731     // Skip DVD code
00732     packet->readUint32LE();
00733     if (packet->eos())
00734         return true;
00735 
00736     _audStream->queuePacket(packet);
00737     return true;
00738 }
00739 
00740 Audio::AudioStream *MPEGPSDecoder::AC3AudioTrack::getAudioStream() const {
00741     return _audStream;
00742 }
00743 
00744 #endif
00745 
00746 // ResidualVM specific start
00747 MPEGPSDecoder::PS2AudioTrack::PS2AudioTrack(Common::SeekableReadStream *firstPacket, Audio::Mixer::SoundType soundType) :
00748         AudioTrack(soundType) {
00749     firstPacket->seek(12); // unknown data (4), 'SShd', header size (4)
00750 
00751     _soundType = firstPacket->readUint32LE();
00752 
00753     if (_soundType == PS2_ADPCM)
00754         error("Unhandled PS2 ADPCM sound in MPEG-PS video");
00755     else if (_soundType != PS2_PCM)
00756         error("Unknown PS2 sound type %x", _soundType);
00757 
00758     uint32 sampleRate = firstPacket->readUint32LE();
00759     _channels = firstPacket->readUint32LE();
00760     _interleave = firstPacket->readUint32LE();
00761 
00762     byte flags = Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN;
00763     if (_channels == 2)
00764         flags |= Audio::FLAG_STEREO;
00765 
00766     _blockBuffer = new byte[_interleave * _channels];
00767     _blockPos = _blockUsed = 0;
00768     _audStream = Audio::makePacketizedRawStream(sampleRate, flags);
00769     _isFirstPacket = true;
00770 
00771     firstPacket->seek(0);
00772 }
00773 
00774 MPEGPSDecoder::PS2AudioTrack::~PS2AudioTrack() {
00775     delete[] _blockBuffer;
00776     delete _audStream;
00777 }
00778 
00779 bool MPEGPSDecoder::PS2AudioTrack::sendPacket(Common::SeekableReadStream *packet, uint32 pts, uint32 dts) {
00780     packet->skip(4);
00781 
00782     if (_isFirstPacket) {
00783         // Skip over the header which we already parsed
00784         packet->skip(4);
00785         packet->skip(packet->readUint32LE());
00786 
00787         if (packet->readUint32BE() != MKTAG('S', 'S', 'b', 'd'))
00788             error("Failed to find 'SSbd' tag");
00789 
00790         packet->readUint32LE(); // body size
00791         _isFirstPacket = false;
00792     }
00793 
00794     uint32 size = packet->size() - packet->pos();
00795     uint32 bytesPerChunk = _interleave * _channels;
00796     uint32 sampleCount = calculateSampleCount(size);
00797 
00798     byte *buffer = (byte *)malloc(sampleCount * 2);
00799     int16 *ptr = (int16 *)buffer;
00800 
00801     // Handle any full chunks first
00802     while (size >= bytesPerChunk) {
00803         packet->read(_blockBuffer + _blockPos, bytesPerChunk - _blockPos);
00804         size -= bytesPerChunk - _blockPos;
00805         _blockPos = 0;
00806 
00807         for (uint32 i = _blockUsed; i < _interleave / 2; i++)
00808             for (uint32 j = 0; j < _channels; j++)
00809                 *ptr++ = READ_UINT16(_blockBuffer + i * 2 + j * _interleave);
00810 
00811         _blockUsed = 0;
00812     }
00813 
00814     // Then fallback on loading any leftover
00815     if (size > 0) {
00816         packet->read(_blockBuffer, size);
00817         _blockPos = size;
00818 
00819         if (size > (_channels - 1) * _interleave) {
00820             _blockUsed = (size - (_channels - 1) * _interleave) / 2;
00821 
00822             for (uint32 i = 0; i < _blockUsed; i++)
00823                 for (uint32 j = 0; j < _channels; j++)
00824                     *ptr++ = READ_UINT16(_blockBuffer + i * 2 + j * _interleave);
00825         }
00826     }
00827 
00828     _audStream->queuePacket(new Common::MemoryReadStream(buffer, sampleCount * 2, DisposeAfterUse::YES));
00829 
00830     delete packet;
00831     return true;
00832 }
00833 
00834 Audio::AudioStream *MPEGPSDecoder::PS2AudioTrack::getAudioStream() const {
00835     return _audStream;
00836 }
00837 
00838 uint32 MPEGPSDecoder::PS2AudioTrack::calculateSampleCount(uint32 packetSize) const {
00839     uint32 bytesPerChunk = _interleave * _channels, result = 0;
00840 
00841     // If we have a partial block, subtract the remainder from the size. That
00842     // gets put towards reading the partial block
00843     if (_blockPos != 0) {
00844         packetSize -= bytesPerChunk - _blockPos;
00845         result += (_interleave / 2) - _blockUsed;
00846     }
00847 
00848     // Round the number of whole chunks down and then calculate how many samples that gives us
00849     result += (packetSize / bytesPerChunk) * _interleave / 2;
00850 
00851     // Total up anything we can get from the remainder
00852     packetSize %= bytesPerChunk;
00853     if (packetSize > (_channels - 1) * _interleave)
00854         result += (packetSize - (_channels - 1) * _interleave) / 2;
00855 
00856     return result * _channels;
00857 }
00858 // ResidualVM specific end
00859 
00860 } // End of namespace Video


Generated on Sat Nov 16 2019 05:00:52 for ResidualVM by doxygen 1.7.1
curved edge   curved edge