mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-01-30 12:32:43 +00:00
This commit is contained in:
commit
7a1d44b552
2
.gitignore
vendored
2
.gitignore
vendored
@ -41,6 +41,8 @@
|
||||
/bin/VertexProgram.txt
|
||||
/bin/BreakPoints.dat
|
||||
/bin/textures
|
||||
/bin/*.lib
|
||||
/bin/*.exp
|
||||
rpcs3/git-version.h
|
||||
|
||||
# Copyrighted files
|
||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -2,3 +2,6 @@
|
||||
path = wxWidgets
|
||||
url = https://github.com/DHrpcs3/wxWidgets.git
|
||||
ignore = dirty
|
||||
[submodule "rpcs3-ffmpeg"]
|
||||
path = ffmpeg
|
||||
url = https://github.com/hrydgard/ppsspp-ffmpeg
|
||||
|
@ -6,9 +6,9 @@ __forceinline void SM_Sleep()
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
__forceinline std::thread::id SM_GetCurrentThreadId()
|
||||
__forceinline size_t SM_GetCurrentThreadId()
|
||||
{
|
||||
return std::this_thread::get_id();
|
||||
return std::this_thread::get_id().hash();
|
||||
}
|
||||
|
||||
__forceinline u32 SM_GetCurrentCPUThreadId()
|
||||
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
extern void SM_Sleep();
|
||||
extern std::thread::id SM_GetCurrentThreadId();
|
||||
extern size_t SM_GetCurrentThreadId();
|
||||
extern u32 SM_GetCurrentCPUThreadId();
|
||||
extern be_t<u32> SM_GetCurrentCPUThreadIdBE();
|
||||
|
||||
@ -20,13 +20,13 @@ enum SMutexResult
|
||||
template
|
||||
<
|
||||
typename T,
|
||||
u32 free_value = 0,
|
||||
u32 dead_value = ~0,
|
||||
u64 free_value = 0,
|
||||
u64 dead_value = ~0,
|
||||
void (*wait)() = SM_Sleep
|
||||
>
|
||||
class SMutexBase
|
||||
{
|
||||
static_assert(sizeof(T) == 4, "Invalid SMutexBase typename");
|
||||
static_assert(sizeof(T) == sizeof(std::atomic<T>), "Invalid SMutexBase type");
|
||||
std::atomic<T> owner;
|
||||
|
||||
public:
|
||||
@ -157,14 +157,14 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
typedef SMutexBase<DWORD>
|
||||
typedef SMutexBase<size_t>
|
||||
SMutexGeneral;
|
||||
typedef SMutexBase<u32>
|
||||
SMutex;
|
||||
typedef SMutexBase<be_t<u32>>
|
||||
SMutexBE;
|
||||
|
||||
typedef SMutexLockerBase<std::thread::id, SM_GetCurrentThreadId>
|
||||
typedef SMutexLockerBase<size_t, SM_GetCurrentThreadId>
|
||||
SMutexGeneralLocker;
|
||||
typedef SMutexLockerBase<u32, SM_GetCurrentCPUThreadId>
|
||||
SMutexLocker;
|
||||
|
99
Utilities/SQueue.h
Normal file
99
Utilities/SQueue.h
Normal file
@ -0,0 +1,99 @@
|
||||
#pragma once
|
||||
|
||||
template<typename T, u32 SQSize = 666>
|
||||
class SQueue
|
||||
{
|
||||
SMutex m_mutex;
|
||||
u32 m_pos;
|
||||
u32 m_count;
|
||||
T m_data[SQSize];
|
||||
|
||||
public:
|
||||
SQueue()
|
||||
: m_pos(0)
|
||||
, m_count(0)
|
||||
{
|
||||
}
|
||||
|
||||
bool Push(T& data)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_mutex.GetOwner() == m_mutex.GetDeadValue())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_count >= SQSize)
|
||||
{
|
||||
Sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
SMutexLocker lock(m_mutex);
|
||||
|
||||
if (m_count >= SQSize) continue;
|
||||
|
||||
m_data[(m_pos + m_count++) % SQSize] = data;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Pop(T& data)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_mutex.GetOwner() == m_mutex.GetDeadValue())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_count)
|
||||
{
|
||||
Sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
SMutexLocker lock(m_mutex);
|
||||
|
||||
if (!m_count) continue;
|
||||
|
||||
data = m_data[m_pos];
|
||||
m_pos = (m_pos + 1) % SQSize;
|
||||
m_count--;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
volatile u32 GetCount()
|
||||
{
|
||||
return m_count;
|
||||
}
|
||||
|
||||
volatile bool IsEmpty()
|
||||
{
|
||||
return !m_count;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
SMutexLocker lock(m_mutex);
|
||||
m_count = 0;
|
||||
}
|
||||
};
|
@ -117,10 +117,12 @@ thread::thread()
|
||||
}
|
||||
|
||||
void thread::start(std::function<void()> func)
|
||||
{ // got a crash related with strings
|
||||
m_thr = std::thread([this, func]()
|
||||
{
|
||||
NamedThreadBase info(m_name);
|
||||
std::string name = m_name;
|
||||
|
||||
m_thr = std::thread([func, name]()
|
||||
{
|
||||
NamedThreadBase info(name);
|
||||
g_tls_this_thread = &info;
|
||||
|
||||
try
|
||||
@ -130,7 +132,7 @@ void thread::start(std::function<void()> func)
|
||||
catch(...)
|
||||
{
|
||||
ConLog.Error("Crash :(");
|
||||
std::terminate();
|
||||
//std::terminate();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
1
ffmpeg
Submodule
1
ffmpeg
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 8bcaa2485c2434d7d7a9da17491bafb58de42bb6
|
@ -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<u64>& 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());
|
||||
}
|
||||
|
@ -168,11 +168,11 @@ struct DMAC
|
||||
switch(cmd & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK))
|
||||
{
|
||||
case MFC_PUT_CMD:
|
||||
memcpy(Memory + ea, Memory + ls_offset + lsa, size);
|
||||
Memory.Copy(ea, ls_offset + lsa, size);
|
||||
return true;
|
||||
|
||||
case MFC_GET_CMD:
|
||||
memcpy(Memory + ls_offset + lsa, Memory + ea, size);
|
||||
Memory.Copy(ls_offset + lsa, ea, size);
|
||||
return true;
|
||||
|
||||
default:
|
||||
|
@ -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<u64>& 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());
|
||||
}
|
||||
|
@ -30,7 +30,14 @@ DbgConsole::~DbgConsole()
|
||||
|
||||
void DbgConsole::Write(int ch, const wxString& text)
|
||||
{
|
||||
while(m_dbg_buffer.IsBusy()) Sleep(1);
|
||||
while (m_dbg_buffer.IsBusy())
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
return;
|
||||
}
|
||||
Sleep(1);
|
||||
}
|
||||
m_dbg_buffer.Push(DbgPacket(ch, text));
|
||||
|
||||
if(!IsAlive()) Start();
|
||||
@ -47,6 +54,10 @@ void DbgConsole::Task()
|
||||
{
|
||||
if(!m_dbg_buffer.HasNewPacket())
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
break;
|
||||
}
|
||||
Sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ bool vfsDir::Create(const wxString& path)
|
||||
|
||||
bool vfsDir::IsExists(const wxString& path) const
|
||||
{
|
||||
return m_stream->IsExists(path);
|
||||
return m_stream->IsExists(path); // Crash (Access violation reading location 0x0000000000000000)
|
||||
}
|
||||
|
||||
const Array<DirEntryInfo>& vfsDir::GetEntries() const
|
||||
|
@ -32,7 +32,7 @@ u64 vfsStreamMemory::Write(const void* src, u64 size)
|
||||
|
||||
if(!size || !Memory.IsGoodAddr(m_addr + Tell(), size)) return 0;
|
||||
|
||||
memcpy(&Memory[m_addr + Tell()], src, size);
|
||||
Memory.CopyFromReal(m_addr + Tell(), (void*)src, size);
|
||||
|
||||
return vfsStream::Write(src, size);
|
||||
}
|
||||
@ -46,7 +46,7 @@ u64 vfsStreamMemory::Read(void* dst, u64 size)
|
||||
|
||||
if(!size || !Memory.IsGoodAddr(m_addr + Tell(), size)) return 0;
|
||||
|
||||
memcpy(dst, &Memory[m_addr + Tell()], size);
|
||||
Memory.CopyToReal(dst, m_addr + Tell(), size);
|
||||
|
||||
return vfsStream::Read(dst, size);
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ void RSXVertexData::Load(u32 start, u32 count)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
memcpy(dst, src, size);
|
||||
memcpy(dst, src, size); // may be dangerous
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -48,18 +48,16 @@ bool MemoryBlock::GetMemFromAddr(void* dst, const u64 addr, const u32 size)
|
||||
{
|
||||
if(!IsMyAddress(addr) || FixAddr(addr) + size > GetSize()) return false;
|
||||
|
||||
memcpy(dst, GetMem(FixAddr(addr)), size);
|
||||
|
||||
return true;
|
||||
// mem cpy(dst, GetMem(FixAddr(addr)), size);
|
||||
return Memory.CopyToReal(dst, (u32)addr, size);
|
||||
}
|
||||
|
||||
bool MemoryBlock::SetMemFromAddr(void* src, const u64 addr, const u32 size)
|
||||
{
|
||||
if(!IsMyAddress(addr) || FixAddr(addr) + size > GetSize()) return false;
|
||||
|
||||
memcpy(GetMem(FixAddr(addr)), src, size);
|
||||
|
||||
return true;
|
||||
// mem cpy(GetMem(FixAddr(addr)), src, size);
|
||||
return Memory.CopyFromReal((u32)addr, src, size);
|
||||
}
|
||||
|
||||
bool MemoryBlock::GetMemFFromAddr(void* dst, const u64 addr)
|
||||
|
@ -238,6 +238,106 @@ public:
|
||||
u64 Read64(const u64 addr);
|
||||
u128 Read128(const u64 addr);
|
||||
|
||||
bool CopyToReal(void* real, u32 from, u32 count) // (4K pages) copy from virtual to real memory
|
||||
{
|
||||
if (!count) return true;
|
||||
|
||||
u8* to = (u8*)real;
|
||||
|
||||
if (u32 frag = from & 4095)
|
||||
{
|
||||
if (!IsGoodAddr(from)) return false;
|
||||
u32 num = 4096 - frag;
|
||||
if (count < num) num = count;
|
||||
memcpy(to, GetMemFromAddr(from), num);
|
||||
to += num;
|
||||
from += num;
|
||||
count -= num;
|
||||
}
|
||||
|
||||
for (u32 page = count / 4096; page > 0; page--)
|
||||
{
|
||||
if (!IsGoodAddr(from)) return false;
|
||||
memcpy(to, GetMemFromAddr(from), 4096);
|
||||
to += 4096;
|
||||
from += 4096;
|
||||
count -= 4096;
|
||||
}
|
||||
|
||||
if (count)
|
||||
{
|
||||
if (!IsGoodAddr(from)) return false;
|
||||
memcpy(to, GetMemFromAddr(from), count);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CopyFromReal(u32 to, void* real, u32 count) // (4K pages) copy from real to virtual memory
|
||||
{
|
||||
if (!count) return true;
|
||||
|
||||
u8* from = (u8*)real;
|
||||
|
||||
if (u32 frag = to & 4095)
|
||||
{
|
||||
if (!IsGoodAddr(to)) return false;
|
||||
u32 num = 4096 - frag;
|
||||
if (count < num) num = count;
|
||||
memcpy(GetMemFromAddr(to), from, num);
|
||||
to += num;
|
||||
from += num;
|
||||
count -= num;
|
||||
}
|
||||
|
||||
for (u32 page = count / 4096; page > 0; page--)
|
||||
{
|
||||
if (!IsGoodAddr(to)) return false;
|
||||
memcpy(GetMemFromAddr(to), from, 4096);
|
||||
to += 4096;
|
||||
from += 4096;
|
||||
count -= 4096;
|
||||
}
|
||||
|
||||
if (count)
|
||||
{
|
||||
if (!IsGoodAddr(to)) return false;
|
||||
memcpy(GetMemFromAddr(to), from, count);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool Copy(u32 to, u32 from, u32 count) // (4K pages) copy from virtual to virtual memory through real
|
||||
{
|
||||
if (u8* buf = (u8*)malloc(count))
|
||||
{
|
||||
if (CopyToReal(buf, from, count))
|
||||
{
|
||||
if (CopyFromReal(to, buf, count))
|
||||
{
|
||||
free(buf);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(buf);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
free(buf);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ReadLeft(u8* dst, const u64 addr, const u32 size)
|
||||
{
|
||||
MemoryBlock& mem = GetMemByAddr(addr);
|
||||
|
@ -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)
|
||||
|
@ -135,6 +135,7 @@ struct CellAudioPortConfig
|
||||
|
||||
struct AudioPortConfig
|
||||
{
|
||||
SMutex m_mutex;
|
||||
bool m_is_audio_port_opened;
|
||||
bool m_is_audio_port_started;
|
||||
u8 channel;
|
||||
@ -366,10 +367,12 @@ int cellAudioInit()
|
||||
memcpy(buffer2, Memory + buf_addr, block_size * sizeof(float));
|
||||
memset(Memory + buf_addr, 0, block_size * sizeof(float));
|
||||
|
||||
// TODO: atomic
|
||||
{
|
||||
SMutexLocker lock(port.m_mutex);
|
||||
port.counter = m_config.counter;
|
||||
port.tag++; // absolute index of block that will be read
|
||||
index = (position + 1) % port.block; // write new value
|
||||
}
|
||||
|
||||
if (first_mix)
|
||||
{
|
||||
@ -599,7 +602,7 @@ int cellAudioPortStop(u32 portNum)
|
||||
|
||||
int cellAudioGetPortTimestamp(u32 portNum, u64 tag, mem64_t stamp)
|
||||
{
|
||||
cellAudio.Warning("cellAudioGetPortTimestamp(portNum=0x%x, tag=0x%llx, stamp_addr=0x%x)", portNum, tag, stamp.GetAddr());
|
||||
cellAudio.Log("cellAudioGetPortTimestamp(portNum=0x%x, tag=0x%llx, stamp_addr=0x%x)", portNum, tag, stamp.GetAddr());
|
||||
|
||||
if (portNum >= m_config.AUDIO_PORT_COUNT)
|
||||
{
|
||||
@ -618,7 +621,8 @@ int cellAudioGetPortTimestamp(u32 portNum, u64 tag, mem64_t stamp)
|
||||
|
||||
AudioPortConfig& port = m_config.m_ports[portNum];
|
||||
|
||||
// TODO: atomic
|
||||
SMutexLocker lock(port.m_mutex);
|
||||
|
||||
stamp = m_config.start_time + (port.counter + (tag - port.tag)) * 256000000 / 48000;
|
||||
|
||||
return CELL_OK;
|
||||
@ -626,7 +630,7 @@ int cellAudioGetPortTimestamp(u32 portNum, u64 tag, mem64_t stamp)
|
||||
|
||||
int cellAudioGetPortBlockTag(u32 portNum, u64 blockNo, mem64_t tag)
|
||||
{
|
||||
cellAudio.Warning("cellAudioGetPortBlockTag(portNum=0x%x, blockNo=0x%llx, tag_addr=0x%x)", portNum, blockNo, tag.GetAddr());
|
||||
cellAudio.Log("cellAudioGetPortBlockTag(portNum=0x%x, blockNo=0x%llx, tag_addr=0x%x)", portNum, blockNo, tag.GetAddr());
|
||||
|
||||
if (portNum >= m_config.AUDIO_PORT_COUNT)
|
||||
{
|
||||
@ -651,7 +655,8 @@ int cellAudioGetPortBlockTag(u32 portNum, u64 blockNo, mem64_t tag)
|
||||
return CELL_AUDIO_ERROR_PARAM;
|
||||
}
|
||||
|
||||
// TODO: atomic
|
||||
SMutexLocker lock(port.m_mutex);
|
||||
|
||||
u64 tag_base = port.tag;
|
||||
if (tag_base % port.block > blockNo)
|
||||
{
|
||||
@ -709,13 +714,13 @@ int cellAudioSetNotifyEventQueue(u64 key)
|
||||
|
||||
m_config.event_key = key;
|
||||
|
||||
EventQueue* eq;
|
||||
/*EventQueue* eq;
|
||||
if (!Emu.GetEventManager().GetEventQueue(key, eq))
|
||||
{
|
||||
return CELL_AUDIO_ERROR_PARAM;
|
||||
}
|
||||
}*/
|
||||
|
||||
// TODO: connect port
|
||||
// TODO: connect port (?????)
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -7,80 +7,646 @@
|
||||
void cellDmux_init();
|
||||
Module cellDmux(0x0007, cellDmux_init);
|
||||
|
||||
void dmuxQueryAttr(u32 info_addr /* may be 0 */, mem_ptr_t<CellDmuxAttr> attr)
|
||||
{
|
||||
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<CellCodecEsFilterId> esFilterId,
|
||||
const u32 esSpecificInfo_addr, mem_ptr_t<CellDmuxEsAttr> attr)
|
||||
{
|
||||
if (esFilterId->filterIdMajor >= 0xe0)
|
||||
attr->memSize = 0x600000; // 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* esALL[192]; memset(esALL, 0, sizeof(esALL));
|
||||
ElementaryStream** esAVC = &esALL[0]; // AVC (max 16)
|
||||
ElementaryStream** esM2V = &esALL[16]; // MPEG-2 (max 16)
|
||||
ElementaryStream** esDATA = &esALL[32]; // user data (max 16)
|
||||
ElementaryStream** esATX = &esALL[48]; // ATRAC3+ (max 48)
|
||||
ElementaryStream** esAC3 = &esALL[96]; // AC3 (max 48)
|
||||
ElementaryStream** esPCM = &esALL[144]; // LPCM (max 48)
|
||||
|
||||
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<u32> code;
|
||||
be_t<u16> 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:
|
||||
{
|
||||
stream.skip(4);
|
||||
stream.get(len);
|
||||
stream.skip(len);
|
||||
}
|
||||
break;
|
||||
|
||||
case PRIVATE_STREAM_2:
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
DemuxerStream backup = stream;
|
||||
|
||||
stream.skip(4);
|
||||
stream.get(len);
|
||||
PesHeader pes(stream);
|
||||
|
||||
if (!pes.new_au && !es.hasdata()) // fatal error
|
||||
{
|
||||
ConLog.Error("PES not found");
|
||||
return;
|
||||
}
|
||||
|
||||
if (pes.new_au && es.hasdata()) // new AU detected
|
||||
{
|
||||
if (es.hasunseen()) // hack, probably useless
|
||||
{
|
||||
stream = backup;
|
||||
continue;
|
||||
}
|
||||
es.finish(stream);
|
||||
// callback
|
||||
mem_ptr_t<CellDmuxEsMsg> 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.new_au)
|
||||
{
|
||||
ConLog.Write("*** AVC AU detected (pts=0x%llx, dts=0x%llx)", pes.pts, pes.dts);
|
||||
}
|
||||
|
||||
if (es.isfull())
|
||||
{
|
||||
stream = backup;
|
||||
continue;
|
||||
}
|
||||
//stream = backup;
|
||||
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
|
||||
ConLog.Warning("Unknown MPEG stream found");
|
||||
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:
|
||||
{
|
||||
bool do_wait = false;
|
||||
for (u32 i = 0; i < 192; i++)
|
||||
{
|
||||
if (esALL[i])
|
||||
{
|
||||
if (esALL[i]->hasunseen()) // hack, probably useless
|
||||
{
|
||||
do_wait = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (do_wait) continue;
|
||||
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<CellDmuxMsg> 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<CellDmuxEsMsg> 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<CellDmuxEsMsg> 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<CellDmuxType> demuxerType, mem_ptr_t<CellDmuxAttr> demuxerAttr)
|
||||
{
|
||||
cellDmux.Error("cellDmuxQueryAttr(demuxerType_addr=0x%x, demuxerAttr_addr=0x%x)", demuxerType.GetAddr(), demuxerAttr.GetAddr());
|
||||
cellDmux.Warning("cellDmuxQueryAttr(demuxerType_addr=0x%x, demuxerAttr_addr=0x%x)", demuxerType.GetAddr(), demuxerAttr.GetAddr());
|
||||
|
||||
if (!demuxerType.IsGood() || !demuxerAttr.IsGood())
|
||||
{
|
||||
return CELL_DMUX_ERROR_FATAL;
|
||||
}
|
||||
|
||||
if (demuxerType->streamType != CELL_DMUX_STREAM_TYPE_PAMF)
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
}
|
||||
|
||||
dmuxQueryAttr(0, demuxerAttr);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellDmuxQueryAttr2(const mem_ptr_t<CellDmuxType2> demuxerType2, mem_ptr_t<CellDmuxAttr> demuxerAttr)
|
||||
{
|
||||
cellDmux.Error("cellDmuxQueryAttr2(demuxerType2_addr=0x%x, demuxerAttr_addr=0x%x)", demuxerType2.GetAddr(), demuxerAttr.GetAddr());
|
||||
cellDmux.Warning("cellDmuxQueryAttr2(demuxerType2_addr=0x%x, demuxerAttr_addr=0x%x)", demuxerType2.GetAddr(), demuxerAttr.GetAddr());
|
||||
|
||||
if (!demuxerType2.IsGood() || !demuxerAttr.IsGood())
|
||||
{
|
||||
return CELL_DMUX_ERROR_FATAL;
|
||||
}
|
||||
|
||||
if (demuxerType2->streamType != CELL_DMUX_STREAM_TYPE_PAMF)
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
}
|
||||
|
||||
dmuxQueryAttr(demuxerType2->streamSpecificInfo_addr, demuxerAttr);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellDmuxOpen(const mem_ptr_t<CellDmuxType> demuxerType, const mem_ptr_t<CellDmuxResource> demuxerResource,
|
||||
const mem_ptr_t<CellDmuxCb> demuxerCb, mem32_t demuxerHandle)
|
||||
{
|
||||
cellDmux.Error("cellDmuxOpen(demuxerType_addr=0x%x, demuxerResource_addr=0x%x, demuxerCb_addr=0x%x, demuxerHandle_addr=0x%x)",
|
||||
cellDmux.Warning("cellDmuxOpen(demuxerType_addr=0x%x, demuxerResource_addr=0x%x, demuxerCb_addr=0x%x, demuxerHandle_addr=0x%x)",
|
||||
demuxerType.GetAddr(), demuxerResource.GetAddr(), demuxerCb.GetAddr(), demuxerHandle.GetAddr());
|
||||
|
||||
if (!demuxerType.IsGood() || !demuxerResource.IsGood() || !demuxerCb.IsGood() || !demuxerHandle.IsGood())
|
||||
{
|
||||
return CELL_DMUX_ERROR_FATAL;
|
||||
}
|
||||
|
||||
if (demuxerType->streamType != CELL_DMUX_STREAM_TYPE_PAMF)
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
}
|
||||
|
||||
if (!Memory.IsGoodAddr(demuxerResource->memAddr, demuxerResource->memSize))
|
||||
{
|
||||
return CELL_DMUX_ERROR_FATAL;
|
||||
}
|
||||
|
||||
// TODO: check demuxerResource and demuxerCb arguments
|
||||
|
||||
demuxerHandle = dmuxOpen(new Demuxer(demuxerResource->memAddr, demuxerResource->memSize, demuxerCb->cbMsgFunc, demuxerCb->cbArg_addr));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellDmuxOpenEx(const mem_ptr_t<CellDmuxType> demuxerType, const mem_ptr_t<CellDmuxResourceEx> demuxerResourceEx,
|
||||
const mem_ptr_t<CellDmuxCb> demuxerCb, mem32_t demuxerHandle)
|
||||
{
|
||||
cellDmux.Error("cellDmuxOpenEx(demuxerType_addr=0x%x, demuxerResourceEx_addr=0x%x, demuxerCb_addr=0x%x, demuxerHandle_addr=0x%x)",
|
||||
cellDmux.Warning("cellDmuxOpenEx(demuxerType_addr=0x%x, demuxerResourceEx_addr=0x%x, demuxerCb_addr=0x%x, demuxerHandle_addr=0x%x)",
|
||||
demuxerType.GetAddr(), demuxerResourceEx.GetAddr(), demuxerCb.GetAddr(), demuxerHandle.GetAddr());
|
||||
|
||||
if (!demuxerType.IsGood() || !demuxerResourceEx.IsGood() || !demuxerCb.IsGood() || !demuxerHandle.IsGood())
|
||||
{
|
||||
return CELL_DMUX_ERROR_FATAL;
|
||||
}
|
||||
|
||||
if (demuxerType->streamType != CELL_DMUX_STREAM_TYPE_PAMF)
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
}
|
||||
|
||||
if (!Memory.IsGoodAddr(demuxerResourceEx->memAddr, demuxerResourceEx->memSize))
|
||||
{
|
||||
return CELL_DMUX_ERROR_FATAL;
|
||||
}
|
||||
|
||||
// TODO: check demuxerResourceEx and demuxerCb arguments
|
||||
|
||||
demuxerHandle = dmuxOpen(new Demuxer(demuxerResourceEx->memAddr, demuxerResourceEx->memSize, demuxerCb->cbMsgFunc, demuxerCb->cbArg_addr));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellDmuxOpen2(const mem_ptr_t<CellDmuxType2> demuxerType2, const mem_ptr_t<CellDmuxResource2> demuxerResource2,
|
||||
const mem_ptr_t<CellDmuxCb> demuxerCb, mem32_t demuxerHandle)
|
||||
{
|
||||
cellDmux.Error("cellDmuxOpen2(demuxerType2_addr=0x%x, demuxerResource2_addr=0x%x, demuxerCb_addr=0x%x, demuxerHandle_addr=0x%x)",
|
||||
cellDmux.Warning("cellDmuxOpen2(demuxerType2_addr=0x%x, demuxerResource2_addr=0x%x, demuxerCb_addr=0x%x, demuxerHandle_addr=0x%x)",
|
||||
demuxerType2.GetAddr(), demuxerResource2.GetAddr(), demuxerCb.GetAddr(), demuxerHandle.GetAddr());
|
||||
|
||||
if (!demuxerType2.IsGood() || !demuxerResource2.IsGood() || !demuxerCb.IsGood() || !demuxerHandle.IsGood())
|
||||
{
|
||||
return CELL_DMUX_ERROR_FATAL;
|
||||
}
|
||||
|
||||
if (demuxerType2->streamType != CELL_DMUX_STREAM_TYPE_PAMF)
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
}
|
||||
|
||||
if (!Memory.IsGoodAddr(demuxerResource2->memAddr, demuxerResource2->memSize))
|
||||
{
|
||||
return CELL_DMUX_ERROR_FATAL;
|
||||
}
|
||||
|
||||
// TODO: check demuxerType2, demuxerResource2 and demuxerCb arguments
|
||||
|
||||
demuxerHandle = dmuxOpen(new Demuxer(demuxerResource2->memAddr, demuxerResource2->memSize, demuxerCb->cbMsgFunc, demuxerCb->cbArg_addr));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellDmuxClose(u32 demuxerHandle)
|
||||
{
|
||||
cellDmux.Error("cellDmuxClose(demuxerHandle=0x%x)", demuxerHandle);
|
||||
cellDmux.Warning("cellDmuxClose(demuxerHandle=%d)", demuxerHandle);
|
||||
|
||||
Demuxer* dmux;
|
||||
if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux))
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
}
|
||||
|
||||
dmux->job.Push(DemuxerTask(dmuxClose));
|
||||
|
||||
while (!dmux->is_finished)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
ConLog.Warning("cellDmuxClose(%d) aborted", demuxerHandle);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
Emu.GetIdManager().RemoveID(demuxerHandle);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellDmuxSetStream(u32 demuxerHandle, const u32 streamAddress, u32 streamSize, bool discontinuity, u64 userData)
|
||||
{
|
||||
cellDmux.Error("cellDmuxSetStream(demuxerHandle=0x%x, 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;
|
||||
if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux))
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
}
|
||||
|
||||
if (!Memory.IsGoodAddr(streamAddress, streamSize))
|
||||
{
|
||||
return CELL_DMUX_ERROR_FATAL;
|
||||
}
|
||||
|
||||
if (dmux->is_running)
|
||||
{
|
||||
Sleep(1); // performance hack
|
||||
return CELL_DMUX_ERROR_BUSY;
|
||||
}
|
||||
|
||||
DemuxerTask task(dmuxSetStream);
|
||||
auto& info = task.stream;
|
||||
info.addr = streamAddress;
|
||||
info.size = streamSize;
|
||||
info.discontinuity = discontinuity;
|
||||
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.Error("cellDmuxResetStream(demuxerHandle=0x%x)", demuxerHandle);
|
||||
cellDmux.Log("cellDmuxResetStream(demuxerHandle=%d)", demuxerHandle);
|
||||
|
||||
Demuxer* dmux;
|
||||
if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux))
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
}
|
||||
|
||||
dmux->job.Push(DemuxerTask(dmuxResetStream));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellDmuxResetStreamAndWaitDone(u32 demuxerHandle)
|
||||
{
|
||||
cellDmux.Error("cellDmuxResetStreamAndWaitDone(demuxerHandle=0x%x)", demuxerHandle);
|
||||
cellDmux.Log("cellDmuxResetStreamAndWaitDone(demuxerHandle=%d)", demuxerHandle);
|
||||
|
||||
Demuxer* dmux;
|
||||
if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux))
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
}
|
||||
|
||||
dmux->job.Push(DemuxerTask(dmuxResetStreamAndWaitDone));
|
||||
|
||||
while (dmux->is_running)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
ConLog.Warning("cellDmuxResetStreamAndWaitDone(%d) aborted", demuxerHandle);
|
||||
break;
|
||||
}
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellDmuxQueryEsAttr(const mem_ptr_t<CellDmuxType> demuxerType, const mem_ptr_t<CellCodecEsFilterId> esFilterId,
|
||||
const u32 esSpecificInfo_addr, mem_ptr_t<CellDmuxEsAttr> esAttr)
|
||||
{
|
||||
cellDmux.Error("cellDmuxQueryEsAttr(demuxerType_addr=0x%x, esFilterId_addr=0x%x, esSpecificInfo_addr=0x%x, esAttr_addr=0x%x)",
|
||||
cellDmux.Warning("cellDmuxQueryEsAttr(demuxerType_addr=0x%x, esFilterId_addr=0x%x, esSpecificInfo_addr=0x%x, esAttr_addr=0x%x)",
|
||||
demuxerType.GetAddr(), esFilterId.GetAddr(), esSpecificInfo_addr, esAttr.GetAddr());
|
||||
|
||||
if (!demuxerType.IsGood() || !esFilterId.IsGood() || !esAttr.IsGood())
|
||||
{
|
||||
return CELL_DMUX_ERROR_FATAL;
|
||||
}
|
||||
|
||||
if (!Memory.IsGoodAddr(esSpecificInfo_addr, 12))
|
||||
{
|
||||
cellDmux.Error("cellDmuxQueryEsAttr: invalid specific info addr (0x%x)", esSpecificInfo_addr);
|
||||
return CELL_DMUX_ERROR_FATAL;
|
||||
}
|
||||
|
||||
if (demuxerType->streamType != CELL_DMUX_STREAM_TYPE_PAMF)
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
}
|
||||
|
||||
// TODO: check esFilterId and esSpecificInfo correctly
|
||||
|
||||
dmuxQueryEsAttr(0, esFilterId, esSpecificInfo_addr, esAttr);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellDmuxQueryEsAttr2(const mem_ptr_t<CellDmuxType2> demuxerType2, const mem_ptr_t<CellCodecEsFilterId> esFilterId,
|
||||
const u32 esSpecificInfo_addr, mem_ptr_t<CellDmuxEsAttr> 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())
|
||||
{
|
||||
return CELL_DMUX_ERROR_FATAL;
|
||||
}
|
||||
|
||||
if (!Memory.IsGoodAddr(esSpecificInfo_addr, 12))
|
||||
{
|
||||
cellDmux.Error("cellDmuxQueryEsAttr2: invalid specific info addr (0x%x)", esSpecificInfo_addr);
|
||||
return CELL_DMUX_ERROR_FATAL;
|
||||
}
|
||||
|
||||
if (demuxerType2->streamType != CELL_DMUX_STREAM_TYPE_PAMF)
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
}
|
||||
|
||||
// TODO: check demuxerType2, esFilterId and esSpecificInfo correctly
|
||||
|
||||
dmuxQueryEsAttr(demuxerType2->streamSpecificInfo_addr, esFilterId, esSpecificInfo_addr, esAttr);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -88,61 +654,243 @@ int cellDmuxEnableEs(u32 demuxerHandle, const mem_ptr_t<CellCodecEsFilterId> esF
|
||||
const mem_ptr_t<CellDmuxEsResource> esResourceInfo, const mem_ptr_t<CellDmuxEsCb> esCb,
|
||||
const u32 esSpecificInfo_addr, mem32_t esHandle)
|
||||
{
|
||||
cellDmux.Error("cellDmuxEnableEs(demuxerHandle=0x%x, esFilterId_addr=0x%x, esResourceInfo_addr=0x%x, esCb_addr=0x%x, "
|
||||
cellDmux.Warning("cellDmuxEnableEs(demuxerHandle=%d, esFilterId_addr=0x%x, esResourceInfo_addr=0x%x, esCb_addr=0x%x, "
|
||||
"esSpecificInfo_addr=0x%x, esHandle_addr=0x%x)", demuxerHandle, esFilterId.GetAddr(), esResourceInfo.GetAddr(),
|
||||
esCb.GetAddr(), esSpecificInfo_addr, esHandle.GetAddr());
|
||||
|
||||
if (!esFilterId.IsGood() || !esResourceInfo.IsGood() || !esCb.IsGood() || !esHandle.IsGood())
|
||||
{
|
||||
return CELL_DMUX_ERROR_FATAL;
|
||||
}
|
||||
|
||||
if (!Memory.IsGoodAddr(esSpecificInfo_addr, 12))
|
||||
{
|
||||
cellDmux.Error("cellDmuxEnableEs: invalid specific info addr (0x%x)", esSpecificInfo_addr);
|
||||
return CELL_DMUX_ERROR_FATAL;
|
||||
}
|
||||
|
||||
if (!Memory.IsGoodAddr(esResourceInfo->memAddr, esResourceInfo->memSize))
|
||||
{
|
||||
return CELL_DMUX_ERROR_FATAL;
|
||||
}
|
||||
|
||||
Demuxer* dmux;
|
||||
if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux))
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
}
|
||||
|
||||
// TODO: check esFilterId, esResourceInfo, esCb and esSpecificInfo correctly
|
||||
|
||||
ElementaryStream* es = new ElementaryStream(dmux, esResourceInfo->memAddr, esResourceInfo->memSize,
|
||||
esFilterId->filterIdMajor, esFilterId->filterIdMinor, esFilterId->supplementalInfo1, esFilterId->supplementalInfo2,
|
||||
esCb->cbEsMsgFunc, esCb->cbArg_addr, esSpecificInfo_addr);
|
||||
|
||||
u32 id = cellDmux.GetNewId(es);
|
||||
es->id = id;
|
||||
esHandle = 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.es.es = id;
|
||||
task.es.es_ptr = es;
|
||||
|
||||
dmux->job.Push(task);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellDmuxDisableEs(u32 esHandle)
|
||||
{
|
||||
cellDmux.Error("cellDmuxDisableEs(esHandle=0x%x)", esHandle);
|
||||
cellDmux.Warning("cellDmuxDisableEs(esHandle=0x%x)", esHandle);
|
||||
|
||||
ElementaryStream* es;
|
||||
if (!Emu.GetIdManager().GetIDData(esHandle, es))
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
}
|
||||
|
||||
DemuxerTask task(dmuxDisableEs);
|
||||
task.es.es = esHandle;
|
||||
task.es.es_ptr = es;
|
||||
|
||||
es->dmux->job.Push(task);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellDmuxResetEs(u32 esHandle)
|
||||
{
|
||||
cellDmux.Error("cellDmuxResetEs(esHandle=0x%x)", esHandle);
|
||||
cellDmux.Log("cellDmuxResetEs(esHandle=0x%x)", esHandle);
|
||||
|
||||
ElementaryStream* es;
|
||||
if (!Emu.GetIdManager().GetIDData(esHandle, es))
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
}
|
||||
|
||||
DemuxerTask task(dmuxResetEs);
|
||||
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);
|
||||
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))
|
||||
{
|
||||
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, const u32 auInfo_ptr_addr, u32 auSpecificInfo_ptr_addr)
|
||||
int cellDmuxPeekAu(u32 esHandle, mem32_t auInfo_ptr, mem32_t auSpecificInfo_ptr)
|
||||
{
|
||||
cellDmux.Error("cellDmuxPeekAu(esHandle=0x%x, auInfo_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)",
|
||||
esHandle, auInfo_ptr_addr, auSpecificInfo_ptr_addr);
|
||||
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, const u32 auInfoEx_ptr_addr, u32 auSpecificInfo_ptr_addr)
|
||||
int cellDmuxGetAuEx(u32 esHandle, mem32_t auInfoEx_ptr, mem32_t auSpecificInfo_ptr)
|
||||
{
|
||||
cellDmux.Error("cellDmuxGetAuEx(esHandle=0x%x, auInfoEx_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)",
|
||||
esHandle, auInfoEx_ptr_addr, auSpecificInfo_ptr_addr);
|
||||
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, const u32 auInfoEx_ptr_addr, u32 auSpecificInfo_ptr_addr)
|
||||
int cellDmuxPeekAuEx(u32 esHandle, mem32_t auInfoEx_ptr, mem32_t auSpecificInfo_ptr)
|
||||
{
|
||||
cellDmux.Error("cellDmuxPeekAuEx(esHandle=0x%x, auInfoEx_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)",
|
||||
esHandle, auInfoEx_ptr_addr, auSpecificInfo_ptr_addr);
|
||||
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.Error("cellDmuxReleaseAu(esHandle=0x%x)", esHandle);
|
||||
cellDmux.Warning("(disabled) cellDmuxReleaseAu(esHandle=0x%x)", esHandle);
|
||||
|
||||
return CELL_OK;
|
||||
|
||||
ElementaryStream* es;
|
||||
if (!Emu.GetIdManager().GetIDData(esHandle, es))
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
}
|
||||
|
||||
if (!es->canrelease())
|
||||
{
|
||||
cellDmux.Error("cellDmuxReleaseAu: no AU");
|
||||
return CELL_DMUX_ERROR_SEQ;
|
||||
//return CELL_OK;
|
||||
}
|
||||
|
||||
DemuxerTask task(dmuxReleaseAu);
|
||||
task.es.es = esHandle;
|
||||
task.es.es_ptr = es;
|
||||
|
||||
es->dmux->job.Push(task);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellDmuxFlushEs(u32 esHandle)
|
||||
{
|
||||
cellDmux.Error("cellDmuxFlushEs(esHandle=0x%x)", esHandle);
|
||||
cellDmux.Log("cellDmuxFlushEs(esHandle=0x%x)", esHandle);
|
||||
|
||||
ElementaryStream* es;
|
||||
if (!Emu.GetIdManager().GetIDData(esHandle, es))
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
}
|
||||
|
||||
DemuxerTask task(dmuxFlushEs);
|
||||
task.es.es = esHandle;
|
||||
task.es.es_ptr = es;
|
||||
|
||||
es->dmux->job.Push(task);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "Utilities/SQueue.h"
|
||||
|
||||
// align size or address to 128
|
||||
#define a128(x) ((x + 127) & (~127))
|
||||
|
||||
// Error Codes
|
||||
enum
|
||||
{
|
||||
@ -30,6 +35,118 @@ enum CellDmuxEsMsgType
|
||||
CELL_DMUX_ES_MSG_TYPE_FLUSH_DONE = 1,
|
||||
};
|
||||
|
||||
enum CellDmuxPamfM2vLevel
|
||||
{
|
||||
CELL_DMUX_PAMF_M2V_MP_LL = 0,
|
||||
CELL_DMUX_PAMF_M2V_MP_ML,
|
||||
CELL_DMUX_PAMF_M2V_MP_H14,
|
||||
CELL_DMUX_PAMF_M2V_MP_HL,
|
||||
};
|
||||
|
||||
enum CellDmuxPamfAvcLevel
|
||||
{
|
||||
CELL_DMUX_PAMF_AVC_LEVEL_2P1 = 21,
|
||||
CELL_DMUX_PAMF_AVC_LEVEL_3P0 = 30,
|
||||
CELL_DMUX_PAMF_AVC_LEVEL_3P1 = 31,
|
||||
CELL_DMUX_PAMF_AVC_LEVEL_3P2 = 32,
|
||||
CELL_DMUX_PAMF_AVC_LEVEL_4P1 = 41,
|
||||
CELL_DMUX_PAMF_AVC_LEVEL_4P2 = 42,
|
||||
};
|
||||
|
||||
struct CellDmuxPamfAuSpecificInfoM2v
|
||||
{
|
||||
be_t<u32> reserved1;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfAuSpecificInfoAvc
|
||||
{
|
||||
be_t<u32> reserved1;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfAuSpecificInfoLpcm
|
||||
{
|
||||
u8 channelAssignmentInfo;
|
||||
u8 samplingFreqInfo;
|
||||
u8 bitsPerSample;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfAuSpecificInfoAc3
|
||||
{
|
||||
be_t<u32> reserved1;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfAuSpecificInfoAtrac3plus
|
||||
{
|
||||
be_t<u32> reserved1;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfAuSpecificInfoUserData
|
||||
{
|
||||
be_t<u32> reserved1;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfEsSpecificInfoM2v
|
||||
{
|
||||
be_t<u32> profileLevel;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfEsSpecificInfoAvc
|
||||
{
|
||||
be_t<u32> level;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfEsSpecificInfoLpcm
|
||||
{
|
||||
be_t<u32> samplingFreq;
|
||||
be_t<u32> numOfChannels;
|
||||
be_t<u32> bitsPerSample;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfEsSpecificInfoAc3
|
||||
{
|
||||
be_t<u32> reserved1;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfEsSpecificInfoAtrac3plus
|
||||
{
|
||||
be_t<u32> reserved1;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfEsSpecificInfoUserData
|
||||
{
|
||||
be_t<u32> reserved1;
|
||||
};
|
||||
|
||||
enum CellDmuxPamfSamplingFrequency
|
||||
{
|
||||
CELL_DMUX_PAMF_FS_48K = 48000,
|
||||
};
|
||||
|
||||
enum CellDmuxPamfBitsPerSample
|
||||
{
|
||||
CELL_DMUX_PAMF_BITS_PER_SAMPLE_16 = 16,
|
||||
CELL_DMUX_PAMF_BITS_PER_SAMPLE_24 = 24,
|
||||
};
|
||||
|
||||
enum CellDmuxPamfLpcmChannelAssignmentInfo
|
||||
{
|
||||
CELL_DMUX_PAMF_LPCM_CH_M1 = 1,
|
||||
CELL_DMUX_PAMF_LPCM_CH_LR = 3,
|
||||
CELL_DMUX_PAMF_LPCM_CH_LRCLSRSLFE = 9,
|
||||
CELL_DMUX_PAMF_LPCM_CH_LRCLSCS1CS2RSLFE = 11,
|
||||
};
|
||||
|
||||
enum CellDmuxPamfLpcmFs
|
||||
{
|
||||
CELL_DMUX_PAMF_LPCM_FS_48K = 1,
|
||||
};
|
||||
|
||||
enum CellDmuxPamfLpcmBitsPerSamples
|
||||
{
|
||||
CELL_DMUX_PAMF_LPCM_BITS_PER_SAMPLE_16 = 1,
|
||||
CELL_DMUX_PAMF_LPCM_BITS_PER_SAMPLE_24 = 3,
|
||||
};
|
||||
|
||||
struct CellDmuxMsg
|
||||
{
|
||||
be_t<CellDmuxMsgType> msgType; //CellDmuxMsgType enum
|
||||
@ -44,13 +161,19 @@ struct CellDmuxEsMsg
|
||||
|
||||
struct CellDmuxType
|
||||
{
|
||||
CellDmuxStreamType streamType;
|
||||
be_t<CellDmuxStreamType> streamType;
|
||||
be_t<u32> reserved[2]; //0
|
||||
};
|
||||
|
||||
struct CellDmuxPamfSpecificInfo
|
||||
{
|
||||
be_t<u32> thisSize;
|
||||
bool programEndCodeCb;
|
||||
};
|
||||
|
||||
struct CellDmuxType2
|
||||
{
|
||||
CellDmuxStreamType streamType;
|
||||
be_t<CellDmuxStreamType> streamType;
|
||||
be_t<u32> streamSpecificInfo_addr;
|
||||
};
|
||||
|
||||
@ -99,17 +222,21 @@ struct CellDmuxResource2
|
||||
be_t<u32> shit[4];
|
||||
};
|
||||
|
||||
typedef mem_func_ptr_t<void (*)(u32 demuxerHandle, mem_ptr_t<CellDmuxMsg> demuxerMsg, u32 cbArg_addr)> CellDmuxCbMsg;
|
||||
|
||||
struct CellDmuxCb
|
||||
{
|
||||
// CellDmuxCbMsg callback
|
||||
be_t<mem_func_ptr_t<void (*)(u32 demuxerHandle_addr, mem_ptr_t<CellDmuxMsg> demuxerMsg, u32 cbArg_addr)>> cbMsgFunc;
|
||||
be_t<u32> cbMsgFunc;
|
||||
be_t<u32> cbArg_addr;
|
||||
};
|
||||
|
||||
typedef mem_func_ptr_t<void (*)(u32 demuxerHandle, u32 esHandle, mem_ptr_t<CellDmuxEsMsg> esMsg, u32 cbArg_addr)> CellDmuxCbEsMsg;
|
||||
|
||||
struct CellDmuxEsCb
|
||||
{
|
||||
// CellDmuxCbEsMsg callback
|
||||
be_t<mem_func_ptr_t<void (*)(u32 demuxerHandle_addr, u32 esHandle_addr, mem_ptr_t<CellDmuxEsMsg> esMsg, u32 cbArg_addr)>> cbEsMsgFunc;
|
||||
be_t<u32> cbEsMsgFunc;
|
||||
be_t<u32> cbArg_addr;
|
||||
};
|
||||
|
||||
@ -153,3 +280,414 @@ struct CellDmuxAuInfoEx
|
||||
CellCodecTimeStamp pts;
|
||||
CellCodecTimeStamp dts;
|
||||
};
|
||||
|
||||
/* Demuxer Thread Classes */
|
||||
|
||||
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;
|
||||
u64 userdata;
|
||||
bool discontinuity;
|
||||
|
||||
template<typename T>
|
||||
bool get(T& out)
|
||||
{
|
||||
if (sizeof(T) > size) return false;
|
||||
|
||||
out = *(T*)Memory.VirtualToRealAddr(addr);
|
||||
addr += sizeof(T);
|
||||
size -= sizeof(T);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool peek(T& out)
|
||||
{
|
||||
if (sizeof(T) > size) return false;
|
||||
|
||||
out = *(T*)Memory.VirtualToRealAddr(addr);
|
||||
return true;
|
||||
}
|
||||
|
||||
void skip(u32 count)
|
||||
{
|
||||
addr += count;
|
||||
size = size > count ? size - count : 0;
|
||||
}
|
||||
|
||||
u64 get_ts(u8 c)
|
||||
{
|
||||
u8 v[4]; get((u32&)v);
|
||||
return
|
||||
(((u64)c & 0x0e) << 29) |
|
||||
(((u64)v[0]) << 21) |
|
||||
(((u64)v[1] & 0x7e) << 15) |
|
||||
(((u64)v[2]) << 7) | ((u64)v[3] >> 1);
|
||||
}
|
||||
|
||||
u64 get_ts()
|
||||
{
|
||||
u8 v; get(v);
|
||||
return get_ts(v);
|
||||
}
|
||||
};
|
||||
|
||||
struct PesHeader
|
||||
{
|
||||
u64 pts;
|
||||
u64 dts;
|
||||
u8 ch;
|
||||
u8 size;
|
||||
bool new_au;
|
||||
|
||||
PesHeader(DemuxerStream& stream)
|
||||
: pts(0xffffffffffffffff)
|
||||
, dts(0xffffffffffffffff)
|
||||
, ch(0)
|
||||
, size(0)
|
||||
, new_au(true)
|
||||
{
|
||||
u16 header;
|
||||
stream.get(header);
|
||||
stream.get(size);
|
||||
if (size)
|
||||
{
|
||||
//ConLog.Write(">>>>> Pes Header (size=%d)", size);
|
||||
if (size < 10)
|
||||
{
|
||||
stream.skip(size);
|
||||
return;
|
||||
}
|
||||
new_au = true;
|
||||
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;
|
||||
|
||||
enum DemuxerJobType
|
||||
{
|
||||
dmuxSetStream,
|
||||
dmuxResetStream,
|
||||
dmuxResetStreamAndWaitDone,
|
||||
dmuxEnableEs,
|
||||
dmuxDisableEs,
|
||||
dmuxResetEs,
|
||||
dmuxReleaseAu,
|
||||
dmuxFlushEs,
|
||||
dmuxClose,
|
||||
};
|
||||
|
||||
struct DemuxerTask
|
||||
{
|
||||
DemuxerJobType type;
|
||||
|
||||
union
|
||||
{
|
||||
DemuxerStream stream;
|
||||
|
||||
struct
|
||||
{
|
||||
u32 es;
|
||||
u32 auInfo_ptr_addr;
|
||||
u32 auSpec_ptr_addr;
|
||||
ElementaryStream* es_ptr;
|
||||
} es;
|
||||
};
|
||||
|
||||
DemuxerTask()
|
||||
{
|
||||
}
|
||||
|
||||
DemuxerTask(DemuxerJobType type)
|
||||
: type(type)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class Demuxer
|
||||
{
|
||||
public:
|
||||
SQueue<DemuxerTask> job;
|
||||
const u32 memAddr;
|
||||
const u32 memSize;
|
||||
const u32 cbFunc;
|
||||
const u32 cbArg;
|
||||
u32 id;
|
||||
volatile bool is_finished;
|
||||
volatile bool is_running;
|
||||
|
||||
|
||||
Demuxer(u32 addr, u32 size, u32 func, u32 arg)
|
||||
: is_finished(false)
|
||||
, is_running(false)
|
||||
, memAddr(addr)
|
||||
, memSize(size)
|
||||
, cbFunc(func)
|
||||
, cbArg(arg)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
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 u32 cbFunc;
|
||||
const u32 cbArg;
|
||||
const u32 spec; //addr
|
||||
|
||||
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)
|
||||
, fidMajor(fidMajor)
|
||||
, fidMinor(fidMinor)
|
||||
, sup1(sup1)
|
||||
, sup2(sup2)
|
||||
, cbFunc(cbFunc)
|
||||
, cbArg(cbArg)
|
||||
, spec(spec)
|
||||
, first_addr(0)
|
||||
, peek_addr(0)
|
||||
, last_addr(a128(addr))
|
||||
, last_size(0)
|
||||
{
|
||||
}
|
||||
|
||||
volatile bool hasunseen()
|
||||
{
|
||||
return peek_addr;
|
||||
}
|
||||
|
||||
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);
|
||||
//ConLog.Write("es::finish(): peek=0x%x, first=0x%x, last=0x%x, size=0x%x", peek_addr, first_addr, last_addr, last_size);
|
||||
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);
|
||||
//ConLog.Write("es::push(): peek=0x%x, first=0x%x, last=0x%x, size=0x%x", peek_addr, first_addr, last_addr, last_size);
|
||||
if (isfull())
|
||||
{
|
||||
ConLog.Error("ElementaryStream::push(): buffer is full");
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
|
||||
u32 data_addr = last_addr + 128 + last_size;
|
||||
last_size += size;
|
||||
if (!Memory.Copy(data_addr, stream.addr, size))
|
||||
{
|
||||
ConLog.Error("ElementaryStream::push(): data copying failed");
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
stream.skip(size);
|
||||
|
||||
mem_ptr_t<CellDmuxAuInfoEx> info(last_addr);
|
||||
info->auAddr = last_addr + 128;
|
||||
info->auSize = last_size;
|
||||
if (pes.size)
|
||||
{
|
||||
info->dts.lower = (u32)pes.dts;
|
||||
info->dts.upper = (u32)(pes.dts >> 32);
|
||||
info->pts.lower = (u32)pes.pts;
|
||||
info->pts.upper = (u32)(pes.pts >> 32);
|
||||
info->isRap = false; // TODO: set valid value
|
||||
info->reserved = 0;
|
||||
info->userData = stream.userdata;
|
||||
}
|
||||
|
||||
mem_ptr_t<CellDmuxPamfAuSpecificInfoAvc> tail(last_addr + sizeof(CellDmuxAuInfoEx));
|
||||
tail->reserved1 = 0;
|
||||
|
||||
mem_ptr_t<CellDmuxAuInfo> inf(last_addr + 64);
|
||||
inf->auAddr = last_addr + 128;
|
||||
inf->auSize = last_size;
|
||||
if (pes.size)
|
||||
{
|
||||
inf->dtsLower = (u32)pes.dts;
|
||||
inf->dtsUpper = (u32)(pes.dts >> 32);
|
||||
inf->ptsLower = (u32)pes.pts;
|
||||
inf->ptsUpper = (u32)(pes.pts >> 32);
|
||||
inf->auMaxSize = 0; // ?????
|
||||
inf->userData = stream.userdata;
|
||||
}
|
||||
}
|
||||
|
||||
volatile bool canrelease()
|
||||
{
|
||||
return first_addr;
|
||||
}
|
||||
|
||||
void release()
|
||||
{
|
||||
SMutexLocker lock(mutex);
|
||||
ConLog.Write("es::release(): peek=0x%x, first=0x%x, last=0x%x, size=0x%x", peek_addr, first_addr, last_addr, last_size);
|
||||
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(%sAu%s): peek=0x%x, first=0x%x, last=0x%x, size=0x%x", wxString(update_index ? "Get" : "Peek").wx_str(),
|
||||
wxString(no_ex ? "" : "Ex").wx_str(), peek_addr, first_addr, last_addr, last_size);*/
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
@ -164,7 +164,7 @@ int cellGifDecDecodeData(u32 mainHandle, u32 subHandle, mem8_ptr_t data, const m
|
||||
switch(current_outParam.outputColorSpace)
|
||||
{
|
||||
case CELL_GIFDEC_RGBA:
|
||||
memcpy(data, image.get(), image_size);
|
||||
Memory.CopyFromReal(data.GetAddr(), image.get(), image_size);
|
||||
break;
|
||||
|
||||
case CELL_GIFDEC_ARGB:
|
||||
|
@ -148,7 +148,7 @@ int cellJpgDecDecodeData(u32 mainHandle, u32 subHandle, mem8_ptr_t data, const m
|
||||
case CELL_JPG_RGBA:
|
||||
case CELL_JPG_RGB:
|
||||
image_size *= current_outParam.outputColorSpace == CELL_JPG_RGBA ? 4 : 3;
|
||||
memcpy(data, image.get(), image_size);
|
||||
Memory.CopyFromReal(data.GetAddr(), image.get(), image_size);
|
||||
break;
|
||||
|
||||
case CELL_JPG_ARGB:
|
||||
|
@ -17,26 +17,16 @@ int pamfStreamTypeToEsFilterId(u8 type, u8 ch, mem_ptr_t<CellCodecEsFilterId> 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<CellPamfReader> 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<CellPamfReader> pSelf, u8 stream)
|
||||
|
||||
u8 pamfGetStreamChannel(mem_ptr_t<CellPamfReader> pSelf, u8 stream)
|
||||
{
|
||||
cellPamf.Warning("TODO: pamfGetStreamChannel");
|
||||
//TODO: get stream channel correctly
|
||||
const mem_ptr_t<PamfHeader> 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;
|
||||
}
|
||||
|
||||
@ -122,7 +116,7 @@ int cellPamfGetHeaderSize(mem_ptr_t<PamfHeader> pAddr, u64 fileSize, mem64_t pSi
|
||||
//return CELL_PAMF_ERROR_UNKNOWN_TYPE;
|
||||
|
||||
const u64 offset = (u64)pAddr->data_offset << 11;
|
||||
pSize = offset /*? offset : 2048*/; //hack
|
||||
pSize = offset;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -135,12 +129,10 @@ int cellPamfGetHeaderSize2(mem_ptr_t<PamfHeader> pAddr, u64 fileSize, u32 attrib
|
||||
//return CELL_PAMF_ERROR_UNKNOWN_TYPE;
|
||||
|
||||
const u64 offset = (u64)pAddr->data_offset << 11;
|
||||
pSize = offset /*? offset : 2048*/; //hack
|
||||
pSize = offset;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
//u32 hack_LastHeader = 0;
|
||||
|
||||
int cellPamfGetStreamOffsetAndSize(mem_ptr_t<PamfHeader> pAddr, u64 fileSize, mem64_t pOffset, mem64_t pSize)
|
||||
{
|
||||
cellPamf.Warning("cellPamfGetStreamOffsetAndSize(pAddr=0x%x, fileSize=%d, pOffset_addr=0x%x, pSize_addr=0x%x)",
|
||||
@ -150,10 +142,9 @@ int cellPamfGetStreamOffsetAndSize(mem_ptr_t<PamfHeader> pAddr, u64 fileSize, me
|
||||
//return CELL_PAMF_ERROR_UNKNOWN_TYPE;
|
||||
|
||||
const u64 offset = (u64)pAddr->data_offset << 11;
|
||||
pOffset = offset /*? offset : 2048*/; //hack
|
||||
pOffset = offset;
|
||||
const u64 size = (u64)pAddr->data_size << 11;
|
||||
pSize = size /*? size : (fileSize - 2048)*/; //hack
|
||||
//if (!(u32)pAddr->magic) hack_LastHeader = pAddr.GetAddr();
|
||||
pSize = size;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -177,7 +168,7 @@ int cellPamfReaderInitialize(mem_ptr_t<CellPamfReader> pSelf, mem_ptr_t<PamfHead
|
||||
pSelf->fileSize = ((u64)pAddr->data_offset << 11) + ((u64)pAddr->data_size << 11);
|
||||
}
|
||||
pSelf->pAddr = pAddr.GetAddr();
|
||||
//if (hack_LastHeader) memcpy(Memory + pAddr.GetAddr(), Memory + hack_LastHeader, 2048);
|
||||
|
||||
if (attribute & CELL_PAMF_ATTRIBUTE_VERIFY_ON)
|
||||
{
|
||||
//TODO
|
||||
|
@ -135,13 +135,15 @@ enum
|
||||
};
|
||||
|
||||
// Timestamp information (time in increments of 90 kHz)
|
||||
struct CellCodecTimeStamp {
|
||||
struct CellCodecTimeStamp
|
||||
{
|
||||
be_t<u32> upper;
|
||||
be_t<u32> lower;
|
||||
};
|
||||
|
||||
// Entry point information
|
||||
struct CellPamfEp {
|
||||
struct CellPamfEp
|
||||
{
|
||||
be_t<u32> indexN;
|
||||
be_t<u32> nThRefPictureOffset;
|
||||
CellCodecTimeStamp pts;
|
||||
|
@ -91,7 +91,7 @@ int cellPngDecReadHeader(u32 mainHandle, u32 subHandle, mem_ptr_t<CellPngDecInfo
|
||||
switch(subHandle_data->src.srcSelect.ToLE())
|
||||
{
|
||||
case CELL_PNGDEC_BUFFER:
|
||||
memcpy(Memory.VirtualToRealAddr(buffer.GetAddr()), Memory.VirtualToRealAddr(subHandle_data->src.streamPtr.ToLE()), buffer.GetSize());
|
||||
Memory.Copy(buffer.GetAddr(), subHandle_data->src.streamPtr.ToLE(), buffer.GetSize());
|
||||
break;
|
||||
case CELL_PNGDEC_FILE:
|
||||
cellFsLseek(fd, 0, CELL_SEEK_SET, pos);
|
||||
@ -145,7 +145,7 @@ int cellPngDecDecodeData(u32 mainHandle, u32 subHandle, mem8_ptr_t data, const m
|
||||
switch(subHandle_data->src.srcSelect.ToLE())
|
||||
{
|
||||
case CELL_PNGDEC_BUFFER:
|
||||
memcpy(Memory.VirtualToRealAddr(png.GetAddr()), Memory.VirtualToRealAddr(subHandle_data->src.streamPtr.ToLE()), png.GetSize());
|
||||
Memory.Copy(png.GetAddr(), subHandle_data->src.streamPtr.ToLE(), png.GetSize());
|
||||
break;
|
||||
case CELL_PNGDEC_FILE:
|
||||
cellFsLseek(fd, 0, CELL_SEEK_SET, pos);
|
||||
@ -164,7 +164,7 @@ int cellPngDecDecodeData(u32 mainHandle, u32 subHandle, mem8_ptr_t data, const m
|
||||
case CELL_PNGDEC_RGB:
|
||||
case CELL_PNGDEC_RGBA:
|
||||
image_size *= current_outParam.outputColorSpace == CELL_PNGDEC_RGBA ? 4 : 3;
|
||||
memcpy(data, image.get(), image_size);
|
||||
Memory.CopyFromReal(data.GetAddr(), image.get(), image_size);
|
||||
break;
|
||||
|
||||
case CELL_PNGDEC_ARGB:
|
||||
|
@ -1,76 +1,578 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
#include "Emu/SysCalls/SC_FUNC.h"
|
||||
#include "cellPamf.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "libavcodec\avcodec.h"
|
||||
#include "libavformat\avformat.h"
|
||||
#include "libavutil\imgutils.h"
|
||||
}
|
||||
|
||||
#include "cellVdec.h"
|
||||
|
||||
void cellVdec_init();
|
||||
Module cellVdec(0x0005, cellVdec_init);
|
||||
|
||||
int vdecRead(void* opaque, u8* buf, int buf_size)
|
||||
{
|
||||
VideoDecoder& vdec = *(VideoDecoder*)opaque;
|
||||
|
||||
if (vdec.reader.size < (u32)buf_size) buf_size = vdec.reader.size;
|
||||
if (!buf_size)
|
||||
{
|
||||
return AVERROR_EOF;
|
||||
}
|
||||
else if (!Memory.CopyToReal(buf, vdec.reader.addr, buf_size))
|
||||
{
|
||||
ConLog.Error("vdecRead: data reading failed (buf_size=0x%x)", buf_size);
|
||||
Emu.Pause();
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
vdec.reader.addr += buf_size;
|
||||
vdec.reader.size -= buf_size;
|
||||
return buf_size;
|
||||
}
|
||||
}
|
||||
|
||||
u32 vdecQueryAttr(CellVdecCodecType type, u32 profile, u32 spec_addr /* may be 0 */, mem_ptr_t<CellVdecAttr> attr)
|
||||
{
|
||||
switch (type) // TODO: check profile levels
|
||||
{
|
||||
case CELL_VDEC_CODEC_TYPE_AVC: cellVdec.Warning("cellVdecQueryAttr: AVC (profile=%d)", profile); break;
|
||||
case CELL_VDEC_CODEC_TYPE_MPEG2: cellVdec.Error("TODO: MPEG2 not supported"); break;
|
||||
case CELL_VDEC_CODEC_TYPE_DIVX: cellVdec.Error("TODO: DIVX not supported"); break;
|
||||
default: return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
// TODO: check values
|
||||
attr->decoderVerLower = 0x280000; // from dmux
|
||||
attr->decoderVerUpper = 0x260000;
|
||||
attr->memSize = 4 * 1024 * 1024;
|
||||
attr->cmdDepth = 16;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
u32 vdecOpen(VideoDecoder* data)
|
||||
{
|
||||
VideoDecoder& vdec = *data;
|
||||
|
||||
u32 vdec_id = cellVdec.GetNewId(data);
|
||||
|
||||
vdec.id = vdec_id;
|
||||
|
||||
thread t("Video Decoder[" + std::to_string(vdec_id) + "] Thread", [&]()
|
||||
{
|
||||
ConLog.Write("Video Decoder enter()");
|
||||
|
||||
VdecTask task;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (vdec.job.IsEmpty() && vdec.is_running)
|
||||
{
|
||||
// TODO: default task (not needed?)
|
||||
Sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (vdec.has_picture) // hack
|
||||
{
|
||||
Sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!vdec.job.Pop(task))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
switch (task.type)
|
||||
{
|
||||
case vdecStartSeq:
|
||||
{
|
||||
// TODO: reset data
|
||||
ConLog.Warning("vdecStartSeq()");
|
||||
vdec.is_running = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case vdecEndSeq:
|
||||
{
|
||||
Callback cb;
|
||||
cb.SetAddr(vdec.cbFunc);
|
||||
cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_SEQDONE, 0, vdec.cbArg);
|
||||
cb.Branch(false);
|
||||
ConLog.Warning("vdecEndSeq()");
|
||||
vdec.is_running = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case vdecDecodeAu:
|
||||
{
|
||||
struct vdecPacket : AVPacket
|
||||
{
|
||||
vdecPacket(u32 size)
|
||||
{
|
||||
av_init_packet(this);
|
||||
data = (u8*)av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
|
||||
memset(data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
|
||||
this->size = size + FF_INPUT_BUFFER_PADDING_SIZE;
|
||||
}
|
||||
|
||||
~vdecPacket()
|
||||
{
|
||||
av_free(data);
|
||||
//av_free_packet(this);
|
||||
}
|
||||
|
||||
} au(task.size);
|
||||
|
||||
if ((task.pts || task.dts) && task.pts != ~0 && task.dts != ~0)
|
||||
{
|
||||
vdec.pts = task.pts;
|
||||
vdec.dts = task.dts;
|
||||
au.pts = vdec.pts;
|
||||
au.dts = vdec.dts;
|
||||
au.flags = AV_PKT_FLAG_KEY;
|
||||
}
|
||||
else
|
||||
{
|
||||
au.pts = vdec.pts;
|
||||
au.dts = vdec.dts;
|
||||
}
|
||||
|
||||
if (task.mode != CELL_VDEC_DEC_MODE_NORMAL)
|
||||
{
|
||||
ConLog.Error("vdecDecodeAu: unsupported decoding mode(%d)", task.mode);
|
||||
break;
|
||||
}
|
||||
|
||||
vdec.reader.addr = task.addr;
|
||||
vdec.reader.size = task.size;
|
||||
|
||||
if (!Memory.CopyToReal(au.data, task.addr, task.size))
|
||||
{
|
||||
ConLog.Error("vdecDecodeAu: AU data accessing failed(addr=0x%x, size=0x%x)", task.addr, task.size);
|
||||
break;
|
||||
}
|
||||
|
||||
/*{
|
||||
wxFile dump;
|
||||
dump.Open(wxString::Format("0x%llx-0x%llx.dump", au.pts, au.dts), wxFile::write);
|
||||
dump.Write(au.data, task.size + FF_INPUT_BUFFER_PADDING_SIZE);
|
||||
dump.Close();
|
||||
}*/
|
||||
|
||||
int got_picture = 0;
|
||||
|
||||
//vdec.ctx->flags |= CODEC_FLAG_TRUNCATED;
|
||||
//vdec.ctx->flags2 |= CODEC_FLAG2_CHUNKS;
|
||||
vdec.ctx->flags2 |= CODEC_FLAG2_LOCAL_HEADER;
|
||||
vdec.ctx->codec_tag = *(u32*)"DAVC";
|
||||
//vdec.ctx->stream_codec_tag = *(u32*)"DAVC";
|
||||
|
||||
//avcodec_get_frame_defaults(vdec.frame);
|
||||
|
||||
|
||||
int decode = avcodec_decode_video2(vdec.ctx, vdec.frame, &got_picture, &au);
|
||||
if (decode < 0)
|
||||
{
|
||||
ConLog.Error("vdecDecodeAu: AU decoding error(%d)", decode);
|
||||
break;
|
||||
}
|
||||
|
||||
if (got_picture)
|
||||
{
|
||||
ConLog.Write("got_picture (%d, vdec: pts=0x%llx, dts=0x%llx)", got_picture, vdec.pts, vdec.dts);
|
||||
|
||||
/*if (vdec.out_data[0]) av_freep(vdec.out_data[0]);
|
||||
|
||||
int err = av_image_alloc(vdec.out_data, vdec.linesize, vdec.ctx->width, vdec.ctx->height, vdec.ctx->pix_fmt, 1);
|
||||
if (err < 0)
|
||||
{
|
||||
ConLog.Error("vdecDecodeAu: av_image_alloc failed(%d)", err);
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
|
||||
vdec.buf_size = err;
|
||||
|
||||
av_image_copy(vdec.out_data, vdec.linesize, (const u8**)(vdec.frame->data), vdec.frame->linesize,
|
||||
vdec.ctx->pix_fmt, vdec.ctx->width, vdec.ctx->height);*/
|
||||
vdec.buf_size = a128(av_image_get_buffer_size(vdec.ctx->pix_fmt, vdec.ctx->width, vdec.ctx->height, 1));
|
||||
|
||||
vdec.userdata = task.userData;
|
||||
vdec.has_picture = true;
|
||||
|
||||
Callback cb;
|
||||
cb.SetAddr(vdec.cbFunc);
|
||||
cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_PICOUT, 0, vdec.cbArg);
|
||||
cb.Branch(false);
|
||||
}
|
||||
|
||||
ConLog.Write("Frame decoded (pts=0x%llx, dts=0x%llx, addr=0x%x, result=0x%x)", au.pts, au.dts, task.addr, decode);
|
||||
|
||||
Callback cb;
|
||||
cb.SetAddr(vdec.cbFunc);
|
||||
cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, 0, vdec.cbArg);
|
||||
cb.Branch(false);
|
||||
}
|
||||
break;
|
||||
|
||||
case vdecClose:
|
||||
{
|
||||
vdec.is_finished = true;
|
||||
ConLog.Write("Video Decoder exit");
|
||||
return;
|
||||
}
|
||||
|
||||
case vdecSetFrameRate:
|
||||
{
|
||||
ConLog.Error("TODO: vdecSetFrameRate(%d)", task.frc);
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
ConLog.Error("Video Decoder error: unknown task(%d)", task.type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ConLog.Warning("Video Decoder aborted");
|
||||
});
|
||||
|
||||
t.detach();
|
||||
|
||||
return vdec_id;
|
||||
}
|
||||
|
||||
int cellVdecQueryAttr(const mem_ptr_t<CellVdecType> type, mem_ptr_t<CellVdecAttr> attr)
|
||||
{
|
||||
cellVdec.Error("cellVdecQueryAttr(type_addr=0x%x, attr_addr=0x%x)", type.GetAddr(), attr.GetAddr());
|
||||
return CELL_OK;
|
||||
cellVdec.Warning("cellVdecQueryAttr(type_addr=0x%x, attr_addr=0x%x)", type.GetAddr(), attr.GetAddr());
|
||||
|
||||
if (!type.IsGood() || !attr.IsGood())
|
||||
{
|
||||
return CELL_VDEC_ERROR_FATAL;
|
||||
}
|
||||
|
||||
return vdecQueryAttr(type->codecType, type->profileLevel, 0, attr);
|
||||
}
|
||||
|
||||
int cellVdecQueryAttrEx(const mem_ptr_t<CellVdecTypeEx> type, mem_ptr_t<CellVdecAttr> attr)
|
||||
{
|
||||
cellVdec.Error("cellVdecQueryAttrEx(type_addr=0x%x, attr_addr=0x%x)", type.GetAddr(), attr.GetAddr());
|
||||
return CELL_OK;
|
||||
cellVdec.Warning("cellVdecQueryAttrEx(type_addr=0x%x, attr_addr=0x%x)", type.GetAddr(), attr.GetAddr());
|
||||
|
||||
if (!type.IsGood() || !attr.IsGood())
|
||||
{
|
||||
return CELL_VDEC_ERROR_FATAL;
|
||||
}
|
||||
|
||||
return vdecQueryAttr(type->codecType, type->profileLevel, type->codecSpecificInfo_addr, attr);
|
||||
}
|
||||
|
||||
int cellVdecOpen(const mem_ptr_t<CellVdecType> type, const mem_ptr_t<CellVdecResource> res, const mem_ptr_t<CellVdecCb> cb, mem32_t handle)
|
||||
{
|
||||
cellVdec.Error("cellVdecOpen(type_addr=0x%x, res_addr=0x%x, cb_addr=0x%x, handle_addr=0x%x)",
|
||||
cellVdec.Warning("cellVdecOpen(type_addr=0x%x, res_addr=0x%x, cb_addr=0x%x, handle_addr=0x%x)",
|
||||
type.GetAddr(), res.GetAddr(), cb.GetAddr(), handle.GetAddr());
|
||||
|
||||
if (!type.IsGood() || !res.IsGood() || !cb.IsGood() || !handle.IsGood())
|
||||
{
|
||||
return CELL_VDEC_ERROR_FATAL;
|
||||
}
|
||||
|
||||
if (!Memory.IsGoodAddr(res->memAddr, res->memSize) || !Memory.IsGoodAddr(cb->cbFunc))
|
||||
{
|
||||
return CELL_VDEC_ERROR_FATAL;
|
||||
}
|
||||
|
||||
handle = vdecOpen(new VideoDecoder(type->codecType, type->profileLevel, res->memAddr, res->memSize, cb->cbFunc, cb->cbArg));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellVdecOpenEx(const mem_ptr_t<CellVdecTypeEx> type, const mem_ptr_t<CellVdecResourceEx> res, const mem_ptr_t<CellVdecCb> cb, mem32_t handle)
|
||||
{
|
||||
cellVdec.Error("cellVdecOpenEx(type_addr=0x%x, res_addr=0x%x, cb_addr=0x%x, handle_addr=0x%x)",
|
||||
cellVdec.Warning("cellVdecOpenEx(type_addr=0x%x, res_addr=0x%x, cb_addr=0x%x, handle_addr=0x%x)",
|
||||
type.GetAddr(), res.GetAddr(), cb.GetAddr(), handle.GetAddr());
|
||||
|
||||
if (!type.IsGood() || !res.IsGood() || !cb.IsGood() || !handle.IsGood())
|
||||
{
|
||||
return CELL_VDEC_ERROR_FATAL;
|
||||
}
|
||||
|
||||
if (!Memory.IsGoodAddr(res->memAddr, res->memSize) || !Memory.IsGoodAddr(cb->cbFunc))
|
||||
{
|
||||
return CELL_VDEC_ERROR_FATAL;
|
||||
}
|
||||
|
||||
handle = vdecOpen(new VideoDecoder(type->codecType, type->profileLevel, res->memAddr, res->memSize, cb->cbFunc, cb->cbArg));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellVdecClose(u32 handle)
|
||||
{
|
||||
cellVdec.Error("cellVdecClose(handle=0x%x)", handle);
|
||||
cellVdec.Warning("cellVdecClose(handle=%d)", handle);
|
||||
|
||||
VideoDecoder* vdec;
|
||||
if (!Emu.GetIdManager().GetIDData(handle, vdec))
|
||||
{
|
||||
return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
vdec->job.Push(VdecTask(vdecClose));
|
||||
|
||||
while (!vdec->is_finished)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
ConLog.Warning("cellVdecClose(%d) aborted", handle);
|
||||
break;
|
||||
}
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
Emu.GetIdManager().RemoveID(handle);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellVdecStartSeq(u32 handle)
|
||||
{
|
||||
cellVdec.Error("cellVdecStartSeq(handle=0x%x)", handle);
|
||||
cellVdec.Log("cellVdecStartSeq(handle=%d)", handle);
|
||||
|
||||
VideoDecoder* vdec;
|
||||
if (!Emu.GetIdManager().GetIDData(handle, vdec))
|
||||
{
|
||||
return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
vdec->job.Push(VdecTask(vdecStartSeq));
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellVdecEndSeq(u32 handle)
|
||||
{
|
||||
cellVdec.Error("cellVdecEndSeq(handle=0x%x)", handle);
|
||||
cellVdec.Log("cellVdecEndSeq(handle=%d)", handle);
|
||||
|
||||
VideoDecoder* vdec;
|
||||
if (!Emu.GetIdManager().GetIDData(handle, vdec))
|
||||
{
|
||||
return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
vdec->job.Push(VdecTask(vdecEndSeq));
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellVdecDecodeAu(u32 handle, CellVdecDecodeMode mode, const mem_ptr_t<CellVdecAuInfo> auInfo)
|
||||
{
|
||||
cellVdec.Error("cellVdecDecodeAu(handle=0x%x, mode=0x%x, auInfo_addr=0x%x)", handle, mode, auInfo.GetAddr());
|
||||
cellVdec.Log("cellVdecDecodeAu(handle=%d, mode=0x%x, auInfo_addr=0x%x)", handle, mode, auInfo.GetAddr());
|
||||
|
||||
VideoDecoder* vdec;
|
||||
if (!Emu.GetIdManager().GetIDData(handle, vdec))
|
||||
{
|
||||
return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
// TODO: check info
|
||||
VdecTask task(vdecDecodeAu);
|
||||
task.mode = mode;
|
||||
task.addr = auInfo->startAddr;
|
||||
task.size = auInfo->size;
|
||||
task.dts = (u64)auInfo->dts.lower | ((u64)auInfo->dts.upper << 32);
|
||||
task.pts = (u64)auInfo->pts.lower | ((u64)auInfo->pts.upper << 32);
|
||||
task.userData = auInfo->userData;
|
||||
task.specData = auInfo->codecSpecificData;
|
||||
|
||||
vdec->job.Push(task);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellVdecGetPicture(u32 handle, const mem_ptr_t<CellVdecPicFormat> format, u32 out_addr)
|
||||
{
|
||||
cellVdec.Error("cellVdecGetPicture(handle=0x%x, format_addr=0x%x, out_addr=0x%x)", handle, format.GetAddr(), out_addr);
|
||||
cellVdec.Warning("cellVdecGetPicture(handle=%d, format_addr=0x%x, out_addr=0x%x)", handle, format.GetAddr(), out_addr);
|
||||
|
||||
VideoDecoder* vdec;
|
||||
if (!Emu.GetIdManager().GetIDData(handle, vdec))
|
||||
{
|
||||
return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
if (!format.IsGood())
|
||||
{
|
||||
return CELL_VDEC_ERROR_FATAL;
|
||||
}
|
||||
|
||||
if (!vdec->has_picture)
|
||||
{
|
||||
return CELL_VDEC_ERROR_EMPTY;
|
||||
}
|
||||
|
||||
if (out_addr)
|
||||
{
|
||||
if (!Memory.IsGoodAddr(out_addr, vdec->buf_size))
|
||||
{
|
||||
return CELL_VDEC_ERROR_FATAL;
|
||||
}
|
||||
|
||||
if (format->formatType != CELL_VDEC_PICFMT_YUV420_PLANAR)
|
||||
{
|
||||
cellVdec.Error("cellVdecGetPicture: TODO: unknown formatType(%d)", (u32)format->formatType);
|
||||
return CELL_OK;
|
||||
}
|
||||
if (format->colorMatrixType != CELL_VDEC_COLOR_MATRIX_TYPE_BT709)
|
||||
{
|
||||
cellVdec.Error("cellVdecGetPicture: TODO: unknown colorMatrixType(%d)", (u32)format->colorMatrixType);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellVdecGetPicItem(u32 handle, const u32 picItem_ptr_addr)
|
||||
AVFrame& frame = *vdec->frame;
|
||||
|
||||
u8* buf = (u8*)malloc(vdec->buf_size);
|
||||
if (!buf)
|
||||
{
|
||||
cellVdec.Error("cellVdecGetPicItem(handle=0x%x, picItem_ptr_addr=0x%x)", handle, picItem_ptr_addr);
|
||||
cellVdec.Error("cellVdecGetPicture: malloc failed (out of memory)");
|
||||
Emu.Pause();
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
// TODO: zero padding bytes
|
||||
|
||||
int err = av_image_copy_to_buffer(buf, vdec->buf_size, frame.data, frame.linesize, vdec->ctx->pix_fmt, frame.width, frame.height, 1);
|
||||
if (err < 0)
|
||||
{
|
||||
cellVdec.Error("cellVdecGetPicture: av_image_copy_to_buffer failed(%d)", err);
|
||||
Emu.Pause();
|
||||
}
|
||||
|
||||
if (!Memory.CopyFromReal(out_addr, buf, vdec->buf_size))
|
||||
{
|
||||
cellVdec.Error("cellVdecGetPicture: data copying failed");
|
||||
Emu.Pause();
|
||||
}
|
||||
|
||||
/*
|
||||
u32 size0 = frame.linesize[0] * frame.height;
|
||||
u32 size1 = frame.linesize[1] * frame.height / 2;
|
||||
u32 size2 = frame.linesize[2] * frame.height / 2;
|
||||
ConLog.Write("*** size0=0x%x, size1=0x%x, size2=0x%x, buf_size=0x%x (res=0x%x)", size0, size1, size2, vdec->buf_size, err);
|
||||
*/
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
vdec->has_picture = false;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellVdecGetPicItem(u32 handle, mem32_t picItem_ptr)
|
||||
{
|
||||
cellVdec.Warning("cellVdecGetPicItem(handle=%d, picItem_ptr_addr=0x%x)", handle, picItem_ptr.GetAddr());
|
||||
|
||||
VideoDecoder* vdec;
|
||||
if (!Emu.GetIdManager().GetIDData(handle, vdec))
|
||||
{
|
||||
return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
if (!picItem_ptr.IsGood())
|
||||
{
|
||||
return CELL_VDEC_ERROR_FATAL;
|
||||
}
|
||||
|
||||
if (!vdec->has_picture)
|
||||
{
|
||||
return CELL_VDEC_ERROR_EMPTY;
|
||||
}
|
||||
|
||||
mem_ptr_t<CellVdecPicItem> info(vdec->memAddr);
|
||||
|
||||
info->codecType = vdec->type;
|
||||
info->startAddr = 0x00000123; // invalid value (no address for picture)
|
||||
info->size = vdec->buf_size;
|
||||
info->auNum = 1;
|
||||
info->auPts[0].lower = vdec->pts;
|
||||
info->auPts[0].upper = vdec->pts >> 32;
|
||||
info->auPts[1].lower = 0xffffffff;
|
||||
info->auPts[1].upper = 0xffffffff;
|
||||
info->auDts[0].lower = vdec->dts;
|
||||
info->auDts[0].upper = vdec->dts >> 32;
|
||||
info->auDts[1].lower = 0xffffffff;
|
||||
info->auDts[1].upper = 0xffffffff;
|
||||
info->auUserData[0] = vdec->userdata;
|
||||
info->auUserData[1] = 0;
|
||||
info->status = CELL_OK;
|
||||
info->attr = CELL_VDEC_PICITEM_ATTR_NORMAL;
|
||||
info->picInfo_addr = vdec->memAddr + sizeof(CellVdecPicItem);
|
||||
|
||||
mem_ptr_t<CellVdecAvcInfo> avc(vdec->memAddr + sizeof(CellVdecPicItem));
|
||||
|
||||
avc->horizontalSize = vdec->frame->width; // ???
|
||||
avc->verticalSize = vdec->frame->height;
|
||||
switch (vdec->frame->pict_type)
|
||||
{
|
||||
case AV_PICTURE_TYPE_I: avc->pictureType[0] = CELL_VDEC_AVC_PCT_I; break;
|
||||
case AV_PICTURE_TYPE_P: avc->pictureType[0] = CELL_VDEC_AVC_PCT_P; break;
|
||||
case AV_PICTURE_TYPE_B: avc->pictureType[0] = CELL_VDEC_AVC_PCT_B; break;
|
||||
default: avc->pictureType[0] = CELL_VDEC_AVC_PCT_UNKNOWN; break; // ???
|
||||
}
|
||||
avc->pictureType[1] = CELL_VDEC_AVC_PCT_UNKNOWN; // ???
|
||||
avc->idrPictureFlag = false; // ???
|
||||
avc->aspect_ratio_idc = CELL_VDEC_AVC_ARI_SAR_UNSPECIFIED; // ???
|
||||
avc->sar_height = 0;
|
||||
avc->sar_width = 0;
|
||||
avc->pic_struct = CELL_VDEC_AVC_PSTR_FRAME; // ???
|
||||
avc->picOrderCount[0] = 0; // ???
|
||||
avc->picOrderCount[1] = 0;
|
||||
avc->vui_parameters_present_flag = true; // ???
|
||||
avc->frame_mbs_only_flag = true; // ??? progressive
|
||||
avc->video_signal_type_present_flag = true; // ???
|
||||
avc->video_format = CELL_VDEC_AVC_VF_COMPONENT; // ???
|
||||
avc->video_full_range_flag = false; // ???
|
||||
avc->colour_description_present_flag = true;
|
||||
avc->colour_primaries = CELL_VDEC_AVC_CP_ITU_R_BT_709_5; // ???
|
||||
avc->transfer_characteristics = CELL_VDEC_AVC_TC_ITU_R_BT_709_5;
|
||||
avc->matrix_coefficients = CELL_VDEC_AVC_MXC_ITU_R_BT_709_5; // important
|
||||
avc->timing_info_present_flag = true;
|
||||
avc->frameRateCode = CELL_VDEC_AVC_FRC_30000DIV1001; // important (!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)
|
||||
avc->fixed_frame_rate_flag = true;
|
||||
avc->low_delay_hrd_flag = true; // ???
|
||||
avc->entropy_coding_mode_flag = true; // ???
|
||||
avc->nalUnitPresentFlags = 0; // ???
|
||||
avc->ccDataLength[0] = 0;
|
||||
avc->ccDataLength[1] = 0;
|
||||
avc->reserved[0] = 0;
|
||||
avc->reserved[1] = 0;
|
||||
|
||||
picItem_ptr = info.GetAddr();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellVdecSetFrameRate(u32 handle, CellVdecFrameRate frc)
|
||||
{
|
||||
cellVdec.Error("cellVdecSetFrameRate(handle=0x%x, frc=0x%x)", handle, frc);
|
||||
cellVdec.Log("cellVdecSetFrameRate(handle=%d, frc=0x%x)", handle, frc);
|
||||
|
||||
VideoDecoder* vdec;
|
||||
if (!Emu.GetIdManager().GetIDData(handle, vdec))
|
||||
{
|
||||
return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
// TODO: check frc value and set frame rate
|
||||
VdecTask task(vdecSetFrameRate);
|
||||
task.frc = frc;
|
||||
|
||||
vdec->job.Push(task);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -87,4 +589,6 @@ void cellVdec_init()
|
||||
cellVdec.AddFunc(0x807c861a, cellVdecGetPicture);
|
||||
cellVdec.AddFunc(0x17c702b9, cellVdecGetPicItem);
|
||||
cellVdec.AddFunc(0xe13ef6fc, cellVdecSetFrameRate);
|
||||
|
||||
avcodec_register_all();
|
||||
}
|
@ -1,5 +1,8 @@
|
||||
#pragma once
|
||||
#include "cellPamf.h"
|
||||
|
||||
#include "Utilities/SQueue.h"
|
||||
|
||||
#define a128(x) ((x + 127) & (~127))
|
||||
|
||||
// Error Codes
|
||||
enum
|
||||
@ -30,7 +33,7 @@ enum CellVdecMsgType
|
||||
};
|
||||
|
||||
// Decoder Operation Mode
|
||||
enum CellVdecDecodeMode
|
||||
enum CellVdecDecodeMode : u32
|
||||
{
|
||||
CELL_VDEC_DEC_MODE_NORMAL,
|
||||
CELL_VDEC_DEC_MODE_B_SKIP,
|
||||
@ -164,11 +167,13 @@ struct CellVdecPicFormat
|
||||
u8 alpha;
|
||||
};
|
||||
|
||||
typedef mem_func_ptr_t<void (*)(u32 handle_addr, CellVdecMsgType msgType, int msgData, u32 cbArg_addr)> CellVdecCbMsg;
|
||||
|
||||
// Callback Function Information
|
||||
struct CellVdecCb
|
||||
{
|
||||
be_t<mem_func_ptr_t<void (*)(u32 handle_addr, CellVdecMsgType msgType, int msgData, u32 cbArg_addr)>> cbFunc;
|
||||
be_t<u32> cbArg_addr;
|
||||
be_t<u32> cbFunc;
|
||||
be_t<u32> cbArg;
|
||||
};
|
||||
|
||||
// Max CC Data Length
|
||||
@ -338,16 +343,18 @@ struct CellVdecAvcInfo
|
||||
AVC_transfer_characteristics transfer_characteristics;
|
||||
AVC_matrix_coefficients matrix_coefficients;
|
||||
bool timing_info_present_flag;
|
||||
CellVdecFrameRate frameRateCode;
|
||||
AVC_FrameRateCode frameRateCode; // ???
|
||||
bool fixed_frame_rate_flag;
|
||||
bool low_delay_hrd_flag;
|
||||
bool entropy_coding_mode_flag;
|
||||
be_t<AVC_NulUnitPresentFlags> nalUnitPresentFlags;
|
||||
be_t<u16> nalUnitPresentFlags;
|
||||
u8 ccDataLength[2];
|
||||
u8 ccData[2][CELL_VDEC_AVC_CCD_MAX];
|
||||
be_t<u64> reserved[2];
|
||||
};
|
||||
|
||||
const int sz = sizeof(CellVdecAvcInfo);
|
||||
|
||||
// DIVX Profile
|
||||
enum DIVX_level : u8
|
||||
{
|
||||
@ -635,3 +642,152 @@ struct CellVdecMpeg2Info
|
||||
u8 ccData[2][128];
|
||||
be_t<u64> reserved[2];
|
||||
};
|
||||
|
||||
/* Video Decoder Thread Classes */
|
||||
|
||||
enum VdecJobType : u32
|
||||
{
|
||||
vdecStartSeq,
|
||||
vdecEndSeq,
|
||||
vdecDecodeAu,
|
||||
vdecSetFrameRate,
|
||||
vdecClose,
|
||||
};
|
||||
|
||||
struct VdecTask
|
||||
{
|
||||
VdecJobType type;
|
||||
union
|
||||
{
|
||||
u32 frc;
|
||||
CellVdecDecodeMode mode;
|
||||
};
|
||||
u32 addr;
|
||||
u32 size;
|
||||
u64 pts;
|
||||
u64 dts;
|
||||
u64 userData;
|
||||
u64 specData;
|
||||
|
||||
VdecTask(VdecJobType type)
|
||||
: type(type)
|
||||
{
|
||||
}
|
||||
|
||||
VdecTask()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
int vdecRead(void* opaque, u8* buf, int buf_size);
|
||||
|
||||
class VideoDecoder
|
||||
{
|
||||
public:
|
||||
SQueue<VdecTask> job;
|
||||
u32 id;
|
||||
volatile bool is_running;
|
||||
volatile bool is_finished;
|
||||
|
||||
AVCodec* codec;
|
||||
AVCodecContext* ctx;
|
||||
AVFormatContext* fmt;
|
||||
AVFrame* frame;
|
||||
AVDictionary* opts;
|
||||
u8* io_buf;
|
||||
u32 buf_size;
|
||||
u64 pts;
|
||||
u64 dts;
|
||||
u64 pos;
|
||||
u64 userdata;
|
||||
volatile bool has_picture;
|
||||
|
||||
struct VideoReader
|
||||
{
|
||||
u32 addr;
|
||||
u32 size;
|
||||
} reader;
|
||||
|
||||
const CellVdecCodecType type;
|
||||
const u32 profile;
|
||||
const u32 memAddr;
|
||||
const u32 memSize;
|
||||
const u32 cbFunc;
|
||||
const u32 cbArg;
|
||||
|
||||
VideoDecoder(CellVdecCodecType type, u32 profile, u32 addr, u32 size, u32 func, u32 arg)
|
||||
: type(type)
|
||||
, profile(profile)
|
||||
, memAddr(addr)
|
||||
, memSize(size)
|
||||
, cbFunc(func)
|
||||
, cbArg(arg)
|
||||
, is_finished(false)
|
||||
, is_running(false)
|
||||
, has_picture(false)
|
||||
, pos(0)
|
||||
{
|
||||
codec = avcodec_find_decoder(AV_CODEC_ID_H264);
|
||||
if (!codec)
|
||||
{
|
||||
ConLog.Error("VideoDecoder(): avcodec_find_decoder failed");
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
ctx = avcodec_alloc_context3(codec);
|
||||
if (!ctx)
|
||||
{
|
||||
ConLog.Error("VideoDecoder(): avcodec_alloc_context3 failed");
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
opts = nullptr;
|
||||
int err = avcodec_open2(ctx, codec, &opts);
|
||||
if (err) // TODO: not multithread safe
|
||||
{
|
||||
ConLog.Error("VideoDecoder(): avcodec_open2 failed(%d)", err);
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
frame = av_frame_alloc();
|
||||
if (!frame)
|
||||
{
|
||||
ConLog.Error("VideoDecoder(): av_frame_alloc failed");
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
fmt = avformat_alloc_context();
|
||||
if (!fmt)
|
||||
{
|
||||
ConLog.Error("VideoDecoder(): avformat_alloc_context failed");
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
io_buf = (u8*)av_malloc(4096);
|
||||
fmt->pb = avio_alloc_context(io_buf, 4096, 0, this, vdecRead, NULL, NULL);
|
||||
if (!fmt->pb)
|
||||
{
|
||||
ConLog.Error("VideoDecoder(): avio_alloc_context failed");
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
//memset(&out_data, 0, sizeof(out_data));
|
||||
//memset(&linesize, 0, sizeof(linesize));
|
||||
}
|
||||
|
||||
~VideoDecoder()
|
||||
{
|
||||
if (io_buf) av_free(io_buf);
|
||||
if (fmt)
|
||||
{
|
||||
avformat_free_context(fmt);
|
||||
}
|
||||
if (frame) av_frame_free(&frame);
|
||||
if (ctx)
|
||||
{
|
||||
avcodec_close(ctx);
|
||||
av_free(ctx);
|
||||
}
|
||||
//if (out_data[0]) av_freep(out_data[0]);
|
||||
}
|
||||
};
|
@ -8,35 +8,186 @@ Module cellVpost(0x0008, cellVpost_init);
|
||||
|
||||
int cellVpostQueryAttr(const mem_ptr_t<CellVpostCfgParam> cfgParam, mem_ptr_t<CellVpostAttr> attr)
|
||||
{
|
||||
cellVpost.Error("cellVpostQueryAttr(cfgParam_addr=0x%x, attr_addr=0x%x)", cfgParam.GetAddr(), attr.GetAddr());
|
||||
cellVpost.Warning("cellVpostQueryAttr(cfgParam_addr=0x%x, attr_addr=0x%x)", cfgParam.GetAddr(), attr.GetAddr());
|
||||
|
||||
if (!cfgParam.IsGood()) return CELL_VPOST_ERROR_Q_ARG_CFG_NULL;
|
||||
if (!attr.IsGood()) return CELL_VPOST_ERROR_Q_ARG_ATTR_NULL;
|
||||
|
||||
// TODO: check cfgParam and output values
|
||||
|
||||
attr->delay = 0;
|
||||
attr->memSize = 4 * 1024 * 1024;
|
||||
attr->vpostVerLower = 0x280000; // from dmux
|
||||
attr->vpostVerUpper = 0x260000;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
u32 vpostOpen(VpostInstance* data)
|
||||
{
|
||||
u32 id = cellVpost.GetNewId(data);
|
||||
|
||||
ConLog.Write("*** Vpost instance created (to_rgba=%d): id = %d", data->to_rgba, id);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
int cellVpostOpen(const mem_ptr_t<CellVpostCfgParam> cfgParam, const mem_ptr_t<CellVpostResource> resource, mem32_t handle)
|
||||
{
|
||||
cellVpost.Error("cellVpostOpen(cfgParam_addr=0x%x, resource_addr=0x%x, handle_addr=0x%x)",
|
||||
cellVpost.Warning("cellVpostOpen(cfgParam_addr=0x%x, resource_addr=0x%x, handle_addr=0x%x)",
|
||||
cfgParam.GetAddr(), resource.GetAddr(), handle.GetAddr());
|
||||
|
||||
if (!cfgParam.IsGood()) return CELL_VPOST_ERROR_O_ARG_CFG_NULL;
|
||||
if (!resource.IsGood()) return CELL_VPOST_ERROR_O_ARG_RSRC_NULL;
|
||||
if (!handle.IsGood()) return CELL_VPOST_ERROR_O_ARG_HDL_NULL;
|
||||
|
||||
// TODO: check values
|
||||
handle = vpostOpen(new VpostInstance(cfgParam->outPicFmt == CELL_VPOST_PIC_FMT_OUT_RGBA_ILV));
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellVpostOpenEx(const mem_ptr_t<CellVpostCfgParam> cfgParam, const mem_ptr_t<CellVpostResourceEx> resource, mem32_t handle)
|
||||
{
|
||||
cellVpost.Error("cellVpostOpenEx(cfgParam_addr=0x%x, resource_addr=0x%x, handle_addr=0x%x)",
|
||||
cellVpost.Warning("cellVpostOpenEx(cfgParam_addr=0x%x, resource_addr=0x%x, handle_addr=0x%x)",
|
||||
cfgParam.GetAddr(), resource.GetAddr(), handle.GetAddr());
|
||||
|
||||
if (!cfgParam.IsGood()) return CELL_VPOST_ERROR_O_ARG_CFG_NULL;
|
||||
if (!resource.IsGood()) return CELL_VPOST_ERROR_O_ARG_RSRC_NULL;
|
||||
if (!handle.IsGood()) return CELL_VPOST_ERROR_O_ARG_HDL_NULL;
|
||||
|
||||
// TODO: check values
|
||||
handle = vpostOpen(new VpostInstance(cfgParam->outPicFmt == CELL_VPOST_PIC_FMT_OUT_RGBA_ILV));
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellVpostClose(u32 handle)
|
||||
{
|
||||
cellVpost.Error("cellVpostClose(handle=0x%x)", handle);
|
||||
cellVpost.Warning("cellVpostClose(handle=0x%x)", handle);
|
||||
|
||||
VpostInstance* vpost;
|
||||
if (!Emu.GetIdManager().GetIDData(handle, vpost))
|
||||
{
|
||||
return CELL_VPOST_ERROR_C_ARG_HDL_INVALID;
|
||||
}
|
||||
|
||||
Emu.GetIdManager().RemoveID(handle);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellVpostExec(u32 handle, const u32 inPicBuff_addr, const mem_ptr_t<CellVpostCtrlParam> ctrlParam,
|
||||
u32 outPicBuff_addr, mem_ptr_t<CellVpostPictureInfo> picInfo)
|
||||
{
|
||||
cellVpost.Error("cellVpostExec(handle=0x%x, inPicBuff_addr=0x%x, ctrlParam_addr=0x%x, outPicBuff_addr=0x%x, picInfo_addr=0x%x)",
|
||||
cellVpost.Warning("cellVpostExec(handle=0x%x, inPicBuff_addr=0x%x, ctrlParam_addr=0x%x, outPicBuff_addr=0x%x, picInfo_addr=0x%x)",
|
||||
handle, inPicBuff_addr, ctrlParam.GetAddr(), outPicBuff_addr, picInfo.GetAddr());
|
||||
|
||||
VpostInstance* vpost;
|
||||
if (!Emu.GetIdManager().GetIDData(handle, vpost))
|
||||
{
|
||||
return CELL_VPOST_ERROR_E_ARG_HDL_INVALID;
|
||||
}
|
||||
|
||||
if (!ctrlParam.IsGood())
|
||||
{
|
||||
return CELL_VPOST_ERROR_E_ARG_CTRL_INVALID;
|
||||
}
|
||||
|
||||
u32 w = ctrlParam->inWidth;
|
||||
u32 h = ctrlParam->inHeight;
|
||||
|
||||
if (!Memory.IsGoodAddr(inPicBuff_addr, w*h*3/2))
|
||||
{
|
||||
return CELL_VPOST_ERROR_E_ARG_INPICBUF_INVALID;
|
||||
}
|
||||
|
||||
if (!Memory.IsGoodAddr(outPicBuff_addr, w*h*4))
|
||||
{
|
||||
return CELL_VPOST_ERROR_E_ARG_OUTPICBUF_INVALID;
|
||||
}
|
||||
|
||||
if (!picInfo.IsGood())
|
||||
{
|
||||
return CELL_VPOST_ERROR_E_ARG_PICINFO_NULL;
|
||||
}
|
||||
|
||||
ctrlParam->inWindow; // ignored
|
||||
ctrlParam->outWindow; // ignored
|
||||
ctrlParam->execType; // ignored
|
||||
ctrlParam->scalerType; // ignored
|
||||
ctrlParam->ipcType; // ignored
|
||||
|
||||
picInfo->inWidth = ctrlParam->inWidth; // copy
|
||||
picInfo->inHeight = ctrlParam->inHeight; // copy
|
||||
picInfo->inDepth = CELL_VPOST_PIC_DEPTH_8; // fixed
|
||||
picInfo->inScanType = CELL_VPOST_SCAN_TYPE_P; // TODO
|
||||
picInfo->inPicFmt = CELL_VPOST_PIC_FMT_IN_YUV420_PLANAR; // fixed
|
||||
picInfo->inChromaPosType = ctrlParam->inChromaPosType; // copy
|
||||
picInfo->inPicStruct = CELL_VPOST_PIC_STRUCT_PFRM; // TODO
|
||||
picInfo->inQuantRange = ctrlParam->inQuantRange; // copy
|
||||
picInfo->inColorMatrix = ctrlParam->inColorMatrix; // copy
|
||||
|
||||
picInfo->outWidth = picInfo->inWidth; // TODO (resampling)
|
||||
picInfo->outHeight = picInfo->inHeight; // TODO
|
||||
picInfo->outDepth = CELL_VPOST_PIC_DEPTH_8; // fixed
|
||||
picInfo->outScanType = CELL_VPOST_SCAN_TYPE_P; // TODO
|
||||
picInfo->outPicFmt = CELL_VPOST_PIC_FMT_OUT_RGBA_ILV; // TODO
|
||||
picInfo->outChromaPosType = ctrlParam->inChromaPosType; // ???
|
||||
picInfo->outPicStruct = picInfo->inPicStruct; // ???
|
||||
picInfo->outQuantRange = ctrlParam->inQuantRange; // ???
|
||||
picInfo->outColorMatrix = ctrlParam->inColorMatrix; // ???
|
||||
|
||||
picInfo->userData = ctrlParam->userData; // copy
|
||||
picInfo->reserved1 = 0;
|
||||
picInfo->reserved2 = 0;
|
||||
|
||||
u8* pY = (u8*)malloc(w*h);
|
||||
u8* pU = (u8*)malloc(w*h/4);
|
||||
u8* pV = (u8*)malloc(w*h/4);
|
||||
u32* res = (u32*)malloc(w*h*4);
|
||||
const u8 alpha = ctrlParam->outAlpha;
|
||||
|
||||
if (!Memory.CopyToReal(pY, inPicBuff_addr, w*h))
|
||||
{
|
||||
cellVpost.Error("cellVpostExec: data copying failed(pY)");
|
||||
}
|
||||
|
||||
if (!Memory.CopyToReal(pU, inPicBuff_addr + w*h, w*h/4))
|
||||
{
|
||||
cellVpost.Error("cellVpostExec: data copying failed(pU)");
|
||||
}
|
||||
|
||||
if (!Memory.CopyToReal(pV, inPicBuff_addr + w*h + w*h/4, w*h/4))
|
||||
{
|
||||
cellVpost.Error("cellVpostExec: data copying failed(pV)");
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < h; i++) for (u32 j = 0; j < w; j++)
|
||||
{
|
||||
float Cr = pV[(i/2)*(w/2)+j/2];
|
||||
float Cb = pU[(i/2)*(w/2)+j/2];
|
||||
float Y = pY[i*w+j];
|
||||
|
||||
int R = Y + 1.5701f * Cr;
|
||||
if (R < 0) R = 0;
|
||||
if (R > 255) R = 255;
|
||||
int G = Y - 0.1870f * Cb - 0.4664f * Cr;
|
||||
if (G < 0) G = 0;
|
||||
if (G > 255) G = 255;
|
||||
int B = Y - 1.8556f * Cb;
|
||||
if (B < 0) B = 0;
|
||||
if (B > 255) B = 255;
|
||||
res[i*w+j] = ((u32)alpha << 24) | (B << 16) | (G << 8) | (R);
|
||||
}
|
||||
|
||||
if (!Memory.CopyFromReal(outPicBuff_addr, res, w*h*4))
|
||||
{
|
||||
cellVpost.Error("cellVpostExec: data copying failed(result)");
|
||||
Emu.Pause();
|
||||
}
|
||||
|
||||
free(pY);
|
||||
free(pU);
|
||||
free(pV);
|
||||
free(res);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
@ -315,3 +315,14 @@ struct CellVpostPictureInfo
|
||||
be_t<u32> reserved1;
|
||||
be_t<u32> reserved2;
|
||||
};
|
||||
|
||||
class VpostInstance
|
||||
{
|
||||
public:
|
||||
const bool to_rgba;
|
||||
|
||||
VpostInstance(bool rgba)
|
||||
: to_rgba(rgba)
|
||||
{
|
||||
}
|
||||
};
|
@ -124,7 +124,7 @@ int sys_raw_spu_image_load(int id, mem_ptr_t<sys_spu_image> img)
|
||||
{
|
||||
sysPrxForUser.Warning("sys_raw_spu_image_load(id=0x%x, img_addr=0x%x)", id, img.GetAddr());
|
||||
|
||||
memcpy(Memory + RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id, Memory + (u32)img->segs_addr, 256 * 1024);
|
||||
Memory.Copy(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id, (u32)img->segs_addr, 256 * 1024);
|
||||
Memory.Write32(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id + RAW_SPU_PROB_OFFSET + SPU_NPC_offs,
|
||||
(u32)img->entry_point);
|
||||
|
||||
|
@ -150,46 +150,67 @@ void fsAioRead(u32 fd, mem_ptr_t<CellFsAio> aio, int xid, mem_func_ptr_t<void (*
|
||||
|
||||
const wxString path = orig_file->GetPath().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))
|
||||
{
|
||||
/*
|
||||
//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;
|
||||
}
|
||||
else
|
||||
|
||||
u32 count = nbytes;
|
||||
if (nbytes != (u64)count)
|
||||
{
|
||||
res = 0;
|
||||
error = CELL_EFAULT;
|
||||
error = CELL_ENOMEM;
|
||||
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 (!Memory.IsGoodAddr(buf_addr))
|
||||
{
|
||||
error = CELL_EFAULT;
|
||||
goto fin;
|
||||
}
|
||||
|
||||
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<CellFsAio> aio, int xid, mem_func_ptr_t<void (*
|
||||
ConLog.Warning("fsAioRead() aborted");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
g_FsAioReadCur++;
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ SysCallBase sys_cond("sys_cond");
|
||||
|
||||
int sys_cond_create(mem32_t cond_id, u32 mutex_id, mem_ptr_t<sys_cond_attribute> 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())
|
||||
@ -28,7 +28,7 @@ int sys_cond_create(mem32_t cond_id, u32 mutex_id, mem_ptr_t<sys_cond_attribute>
|
||||
|
||||
if (mutex->is_recursive)
|
||||
{
|
||||
sys_cond.Warning("Recursive mutex(%d)", mutex_id);
|
||||
sys_cond.Warning("*** condition on recursive mutex(%d)", mutex_id);
|
||||
}
|
||||
|
||||
Cond* cond = new Cond(mutex, attr->name_u64);
|
||||
@ -60,6 +60,136 @@ int sys_cond_destroy(u32 cond_id)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int sys_cond_signal(u32 cond_id)
|
||||
{
|
||||
sys_cond.Log("sys_cond_signal(cond_id=%d)", cond_id);
|
||||
|
||||
Cond* cond;
|
||||
if (!Emu.GetIdManager().GetIDData(cond_id, cond))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
Mutex* mutex = cond->mutex;
|
||||
u32 tid = GetCurrentPPUThread().GetId();
|
||||
|
||||
bool was_locked = (mutex->m_mutex.GetOwner() == tid);
|
||||
|
||||
if (u32 target = (mutex->protocol == SYS_SYNC_PRIORITY ? cond->m_queue.pop_prio() : cond->m_queue.pop()))
|
||||
{
|
||||
if (!was_locked) // mutex hasn't been locked (don't care about mutex state)
|
||||
{
|
||||
mutex->m_mutex.lock(tid);
|
||||
mutex->recursive = 1;
|
||||
mutex->m_mutex.unlock(tid, target);
|
||||
}
|
||||
else // mutex has been locked (should preserve original mutex state)
|
||||
{
|
||||
mutex->recursive = 1;
|
||||
mutex->m_mutex.unlock(tid, target);
|
||||
mutex->m_mutex.lock(tid);
|
||||
mutex->recursive = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
ConLog.Warning("sys_cond_signal(id=%d) aborted", cond_id);
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int sys_cond_signal_all(u32 cond_id)
|
||||
{
|
||||
sys_cond.Log("sys_cond_signal_all(cond_id=%d)", cond_id);
|
||||
|
||||
Cond* cond;
|
||||
if (!Emu.GetIdManager().GetIDData(cond_id, cond))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
Mutex* mutex = cond->mutex;
|
||||
u32 tid = GetCurrentPPUThread().GetId();
|
||||
|
||||
bool was_locked = (mutex->m_mutex.GetOwner() == tid);
|
||||
|
||||
while (u32 target = (mutex->protocol == SYS_SYNC_PRIORITY ? cond->m_queue.pop_prio() : cond->m_queue.pop()))
|
||||
{
|
||||
if (!was_locked)
|
||||
{
|
||||
mutex->m_mutex.lock(tid);
|
||||
mutex->recursive = 1;
|
||||
mutex->m_mutex.unlock(tid, target);
|
||||
}
|
||||
else
|
||||
{
|
||||
mutex->recursive = 1;
|
||||
mutex->m_mutex.unlock(tid, target);
|
||||
mutex->m_mutex.lock(tid);
|
||||
mutex->recursive = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
ConLog.Warning("sys_cond_signal_all(id=%d) aborted", cond_id);
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int sys_cond_signal_to(u32 cond_id, u32 thread_id)
|
||||
{
|
||||
sys_cond.Log("sys_cond_signal_to(cond_id=%d, thread_id=%d)", cond_id, thread_id);
|
||||
|
||||
Cond* cond;
|
||||
if (!Emu.GetIdManager().GetIDData(cond_id, cond))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (!Emu.GetIdManager().CheckID(thread_id))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (!cond->m_queue.invalidate(thread_id))
|
||||
{
|
||||
return CELL_EPERM;
|
||||
}
|
||||
|
||||
Mutex* mutex = cond->mutex;
|
||||
u32 tid = GetCurrentPPUThread().GetId();
|
||||
|
||||
bool was_locked = (mutex->m_mutex.GetOwner() == tid);
|
||||
|
||||
u32 target = thread_id;
|
||||
{
|
||||
if (!was_locked)
|
||||
{
|
||||
mutex->m_mutex.lock(tid);
|
||||
mutex->recursive = 1;
|
||||
mutex->m_mutex.unlock(tid, target);
|
||||
}
|
||||
else
|
||||
{
|
||||
mutex->recursive = 1;
|
||||
mutex->m_mutex.unlock(tid, target);
|
||||
mutex->m_mutex.lock(tid);
|
||||
mutex->recursive = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
ConLog.Warning("sys_cond_signal_to(id=%d, to=%d) aborted", cond_id, thread_id);
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int sys_cond_wait(u32 cond_id, u64 timeout)
|
||||
{
|
||||
sys_cond.Log("sys_cond_wait(cond_id=%d, timeout=%lld)", cond_id, timeout);
|
||||
@ -114,98 +244,3 @@ int sys_cond_wait(u32 cond_id, u64 timeout)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int sys_cond_signal(u32 cond_id)
|
||||
{
|
||||
sys_cond.Log("sys_cond_signal(cond_id=%d)", cond_id);
|
||||
|
||||
Cond* cond;
|
||||
if (!Emu.GetIdManager().GetIDData(cond_id, cond))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
Mutex* mutex = cond->mutex;
|
||||
u32 tid = GetCurrentPPUThread().GetId();
|
||||
|
||||
if (u32 target = (mutex->protocol == SYS_SYNC_PRIORITY ? mutex->m_queue.pop_prio() : mutex->m_queue.pop()))
|
||||
{
|
||||
if (mutex->m_mutex.trylock(target) != SMR_OK)
|
||||
{
|
||||
mutex->m_mutex.lock(tid);
|
||||
mutex->recursive = 1;
|
||||
mutex->m_mutex.unlock(tid, target);
|
||||
}
|
||||
}
|
||||
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
ConLog.Warning("sys_cond_signal(id=%d) aborted", cond_id);
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int sys_cond_signal_all(u32 cond_id)
|
||||
{
|
||||
sys_cond.Log("sys_cond_signal_all(cond_id=%d)", cond_id);
|
||||
|
||||
Cond* cond;
|
||||
if (!Emu.GetIdManager().GetIDData(cond_id, cond))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
Mutex* mutex = cond->mutex;
|
||||
u32 tid = GetCurrentPPUThread().GetId();
|
||||
|
||||
while (u32 target = (mutex->protocol == SYS_SYNC_PRIORITY ? mutex->m_queue.pop_prio() : mutex->m_queue.pop()))
|
||||
{
|
||||
if (mutex->m_mutex.trylock(target) != SMR_OK)
|
||||
{
|
||||
mutex->m_mutex.lock(tid);
|
||||
mutex->recursive = 1;
|
||||
mutex->m_mutex.unlock(tid, target);
|
||||
}
|
||||
}
|
||||
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
ConLog.Warning("sys_cond_signal_all(id=%d) aborted", cond_id);
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int sys_cond_signal_to(u32 cond_id, u32 thread_id)
|
||||
{
|
||||
sys_cond.Log("sys_cond_signal_to(cond_id=%d, thread_id=%d)", cond_id, thread_id);
|
||||
|
||||
Cond* cond;
|
||||
if (!Emu.GetIdManager().GetIDData(cond_id, cond))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (!cond->m_queue.invalidate(thread_id))
|
||||
{
|
||||
return CELL_EPERM;
|
||||
}
|
||||
|
||||
Mutex* mutex = cond->mutex;
|
||||
u32 tid = GetCurrentPPUThread().GetId();
|
||||
|
||||
if (mutex->m_mutex.trylock(thread_id) != SMR_OK)
|
||||
{
|
||||
mutex->m_mutex.lock(tid);
|
||||
mutex->recursive = 1;
|
||||
mutex->m_mutex.unlock(tid, thread_id);
|
||||
}
|
||||
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
ConLog.Warning("sys_cond_signal_to(id=%d, to=%d) aborted", cond_id, thread_id);
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ int cellGcmCallback(u32 context_addr, u32 count)
|
||||
|
||||
const s32 res = ctx.current - ctx.begin - ctrl.put;
|
||||
|
||||
if(res > 0) memcpy(&Memory[ctx.begin], &Memory[ctx.current - res], res);
|
||||
if(res > 0) Memory.Copy(ctx.begin, ctx.current - res, res);
|
||||
|
||||
ctx.current = ctx.begin + res;
|
||||
|
||||
|
@ -84,13 +84,22 @@ int sys_lwcond_signal(mem_ptr_t<sys_lwcond_t> lwcond)
|
||||
mem_ptr_t<sys_lwmutex_t> mutex(lwcond->lwmutex);
|
||||
be_t<u32> tid = GetCurrentPPUThread().GetId();
|
||||
|
||||
bool was_locked = (mutex->mutex.GetOwner() == tid);
|
||||
|
||||
if (be_t<u32> target = (mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? sq->pop_prio() : sq->pop()))
|
||||
{
|
||||
if (mutex->mutex.owner.trylock(target) != SMR_OK)
|
||||
if (!was_locked)
|
||||
{
|
||||
mutex->mutex.owner.lock(tid);
|
||||
mutex->mutex.lock(tid);
|
||||
mutex->recursive_count = 1;
|
||||
mutex->mutex.unlock(tid, target);
|
||||
}
|
||||
else
|
||||
{
|
||||
mutex->recursive_count = 1;
|
||||
mutex->mutex.unlock(tid, target);
|
||||
mutex->mutex.lock(tid);
|
||||
mutex->recursive_count = 1;
|
||||
mutex->mutex.owner.unlock(tid, target);
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,13 +129,22 @@ int sys_lwcond_signal_all(mem_ptr_t<sys_lwcond_t> lwcond)
|
||||
mem_ptr_t<sys_lwmutex_t> mutex(lwcond->lwmutex);
|
||||
be_t<u32> tid = GetCurrentPPUThread().GetId();
|
||||
|
||||
bool was_locked = (mutex->mutex.GetOwner() == tid);
|
||||
|
||||
while (be_t<u32> target = (mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? sq->pop_prio() : sq->pop()))
|
||||
{
|
||||
if (mutex->mutex.owner.trylock(target) != SMR_OK)
|
||||
if (!was_locked)
|
||||
{
|
||||
mutex->mutex.owner.lock(tid);
|
||||
mutex->mutex.lock(tid);
|
||||
mutex->recursive_count = 1;
|
||||
mutex->mutex.unlock(tid, target);
|
||||
}
|
||||
else
|
||||
{
|
||||
mutex->recursive_count = 1;
|
||||
mutex->mutex.unlock(tid, target);
|
||||
mutex->mutex.lock(tid);
|
||||
mutex->recursive_count = 1;
|
||||
mutex->mutex.owner.unlock(tid, target);
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,6 +171,11 @@ int sys_lwcond_signal_to(mem_ptr_t<sys_lwcond_t> lwcond, u32 ppu_thread_id)
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (!Emu.GetIdManager().CheckID(ppu_thread_id))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (!sq->invalidate(ppu_thread_id))
|
||||
{
|
||||
return CELL_EPERM;
|
||||
@ -161,13 +184,23 @@ int sys_lwcond_signal_to(mem_ptr_t<sys_lwcond_t> lwcond, u32 ppu_thread_id)
|
||||
mem_ptr_t<sys_lwmutex_t> mutex(lwcond->lwmutex);
|
||||
be_t<u32> tid = GetCurrentPPUThread().GetId();
|
||||
|
||||
be_t<u32> target = ppu_thread_id;
|
||||
bool was_locked = (mutex->mutex.GetOwner() == tid);
|
||||
|
||||
if (mutex->mutex.owner.trylock(target) != SMR_OK)
|
||||
be_t<u32> target = ppu_thread_id;
|
||||
{
|
||||
mutex->mutex.owner.lock(tid);
|
||||
if (!was_locked)
|
||||
{
|
||||
mutex->mutex.lock(tid);
|
||||
mutex->recursive_count = 1;
|
||||
mutex->mutex.owner.unlock(tid, target);
|
||||
mutex->mutex.unlock(tid, target);
|
||||
}
|
||||
else
|
||||
{
|
||||
mutex->recursive_count = 1;
|
||||
mutex->mutex.unlock(tid, target);
|
||||
mutex->mutex.lock(tid);
|
||||
mutex->recursive_count = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (Emu.IsStopped())
|
||||
@ -197,7 +230,7 @@ int sys_lwcond_wait(mem_ptr_t<sys_lwcond_t> lwcond, u64 timeout)
|
||||
u32 tid_le = GetCurrentPPUThread().GetId();
|
||||
be_t<u32> tid = tid_le;
|
||||
|
||||
if (mutex->mutex.owner.GetOwner() != tid)
|
||||
if (mutex->mutex.GetOwner() != tid)
|
||||
{
|
||||
return CELL_EPERM; // caller must own this lwmutex
|
||||
}
|
||||
@ -205,7 +238,7 @@ int sys_lwcond_wait(mem_ptr_t<sys_lwcond_t> lwcond, u64 timeout)
|
||||
sq->push(tid_le);
|
||||
|
||||
mutex->recursive_count = 0;
|
||||
mutex->mutex.owner.unlock(tid);
|
||||
mutex->mutex.unlock(tid);
|
||||
|
||||
u32 counter = 0;
|
||||
const u32 max_counter = timeout ? (timeout / 1000) : ~0;
|
||||
@ -216,7 +249,7 @@ int sys_lwcond_wait(mem_ptr_t<sys_lwcond_t> lwcond, u64 timeout)
|
||||
case SMR_OK: mutex->unlock(tid); break;
|
||||
case SMR_SIGNAL: return CELL_OK;
|
||||
} */
|
||||
if (mutex->mutex.owner.GetOwner() == tid)
|
||||
if (mutex->mutex.GetOwner() == tid)
|
||||
{
|
||||
_mm_mfence();
|
||||
mutex->recursive_count = 1;
|
||||
|
@ -28,9 +28,8 @@ int sys_lwmutex_create(mem_ptr_t<sys_lwmutex_t> lwmutex, mem_ptr_t<sys_lwmutex_a
|
||||
}
|
||||
|
||||
lwmutex->attribute = attr->attr_protocol | attr->attr_recursive;
|
||||
lwmutex->mutex.all_info() = 0;
|
||||
lwmutex->mutex.all_info() = 0;
|
||||
lwmutex->mutex.owner.initialize();
|
||||
lwmutex->all_info() = ~0;
|
||||
lwmutex->mutex.initialize();
|
||||
//lwmutex->waiter = lwmutex->owner.GetOwner();
|
||||
lwmutex->pad = 0;
|
||||
lwmutex->recursive_count = 0;
|
||||
@ -54,10 +53,10 @@ int sys_lwmutex_destroy(mem_ptr_t<sys_lwmutex_t> lwmutex)
|
||||
if (!Emu.GetIdManager().CheckID(sq_id)) return CELL_ESRCH;
|
||||
|
||||
// try to make it unable to lock
|
||||
switch (int res = lwmutex->trylock(lwmutex->mutex.owner.GetDeadValue()))
|
||||
switch (int res = lwmutex->trylock(lwmutex->mutex.GetDeadValue()))
|
||||
{
|
||||
case CELL_OK:
|
||||
lwmutex->mutex.all_info() = 0;
|
||||
lwmutex->all_info() = 0;
|
||||
lwmutex->attribute = 0;
|
||||
lwmutex->sleep_queue = 0;
|
||||
Emu.GetIdManager().RemoveID(sq_id);
|
||||
@ -208,7 +207,7 @@ int sys_lwmutex_t::trylock(be_t<u32> tid)
|
||||
{
|
||||
if (!attribute.ToBE()) return CELL_EINVAL;
|
||||
|
||||
if (tid == mutex.owner.GetOwner())
|
||||
if (tid == mutex.GetOwner())
|
||||
{
|
||||
if (attribute.ToBE() & se32(SYS_SYNC_RECURSIVE))
|
||||
{
|
||||
@ -222,7 +221,7 @@ int sys_lwmutex_t::trylock(be_t<u32> tid)
|
||||
}
|
||||
}
|
||||
|
||||
switch (mutex.owner.trylock(tid))
|
||||
switch (mutex.trylock(tid))
|
||||
{
|
||||
case SMR_OK: recursive_count = 1; return CELL_OK;
|
||||
case SMR_FAILED: return CELL_EBUSY;
|
||||
@ -232,7 +231,7 @@ int sys_lwmutex_t::trylock(be_t<u32> tid)
|
||||
|
||||
int sys_lwmutex_t::unlock(be_t<u32> tid)
|
||||
{
|
||||
if (tid != mutex.owner.GetOwner())
|
||||
if (tid != mutex.GetOwner())
|
||||
{
|
||||
return CELL_EPERM;
|
||||
}
|
||||
@ -251,8 +250,8 @@ int sys_lwmutex_t::unlock(be_t<u32> tid)
|
||||
target = attribute.ToBE() & se32(SYS_SYNC_FIFO) ? sq->pop() : sq->pop_prio();
|
||||
case se32(SYS_SYNC_RETRY): break;
|
||||
}
|
||||
if (target) mutex.owner.unlock(tid, target);
|
||||
else mutex.owner.unlock(tid);
|
||||
if (target) mutex.unlock(tid, target);
|
||||
else mutex.unlock(tid);
|
||||
}
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -277,7 +276,7 @@ int sys_lwmutex_t::lock(be_t<u32> tid, u64 timeout)
|
||||
default: break;
|
||||
}
|
||||
|
||||
switch (mutex.owner.lock(tid, timeout))
|
||||
switch (mutex.lock(tid, timeout))
|
||||
{
|
||||
case SMR_OK:
|
||||
sq->invalidate(tid);
|
||||
|
@ -65,13 +65,9 @@ struct SleepQueue
|
||||
|
||||
struct sys_lwmutex_t
|
||||
{
|
||||
struct sys_lwmutex_lock_info_t
|
||||
{
|
||||
/* volatile */ SMutexBase<be_t<u32>, 0xffffffff, 0> owner;
|
||||
/* volatile */ SMutexBase<be_t<u32>, ~0, 0> mutex;
|
||||
/* volatile */ be_t<u32> waiter; // not used
|
||||
u64 &all_info(){return *(reinterpret_cast<u64*>(this));
|
||||
}
|
||||
}mutex;
|
||||
u64 &all_info(){return *(reinterpret_cast<u64*>(this));}
|
||||
be_t<u32> attribute;
|
||||
be_t<u32> recursive_count;
|
||||
be_t<u32> sleep_queue;
|
||||
|
@ -134,7 +134,7 @@ int sys_spu_thread_initialize(mem32_t thread, u32 group, u32 spu_num, mem_ptr_t<
|
||||
CPUThread& new_thread = Emu.GetCPU().AddThread(CPU_THREAD_SPU);
|
||||
//copy SPU image:
|
||||
u32 spu_offset = Memory.MainMem.AllocAlign(256 * 1024);
|
||||
memcpy(Memory + spu_offset, Memory + (u32)img->segs_addr, 256 * 1024);
|
||||
Memory.CopyToReal(Memory + spu_offset, (u32)img->segs_addr, 256 * 1024);
|
||||
//initialize from new place:
|
||||
new_thread.SetOffset(spu_offset);
|
||||
new_thread.SetEntry(spu_ep);
|
||||
|
@ -136,11 +136,22 @@ void LogWriter::WriteToLog(std::string prefix, std::string value, std::string co
|
||||
if(wxThread::IsMain())
|
||||
#endif
|
||||
{
|
||||
while(LogBuffer.IsBusy()) wxYieldIfNeeded();
|
||||
while(LogBuffer.IsBusy())
|
||||
{
|
||||
// need extra break condition?
|
||||
wxYieldIfNeeded();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while(LogBuffer.IsBusy()) Sleep(1);
|
||||
while (LogBuffer.IsBusy())
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
break;
|
||||
}
|
||||
Sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
//if(LogBuffer.put == LogBuffer.get) LogBuffer.Flush();
|
||||
|
@ -29,10 +29,10 @@ MemoryViewerPanel::MemoryViewerPanel(wxWindow* parent)
|
||||
s_tools_mem_bytes.Add(sc_bytes);
|
||||
|
||||
wxStaticBoxSizer& s_tools_mem_buttons = *new wxStaticBoxSizer(wxHORIZONTAL, this, "Control");
|
||||
wxButton* b_fprev = new wxButton(this, wxID_ANY, "\u00AB", wxDefaultPosition, wxSize(21, 21));
|
||||
wxButton* b_fprev = new wxButton(this, wxID_ANY, "<<", wxDefaultPosition, wxSize(21, 21));
|
||||
wxButton* b_prev = new wxButton(this, wxID_ANY, "<", wxDefaultPosition, wxSize(21, 21));
|
||||
wxButton* b_next = new wxButton(this, wxID_ANY, ">", wxDefaultPosition, wxSize(21, 21));
|
||||
wxButton* b_fnext = new wxButton(this, wxID_ANY, "\u00BB", wxDefaultPosition, wxSize(21, 21));
|
||||
wxButton* b_fnext = new wxButton(this, wxID_ANY, ">>", wxDefaultPosition, wxSize(21, 21));
|
||||
s_tools_mem_buttons.Add(b_fprev);
|
||||
s_tools_mem_buttons.Add(b_prev);
|
||||
s_tools_mem_buttons.Add(b_next);
|
||||
|
@ -69,20 +69,20 @@
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<IncludePath>.\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;..\..\ffmpeg;$(IncludePath)</IncludePath>
|
||||
<IncludePath>.\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86\Include;$(IncludePath)</IncludePath>
|
||||
<OutDir>$(SolutionDir)bin\</OutDir>
|
||||
<LibraryPath>..\libs\$(Configuration)\;$(LibraryPath)</LibraryPath>
|
||||
<TargetName>$(ProjectName)-$(PlatformShortName)-dbg</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<IncludePath>.\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;..\..\ffmpeg;$(IncludePath)</IncludePath>
|
||||
<IncludePath>.\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;$(IncludePath)</IncludePath>
|
||||
<OutDir>$(SolutionDir)bin\</OutDir>
|
||||
<LibraryPath>..\libs\$(Configuration)\;$(LibraryPath)</LibraryPath>
|
||||
<TargetName>$(ProjectName)-$(PlatformShortName)-dbg</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>.\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;..\..\ffmpeg;$(IncludePath)</IncludePath>
|
||||
<IncludePath>.\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86\Include;$(IncludePath)</IncludePath>
|
||||
<OutDir>$(SolutionDir)bin\</OutDir>
|
||||
<LibraryPath>..\libs\$(Configuration)\;$(LibraryPath)</LibraryPath>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
@ -91,7 +91,7 @@
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>.\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;..\..\ffmpeg;$(IncludePath)</IncludePath>
|
||||
<IncludePath>.\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;$(IncludePath)</IncludePath>
|
||||
<OutDir>$(SolutionDir)bin\</OutDir>
|
||||
<LibraryPath>..\libs\$(Configuration)\;$(LibraryPath)</LibraryPath>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
@ -109,10 +109,10 @@
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>wxmsw31ud_adv.lib;wxbase31ud.lib;wxmsw31ud_core.lib;wxmsw31ud_aui.lib;wxtiffd.lib;wxjpegd.lib;wxpngd.lib;wxzlibd.lib;odbc32.lib;odbccp32.lib;comctl32.lib;ws2_32.lib;shlwapi.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>wxmsw31ud_adv.lib;wxbase31ud.lib;wxmsw31ud_core.lib;wxmsw31ud_aui.lib;wxtiffd.lib;wxjpegd.lib;wxpngd.lib;wxzlibd.lib;odbc32.lib;odbccp32.lib;comctl32.lib;ws2_32.lib;shlwapi.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;rpcrt4.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||
<DataExecutionPrevention>false</DataExecutionPrevention>
|
||||
<AdditionalLibraryDirectories>..\wxWidgets\lib\vc_lib</AdditionalLibraryDirectories>
|
||||
<AdditionalLibraryDirectories>..\wxWidgets\lib\vc_lib;..\ffmpeg\Windows\x86\lib</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<PreBuildEvent>
|
||||
<Command>
|
||||
@ -129,14 +129,17 @@
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>wxmsw31ud_adv.lib;wxbase31ud.lib;wxmsw31ud_core.lib;wxmsw31ud_aui.lib;wxtiffd.lib;wxjpegd.lib;wxpngd.lib;wxzlibd.lib;odbc32.lib;odbccp32.lib;comctl32.lib;ws2_32.lib;shlwapi.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>wxmsw31ud_adv.lib;wxbase31ud.lib;wxmsw31ud_core.lib;wxmsw31ud_aui.lib;wxtiffd.lib;wxjpegd.lib;wxpngd.lib;wxzlibd.lib;odbc32.lib;odbccp32.lib;comctl32.lib;ws2_32.lib;shlwapi.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;rpcrt4.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||
<DataExecutionPrevention>false</DataExecutionPrevention>
|
||||
<AdditionalLibraryDirectories>..\wxWidgets\lib\vc_x64_lib</AdditionalLibraryDirectories>
|
||||
<AdditionalLibraryDirectories>..\wxWidgets\lib\vc_x64_lib;..\ffmpeg\Windows\x86_64\lib</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<PreBuildEvent>
|
||||
<Command>"$(SolutionDir)\Utilities\git-version-gen.cmd"</Command>
|
||||
</PreBuildEvent>
|
||||
<ProjectReference>
|
||||
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
|
||||
</ProjectReference>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
@ -158,12 +161,12 @@
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>wxmsw31u_adv.lib;wxbase31u.lib;wxmsw31u_core.lib;wxmsw31u_aui.lib;odbc32.lib;odbccp32.lib;comctl32.lib;ws2_32.lib;shlwapi.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;rpcrt4.lib;wxtiff.lib;wxjpeg.lib;wxpng.lib;wxzlib.lib;wxregexu.lib;wxexpat.lib;wsock32.lib;wininet.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>wxmsw31u_adv.lib;wxbase31u.lib;wxmsw31u_core.lib;wxmsw31u_aui.lib;odbc32.lib;odbccp32.lib;comctl32.lib;ws2_32.lib;shlwapi.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;rpcrt4.lib;wxtiff.lib;wxjpeg.lib;wxpng.lib;wxzlib.lib;wxregexu.lib;wxexpat.lib;wsock32.lib;wininet.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<IgnoreAllDefaultLibraries>
|
||||
</IgnoreAllDefaultLibraries>
|
||||
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||
<DataExecutionPrevention>false</DataExecutionPrevention>
|
||||
<AdditionalLibraryDirectories>..\wxWidgets\lib\vc_lib</AdditionalLibraryDirectories>
|
||||
<AdditionalLibraryDirectories>..\wxWidgets\lib\vc_lib;..\ffmpeg\Windows\x86\lib</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<PreBuildEvent>
|
||||
<Command>
|
||||
@ -190,12 +193,12 @@
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>wxmsw31u_adv.lib;wxbase31u.lib;wxmsw31u_core.lib;wxmsw31u_aui.lib;odbc32.lib;odbccp32.lib;comctl32.lib;ws2_32.lib;shlwapi.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;rpcrt4.lib;wxtiff.lib;wxjpeg.lib;wxpng.lib;wxzlib.lib;wxregexu.lib;wxexpat.lib;wsock32.lib;wininet.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>wxmsw31u_adv.lib;wxbase31u.lib;wxmsw31u_core.lib;wxmsw31u_aui.lib;odbc32.lib;odbccp32.lib;comctl32.lib;ws2_32.lib;shlwapi.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;rpcrt4.lib;wxtiff.lib;wxjpeg.lib;wxpng.lib;wxzlib.lib;wxregexu.lib;wxexpat.lib;wsock32.lib;wininet.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<IgnoreAllDefaultLibraries>
|
||||
</IgnoreAllDefaultLibraries>
|
||||
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||
<DataExecutionPrevention>false</DataExecutionPrevention>
|
||||
<AdditionalLibraryDirectories>..\wxWidgets\lib\vc_x64_lib</AdditionalLibraryDirectories>
|
||||
<AdditionalLibraryDirectories>..\wxWidgets\lib\vc_x64_lib;..\ffmpeg\Windows\x86_64\lib</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<PreBuildEvent>
|
||||
<Command>
|
||||
@ -343,10 +346,12 @@
|
||||
<ClInclude Include="..\Utilities\IdManager.h" />
|
||||
<ClInclude Include="..\Utilities\MTProgressDialog.h" />
|
||||
<ClInclude Include="..\Utilities\SMutex.h" />
|
||||
<ClInclude Include="..\Utilities\SQueue.h" />
|
||||
<ClInclude Include="..\Utilities\Thread.h" />
|
||||
<ClInclude Include="..\Utilities\Timer.h" />
|
||||
<ClInclude Include="Emu\Audio\AudioManager.h" />
|
||||
<ClInclude Include="Emu\Audio\cellAudio.h" />
|
||||
<ClInclude Include="Emu\Cell\MFC.h" />
|
||||
<ClInclude Include="Emu\Cell\PPCDecoder.h" />
|
||||
<ClInclude Include="Emu\Cell\PPCDisAsm.h" />
|
||||
<ClInclude Include="Emu\Cell\PPCInstrTable.h" />
|
||||
|
@ -603,5 +603,11 @@
|
||||
<ClInclude Include="..\Utilities\SMutex.h">
|
||||
<Filter>Utilities</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Utilities\SQueue.h">
|
||||
<Filter>Utilities</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\Cell\MFC.h">
|
||||
<Filter>Include</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
Loading…
x
Reference in New Issue
Block a user