rpcsx/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp

1147 lines
30 KiB
C++
Raw Normal View History

#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/SysCalls/Modules.h"
2014-09-12 23:14:48 +02:00
#include "Emu/SysCalls/Callback.h"
2014-08-23 22:40:04 +02:00
2014-08-26 01:55:37 +02:00
#include "Emu/CPU/CPUThreadManager.h"
2014-01-19 11:52:30 +01:00
#include "cellPamf.h"
#include "cellDmux.h"
Module *cellDmux = nullptr;
2014-08-23 22:40:04 +02:00
PesHeader::PesHeader(DemuxerStream& stream)
: pts(0xffffffffffffffffull)
, dts(0xffffffffffffffffull)
, size(0)
, new_au(false)
{
u16 header;
stream.get(header);
stream.get(size);
if (size)
{
u8 empty = 0;
u8 v;
while (true)
{
stream.get(v);
if (v != 0xFF) break; // skip padding bytes
empty++;
if (empty == size) return;
};
if ((v & 0xF0) == 0x20 && (size - empty) >= 5) // pts only
{
new_au = true;
pts = stream.get_ts(v);
stream.skip(size - empty - 5);
}
else
{
new_au = true;
if ((v & 0xF0) != 0x30 || (size - empty) < 10)
{
cellDmux->Error("PesHeader(): pts not found");
Emu.Pause();
}
pts = stream.get_ts(v);
stream.get(v);
if ((v & 0xF0) != 0x10)
{
cellDmux->Error("PesHeader(): dts not found");
Emu.Pause();
}
dts = stream.get_ts(v);
stream.skip(size - empty - 10);
}
}
}
bool ElementaryStream::is_full()
{
if (released < put_count)
{
2014-10-18 00:20:03 +02:00
u32 first = entries.Peek(&dmux->is_closed);
2014-08-23 22:40:04 +02:00
if (first >= put)
{
return (first - put) < GetMaxAU();
}
else
{
// probably, always false
return (put + GetMaxAU()) > (memAddr + memSize);
}
}
else
{
return false;
}
}
const u32 ElementaryStream::GetMaxAU() const
{
return (fidMajor == 0xbd) ? 4096 : 640 * 1024 + 128; // TODO
}
u32 ElementaryStream::freespace()
{
if (size > GetMaxAU())
{
cellDmux->Error("es::freespace(): last_size too big (size=0x%x, max_au=0x%x)", size, GetMaxAU());
Emu.Pause();
return 0;
}
return GetMaxAU() - size;
}
bool ElementaryStream::hasunseen()
{
std::lock_guard<std::mutex> lock(m_mutex);
return peek_count < put_count;
}
bool ElementaryStream::hasdata()
{
std::lock_guard<std::mutex> lock(m_mutex);
return size != 0;
}
bool ElementaryStream::isfull()
{
std::lock_guard<std::mutex> lock(m_mutex);
return is_full();
}
2014-09-02 03:05:13 +02:00
void ElementaryStream::finish(DemuxerStream& stream) // not multithread-safe (or safe?)
2014-08-23 22:40:04 +02:00
{
u32 addr;
{
std::lock_guard<std::mutex> lock(m_mutex);
//if (fidMajor != 0xbd) LOG_NOTICE(HLE, ">>> es::finish(): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", peek, first, put, size);
addr = put;
2014-09-02 03:05:13 +02:00
auto info = vm::ptr<CellDmuxAuInfo>::make(put);
2014-08-23 22:40:04 +02:00
//if (fidMajor != 0xbd) LOG_WARNING(HLE, "es::finish(): (%s) size = 0x%x, info_addr=0x%x, pts = 0x%x",
//wxString(fidMajor == 0xbd ? "ATRAC3P Audio" : "Video AVC").wx_str(),
//(u32)info->auSize, put, (u32)info->ptsLower);
u32 new_addr = a128(put + 128 + size);
put = ((new_addr + GetMaxAU()) > (memAddr + memSize))
? memAddr : new_addr;
size = 0;
put_count++;
//if (fidMajor != 0xbd) LOG_NOTICE(HLE, "<<< es::finish(): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", peek, first, put, size);
}
2014-10-18 00:20:03 +02:00
if (!entries.Push(addr, &sq_no_wait))
2014-08-23 22:40:04 +02:00
{
cellDmux->Error("es::finish() aborted (no space)");
2014-10-18 00:20:03 +02:00
Emu.Pause();
2014-08-23 22:40:04 +02:00
}
}
void ElementaryStream::push(DemuxerStream& stream, u32 sz, PesHeader& pes)
{
std::lock_guard<std::mutex> lock(m_mutex);
if (is_full())
{
cellDmux->Error("es::push(): buffer is full");
Emu.Pause();
return;
}
u32 data_addr = put + 128 + size;
size += sz;
2014-09-05 22:26:36 +02:00
memcpy(vm::get_ptr<void>(data_addr), vm::get_ptr<void>(stream.addr), sz);
2014-08-23 22:40:04 +02:00
stream.skip(sz);
2014-09-02 03:05:13 +02:00
auto info = vm::ptr<CellDmuxAuInfoEx>::make(put);
2014-08-23 22:40:04 +02:00
info->auAddr = put + 128;
info->auSize = size;
if (pes.new_au)
{
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;
}
2014-09-02 03:05:13 +02:00
auto tail = vm::ptr<CellDmuxPamfAuSpecificInfoAvc>::make(put + sizeof(CellDmuxAuInfoEx));
2014-08-23 22:40:04 +02:00
tail->reserved1 = 0;
2014-09-02 03:05:13 +02:00
auto inf = vm::ptr<CellDmuxAuInfo>::make(put + 64);
2014-08-23 22:40:04 +02:00
inf->auAddr = put + 128;
inf->auSize = size;
if (pes.new_au)
{
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;
}
}
bool ElementaryStream::release()
{
std::lock_guard<std::mutex> lock(m_mutex);
//if (fidMajor != 0xbd) LOG_NOTICE(HLE, ">>> es::release(): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", peek, first, put, size);
if (released >= put_count)
{
cellDmux->Error("es::release(): buffer is empty");
2014-10-18 00:20:03 +02:00
Emu.Pause();
2014-08-23 22:40:04 +02:00
return false;
}
2014-10-18 00:20:03 +02:00
u32 addr = entries.Peek(&dmux->is_closed);
2014-08-23 22:40:04 +02:00
2014-09-02 03:05:13 +02:00
auto info = vm::ptr<CellDmuxAuInfo>::make(addr);
2014-08-23 22:40:04 +02:00
//if (fidMajor != 0xbd) LOG_WARNING(HLE, "es::release(): (%s) size = 0x%x, info = 0x%x, pts = 0x%x",
//wxString(fidMajor == 0xbd ? "ATRAC3P Audio" : "Video AVC").wx_str(), (u32)info->auSize, first, (u32)info->ptsLower);
if (released >= peek_count)
{
cellDmux->Error("es::release(): buffer has not been seen yet");
2014-10-18 00:20:03 +02:00
Emu.Pause();
2014-08-23 22:40:04 +02:00
return false;
}
released++;
2014-10-18 00:20:03 +02:00
if (!entries.Pop(addr, &sq_no_wait))
2014-08-23 22:40:04 +02:00
{
cellDmux->Error("es::release(): entries.Pop() aborted (no entries found)");
2014-10-18 00:20:03 +02:00
Emu.Pause();
2014-08-23 22:40:04 +02:00
return false;
}
//if (fidMajor != 0xbd) LOG_NOTICE(HLE, "<<< es::release(): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", peek, first, put, size);
return true;
}
bool ElementaryStream::peek(u32& out_data, bool no_ex, u32& out_spec, bool update_index)
{
std::lock_guard<std::mutex> lock(m_mutex);
//if (fidMajor != 0xbd) LOG_NOTICE(HLE, ">>> es::peek(%sAu%s): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", wxString(update_index ? "Get" : "Peek").wx_str(),
//wxString(no_ex ? "" : "Ex").wx_str(), peek, first, put, size);
if (peek_count >= put_count) return false;
if (peek_count < released)
{
cellDmux->Error("es::peek(): sequence error: peek_count < released (peek_count=%d, released=%d)", peek_count, released);
Emu.Pause();
return false;
}
2014-10-18 00:20:03 +02:00
u32 addr = entries.Peek(&dmux->is_closed, peek_count - released);
2014-09-02 03:05:13 +02:00
auto info = vm::ptr<CellDmuxAuInfo>::make(addr);
2014-08-23 22:40:04 +02:00
//if (fidMajor != 0xbd) LOG_WARNING(HLE, "es::peek(%sAu(Ex)): (%s) size = 0x%x, info = 0x%x, pts = 0x%x",
//wxString(update_index ? "Get" : "Peek").wx_str(),
//wxString(fidMajor == 0xbd ? "ATRAC3P Audio" : "Video AVC").wx_str(), (u32)info->auSize, peek, (u32)info->ptsLower);
out_data = addr;
out_spec = out_data + sizeof(CellDmuxAuInfoEx);
if (no_ex) out_data += 64;
if (update_index)
{
peek_count++;
}
//if (fidMajor != 0xbd) LOG_NOTICE(HLE, "<<< es::peek(%sAu%s): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", wxString(update_index ? "Get" : "Peek").wx_str(),
//wxString(no_ex ? "" : "Ex").wx_str(), peek, first, put, size);
return true;
}
void ElementaryStream::reset()
{
std::lock_guard<std::mutex> lock(m_mutex);
//first = 0;
//peek = 0;
put = memAddr;
size = 0;
entries.Clear();
put_count = 0;
released = 0;
peek_count = 0;
}
2014-09-02 03:05:13 +02:00
void dmuxQueryAttr(u32 info_addr /* may be 0 */, vm::ptr<CellDmuxAttr> attr)
2014-02-24 01:00:42 +01:00
{
attr->demuxerVerLower = 0x280000; // TODO: check values
attr->demuxerVerUpper = 0x260000;
attr->memSize = 0x10000; // 0x3e8e6 from ps3
2014-02-24 01:00:42 +01:00
}
void dmuxQueryEsAttr(u32 info_addr /* may be 0 */, vm::ptr<const CellCodecEsFilterId> esFilterId,
2014-09-02 03:05:13 +02:00
const u32 esSpecificInfo_addr, vm::ptr<CellDmuxEsAttr> attr)
2014-02-24 01:00:42 +01:00
{
if (esFilterId->filterIdMajor >= 0xe0)
attr->memSize = 0x500000; // 0x45fa49 from ps3
else
attr->memSize = 0x8000; // 0x73d9 from ps3
2014-02-24 01:00:42 +01:00
cellDmux->Warning("*** filter(0x%x, 0x%x, 0x%x, 0x%x)", (u32)esFilterId->filterIdMajor, (u32)esFilterId->filterIdMinor,
(u32)esFilterId->supplementalInfo1, (u32)esFilterId->supplementalInfo2);
}
2014-02-24 01:00:42 +01:00
u32 dmuxOpen(Demuxer* data)
{
Demuxer& dmux = *data;
u32 dmux_id = cellDmux->GetNewId(data);
dmux.id = dmux_id;
2014-02-24 01:00:42 +01:00
2014-09-12 23:14:48 +02:00
dmux.dmuxCb = (PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU);
2014-03-07 22:31:08 +01:00
dmux.dmuxCb->SetName("Demuxer[" + std::to_string(dmux_id) + "] Callback");
2014-09-13 16:25:02 +02:00
dmux.dmuxCb->SetEntry(0);
2014-09-12 23:14:48 +02:00
dmux.dmuxCb->SetPrio(1001);
dmux.dmuxCb->SetStackSize(0x10000);
2014-09-13 16:25:02 +02:00
dmux.dmuxCb->InitStack();
dmux.dmuxCb->InitRegs();
dmux.dmuxCb->DoRun();
2014-03-07 22:31:08 +01:00
thread t("Demuxer[" + std::to_string(dmux_id) + "] Thread", [&]()
2014-02-24 01:00:42 +01:00
{
2014-08-23 22:40:04 +02:00
cellDmux->Notice("Demuxer thread started (mem=0x%x, size=0x%x, cb=0x%x, arg=0x%x)", dmux.memAddr, dmux.memSize, dmux.cbFunc, dmux.cbArg);
2014-02-24 01:00:42 +01:00
DemuxerTask task;
DemuxerStream stream;
ElementaryStream* esALL[192]; memset(esALL, 0, sizeof(esALL));
2014-02-27 19:25:32 +01:00
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;
2014-02-24 01:00:42 +01:00
2014-03-06 12:40:50 +01:00
u32 updates_count = 0;
u32 updates_signaled = 0;
2014-02-24 01:00:42 +01:00
while (true)
{
2014-10-18 00:20:03 +02:00
if (Emu.IsStopped() || dmux.is_closed)
2014-02-24 01:00:42 +01:00
{
break;
}
2014-06-29 05:21:57 +02:00
if (!dmux.job.GetCountUnsafe() && 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))
{
2014-03-06 12:40:50 +01:00
dmux.is_running = false;
// demuxing finished
2014-09-02 03:05:13 +02:00
auto dmuxMsg = vm::ptr<CellDmuxMsg>::make(a128(dmux.memAddr) + (cb_add ^= 16));
2014-03-06 12:40:50 +01:00
dmuxMsg->msgType = CELL_DMUX_MSG_TYPE_DEMUX_DONE;
dmuxMsg->supplementalInfo = stream.userdata;
2014-09-12 23:14:48 +02:00
dmux.cbFunc.call(*dmux.dmuxCb, dmux.id, dmuxMsg, dmux.cbArg);
2014-03-07 22:31:08 +01:00
updates_signaled++;
}
else switch (code.ToLE())
{
case PACK_START_CODE:
2014-10-18 00:20:03 +02:00
{
stream.skip(14);
}
break;
case SYSTEM_HEADER_START_CODE:
2014-10-18 00:20:03 +02:00
{
stream.skip(18);
}
break;
case PADDING_STREAM:
2014-10-18 00:20:03 +02:00
{
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:
{
DemuxerStream backup = stream;
// audio AT3+ (and probably LPCM or user data)
stream.skip(4);
stream.get(len);
PesHeader pes(stream);
if (!pes.new_au) // temporarily
2014-03-01 09:38:50 +01:00
{
2014-10-18 00:20:03 +02:00
cellDmux->Error("No pts info found");
2014-03-01 09:38:50 +01:00
}
2014-10-18 00:20:03 +02:00
// read additional header:
stream.peek(ch); // ???
//stream.skip(4);
//pes.size += 4;
if (esATX[ch])
{
2014-10-18 00:20:03 +02:00
ElementaryStream& es = *esATX[ch];
if (es.isfull())
{
stream = backup;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
continue;
}
/*if (es.hasunseen()) // hack, probably useless
{
stream = backup;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
continue;
}*/
stream.skip(4);
2014-10-18 00:20:03 +02:00
len -= 4;
es.push(stream, len - pes.size - 3, pes);
es.finish(stream);
//LOG_NOTICE(HLE, "*** AT3+ AU sent (len=0x%x, pts=0x%llx)", len - pes.size - 3, pes.pts);
auto esMsg = vm::ptr<CellDmuxEsMsg>::make(a128(dmux.memAddr) + (cb_add ^= 16));
esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND;
esMsg->supplementalInfo = stream.userdata;
es.cbFunc.call(*dmux.dmuxCb, dmux.id, es.id, esMsg, es.cbArg);
}
2014-10-18 00:20:03 +02:00
else
{
stream.skip(len - pes.size - 3);
}
}
break;
2014-10-18 00:20:03 +02:00
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])
{
2014-10-18 00:20:03 +02:00
ElementaryStream& es = *esAVC[ch];
if (es.isfull())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
continue;
}
DemuxerStream backup = stream;
stream.skip(4);
stream.get(len);
PesHeader pes(stream);
2014-10-18 00:20:03 +02:00
if (es.freespace() < (u32)(len + 6))
{
2014-10-18 00:20:03 +02:00
pes.new_au = true;
}
2014-10-18 00:20:03 +02:00
if (pes.new_au && es.hasdata()) // new AU detected
{
2014-06-29 23:08:56 +02:00
/*if (es.hasunseen()) // hack, probably useless
2014-03-07 22:31:08 +01:00
{
stream = backup;
2014-07-12 09:02:39 +02:00
std::this_thread::sleep_for(std::chrono::milliseconds(1));
2014-03-07 22:31:08 +01:00
continue;
2014-06-29 23:08:56 +02:00
}*/
es.finish(stream);
2014-10-18 00:20:03 +02:00
// callback
2014-09-02 03:05:13 +02:00
auto esMsg = vm::ptr<CellDmuxEsMsg>::make(a128(dmux.memAddr) + (cb_add ^= 16));
esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND;
esMsg->supplementalInfo = stream.userdata;
2014-09-12 23:14:48 +02:00
es.cbFunc.call(*dmux.dmuxCb, dmux.id, es.id, esMsg, es.cbArg);
}
2014-10-18 00:20:03 +02:00
if (pes.new_au)
{
2014-10-18 00:20:03 +02:00
//LOG_NOTICE(HLE, "*** AVC AU detected (pts=0x%llx, dts=0x%llx)", pes.pts, pes.dts);
}
2014-10-18 00:20:03 +02:00
if (es.isfull())
{
2014-03-03 00:02:42 +01:00
stream = backup;
2014-10-18 00:20:03 +02:00
std::this_thread::sleep_for(std::chrono::milliseconds(1));
continue;
}
2014-10-18 00:20:03 +02:00
//reconstruction of MPEG2-PS stream for vdec module
stream = backup;
es.push(stream, len + 6 /*- pes.size - 3*/, pes);
}
2014-10-18 00:20:03 +02:00
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:
2014-10-18 00:20:03 +02:00
{
// unknown
cellDmux->Warning("Unknown MPEG stream found");
stream.skip(4);
stream.get(len);
stream.skip(len);
}
break;
case USER_DATA_START_CODE:
2014-10-18 00:20:03 +02:00
{
cellDmux->Error("USER_DATA_START_CODE found");
Emu.Pause();
return;
}
default:
2014-10-18 00:20:03 +02:00
{
// search
stream.skip(1);
}
}
continue;
}
2014-02-24 01:00:42 +01:00
// wait for task with yielding (if no default work)
2014-10-18 00:20:03 +02:00
if (!dmux.job.Pop(task, &dmux.is_closed))
{
break; // Emu is stopped
}
2014-03-06 12:40:50 +01:00
2014-02-24 01:00:42 +01:00
switch (task.type)
{
case dmuxSetStream:
2014-10-18 00:20:03 +02:00
{
if (task.stream.discontinuity)
{
2014-10-18 00:20:03 +02:00
cellDmux->Warning("dmuxSetStream (beginning)");
for (u32 i = 0; i < 192; i++)
{
2014-10-18 00:20:03 +02:00
if (esALL[i])
{
2014-10-18 00:20:03 +02:00
esALL[i]->reset();
}
}
2014-10-18 00:20:03 +02:00
updates_count = 0;
updates_signaled = 0;
}
2014-03-13 10:17:45 +01:00
2014-10-18 00:20:03 +02:00
if (updates_count != updates_signaled)
{
cellDmux->Error("dmuxSetStream: stream update inconsistency (input=%d, signaled=%d)", updates_count, updates_signaled);
Emu.Pause();
return;
}
2014-03-13 10:17:45 +01:00
2014-10-18 00:20:03 +02:00
updates_count++;
stream = task.stream;
//LOG_NOTICE(HLE, "*** stream updated(addr=0x%x, size=0x%x, discont=%d, userdata=0x%llx)",
//stream.addr, stream.size, stream.discontinuity, stream.userdata);
2014-03-13 10:17:45 +01:00
2014-10-18 00:20:03 +02:00
dmux.is_running = true;
dmux.fbSetStream.Push(task.stream.addr, &dmux.is_closed); // feedback
}
break;
2014-02-24 01:00:42 +01:00
case dmuxResetStream:
case dmuxResetStreamAndWaitDone:
2014-10-18 00:20:03 +02:00
{
auto dmuxMsg = vm::ptr<CellDmuxMsg>::make(a128(dmux.memAddr) + (cb_add ^= 16));
dmuxMsg->msgType = CELL_DMUX_MSG_TYPE_DEMUX_DONE;
dmuxMsg->supplementalInfo = stream.userdata;
dmux.cbFunc.call(*dmux.dmuxCb, dmux.id, dmuxMsg, dmux.cbArg);
updates_signaled++;
dmux.is_running = false;
if (task.type == dmuxResetStreamAndWaitDone)
{
2014-10-18 00:20:03 +02:00
dmux.fbSetStream.Push(0, &dmux.is_closed);
}
2014-10-18 00:20:03 +02:00
}
break;
2014-10-18 00:20:03 +02:00
case dmuxEnableEs:
{
ElementaryStream& es = *task.es.es_ptr;
if (es.fidMajor >= 0xe0 &&
es.fidMajor <= 0xef &&
es.fidMinor == 0 &&
es.sup1 == 1 &&
es.sup2 == 0)
{
2014-10-18 00:20:03 +02:00
esAVC[es.fidMajor - 0xe0] = task.es.es_ptr;
}
2014-10-18 00:20:03 +02:00
else if (es.fidMajor == 0xbd &&
es.fidMinor == 0 &&
es.sup1 == 0 &&
es.sup2 == 0)
{
2014-10-18 00:20:03 +02:00
esATX[0] = task.es.es_ptr;
}
2014-10-18 00:20:03 +02:00
else
{
2014-10-18 00:20:03 +02:00
cellDmux->Warning("dmuxEnableEs: (TODO) unsupported filter (0x%x, 0x%x, 0x%x, 0x%x)", es.fidMajor, es.fidMinor, es.sup1, es.sup2);
}
2014-10-18 00:20:03 +02:00
es.dmux = &dmux;
}
break;
2014-10-18 00:20:03 +02:00
case dmuxDisableEs:
{
ElementaryStream& es = *task.es.es_ptr;
if (es.dmux != &dmux)
{
2014-10-18 00:20:03 +02:00
cellDmux->Warning("dmuxDisableEs: invalid elementary stream");
break;
}
2014-10-18 00:20:03 +02:00
for (u32 i = 0; i < 192; i++)
{
2014-10-18 00:20:03 +02:00
if (esALL[i] == &es)
{
2014-10-18 00:20:03 +02:00
esALL[i] = nullptr;
}
2014-10-18 00:20:03 +02:00
}
es.dmux = nullptr;
Emu.GetIdManager().RemoveID(task.es.es);
}
break;
case dmuxFlushEs:
{
ElementaryStream& es = *task.es.es_ptr;
2014-10-18 00:20:03 +02:00
if (es.hasdata())
{
es.finish(stream);
// callback
2014-09-02 03:05:13 +02:00
auto esMsg = vm::ptr<CellDmuxEsMsg>::make(a128(dmux.memAddr) + (cb_add ^= 16));
2014-10-18 00:20:03 +02:00
esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND;
esMsg->supplementalInfo = stream.userdata;
2014-09-12 23:14:48 +02:00
es.cbFunc.call(*dmux.dmuxCb, dmux.id, es.id, esMsg, es.cbArg);
}
2014-10-18 00:20:03 +02:00
// callback
auto esMsg = vm::ptr<CellDmuxEsMsg>::make(a128(dmux.memAddr) + (cb_add ^= 16));
esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_FLUSH_DONE;
esMsg->supplementalInfo = stream.userdata;
es.cbFunc.call(*dmux.dmuxCb, dmux.id, es.id, esMsg, es.cbArg);
}
break;
case dmuxResetEs:
2014-10-18 00:20:03 +02:00
{
task.es.es_ptr->reset();
}
break;
case dmuxClose: break;
2014-02-24 01:00:42 +01:00
default:
2014-10-18 00:20:03 +02:00
{
2014-08-23 22:40:04 +02:00
cellDmux->Error("Demuxer thread error: unknown task(%d)", task.type);
2014-10-18 00:20:03 +02:00
Emu.Pause();
return;
2014-10-18 00:20:03 +02:00
}
2014-02-24 01:00:42 +01:00
}
}
2014-10-18 00:20:03 +02:00
dmux.is_finished = true;
if (Emu.IsStopped()) cellDmux->Warning("Demuxer thread aborted");
if (dmux.is_closed) cellDmux->Notice("Demuxer thread ended");
2014-02-24 01:00:42 +01:00
});
t.detach();
return dmux_id;
}
int cellDmuxQueryAttr(vm::ptr<const CellDmuxType> demuxerType, vm::ptr<CellDmuxAttr> demuxerAttr)
{
2014-09-02 03:05:13 +02:00
cellDmux->Warning("cellDmuxQueryAttr(demuxerType_addr=0x%x, demuxerAttr_addr=0x%x)", demuxerType.addr(), demuxerAttr.addr());
if (demuxerType->streamType != CELL_DMUX_STREAM_TYPE_PAMF)
{
return CELL_DMUX_ERROR_ARG;
}
dmuxQueryAttr(0, demuxerAttr);
return CELL_OK;
}
int cellDmuxQueryAttr2(vm::ptr<const CellDmuxType2> demuxerType2, vm::ptr<CellDmuxAttr> demuxerAttr)
{
2014-09-02 03:05:13 +02:00
cellDmux->Warning("cellDmuxQueryAttr2(demuxerType2_addr=0x%x, demuxerAttr_addr=0x%x)", demuxerType2.addr(), demuxerAttr.addr());
if (demuxerType2->streamType != CELL_DMUX_STREAM_TYPE_PAMF)
{
return CELL_DMUX_ERROR_ARG;
}
dmuxQueryAttr(demuxerType2->streamSpecificInfo_addr, demuxerAttr);
return CELL_OK;
2014-02-24 01:00:42 +01:00
}
int cellDmuxOpen(vm::ptr<const CellDmuxType> demuxerType, vm::ptr<const CellDmuxResource> demuxerResource,
2014-10-11 19:20:01 +02:00
vm::ptr<const CellDmuxCb> demuxerCb, vm::ptr<u32> demuxerHandle)
{
cellDmux->Warning("cellDmuxOpen(demuxerType_addr=0x%x, demuxerResource_addr=0x%x, demuxerCb_addr=0x%x, demuxerHandle_addr=0x%x)",
2014-09-02 03:05:13 +02:00
demuxerType.addr(), demuxerResource.addr(), demuxerCb.addr(), demuxerHandle.addr());
2014-02-24 01:00:42 +01:00
if (demuxerType->streamType != CELL_DMUX_STREAM_TYPE_PAMF)
{
return CELL_DMUX_ERROR_ARG;
}
// TODO: check demuxerResource and demuxerCb arguments
2014-09-12 23:14:48 +02:00
*demuxerHandle = dmuxOpen(new Demuxer(demuxerResource->memAddr, demuxerResource->memSize, vm::ptr<CellDmuxCbMsg>::make(demuxerCb->cbMsgFunc.addr()), demuxerCb->cbArg));
2014-02-24 01:00:42 +01:00
return CELL_OK;
}
int cellDmuxOpenEx(vm::ptr<const CellDmuxType> demuxerType, vm::ptr<const CellDmuxResourceEx> demuxerResourceEx,
2014-10-11 19:20:01 +02:00
vm::ptr<const CellDmuxCb> demuxerCb, vm::ptr<u32> demuxerHandle)
{
cellDmux->Warning("cellDmuxOpenEx(demuxerType_addr=0x%x, demuxerResourceEx_addr=0x%x, demuxerCb_addr=0x%x, demuxerHandle_addr=0x%x)",
2014-09-02 03:05:13 +02:00
demuxerType.addr(), demuxerResourceEx.addr(), demuxerCb.addr(), demuxerHandle.addr());
2014-02-24 01:00:42 +01:00
if (demuxerType->streamType != CELL_DMUX_STREAM_TYPE_PAMF)
{
return CELL_DMUX_ERROR_ARG;
}
// TODO: check demuxerResourceEx and demuxerCb arguments
2014-09-12 23:14:48 +02:00
*demuxerHandle = dmuxOpen(new Demuxer(demuxerResourceEx->memAddr, demuxerResourceEx->memSize, vm::ptr<CellDmuxCbMsg>::make(demuxerCb->cbMsgFunc.addr()), demuxerCb->cbArg));
2014-02-24 01:00:42 +01:00
return CELL_OK;
}
int cellDmuxOpen2(vm::ptr<const CellDmuxType2> demuxerType2, vm::ptr<const CellDmuxResource2> demuxerResource2,
2014-10-11 19:20:01 +02:00
vm::ptr<const CellDmuxCb> demuxerCb, vm::ptr<u32> demuxerHandle)
{
cellDmux->Warning("cellDmuxOpen2(demuxerType2_addr=0x%x, demuxerResource2_addr=0x%x, demuxerCb_addr=0x%x, demuxerHandle_addr=0x%x)",
2014-09-02 03:05:13 +02:00
demuxerType2.addr(), demuxerResource2.addr(), demuxerCb.addr(), demuxerHandle.addr());
2014-02-24 01:00:42 +01:00
if (demuxerType2->streamType != CELL_DMUX_STREAM_TYPE_PAMF)
{
return CELL_DMUX_ERROR_ARG;
}
// TODO: check demuxerType2, demuxerResource2 and demuxerCb arguments
2014-09-12 23:14:48 +02:00
*demuxerHandle = dmuxOpen(new Demuxer(demuxerResource2->memAddr, demuxerResource2->memSize, vm::ptr<CellDmuxCbMsg>::make(demuxerCb->cbMsgFunc.addr()), demuxerCb->cbArg));
2014-02-24 01:00:42 +01:00
return CELL_OK;
}
int cellDmuxClose(u32 demuxerHandle)
{
cellDmux->Warning("cellDmuxClose(demuxerHandle=%d)", demuxerHandle);
2014-02-24 01:00:42 +01:00
Demuxer* dmux;
if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux))
{
return CELL_DMUX_ERROR_ARG;
}
2014-10-18 00:20:03 +02:00
dmux->is_closed = true;
dmux->job.Push(DemuxerTask(dmuxClose), &sq_no_wait);
2014-02-24 01:00:42 +01:00
while (!dmux->is_finished)
{
if (Emu.IsStopped())
{
2014-08-23 22:40:04 +02:00
cellDmux->Warning("cellDmuxClose(%d) aborted", demuxerHandle);
2014-02-24 01:00:42 +01:00
return CELL_OK;
}
2014-07-12 09:02:39 +02:00
std::this_thread::sleep_for(std::chrono::milliseconds(1));
2014-02-24 01:00:42 +01:00
}
if (dmux->dmuxCb) Emu.GetCPU().RemoveThread(dmux->dmuxCb->GetId());
2014-02-24 01:00:42 +01:00
Emu.GetIdManager().RemoveID(demuxerHandle);
return CELL_OK;
}
int cellDmuxSetStream(u32 demuxerHandle, const u32 streamAddress, u32 streamSize, bool discontinuity, u64 userData)
{
cellDmux->Log("cellDmuxSetStream(demuxerHandle=%d, streamAddress=0x%x, streamSize=%d, discontinuity=%d, userData=0x%llx",
demuxerHandle, streamAddress, streamSize, discontinuity, userData);
2014-02-24 01:00:42 +01:00
Demuxer* dmux;
if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux))
{
return CELL_DMUX_ERROR_ARG;
}
2014-03-13 10:17:45 +01:00
if (dmux->is_running)
2014-02-24 01:00:42 +01:00
{
2014-03-06 12:40:50 +01:00
if (Emu.IsStopped())
{
2014-08-23 22:40:04 +02:00
cellDmux->Warning("cellDmuxSetStream(%d) aborted (waiting)", demuxerHandle);
2014-03-13 10:17:45 +01:00
return CELL_OK;
2014-03-06 12:40:50 +01:00
}
2014-07-12 09:02:39 +02:00
std::this_thread::sleep_for(std::chrono::milliseconds(1));
2014-03-07 22:31:08 +01:00
return CELL_DMUX_ERROR_BUSY;
2014-02-24 01:00:42 +01:00
}
DemuxerTask task(dmuxSetStream);
auto& info = task.stream;
info.addr = streamAddress;
info.size = streamSize;
info.discontinuity = discontinuity;
info.userdata = userData;
2014-10-18 00:20:03 +02:00
dmux->job.Push(task, &dmux->is_closed);
2014-03-13 10:17:45 +01:00
u32 addr;
2014-10-18 00:20:03 +02:00
if (!dmux->fbSetStream.Pop(addr, &dmux->is_closed))
{
2014-08-23 22:40:04 +02:00
cellDmux->Warning("cellDmuxSetStream(%d) aborted (fbSetStream.Pop())", demuxerHandle);
2014-03-13 10:17:45 +01:00
return CELL_OK;
}
if (addr != info.addr)
{
2014-08-23 22:40:04 +02:00
cellDmux->Error("cellDmuxSetStream(%d): wrong stream queued (right=0x%x, queued=0x%x)", demuxerHandle, info.addr, addr);
2014-03-13 10:17:45 +01:00
Emu.Pause();
}
return CELL_OK;
}
int cellDmuxResetStream(u32 demuxerHandle)
{
cellDmux->Warning("cellDmuxResetStream(demuxerHandle=%d)", demuxerHandle);
2014-02-24 01:00:42 +01:00
Demuxer* dmux;
if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux))
{
return CELL_DMUX_ERROR_ARG;
}
2014-10-18 00:20:03 +02:00
dmux->job.Push(DemuxerTask(dmuxResetStream), &dmux->is_closed);
2014-02-24 01:00:42 +01:00
return CELL_OK;
}
int cellDmuxResetStreamAndWaitDone(u32 demuxerHandle)
{
cellDmux->Warning("cellDmuxResetStreamAndWaitDone(demuxerHandle=%d)", demuxerHandle);
2014-02-24 01:00:42 +01:00
Demuxer* dmux;
if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux))
{
return CELL_DMUX_ERROR_ARG;
}
2014-10-18 00:20:03 +02:00
dmux->job.Push(DemuxerTask(dmuxResetStreamAndWaitDone), &dmux->is_closed);
2014-02-24 01:00:42 +01:00
2014-04-03 22:46:40 +02:00
u32 addr;
2014-10-18 00:20:03 +02:00
if (!dmux->fbSetStream.Pop(addr, &dmux->is_closed))
{
2014-08-23 22:40:04 +02:00
cellDmux->Warning("cellDmuxResetStreamAndWaitDone(%d) aborted (fbSetStream.Pop())", demuxerHandle);
2014-04-03 22:46:40 +02:00
return CELL_OK;
}
if (addr != 0)
{
2014-08-23 22:40:04 +02:00
cellDmux->Error("cellDmuxResetStreamAndWaitDone(%d): wrong stream queued (0x%x)", demuxerHandle, addr);
2014-04-03 22:46:40 +02:00
Emu.Pause();
}
return CELL_OK;
}
int cellDmuxQueryEsAttr(vm::ptr<const CellDmuxType> demuxerType, vm::ptr<const CellCodecEsFilterId> esFilterId,
2014-09-02 03:05:13 +02:00
const u32 esSpecificInfo_addr, vm::ptr<CellDmuxEsAttr> esAttr)
{
cellDmux->Warning("cellDmuxQueryEsAttr(demuxerType_addr=0x%x, esFilterId_addr=0x%x, esSpecificInfo_addr=0x%x, esAttr_addr=0x%x)",
2014-09-02 03:05:13 +02:00
demuxerType.addr(), esFilterId.addr(), esSpecificInfo_addr, esAttr.addr());
2014-02-24 01:00:42 +01:00
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(vm::ptr<const CellDmuxType2> demuxerType2, vm::ptr<const CellCodecEsFilterId> esFilterId,
2014-09-02 03:05:13 +02:00
const u32 esSpecificInfo_addr, vm::ptr<CellDmuxEsAttr> esAttr)
{
cellDmux->Warning("cellDmuxQueryEsAttr2(demuxerType2_addr=0x%x, esFilterId_addr=0x%x, esSpecificInfo_addr=0x%x, esAttr_addr=0x%x)",
2014-09-02 03:05:13 +02:00
demuxerType2.addr(), esFilterId.addr(), esSpecificInfo_addr, esAttr.addr());
2014-02-24 01:00:42 +01:00
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;
}
int cellDmuxEnableEs(u32 demuxerHandle, vm::ptr<const CellCodecEsFilterId> esFilterId,
vm::ptr<const CellDmuxEsResource> esResourceInfo, vm::ptr<const CellDmuxEsCb> esCb,
2014-10-11 19:20:01 +02:00
const u32 esSpecificInfo_addr, vm::ptr<u32> esHandle)
{
cellDmux->Warning("cellDmuxEnableEs(demuxerHandle=%d, esFilterId_addr=0x%x, esResourceInfo_addr=0x%x, esCb_addr=0x%x, "
2014-09-02 03:05:13 +02:00
"esSpecificInfo_addr=0x%x, esHandle_addr=0x%x)", demuxerHandle, esFilterId.addr(), esResourceInfo.addr(),
esCb.addr(), esSpecificInfo_addr, esHandle.addr());
2014-02-24 01:00:42 +01:00
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,
2014-09-12 23:14:48 +02:00
vm::ptr<CellDmuxCbEsMsg>::make(esCb->cbEsMsgFunc.addr()), esCb->cbArg, esSpecificInfo_addr);
2014-02-24 01:00:42 +01:00
u32 id = cellDmux->GetNewId(es);
es->id = id;
2014-09-01 02:51:48 +02:00
*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);
2014-02-24 01:00:42 +01:00
DemuxerTask task(dmuxEnableEs);
task.es.es = id;
task.es.es_ptr = es;
2014-02-24 01:00:42 +01:00
2014-10-18 00:20:03 +02:00
dmux->job.Push(task, &dmux->is_closed);
return CELL_OK;
}
int cellDmuxDisableEs(u32 esHandle)
{
cellDmux->Warning("cellDmuxDisableEs(esHandle=0x%x)", esHandle);
2014-02-24 01:00:42 +01:00
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;
2014-02-24 01:00:42 +01:00
2014-10-18 00:20:03 +02:00
es->dmux->job.Push(task, &es->dmux->is_closed);
return CELL_OK;
}
int cellDmuxResetEs(u32 esHandle)
{
cellDmux->Log("cellDmuxResetEs(esHandle=0x%x)", esHandle);
2014-02-24 01:00:42 +01:00
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;
2014-02-24 01:00:42 +01:00
2014-10-18 00:20:03 +02:00
es->dmux->job.Push(task, &es->dmux->is_closed);
return CELL_OK;
}
2014-10-11 19:20:01 +02:00
int cellDmuxGetAu(u32 esHandle, vm::ptr<u32> auInfo_ptr, vm::ptr<u32> auSpecificInfo_ptr)
{
cellDmux->Log("cellDmuxGetAu(esHandle=0x%x, auInfo_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)",
2014-09-01 02:51:48 +02:00
esHandle, auInfo_ptr.addr(), auSpecificInfo_ptr.addr());
ElementaryStream* es;
if (!Emu.GetIdManager().GetIDData(esHandle, es))
{
return CELL_DMUX_ERROR_ARG;
}
u32 info;
u32 spec;
if (!es->peek(info, true, spec, true))
{
return CELL_DMUX_ERROR_EMPTY;
}
2014-09-01 02:51:48 +02:00
*auInfo_ptr = info;
*auSpecificInfo_ptr = spec;
return CELL_OK;
}
2014-10-11 19:20:01 +02:00
int cellDmuxPeekAu(u32 esHandle, vm::ptr<u32> auInfo_ptr, vm::ptr<u32> auSpecificInfo_ptr)
{
cellDmux->Log("cellDmuxPeekAu(esHandle=0x%x, auInfo_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)",
2014-09-01 02:51:48 +02:00
esHandle, auInfo_ptr.addr(), auSpecificInfo_ptr.addr());
ElementaryStream* es;
if (!Emu.GetIdManager().GetIDData(esHandle, es))
{
return CELL_DMUX_ERROR_ARG;
}
u32 info;
u32 spec;
if (!es->peek(info, true, spec, false))
{
return CELL_DMUX_ERROR_EMPTY;
}
2014-09-01 02:51:48 +02:00
*auInfo_ptr = info;
*auSpecificInfo_ptr = spec;
return CELL_OK;
}
2014-10-11 19:20:01 +02:00
int cellDmuxGetAuEx(u32 esHandle, vm::ptr<u32> auInfoEx_ptr, vm::ptr<u32> auSpecificInfo_ptr)
{
cellDmux->Log("cellDmuxGetAuEx(esHandle=0x%x, auInfoEx_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)",
2014-09-01 02:51:48 +02:00
esHandle, auInfoEx_ptr.addr(), auSpecificInfo_ptr.addr());
ElementaryStream* es;
if (!Emu.GetIdManager().GetIDData(esHandle, es))
{
return CELL_DMUX_ERROR_ARG;
}
u32 info;
u32 spec;
if (!es->peek(info, false, spec, true))
{
return CELL_DMUX_ERROR_EMPTY;
}
2014-09-01 02:51:48 +02:00
*auInfoEx_ptr = info;
*auSpecificInfo_ptr = spec;
return CELL_OK;
}
2014-10-11 19:20:01 +02:00
int cellDmuxPeekAuEx(u32 esHandle, vm::ptr<u32> auInfoEx_ptr, vm::ptr<u32> auSpecificInfo_ptr)
{
cellDmux->Log("cellDmuxPeekAuEx(esHandle=0x%x, auInfoEx_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)",
2014-09-01 02:51:48 +02:00
esHandle, auInfoEx_ptr.addr(), auSpecificInfo_ptr.addr());
ElementaryStream* es;
if (!Emu.GetIdManager().GetIDData(esHandle, es))
{
return CELL_DMUX_ERROR_ARG;
}
u32 info;
u32 spec;
if (!es->peek(info, false, spec, false))
{
return CELL_DMUX_ERROR_EMPTY;
}
2014-09-01 02:51:48 +02:00
*auInfoEx_ptr = info;
*auSpecificInfo_ptr = spec;
return CELL_OK;
}
int cellDmuxReleaseAu(u32 esHandle)
{
cellDmux->Log("cellDmuxReleaseAu(esHandle=0x%x)", esHandle);
2014-03-01 09:38:50 +01:00
2014-02-24 01:00:42 +01:00
ElementaryStream* es;
if (!Emu.GetIdManager().GetIDData(esHandle, es))
{
return CELL_DMUX_ERROR_ARG;
}
2014-03-07 22:31:08 +01:00
if (!es->release())
{
return CELL_DMUX_ERROR_SEQ;
}
return CELL_OK;
}
int cellDmuxFlushEs(u32 esHandle)
{
cellDmux->Warning("cellDmuxFlushEs(esHandle=0x%x)", esHandle);
2014-02-24 01:00:42 +01:00
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;
2014-02-24 01:00:42 +01:00
2014-10-18 00:20:03 +02:00
es->dmux->job.Push(task, &es->dmux->is_closed);
return CELL_OK;
}
void cellDmux_init(Module *pxThis)
{
cellDmux = pxThis;
cellDmux->AddFunc(0xa2d4189b, cellDmuxQueryAttr);
cellDmux->AddFunc(0x3f76e3cd, cellDmuxQueryAttr2);
cellDmux->AddFunc(0x68492de9, cellDmuxOpen);
cellDmux->AddFunc(0xf6c23560, cellDmuxOpenEx);
cellDmux->AddFunc(0x11bc3a6c, cellDmuxOpen2);
cellDmux->AddFunc(0x8c692521, cellDmuxClose);
cellDmux->AddFunc(0x04e7499f, cellDmuxSetStream);
cellDmux->AddFunc(0x5d345de9, cellDmuxResetStream);
cellDmux->AddFunc(0xccff1284, cellDmuxResetStreamAndWaitDone);
cellDmux->AddFunc(0x02170d1a, cellDmuxQueryEsAttr);
cellDmux->AddFunc(0x52911bcf, cellDmuxQueryEsAttr2);
cellDmux->AddFunc(0x7b56dc3f, cellDmuxEnableEs);
cellDmux->AddFunc(0x05371c8d, cellDmuxDisableEs);
cellDmux->AddFunc(0x21d424f0, cellDmuxResetEs);
cellDmux->AddFunc(0x42c716b5, cellDmuxGetAu);
cellDmux->AddFunc(0x2750c5e0, cellDmuxPeekAu);
cellDmux->AddFunc(0x2c9a5857, cellDmuxGetAuEx);
cellDmux->AddFunc(0x002e8da2, cellDmuxPeekAuEx);
cellDmux->AddFunc(0x24ea6474, cellDmuxReleaseAu);
cellDmux->AddFunc(0xebb3b2bd, cellDmuxFlushEs);
}