1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "audio/audiostream.h"
24 #include "audio/decoders/raw.h"
25 #include "audio/decoders/ac3.h"
26 #include "audio/decoders/mp3.h"
27 #include "common/debug.h"
28 #include "common/endian.h"
29 #include "common/stream.h"
30 #include "common/memstream.h"
31 #include "common/system.h"
32 #include "common/textconsole.h"
33
34 #include "video/mpegps_decoder.h"
35 #include "image/codecs/mpeg.h"
36
37 // The demuxing code is based on libav's demuxing code
38
39 namespace Video {
40
41 // --------------------------------------------------------------------------
42 // Decoder - This is the part that takes a packet and figures out what to do
43 // with it.
44 // --------------------------------------------------------------------------
45
46 enum {
47 kStartCodePack = 0x1BA,
48 kStartCodeSystemHeader = 0x1BB,
49 kStartCodeProgramStreamMap = 0x1BC,
50 kStartCodePrivateStream1 = 0x1BD,
51 kStartCodePaddingStream = 0x1BE,
52 kStartCodePrivateStream2 = 0x1BF
53 };
54
MPEGPSDecoder(double decibel)55 MPEGPSDecoder::MPEGPSDecoder(double decibel) {
56 _decibel = decibel;
57 _demuxer = new MPEGPSDemuxer();
58 }
59
~MPEGPSDecoder()60 MPEGPSDecoder::~MPEGPSDecoder() {
61 close();
62 delete _demuxer;
63 }
64
loadStream(Common::SeekableReadStream * stream)65 bool MPEGPSDecoder::loadStream(Common::SeekableReadStream *stream) {
66 close();
67
68 if (!_demuxer->loadStream(stream)) {
69 close();
70 return false;
71 }
72
73 if (!addFirstVideoTrack()) {
74 close();
75 return false;
76 }
77
78 return true;
79 }
80
close()81 void MPEGPSDecoder::close() {
82 VideoDecoder::close();
83 _demuxer->close();
84 _streamMap.clear();
85 }
86
getStream(uint32 startCode,Common::SeekableReadStream * packet)87 MPEGPSDecoder::MPEGStream *MPEGPSDecoder::getStream(uint32 startCode, Common::SeekableReadStream *packet) {
88 MPEGStream *stream = 0;
89
90 if (_streamMap.contains(startCode)) {
91 // We already found the stream
92 stream = _streamMap[startCode];
93 } else {
94 // We haven't seen this before
95
96 if (startCode == kStartCodePrivateStream1) {
97 PrivateStreamType streamType = detectPrivateStreamType(packet);
98 packet->seek(0);
99
100 // TODO: Handling of these types (as needed)
101 bool handled = false;
102 const char *typeName;
103
104 switch (streamType) {
105 case kPrivateStreamAC3: {
106 typeName = "AC-3";
107
108 #ifdef USE_A52
109 handled = true;
110 AC3AudioTrack *ac3Track = new AC3AudioTrack(*packet, _decibel, getSoundType());
111 stream = ac3Track;
112 _streamMap[startCode] = ac3Track;
113 addTrack(ac3Track);
114 #endif
115 break;
116 }
117 case kPrivateStreamDTS:
118 typeName = "DTS";
119 break;
120 case kPrivateStreamDVDPCM:
121 typeName = "DVD PCM";
122 break;
123 case kPrivateStreamPS2Audio: {
124 typeName = "PS2 Audio";
125 handled = true;
126 PS2AudioTrack *audioTrack = new PS2AudioTrack(packet, getSoundType());
127 stream = audioTrack;
128 _streamMap[startCode] = audioTrack;
129 addTrack(audioTrack);
130 break;
131 }
132 default:
133 typeName = "Unknown";
134 break;
135 }
136
137 if (!handled) {
138 warning("Unhandled DVD private stream: %s", typeName);
139
140 // Make it 0 so we don't get the warning twice
141 _streamMap[startCode] = 0;
142 }
143 } else if (startCode >= 0x1E0 && startCode <= 0x1EF) {
144 // Video stream
145 // TODO: Multiple video streams
146 warning("Found extra video stream 0x%04X", startCode);
147 _streamMap[startCode] = 0;
148 } else if (startCode >= 0x1C0 && startCode <= 0x1DF) {
149 #ifdef USE_MAD
150 // MPEG Audio stream
151 MPEGAudioTrack *audioTrack = new MPEGAudioTrack(*packet, getSoundType());
152 stream = audioTrack;
153 _streamMap[startCode] = audioTrack;
154 addTrack(audioTrack);
155 #else
156 warning("Found audio stream 0x%04X, but no MAD support compiled in", startCode);
157 _streamMap[startCode] = 0;
158 #endif
159 } else {
160 // Probably not relevant
161 debug(0, "Found unhandled MPEG-PS stream type 0x%04x", startCode);
162 _streamMap[startCode] = 0;
163 }
164 }
165
166 return stream;
167 }
168
readNextPacket()169 void MPEGPSDecoder::readNextPacket() {
170 for (;;) {
171 int32 startCode;
172 uint32 pts, dts;
173 Common::SeekableReadStream *packet = _demuxer->getNextPacket(getTime(), startCode, pts, dts);
174
175 if (!packet) {
176 // End of stream
177 for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++)
178 if ((*it)->getTrackType() == Track::kTrackTypeVideo)
179 ((MPEGVideoTrack *)*it)->setEndOfTrack();
180 return;
181 }
182
183 MPEGStream *stream = getStream(startCode, packet);
184
185 if (stream) {
186 packet->seek(0);
187
188 bool done = stream->sendPacket(packet, pts, dts);
189
190 if (done && stream->getStreamType() == MPEGStream::kStreamTypeVideo)
191 return;
192 } else {
193 delete packet;
194 }
195 }
196 }
197
addFirstVideoTrack()198 bool MPEGPSDecoder::addFirstVideoTrack() {
199 int32 startCode;
200 uint32 pts, dts;
201 Common::SeekableReadStream *packet = _demuxer->getFirstVideoPacket(startCode, pts, dts);
202
203 if (!packet)
204 return false;
205
206 // Video stream
207 // Can be MPEG-1/2 or MPEG-4/h.264. We'll assume the former and
208 // I hope we never need the latter.
209 MPEGVideoTrack *track = new MPEGVideoTrack(packet, getDefaultHighColorFormat());
210 addTrack(track);
211 _streamMap[startCode] = track;
212
213 return true;
214 }
215
detectPrivateStreamType(Common::SeekableReadStream * packet)216 MPEGPSDecoder::PrivateStreamType MPEGPSDecoder::detectPrivateStreamType(Common::SeekableReadStream *packet) {
217 uint32 dvdCode = packet->readUint32LE();
218 if (packet->eos())
219 return kPrivateStreamUnknown;
220
221 uint32 ps2Header = packet->readUint32BE();
222 if (!packet->eos() && ps2Header == MKTAG('S', 'S', 'h', 'd'))
223 return kPrivateStreamPS2Audio;
224
225 switch (dvdCode & 0xE0) {
226 case 0x80:
227 if ((dvdCode & 0xF8) == 0x88)
228 return kPrivateStreamDTS;
229
230 return kPrivateStreamAC3;
231 case 0xA0:
232 return kPrivateStreamDVDPCM;
233 default:
234 break;
235 }
236
237 return kPrivateStreamUnknown;
238 }
239
240 // --------------------------------------------------------------------------
241 // Demuxer - This is the part that reads packets from the stream and delivers
242 // them to the decoder.
243 //
244 // It will buffer a number of packets in advance, because otherwise it may
245 // not encounter any audio packets until it's far too late to decode them.
246 // Before I added this, there would be 9 or 10 frames of video before the
247 // first audio packet, even though the timestamp indicated that the audio
248 // should start slightly before the video.
249 // --------------------------------------------------------------------------
250
251 #define PREBUFFERED_PACKETS 150
252 #define AUDIO_THRESHOLD 100
253
MPEGPSDemuxer()254 MPEGPSDecoder::MPEGPSDemuxer::MPEGPSDemuxer() {
255 _stream = 0;
256 }
257
~MPEGPSDemuxer()258 MPEGPSDecoder::MPEGPSDemuxer::~MPEGPSDemuxer() {
259 close();
260 }
261
loadStream(Common::SeekableReadStream * stream)262 bool MPEGPSDecoder::MPEGPSDemuxer::loadStream(Common::SeekableReadStream *stream) {
263 close();
264
265 _stream = stream;
266
267 int queuedPackets = 0;
268 while (queueNextPacket() && queuedPackets < PREBUFFERED_PACKETS) {
269 queuedPackets++;
270 }
271
272 return true;
273 }
274
close()275 void MPEGPSDecoder::MPEGPSDemuxer::close() {
276 delete _stream;
277 _stream = 0;
278
279 while (!_audioQueue.empty()) {
280 Packet packet = _audioQueue.pop();
281 delete packet._stream;
282 }
283
284 while (!_videoQueue.empty()) {
285 Packet packet = _videoQueue.pop();
286 delete packet._stream;
287 }
288 }
289
getFirstVideoPacket(int32 & startCode,uint32 & pts,uint32 & dts)290 Common::SeekableReadStream *MPEGPSDecoder::MPEGPSDemuxer::getFirstVideoPacket(int32 &startCode, uint32 &pts, uint32 &dts) {
291 if (_videoQueue.empty())
292 return nullptr;
293 Packet packet = _videoQueue.front();
294 startCode = packet._startCode;
295 pts = packet._pts;
296 dts = packet._dts;
297 return packet._stream;
298 }
299
getNextPacket(uint32 currentTime,int32 & startCode,uint32 & pts,uint32 & dts)300 Common::SeekableReadStream *MPEGPSDecoder::MPEGPSDemuxer::getNextPacket(uint32 currentTime, int32 &startCode, uint32 &pts, uint32 &dts) {
301 queueNextPacket();
302
303 // The idea here is to prioritize the delivery of audio packets,
304 // because when the decoder wants a frame it will keep asking until it
305 // gets a frame. There is nothing like that in the decoder to ensure
306 // speedy delivery of audio.
307
308 if (!_audioQueue.empty()) {
309 Packet packet = _audioQueue.front();
310 bool usePacket = false;
311
312 if (packet._pts == 0xFFFFFFFF) {
313 // No timestamp? Use it just in case. This could be a
314 // bad idea, but in my tests all audio packets have a
315 // time stamp.
316 usePacket = true;
317 } else {
318 uint32 packetTime = packet._pts / 90;
319 if (packetTime <= currentTime || packetTime - currentTime < AUDIO_THRESHOLD || _videoQueue.empty()) {
320 // The packet is overdue, or will be soon.
321 //
322 // TODO: We should pad or trim the first audio
323 // packet based on the timestamp to get the
324 // audio to start at the exact desired time.
325 // But for some reason it seems to work well
326 // enough anyway. For now.
327 usePacket = true;
328 }
329 }
330
331 if (usePacket) {
332 _audioQueue.pop();
333 startCode = packet._startCode;
334 pts = packet._pts;
335 dts = packet._dts;
336 return packet._stream;
337 }
338 }
339
340 if (!_videoQueue.empty()) {
341 Packet packet = _videoQueue.pop();
342 startCode = packet._startCode;
343 pts = packet._pts;
344 dts = packet._dts;
345 return packet._stream;
346 }
347
348 return nullptr;
349 }
350
queueNextPacket()351 bool MPEGPSDecoder::MPEGPSDemuxer::queueNextPacket() {
352 if (_stream->eos())
353 return false;
354
355 for (;;) {
356 int32 startCode;
357 uint32 pts, dts;
358 int size = readNextPacketHeader(startCode, pts, dts);
359
360 if (size < 0) {
361 // End of stream
362 return false;
363 }
364
365 Common::SeekableReadStream *stream = _stream->readStream(size);
366
367 if (startCode == kStartCodePrivateStream1 || (startCode >= 0x1C0 && startCode <= 0x1DF)) {
368 // Audio packet
369 _audioQueue.push(Packet(stream, startCode, pts, dts));
370 return true;
371 }
372
373 if (startCode >= 0x1E0 && startCode <= 0x1EF) {
374 // Video packet
375 _videoQueue.push(Packet(stream, startCode, pts, dts));
376 return true;
377 }
378
379 delete stream;
380 }
381 }
382
readNextPacketHeader(int32 & startCode,uint32 & pts,uint32 & dts)383 int MPEGPSDecoder::MPEGPSDemuxer::readNextPacketHeader(int32 &startCode, uint32 &pts, uint32 &dts) {
384 for (;;) {
385 uint32 size;
386 startCode = findNextStartCode(size);
387
388 if (_stream->eos())
389 return -1;
390
391 if (startCode < 0)
392 continue;
393
394 uint32 lastSync = _stream->pos();
395
396 if (startCode == kStartCodePack || startCode == kStartCodeSystemHeader)
397 continue;
398
399 int length = _stream->readUint16BE();
400
401 if (startCode == kStartCodePaddingStream || startCode == kStartCodePrivateStream2) {
402 _stream->skip(length);
403 continue;
404 }
405
406 if (startCode == kStartCodeProgramStreamMap) {
407 parseProgramStreamMap(length);
408 continue;
409 }
410
411 // Find matching stream
412 if (!((startCode >= 0x1C0 && startCode <= 0x1DF) ||
413 (startCode >= 0x1E0 && startCode <= 0x1EF) ||
414 startCode == kStartCodePrivateStream1 || startCode == 0x1FD))
415 continue;
416
417 // Stuffing
418 byte c;
419 for (;;) {
420 if (length < 1) {
421 _stream->seek(lastSync);
422 continue;
423 }
424
425 c = _stream->readByte();
426 length--;
427
428 // XXX: for mpeg1, should test only bit 7
429 if (c != 0xFF)
430 break;
431 }
432
433 if ((c & 0xC0) == 0x40) {
434 // Buffer scale and size
435 _stream->readByte();
436 c = _stream->readByte();
437 length -= 2;
438 }
439
440 pts = 0xFFFFFFFF;
441 dts = 0xFFFFFFFF;
442
443 if ((c & 0xE0) == 0x20) {
444 dts = pts = readPTS(c);
445 length -= 4;
446
447 if (c & 0x10) {
448 dts = readPTS(-1);
449 length -= 5;
450 }
451 } else if ((c & 0xC0) == 0x80) {
452 // MPEG-2 PES
453 byte flags = _stream->readByte();
454 int headerLength = _stream->readByte();
455 length -= 2;
456
457 if (headerLength > length) {
458 _stream->seek(lastSync);
459 continue;
460 }
461
462 length -= headerLength;
463
464 if (flags & 0x80) {
465 dts = pts = readPTS(-1);
466 headerLength -= 5;
467
468 if (flags & 0x40) {
469 dts = readPTS(-1);
470 headerLength -= 5;
471 }
472 }
473
474 if (flags & 0x3F && headerLength == 0) {
475 flags &= 0xC0;
476 warning("Further flags set but no bytes left");
477 }
478
479 if (flags & 0x01) { // PES extension
480 byte pesExt =_stream->readByte();
481 headerLength--;
482
483 // Skip PES private data, program packet sequence
484 int skip = (pesExt >> 4) & 0xB;
485 skip += skip & 0x9;
486
487 if (pesExt & 0x40 || skip > headerLength) {
488 warning("pesExt %x is invalid", pesExt);
489 pesExt = skip = 0;
490 } else {
491 _stream->skip(skip);
492 headerLength -= skip;
493 }
494
495 if (pesExt & 0x01) { // PES extension 2
496 byte ext2Length = _stream->readByte();
497 headerLength--;
498
499 if ((ext2Length & 0x7F) != 0) {
500 byte idExt = _stream->readByte();
501
502 if ((idExt & 0x80) == 0)
503 startCode = (startCode & 0xFF) << 8;
504
505 headerLength--;
506 }
507 }
508 }
509
510 if (headerLength < 0) {
511 _stream->seek(lastSync);
512 continue;
513 }
514
515 _stream->skip(headerLength);
516 } else if (c != 0xF) {
517 continue;
518 }
519
520 if (length < 0) {
521 _stream->seek(lastSync);
522 continue;
523 }
524
525 return length;
526 }
527 }
528
529 #define MAX_SYNC_SIZE 100000
530
findNextStartCode(uint32 & size)531 int MPEGPSDecoder::MPEGPSDemuxer::findNextStartCode(uint32 &size) {
532 size = MAX_SYNC_SIZE;
533 int32 state = 0xFF;
534
535 while (size > 0) {
536 byte v = _stream->readByte();
537
538 if (_stream->eos())
539 return -1;
540
541 size--;
542
543 if (state == 0x1)
544 return ((state << 8) | v) & 0xFFFFFF;
545
546 state = ((state << 8) | v) & 0xFFFFFF;
547 }
548
549 return -1;
550 }
551
readPTS(int c)552 uint32 MPEGPSDecoder::MPEGPSDemuxer::readPTS(int c) {
553 byte buf[5];
554
555 buf[0] = (c < 0) ? _stream->readByte() : c;
556 _stream->read(buf + 1, 4);
557
558 return ((buf[0] & 0x0E) << 29) | ((READ_BE_UINT16(buf + 1) >> 1) << 15) | (READ_BE_UINT16(buf + 3) >> 1);
559 }
560
parseProgramStreamMap(int length)561 void MPEGPSDecoder::MPEGPSDemuxer::parseProgramStreamMap(int length) {
562 _stream->readByte();
563 _stream->readByte();
564
565 // skip program stream info
566 _stream->skip(_stream->readUint16BE());
567
568 int esMapLength = _stream->readUint16BE();
569
570 while (esMapLength >= 4) {
571 _stream->readByte(); // type
572 _stream->readByte(); // esID
573 uint16 esInfoLength = _stream->readUint16BE();
574
575 // Skip program stream info
576 _stream->skip(esInfoLength);
577
578 esMapLength -= 4 + esInfoLength;
579 }
580
581 _stream->readUint32BE(); // CRC32
582 }
583
584 // --------------------------------------------------------------------------
585 // Video track
586 // --------------------------------------------------------------------------
587
MPEGVideoTrack(Common::SeekableReadStream * firstPacket,const Graphics::PixelFormat & format)588 MPEGPSDecoder::MPEGVideoTrack::MPEGVideoTrack(Common::SeekableReadStream *firstPacket, const Graphics::PixelFormat &format) {
589 _surface = 0;
590 _endOfTrack = false;
591 _curFrame = -1;
592 _framePts = 0xFFFFFFFF;
593 _nextFrameStartTime = Audio::Timestamp(0, 27000000); // 27 MHz timer
594
595 findDimensions(firstPacket, format);
596
597 #ifdef USE_MPEG2
598 _mpegDecoder = new Image::MPEGDecoder();
599 #endif
600 }
601
~MPEGVideoTrack()602 MPEGPSDecoder::MPEGVideoTrack::~MPEGVideoTrack() {
603 #ifdef USE_MPEG2
604 delete _mpegDecoder;
605 #endif
606
607 if (_surface) {
608 _surface->free();
609 delete _surface;
610 }
611 }
612
getWidth() const613 uint16 MPEGPSDecoder::MPEGVideoTrack::getWidth() const {
614 return _surface ? _surface->w : 0;
615 }
616
getHeight() const617 uint16 MPEGPSDecoder::MPEGVideoTrack::getHeight() const {
618 return _surface ? _surface->h : 0;
619 }
620
getPixelFormat() const621 Graphics::PixelFormat MPEGPSDecoder::MPEGVideoTrack::getPixelFormat() const {
622 if (!_surface)
623 return Graphics::PixelFormat();
624
625 return _surface->format;
626 }
627
decodeNextFrame()628 const Graphics::Surface *MPEGPSDecoder::MPEGVideoTrack::decodeNextFrame() {
629 return _surface;
630 }
631
sendPacket(Common::SeekableReadStream * packet,uint32 pts,uint32 dts)632 bool MPEGPSDecoder::MPEGVideoTrack::sendPacket(Common::SeekableReadStream *packet, uint32 pts, uint32 dts) {
633 #ifdef USE_MPEG2
634 if (pts != 0xFFFFFFFF) {
635 _framePts = pts;
636 }
637
638 uint32 framePeriod;
639 bool foundFrame = _mpegDecoder->decodePacket(*packet, framePeriod, _surface);
640
641 if (foundFrame) {
642 _curFrame++;
643
644 // If there has been a timestamp since the previous frame, use that for
645 // syncing. Usually it will be the timestamp from the current packet,
646 // but it might not be.
647
648 if (_framePts != 0xFFFFFFFF) {
649 _nextFrameStartTime = Audio::Timestamp(_framePts / 90, 27000000);
650 } else {
651 _nextFrameStartTime = _nextFrameStartTime.addFrames(framePeriod);
652 }
653
654 _framePts = 0xFFFFFFFF;
655 }
656 #endif
657
658 delete packet;
659
660 #ifdef USE_MPEG2
661 return foundFrame;
662 #else
663 return true;
664 #endif
665 }
666
findDimensions(Common::SeekableReadStream * firstPacket,const Graphics::PixelFormat & format)667 void MPEGPSDecoder::MPEGVideoTrack::findDimensions(Common::SeekableReadStream *firstPacket, const Graphics::PixelFormat &format) {
668 // First, check for the picture start code
669 if (firstPacket->readUint32BE() != 0x1B3)
670 error("Failed to detect MPEG sequence start");
671
672 // This is part of the bitstream, but there's really no purpose
673 // to use Common::BitStream just for this: 12 bits width, 12 bits
674 // height
675 uint16 width = firstPacket->readByte() << 4;
676 uint16 height = firstPacket->readByte();
677 width |= (height & 0xF0) >> 4;
678 height = ((height & 0x0F) << 8) | firstPacket->readByte();
679
680 debug(0, "MPEG dimensions: %dx%d", width, height);
681
682 _surface = new Graphics::Surface();
683 _surface->create(width, height, format);
684
685 firstPacket->seek(0);
686 }
687
688 // --------------------------------------------------------------------------
689 // Audio track
690 // --------------------------------------------------------------------------
691
692 #ifdef USE_MAD
693
694 // The audio code here is almost entirely based on what we do in mp3.cpp
695
MPEGAudioTrack(Common::SeekableReadStream & firstPacket,Audio::Mixer::SoundType soundType)696 MPEGPSDecoder::MPEGAudioTrack::MPEGAudioTrack(Common::SeekableReadStream &firstPacket, Audio::Mixer::SoundType soundType) :
697 AudioTrack(soundType) {
698 _audStream = Audio::makePacketizedMP3Stream(firstPacket);
699 }
700
~MPEGAudioTrack()701 MPEGPSDecoder::MPEGAudioTrack::~MPEGAudioTrack() {
702 delete _audStream;
703 }
704
sendPacket(Common::SeekableReadStream * packet,uint32 pts,uint32 dts)705 bool MPEGPSDecoder::MPEGAudioTrack::sendPacket(Common::SeekableReadStream *packet, uint32 pts, uint32 dts) {
706 _audStream->queuePacket(packet);
707 return true;
708 }
709
getAudioStream() const710 Audio::AudioStream *MPEGPSDecoder::MPEGAudioTrack::getAudioStream() const {
711 return _audStream;
712 }
713
714 #endif
715
716 #ifdef USE_A52
717
AC3AudioTrack(Common::SeekableReadStream & firstPacket,double decibel,Audio::Mixer::SoundType soundType)718 MPEGPSDecoder::AC3AudioTrack::AC3AudioTrack(Common::SeekableReadStream &firstPacket, double decibel, Audio::Mixer::SoundType soundType) :
719 AudioTrack(soundType) {
720 _audStream = Audio::makeAC3Stream(firstPacket, decibel);
721 if (!_audStream)
722 error("Could not create AC-3 stream");
723 }
724
~AC3AudioTrack()725 MPEGPSDecoder::AC3AudioTrack::~AC3AudioTrack() {
726 delete _audStream;
727 }
728
sendPacket(Common::SeekableReadStream * packet,uint32 pts,uint32 dts)729 bool MPEGPSDecoder::AC3AudioTrack::sendPacket(Common::SeekableReadStream *packet, uint32 pts, uint32 dts) {
730 // Skip DVD code
731 packet->readUint32LE();
732 if (packet->eos())
733 return true;
734
735 _audStream->queuePacket(packet);
736 return true;
737 }
738
getAudioStream() const739 Audio::AudioStream *MPEGPSDecoder::AC3AudioTrack::getAudioStream() const {
740 return _audStream;
741 }
742
743 #endif
744
PS2AudioTrack(Common::SeekableReadStream * firstPacket,Audio::Mixer::SoundType soundType)745 MPEGPSDecoder::PS2AudioTrack::PS2AudioTrack(Common::SeekableReadStream *firstPacket, Audio::Mixer::SoundType soundType) :
746 AudioTrack(soundType) {
747 firstPacket->seek(12); // unknown data (4), 'SShd', header size (4)
748
749 _soundType = firstPacket->readUint32LE();
750
751 if (_soundType == PS2_ADPCM)
752 error("Unhandled PS2 ADPCM sound in MPEG-PS video");
753 else if (_soundType != PS2_PCM)
754 error("Unknown PS2 sound type %x", _soundType);
755
756 uint32 sampleRate = firstPacket->readUint32LE();
757 _channels = firstPacket->readUint32LE();
758 _interleave = firstPacket->readUint32LE();
759
760 byte flags = Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN;
761 if (_channels == 2)
762 flags |= Audio::FLAG_STEREO;
763
764 _blockBuffer = new byte[_interleave * _channels];
765 _blockPos = _blockUsed = 0;
766 _audStream = Audio::makePacketizedRawStream(sampleRate, flags);
767 _isFirstPacket = true;
768
769 firstPacket->seek(0);
770 }
771
~PS2AudioTrack()772 MPEGPSDecoder::PS2AudioTrack::~PS2AudioTrack() {
773 delete[] _blockBuffer;
774 delete _audStream;
775 }
776
sendPacket(Common::SeekableReadStream * packet,uint32 pts,uint32 dts)777 bool MPEGPSDecoder::PS2AudioTrack::sendPacket(Common::SeekableReadStream *packet, uint32 pts, uint32 dts) {
778 packet->skip(4);
779
780 if (_isFirstPacket) {
781 // Skip over the header which we already parsed
782 packet->skip(4);
783 packet->skip(packet->readUint32LE());
784
785 if (packet->readUint32BE() != MKTAG('S', 'S', 'b', 'd'))
786 error("Failed to find 'SSbd' tag");
787
788 packet->readUint32LE(); // body size
789 _isFirstPacket = false;
790 }
791
792 uint32 size = packet->size() - packet->pos();
793 uint32 bytesPerChunk = _interleave * _channels;
794 uint32 sampleCount = calculateSampleCount(size);
795
796 byte *buffer = (byte *)malloc(sampleCount * 2);
797 int16 *ptr = (int16 *)buffer;
798
799 // Handle any full chunks first
800 while (size >= bytesPerChunk) {
801 packet->read(_blockBuffer + _blockPos, bytesPerChunk - _blockPos);
802 size -= bytesPerChunk - _blockPos;
803 _blockPos = 0;
804
805 for (uint32 i = _blockUsed; i < _interleave / 2; i++)
806 for (uint32 j = 0; j < _channels; j++)
807 *ptr++ = READ_UINT16(_blockBuffer + i * 2 + j * _interleave);
808
809 _blockUsed = 0;
810 }
811
812 // Then fallback on loading any leftover
813 if (size > 0) {
814 packet->read(_blockBuffer, size);
815 _blockPos = size;
816
817 if (size > (_channels - 1) * _interleave) {
818 _blockUsed = (size - (_channels - 1) * _interleave) / 2;
819
820 for (uint32 i = 0; i < _blockUsed; i++)
821 for (uint32 j = 0; j < _channels; j++)
822 *ptr++ = READ_UINT16(_blockBuffer + i * 2 + j * _interleave);
823 }
824 }
825
826 _audStream->queuePacket(new Common::MemoryReadStream(buffer, sampleCount * 2, DisposeAfterUse::YES));
827
828 delete packet;
829 return true;
830 }
831
getAudioStream() const832 Audio::AudioStream *MPEGPSDecoder::PS2AudioTrack::getAudioStream() const {
833 return _audStream;
834 }
835
calculateSampleCount(uint32 packetSize) const836 uint32 MPEGPSDecoder::PS2AudioTrack::calculateSampleCount(uint32 packetSize) const {
837 uint32 bytesPerChunk = _interleave * _channels, result = 0;
838
839 // If we have a partial block, subtract the remainder from the size. That
840 // gets put towards reading the partial block
841 if (_blockPos != 0) {
842 packetSize -= bytesPerChunk - _blockPos;
843 result += (_interleave / 2) - _blockUsed;
844 }
845
846 // Round the number of whole chunks down and then calculate how many samples that gives us
847 result += (packetSize / bytesPerChunk) * _interleave / 2;
848
849 // Total up anything we can get from the remainder
850 packetSize %= bytesPerChunk;
851 if (packetSize > (_channels - 1) * _interleave)
852 result += (packetSize - (_channels - 1) * _interleave) / 2;
853
854 return result * _channels;
855 }
856 } // End of namespace Video
857