diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 3248aba4d2..b55c9b4c13 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -233,6 +233,7 @@ + @@ -411,6 +412,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index caec603430..7172448df5 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -430,6 +430,9 @@ HW + + HW + @@ -795,6 +798,9 @@ HW + + HW + @@ -802,4 +808,4 @@ - + \ No newline at end of file diff --git a/Core/HW/MpegDemux.cpp b/Core/HW/MpegDemux.cpp new file mode 100644 index 0000000000..91201a3eb7 --- /dev/null +++ b/Core/HW/MpegDemux.cpp @@ -0,0 +1,192 @@ +#include "MpegDemux.h" + +const int PACKET_START_CODE_MASK = 0xffffff00; +const int PACKET_START_CODE_PREFIX = 0x00000100; + +const int SEQUENCE_START_CODE = 0x000001b3; +const int EXT_START_CODE = 0x000001b5; +const int SEQUENCE_END_CODE = 0x000001b7; +const int GOP_START_CODE = 0x000001b8; +const int ISO_11172_END_CODE = 0x000001b9; +const int PACK_START_CODE = 0x000001ba; +const int SYSTEM_HEADER_START_CODE = 0x000001bb; +const int PROGRAM_STREAM_MAP = 0x000001bc; +const int PRIVATE_STREAM_1 = 0x000001bd; +const int PADDING_STREAM = 0x000001be; +const int PRIVATE_STREAM_2 = 0x000001bf; + +MpegDemux::MpegDemux(u8* buffer, int size, int offset) +{ + m_buf = buffer; + m_len = size; + m_index = offset; + m_audioStream = 0; + m_audiopos = 0; + m_audioChannel = -1; + m_readSize = 0; +} + + +MpegDemux::~MpegDemux(void) +{ + if (m_audioStream) + delete [] m_audioStream; +} + +void MpegDemux::setReadSize(int readSize) +{ + m_readSize = readSize; +} + +int MpegDemux::readPesHeader(PesHeader &pesHeader, int length, int startCode) { + int c = 0; + while (length > 0) { + c = read8(); + length--; + if (c != 0xFF) { + break; + } + } + if ((c & 0xC0) == 0x40) { + read8(); + c = read8(); + length -= 2; + } + pesHeader.pts = 0; + pesHeader.dts = 0; + if ((c & 0xE0) == 0x20) { + pesHeader.dts = pesHeader.pts = readPts(c); + length -= 4; + if ((c & 0x10) != 0) { + pesHeader.dts = readPts(); + length -= 5; + } + } else if ((c & 0xC0) == 0x80) { + int flags = read8(); + int headerLength = read8(); + length -= 2; + length -= headerLength; + if ((flags & 0x80) != 0) { + pesHeader.dts = pesHeader.pts = readPts(); + headerLength -= 5; + if ((flags & 0x40) != 0) { + pesHeader.dts = readPts(); + headerLength -= 5; + } + } + if ((flags & 0x3F) != 0 && headerLength == 0) { + flags &= 0xC0; + } + if ((flags & 0x01) != 0) { + int pesExt = read8(); + headerLength--; + int skip = (pesExt >> 4) & 0x0B; + skip += skip & 0x09; + if ((pesExt & 0x40) != 0 || skip > headerLength) { + pesExt = skip = 0; + } + this->skip(skip); + headerLength -= skip; + if ((pesExt & 0x01) != 0) { + int ext2Length = read8(); + headerLength--; + if ((ext2Length & 0x7F) != 0) { + int idExt = read8(); + headerLength--; + if ((idExt & 0x80) == 0) { + startCode = ((startCode & 0xFF) << 8) | idExt; + } + } + } + } + skip(headerLength); + } + if (startCode == PRIVATE_STREAM_1) { + int channel = read8(); + pesHeader.channel = channel; + length--; + if (channel >= 0x80 && channel <= 0xCF) { + // Skip audio header + skip(3); + length -= 3; + if (channel >= 0xB0 && channel <= 0xBF) { + skip(1); + length--; + } + } else { + // PSP audio has additional 3 bytes in header + skip(3); + length -= 3; + } + } + return length; +} + +int MpegDemux::demuxStream(bool bdemux, int startCode, int channel) +{ + int length = read16(); + if (bdemux) { + PesHeader pesHeader(channel); + length = readPesHeader(pesHeader, length, startCode); + if (pesHeader.channel == channel || channel < 0) { + channel = pesHeader.channel; + memcpy(m_audioStream + m_audiopos, m_buf + m_index, length); + m_audiopos += length; + } + skip(length); + } else { + skip(length); + } + return channel; +} + +void MpegDemux::demux() +{ + if (!m_audioStream) + m_audioStream = new u8[m_len - m_index]; + while (m_index < m_len) + { + if (m_readSize != m_len && m_index + 2048 > m_readSize) + return; + // Search for start code + int startCode = 0xFF; + while ((startCode & PACKET_START_CODE_MASK) != PACKET_START_CODE_PREFIX && !isEOF()) { + startCode = (startCode << 8) | read8(); + } + switch (startCode) { + case PACK_START_CODE: { + skip(10); + break; + } + case SYSTEM_HEADER_START_CODE: { + skip(14); + break; + } + case PADDING_STREAM: + case PRIVATE_STREAM_2: { + int length = read16(); + skip(length); + break; + } + case PRIVATE_STREAM_1: { + // Audio stream + m_audioChannel = demuxStream(true, startCode, m_audioChannel); + break; + } + case 0x1E0: case 0x1E1: case 0x1E2: case 0x1E3: + case 0x1E4: case 0x1E5: case 0x1E6: case 0x1E7: + case 0x1E8: case 0x1E9: case 0x1EA: case 0x1EB: + case 0x1EC: case 0x1ED: case 0x1EE: case 0x1EF: { + // Video Stream + demuxStream(false, startCode, -1); + break; + } + } + } +} + +int MpegDemux::getaudioStream(u8** audioStream) +{ + *audioStream = m_audioStream; + return m_audiopos; +} \ No newline at end of file diff --git a/Core/HW/MpegDemux.h b/Core/HW/MpegDemux.h new file mode 100644 index 0000000000..5d760a6ae6 --- /dev/null +++ b/Core/HW/MpegDemux.h @@ -0,0 +1,63 @@ +// This is a simple version MpegDemux that can get media's audio stream. +// Thanks to JPCSP project. + +#pragma once + +#include "../../Globals.h" + +class MpegDemux +{ +public: + MpegDemux(u8* buffer, int size, int offset); + ~MpegDemux(void); + + void setReadSize(int readSize); + + void demux(); + + // return it's size + int getaudioStream(u8 **audioStream); +private: + struct PesHeader { + long pts; + long dts; + int channel; + + PesHeader(int chan) { + pts = 0; + dts = 0; + channel = chan; + } + }; + int read8() { + return m_buf[m_index++] & 0xFF; + } + int read16() { + return (read8() << 8) | read8(); + } + long readPts() { + return readPts(read8()); + } + long readPts(int c) { + return (((long) (c & 0x0E)) << 29) | ((read16() >> 1) << 15) | (read16() >> 1); + } + bool isEOF() { + return m_index >= m_len; + } + void skip(int n) { + if (n > 0) { + m_index += n; + } + } + int readPesHeader(PesHeader &pesHeader, int length, int startCode); + int demuxStream(bool bdemux, int startCode, int channel); +private: + int m_index; + int m_len; + u8* m_buf; + u8* m_audioStream; + int m_audiopos; + int m_audioChannel; + int m_readSize; +}; +