3 const int PACKET_START_CODE_MASK
= 0xffffff00;
4 const int PACKET_START_CODE_PREFIX
= 0x00000100;
6 // http://dvd.sourceforge.net/dvdinfo/mpeghdrs.html
8 const int USER_DATA_START_CODE
= 0x000001b2;
9 const int SEQUENCE_START_CODE
= 0x000001b3;
10 const int EXT_START_CODE
= 0x000001b5;
11 const int SEQUENCE_END_CODE
= 0x000001b7;
12 const int GOP_START_CODE
= 0x000001b8;
13 const int ISO_11172_END_CODE
= 0x000001b9;
14 const int PACK_START_CODE
= 0x000001ba;
15 const int SYSTEM_HEADER_START_CODE
= 0x000001bb;
16 const int PROGRAM_STREAM_MAP
= 0x000001bc;
17 const int PRIVATE_STREAM_1
= 0x000001bd;
18 const int PADDING_STREAM
= 0x000001be;
19 const int PRIVATE_STREAM_2
= 0x000001bf;
21 MpegDemux::MpegDemux(int size
, int offset
) : m_audioStream(size
) {
30 MpegDemux::~MpegDemux() {
34 void MpegDemux::DoState(PointerWrap
&p
) {
35 auto s
= p
.Section("MpegDemux", 1);
44 p
.DoArray(m_buf
, m_len
);
45 p
.DoClass(m_audioStream
);
48 bool MpegDemux::addStreamData(const u8
*buf
, int addSize
) {
49 if (m_readSize
+ addSize
> m_len
)
51 memcpy(m_buf
+ m_readSize
, buf
, addSize
);
52 m_readSize
+= addSize
;
56 int MpegDemux::readPesHeader(PesHeader
&pesHeader
, int length
, int startCode
) {
65 if ((c
& 0xC0) == 0x40) {
72 if ((c
& 0xE0) == 0x20) {
73 pesHeader
.dts
= pesHeader
.pts
= readPts(c
);
75 if ((c
& 0x10) != 0) {
76 pesHeader
.dts
= readPts();
79 } else if ((c
& 0xC0) == 0x80) {
81 int headerLength
= read8();
83 length
-= headerLength
;
84 if ((flags
& 0x80) != 0) {
85 pesHeader
.dts
= pesHeader
.pts
= readPts();
87 if ((flags
& 0x40) != 0) {
88 pesHeader
.dts
= readPts();
92 if ((flags
& 0x3F) != 0 && headerLength
== 0) {
95 if ((flags
& 0x01) != 0) {
98 int skip
= (pesExt
>> 4) & 0x0B;
100 if ((pesExt
& 0x40) != 0 || skip
> headerLength
) {
104 headerLength
-= skip
;
105 if ((pesExt
& 0x01) != 0) {
106 int ext2Length
= read8();
108 if ((ext2Length
& 0x7F) != 0) {
111 if ((idExt
& 0x80) == 0) {
112 startCode
= ((startCode
& 0xFF) << 8) | idExt
;
119 if (startCode
== PRIVATE_STREAM_1
) {
120 int channel
= read8();
121 pesHeader
.channel
= channel
;
123 if (channel
>= 0x80 && channel
<= 0xCF) {
127 if (channel
>= 0xB0 && channel
<= 0xBF) {
132 // PSP audio has additional 3 bytes in header
140 int MpegDemux::demuxStream(bool bdemux
, int startCode
, int channel
)
142 int length
= read16();
144 PesHeader
pesHeader(channel
);
145 length
= readPesHeader(pesHeader
, length
, startCode
);
146 if (pesHeader
.channel
== channel
|| channel
< 0) {
147 channel
= pesHeader
.channel
;
148 m_audioStream
.push(m_buf
+ m_index
, length
, pesHeader
.pts
);
157 void MpegDemux::demux(int audioChannel
)
159 if (audioChannel
>= 0)
160 m_audioChannel
= audioChannel
;
161 while (m_index
< m_len
)
163 if (m_index
+ 2048 > m_readSize
)
165 // Search for start code
166 int startCode
= 0xFF;
167 while ((startCode
& PACKET_START_CODE_MASK
) != PACKET_START_CODE_PREFIX
&& !isEOF()) {
168 startCode
= (startCode
<< 8) | read8();
171 case PACK_START_CODE
:
174 case SYSTEM_HEADER_START_CODE
:
178 case PRIVATE_STREAM_2
:
180 int length
= read16();
184 case PRIVATE_STREAM_1
: {
186 m_audioChannel
= demuxStream(true, startCode
, m_audioChannel
);
189 case 0x1E0: case 0x1E1: case 0x1E2: case 0x1E3:
190 case 0x1E4: case 0x1E5: case 0x1E6: case 0x1E7:
191 case 0x1E8: case 0x1E9: case 0x1EA: case 0x1EB:
192 case 0x1EC: case 0x1ED: case 0x1EE: case 0x1EF:
194 demuxStream(false, startCode
, -1);
196 case USER_DATA_START_CODE
:
197 // User data, probably same as queried by sceMpegGetUserdataAu.
198 // Not sure what exactly to do or how much to read.
199 // TODO: implement properly.
203 if (m_index
< m_readSize
) {
204 int size
= m_readSize
- m_index
;
205 memcpy(m_buf
, m_buf
+ m_index
, size
);
214 static bool isHeader(u8
* audioStream
, int offset
)
216 const u8 header1
= (u8
)0x0F;
217 const u8 header2
= (u8
)0xD0;
218 return (audioStream
[offset
] == header1
) && (audioStream
[offset
+1] == header2
);
221 static int getNextHeaderPosition(u8
* audioStream
, int curpos
, int limit
, int frameSize
)
223 int endScan
= limit
- 1;
225 // Most common case: the header can be found at each frameSize
226 int offset
= curpos
+ frameSize
- 8;
227 if (offset
< endScan
&& isHeader(audioStream
, offset
))
229 for (int scan
= curpos
; scan
< endScan
; scan
++) {
230 if (isHeader(audioStream
, scan
))
237 int MpegDemux::getNextAudioFrame(u8
**buf
, int *headerCode1
, int *headerCode2
, s64
*pts
)
241 if (!hasNextAudioFrame(&gotsize
, &frameSize
, headerCode1
, headerCode2
))
244 int nextHeader
= getNextHeaderPosition(m_audioFrame
, audioPos
, gotsize
, frameSize
);
245 if (nextHeader
>= 0) {
246 audioPos
= nextHeader
;
250 m_audioStream
.pop_front(0, audioPos
, pts
);
252 *buf
= m_audioFrame
+ 8;
254 return frameSize
- 8;
257 bool MpegDemux::hasNextAudioFrame(int *gotsizeOut
, int *frameSizeOut
, int *headerCode1
, int *headerCode2
)
259 int gotsize
= m_audioStream
.get_front(m_audioFrame
, 0x2000);
260 if (gotsize
== 0 || !isHeader(m_audioFrame
, 0))
262 u8 code1
= m_audioFrame
[2];
263 u8 code2
= m_audioFrame
[3];
264 int frameSize
= (((code1
& 0x03) << 8) | ((code2
& 0xFF) * 8)) + 0x10;
265 if (frameSize
> gotsize
)
269 *gotsizeOut
= gotsize
;
271 *frameSizeOut
= frameSize
;
273 *headerCode1
= code1
;
275 *headerCode2
= code2
;