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


Generated on Sat May 25 2019 05:00:50 for ResidualVM by doxygen 1.7.1
curved edge   curved edge