diff --git a/Utilities/SQueue.h b/Utilities/SQueue.h index ca7cb9fe15..1fee6f6727 100644 --- a/Utilities/SQueue.h +++ b/Utilities/SQueue.h @@ -81,15 +81,13 @@ public: } } - u32 GetCount() + volatile u32 GetCount() { - SMutexLocker lock(m_mutex); return m_count; } - bool IsEmpty() + volatile bool IsEmpty() { - SMutexLocker lock(m_mutex); return !m_count; } diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index df197bc1d9..2d98e28e4b 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -296,7 +296,7 @@ void CPUThread::ExecOnce() void CPUThread::Task() { - ConLog.Write("%s enter", CPUThread::GetFName().wx_str()); + if (Ini.HLELogging.GetValue()) ConLog.Write("%s enter", CPUThread::GetFName().wx_str()); const Array& bp = Emu.GetBreakPoints(); @@ -358,5 +358,5 @@ void CPUThread::Task() ConLog.Success("Exit Code: %d", exitcode); } - ConLog.Write("%s leave", CPUThread::GetFName().wx_str()); + if (Ini.HLELogging.GetValue()) ConLog.Write("%s leave", CPUThread::GetFName().wx_str()); } diff --git a/rpcs3/Emu/Cell/RawSPUThread.cpp b/rpcs3/Emu/Cell/RawSPUThread.cpp index 9a5c84e854..49f2abfff2 100644 --- a/rpcs3/Emu/Cell/RawSPUThread.cpp +++ b/rpcs3/Emu/Cell/RawSPUThread.cpp @@ -251,7 +251,7 @@ u32 RawSPUThread::GetIndex() const void RawSPUThread::Task() { - ConLog.Write("%s enter", PPCThread::GetFName().wx_str()); + if (Ini.HLELogging.GetValue()) ConLog.Write("%s enter", PPCThread::GetFName().wx_str()); const Array& bp = Emu.GetBreakPoints(); @@ -334,5 +334,5 @@ void RawSPUThread::Task() ConLog.Error("Exception: %s", wxString(e).wx_str()); } - ConLog.Write("%s leave", PPCThread::GetFName().wx_str()); + if (Ini.HLELogging.GetValue()) ConLog.Write("%s leave", PPCThread::GetFName().wx_str()); } diff --git a/rpcs3/Emu/SysCalls/Callback.cpp b/rpcs3/Emu/SysCalls/Callback.cpp index 017341218d..f64851b6c3 100644 --- a/rpcs3/Emu/SysCalls/Callback.cpp +++ b/rpcs3/Emu/SysCalls/Callback.cpp @@ -53,10 +53,33 @@ void Callback::Branch(bool wait) { m_has_data = false; + static SMutexGeneral cb_mutex; + CPUThread& thr = Emu.GetCallbackThread(); - while(Emu.IsRunning() && thr.IsAlive()) +again: + + while (thr.IsAlive()) + { + if (Emu.IsStopped()) + { + ConLog.Warning("Callback::Branch() aborted"); + return; + } Sleep(1); + } + + SMutexGeneralLocker lock(cb_mutex); + + if (thr.IsAlive()) + { + goto again; + } + if (Emu.IsStopped()) + { + ConLog.Warning("Callback::Branch() aborted"); + return; + } thr.Stop(); thr.Reset(); @@ -74,8 +97,20 @@ void Callback::Branch(bool wait) thr.Exec(); - if(wait) - GetCurrentPPCThread()->Wait(thr); + if (!wait) + { + return; + } + + while (thr.IsAlive()) + { + if (Emu.IsStopped()) + { + ConLog.Warning("Callback::Branch(true) aborted (end)"); + return; + } + Sleep(1); + } } void Callback::SetName(const std::string& name) diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp index bd1d4d9d14..b7b81bef2c 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp @@ -4,25 +4,334 @@ #include "cellPamf.h" #include "cellDmux.h" -extern "C" -{ -#include "libavformat\avformat.h" -} - void cellDmux_init(); Module cellDmux(0x0007, cellDmux_init); void dmuxQueryAttr(u32 info_addr /* may be 0 */, mem_ptr_t attr) { - attr->demuxerVerLower = 0; // TODO: check values - attr->demuxerVerUpper = 0; - attr->memSize = 1024 * 1024; // 1M + attr->demuxerVerLower = 0x280000; // TODO: check values + attr->demuxerVerUpper = 0x260000; + attr->memSize = 0x10000; // 0x3e8e6 from ps3 } void dmuxQueryEsAttr(u32 info_addr /* may be 0 */, const mem_ptr_t esFilterId, const u32 esSpecificInfo_addr, mem_ptr_t attr) { - attr->memSize = 1024 * 1024; + if (esFilterId->filterIdMajor >= 0xe0) + attr->memSize = 0x500000; // 0x45fa49 from ps3 + else + attr->memSize = 0x10000; // 0x73d9 from ps3 + + cellDmux.Warning("*** filter(0x%x, 0x%x, 0x%x, 0x%x)", (u32)esFilterId->filterIdMajor, (u32)esFilterId->filterIdMinor, + (u32)esFilterId->supplementalInfo1, (u32)esFilterId->supplementalInfo2); +} + +u32 dmuxOpen(Demuxer* data) +{ + Demuxer& dmux = *data; + + u32 dmux_id = cellDmux.GetNewId(data); + + dmux.id = dmux_id; + + thread t("Demuxer[" + std::to_string(dmux_id) + "] Thread", [&]() + { + ConLog.Write("Demuxer enter (mem=0x%x, size=0x%x, cb=0x%x, arg=0x%x)", dmux.memAddr, dmux.memSize, dmux.cbFunc, dmux.cbArg); + + DemuxerTask task; + DemuxerStream stream; + /* + ElementaryStream* esAVC[16]; memset(esAVC, 0, sizeof(esAVC)); + ElementaryStream* esM2V[16]; memset(esM2V, 0, sizeof(esM2V)); + ElementaryStream* esDATA[16]; memset(esDATA, 0, sizeof(esDATA)); + ElementaryStream* esATRAX[48]; memset(esATRAX, 0, sizeof(esATRAX)); + ElementaryStream* esAC3[48]; memset(esAC3, 0, sizeof(esAC3)); + ElementaryStream* esLPCM[48]; memset(esLPCM, 0, sizeof(esLPCM)); + */ + ElementaryStream* esALL[192]; memset(esALL, 0, sizeof(esALL)); + ElementaryStream** esAVC = &esALL[0]; + + u32 cb_add = 0; + + while (true) + { + if (Emu.IsStopped()) + { + break; + } + + if (dmux.job.IsEmpty() && dmux.is_running) + { + // default task (demuxing) (if there is no other work) + be_t code; + be_t len; + u8 ch; + + if (!stream.peek(code)) + { + // demuxing finished + task.type = dmuxResetStream; + goto task; + } + else switch (code.ToLE()) + { + case PACK_START_CODE: + { + stream.skip(14); + } + break; + + case SYSTEM_HEADER_START_CODE: + { + stream.skip(18); + } + break; + + case PADDING_STREAM: + case PRIVATE_STREAM_2: + { + // unknown + stream.skip(4); + stream.get(len); + stream.skip(len); + } + break; + + case PRIVATE_STREAM_1: + { + // audio AT3+ (and probably LPCM or user data) + stream.skip(4); + stream.get(len); + + // skipping... + stream.skip(len); + } + 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 AVC + ch = code - 0x1e0; + if (esAVC[ch]) + { + ElementaryStream& es = *esAVC[ch]; + if (es.isfull()) + { + Sleep(1); + continue; + } + + stream.skip(4); + stream.get(len); + PesHeader pes(stream); + + if (!pes.size && !es.hasdata()) // fatal error + { + ConLog.Error("PES not found"); + return; + } + + if (pes.size && es.hasdata()) // new AU detected + { + es.finish(stream); + // callback + mem_ptr_t esMsg(a128(dmux.memAddr) + (cb_add ^= 16)); + esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND; + esMsg->supplementalInfo = stream.userdata; + Callback cb; + cb.SetAddr(es.cbFunc); + cb.Handle(dmux.id, es.id, esMsg.GetAddr(), es.cbArg); + cb.Branch(false); + } + + if (pes.size) + { + //ConLog.Write("*** AVC AU detected (pts=0x%x, dts=0x%x)", pes.pts, pes.dts); + } + + es.push(stream, len - pes.size - 3, pes); + } + else + { + stream.skip(4); + stream.get(len); + stream.skip(len); + } + } + break; + + case 0x1c0: case 0x1c1: case 0x1c2: case 0x1c3: + case 0x1c4: case 0x1c5: case 0x1c6: case 0x1c7: + case 0x1c8: case 0x1c9: case 0x1ca: case 0x1cb: + case 0x1cc: case 0x1cd: case 0x1ce: case 0x1cf: + case 0x1d0: case 0x1d1: case 0x1d2: case 0x1d3: + case 0x1d4: case 0x1d5: case 0x1d6: case 0x1d7: + case 0x1d8: case 0x1d9: case 0x1da: case 0x1db: + case 0x1dc: case 0x1dd: case 0x1de: case 0x1df: + { + // unknown + stream.skip(4); + stream.get(len); + stream.skip(len); + } + break; + + case USER_DATA_START_CODE: + { + ConLog.Error("USER_DATA_START_CODE found"); + return; + } + + default: + { + // search + stream.skip(1); + } + break; + + } + continue; + } + + // wait for task with yielding (if no default work) + if (!dmux.job.Pop(task)) + { + break; // Emu is stopped + } +task: + switch (task.type) + { + case dmuxSetStream: + { + stream = task.stream; + ConLog.Write("*** stream updated(addr=0x%x, size=0x%x, discont=%d, userdata=0x%llx)", + stream.addr, stream.size, stream.discontinuity, stream.userdata); + if (stream.discontinuity) for (u32 i = 0; i < 192; i++) + { + if (esALL[i]) + { + esALL[i]->reset(); + } + } + dmux.is_running = true; + } + break; + + case dmuxResetStream: + case dmuxResetStreamAndWaitDone: + { + // TODO: send CELL_DMUX_MSG_TYPE_DEMUX_DONE callback and provide waiting condition + mem_ptr_t dmuxMsg(a128(dmux.memAddr) + (cb_add ^= 16)); + dmuxMsg->msgType = CELL_DMUX_MSG_TYPE_DEMUX_DONE; + dmuxMsg->supplementalInfo = stream.userdata; + Callback cb; + cb.SetAddr(dmux.cbFunc); + cb.Handle(dmux.id, dmuxMsg.GetAddr(), dmux.cbArg); + cb.Branch(task.type == dmuxResetStreamAndWaitDone); + dmux.is_running = false; + } + break; + + case dmuxClose: + { + dmux.is_finished = true; + ConLog.Write("Demuxer exit"); + return; + } + + case dmuxEnableEs: + { + ElementaryStream& es = *task.es.es_ptr; + if (es.fidMajor >= 0xe0 && + es.fidMajor <= 0xef && + es.fidMinor == 0 && + es.sup1 == 1 && + es.sup2 == 0) + { + esAVC[es.fidMajor - 0xe0] = task.es.es_ptr; + } + else + { + ConLog.Warning("dmuxEnableEs: (TODO) unsupported filter (0x%x, 0x%x, 0x%x, 0x%x)", es.fidMajor, es.fidMinor, es.sup1, es.sup2); + } + es.dmux = &dmux; + } + break; + + case dmuxDisableEs: + { + ElementaryStream& es = *task.es.es_ptr; + if (es.dmux != &dmux) + { + ConLog.Warning("dmuxDisableEs: invalid elementary stream"); + break; + } + for (u32 i = 0; i < 192; i++) + { + if (esALL[i] == &es) + { + esALL[i] = nullptr; + } + } + es.dmux = nullptr; + Emu.GetIdManager().RemoveID(task.es.es); + } + break; + + case dmuxReleaseAu: + { + task.es.es_ptr->release(); + } + break; + + case dmuxFlushEs: + { + ElementaryStream& es = *task.es.es_ptr; + + if (es.hasdata()) + { + es.finish(stream); + // callback + mem_ptr_t esMsg(a128(dmux.memAddr) + (cb_add ^= 16)); + esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND; + esMsg->supplementalInfo = stream.userdata; + Callback cb; + cb.SetAddr(es.cbFunc); + cb.Handle(dmux.id, es.id, esMsg.GetAddr(), es.cbArg); + cb.Branch(false); + } + + // callback + mem_ptr_t esMsg(a128(dmux.memAddr) + (cb_add ^= 16)); + esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_FLUSH_DONE; + esMsg->supplementalInfo = stream.userdata; + Callback cb; + cb.SetAddr(es.cbFunc); + cb.Handle(dmux.id, es.id, esMsg.GetAddr(), es.cbArg); + cb.Branch(false); + } + break; + + case dmuxResetEs: + { + task.es.es_ptr->reset(); + } + break; + + default: + ConLog.Error("Demuxer error: unknown task(%d)", task.type); + return; + } + } + ConLog.Warning("Demuxer aborted"); + }); + + t.detach(); + + return dmux_id; } int cellDmuxQueryAttr(const mem_ptr_t demuxerType, mem_ptr_t demuxerAttr) @@ -61,53 +370,6 @@ int cellDmuxQueryAttr2(const mem_ptr_t demuxerType2, mem_ptr_t demuxerType, const mem_ptr_t demuxerResource, const mem_ptr_t demuxerCb, mem32_t demuxerHandle) { @@ -131,7 +393,7 @@ int cellDmuxOpen(const mem_ptr_t demuxerType, const mem_ptr_tmemAddr, demuxerResource->memSize, (CellDmuxCbMsg&)demuxerCb->cbMsgFunc, demuxerCb->cbArg_addr)); + demuxerHandle = dmuxOpen(new Demuxer(demuxerResource->memAddr, demuxerResource->memSize, demuxerCb->cbMsgFunc, demuxerCb->cbArg_addr)); return CELL_OK; } @@ -159,7 +421,7 @@ int cellDmuxOpenEx(const mem_ptr_t demuxerType, const mem_ptr_tmemAddr, demuxerResourceEx->memSize, (CellDmuxCbMsg&)demuxerCb->cbMsgFunc, demuxerCb->cbArg_addr)); + demuxerHandle = dmuxOpen(new Demuxer(demuxerResourceEx->memAddr, demuxerResourceEx->memSize, demuxerCb->cbMsgFunc, demuxerCb->cbArg_addr)); return CELL_OK; } @@ -187,7 +449,7 @@ int cellDmuxOpen2(const mem_ptr_t demuxerType2, const mem_ptr_tmemAddr, demuxerResource2->memSize, (CellDmuxCbMsg&)demuxerCb->cbMsgFunc, demuxerCb->cbArg_addr)); + demuxerHandle = dmuxOpen(new Demuxer(demuxerResource2->memAddr, demuxerResource2->memSize, demuxerCb->cbMsgFunc, demuxerCb->cbArg_addr)); return CELL_OK; } @@ -221,7 +483,7 @@ int cellDmuxClose(u32 demuxerHandle) int cellDmuxSetStream(u32 demuxerHandle, const u32 streamAddress, u32 streamSize, bool discontinuity, u64 userData) { - cellDmux.Warning("cellDmuxSetStream(demuxerHandle=%d, streamAddress=0x%x, streamSize=%d, discontinuity=%d, userData=0x%llx", + cellDmux.Log("cellDmuxSetStream(demuxerHandle=%d, streamAddress=0x%x, streamSize=%d, discontinuity=%d, userData=0x%llx", demuxerHandle, streamAddress, streamSize, discontinuity, userData); Demuxer* dmux; @@ -235,8 +497,9 @@ int cellDmuxSetStream(u32 demuxerHandle, const u32 streamAddress, u32 streamSize return CELL_DMUX_ERROR_FATAL; } - if (!dmux->job.IsEmpty()) + if (dmux->is_running) { + Sleep(1); // performance hack return CELL_DMUX_ERROR_BUSY; } @@ -248,12 +511,22 @@ int cellDmuxSetStream(u32 demuxerHandle, const u32 streamAddress, u32 streamSize info.userdata = userData; dmux->job.Push(task); + + while (!dmux->is_running) + { + if (Emu.IsStopped()) + { + ConLog.Warning("cellDmuxSetStream(%d) aborted", demuxerHandle); + break; + } + Sleep(1); + } return CELL_OK; } int cellDmuxResetStream(u32 demuxerHandle) { - cellDmux.Warning("cellDmuxResetStream(demuxerHandle=%d)", demuxerHandle); + cellDmux.Log("cellDmuxResetStream(demuxerHandle=%d)", demuxerHandle); Demuxer* dmux; if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux)) @@ -268,7 +541,7 @@ int cellDmuxResetStream(u32 demuxerHandle) int cellDmuxResetStreamAndWaitDone(u32 demuxerHandle) { - cellDmux.Error("cellDmuxResetStreamAndWaitDone(demuxerHandle=%d)", demuxerHandle); + cellDmux.Log("cellDmuxResetStreamAndWaitDone(demuxerHandle=%d)", demuxerHandle); Demuxer* dmux; if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux)) @@ -276,9 +549,17 @@ int cellDmuxResetStreamAndWaitDone(u32 demuxerHandle) return CELL_DMUX_ERROR_ARG; } - dmux->job.Push(DemuxerTask(dmuxResetStream)); + dmux->job.Push(DemuxerTask(dmuxResetStreamAndWaitDone)); - // TODO: wait done + while (dmux->is_running) + { + if (Emu.IsStopped()) + { + ConLog.Warning("cellDmuxResetStreamAndWaitDone(%d) aborted", demuxerHandle); + break; + } + Sleep(1); + } return CELL_OK; } @@ -314,7 +595,7 @@ int cellDmuxQueryEsAttr(const mem_ptr_t demuxerType, const mem_ptr int cellDmuxQueryEsAttr2(const mem_ptr_t demuxerType2, const mem_ptr_t esFilterId, const u32 esSpecificInfo_addr, mem_ptr_t esAttr) { - cellDmux.Error("cellDmuxQueryEsAttr2(demuxerType2_addr=0x%x, esFilterId_addr=0x%x, esSpecificInfo_addr=0x%x, esAttr_addr=0x%x)", + cellDmux.Warning("cellDmuxQueryEsAttr2(demuxerType2_addr=0x%x, esFilterId_addr=0x%x, esSpecificInfo_addr=0x%x, esAttr_addr=0x%x)", demuxerType2.GetAddr(), esFilterId.GetAddr(), esSpecificInfo_addr, esAttr.GetAddr()); if (!demuxerType2.IsGood() || !esFilterId.IsGood() || !esAttr.IsGood()) @@ -373,13 +654,17 @@ int cellDmuxEnableEs(u32 demuxerHandle, const mem_ptr_t esF ElementaryStream* es = new ElementaryStream(dmux, esResourceInfo->memAddr, esResourceInfo->memSize, esFilterId->filterIdMajor, esFilterId->filterIdMinor, esFilterId->supplementalInfo1, esFilterId->supplementalInfo2, - (CellDmuxCbEsMsg&)esCb->cbEsMsgFunc, esCb->cbArg_addr, esSpecificInfo_addr); + esCb->cbEsMsgFunc, esCb->cbArg_addr, esSpecificInfo_addr); u32 id = cellDmux.GetNewId(es); + es->id = id; + + cellDmux.Warning("*** New ES(dmux=%d, addr=0x%x, size=0x%x, filter(0x%x, 0x%x, 0x%x, 0x%x), cb=0x%x(arg=0x%x), spec=0x%x): id = %d", + demuxerHandle, es->memAddr, es->memSize, es->fidMajor, es->fidMinor, es->sup1, es->sup2, (u32)esCb->cbEsMsgFunc, es->cbArg, es->spec, id); DemuxerTask task(dmuxEnableEs); - task.au.es = id; - task.au.es_ptr = es; + task.es.es = id; + task.es.es_ptr = es; dmux->job.Push(task); return CELL_OK; @@ -396,8 +681,8 @@ int cellDmuxDisableEs(u32 esHandle) } DemuxerTask task(dmuxDisableEs); - task.esHandle = esHandle; - task.au.es_ptr = es; + task.es.es = esHandle; + task.es.es_ptr = es; es->dmux->job.Push(task); return CELL_OK; @@ -405,7 +690,7 @@ int cellDmuxDisableEs(u32 esHandle) int cellDmuxResetEs(u32 esHandle) { - cellDmux.Warning("cellDmuxResetEs(esHandle=0x%x)", esHandle); + cellDmux.Log("cellDmuxResetEs(esHandle=0x%x)", esHandle); ElementaryStream* es; if (!Emu.GetIdManager().GetIDData(esHandle, es)) @@ -414,44 +699,17 @@ int cellDmuxResetEs(u32 esHandle) } DemuxerTask task(dmuxResetEs); - task.esHandle = esHandle; - task.au.es_ptr = es; + task.es.es = esHandle; + task.es.es_ptr = es; es->dmux->job.Push(task); return CELL_OK; } -int cellDmuxGetAu(u32 esHandle, const u32 auInfo_ptr_addr, u32 auSpecificInfo_ptr_addr) +int cellDmuxGetAu(u32 esHandle, mem32_t auInfo_ptr, mem32_t auSpecificInfo_ptr) { - cellDmux.Error("cellDmuxGetAu(esHandle=0x%x, auInfo_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)", - esHandle, auInfo_ptr_addr, auSpecificInfo_ptr_addr); - return CELL_OK; -} - -int cellDmuxPeekAu(u32 esHandle, const u32 auInfo_ptr_addr, u32 auSpecificInfo_ptr_addr) -{ - cellDmux.Error("cellDmuxPeekAu(esHandle=0x%x, auInfo_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)", - esHandle, auInfo_ptr_addr, auSpecificInfo_ptr_addr); - return CELL_OK; -} - -int cellDmuxGetAuEx(u32 esHandle, const u32 auInfoEx_ptr_addr, u32 auSpecificInfo_ptr_addr) -{ - cellDmux.Error("cellDmuxGetAuEx(esHandle=0x%x, auInfoEx_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)", - esHandle, auInfoEx_ptr_addr, auSpecificInfo_ptr_addr); - return CELL_OK; -} - -int cellDmuxPeekAuEx(u32 esHandle, const u32 auInfoEx_ptr_addr, u32 auSpecificInfo_ptr_addr) -{ - cellDmux.Error("cellDmuxPeekAuEx(esHandle=0x%x, auInfoEx_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)", - esHandle, auInfoEx_ptr_addr, auSpecificInfo_ptr_addr); - return CELL_OK; -} - -int cellDmuxReleaseAu(u32 esHandle) -{ - cellDmux.Warning("cellDmuxReleaseAu(esHandle=0x%x)", esHandle); + cellDmux.Log("cellDmuxGetAu(esHandle=0x%x, auInfo_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)", + esHandle, auInfo_ptr.GetAddr(), auSpecificInfo_ptr.GetAddr()); ElementaryStream* es; if (!Emu.GetIdManager().GetIDData(esHandle, es)) @@ -459,9 +717,125 @@ int cellDmuxReleaseAu(u32 esHandle) return CELL_DMUX_ERROR_ARG; } + if (!auInfo_ptr.IsGood() || !auSpecificInfo_ptr.IsGood()) + { + return CELL_DMUX_ERROR_FATAL; + } + + u32 info; + u32 spec; + if (!es->peek(info, true, spec, true)) + { + return CELL_DMUX_ERROR_EMPTY; + } + + auInfo_ptr = info; + auSpecificInfo_ptr = spec; + return CELL_OK; +} + +int cellDmuxPeekAu(u32 esHandle, mem32_t auInfo_ptr, mem32_t auSpecificInfo_ptr) +{ + cellDmux.Log("cellDmuxPeekAu(esHandle=0x%x, auInfo_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)", + esHandle, auInfo_ptr.GetAddr(), auSpecificInfo_ptr.GetAddr()); + + ElementaryStream* es; + if (!Emu.GetIdManager().GetIDData(esHandle, es)) + { + return CELL_DMUX_ERROR_ARG; + } + + if (!auInfo_ptr.IsGood() || !auSpecificInfo_ptr.IsGood()) + { + return CELL_DMUX_ERROR_FATAL; + } + + u32 info; + u32 spec; + if (!es->peek(info, true, spec, false)) + { + return CELL_DMUX_ERROR_EMPTY; + } + + auInfo_ptr = info; + auSpecificInfo_ptr = spec; + return CELL_OK; +} + +int cellDmuxGetAuEx(u32 esHandle, mem32_t auInfoEx_ptr, mem32_t auSpecificInfo_ptr) +{ + cellDmux.Log("cellDmuxGetAuEx(esHandle=0x%x, auInfoEx_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)", + esHandle, auInfoEx_ptr.GetAddr(), auSpecificInfo_ptr.GetAddr()); + + ElementaryStream* es; + if (!Emu.GetIdManager().GetIDData(esHandle, es)) + { + return CELL_DMUX_ERROR_ARG; + } + + if (!auInfoEx_ptr.IsGood() || !auSpecificInfo_ptr.IsGood()) + { + return CELL_DMUX_ERROR_FATAL; + } + + u32 info; + u32 spec; + if (!es->peek(info, false, spec, true)) + { + return CELL_DMUX_ERROR_EMPTY; + } + + auInfoEx_ptr = info; + auSpecificInfo_ptr = spec; + return CELL_OK; +} + +int cellDmuxPeekAuEx(u32 esHandle, mem32_t auInfoEx_ptr, mem32_t auSpecificInfo_ptr) +{ + cellDmux.Log("cellDmuxPeekAuEx(esHandle=0x%x, auInfoEx_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)", + esHandle, auInfoEx_ptr.GetAddr(), auSpecificInfo_ptr.GetAddr()); + + ElementaryStream* es; + if (!Emu.GetIdManager().GetIDData(esHandle, es)) + { + return CELL_DMUX_ERROR_ARG; + } + + if (!auInfoEx_ptr.IsGood() || !auSpecificInfo_ptr.IsGood()) + { + return CELL_DMUX_ERROR_FATAL; + } + + u32 info; + u32 spec; + if (!es->peek(info, false, spec, false)) + { + return CELL_DMUX_ERROR_EMPTY; + } + + auInfoEx_ptr = info; + auSpecificInfo_ptr = spec; + return CELL_OK; +} + +int cellDmuxReleaseAu(u32 esHandle) +{ + cellDmux.Log("cellDmuxReleaseAu(esHandle=0x%x)", esHandle); + + ElementaryStream* es; + if (!Emu.GetIdManager().GetIDData(esHandle, es)) + { + return CELL_DMUX_ERROR_ARG; + } + + if (!es->canrelease()) + { + return CELL_DMUX_ERROR_SEQ; + } + DemuxerTask task(dmuxReleaseAu); - task.esHandle = esHandle; - task.au.es_ptr = es; + task.es.es = esHandle; + task.es.es_ptr = es; es->dmux->job.Push(task); return CELL_OK; @@ -469,7 +843,7 @@ int cellDmuxReleaseAu(u32 esHandle) int cellDmuxFlushEs(u32 esHandle) { - cellDmux.Warning("cellDmuxFlushEs(esHandle=0x%x)", esHandle); + cellDmux.Log("cellDmuxFlushEs(esHandle=0x%x)", esHandle); ElementaryStream* es; if (!Emu.GetIdManager().GetIDData(esHandle, es)) @@ -478,8 +852,8 @@ int cellDmuxFlushEs(u32 esHandle) } DemuxerTask task(dmuxFlushEs); - task.esHandle = esHandle; - task.au.es_ptr = es; + task.es.es = esHandle; + task.es.es_ptr = es; es->dmux->job.Push(task); return CELL_OK; diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.h b/rpcs3/Emu/SysCalls/Modules/cellDmux.h index b2a3fe5ec8..2d0aa2ca38 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.h +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.h @@ -2,6 +2,9 @@ #include "Utilities/SQueue.h" +// align size or address to 128 +#define a128(x) ((x + 127) & (~127)) + // Error Codes enum { @@ -232,7 +235,7 @@ struct CellDmuxResource2 }; }; -typedef mem_func_ptr_t demuxerMsg, u32 cbArg_addr)> CellDmuxCbMsg; +typedef mem_func_ptr_t demuxerMsg, u32 cbArg_addr)> CellDmuxCbMsg; struct CellDmuxCb { @@ -241,7 +244,7 @@ struct CellDmuxCb be_t cbArg_addr; }; -typedef mem_func_ptr_t esMsg, u32 cbArg_addr)> CellDmuxCbEsMsg; +typedef mem_func_ptr_t esMsg, u32 cbArg_addr)> CellDmuxCbEsMsg; struct CellDmuxEsCb { @@ -293,16 +296,120 @@ struct CellDmuxAuInfoEx /* Demuxer Thread Classes */ -struct AccessUnit +enum +{ + /* http://dvd.sourceforge.net/dvdinfo/mpeghdrs.html */ + + PACKET_START_CODE_MASK = 0xffffff00, + PACKET_START_CODE_PREFIX = 0x00000100, + + USER_DATA_START_CODE = 0x000001b2, + SEQUENCE_START_CODE = 0x000001b3, + EXT_START_CODE = 0x000001b5, + SEQUENCE_END_CODE = 0x000001b7, + GOP_START_CODE = 0x000001b8, + ISO_11172_END_CODE = 0x000001b9, + PACK_START_CODE = 0x000001ba, + SYSTEM_HEADER_START_CODE = 0x000001bb, + PROGRAM_STREAM_MAP = 0x000001bc, + PRIVATE_STREAM_1 = 0x000001bd, + PADDING_STREAM = 0x000001be, + PRIVATE_STREAM_2 = 0x000001bf, +}; + +enum +{ + MAX_AU = 640 * 1024 + 128, // 640 KB +}; + +struct DemuxerStream { u32 addr; u32 size; - u32 ptsUpper; - u32 ptsLower; - u32 dtsUpper; - u32 dtsLower; - u64 userData; - bool isRap; + u64 userdata; + bool discontinuity; + + template + bool get(T& out) + { + if (sizeof(T) > size) return false; + + out = *mem_ptr_t(addr); + addr += sizeof(T); + size -= sizeof(T); + + return true; + } + + template + bool peek(T& out) + { + if (sizeof(T) > size) return false; + + out = *mem_ptr_t(addr); + return true; + } + + void skip(u32 count) + { + addr += count; + size = size > count ? size - count : 0; + } + + u32 get_ts(u8 c) + { + u16 v1, v2; get(v1); get(v2); + return (((u32) (c & 0x0E)) << 29) | ((v1 >> 1) << 15) | (v2 >> 1); + } + + u32 get_ts() + { + u8 v; get(v); + return get_ts(v); + } +}; + +struct PesHeader +{ + u32 pts; + u32 dts; + u8 ch; + u8 size; + + PesHeader(DemuxerStream& stream) + : pts(0) + , dts(0) + , ch(0) + , size(0) + { + u16 header; + stream.get(header); + stream.get(size); + if (size) + { + if (size < 10) + { + ConLog.Error("Unknown PesHeader size"); + Emu.Pause(); + } + u8 v; + stream.get(v); + if ((v & 0xF0) != 0x30) + { + ConLog.Error("Pts not found"); + Emu.Pause(); + } + pts = stream.get_ts(v); + stream.get(v); + if ((v & 0xF0) != 0x10) + { + ConLog.Error("Dts not found"); + Emu.Pause(); + } + dts = stream.get_ts(v); + stream.skip(size - 10); + } + } }; class ElementaryStream; @@ -311,32 +418,22 @@ enum DemuxerJobType { dmuxSetStream, dmuxResetStream, + dmuxResetStreamAndWaitDone, dmuxEnableEs, dmuxDisableEs, dmuxResetEs, - dmuxGetAu, - dmuxPeekAu, dmuxReleaseAu, dmuxFlushEs, dmuxClose, }; -#pragma pack(push, 1) struct DemuxerTask { DemuxerJobType type; union { - struct - { - u32 addr; - u64 userdata; - u32 size; - /*bool*/u32 discontinuity; - } stream; - - u32 esHandle; + DemuxerStream stream; struct { @@ -344,7 +441,7 @@ struct DemuxerTask u32 auInfo_ptr_addr; u32 auSpec_ptr_addr; ElementaryStream* es_ptr; - } au; + } es; }; DemuxerTask() @@ -356,8 +453,6 @@ struct DemuxerTask { } }; -static_assert(sizeof(DemuxerTask) == 24, ""); -#pragma pack(pop) class Demuxer { @@ -365,13 +460,16 @@ public: SQueue job; const u32 memAddr; const u32 memSize; - const CellDmuxCbMsg cbFunc; + const u32 cbFunc; const u32 cbArg; + u32 id; bool is_finished; + bool is_running; - Demuxer(u32 addr, u32 size, CellDmuxCbMsg func, u32 arg) + Demuxer(u32 addr, u32 size, u32 func, u32 arg) : is_finished(false) + , is_running(false) , memAddr(addr) , memSize(size) , cbFunc(func) @@ -382,19 +480,27 @@ public: class ElementaryStream { + SMutex mutex; + + u32 first_addr; // AU that will be released + u32 last_addr; // AU that is being written now + u32 last_size; // number of bytes written (after 128b header) + u32 peek_addr; // AU that will be obtained by GetAu(Ex)/PeekAu(Ex) + public: Demuxer* dmux; + u32 id; const u32 memAddr; const u32 memSize; const u32 fidMajor; const u32 fidMinor; const u32 sup1; const u32 sup2; - const CellDmuxCbEsMsg cbFunc; + const u32 cbFunc; const u32 cbArg; const u32 spec; //addr - ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, CellDmuxCbEsMsg cbFunc, u32 cbArg, u32 spec) + ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, u32 cbFunc, u32 cbArg, u32 spec) : dmux(dmux) , memAddr(addr) , memSize(size) @@ -405,6 +511,175 @@ public: , cbFunc(cbFunc) , cbArg(cbArg) , spec(spec) + , first_addr(0) + , peek_addr(0) + , last_addr(a128(addr)) + , last_size(0) { } + + volatile bool hasdata() + { + return last_size; + } + + bool isfull() // not multithread-safe + { + if (first_addr) + { + if (first_addr > last_addr) + { + return (first_addr - last_addr) < MAX_AU; + } + else + { + return (first_addr + MAX_AU) > (memAddr + memSize); + } + } + else + { + return false; + } + } + + void finish(DemuxerStream& stream) // not multithread-safe + { + SMutexLocker lock(mutex); + + if (!first_addr) + { + first_addr = last_addr; + } + if (!peek_addr) + { + peek_addr = last_addr; + } + u32 new_addr = a128(last_addr + 128 + last_size); + if ((new_addr + MAX_AU) > (memAddr + memSize)) + { + last_addr = memAddr; + } + else + { + last_addr = new_addr; + } + last_size = 0; + } + + void push(DemuxerStream& stream, u32 size, PesHeader& pes) + { + SMutexLocker lock(mutex); + if (isfull()) + { + ConLog.Error("ElementaryStream::push(): buffer is full"); + Emu.Pause(); + return; + } + + u32 data_addr = last_addr + 128 + last_size; + last_size += size; + memcpy(Memory + data_addr, Memory + stream.addr, size); + stream.skip(size); + + mem_ptr_t info(last_addr); + info->auAddr = last_addr + 128; + info->auSize = last_size; + if (pes.size) + { + info->dts.lower = pes.dts; + info->dts.upper = 0; + info->pts.lower = pes.pts; + info->pts.upper = 0; + info->isRap = false; // TODO: set valid value + info->reserved = 0; + info->userData = stream.userdata; + } + + mem_ptr_t tail(last_addr + sizeof(CellDmuxAuInfoEx)); + tail->reserved1 = 0; + + mem_ptr_t inf(last_addr + 64); + inf->auAddr = last_addr + 128; + inf->auSize = last_size; + if (pes.size) + { + inf->dtsLower = pes.dts; + inf->dtsUpper = 0; + inf->ptsLower = pes.pts; + inf->ptsUpper = 0; + inf->auMaxSize = 0; // ????? + inf->userData = stream.userdata; + } + } + + volatile bool canrelease() + { + return first_addr; + } + + void release() + { + SMutexLocker lock(mutex); + if (!canrelease()) + { + ConLog.Error("ElementaryStream::release(): buffer is empty"); + Emu.Pause(); + return; + } + + u32 size = a128(Memory.Read32(first_addr + 4) + 128); + u32 new_addr = first_addr + size; + if (peek_addr <= first_addr) peek_addr = new_addr; + if (new_addr == last_addr) + { + first_addr = 0; + } + else if ((new_addr + MAX_AU) > (memAddr + memSize)) + { + first_addr = memAddr; + } + else + { + first_addr = new_addr; + } + } + + bool peek(u32& out_data, bool no_ex, u32& out_spec, bool update_index) + { + SMutexLocker lock(mutex); + ConLog.Write("es::peek(): peek_addr=0x%x", peek_addr); + if (!peek_addr) return false; + + out_data = peek_addr; + out_spec = out_data + sizeof(CellDmuxAuInfoEx); + if (no_ex) out_data += 64; + + if (update_index) + { + u32 size = a128(Memory.Read32(peek_addr + 4) + 128); + u32 new_addr = peek_addr + size; + if (new_addr = last_addr) + { + peek_addr = 0; + } + else if ((new_addr + MAX_AU) > (memAddr + memSize)) + { + peek_addr = memAddr; + } + else + { + peek_addr = new_addr; + } + } + return true; + } + + void reset() + { + SMutexLocker lock(mutex); + first_addr = 0; + peek_addr = 0; + last_addr = a128(memAddr); + last_size = 0; + } }; \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Modules/cellPamf.cpp b/rpcs3/Emu/SysCalls/Modules/cellPamf.cpp index 1559788875..d0e95c310e 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPamf.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellPamf.cpp @@ -17,26 +17,16 @@ int pamfStreamTypeToEsFilterId(u8 type, u8 ch, mem_ptr_t pE switch (type) { case CELL_PAMF_STREAM_TYPE_AVC: - switch (ch) { - case 0: + if (ch < 16) { - pEsFilterId->filterIdMajor = 0xe0; //fake info + pEsFilterId->filterIdMajor = 0xe0 + ch; pEsFilterId->filterIdMinor = 0; pEsFilterId->supplementalInfo1 = 0x01; pEsFilterId->supplementalInfo2 = 0; } - break; - case 1: - { - pEsFilterId->filterIdMajor = 0xe1; - pEsFilterId->filterIdMinor = 0; - pEsFilterId->supplementalInfo1 = 0x01; - pEsFilterId->supplementalInfo2 = 0; - } - break; - default: - cellPamf.Error("*** TODO: pamfStreamTypeToEsFilterId: CELL_PAMF_STREAM_TYPE_AVC (ch=%d)", ch); + else + cellPamf.Error("pamfStreamTypeToEsFilterId: invalid CELL_PAMF_STREAM_TYPE_AVC channel (ch=%d)", ch); } break; case CELL_PAMF_STREAM_TYPE_ATRAC3PLUS: @@ -96,7 +86,7 @@ u8 pamfGetStreamType(mem_ptr_t pSelf, u8 stream) case 0x80: return CELL_PAMF_STREAM_TYPE_PAMF_LPCM; case 0xdd: return CELL_PAMF_STREAM_TYPE_USER_DATA; default: - cellPamf.Error("pamfGetStreamType: unsupported stream type found(0x%x)", + cellPamf.Error("pamfGetStreamType: (TODO) unsupported stream type found(0x%x)", pAddr->stream_headers[stream].type); return 0; } @@ -104,12 +94,16 @@ u8 pamfGetStreamType(mem_ptr_t pSelf, u8 stream) u8 pamfGetStreamChannel(mem_ptr_t pSelf, u8 stream) { - cellPamf.Warning("TODO: pamfGetStreamChannel"); //TODO: get stream channel correctly const mem_ptr_t pAddr(pSelf->pAddr); if ((pAddr->stream_headers[stream].type == 0x1b) && - (pAddr->stream_headers[stream].stream_id == 0xe1)) return 1; + (pAddr->stream_headers[stream].stream_id >= 0xe0) && + (pAddr->stream_headers[stream].stream_id <= 0xef)) + { + return pAddr->stream_headers[stream].stream_id - 0xe0; + } + cellPamf.Error("TODO: pamfGetStreamChannel (-> 0)"); return 0; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp index 74d3599841..0bf21a30cf 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp @@ -3,6 +3,11 @@ #include "Emu/SysCalls/SC_FUNC.h" #include "cellVdec.h" +extern "C" +{ +#include "libavformat\avformat.h" +} + void cellVdec_init(); Module cellVdec(0x0005, cellVdec_init); diff --git a/rpcs3/Emu/SysCalls/Modules/sys_fs.cpp b/rpcs3/Emu/SysCalls/Modules/sys_fs.cpp index 776dab9ee4..fdf46cad6f 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_fs.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sys_fs.cpp @@ -150,46 +150,67 @@ void fsAioRead(u32 fd, mem_ptr_t aio, int xid, mem_func_ptr_tGetPath().AfterFirst('/'); - u64 nbytes = (u64)aio->size; - const u32 buf_addr = (u32)aio->buf_addr; + u64 nbytes = aio->size; + u32 buf_addr = aio->buf_addr; - u64 res; - u32 error; + u32 res = 0; + u32 error = CELL_OK; - if(Memory.IsGoodAddr(buf_addr)) + vfsStream& file = *(vfsStream*)orig_file; + const u64 old_pos = file.Tell(); + file.Seek((u64)aio->offset); + + u32 count = nbytes; + if (nbytes != (u64)count) { - /* - //open the file again (to prevent access conflicts roughly) - vfsLocalFile file(path, vfsRead); - */ - vfsStream& file = *(vfsStream*)orig_file; - if(!Memory.IsGoodAddr(buf_addr, nbytes)) - { - MemoryBlock& block = Memory.GetMemByAddr(buf_addr); - nbytes = block.GetSize() - (buf_addr - block.GetStartAddr()); - } - - const u64 old_pos = file.Tell(); - file.Seek((u64)aio->offset); - res = nbytes ? file.Read(Memory.GetMemFromAddr(buf_addr), nbytes) : 0; - file.Seek(old_pos); - error = CELL_OK; + error = CELL_ENOMEM; + goto fin; } - else + + if (!Memory.IsGoodAddr(buf_addr)) { - res = 0; error = CELL_EFAULT; + goto fin; } - ConLog.Warning("*** fsAioRead(fd=%d, offset=0x%llx, buf_addr=0x%x, size=0x%x, res=0x%x, xid=0x%x [%s])", - fd, (u64)aio->offset, buf_addr, (u64)aio->size, res, xid, path.wx_str()); + if (count) if (u32 frag = buf_addr & 4095) // memory page fragment + { + u32 req = min(count, 4096 - frag); + u32 read = file.Read(Memory + buf_addr, req); + buf_addr += req; + res += read; + count -= req; + if (read < req) goto fin; + } + + for (u32 pages = count / 4096; pages > 0; pages--) // full pages + { + if (!Memory.IsGoodAddr(buf_addr)) goto fin; // ??? (probably EFAULT) + u32 read = file.Read(Memory + buf_addr, 4096); + buf_addr += 4096; + res += read; + count -= 4096; + if (read < 4096) goto fin; + } + + if (count) // last fragment + { + if (!Memory.IsGoodAddr(buf_addr)) goto fin; + res += file.Read(Memory + buf_addr, count); + } + +fin: + file.Seek(old_pos); + + ConLog.Warning("*** fsAioRead(fd=%d, offset=0x%llx, buf_addr=0x%x, size=0x%x, error=0x%x, res=0x%x, xid=0x%x [%s])", + fd, (u64)aio->offset, buf_addr, (u64)aio->size, error, res, xid, path.wx_str()); if (func) // start callback thread { func.async(aio, error, xid, res); } - CPUThread& thr = Emu.GetCallbackThread(); + /*CPUThread& thr = Emu.GetCallbackThread(); while (thr.IsAlive()) { Sleep(1); @@ -198,7 +219,7 @@ void fsAioRead(u32 fd, mem_ptr_t aio, int xid, mem_func_ptr_t attr) { - sys_cond.Log("sys_cond_create(cond_id_addr=0x%x, mutex_id=%d, attr_addr=%d)", + sys_cond.Log("sys_cond_create(cond_id_addr=0x%x, mutex_id=%d, attr_addr=0x%x)", cond_id.GetAddr(), mutex_id, attr.GetAddr()); if (!cond_id.IsGood() || !attr.IsGood()) diff --git a/rpcs3/Emu/SysCalls/lv2/SC_FileSystem.cpp b/rpcs3/Emu/SysCalls/lv2/SC_FileSystem.cpp index e688a46d74..64a9aa9e35 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_FileSystem.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_FileSystem.cpp @@ -94,16 +94,43 @@ int cellFsRead(u32 fd, u32 buf_addr, u64 nbytes, mem64_t nread) vfsStream* file; if(!sys_fs.CheckId(fd, file)) return CELL_ESRCH; - if(Memory.IsGoodAddr(buf_addr) && !Memory.IsGoodAddr(buf_addr, nbytes)) + if (nread.GetAddr() && !nread.IsGood()) return CELL_EFAULT; + + u32 res = 0; + u32 count = nbytes; + if (nbytes != (u64)count) return CELL_ENOMEM; + + if (!Memory.IsGoodAddr(buf_addr)) return CELL_EFAULT; + + if (count) if (u32 frag = buf_addr & 4095) // memory page fragment { - MemoryBlock& block = Memory.GetMemByAddr(buf_addr); - nbytes = block.GetSize() - (buf_addr - block.GetStartAddr()); + u32 req = min(count, 4096 - frag); + u32 read = file->Read(Memory + buf_addr, req); + buf_addr += req; + res += read; + count -= req; + if (read < req) goto fin; } - const u64 res = nbytes ? file->Read(Memory.GetMemFromAddr(buf_addr), nbytes) : 0; + for (u32 pages = count / 4096; pages > 0; pages--) // full pages + { + if (!Memory.IsGoodAddr(buf_addr)) goto fin; // ??? (probably EFAULT) + u32 read = file->Read(Memory + buf_addr, 4096); + buf_addr += 4096; + res += read; + count -= 4096; + if (read < 4096) goto fin; + } - if(nread.IsGood()) - nread = res; + if (count) // last fragment + { + if (!Memory.IsGoodAddr(buf_addr)) goto fin; + res += file->Read(Memory + buf_addr, count); + } + +fin: + + if (nread.GetAddr()) nread = res; // write value if not NULL return CELL_OK; }