mirror of
https://github.com/libretro/ppsspp.git
synced 2025-01-06 00:18:21 +00:00
Merge branch 'master' of github.com:hrydgard/ppsspp
This commit is contained in:
commit
5b5f9cbe4f
@ -221,6 +221,11 @@ template<int func(u32, const char *)> void WrapI_UC() {
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(u32, const char *, int)> void WrapI_UCI() {
|
||||
int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, int , int , int, int, int)> void WrapU_UIIIII() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5));
|
||||
RETURN(retval);
|
||||
|
@ -271,7 +271,11 @@ void AnalyzeMpeg(u32 buffer_addr, MpegContext *ctx) {
|
||||
|
||||
if (ctx->mediaengine && (ctx->mpegStreamSize > 0) && !ctx->isAnalyzed) {
|
||||
// init mediaEngine
|
||||
ctx->mediaengine->loadStream(Memory::GetPointer(buffer_addr), ctx->mpegOffset, ctx->mpegOffset + ctx->mpegStreamSize);
|
||||
SceMpegRingBuffer ringbuffer = {0};
|
||||
if(ctx->mpegRingbufferAddr != 0){
|
||||
Memory::ReadStruct(ctx->mpegRingbufferAddr, &ringbuffer);
|
||||
};
|
||||
ctx->mediaengine->loadStream(Memory::GetPointer(buffer_addr), ctx->mpegOffset, ringbuffer.packets * ringbuffer.packetSize);
|
||||
ctx->mediaengine->setVideoDim();
|
||||
}
|
||||
// When used with scePsmf, some applications attempt to use sceMpegQueryStreamOffset
|
||||
@ -643,7 +647,7 @@ u32 sceMpegAvcDecode(u32 mpeg, u32 auAddr, u32 frameWidth, u32 bufferAddr, u32 i
|
||||
} else {
|
||||
ctx->avc.avcFrameStatus = 0;
|
||||
}
|
||||
ringbuffer.packetsFree = std::max(0, ringbuffer.packets - ctx->mediaengine->getBufferedSize() / 2048);
|
||||
ringbuffer.packetsFree = ctx->mediaengine->getRemainSize() / 2048;
|
||||
|
||||
avcAu.pts = ctx->mediaengine->getVideoTimeStamp() + ctx->mpegFirstTimestamp;
|
||||
|
||||
@ -788,7 +792,7 @@ int sceMpegAvcDecodeYCbCr(u32 mpeg, u32 auAddr, u32 bufferAddr, u32 initAddr)
|
||||
}else {
|
||||
ctx->avc.avcFrameStatus = 0;
|
||||
}
|
||||
ringbuffer.packetsFree = std::max(0, ringbuffer.packets - ctx->mediaengine->getBufferedSize() / 2048);
|
||||
ringbuffer.packetsFree = ctx->mediaengine->getRemainSize() / 2048;
|
||||
|
||||
avcAu.pts = ctx->mediaengine->getVideoTimeStamp() + ctx->mpegFirstTimestamp;
|
||||
|
||||
|
@ -156,11 +156,16 @@ public:
|
||||
class PsmfPlayer {
|
||||
public:
|
||||
// For savestates only.
|
||||
PsmfPlayer() { mediaengine = new MediaEngine;}
|
||||
PsmfPlayer() { mediaengine = new MediaEngine; filehandle = 0;}
|
||||
PsmfPlayer(u32 data);
|
||||
~PsmfPlayer() { if (mediaengine) delete mediaengine;}
|
||||
~PsmfPlayer() { if (mediaengine) delete mediaengine; pspFileSystem.CloseFile(filehandle);}
|
||||
void DoState(PointerWrap &p);
|
||||
|
||||
u32 filehandle;
|
||||
u32 fileoffset;
|
||||
u32 filesize;
|
||||
u8 tempbuf[0x10000];
|
||||
|
||||
int videoCodec;
|
||||
int videoStreamNum;
|
||||
int audioCodec;
|
||||
@ -276,6 +281,9 @@ PsmfPlayer::PsmfPlayer(u32 data) {
|
||||
psmfPlayerLastTimestamp = getMpegTimeStamp(Memory::GetPointer(data + PSMF_LAST_TIMESTAMP_OFFSET)) ;
|
||||
status = PSMF_PLAYER_STATUS_INIT;
|
||||
mediaengine = new MediaEngine;
|
||||
filehandle = 0;
|
||||
fileoffset = 0;
|
||||
filesize = 0;
|
||||
}
|
||||
|
||||
void Psmf::DoState(PointerWrap &p) {
|
||||
@ -321,6 +329,12 @@ void PsmfPlayer::DoState(PointerWrap &p) {
|
||||
p.Do(psmfMaxAheadTimestamp);
|
||||
p.Do(psmfPlayerLastTimestamp);
|
||||
p.DoClass(mediaengine);
|
||||
p.Do(filehandle);
|
||||
p.Do(fileoffset);
|
||||
p.Do(filesize);
|
||||
|
||||
p.Do(status);
|
||||
p.Do(psmfPlayerAvcAu);
|
||||
|
||||
p.DoMarker("PsmfPlayer");
|
||||
}
|
||||
@ -762,6 +776,23 @@ int scePsmfPlayerBreak(u32 psmfPlayer)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _PsmfPlayerSetPsmfOffset(PsmfPlayer *psmfplayer, const char * filename, int offset, bool docallback) {
|
||||
psmfplayer->filehandle = pspFileSystem.OpenFile(filename, (FileAccess) FILEACCESS_READ);
|
||||
psmfplayer->fileoffset = offset;
|
||||
if (psmfplayer->filehandle && psmfplayer->tempbuf) {
|
||||
pspFileSystem.SeekFile(psmfplayer->filehandle, offset, FILEMOVE_BEGIN);
|
||||
u8* buf = psmfplayer->tempbuf;
|
||||
u32 tempbufSize = sizeof(psmfplayer->tempbuf);
|
||||
int size = pspFileSystem.ReadFile(psmfplayer->filehandle, buf, tempbufSize);
|
||||
if (size) {
|
||||
psmfplayer->mediaengine->loadStream(buf, 2048, std::max(2048 * 500, (int)tempbufSize));
|
||||
psmfplayer->mediaengine->addStreamData(buf + 2048, size - 2048);
|
||||
}
|
||||
psmfplayer->psmfPlayerLastTimestamp = psmfplayer->mediaengine->getLastTimeStamp();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scePsmfPlayerSetPsmf(u32 psmfPlayer, const char *filename)
|
||||
{
|
||||
PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
|
||||
@ -769,12 +800,11 @@ int scePsmfPlayerSetPsmf(u32 psmfPlayer, const char *filename)
|
||||
{
|
||||
INFO_LOG(HLE, "scePsmfPlayerSetPsmf(%08x, %s)", psmfPlayer, filename);
|
||||
psmfplayer->status = PSMF_PLAYER_STATUS_STANDBY;
|
||||
psmfplayer->mediaengine->loadFile(filename);
|
||||
psmfplayer->psmfPlayerLastTimestamp = psmfplayer->mediaengine->getLastTimeStamp();
|
||||
_PsmfPlayerSetPsmfOffset(psmfplayer, filename, 0, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
INFO_LOG(HLE, "scePsmfPlayerSetPsmf(%08x, %s): invalid psmf player", psmfPlayer, filename);
|
||||
ERROR_LOG(HLE, "scePsmfPlayerSetPsmf(%08x, %s): invalid psmf player", psmfPlayer, filename);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -788,12 +818,46 @@ int scePsmfPlayerSetPsmfCB(u32 psmfPlayer, const char *filename)
|
||||
{
|
||||
INFO_LOG(HLE, "scePsmfPlayerSetPsmfCB(%08x, %s)", psmfPlayer, filename);
|
||||
psmfplayer->status = PSMF_PLAYER_STATUS_STANDBY;
|
||||
psmfplayer->mediaengine->loadFile(filename);
|
||||
psmfplayer->psmfPlayerLastTimestamp = psmfplayer->mediaengine->getLastTimeStamp();
|
||||
_PsmfPlayerSetPsmfOffset(psmfplayer, filename, 0, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
INFO_LOG(HLE, "scePsmfPlayerSetPsmfCB(%08x, %s): invalid psmf player", psmfPlayer, filename);
|
||||
ERROR_LOG(HLE, "scePsmfPlayerSetPsmfCB(%08x, %s): invalid psmf player", psmfPlayer, filename);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scePsmfPlayerSetPsmfOffset(u32 psmfPlayer, const char *filename, int offset)
|
||||
{
|
||||
PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
|
||||
if (psmfplayer)
|
||||
{
|
||||
INFO_LOG(HLE, "scePsmfPlayerSetPsmfOffset(%08x, %s, %i)", psmfPlayer, filename, offset);
|
||||
psmfplayer->status = PSMF_PLAYER_STATUS_STANDBY;
|
||||
_PsmfPlayerSetPsmfOffset(psmfplayer, filename, offset, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(HLE, "scePsmfPlayerSetPsmfOffset(%08x, %s, %i): invalid psmf player", psmfPlayer, filename, offset);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scePsmfPlayerSetPsmfOffsetCB(u32 psmfPlayer, const char *filename, int offset)
|
||||
{
|
||||
// TODO: hleCheckCurrentCallbacks?
|
||||
PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
|
||||
if (psmfplayer)
|
||||
{
|
||||
INFO_LOG(HLE, "scePsmfPlayerSetPsmfOffsetCB(%08x, %s, %i)", psmfPlayer, filename, offset);
|
||||
psmfplayer->status = PSMF_PLAYER_STATUS_STANDBY;
|
||||
_PsmfPlayerSetPsmfOffset(psmfplayer, filename, offset, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(HLE, "scePsmfPlayerSetPsmfOffsetCB(%08x, %s, %i): invalid psmf player", psmfPlayer, filename, offset);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -906,6 +970,14 @@ int scePsmfPlayerGetVideoData(u32 psmfPlayer, u32 videoDataAddr)
|
||||
Memory::Write_U32(psmfplayer->psmfPlayerAvcAu.pts, videoDataAddr + 8);
|
||||
}
|
||||
|
||||
u32 tempbufSize = sizeof(psmfplayer->tempbuf);
|
||||
int addSize = std::min(psmfplayer->mediaengine->getRemainSize(), (int)tempbufSize);
|
||||
if (psmfplayer->filehandle && psmfplayer->tempbuf && addSize > 0) {
|
||||
u8* buf = psmfplayer->tempbuf;
|
||||
int size = pspFileSystem.ReadFile(psmfplayer->filehandle, buf, addSize);
|
||||
if (size)
|
||||
psmfplayer->mediaengine->addStreamData(buf, size);
|
||||
}
|
||||
int ret = psmfplayer->mediaengine->IsVideoEnd() ? ERROR_PSMFPLAYER_NO_MORE_DATA : 0;
|
||||
|
||||
s64 deltapts = psmfplayer->mediaengine->getVideoTimeStamp() - psmfplayer->mediaengine->getAudioTimeStamp();
|
||||
@ -1042,10 +1114,14 @@ u32 scePsmfPlayerGetCurrentAudioStream(u32 psmfPlayer, u32 audioCodecAddr, u32 a
|
||||
|
||||
int scePsmfPlayerSetTempBuf(u32 psmfPlayer, u32 tempBufAddr, u32 tempBufSize)
|
||||
{
|
||||
ERROR_LOG(HLE, "UNIMPL scePsmfPlayerSetTempBuf(%08x, %08x, %08x)", psmfPlayer, tempBufAddr, tempBufSize);
|
||||
INFO_LOG(HLE, "scePsmfPlayerSetTempBuf(%08x, %08x, %08x)", psmfPlayer, tempBufAddr, tempBufSize);
|
||||
PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
|
||||
if (psmfplayer)
|
||||
if (psmfplayer) {
|
||||
psmfplayer->status = PSMF_PLAYER_STATUS_INIT;
|
||||
// fake it right now, use tempbuf from memory directly
|
||||
//psmfplayer->tempbuf = tempBufAddr;
|
||||
//psmfplayer->tempbufSize = tempBufSize;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1193,8 +1269,8 @@ const HLEFunction scePsmfPlayer[] =
|
||||
{0xf3efaa91, WrapU_UUU<scePsmfPlayerGetCurrentPlayMode>, "scePsmfPlayerGetCurrentPlayMode"},
|
||||
{0xf8ef08a6, WrapI_U<scePsmfPlayerGetCurrentStatus>, "scePsmfPlayerGetCurrentStatus"},
|
||||
{0x2D0E4E0A, WrapI_UUU<scePsmfPlayerSetTempBuf>, "scePsmfPlayerSetTempBuf"},
|
||||
{0x76C0F4AE, 0, "scePsmfPlayerSetPsmfOffset"},
|
||||
{0xA72DB4F9, 0, "scePsmfPlayerSetPsmfOffsetCB"},
|
||||
{0x76C0F4AE, WrapI_UCI<scePsmfPlayerSetPsmfOffset>, "scePsmfPlayerSetPsmfOffset"},
|
||||
{0xA72DB4F9, WrapI_UCI<scePsmfPlayerSetPsmfOffsetCB>, "scePsmfPlayerSetPsmfOffsetCB"},
|
||||
};
|
||||
|
||||
void Register_scePsmf() {
|
||||
|
@ -80,7 +80,7 @@ static int getPixelFormatBytes(int pspFormat)
|
||||
}
|
||||
}
|
||||
|
||||
MediaEngine::MediaEngine(): m_streamSize(0), m_readSize(0), m_decodedPos(0), m_pdata(0) {
|
||||
MediaEngine::MediaEngine(): m_pdata(0) {
|
||||
m_pFormatCtx = 0;
|
||||
m_pCodecCtx = 0;
|
||||
m_pFrame = 0;
|
||||
@ -93,6 +93,8 @@ MediaEngine::MediaEngine(): m_streamSize(0), m_readSize(0), m_decodedPos(0), m_p
|
||||
m_audioContext = 0;
|
||||
m_isVideoEnd = false;
|
||||
m_isAudioEnd = false;
|
||||
m_bufSize = 0x2000;
|
||||
m_mpegheaderReadPos = 0;
|
||||
}
|
||||
|
||||
MediaEngine::~MediaEngine() {
|
||||
@ -117,7 +119,7 @@ void MediaEngine::closeMedia() {
|
||||
avformat_close_input(&m_pFormatCtx);
|
||||
#endif // USE_FFMPEG
|
||||
if (m_pdata)
|
||||
delete [] m_pdata;
|
||||
delete m_pdata;
|
||||
if (m_demux)
|
||||
delete m_demux;
|
||||
m_buffer = 0;
|
||||
@ -133,50 +135,53 @@ void MediaEngine::closeMedia() {
|
||||
m_isAudioEnd = false;
|
||||
}
|
||||
|
||||
void MediaEngine::DoState(PointerWrap &p){
|
||||
p.Do(m_videoStream);
|
||||
p.Do(m_audioStream);
|
||||
|
||||
p.DoArray(m_mpegheader, sizeof(m_mpegheader));
|
||||
|
||||
p.Do(m_ringbuffersize);
|
||||
|
||||
u32 hasloadStream = m_pdata != NULL;
|
||||
p.Do(hasloadStream);
|
||||
if (hasloadStream && p.mode == p.MODE_READ)
|
||||
loadStream(m_mpegheader, 2048, m_ringbuffersize);
|
||||
u32 hasopencontext = m_pFormatCtx != NULL;
|
||||
p.Do(hasopencontext);
|
||||
if (hasopencontext && p.mode == p.MODE_READ)
|
||||
openContext();
|
||||
if (m_pdata)
|
||||
m_pdata->DoState(p);
|
||||
if (m_demux)
|
||||
m_demux->DoState(p);
|
||||
|
||||
p.Do(m_videopts);
|
||||
p.Do(m_audiopts);
|
||||
|
||||
p.Do(m_isVideoEnd);
|
||||
p.Do(m_isAudioEnd);
|
||||
p.DoMarker("MediaEngine");
|
||||
}
|
||||
|
||||
int _MpegReadbuffer(void *opaque, uint8_t *buf, int buf_size)
|
||||
{
|
||||
MediaEngine *mpeg = (MediaEngine *)opaque;
|
||||
if ((u32)mpeg->m_decodeNextPos > (u32)mpeg->m_streamSize)
|
||||
return -1;
|
||||
|
||||
int size = std::min(mpeg->m_bufSize, buf_size);
|
||||
int available = mpeg->m_readSize - mpeg->m_decodeNextPos;
|
||||
int remaining = mpeg->m_streamSize - mpeg->m_decodeNextPos;
|
||||
|
||||
// There's more in the file, and there's not as much as requested available.
|
||||
// Return nothing. Partial packets will cause artifacts or green frames.
|
||||
if (available < remaining && size > available)
|
||||
int size = buf_size;
|
||||
const int mpegheaderSize = sizeof(mpeg->m_mpegheader);
|
||||
if (mpeg->m_mpegheaderReadPos < mpegheaderSize) {
|
||||
size = std::min(buf_size, mpegheaderSize - mpeg->m_mpegheaderReadPos);
|
||||
memcpy(buf, mpeg->m_mpegheader + mpeg->m_mpegheaderReadPos, size);
|
||||
mpeg->m_mpegheaderReadPos += size;
|
||||
} else if (mpeg->m_mpegheaderReadPos == mpegheaderSize) {
|
||||
return 0;
|
||||
|
||||
size = std::min(size, remaining);
|
||||
if (size > 0)
|
||||
memcpy(buf, mpeg->m_pdata + mpeg->m_decodeNextPos, size);
|
||||
mpeg->m_decodeNextPos += size;
|
||||
return size;
|
||||
}
|
||||
|
||||
int64_t _MpegSeekbuffer(void *opaque, int64_t offset, int whence)
|
||||
{
|
||||
MediaEngine *mpeg = (MediaEngine*)opaque;
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
mpeg->m_decodeNextPos = offset;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
mpeg->m_decodeNextPos += offset;
|
||||
break;
|
||||
case SEEK_END:
|
||||
mpeg->m_decodeNextPos = mpeg->m_streamSize - (u32)offset;
|
||||
break;
|
||||
|
||||
#ifdef USE_FFMPEG
|
||||
// Don't seek, just return the full size.
|
||||
// Returning this means FFmpeg won't think frames are truncated if we don't have them yet.
|
||||
case AVSEEK_SIZE:
|
||||
return mpeg->m_streamSize;
|
||||
#endif
|
||||
} else {
|
||||
size = mpeg->m_pdata->pop_front(buf, buf_size);
|
||||
if (size > 0)
|
||||
mpeg->m_decodingsize = size;
|
||||
}
|
||||
return mpeg->m_decodeNextPos;
|
||||
return size;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
@ -194,13 +199,15 @@ bool MediaEngine::openContext() {
|
||||
av_log_set_level(AV_LOG_VERBOSE);
|
||||
av_log_set_callback(&ffmpeg_logger);
|
||||
#endif
|
||||
if (m_readSize <= 0x2000 || m_pFormatCtx || !m_pdata)
|
||||
if (m_pFormatCtx || !m_pdata)
|
||||
return false;
|
||||
m_mpegheaderReadPos = 0;
|
||||
m_decodingsize = 0;
|
||||
|
||||
u8* tempbuf = (u8*)av_malloc(m_bufSize);
|
||||
|
||||
m_pFormatCtx = avformat_alloc_context();
|
||||
m_pIOContext = avio_alloc_context(tempbuf, m_bufSize, 0, (void*)this, _MpegReadbuffer, NULL, _MpegSeekbuffer);
|
||||
m_pIOContext = avio_alloc_context(tempbuf, m_bufSize, 0, (void*)this, _MpegReadbuffer, NULL, 0);
|
||||
m_pFormatCtx->pb = m_pIOContext;
|
||||
|
||||
// Open video file
|
||||
@ -236,20 +243,16 @@ bool MediaEngine::openContext() {
|
||||
return false; // Could not open codec
|
||||
|
||||
setVideoDim();
|
||||
int mpegoffset = bswap32(*(int*)(m_pdata + 8));
|
||||
m_demux = new MpegDemux(m_pdata, m_streamSize, mpegoffset);
|
||||
m_demux->setReadSize(m_readSize);
|
||||
m_demux->demux(m_audioStream);
|
||||
m_audioPos = 0;
|
||||
m_audioContext = Atrac3plus_Decoder::OpenContext();
|
||||
m_isVideoEnd = false;
|
||||
m_isAudioEnd = false;
|
||||
m_decodedPos = mpegoffset;
|
||||
m_mpegheaderReadPos++;
|
||||
av_seek_frame(m_pFormatCtx, m_videoStream, 0, 0);
|
||||
#endif // USE_FFMPEG
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MediaEngine::loadStream(u8* buffer, int readSize, int StreamSize)
|
||||
bool MediaEngine::loadStream(u8* buffer, int readSize, int RingbufferSize)
|
||||
{
|
||||
closeMedia();
|
||||
// force to clear the useless FBO
|
||||
@ -257,55 +260,36 @@ bool MediaEngine::loadStream(u8* buffer, int readSize, int StreamSize)
|
||||
|
||||
m_videopts = 0;
|
||||
m_audiopts = 0;
|
||||
m_bufSize = 0x2000;
|
||||
m_decodeNextPos = 0;
|
||||
m_readSize = readSize;
|
||||
m_streamSize = StreamSize;
|
||||
m_pdata = new u8[StreamSize];
|
||||
m_ringbuffersize = RingbufferSize;
|
||||
m_pdata = new Atrac3plus_Decoder::BufferQueue(RingbufferSize + 2048);
|
||||
if (!m_pdata)
|
||||
return false;
|
||||
memcpy(m_pdata, buffer, m_readSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MediaEngine::loadFile(const char* filename)
|
||||
{
|
||||
PSPFileInfo info = pspFileSystem.GetFileInfo(filename);
|
||||
s64 infosize = info.size;
|
||||
u8* buf = new u8[infosize];
|
||||
if (!buf)
|
||||
return false;
|
||||
u32 h = pspFileSystem.OpenFile(filename, (FileAccess) FILEACCESS_READ);
|
||||
pspFileSystem.ReadFile(h, buf, infosize);
|
||||
pspFileSystem.CloseFile(h);
|
||||
|
||||
closeMedia();
|
||||
// force to clear the useless FBO
|
||||
gpu->Resized();
|
||||
|
||||
m_videopts = 0;
|
||||
m_audiopts = 0;
|
||||
m_bufSize = 0x2000;
|
||||
m_decodeNextPos = 0;
|
||||
m_readSize = infosize;
|
||||
m_streamSize = infosize;
|
||||
m_pdata = buf;
|
||||
|
||||
m_pdata->push(buffer, readSize);
|
||||
m_firstTimeStamp = getMpegTimeStamp(buffer + PSMF_FIRST_TIMESTAMP_OFFSET);
|
||||
m_lastTimeStamp = getMpegTimeStamp(buffer + PSMF_LAST_TIMESTAMP_OFFSET);
|
||||
int mpegoffset = bswap32(*(int*)(buffer + 8));
|
||||
m_demux = new MpegDemux(RingbufferSize + 2048, mpegoffset);
|
||||
m_demux->addStreamData(buffer, readSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
int MediaEngine::addStreamData(u8* buffer, int addSize) {
|
||||
int size = std::min(addSize, m_streamSize - m_readSize);
|
||||
int size = addSize;
|
||||
if (size > 0 && m_pdata) {
|
||||
memcpy(m_pdata + m_readSize, buffer, size);
|
||||
m_readSize += size;
|
||||
if (!m_pFormatCtx && (m_readSize > 0x20000 || m_readSize >= m_streamSize))
|
||||
openContext();
|
||||
if (!m_pdata->push(buffer, size))
|
||||
size = 0;
|
||||
if (m_demux) {
|
||||
m_demux->setReadSize(m_readSize);
|
||||
m_demux->addStreamData(buffer, addSize);
|
||||
m_demux->demux(m_audioStream);
|
||||
}
|
||||
#ifdef USE_FFMPEG
|
||||
if (!m_pFormatCtx) {
|
||||
m_pdata->get_front(m_mpegheader, sizeof(m_mpegheader));
|
||||
int mpegoffset = bswap32(*(int*)(m_mpegheader + 8));
|
||||
m_pdata->pop_front(0, mpegoffset);
|
||||
openContext();
|
||||
}
|
||||
#endif // USE_FFMPEG
|
||||
}
|
||||
return size;
|
||||
}
|
||||
@ -389,15 +373,6 @@ bool MediaEngine::stepVideo(int videoPixelMode) {
|
||||
bool bGetFrame = false;
|
||||
while (!bGetFrame) {
|
||||
bool dataEnd = av_read_frame(m_pFormatCtx, &packet) < 0;
|
||||
if (!dataEnd) {
|
||||
if (packet.pos != -1) {
|
||||
m_decodedPos = packet.pos;
|
||||
} else {
|
||||
// Packet doesn't know where it is in the file, let's try to approximate.
|
||||
m_decodedPos += packet.size;
|
||||
}
|
||||
}
|
||||
|
||||
// Even if we've read all frames, some may have been re-ordered frames at the end.
|
||||
// Still need to decode those, so keep calling avcodec_decode_video2().
|
||||
if (dataEnd || packet.stream_index == m_videoStream) {
|
||||
@ -410,16 +385,15 @@ bool MediaEngine::stepVideo(int videoPixelMode) {
|
||||
sws_scale(m_sws_ctx, m_pFrame->data, m_pFrame->linesize, 0,
|
||||
m_pCodecCtx->height, m_pFrameRGB->data, m_pFrameRGB->linesize);
|
||||
|
||||
s64 firstTimeStamp = getMpegTimeStamp(m_pdata + PSMF_FIRST_TIMESTAMP_OFFSET);
|
||||
m_videopts = m_pFrame->pkt_dts + av_frame_get_pkt_duration(m_pFrame) - firstTimeStamp;
|
||||
m_videopts = m_pFrame->pkt_dts + av_frame_get_pkt_duration(m_pFrame) - m_firstTimeStamp;
|
||||
bGetFrame = true;
|
||||
}
|
||||
if (result <= 0 && dataEnd) {
|
||||
// Sometimes, m_readSize is less than m_streamSize at the end, but not by much.
|
||||
// This is kinda a hack, but the ringbuffer would have to be prematurely empty too.
|
||||
m_isVideoEnd = !bGetFrame && m_readSize >= (m_streamSize - 4096);
|
||||
m_isVideoEnd = !bGetFrame && (m_pdata->getQueueSize() == 0);
|
||||
if (m_isVideoEnd)
|
||||
m_decodedPos = m_readSize;
|
||||
m_decodingsize = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -593,54 +567,23 @@ int MediaEngine::writeVideoImageWithRange(u8* buffer, int frameWidth, int videoP
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool isHeader(u8* audioStream, int offset)
|
||||
{
|
||||
const u8 header1 = (u8)0x0F;
|
||||
const u8 header2 = (u8)0xD0;
|
||||
return (audioStream[offset] == header1) && (audioStream[offset+1] == header2);
|
||||
}
|
||||
|
||||
static int getNextHeaderPosition(u8* audioStream, int curpos, int limit, int frameSize)
|
||||
{
|
||||
int endScan = limit - 1;
|
||||
|
||||
// Most common case: the header can be found at each frameSize
|
||||
int offset = curpos + frameSize - 8;
|
||||
if (offset < endScan && isHeader(audioStream, offset))
|
||||
return offset;
|
||||
for (int scan = curpos; scan < endScan; scan++) {
|
||||
if (isHeader(audioStream, scan))
|
||||
return scan;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int MediaEngine::getBufferedSize() {
|
||||
return std::max(0, m_readSize - (int)m_decodedPos);
|
||||
int MediaEngine::getRemainSize() {
|
||||
if (!m_pdata)
|
||||
return 0;
|
||||
return std::max(m_pdata->getRemainSize() - m_decodingsize - 2048, 0);
|
||||
}
|
||||
|
||||
int MediaEngine::getAudioSamples(u8* buffer) {
|
||||
if (!m_demux) {
|
||||
return 0;
|
||||
}
|
||||
u8* audioStream = 0;
|
||||
int audioSize = m_demux->getaudioStream(&audioStream);
|
||||
if (m_audioPos >= audioSize || !isHeader(audioStream, m_audioPos))
|
||||
{
|
||||
m_isAudioEnd = m_demux->getFilePosition() >= m_streamSize;
|
||||
u8 *audioFrame = 0;
|
||||
int headerCode1, headerCode2;
|
||||
int frameSize = m_demux->getNextaudioFrame(&audioFrame, &headerCode1, &headerCode2);
|
||||
if (frameSize == 0)
|
||||
return 0;
|
||||
}
|
||||
u8 headerCode1 = audioStream[2];
|
||||
u8 headerCode2 = audioStream[3];
|
||||
int frameSize = ((headerCode1 & 0x03) << 8) | (headerCode2 & 0xFF) * 8 + 0x10;
|
||||
if (m_audioPos + frameSize > audioSize)
|
||||
return 0;
|
||||
m_audioPos += 8;
|
||||
int nextHeader = getNextHeaderPosition(audioStream, m_audioPos, audioSize, frameSize);
|
||||
u8* frame = audioStream + m_audioPos;
|
||||
int outbytes = 0;
|
||||
Atrac3plus_Decoder::Decode(m_audioContext, frame, frameSize - 8, &outbytes, buffer);
|
||||
Atrac3plus_Decoder::Decode(m_audioContext, audioFrame, frameSize, &outbytes, buffer);
|
||||
if (headerCode1 == 0x24) {
|
||||
// it a mono atrac3plus, convert it to stereo
|
||||
s16 *outbuf = (s16*)buffer;
|
||||
@ -651,13 +594,8 @@ int MediaEngine::getAudioSamples(u8* buffer) {
|
||||
outbuf[i * 2 + 1] = sample;
|
||||
}
|
||||
}
|
||||
if (nextHeader >= 0) {
|
||||
m_audioPos = nextHeader;
|
||||
} else
|
||||
m_audioPos = audioSize;
|
||||
m_audiopts += 4180;
|
||||
m_decodedPos += frameSize;
|
||||
return outbytes;
|
||||
return 0x2000;
|
||||
}
|
||||
|
||||
s64 MediaEngine::getVideoTimeStamp() {
|
||||
@ -673,7 +611,5 @@ s64 MediaEngine::getAudioTimeStamp() {
|
||||
s64 MediaEngine::getLastTimeStamp() {
|
||||
if (!m_pdata)
|
||||
return 0;
|
||||
s64 firstTimeStamp = getMpegTimeStamp(m_pdata + PSMF_FIRST_TIMESTAMP_OFFSET);
|
||||
s64 lastTimeStamp = getMpegTimeStamp(m_pdata + PSMF_LAST_TIMESTAMP_OFFSET);
|
||||
return lastTimeStamp - firstTimeStamp;
|
||||
return m_lastTimeStamp - m_firstTimeStamp;
|
||||
}
|
||||
|
@ -48,8 +48,7 @@ public:
|
||||
~MediaEngine();
|
||||
|
||||
void closeMedia();
|
||||
bool loadStream(u8* buffer, int readSize, int StreamSize);
|
||||
bool loadFile(const char* filename);
|
||||
bool loadStream(u8* buffer, int readSize, int RingbufferSize);
|
||||
// open the mpeg context
|
||||
bool openContext();
|
||||
// Returns number of packets actually added.
|
||||
@ -58,8 +57,7 @@ public:
|
||||
void setVideoStream(int streamNum) { m_videoStream = streamNum; }
|
||||
void setAudioStream(int streamNum) { m_audioStream = streamNum; }
|
||||
|
||||
int getRemainSize() { return m_streamSize - m_readSize;}
|
||||
int getBufferedSize();
|
||||
int getRemainSize();
|
||||
|
||||
bool stepVideo(int videoPixelMode);
|
||||
int writeVideoImage(u8* buffer, int frameWidth = 512, int videoPixelMode = 3);
|
||||
@ -75,11 +73,7 @@ public:
|
||||
bool IsVideoEnd() { return m_isVideoEnd; }
|
||||
bool IsAudioEnd() { return m_isAudioEnd; }
|
||||
|
||||
void DoState(PointerWrap &p) {
|
||||
p.Do(m_streamSize);
|
||||
p.Do(m_readSize);
|
||||
p.DoMarker("MediaEngine");
|
||||
}
|
||||
void DoState(PointerWrap &p);
|
||||
|
||||
private:
|
||||
void updateSwsFormat(int videoPixelMode);
|
||||
@ -99,19 +93,22 @@ public:
|
||||
|
||||
int m_desWidth;
|
||||
int m_desHeight;
|
||||
int m_streamSize;
|
||||
int m_readSize;
|
||||
int m_decodeNextPos;
|
||||
s64 m_decodedPos;
|
||||
int m_decodingsize;
|
||||
int m_bufSize;
|
||||
s64 m_videopts;
|
||||
u8* m_pdata;
|
||||
Atrac3plus_Decoder::BufferQueue *m_pdata;
|
||||
|
||||
MpegDemux *m_demux;
|
||||
int m_audioPos;
|
||||
void* m_audioContext;
|
||||
s64 m_audiopts;
|
||||
|
||||
s64 m_firstTimeStamp;
|
||||
s64 m_lastTimeStamp;
|
||||
|
||||
bool m_isVideoEnd;
|
||||
bool m_isAudioEnd;
|
||||
|
||||
int m_ringbuffersize;
|
||||
u8 m_mpegheader[0x10000];
|
||||
int m_mpegheaderReadPos;
|
||||
};
|
||||
|
@ -18,13 +18,12 @@ 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)
|
||||
MpegDemux::MpegDemux(int size, int offset) : m_audioStream(size)
|
||||
{
|
||||
m_buf = buffer;
|
||||
m_buf = new u8[size];
|
||||
|
||||
m_len = size;
|
||||
m_index = offset;
|
||||
m_audioStream = 0;
|
||||
m_audiopos = 0;
|
||||
m_audioChannel = -1;
|
||||
m_readSize = 0;
|
||||
}
|
||||
@ -32,13 +31,14 @@ MpegDemux::MpegDemux(u8* buffer, int size, int offset)
|
||||
|
||||
MpegDemux::~MpegDemux(void)
|
||||
{
|
||||
if (m_audioStream)
|
||||
delete [] m_audioStream;
|
||||
}
|
||||
|
||||
void MpegDemux::setReadSize(int readSize)
|
||||
{
|
||||
m_readSize = readSize;
|
||||
bool MpegDemux::addStreamData(u8* buf, int addSize) {
|
||||
if (m_readSize + addSize > m_len)
|
||||
return false;
|
||||
memcpy(m_buf + m_readSize, buf, addSize);
|
||||
m_readSize += addSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
int MpegDemux::readPesHeader(PesHeader &pesHeader, int length, int startCode) {
|
||||
@ -133,8 +133,7 @@ int MpegDemux::demuxStream(bool bdemux, int startCode, int 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;
|
||||
m_audioStream.push(m_buf + m_index, length);
|
||||
}
|
||||
skip(length);
|
||||
} else {
|
||||
@ -145,14 +144,12 @@ int MpegDemux::demuxStream(bool bdemux, int startCode, int channel)
|
||||
|
||||
void MpegDemux::demux(int audioChannel)
|
||||
{
|
||||
if (!m_audioStream)
|
||||
m_audioStream = new u8[m_len - m_index];
|
||||
if (audioChannel >= 0)
|
||||
m_audioChannel = audioChannel;
|
||||
while (m_index < m_len)
|
||||
{
|
||||
if (m_readSize != m_len && m_index + 2048 > m_readSize)
|
||||
return;
|
||||
if (m_index + 2048 > m_readSize)
|
||||
break;
|
||||
// Search for start code
|
||||
int startCode = 0xFF;
|
||||
while ((startCode & PACKET_START_CODE_MASK) != PACKET_START_CODE_PREFIX && !isEOF()) {
|
||||
@ -191,10 +188,59 @@ void MpegDemux::demux(int audioChannel)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (m_index < m_readSize) {
|
||||
int size = m_readSize - m_index;
|
||||
memcpy(m_buf, m_buf + m_index, size);
|
||||
m_index = 0;
|
||||
m_readSize = size;
|
||||
} else {
|
||||
m_index = 0;
|
||||
m_readSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int MpegDemux::getaudioStream(u8** audioStream)
|
||||
static bool isHeader(u8* audioStream, int offset)
|
||||
{
|
||||
*audioStream = m_audioStream;
|
||||
return m_audiopos;
|
||||
const u8 header1 = (u8)0x0F;
|
||||
const u8 header2 = (u8)0xD0;
|
||||
return (audioStream[offset] == header1) && (audioStream[offset+1] == header2);
|
||||
}
|
||||
|
||||
static int getNextHeaderPosition(u8* audioStream, int curpos, int limit, int frameSize)
|
||||
{
|
||||
int endScan = limit - 1;
|
||||
|
||||
// Most common case: the header can be found at each frameSize
|
||||
int offset = curpos + frameSize - 8;
|
||||
if (offset < endScan && isHeader(audioStream, offset))
|
||||
return offset;
|
||||
for (int scan = curpos; scan < endScan; scan++) {
|
||||
if (isHeader(audioStream, scan))
|
||||
return scan;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int MpegDemux::getNextaudioFrame(u8** buf, int *headerCode1, int *headerCode2)
|
||||
{
|
||||
int gotsize = m_audioStream.get_front(m_audioFrame, 0x2000);
|
||||
if (gotsize == 0 || !isHeader(m_audioFrame, 0))
|
||||
return 0;
|
||||
u8 Code1 = m_audioFrame[2];
|
||||
u8 Code2 = m_audioFrame[3];
|
||||
int frameSize = ((Code1 & 0x03) << 8) | (Code2 & 0xFF) * 8 + 0x10;
|
||||
if (frameSize > gotsize)
|
||||
return 0;
|
||||
int audioPos = 8;
|
||||
int nextHeader = getNextHeaderPosition(m_audioFrame, audioPos, gotsize, frameSize);
|
||||
if (nextHeader >= 0) {
|
||||
audioPos = nextHeader;
|
||||
} else
|
||||
audioPos = gotsize;
|
||||
m_audioStream.pop_front(0, audioPos);
|
||||
*buf = m_audioFrame + 8;
|
||||
if (headerCode1) *headerCode1 = Code1;
|
||||
if (headerCode2) *headerCode2 = Code2;
|
||||
return frameSize - 8;
|
||||
}
|
||||
|
@ -4,20 +4,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../Globals.h"
|
||||
#include "Core/HW/atrac3plus.h"
|
||||
#include "Common/ChunkFile.h"
|
||||
|
||||
class MpegDemux
|
||||
{
|
||||
public:
|
||||
MpegDemux(u8* buffer, int size, int offset);
|
||||
MpegDemux(int size, int offset);
|
||||
~MpegDemux(void);
|
||||
|
||||
void setReadSize(int readSize);
|
||||
|
||||
bool addStreamData(u8* buf, int addSize);
|
||||
void demux(int audioChannel);
|
||||
|
||||
// return its size
|
||||
int getaudioStream(u8 **audioStream);
|
||||
int getFilePosition() { return m_index; }
|
||||
// return its framesize
|
||||
int getNextaudioFrame(u8** buf, int *headerCode1, int *headerCode2);
|
||||
private:
|
||||
struct PesHeader {
|
||||
long pts;
|
||||
@ -52,12 +52,22 @@ private:
|
||||
}
|
||||
int readPesHeader(PesHeader &pesHeader, int length, int startCode);
|
||||
int demuxStream(bool bdemux, int startCode, int channel);
|
||||
public:
|
||||
void DoState(PointerWrap &p) {
|
||||
p.Do(m_index);
|
||||
p.Do(m_len);
|
||||
p.Do(m_audioChannel);
|
||||
p.Do(m_readSize);
|
||||
if (m_buf)
|
||||
p.DoArray(m_buf, m_len);
|
||||
p.DoClass(m_audioStream);
|
||||
}
|
||||
private:
|
||||
int m_index;
|
||||
int m_len;
|
||||
u8* m_buf;
|
||||
u8* m_audioStream;
|
||||
int m_audiopos;
|
||||
Atrac3plus_Decoder::BufferQueue m_audioStream;
|
||||
u8 m_audioFrame[0x2000];
|
||||
int m_audioChannel;
|
||||
int m_readSize;
|
||||
};
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef _ATRAC3PLUS_DECODER_
|
||||
#define _ATRAC3PLUS_DECODER_
|
||||
|
||||
#include "Common/ChunkFile.h"
|
||||
|
||||
namespace Atrac3plus_Decoder {
|
||||
bool IsSupported();
|
||||
bool IsInstalled();
|
||||
@ -49,6 +51,10 @@ namespace Atrac3plus_Decoder {
|
||||
return (end + bufQueueSize - start) % bufQueueSize;
|
||||
}
|
||||
|
||||
inline int getRemainSize() {
|
||||
return bufQueueSize - getQueueSize();
|
||||
}
|
||||
|
||||
bool push(unsigned char *buf, int addsize) {
|
||||
int queuesz = getQueueSize();
|
||||
int space = bufQueueSize - queuesz;
|
||||
@ -66,6 +72,25 @@ namespace Atrac3plus_Decoder {
|
||||
}
|
||||
|
||||
int pop_front(unsigned char *buf, int wantedsize) {
|
||||
if (wantedsize <= 0)
|
||||
return 0;
|
||||
int bytesgot = getQueueSize();
|
||||
if (wantedsize < bytesgot)
|
||||
bytesgot = wantedsize;
|
||||
if (buf) {
|
||||
if (start + bytesgot <= bufQueueSize) {
|
||||
memcpy(buf, bufQueue + start, bytesgot);
|
||||
} else {
|
||||
int size = bufQueueSize - start;
|
||||
memcpy(buf, bufQueue + start, size);
|
||||
memcpy(buf + size, bufQueue, bytesgot - size);
|
||||
}
|
||||
}
|
||||
start = (start + bytesgot) % bufQueueSize;
|
||||
return bytesgot;
|
||||
}
|
||||
|
||||
int get_front(unsigned char *buf, int wantedsize) {
|
||||
if (wantedsize <= 0)
|
||||
return 0;
|
||||
int bytesgot = getQueueSize();
|
||||
@ -78,10 +103,17 @@ namespace Atrac3plus_Decoder {
|
||||
memcpy(buf, bufQueue + start, size);
|
||||
memcpy(buf + size, bufQueue, bytesgot - size);
|
||||
}
|
||||
start = (start + bytesgot) % bufQueueSize;
|
||||
return bytesgot;
|
||||
}
|
||||
|
||||
void DoState(PointerWrap &p) {
|
||||
p.Do(bufQueueSize);
|
||||
p.Do(start);
|
||||
p.Do(end);
|
||||
if (bufQueue)
|
||||
p.DoArray(bufQueue, bufQueueSize);
|
||||
}
|
||||
|
||||
unsigned char* bufQueue;
|
||||
int start, end;
|
||||
int bufQueueSize;
|
||||
|
Loading…
Reference in New Issue
Block a user