mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-09-01 18:25:19 +02:00
demux()'s "not enough data, rewind and try again next time" logic unconditionally subtracted 4 (or 6) from m_index, assuming that many bytes were consumed scanning for a start code. But the inner scan can also exit via reaching the end of the buffer without finding a start code at all, having consumed fewer bytes than that - when the buffer holds under 4 bytes total, m_index goes negative, and the subsequent memmove(m_buf, m_buf + m_index, size) then reads before the start of m_buf. Clamp the rewind to 0. read8()/skip() also had no bounds check against m_len (the actual buffer allocation) at all - readPesHeader()'s header-length fields are only cross-checked against the outer PES packet length, not against how much data is actually available, so a crafted stream claiming a long header could walk m_index past the buffer. Bound both against m_len directly, at the lowest-level primitives so every caller is covered.
90 lines
1.9 KiB
C++
90 lines
1.9 KiB
C++
// This is a simple version MpegDemux that can get media's audio stream.
|
|
// Thanks to JPCSP project.
|
|
|
|
#pragma once
|
|
|
|
#include "Common/CommonTypes.h"
|
|
#include "Core/HW/BufferQueue.h"
|
|
|
|
class PointerWrap;
|
|
|
|
class MpegDemux
|
|
{
|
|
public:
|
|
MpegDemux(int size, int offset);
|
|
~MpegDemux();
|
|
|
|
bool addStreamData(const u8 *buf, int addSize);
|
|
bool demux(int audioChannel);
|
|
void setAudioChannel(int audioChannel);
|
|
|
|
// return its framesize
|
|
int getNextAudioFrame(u8 **buf, int *headerCode1, int *headerCode2, s64 *pts = NULL);
|
|
bool hasNextAudioFrame(int *gotsizeOut, int *frameSizeOut, int *headerCode1, int *headerCode2);
|
|
|
|
int getRemainSize() const {
|
|
return m_len - m_readSize;
|
|
}
|
|
|
|
void DoState(PointerWrap &p);
|
|
|
|
private:
|
|
struct PesHeader {
|
|
s64 pts;
|
|
s64 dts;
|
|
int channel;
|
|
|
|
PesHeader(int chan) {
|
|
pts = 0;
|
|
dts = 0;
|
|
channel = chan;
|
|
}
|
|
};
|
|
|
|
int read8() {
|
|
// PES header field lengths (e.g. readPesHeader()'s headerLength byte) are
|
|
// only cross-checked against the outer packet length, not against how much
|
|
// data is actually available - a crafted stream can claim more than that,
|
|
// so guard the actual buffer access here rather than in every caller.
|
|
if (m_index >= m_len) {
|
|
return 0;
|
|
}
|
|
return m_buf[m_index++];
|
|
}
|
|
int read16() {
|
|
return (read8() << 8) | read8();
|
|
}
|
|
int read24() {
|
|
return (read8() << 16) | (read8() << 8) | read8();
|
|
}
|
|
s64 readPts() {
|
|
return readPts(read8());
|
|
}
|
|
s64 readPts(int c) {
|
|
return (((s64) (c & 0x0E)) << 29) | ((read16() >> 1) << 15) | (read16() >> 1);
|
|
}
|
|
bool isEOF() const {
|
|
return m_index >= m_readSize;
|
|
}
|
|
void skip(int n) {
|
|
if (n > 0) {
|
|
m_index += n;
|
|
if (m_index > m_len) {
|
|
m_index = m_len;
|
|
}
|
|
}
|
|
}
|
|
int readPesHeader(PesHeader &pesHeader, int length, int startCode);
|
|
int demuxStream(bool bdemux, int startCode, int length, int channel);
|
|
bool skipPackHeader();
|
|
|
|
int m_index;
|
|
int m_len;
|
|
u8 *m_buf;
|
|
BufferQueue m_audioStream;
|
|
u8 m_audioFrame[0x2000];
|
|
int m_audioChannel;
|
|
int m_readSize;
|
|
};
|
|
|