From 8df7f49b55fe31070899eabd692063302f362067 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Sat, 22 Feb 2014 21:42:23 +0400 Subject: [PATCH 1/8] ffmpeg submodule added --- .gitmodules | 3 +++ ffmpeg | 1 + 2 files changed, 4 insertions(+) create mode 160000 ffmpeg diff --git a/.gitmodules b/.gitmodules index 8bc866cb94..c0d4ac8d2d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -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 diff --git a/ffmpeg b/ffmpeg new file mode 160000 index 0000000000..8bcaa2485c --- /dev/null +++ b/ffmpeg @@ -0,0 +1 @@ +Subproject commit 8bcaa2485c2434d7d7a9da17491bafb58de42bb6 From a14276abf16a3eb27a5106b61b3d0cc618ef8a8d Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Mon, 24 Feb 2014 04:00:42 +0400 Subject: [PATCH 2/8] Work on demuxer, ffmpeg libs linked --- Utilities/SQueue.h | 101 +++++++ rpcs3/Emu/SysCalls/Modules/cellAudio.cpp | 2 +- rpcs3/Emu/SysCalls/Modules/cellDmux.cpp | 369 ++++++++++++++++++++++- rpcs3/Emu/SysCalls/Modules/cellDmux.h | 250 ++++++++++++++- rpcs3/Emu/SysCalls/Modules/cellPamf.h | 6 +- rpcs3/rpcs3.vcxproj | 28 +- rpcs3/rpcs3.vcxproj.filters | 3 + 7 files changed, 725 insertions(+), 34 deletions(-) create mode 100644 Utilities/SQueue.h diff --git a/Utilities/SQueue.h b/Utilities/SQueue.h new file mode 100644 index 0000000000..ca7cb9fe15 --- /dev/null +++ b/Utilities/SQueue.h @@ -0,0 +1,101 @@ +#pragma once + +template +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; + } + } + } + + u32 GetCount() + { + SMutexLocker lock(m_mutex); + return m_count; + } + + bool IsEmpty() + { + SMutexLocker lock(m_mutex); + return !m_count; + } + + void Clear() + { + SMutexLocker lock(m_mutex); + m_count = 0; + } +}; \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp index 50290f9e97..ecf52c7c49 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp @@ -298,7 +298,7 @@ int cellAudioInit() m_config.m_indexes = Memory.Alloc(sizeof(u64) * m_config.AUDIO_PORT_COUNT, 16); memset(Memory + m_config.m_indexes, 0, sizeof(u64) * m_config.AUDIO_PORT_COUNT); - thread t("AudioThread", []() + thread t("Audio Thread", []() { WAVHeader header(2); // WAV file header (stereo) diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp index 84e54578c2..bd1d4d9d14 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp @@ -4,75 +4,310 @@ #include "cellPamf.h" #include "cellDmux.h" +extern "C" +{ +#include "libavformat\avformat.h" +} + void cellDmux_init(); Module cellDmux(0x0007, cellDmux_init); +void dmuxQueryAttr(u32 info_addr /* may be 0 */, mem_ptr_t attr) +{ + attr->demuxerVerLower = 0; // TODO: check values + attr->demuxerVerUpper = 0; + attr->memSize = 1024 * 1024; // 1M +} + +void dmuxQueryEsAttr(u32 info_addr /* may be 0 */, const mem_ptr_t esFilterId, + const u32 esSpecificInfo_addr, mem_ptr_t attr) +{ + attr->memSize = 1024 * 1024; +} + int cellDmuxQueryAttr(const mem_ptr_t demuxerType, mem_ptr_t 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 demuxerType2, mem_ptr_t 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; } +u32 dmuxOpen(Demuxer* data) +{ + Demuxer& dmux = *data; + + u32 id = cellDmux.GetNewId(data); + + thread t("Demuxer [" + std::to_string(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; + + while (true) + { + if (!dmux.job.Pop(task)) + { + break; + } + + switch (task.type) + { + case dmuxSetStream: + case dmuxResetStream: + case dmuxEnableEs: + case dmuxDisableEs: + case dmuxResetEs: + case dmuxGetAu: + case dmuxPeekAu: + case dmuxReleaseAu: + case dmuxFlushEs: + case dmuxClose: + dmux.is_finished = true; + ConLog.Write("Demuxer exit"); + return; + default: + ConLog.Error("Demuxer error: unknown task(%d)", task.type); + } + } + + ConLog.Warning("Demuxer aborted"); + }); + + t.detach(); + + return id; +} + int cellDmuxOpen(const mem_ptr_t demuxerType, const mem_ptr_t demuxerResource, const mem_ptr_t 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, (CellDmuxCbMsg&)demuxerCb->cbMsgFunc, demuxerCb->cbArg_addr)); + return CELL_OK; } int cellDmuxOpenEx(const mem_ptr_t demuxerType, const mem_ptr_t demuxerResourceEx, const mem_ptr_t 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, (CellDmuxCbMsg&)demuxerCb->cbMsgFunc, demuxerCb->cbArg_addr)); + return CELL_OK; } int cellDmuxOpen2(const mem_ptr_t demuxerType2, const mem_ptr_t demuxerResource2, const mem_ptr_t 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, (CellDmuxCbMsg&)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.Warning("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->job.IsEmpty()) + { + 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); return CELL_OK; } int cellDmuxResetStream(u32 demuxerHandle) { - cellDmux.Error("cellDmuxResetStream(demuxerHandle=0x%x)", demuxerHandle); + cellDmux.Warning("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.Error("cellDmuxResetStreamAndWaitDone(demuxerHandle=%d)", demuxerHandle); + + Demuxer* dmux; + if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux)) + { + return CELL_DMUX_ERROR_ARG; + } + + dmux->job.Push(DemuxerTask(dmuxResetStream)); + + // TODO: wait done + return CELL_OK; } int cellDmuxQueryEsAttr(const mem_ptr_t demuxerType, const mem_ptr_t esFilterId, const u32 esSpecificInfo_addr, mem_ptr_t 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; } @@ -81,6 +316,26 @@ int cellDmuxQueryEsAttr2(const mem_ptr_t demuxerType2, const mem_ { cellDmux.Error("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,21 +343,81 @@ int cellDmuxEnableEs(u32 demuxerHandle, const mem_ptr_t esF const mem_ptr_t esResourceInfo, const mem_ptr_t 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, + (CellDmuxCbEsMsg&)esCb->cbEsMsgFunc, esCb->cbArg_addr, esSpecificInfo_addr); + + u32 id = cellDmux.GetNewId(es); + + DemuxerTask task(dmuxEnableEs); + task.au.es = id; + task.au.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.esHandle = esHandle; + task.au.es_ptr = es; + + es->dmux->job.Push(task); return CELL_OK; } int cellDmuxResetEs(u32 esHandle) { - cellDmux.Error("cellDmuxResetEs(esHandle=0x%x)", esHandle); + cellDmux.Warning("cellDmuxResetEs(esHandle=0x%x)", esHandle); + + ElementaryStream* es; + if (!Emu.GetIdManager().GetIDData(esHandle, es)) + { + return CELL_DMUX_ERROR_ARG; + } + + DemuxerTask task(dmuxResetEs); + task.esHandle = esHandle; + task.au.es_ptr = es; + + es->dmux->job.Push(task); return CELL_OK; } @@ -136,13 +451,37 @@ int cellDmuxPeekAuEx(u32 esHandle, const u32 auInfoEx_ptr_addr, u32 auSpecificIn int cellDmuxReleaseAu(u32 esHandle) { - cellDmux.Error("cellDmuxReleaseAu(esHandle=0x%x)", esHandle); + cellDmux.Warning("cellDmuxReleaseAu(esHandle=0x%x)", esHandle); + + ElementaryStream* es; + if (!Emu.GetIdManager().GetIDData(esHandle, es)) + { + return CELL_DMUX_ERROR_ARG; + } + + DemuxerTask task(dmuxReleaseAu); + task.esHandle = esHandle; + task.au.es_ptr = es; + + es->dmux->job.Push(task); return CELL_OK; } int cellDmuxFlushEs(u32 esHandle) { - cellDmux.Error("cellDmuxFlushEs(esHandle=0x%x)", esHandle); + cellDmux.Warning("cellDmuxFlushEs(esHandle=0x%x)", esHandle); + + ElementaryStream* es; + if (!Emu.GetIdManager().GetIDData(esHandle, es)) + { + return CELL_DMUX_ERROR_ARG; + } + + DemuxerTask task(dmuxFlushEs); + task.esHandle = esHandle; + task.au.es_ptr = es; + + es->dmux->job.Push(task); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.h b/rpcs3/Emu/SysCalls/Modules/cellDmux.h index 77bab0fcdb..b2a3fe5ec8 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.h +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.h @@ -1,5 +1,7 @@ #pragma once +#include "Utilities/SQueue.h" + // Error Codes enum { @@ -30,6 +32,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 reserved1; +}; + +struct CellDmuxPamfAuSpecificInfoAvc +{ + be_t reserved1; +}; + +struct CellDmuxPamfAuSpecificInfoLpcm +{ + u8 channelAssignmentInfo; + u8 samplingFreqInfo; + u8 bitsPerSample; +}; + +struct CellDmuxPamfAuSpecificInfoAc3 +{ + be_t reserved1; +}; + +struct CellDmuxPamfAuSpecificInfoAtrac3plus +{ + be_t reserved1; +}; + +struct CellDmuxPamfAuSpecificInfoUserData +{ + be_t reserved1; +}; + +struct CellDmuxPamfEsSpecificInfoM2v +{ + be_t profileLevel; +}; + +struct CellDmuxPamfEsSpecificInfoAvc +{ + be_t level; +}; + +struct CellDmuxPamfEsSpecificInfoLpcm +{ + be_t samplingFreq; + be_t numOfChannels; + be_t bitsPerSample; +}; + +struct CellDmuxPamfEsSpecificInfoAc3 +{ + be_t reserved1; +}; + +struct CellDmuxPamfEsSpecificInfoAtrac3plus +{ + be_t reserved1; +}; + +struct CellDmuxPamfEsSpecificInfoUserData +{ + be_t 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 msgType; //CellDmuxMsgType enum @@ -44,13 +158,19 @@ struct CellDmuxEsMsg struct CellDmuxType { - CellDmuxStreamType streamType; + be_t streamType; be_t reserved[2]; //0 }; +struct CellDmuxPamfSpecificInfo +{ + be_t thisSize; + bool programEndCodeCb; +}; + struct CellDmuxType2 { - CellDmuxStreamType streamType; + be_t streamType; be_t streamSpecificInfo_addr; }; @@ -112,17 +232,21 @@ struct CellDmuxResource2 }; }; +typedef mem_func_ptr_t demuxerMsg, u32 cbArg_addr)> CellDmuxCbMsg; + struct CellDmuxCb { // CellDmuxCbMsg callback - be_t demuxerMsg, u32 cbArg_addr)>> cbMsgFunc; + be_t cbMsgFunc; be_t cbArg_addr; }; +typedef mem_func_ptr_t esMsg, u32 cbArg_addr)> CellDmuxCbEsMsg; + struct CellDmuxEsCb { // CellDmuxCbEsMsg callback - be_t esMsg, u32 cbArg_addr)>> cbEsMsgFunc; + be_t cbEsMsgFunc; be_t cbArg_addr; }; @@ -165,4 +289,122 @@ struct CellDmuxAuInfoEx be_t userData; CellCodecTimeStamp pts; CellCodecTimeStamp dts; +}; + +/* Demuxer Thread Classes */ + +struct AccessUnit +{ + u32 addr; + u32 size; + u32 ptsUpper; + u32 ptsLower; + u32 dtsUpper; + u32 dtsLower; + u64 userData; + bool isRap; +}; + +class ElementaryStream; + +enum DemuxerJobType +{ + dmuxSetStream, + dmuxResetStream, + dmuxEnableEs, + dmuxDisableEs, + dmuxResetEs, + dmuxGetAu, + dmuxPeekAu, + dmuxReleaseAu, + dmuxFlushEs, + dmuxClose, +}; + +#pragma pack(push, 1) +struct DemuxerTask +{ + DemuxerJobType type; + + union + { + struct + { + u32 addr; + u64 userdata; + u32 size; + /*bool*/u32 discontinuity; + } stream; + + u32 esHandle; + + struct + { + u32 es; + u32 auInfo_ptr_addr; + u32 auSpec_ptr_addr; + ElementaryStream* es_ptr; + } au; + }; + + DemuxerTask() + { + } + + DemuxerTask(DemuxerJobType type) + : type(type) + { + } +}; +static_assert(sizeof(DemuxerTask) == 24, ""); +#pragma pack(pop) + +class Demuxer +{ +public: + SQueue job; + const u32 memAddr; + const u32 memSize; + const CellDmuxCbMsg cbFunc; + const u32 cbArg; + bool is_finished; + + + Demuxer(u32 addr, u32 size, CellDmuxCbMsg func, u32 arg) + : is_finished(false) + , memAddr(addr) + , memSize(size) + , cbFunc(func) + , cbArg(arg) + { + } +}; + +class ElementaryStream +{ +public: + Demuxer* dmux; + const u32 memAddr; + const u32 memSize; + const u32 fidMajor; + const u32 fidMinor; + const u32 sup1; + const u32 sup2; + const CellDmuxCbEsMsg cbFunc; + const u32 cbArg; + const u32 spec; //addr + + ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, CellDmuxCbEsMsg cbFunc, u32 cbArg, u32 spec) + : dmux(dmux) + , memAddr(addr) + , memSize(size) + , fidMajor(fidMajor) + , fidMinor(fidMinor) + , sup1(sup1) + , sup2(sup2) + , cbFunc(cbFunc) + , cbArg(cbArg) + , spec(spec) + { + } }; \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Modules/cellPamf.h b/rpcs3/Emu/SysCalls/Modules/cellPamf.h index b88c473af0..152faa29c0 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPamf.h +++ b/rpcs3/Emu/SysCalls/Modules/cellPamf.h @@ -135,13 +135,15 @@ enum }; // Timestamp information (time in increments of 90 kHz) -struct CellCodecTimeStamp { +struct CellCodecTimeStamp +{ be_t upper; be_t lower; }; // Entry point information -struct CellPamfEp { +struct CellPamfEp +{ be_t indexN; be_t nThRefPictureOffset; CellCodecTimeStamp pts; diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index c9b3ad0722..24e51cea61 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -69,20 +69,20 @@ - .\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;..\..\ffmpeg;$(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) $(SolutionDir)bin\ ..\libs\$(Configuration)\;$(LibraryPath) $(ProjectName)-$(PlatformShortName)-dbg - .\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;..\..\ffmpeg;$(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) $(SolutionDir)bin\ ..\libs\$(Configuration)\;$(LibraryPath) $(ProjectName)-$(PlatformShortName)-dbg false - .\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;..\..\ffmpeg;$(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) $(SolutionDir)bin\ ..\libs\$(Configuration)\;$(LibraryPath) false @@ -91,7 +91,7 @@ false - .\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;..\..\ffmpeg;$(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) $(SolutionDir)bin\ ..\libs\$(Configuration)\;$(LibraryPath) false @@ -109,10 +109,10 @@ true - 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) + 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) %(IgnoreSpecificDefaultLibraries) false - ..\wxWidgets\lib\vc_lib + ..\wxWidgets\lib\vc_lib;..\ffmpeg\Windows\x86\lib @@ -129,14 +129,17 @@ true - 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) + 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) %(IgnoreSpecificDefaultLibraries) false - ..\wxWidgets\lib\vc_x64_lib + ..\wxWidgets\lib\vc_x64_lib;..\ffmpeg\Windows\x86_64\lib "$(SolutionDir)\Utilities\git-version-gen.cmd" + + false + @@ -158,12 +161,12 @@ true true true - 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) + 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) %(IgnoreSpecificDefaultLibraries) false - ..\wxWidgets\lib\vc_lib + ..\wxWidgets\lib\vc_lib;..\ffmpeg\Windows\x86\lib @@ -190,12 +193,12 @@ true true true - 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) + 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) %(IgnoreSpecificDefaultLibraries) false - ..\wxWidgets\lib\vc_x64_lib + ..\wxWidgets\lib\vc_x64_lib;..\ffmpeg\Windows\x86_64\lib @@ -341,6 +344,7 @@ + diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index 041ee71a3a..c1a23c8016 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -597,5 +597,8 @@ Utilities + + Utilities + \ No newline at end of file From 0bd5dc53635ba461386ff5212c5cbbf1f6b0ede2 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Wed, 26 Feb 2014 11:51:00 +0400 Subject: [PATCH 3/8] Demuxer improved, cellPamf improved File reading improved --- Utilities/SQueue.h | 6 +- rpcs3/Emu/CPU/CPUThread.cpp | 4 +- rpcs3/Emu/Cell/RawSPUThread.cpp | 4 +- rpcs3/Emu/SysCalls/Callback.cpp | 41 +- rpcs3/Emu/SysCalls/Modules/cellDmux.cpp | 592 ++++++++++++++++++----- rpcs3/Emu/SysCalls/Modules/cellDmux.h | 331 +++++++++++-- rpcs3/Emu/SysCalls/Modules/cellPamf.cpp | 28 +- rpcs3/Emu/SysCalls/Modules/cellVdec.cpp | 5 + rpcs3/Emu/SysCalls/Modules/sys_fs.cpp | 75 +-- rpcs3/Emu/SysCalls/lv2/SC_Condition.cpp | 2 +- rpcs3/Emu/SysCalls/lv2/SC_FileSystem.cpp | 39 +- 11 files changed, 928 insertions(+), 199 deletions(-) diff --git a/Utilities/SQueue.h b/Utilities/SQueue.h index ca7cb9fe15..1fee6f6727 100644 --- a/Utilities/SQueue.h +++ b/Utilities/SQueue.h @@ -81,15 +81,13 @@ public: } } - u32 GetCount() + volatile u32 GetCount() { - SMutexLocker lock(m_mutex); return m_count; } - bool IsEmpty() + volatile bool IsEmpty() { - SMutexLocker lock(m_mutex); return !m_count; } diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index df197bc1d9..2d98e28e4b 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -296,7 +296,7 @@ void CPUThread::ExecOnce() void CPUThread::Task() { - ConLog.Write("%s enter", CPUThread::GetFName().wx_str()); + if (Ini.HLELogging.GetValue()) ConLog.Write("%s enter", CPUThread::GetFName().wx_str()); const Array& bp = Emu.GetBreakPoints(); @@ -358,5 +358,5 @@ void CPUThread::Task() ConLog.Success("Exit Code: %d", exitcode); } - ConLog.Write("%s leave", CPUThread::GetFName().wx_str()); + if (Ini.HLELogging.GetValue()) ConLog.Write("%s leave", CPUThread::GetFName().wx_str()); } diff --git a/rpcs3/Emu/Cell/RawSPUThread.cpp b/rpcs3/Emu/Cell/RawSPUThread.cpp index 9a5c84e854..49f2abfff2 100644 --- a/rpcs3/Emu/Cell/RawSPUThread.cpp +++ b/rpcs3/Emu/Cell/RawSPUThread.cpp @@ -251,7 +251,7 @@ u32 RawSPUThread::GetIndex() const void RawSPUThread::Task() { - ConLog.Write("%s enter", PPCThread::GetFName().wx_str()); + if (Ini.HLELogging.GetValue()) ConLog.Write("%s enter", PPCThread::GetFName().wx_str()); const Array& bp = Emu.GetBreakPoints(); @@ -334,5 +334,5 @@ void RawSPUThread::Task() ConLog.Error("Exception: %s", wxString(e).wx_str()); } - ConLog.Write("%s leave", PPCThread::GetFName().wx_str()); + if (Ini.HLELogging.GetValue()) ConLog.Write("%s leave", PPCThread::GetFName().wx_str()); } diff --git a/rpcs3/Emu/SysCalls/Callback.cpp b/rpcs3/Emu/SysCalls/Callback.cpp index 017341218d..f64851b6c3 100644 --- a/rpcs3/Emu/SysCalls/Callback.cpp +++ b/rpcs3/Emu/SysCalls/Callback.cpp @@ -53,10 +53,33 @@ void Callback::Branch(bool wait) { m_has_data = false; + static SMutexGeneral cb_mutex; + CPUThread& thr = Emu.GetCallbackThread(); - while(Emu.IsRunning() && thr.IsAlive()) +again: + + while (thr.IsAlive()) + { + if (Emu.IsStopped()) + { + ConLog.Warning("Callback::Branch() aborted"); + return; + } Sleep(1); + } + + SMutexGeneralLocker lock(cb_mutex); + + if (thr.IsAlive()) + { + goto again; + } + if (Emu.IsStopped()) + { + ConLog.Warning("Callback::Branch() aborted"); + return; + } thr.Stop(); thr.Reset(); @@ -74,8 +97,20 @@ void Callback::Branch(bool wait) thr.Exec(); - if(wait) - GetCurrentPPCThread()->Wait(thr); + if (!wait) + { + return; + } + + while (thr.IsAlive()) + { + if (Emu.IsStopped()) + { + ConLog.Warning("Callback::Branch(true) aborted (end)"); + return; + } + Sleep(1); + } } void Callback::SetName(const std::string& name) diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp index bd1d4d9d14..b7b81bef2c 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp @@ -4,25 +4,334 @@ #include "cellPamf.h" #include "cellDmux.h" -extern "C" -{ -#include "libavformat\avformat.h" -} - void cellDmux_init(); Module cellDmux(0x0007, cellDmux_init); void dmuxQueryAttr(u32 info_addr /* may be 0 */, mem_ptr_t attr) { - attr->demuxerVerLower = 0; // TODO: check values - attr->demuxerVerUpper = 0; - attr->memSize = 1024 * 1024; // 1M + attr->demuxerVerLower = 0x280000; // TODO: check values + attr->demuxerVerUpper = 0x260000; + attr->memSize = 0x10000; // 0x3e8e6 from ps3 } void dmuxQueryEsAttr(u32 info_addr /* may be 0 */, const mem_ptr_t esFilterId, const u32 esSpecificInfo_addr, mem_ptr_t attr) { - attr->memSize = 1024 * 1024; + if (esFilterId->filterIdMajor >= 0xe0) + attr->memSize = 0x500000; // 0x45fa49 from ps3 + else + attr->memSize = 0x10000; // 0x73d9 from ps3 + + cellDmux.Warning("*** filter(0x%x, 0x%x, 0x%x, 0x%x)", (u32)esFilterId->filterIdMajor, (u32)esFilterId->filterIdMinor, + (u32)esFilterId->supplementalInfo1, (u32)esFilterId->supplementalInfo2); +} + +u32 dmuxOpen(Demuxer* data) +{ + Demuxer& dmux = *data; + + u32 dmux_id = cellDmux.GetNewId(data); + + dmux.id = dmux_id; + + thread t("Demuxer[" + std::to_string(dmux_id) + "] Thread", [&]() + { + ConLog.Write("Demuxer enter (mem=0x%x, size=0x%x, cb=0x%x, arg=0x%x)", dmux.memAddr, dmux.memSize, dmux.cbFunc, dmux.cbArg); + + DemuxerTask task; + DemuxerStream stream; + /* + ElementaryStream* esAVC[16]; memset(esAVC, 0, sizeof(esAVC)); + ElementaryStream* esM2V[16]; memset(esM2V, 0, sizeof(esM2V)); + ElementaryStream* esDATA[16]; memset(esDATA, 0, sizeof(esDATA)); + ElementaryStream* esATRAX[48]; memset(esATRAX, 0, sizeof(esATRAX)); + ElementaryStream* esAC3[48]; memset(esAC3, 0, sizeof(esAC3)); + ElementaryStream* esLPCM[48]; memset(esLPCM, 0, sizeof(esLPCM)); + */ + ElementaryStream* esALL[192]; memset(esALL, 0, sizeof(esALL)); + ElementaryStream** esAVC = &esALL[0]; + + u32 cb_add = 0; + + while (true) + { + if (Emu.IsStopped()) + { + break; + } + + if (dmux.job.IsEmpty() && dmux.is_running) + { + // default task (demuxing) (if there is no other work) + be_t code; + be_t len; + u8 ch; + + if (!stream.peek(code)) + { + // demuxing finished + task.type = dmuxResetStream; + goto task; + } + else switch (code.ToLE()) + { + case PACK_START_CODE: + { + stream.skip(14); + } + break; + + case SYSTEM_HEADER_START_CODE: + { + stream.skip(18); + } + break; + + case PADDING_STREAM: + case PRIVATE_STREAM_2: + { + // unknown + stream.skip(4); + stream.get(len); + stream.skip(len); + } + break; + + case PRIVATE_STREAM_1: + { + // audio AT3+ (and probably LPCM or user data) + stream.skip(4); + stream.get(len); + + // skipping... + stream.skip(len); + } + break; + + case 0x1e0: case 0x1e1: case 0x1e2: case 0x1e3: + case 0x1e4: case 0x1e5: case 0x1e6: case 0x1e7: + case 0x1e8: case 0x1e9: case 0x1ea: case 0x1eb: + case 0x1ec: case 0x1ed: case 0x1ee: case 0x1ef: + { + // video AVC + ch = code - 0x1e0; + if (esAVC[ch]) + { + ElementaryStream& es = *esAVC[ch]; + if (es.isfull()) + { + Sleep(1); + continue; + } + + stream.skip(4); + stream.get(len); + PesHeader pes(stream); + + if (!pes.size && !es.hasdata()) // fatal error + { + ConLog.Error("PES not found"); + return; + } + + if (pes.size && es.hasdata()) // new AU detected + { + es.finish(stream); + // callback + mem_ptr_t esMsg(a128(dmux.memAddr) + (cb_add ^= 16)); + esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND; + esMsg->supplementalInfo = stream.userdata; + Callback cb; + cb.SetAddr(es.cbFunc); + cb.Handle(dmux.id, es.id, esMsg.GetAddr(), es.cbArg); + cb.Branch(false); + } + + if (pes.size) + { + //ConLog.Write("*** AVC AU detected (pts=0x%x, dts=0x%x)", pes.pts, pes.dts); + } + + es.push(stream, len - pes.size - 3, pes); + } + else + { + stream.skip(4); + stream.get(len); + stream.skip(len); + } + } + break; + + case 0x1c0: case 0x1c1: case 0x1c2: case 0x1c3: + case 0x1c4: case 0x1c5: case 0x1c6: case 0x1c7: + case 0x1c8: case 0x1c9: case 0x1ca: case 0x1cb: + case 0x1cc: case 0x1cd: case 0x1ce: case 0x1cf: + case 0x1d0: case 0x1d1: case 0x1d2: case 0x1d3: + case 0x1d4: case 0x1d5: case 0x1d6: case 0x1d7: + case 0x1d8: case 0x1d9: case 0x1da: case 0x1db: + case 0x1dc: case 0x1dd: case 0x1de: case 0x1df: + { + // unknown + stream.skip(4); + stream.get(len); + stream.skip(len); + } + break; + + case USER_DATA_START_CODE: + { + ConLog.Error("USER_DATA_START_CODE found"); + return; + } + + default: + { + // search + stream.skip(1); + } + break; + + } + continue; + } + + // wait for task with yielding (if no default work) + if (!dmux.job.Pop(task)) + { + break; // Emu is stopped + } +task: + switch (task.type) + { + case dmuxSetStream: + { + stream = task.stream; + ConLog.Write("*** stream updated(addr=0x%x, size=0x%x, discont=%d, userdata=0x%llx)", + stream.addr, stream.size, stream.discontinuity, stream.userdata); + if (stream.discontinuity) for (u32 i = 0; i < 192; i++) + { + if (esALL[i]) + { + esALL[i]->reset(); + } + } + dmux.is_running = true; + } + break; + + case dmuxResetStream: + case dmuxResetStreamAndWaitDone: + { + // TODO: send CELL_DMUX_MSG_TYPE_DEMUX_DONE callback and provide waiting condition + mem_ptr_t dmuxMsg(a128(dmux.memAddr) + (cb_add ^= 16)); + dmuxMsg->msgType = CELL_DMUX_MSG_TYPE_DEMUX_DONE; + dmuxMsg->supplementalInfo = stream.userdata; + Callback cb; + cb.SetAddr(dmux.cbFunc); + cb.Handle(dmux.id, dmuxMsg.GetAddr(), dmux.cbArg); + cb.Branch(task.type == dmuxResetStreamAndWaitDone); + dmux.is_running = false; + } + break; + + case dmuxClose: + { + dmux.is_finished = true; + ConLog.Write("Demuxer exit"); + return; + } + + case dmuxEnableEs: + { + ElementaryStream& es = *task.es.es_ptr; + if (es.fidMajor >= 0xe0 && + es.fidMajor <= 0xef && + es.fidMinor == 0 && + es.sup1 == 1 && + es.sup2 == 0) + { + esAVC[es.fidMajor - 0xe0] = task.es.es_ptr; + } + else + { + ConLog.Warning("dmuxEnableEs: (TODO) unsupported filter (0x%x, 0x%x, 0x%x, 0x%x)", es.fidMajor, es.fidMinor, es.sup1, es.sup2); + } + es.dmux = &dmux; + } + break; + + case dmuxDisableEs: + { + ElementaryStream& es = *task.es.es_ptr; + if (es.dmux != &dmux) + { + ConLog.Warning("dmuxDisableEs: invalid elementary stream"); + break; + } + for (u32 i = 0; i < 192; i++) + { + if (esALL[i] == &es) + { + esALL[i] = nullptr; + } + } + es.dmux = nullptr; + Emu.GetIdManager().RemoveID(task.es.es); + } + break; + + case dmuxReleaseAu: + { + task.es.es_ptr->release(); + } + break; + + case dmuxFlushEs: + { + ElementaryStream& es = *task.es.es_ptr; + + if (es.hasdata()) + { + es.finish(stream); + // callback + mem_ptr_t esMsg(a128(dmux.memAddr) + (cb_add ^= 16)); + esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND; + esMsg->supplementalInfo = stream.userdata; + Callback cb; + cb.SetAddr(es.cbFunc); + cb.Handle(dmux.id, es.id, esMsg.GetAddr(), es.cbArg); + cb.Branch(false); + } + + // callback + mem_ptr_t esMsg(a128(dmux.memAddr) + (cb_add ^= 16)); + esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_FLUSH_DONE; + esMsg->supplementalInfo = stream.userdata; + Callback cb; + cb.SetAddr(es.cbFunc); + cb.Handle(dmux.id, es.id, esMsg.GetAddr(), es.cbArg); + cb.Branch(false); + } + break; + + case dmuxResetEs: + { + task.es.es_ptr->reset(); + } + break; + + default: + ConLog.Error("Demuxer error: unknown task(%d)", task.type); + return; + } + } + ConLog.Warning("Demuxer aborted"); + }); + + t.detach(); + + return dmux_id; } int cellDmuxQueryAttr(const mem_ptr_t demuxerType, mem_ptr_t demuxerAttr) @@ -61,53 +370,6 @@ int cellDmuxQueryAttr2(const mem_ptr_t demuxerType2, mem_ptr_t demuxerType, const mem_ptr_t demuxerResource, const mem_ptr_t demuxerCb, mem32_t demuxerHandle) { @@ -131,7 +393,7 @@ int cellDmuxOpen(const mem_ptr_t demuxerType, const mem_ptr_tmemAddr, demuxerResource->memSize, (CellDmuxCbMsg&)demuxerCb->cbMsgFunc, demuxerCb->cbArg_addr)); + demuxerHandle = dmuxOpen(new Demuxer(demuxerResource->memAddr, demuxerResource->memSize, demuxerCb->cbMsgFunc, demuxerCb->cbArg_addr)); return CELL_OK; } @@ -159,7 +421,7 @@ int cellDmuxOpenEx(const mem_ptr_t demuxerType, const mem_ptr_tmemAddr, demuxerResourceEx->memSize, (CellDmuxCbMsg&)demuxerCb->cbMsgFunc, demuxerCb->cbArg_addr)); + demuxerHandle = dmuxOpen(new Demuxer(demuxerResourceEx->memAddr, demuxerResourceEx->memSize, demuxerCb->cbMsgFunc, demuxerCb->cbArg_addr)); return CELL_OK; } @@ -187,7 +449,7 @@ int cellDmuxOpen2(const mem_ptr_t demuxerType2, const mem_ptr_tmemAddr, demuxerResource2->memSize, (CellDmuxCbMsg&)demuxerCb->cbMsgFunc, demuxerCb->cbArg_addr)); + demuxerHandle = dmuxOpen(new Demuxer(demuxerResource2->memAddr, demuxerResource2->memSize, demuxerCb->cbMsgFunc, demuxerCb->cbArg_addr)); return CELL_OK; } @@ -221,7 +483,7 @@ int cellDmuxClose(u32 demuxerHandle) int cellDmuxSetStream(u32 demuxerHandle, const u32 streamAddress, u32 streamSize, bool discontinuity, u64 userData) { - cellDmux.Warning("cellDmuxSetStream(demuxerHandle=%d, streamAddress=0x%x, streamSize=%d, discontinuity=%d, userData=0x%llx", + cellDmux.Log("cellDmuxSetStream(demuxerHandle=%d, streamAddress=0x%x, streamSize=%d, discontinuity=%d, userData=0x%llx", demuxerHandle, streamAddress, streamSize, discontinuity, userData); Demuxer* dmux; @@ -235,8 +497,9 @@ int cellDmuxSetStream(u32 demuxerHandle, const u32 streamAddress, u32 streamSize return CELL_DMUX_ERROR_FATAL; } - if (!dmux->job.IsEmpty()) + if (dmux->is_running) { + Sleep(1); // performance hack return CELL_DMUX_ERROR_BUSY; } @@ -248,12 +511,22 @@ int cellDmuxSetStream(u32 demuxerHandle, const u32 streamAddress, u32 streamSize info.userdata = userData; dmux->job.Push(task); + + while (!dmux->is_running) + { + if (Emu.IsStopped()) + { + ConLog.Warning("cellDmuxSetStream(%d) aborted", demuxerHandle); + break; + } + Sleep(1); + } return CELL_OK; } int cellDmuxResetStream(u32 demuxerHandle) { - cellDmux.Warning("cellDmuxResetStream(demuxerHandle=%d)", demuxerHandle); + cellDmux.Log("cellDmuxResetStream(demuxerHandle=%d)", demuxerHandle); Demuxer* dmux; if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux)) @@ -268,7 +541,7 @@ int cellDmuxResetStream(u32 demuxerHandle) int cellDmuxResetStreamAndWaitDone(u32 demuxerHandle) { - cellDmux.Error("cellDmuxResetStreamAndWaitDone(demuxerHandle=%d)", demuxerHandle); + cellDmux.Log("cellDmuxResetStreamAndWaitDone(demuxerHandle=%d)", demuxerHandle); Demuxer* dmux; if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux)) @@ -276,9 +549,17 @@ int cellDmuxResetStreamAndWaitDone(u32 demuxerHandle) return CELL_DMUX_ERROR_ARG; } - dmux->job.Push(DemuxerTask(dmuxResetStream)); + dmux->job.Push(DemuxerTask(dmuxResetStreamAndWaitDone)); - // TODO: wait done + while (dmux->is_running) + { + if (Emu.IsStopped()) + { + ConLog.Warning("cellDmuxResetStreamAndWaitDone(%d) aborted", demuxerHandle); + break; + } + Sleep(1); + } return CELL_OK; } @@ -314,7 +595,7 @@ int cellDmuxQueryEsAttr(const mem_ptr_t demuxerType, const mem_ptr int cellDmuxQueryEsAttr2(const mem_ptr_t demuxerType2, const mem_ptr_t esFilterId, const u32 esSpecificInfo_addr, mem_ptr_t esAttr) { - cellDmux.Error("cellDmuxQueryEsAttr2(demuxerType2_addr=0x%x, esFilterId_addr=0x%x, esSpecificInfo_addr=0x%x, esAttr_addr=0x%x)", + cellDmux.Warning("cellDmuxQueryEsAttr2(demuxerType2_addr=0x%x, esFilterId_addr=0x%x, esSpecificInfo_addr=0x%x, esAttr_addr=0x%x)", demuxerType2.GetAddr(), esFilterId.GetAddr(), esSpecificInfo_addr, esAttr.GetAddr()); if (!demuxerType2.IsGood() || !esFilterId.IsGood() || !esAttr.IsGood()) @@ -373,13 +654,17 @@ int cellDmuxEnableEs(u32 demuxerHandle, const mem_ptr_t esF ElementaryStream* es = new ElementaryStream(dmux, esResourceInfo->memAddr, esResourceInfo->memSize, esFilterId->filterIdMajor, esFilterId->filterIdMinor, esFilterId->supplementalInfo1, esFilterId->supplementalInfo2, - (CellDmuxCbEsMsg&)esCb->cbEsMsgFunc, esCb->cbArg_addr, esSpecificInfo_addr); + esCb->cbEsMsgFunc, esCb->cbArg_addr, esSpecificInfo_addr); u32 id = cellDmux.GetNewId(es); + es->id = id; + + cellDmux.Warning("*** New ES(dmux=%d, addr=0x%x, size=0x%x, filter(0x%x, 0x%x, 0x%x, 0x%x), cb=0x%x(arg=0x%x), spec=0x%x): id = %d", + demuxerHandle, es->memAddr, es->memSize, es->fidMajor, es->fidMinor, es->sup1, es->sup2, (u32)esCb->cbEsMsgFunc, es->cbArg, es->spec, id); DemuxerTask task(dmuxEnableEs); - task.au.es = id; - task.au.es_ptr = es; + task.es.es = id; + task.es.es_ptr = es; dmux->job.Push(task); return CELL_OK; @@ -396,8 +681,8 @@ int cellDmuxDisableEs(u32 esHandle) } DemuxerTask task(dmuxDisableEs); - task.esHandle = esHandle; - task.au.es_ptr = es; + task.es.es = esHandle; + task.es.es_ptr = es; es->dmux->job.Push(task); return CELL_OK; @@ -405,7 +690,7 @@ int cellDmuxDisableEs(u32 esHandle) int cellDmuxResetEs(u32 esHandle) { - cellDmux.Warning("cellDmuxResetEs(esHandle=0x%x)", esHandle); + cellDmux.Log("cellDmuxResetEs(esHandle=0x%x)", esHandle); ElementaryStream* es; if (!Emu.GetIdManager().GetIDData(esHandle, es)) @@ -414,44 +699,17 @@ int cellDmuxResetEs(u32 esHandle) } DemuxerTask task(dmuxResetEs); - task.esHandle = esHandle; - task.au.es_ptr = es; + task.es.es = esHandle; + task.es.es_ptr = es; es->dmux->job.Push(task); return CELL_OK; } -int cellDmuxGetAu(u32 esHandle, const u32 auInfo_ptr_addr, u32 auSpecificInfo_ptr_addr) +int cellDmuxGetAu(u32 esHandle, mem32_t auInfo_ptr, mem32_t auSpecificInfo_ptr) { - cellDmux.Error("cellDmuxGetAu(esHandle=0x%x, auInfo_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)", - esHandle, auInfo_ptr_addr, auSpecificInfo_ptr_addr); - return CELL_OK; -} - -int cellDmuxPeekAu(u32 esHandle, const u32 auInfo_ptr_addr, u32 auSpecificInfo_ptr_addr) -{ - cellDmux.Error("cellDmuxPeekAu(esHandle=0x%x, auInfo_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)", - esHandle, auInfo_ptr_addr, auSpecificInfo_ptr_addr); - return CELL_OK; -} - -int cellDmuxGetAuEx(u32 esHandle, const u32 auInfoEx_ptr_addr, u32 auSpecificInfo_ptr_addr) -{ - cellDmux.Error("cellDmuxGetAuEx(esHandle=0x%x, auInfoEx_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)", - esHandle, auInfoEx_ptr_addr, auSpecificInfo_ptr_addr); - return CELL_OK; -} - -int cellDmuxPeekAuEx(u32 esHandle, const u32 auInfoEx_ptr_addr, u32 auSpecificInfo_ptr_addr) -{ - cellDmux.Error("cellDmuxPeekAuEx(esHandle=0x%x, auInfoEx_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)", - esHandle, auInfoEx_ptr_addr, auSpecificInfo_ptr_addr); - return CELL_OK; -} - -int cellDmuxReleaseAu(u32 esHandle) -{ - cellDmux.Warning("cellDmuxReleaseAu(esHandle=0x%x)", esHandle); + cellDmux.Log("cellDmuxGetAu(esHandle=0x%x, auInfo_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)", + esHandle, auInfo_ptr.GetAddr(), auSpecificInfo_ptr.GetAddr()); ElementaryStream* es; if (!Emu.GetIdManager().GetIDData(esHandle, es)) @@ -459,9 +717,125 @@ int cellDmuxReleaseAu(u32 esHandle) return CELL_DMUX_ERROR_ARG; } + if (!auInfo_ptr.IsGood() || !auSpecificInfo_ptr.IsGood()) + { + return CELL_DMUX_ERROR_FATAL; + } + + u32 info; + u32 spec; + if (!es->peek(info, true, spec, true)) + { + return CELL_DMUX_ERROR_EMPTY; + } + + auInfo_ptr = info; + auSpecificInfo_ptr = spec; + return CELL_OK; +} + +int cellDmuxPeekAu(u32 esHandle, mem32_t auInfo_ptr, mem32_t auSpecificInfo_ptr) +{ + cellDmux.Log("cellDmuxPeekAu(esHandle=0x%x, auInfo_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)", + esHandle, auInfo_ptr.GetAddr(), auSpecificInfo_ptr.GetAddr()); + + ElementaryStream* es; + if (!Emu.GetIdManager().GetIDData(esHandle, es)) + { + return CELL_DMUX_ERROR_ARG; + } + + if (!auInfo_ptr.IsGood() || !auSpecificInfo_ptr.IsGood()) + { + return CELL_DMUX_ERROR_FATAL; + } + + u32 info; + u32 spec; + if (!es->peek(info, true, spec, false)) + { + return CELL_DMUX_ERROR_EMPTY; + } + + auInfo_ptr = info; + auSpecificInfo_ptr = spec; + return CELL_OK; +} + +int cellDmuxGetAuEx(u32 esHandle, mem32_t auInfoEx_ptr, mem32_t auSpecificInfo_ptr) +{ + cellDmux.Log("cellDmuxGetAuEx(esHandle=0x%x, auInfoEx_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)", + esHandle, auInfoEx_ptr.GetAddr(), auSpecificInfo_ptr.GetAddr()); + + ElementaryStream* es; + if (!Emu.GetIdManager().GetIDData(esHandle, es)) + { + return CELL_DMUX_ERROR_ARG; + } + + if (!auInfoEx_ptr.IsGood() || !auSpecificInfo_ptr.IsGood()) + { + return CELL_DMUX_ERROR_FATAL; + } + + u32 info; + u32 spec; + if (!es->peek(info, false, spec, true)) + { + return CELL_DMUX_ERROR_EMPTY; + } + + auInfoEx_ptr = info; + auSpecificInfo_ptr = spec; + return CELL_OK; +} + +int cellDmuxPeekAuEx(u32 esHandle, mem32_t auInfoEx_ptr, mem32_t auSpecificInfo_ptr) +{ + cellDmux.Log("cellDmuxPeekAuEx(esHandle=0x%x, auInfoEx_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)", + esHandle, auInfoEx_ptr.GetAddr(), auSpecificInfo_ptr.GetAddr()); + + ElementaryStream* es; + if (!Emu.GetIdManager().GetIDData(esHandle, es)) + { + return CELL_DMUX_ERROR_ARG; + } + + if (!auInfoEx_ptr.IsGood() || !auSpecificInfo_ptr.IsGood()) + { + return CELL_DMUX_ERROR_FATAL; + } + + u32 info; + u32 spec; + if (!es->peek(info, false, spec, false)) + { + return CELL_DMUX_ERROR_EMPTY; + } + + auInfoEx_ptr = info; + auSpecificInfo_ptr = spec; + return CELL_OK; +} + +int cellDmuxReleaseAu(u32 esHandle) +{ + cellDmux.Log("cellDmuxReleaseAu(esHandle=0x%x)", esHandle); + + ElementaryStream* es; + if (!Emu.GetIdManager().GetIDData(esHandle, es)) + { + return CELL_DMUX_ERROR_ARG; + } + + if (!es->canrelease()) + { + return CELL_DMUX_ERROR_SEQ; + } + DemuxerTask task(dmuxReleaseAu); - task.esHandle = esHandle; - task.au.es_ptr = es; + task.es.es = esHandle; + task.es.es_ptr = es; es->dmux->job.Push(task); return CELL_OK; @@ -469,7 +843,7 @@ int cellDmuxReleaseAu(u32 esHandle) int cellDmuxFlushEs(u32 esHandle) { - cellDmux.Warning("cellDmuxFlushEs(esHandle=0x%x)", esHandle); + cellDmux.Log("cellDmuxFlushEs(esHandle=0x%x)", esHandle); ElementaryStream* es; if (!Emu.GetIdManager().GetIDData(esHandle, es)) @@ -478,8 +852,8 @@ int cellDmuxFlushEs(u32 esHandle) } DemuxerTask task(dmuxFlushEs); - task.esHandle = esHandle; - task.au.es_ptr = es; + task.es.es = esHandle; + task.es.es_ptr = es; es->dmux->job.Push(task); return CELL_OK; diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.h b/rpcs3/Emu/SysCalls/Modules/cellDmux.h index b2a3fe5ec8..2d0aa2ca38 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.h +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.h @@ -2,6 +2,9 @@ #include "Utilities/SQueue.h" +// align size or address to 128 +#define a128(x) ((x + 127) & (~127)) + // Error Codes enum { @@ -232,7 +235,7 @@ struct CellDmuxResource2 }; }; -typedef mem_func_ptr_t demuxerMsg, u32 cbArg_addr)> CellDmuxCbMsg; +typedef mem_func_ptr_t demuxerMsg, u32 cbArg_addr)> CellDmuxCbMsg; struct CellDmuxCb { @@ -241,7 +244,7 @@ struct CellDmuxCb be_t cbArg_addr; }; -typedef mem_func_ptr_t esMsg, u32 cbArg_addr)> CellDmuxCbEsMsg; +typedef mem_func_ptr_t esMsg, u32 cbArg_addr)> CellDmuxCbEsMsg; struct CellDmuxEsCb { @@ -293,16 +296,120 @@ struct CellDmuxAuInfoEx /* Demuxer Thread Classes */ -struct AccessUnit +enum +{ + /* http://dvd.sourceforge.net/dvdinfo/mpeghdrs.html */ + + PACKET_START_CODE_MASK = 0xffffff00, + PACKET_START_CODE_PREFIX = 0x00000100, + + USER_DATA_START_CODE = 0x000001b2, + SEQUENCE_START_CODE = 0x000001b3, + EXT_START_CODE = 0x000001b5, + SEQUENCE_END_CODE = 0x000001b7, + GOP_START_CODE = 0x000001b8, + ISO_11172_END_CODE = 0x000001b9, + PACK_START_CODE = 0x000001ba, + SYSTEM_HEADER_START_CODE = 0x000001bb, + PROGRAM_STREAM_MAP = 0x000001bc, + PRIVATE_STREAM_1 = 0x000001bd, + PADDING_STREAM = 0x000001be, + PRIVATE_STREAM_2 = 0x000001bf, +}; + +enum +{ + MAX_AU = 640 * 1024 + 128, // 640 KB +}; + +struct DemuxerStream { u32 addr; u32 size; - u32 ptsUpper; - u32 ptsLower; - u32 dtsUpper; - u32 dtsLower; - u64 userData; - bool isRap; + u64 userdata; + bool discontinuity; + + template + bool get(T& out) + { + if (sizeof(T) > size) return false; + + out = *mem_ptr_t(addr); + addr += sizeof(T); + size -= sizeof(T); + + return true; + } + + template + bool peek(T& out) + { + if (sizeof(T) > size) return false; + + out = *mem_ptr_t(addr); + return true; + } + + void skip(u32 count) + { + addr += count; + size = size > count ? size - count : 0; + } + + u32 get_ts(u8 c) + { + u16 v1, v2; get(v1); get(v2); + return (((u32) (c & 0x0E)) << 29) | ((v1 >> 1) << 15) | (v2 >> 1); + } + + u32 get_ts() + { + u8 v; get(v); + return get_ts(v); + } +}; + +struct PesHeader +{ + u32 pts; + u32 dts; + u8 ch; + u8 size; + + PesHeader(DemuxerStream& stream) + : pts(0) + , dts(0) + , ch(0) + , size(0) + { + u16 header; + stream.get(header); + stream.get(size); + if (size) + { + if (size < 10) + { + ConLog.Error("Unknown PesHeader size"); + Emu.Pause(); + } + u8 v; + stream.get(v); + if ((v & 0xF0) != 0x30) + { + ConLog.Error("Pts not found"); + Emu.Pause(); + } + pts = stream.get_ts(v); + stream.get(v); + if ((v & 0xF0) != 0x10) + { + ConLog.Error("Dts not found"); + Emu.Pause(); + } + dts = stream.get_ts(v); + stream.skip(size - 10); + } + } }; class ElementaryStream; @@ -311,32 +418,22 @@ enum DemuxerJobType { dmuxSetStream, dmuxResetStream, + dmuxResetStreamAndWaitDone, dmuxEnableEs, dmuxDisableEs, dmuxResetEs, - dmuxGetAu, - dmuxPeekAu, dmuxReleaseAu, dmuxFlushEs, dmuxClose, }; -#pragma pack(push, 1) struct DemuxerTask { DemuxerJobType type; union { - struct - { - u32 addr; - u64 userdata; - u32 size; - /*bool*/u32 discontinuity; - } stream; - - u32 esHandle; + DemuxerStream stream; struct { @@ -344,7 +441,7 @@ struct DemuxerTask u32 auInfo_ptr_addr; u32 auSpec_ptr_addr; ElementaryStream* es_ptr; - } au; + } es; }; DemuxerTask() @@ -356,8 +453,6 @@ struct DemuxerTask { } }; -static_assert(sizeof(DemuxerTask) == 24, ""); -#pragma pack(pop) class Demuxer { @@ -365,13 +460,16 @@ public: SQueue job; const u32 memAddr; const u32 memSize; - const CellDmuxCbMsg cbFunc; + const u32 cbFunc; const u32 cbArg; + u32 id; bool is_finished; + bool is_running; - Demuxer(u32 addr, u32 size, CellDmuxCbMsg func, u32 arg) + Demuxer(u32 addr, u32 size, u32 func, u32 arg) : is_finished(false) + , is_running(false) , memAddr(addr) , memSize(size) , cbFunc(func) @@ -382,19 +480,27 @@ public: class ElementaryStream { + SMutex mutex; + + u32 first_addr; // AU that will be released + u32 last_addr; // AU that is being written now + u32 last_size; // number of bytes written (after 128b header) + u32 peek_addr; // AU that will be obtained by GetAu(Ex)/PeekAu(Ex) + public: Demuxer* dmux; + u32 id; const u32 memAddr; const u32 memSize; const u32 fidMajor; const u32 fidMinor; const u32 sup1; const u32 sup2; - const CellDmuxCbEsMsg cbFunc; + const u32 cbFunc; const u32 cbArg; const u32 spec; //addr - ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, CellDmuxCbEsMsg cbFunc, u32 cbArg, u32 spec) + ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, u32 cbFunc, u32 cbArg, u32 spec) : dmux(dmux) , memAddr(addr) , memSize(size) @@ -405,6 +511,175 @@ public: , cbFunc(cbFunc) , cbArg(cbArg) , spec(spec) + , first_addr(0) + , peek_addr(0) + , last_addr(a128(addr)) + , last_size(0) { } + + volatile bool hasdata() + { + return last_size; + } + + bool isfull() // not multithread-safe + { + if (first_addr) + { + if (first_addr > last_addr) + { + return (first_addr - last_addr) < MAX_AU; + } + else + { + return (first_addr + MAX_AU) > (memAddr + memSize); + } + } + else + { + return false; + } + } + + void finish(DemuxerStream& stream) // not multithread-safe + { + SMutexLocker lock(mutex); + + if (!first_addr) + { + first_addr = last_addr; + } + if (!peek_addr) + { + peek_addr = last_addr; + } + u32 new_addr = a128(last_addr + 128 + last_size); + if ((new_addr + MAX_AU) > (memAddr + memSize)) + { + last_addr = memAddr; + } + else + { + last_addr = new_addr; + } + last_size = 0; + } + + void push(DemuxerStream& stream, u32 size, PesHeader& pes) + { + SMutexLocker lock(mutex); + if (isfull()) + { + ConLog.Error("ElementaryStream::push(): buffer is full"); + Emu.Pause(); + return; + } + + u32 data_addr = last_addr + 128 + last_size; + last_size += size; + memcpy(Memory + data_addr, Memory + stream.addr, size); + stream.skip(size); + + mem_ptr_t info(last_addr); + info->auAddr = last_addr + 128; + info->auSize = last_size; + if (pes.size) + { + info->dts.lower = pes.dts; + info->dts.upper = 0; + info->pts.lower = pes.pts; + info->pts.upper = 0; + info->isRap = false; // TODO: set valid value + info->reserved = 0; + info->userData = stream.userdata; + } + + mem_ptr_t tail(last_addr + sizeof(CellDmuxAuInfoEx)); + tail->reserved1 = 0; + + mem_ptr_t inf(last_addr + 64); + inf->auAddr = last_addr + 128; + inf->auSize = last_size; + if (pes.size) + { + inf->dtsLower = pes.dts; + inf->dtsUpper = 0; + inf->ptsLower = pes.pts; + inf->ptsUpper = 0; + inf->auMaxSize = 0; // ????? + inf->userData = stream.userdata; + } + } + + volatile bool canrelease() + { + return first_addr; + } + + void release() + { + SMutexLocker lock(mutex); + if (!canrelease()) + { + ConLog.Error("ElementaryStream::release(): buffer is empty"); + Emu.Pause(); + return; + } + + u32 size = a128(Memory.Read32(first_addr + 4) + 128); + u32 new_addr = first_addr + size; + if (peek_addr <= first_addr) peek_addr = new_addr; + if (new_addr == last_addr) + { + first_addr = 0; + } + else if ((new_addr + MAX_AU) > (memAddr + memSize)) + { + first_addr = memAddr; + } + else + { + first_addr = new_addr; + } + } + + bool peek(u32& out_data, bool no_ex, u32& out_spec, bool update_index) + { + SMutexLocker lock(mutex); + ConLog.Write("es::peek(): peek_addr=0x%x", peek_addr); + if (!peek_addr) return false; + + out_data = peek_addr; + out_spec = out_data + sizeof(CellDmuxAuInfoEx); + if (no_ex) out_data += 64; + + if (update_index) + { + u32 size = a128(Memory.Read32(peek_addr + 4) + 128); + u32 new_addr = peek_addr + size; + if (new_addr = last_addr) + { + peek_addr = 0; + } + else if ((new_addr + MAX_AU) > (memAddr + memSize)) + { + peek_addr = memAddr; + } + else + { + peek_addr = new_addr; + } + } + return true; + } + + void reset() + { + SMutexLocker lock(mutex); + first_addr = 0; + peek_addr = 0; + last_addr = a128(memAddr); + last_size = 0; + } }; \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Modules/cellPamf.cpp b/rpcs3/Emu/SysCalls/Modules/cellPamf.cpp index 1559788875..d0e95c310e 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPamf.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellPamf.cpp @@ -17,26 +17,16 @@ int pamfStreamTypeToEsFilterId(u8 type, u8 ch, mem_ptr_t pE switch (type) { case CELL_PAMF_STREAM_TYPE_AVC: - switch (ch) { - case 0: + if (ch < 16) { - pEsFilterId->filterIdMajor = 0xe0; //fake info + pEsFilterId->filterIdMajor = 0xe0 + ch; pEsFilterId->filterIdMinor = 0; pEsFilterId->supplementalInfo1 = 0x01; pEsFilterId->supplementalInfo2 = 0; } - break; - case 1: - { - pEsFilterId->filterIdMajor = 0xe1; - pEsFilterId->filterIdMinor = 0; - pEsFilterId->supplementalInfo1 = 0x01; - pEsFilterId->supplementalInfo2 = 0; - } - break; - default: - cellPamf.Error("*** TODO: pamfStreamTypeToEsFilterId: CELL_PAMF_STREAM_TYPE_AVC (ch=%d)", ch); + else + cellPamf.Error("pamfStreamTypeToEsFilterId: invalid CELL_PAMF_STREAM_TYPE_AVC channel (ch=%d)", ch); } break; case CELL_PAMF_STREAM_TYPE_ATRAC3PLUS: @@ -96,7 +86,7 @@ u8 pamfGetStreamType(mem_ptr_t pSelf, u8 stream) case 0x80: return CELL_PAMF_STREAM_TYPE_PAMF_LPCM; case 0xdd: return CELL_PAMF_STREAM_TYPE_USER_DATA; default: - cellPamf.Error("pamfGetStreamType: unsupported stream type found(0x%x)", + cellPamf.Error("pamfGetStreamType: (TODO) unsupported stream type found(0x%x)", pAddr->stream_headers[stream].type); return 0; } @@ -104,12 +94,16 @@ u8 pamfGetStreamType(mem_ptr_t pSelf, u8 stream) u8 pamfGetStreamChannel(mem_ptr_t pSelf, u8 stream) { - cellPamf.Warning("TODO: pamfGetStreamChannel"); //TODO: get stream channel correctly const mem_ptr_t pAddr(pSelf->pAddr); if ((pAddr->stream_headers[stream].type == 0x1b) && - (pAddr->stream_headers[stream].stream_id == 0xe1)) return 1; + (pAddr->stream_headers[stream].stream_id >= 0xe0) && + (pAddr->stream_headers[stream].stream_id <= 0xef)) + { + return pAddr->stream_headers[stream].stream_id - 0xe0; + } + cellPamf.Error("TODO: pamfGetStreamChannel (-> 0)"); return 0; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp index 74d3599841..0bf21a30cf 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp @@ -3,6 +3,11 @@ #include "Emu/SysCalls/SC_FUNC.h" #include "cellVdec.h" +extern "C" +{ +#include "libavformat\avformat.h" +} + void cellVdec_init(); Module cellVdec(0x0005, cellVdec_init); diff --git a/rpcs3/Emu/SysCalls/Modules/sys_fs.cpp b/rpcs3/Emu/SysCalls/Modules/sys_fs.cpp index 776dab9ee4..fdf46cad6f 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_fs.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sys_fs.cpp @@ -150,46 +150,67 @@ void fsAioRead(u32 fd, mem_ptr_t aio, int xid, mem_func_ptr_tGetPath().AfterFirst('/'); - u64 nbytes = (u64)aio->size; - const u32 buf_addr = (u32)aio->buf_addr; + u64 nbytes = aio->size; + u32 buf_addr = aio->buf_addr; - u64 res; - u32 error; + u32 res = 0; + u32 error = CELL_OK; - if(Memory.IsGoodAddr(buf_addr)) + vfsStream& file = *(vfsStream*)orig_file; + const u64 old_pos = file.Tell(); + file.Seek((u64)aio->offset); + + u32 count = nbytes; + if (nbytes != (u64)count) { - /* - //open the file again (to prevent access conflicts roughly) - vfsLocalFile file(path, vfsRead); - */ - vfsStream& file = *(vfsStream*)orig_file; - if(!Memory.IsGoodAddr(buf_addr, nbytes)) - { - MemoryBlock& block = Memory.GetMemByAddr(buf_addr); - nbytes = block.GetSize() - (buf_addr - block.GetStartAddr()); - } - - const u64 old_pos = file.Tell(); - file.Seek((u64)aio->offset); - res = nbytes ? file.Read(Memory.GetMemFromAddr(buf_addr), nbytes) : 0; - file.Seek(old_pos); - error = CELL_OK; + error = CELL_ENOMEM; + goto fin; } - else + + if (!Memory.IsGoodAddr(buf_addr)) { - res = 0; error = CELL_EFAULT; + goto fin; } - ConLog.Warning("*** fsAioRead(fd=%d, offset=0x%llx, buf_addr=0x%x, size=0x%x, res=0x%x, xid=0x%x [%s])", - fd, (u64)aio->offset, buf_addr, (u64)aio->size, res, xid, path.wx_str()); + if (count) if (u32 frag = buf_addr & 4095) // memory page fragment + { + u32 req = min(count, 4096 - frag); + u32 read = file.Read(Memory + buf_addr, req); + buf_addr += req; + res += read; + count -= req; + if (read < req) goto fin; + } + + for (u32 pages = count / 4096; pages > 0; pages--) // full pages + { + if (!Memory.IsGoodAddr(buf_addr)) goto fin; // ??? (probably EFAULT) + u32 read = file.Read(Memory + buf_addr, 4096); + buf_addr += 4096; + res += read; + count -= 4096; + if (read < 4096) goto fin; + } + + if (count) // last fragment + { + if (!Memory.IsGoodAddr(buf_addr)) goto fin; + res += file.Read(Memory + buf_addr, count); + } + +fin: + file.Seek(old_pos); + + ConLog.Warning("*** fsAioRead(fd=%d, offset=0x%llx, buf_addr=0x%x, size=0x%x, error=0x%x, res=0x%x, xid=0x%x [%s])", + fd, (u64)aio->offset, buf_addr, (u64)aio->size, error, res, xid, path.wx_str()); if (func) // start callback thread { func.async(aio, error, xid, res); } - CPUThread& thr = Emu.GetCallbackThread(); + /*CPUThread& thr = Emu.GetCallbackThread(); while (thr.IsAlive()) { Sleep(1); @@ -198,7 +219,7 @@ void fsAioRead(u32 fd, mem_ptr_t aio, int xid, mem_func_ptr_t attr) { - sys_cond.Log("sys_cond_create(cond_id_addr=0x%x, mutex_id=%d, attr_addr=%d)", + sys_cond.Log("sys_cond_create(cond_id_addr=0x%x, mutex_id=%d, attr_addr=0x%x)", cond_id.GetAddr(), mutex_id, attr.GetAddr()); if (!cond_id.IsGood() || !attr.IsGood()) diff --git a/rpcs3/Emu/SysCalls/lv2/SC_FileSystem.cpp b/rpcs3/Emu/SysCalls/lv2/SC_FileSystem.cpp index e688a46d74..64a9aa9e35 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_FileSystem.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_FileSystem.cpp @@ -94,16 +94,43 @@ int cellFsRead(u32 fd, u32 buf_addr, u64 nbytes, mem64_t nread) vfsStream* file; if(!sys_fs.CheckId(fd, file)) return CELL_ESRCH; - if(Memory.IsGoodAddr(buf_addr) && !Memory.IsGoodAddr(buf_addr, nbytes)) + if (nread.GetAddr() && !nread.IsGood()) return CELL_EFAULT; + + u32 res = 0; + u32 count = nbytes; + if (nbytes != (u64)count) return CELL_ENOMEM; + + if (!Memory.IsGoodAddr(buf_addr)) return CELL_EFAULT; + + if (count) if (u32 frag = buf_addr & 4095) // memory page fragment { - MemoryBlock& block = Memory.GetMemByAddr(buf_addr); - nbytes = block.GetSize() - (buf_addr - block.GetStartAddr()); + u32 req = min(count, 4096 - frag); + u32 read = file->Read(Memory + buf_addr, req); + buf_addr += req; + res += read; + count -= req; + if (read < req) goto fin; } - const u64 res = nbytes ? file->Read(Memory.GetMemFromAddr(buf_addr), nbytes) : 0; + for (u32 pages = count / 4096; pages > 0; pages--) // full pages + { + if (!Memory.IsGoodAddr(buf_addr)) goto fin; // ??? (probably EFAULT) + u32 read = file->Read(Memory + buf_addr, 4096); + buf_addr += 4096; + res += read; + count -= 4096; + if (read < 4096) goto fin; + } - if(nread.IsGood()) - nread = res; + if (count) // last fragment + { + if (!Memory.IsGoodAddr(buf_addr)) goto fin; + res += file->Read(Memory + buf_addr, count); + } + +fin: + + if (nread.GetAddr()) nread = res; // write value if not NULL return CELL_OK; } From 8048c70bc8af4008b9d9b449844c66d44bc906a8 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Wed, 26 Feb 2014 14:35:30 +0400 Subject: [PATCH 4/8] cond/lwcond fixed --- rpcs3/Emu/SysCalls/Modules/cellAudio.cpp | 21 ++- rpcs3/Emu/SysCalls/Modules/cellDmux.cpp | 3 +- rpcs3/Emu/SysCalls/lv2/SC_Condition.cpp | 227 +++++++++++++---------- rpcs3/Emu/SysCalls/lv2/SC_Lwcond.cpp | 47 ++++- 4 files changed, 186 insertions(+), 112 deletions(-) diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp index ecf52c7c49..e25cb587b9 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp @@ -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 - port.counter = m_config.counter; - port.tag++; // absolute index of block that will be read - index = (position + 1) % port.block; // write new value + { + 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) { diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp index b7b81bef2c..fe558d0ae8 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp @@ -149,7 +149,7 @@ u32 dmuxOpen(Demuxer* data) if (pes.size) { - //ConLog.Write("*** AVC AU detected (pts=0x%x, dts=0x%x)", pes.pts, pes.dts); + ConLog.Write("*** AVC AU detected (pts=0x%x, dts=0x%x)", pes.pts, pes.dts); } es.push(stream, len - pes.size - 3, pes); @@ -658,6 +658,7 @@ int cellDmuxEnableEs(u32 demuxerHandle, const mem_ptr_t esF 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); diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Condition.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Condition.cpp index 051653afdf..97555928d8 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Condition.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Condition.cpp @@ -28,7 +28,7 @@ int sys_cond_create(mem32_t cond_id, u32 mutex_id, mem_ptr_t 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); @@ -113,99 +243,4 @@ int sys_cond_wait(u32 cond_id, u64 timeout) 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(); - - 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; } \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Lwcond.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Lwcond.cpp index fc367333a3..e071687992 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Lwcond.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Lwcond.cpp @@ -84,14 +84,23 @@ int sys_lwcond_signal(mem_ptr_t lwcond) mem_ptr_t mutex(lwcond->lwmutex); be_t tid = GetCurrentPPUThread().GetId(); + bool was_locked = (mutex->owner.GetOwner() == tid); + if (be_t target = (mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? sq->pop_prio() : sq->pop())) { - if (mutex->owner.trylock(target) != SMR_OK) + if (!was_locked) { mutex->owner.lock(tid); mutex->recursive_count = 1; mutex->owner.unlock(tid, target); } + else + { + mutex->recursive_count = 1; + mutex->owner.unlock(tid, target); + mutex->owner.lock(tid); + mutex->recursive_count = 1; + } } if (Emu.IsStopped()) @@ -120,14 +129,23 @@ int sys_lwcond_signal_all(mem_ptr_t lwcond) mem_ptr_t mutex(lwcond->lwmutex); be_t tid = GetCurrentPPUThread().GetId(); + bool was_locked = (mutex->owner.GetOwner() == tid); + while (be_t target = (mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? sq->pop_prio() : sq->pop())) { - if (mutex->owner.trylock(target) != SMR_OK) + if (!was_locked) { mutex->owner.lock(tid); mutex->recursive_count = 1; mutex->owner.unlock(tid, target); } + else + { + mutex->recursive_count = 1; + mutex->owner.unlock(tid, target); + mutex->owner.lock(tid); + mutex->recursive_count = 1; + } } if (Emu.IsStopped()) @@ -153,6 +171,11 @@ int sys_lwcond_signal_to(mem_ptr_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 lwcond, u32 ppu_thread_id) mem_ptr_t mutex(lwcond->lwmutex); be_t tid = GetCurrentPPUThread().GetId(); - be_t target = ppu_thread_id; + bool was_locked = (mutex->owner.GetOwner() == tid); - if (mutex->owner.trylock(target) != SMR_OK) + be_t target = ppu_thread_id; { - mutex->owner.lock(tid); - mutex->recursive_count = 1; - mutex->owner.unlock(tid, target); + if (!was_locked) + { + mutex->owner.lock(tid); + mutex->recursive_count = 1; + mutex->owner.unlock(tid, target); + } + else + { + mutex->recursive_count = 1; + mutex->owner.unlock(tid, target); + mutex->owner.lock(tid); + mutex->recursive_count = 1; + } } if (Emu.IsStopped()) From 8b952bf98c195f3b5103e3b5e1e04cede9af66d2 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Wed, 26 Feb 2014 18:06:13 +0400 Subject: [PATCH 5/8] memcpy partially replaced Fixed one of exit issues --- rpcs3/Emu/Cell/MFC.h | 4 +- rpcs3/Emu/DbgConsole.cpp | 11 +- rpcs3/Emu/FS/vfsStreamMemory.cpp | 4 +- rpcs3/Emu/GS/RSXThread.cpp | 2 +- rpcs3/Emu/Memory/Memory.cpp | 10 +- rpcs3/Emu/Memory/Memory.h | 100 +++++++++++++++++++ rpcs3/Emu/SysCalls/Modules/cellDmux.h | 2 +- rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp | 2 +- rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp | 2 +- rpcs3/Emu/SysCalls/Modules/cellPamf.cpp | 13 +-- rpcs3/Emu/SysCalls/Modules/cellPngDec.cpp | 6 +- rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp | 2 +- rpcs3/Emu/SysCalls/lv2/SC_GCM.cpp | 2 +- rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp | 2 +- rpcs3/rpcs3.vcxproj | 1 + rpcs3/rpcs3.vcxproj.filters | 3 + 16 files changed, 136 insertions(+), 30 deletions(-) diff --git a/rpcs3/Emu/Cell/MFC.h b/rpcs3/Emu/Cell/MFC.h index ca8235c05a..6016924ae5 100644 --- a/rpcs3/Emu/Cell/MFC.h +++ b/rpcs3/Emu/Cell/MFC.h @@ -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: diff --git a/rpcs3/Emu/DbgConsole.cpp b/rpcs3/Emu/DbgConsole.cpp index 1b5858bcf6..3bdbbf4197 100644 --- a/rpcs3/Emu/DbgConsole.cpp +++ b/rpcs3/Emu/DbgConsole.cpp @@ -26,7 +26,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(); @@ -43,11 +50,11 @@ void DbgConsole::Task() { if(!m_dbg_buffer.HasNewPacket()) { - Sleep(1); if (Emu.IsStopped()) { break; } + Sleep(1); continue; } diff --git a/rpcs3/Emu/FS/vfsStreamMemory.cpp b/rpcs3/Emu/FS/vfsStreamMemory.cpp index 8bb08090e6..feecb51330 100644 --- a/rpcs3/Emu/FS/vfsStreamMemory.cpp +++ b/rpcs3/Emu/FS/vfsStreamMemory.cpp @@ -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); } diff --git a/rpcs3/Emu/GS/RSXThread.cpp b/rpcs3/Emu/GS/RSXThread.cpp index e46b81e32c..c16bc64cef 100644 --- a/rpcs3/Emu/GS/RSXThread.cpp +++ b/rpcs3/Emu/GS/RSXThread.cpp @@ -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; diff --git a/rpcs3/Emu/Memory/Memory.cpp b/rpcs3/Emu/Memory/Memory.cpp index df8178826e..8bf12506dc 100644 --- a/rpcs3/Emu/Memory/Memory.cpp +++ b/rpcs3/Emu/Memory/Memory.cpp @@ -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) diff --git a/rpcs3/Emu/Memory/Memory.h b/rpcs3/Emu/Memory/Memory.h index 5e9ae0e863..ea670cb846 100644 --- a/rpcs3/Emu/Memory/Memory.h +++ b/rpcs3/Emu/Memory/Memory.h @@ -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); diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.h b/rpcs3/Emu/SysCalls/Modules/cellDmux.h index 3379d18275..d83e1fc754 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.h +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.h @@ -565,7 +565,7 @@ public: u32 data_addr = last_addr + 128 + last_size; last_size += size; - memcpy(Memory + data_addr, Memory + stream.addr, size); + Memory.Copy(data_addr, stream.addr, size); stream.skip(size); mem_ptr_t info(last_addr); diff --git a/rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp b/rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp index 106725a816..b86104187c 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp @@ -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: diff --git a/rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp b/rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp index 3b78ca94da..45e3ac79fb 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp @@ -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: diff --git a/rpcs3/Emu/SysCalls/Modules/cellPamf.cpp b/rpcs3/Emu/SysCalls/Modules/cellPamf.cpp index d0e95c310e..6f5284e061 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPamf.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellPamf.cpp @@ -116,7 +116,7 @@ int cellPamfGetHeaderSize(mem_ptr_t 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; } @@ -129,12 +129,10 @@ int cellPamfGetHeaderSize2(mem_ptr_t 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 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)", @@ -144,10 +142,9 @@ int cellPamfGetStreamOffsetAndSize(mem_ptr_t 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; } @@ -171,7 +168,7 @@ int cellPamfReaderInitialize(mem_ptr_t pSelf, mem_ptr_tfileSize = ((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 diff --git a/rpcs3/Emu/SysCalls/Modules/cellPngDec.cpp b/rpcs3/Emu/SysCalls/Modules/cellPngDec.cpp index 35b1f8ab79..64d83d5b92 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPngDec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellPngDec.cpp @@ -91,7 +91,7 @@ int cellPngDecReadHeader(u32 mainHandle, u32 subHandle, mem_ptr_tsrc.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: diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp index 9a3c233faa..0d4042799c 100644 --- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp @@ -124,7 +124,7 @@ int sys_raw_spu_image_load(int id, mem_ptr_t 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); diff --git a/rpcs3/Emu/SysCalls/lv2/SC_GCM.cpp b/rpcs3/Emu/SysCalls/lv2/SC_GCM.cpp index 520883fecf..5206dc5627 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_GCM.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_GCM.cpp @@ -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; diff --git a/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp b/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp index 4b3c858264..02b898207e 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp @@ -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); diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index d4279bb665..8b9eee4f67 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -350,6 +350,7 @@ + diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index 366b3c5864..6f0a993820 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -603,5 +603,8 @@ Utilities + + Include + \ No newline at end of file From dbdae777800e1a8f9c0b7d015589837c933d2895 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Thu, 27 Feb 2014 22:25:32 +0400 Subject: [PATCH 6/8] Some errors fixed --- .gitignore | 2 + Utilities/Thread.cpp | 10 +- rpcs3/Emu/SysCalls/Modules/cellDmux.cpp | 33 ++- rpcs3/Emu/SysCalls/Modules/cellDmux.h | 55 +++-- rpcs3/Emu/SysCalls/Modules/cellVdec.cpp | 278 ++++++++++++++++++++++-- rpcs3/Emu/SysCalls/Modules/cellVdec.h | 116 +++++++++- rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp | 2 +- rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.h | 2 +- rpcs3/Gui/ConLog.cpp | 15 +- 9 files changed, 456 insertions(+), 57 deletions(-) diff --git a/.gitignore b/.gitignore index e3ceeff00f..cea62cad43 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,8 @@ /bin/VertexProgram.txt /bin/BreakPoints.dat /bin/textures +/bin/*.lib +/bin/*.exp rpcs3/git-version.h # Copyrighted files diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index 6bd33d6b86..b71fc5eeea 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -117,10 +117,12 @@ thread::thread() } void thread::start(std::function func) -{ // got a crash related with strings - m_thr = std::thread([this, func]() +{ + std::string name = m_name; + + m_thr = std::thread([func, name]() { - NamedThreadBase info(m_name); + NamedThreadBase info(name); g_tls_this_thread = &info; try @@ -130,7 +132,7 @@ void thread::start(std::function func) catch(...) { ConLog.Error("Crash :("); - std::terminate(); + //std::terminate(); } }); } diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp index fe558d0ae8..d11dfa1c52 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp @@ -18,7 +18,7 @@ void dmuxQueryEsAttr(u32 info_addr /* may be 0 */, const mem_ptr_t attr) { if (esFilterId->filterIdMajor >= 0xe0) - attr->memSize = 0x500000; // 0x45fa49 from ps3 + attr->memSize = 0x600000; // 0x45fa49 from ps3 else attr->memSize = 0x10000; // 0x73d9 from ps3 @@ -40,16 +40,13 @@ u32 dmuxOpen(Demuxer* data) DemuxerTask task; DemuxerStream stream; - /* - ElementaryStream* esAVC[16]; memset(esAVC, 0, sizeof(esAVC)); - ElementaryStream* esM2V[16]; memset(esM2V, 0, sizeof(esM2V)); - ElementaryStream* esDATA[16]; memset(esDATA, 0, sizeof(esDATA)); - ElementaryStream* esATRAX[48]; memset(esATRAX, 0, sizeof(esATRAX)); - ElementaryStream* esAC3[48]; memset(esAC3, 0, sizeof(esAC3)); - ElementaryStream* esLPCM[48]; memset(esLPCM, 0, sizeof(esLPCM)); - */ ElementaryStream* esALL[192]; memset(esALL, 0, sizeof(esALL)); - ElementaryStream** esAVC = &esALL[0]; + 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; @@ -124,6 +121,8 @@ u32 dmuxOpen(Demuxer* data) continue; } + DemuxerStream backup = stream; + stream.skip(4); stream.get(len); PesHeader pes(stream); @@ -136,6 +135,11 @@ u32 dmuxOpen(Demuxer* data) if (pes.size && es.hasdata()) // new AU detected { + /*if (es.hasunseen()) + { + stream = backup; + continue; + }*/ es.finish(stream); // callback mem_ptr_t esMsg(a128(dmux.memAddr) + (cb_add ^= 16)); @@ -149,7 +153,13 @@ u32 dmuxOpen(Demuxer* data) if (pes.size) { - ConLog.Write("*** AVC AU detected (pts=0x%x, dts=0x%x)", pes.pts, pes.dts); + ConLog.Write("*** AVC AU detected (pts=0x%llx, dts=0x%llx)", pes.pts, pes.dts); + } + + if (es.isfull()) + { + stream = backup; + continue; } es.push(stream, len - pes.size - 3, pes); @@ -173,6 +183,7 @@ u32 dmuxOpen(Demuxer* data) case 0x1dc: case 0x1dd: case 0x1de: case 0x1df: { // unknown + ConLog.Warning("Unknown MPEG stream found"); stream.skip(4); stream.get(len); stream.skip(len); diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.h b/rpcs3/Emu/SysCalls/Modules/cellDmux.h index d83e1fc754..a61918b01b 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.h +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.h @@ -321,7 +321,7 @@ struct DemuxerStream { if (sizeof(T) > size) return false; - out = *mem_ptr_t(addr); + out = *(T*)Memory.VirtualToRealAddr(addr); addr += sizeof(T); size -= sizeof(T); @@ -333,7 +333,7 @@ struct DemuxerStream { if (sizeof(T) > size) return false; - out = *mem_ptr_t(addr); + out = *(T*)Memory.VirtualToRealAddr(addr); return true; } @@ -343,13 +343,17 @@ struct DemuxerStream size = size > count ? size - count : 0; } - u32 get_ts(u8 c) + u64 get_ts(u8 c) { - u16 v1, v2; get(v1); get(v2); - return (((u32) (c & 0x0E)) << 29) | ((v1 >> 1) << 15) | (v2 >> 1); + 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); } - u32 get_ts() + u64 get_ts() { u8 v; get(v); return get_ts(v); @@ -358,8 +362,8 @@ struct DemuxerStream struct PesHeader { - u32 pts; - u32 dts; + u64 pts; + u64 dts; u8 ch; u8 size; @@ -505,6 +509,11 @@ public: { } + volatile bool hasunseen() + { + return peek_addr; + } + volatile bool hasdata() { return last_size; @@ -532,7 +541,7 @@ public: 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; @@ -556,6 +565,7 @@ public: 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"); @@ -565,7 +575,12 @@ public: u32 data_addr = last_addr + 128 + last_size; last_size += size; - Memory.Copy(data_addr, stream.addr, 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 info(last_addr); @@ -573,10 +588,10 @@ public: info->auSize = last_size; if (pes.size) { - info->dts.lower = pes.dts; - info->dts.upper = 0; - info->pts.lower = pes.pts; - info->pts.upper = 0; + info->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; @@ -590,10 +605,10 @@ public: inf->auSize = last_size; if (pes.size) { - inf->dtsLower = pes.dts; - inf->dtsUpper = 0; - inf->ptsLower = pes.pts; - inf->ptsUpper = 0; + 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; } @@ -607,6 +622,7 @@ public: 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"); @@ -634,7 +650,8 @@ public: bool peek(u32& out_data, bool no_ex, u32& out_spec, bool update_index) { SMutexLocker lock(mutex); - ConLog.Write("es::peek(): peek_addr=0x%x", peek_addr); + /*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; diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp index 0bf21a30cf..45cdf7f38a 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp @@ -1,81 +1,327 @@ #include "stdafx.h" #include "Emu/SysCalls/SysCalls.h" #include "Emu/SysCalls/SC_FUNC.h" -#include "cellVdec.h" +#include "cellPamf.h" extern "C" { -#include "libavformat\avformat.h" +#include "libavcodec\avcodec.h" } +#include "cellVdec.h" + void cellVdec_init(); Module cellVdec(0x0005, cellVdec_init); +u32 vdecQueryAttr(CellVdecCodecType type, u32 profile, u32 spec_addr /* may be 0 */, mem_ptr_t 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 = 64 * 1024 * 1024; + attr->cmdDepth = 15; + 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.job.Pop(task)) + { + break; + } + + switch (task.type) + { + case vdecStartSeq: + { + // TODO: reset data + ConLog.Warning("vdecStartSeq()"); + vdec.is_running = true; + } + break; + + case vdecEndSeq: + { + // TODO: send callback + ConLog.Warning("vdecEndSeq()"); + vdec.is_running = false; + } + break; + + case vdecDecodeAu: + { + struct vdecPacket : AVPacket + { + vdecPacket(u32 size) + { + av_new_packet(this, size + FF_INPUT_BUFFER_PADDING_SIZE); + memset(data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE); + } + + ~vdecPacket() + { + av_free_packet(this); + } + + } au(task.size); + + au.pts = task.pts; + au.dts = task.dts; + + if (task.mode != CELL_VDEC_DEC_MODE_NORMAL) + { + ConLog.Error("vdecDecodeAu: unsupported decoding mode(%d)", task.mode); + break; + } + + 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; + } + + int got_picture = 0; + + int decode = avcodec_decode_video2(vdec.ctx, vdec.frame, &got_picture, &au); + if (decode < 0) + { + ConLog.Error("vdecDecodeAu: AU decoding error(%d)", decode); + break; + } + + ConLog.Write("Frame decoded (%d)", decode); + } + break; + + case vdecClose: + { + vdec.is_finished = true; + ConLog.Write("Video Decoder exit"); + return; + } + + case vdecSetFrameRate: + { + ConLog.Error("TODO: vdecSetFrameRate(%d)", task.frc); + } + + 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 type, mem_ptr_t 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 type, mem_ptr_t 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 type, const mem_ptr_t res, const mem_ptr_t 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 type, const mem_ptr_t res, const mem_ptr_t 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 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 format, u32 out_addr) { - cellVdec.Error("cellVdecGetPicture(handle=0x%x, format_addr=0x%x, out_addr=0x%x)", handle, format.GetAddr(), out_addr); + cellVdec.Error("cellVdecGetPicture(handle=%d, format_addr=0x%x, out_addr=0x%x)", handle, format.GetAddr(), out_addr); return CELL_OK; } int cellVdecGetPicItem(u32 handle, const u32 picItem_ptr_addr) { - cellVdec.Error("cellVdecGetPicItem(handle=0x%x, picItem_ptr_addr=0x%x)", handle, picItem_ptr_addr); + cellVdec.Error("cellVdecGetPicItem(handle=%d, picItem_ptr_addr=0x%x)", handle, picItem_ptr_addr); 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; } @@ -92,4 +338,6 @@ void cellVdec_init() cellVdec.AddFunc(0x807c861a, cellVdecGetPicture); cellVdec.AddFunc(0x17c702b9, cellVdecGetPicItem); cellVdec.AddFunc(0xe13ef6fc, cellVdecSetFrameRate); + + avcodec_register_all(); } \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.h b/rpcs3/Emu/SysCalls/Modules/cellVdec.h index 771924fea5..69de466bca 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.h +++ b/rpcs3/Emu/SysCalls/Modules/cellVdec.h @@ -1,5 +1,6 @@ #pragma once -#include "cellPamf.h" + +#include "Utilities/SQueue.h" // Error Codes enum @@ -30,7 +31,7 @@ enum CellVdecMsgType }; // Decoder Operation Mode -enum CellVdecDecodeMode +enum CellVdecDecodeMode : u32 { CELL_VDEC_DEC_MODE_NORMAL, CELL_VDEC_DEC_MODE_B_SKIP, @@ -164,11 +165,13 @@ struct CellVdecPicFormat u8 alpha; }; +typedef mem_func_ptr_t CellVdecCbMsg; + // Callback Function Information struct CellVdecCb { - be_t> cbFunc; - be_t cbArg_addr; + be_t cbFunc; + be_t cbArg; }; // Max CC Data Length @@ -634,4 +637,109 @@ struct CellVdecMpeg2Info u8 ccDataLength[2]; u8 ccData[2][128]; be_t 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() + { + } +}; + +class VideoDecoder +{ +public: + SQueue job; + u32 id; + volatile bool is_running; + volatile bool is_finished; + + AVCodec* codec; + AVCodecContext* ctx; + AVFrame* frame; + + const u32 type; + const u32 profile; + const u32 memAddr; + const u32 memSize; + const u32 cbFunc; + const u32 cbArg; + + VideoDecoder(u32 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) + { + 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; + } + if (int err = avcodec_open2(ctx, codec, NULL)) // 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; + } + } + + ~VideoDecoder() + { + if (frame) av_frame_free(&frame); + if (ctx) + { + avcodec_close(ctx); + av_free(ctx); + } + } }; \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp index a2a7c2e4d3..2a42841c31 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp @@ -28,7 +28,7 @@ int sys_lwmutex_create(mem_ptr_t lwmutex, mem_ptr_tattribute = attr->attr_protocol | attr->attr_recursive; - lwmutex->all_info() = 0; + lwmutex->all_info() = ~0; lwmutex->mutex.initialize(); //lwmutex->waiter = lwmutex->owner.GetOwner(); lwmutex->pad = 0; diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.h b/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.h index 4acde466bd..971363a92f 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.h +++ b/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.h @@ -65,7 +65,7 @@ struct SleepQueue struct sys_lwmutex_t { - /* volatile */ SMutexBase, 0xffffffff, 0> mutex; + /* volatile */ SMutexBase, ~0, 0> mutex; /* volatile */ be_t waiter; // not used u64 &all_info(){return *(reinterpret_cast(this));} be_t attribute; diff --git a/rpcs3/Gui/ConLog.cpp b/rpcs3/Gui/ConLog.cpp index 33a324dd9e..7b5ee9300c 100644 --- a/rpcs3/Gui/ConLog.cpp +++ b/rpcs3/Gui/ConLog.cpp @@ -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(); From 17fa60c31c05bd3931565359d90624b5cef05d4d Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Sat, 1 Mar 2014 12:38:50 +0400 Subject: [PATCH 7/8] Vpost draft --- rpcs3/Emu/FS/vfsDir.cpp | 2 +- rpcs3/Emu/SysCalls/Modules/cellDmux.cpp | 38 +++- rpcs3/Emu/SysCalls/Modules/cellDmux.h | 17 +- rpcs3/Emu/SysCalls/Modules/cellVdec.cpp | 228 ++++++++++++++++++++++- rpcs3/Emu/SysCalls/Modules/cellVdec.h | 26 ++- rpcs3/Emu/SysCalls/Modules/cellVpost.cpp | 161 +++++++++++++++- rpcs3/Emu/SysCalls/Modules/cellVpost.h | 11 ++ rpcs3/Gui/MemoryViewer.cpp | 4 +- 8 files changed, 451 insertions(+), 36 deletions(-) diff --git a/rpcs3/Emu/FS/vfsDir.cpp b/rpcs3/Emu/FS/vfsDir.cpp index 0d165c6ca5..8fcb8d4bde 100644 --- a/rpcs3/Emu/FS/vfsDir.cpp +++ b/rpcs3/Emu/FS/vfsDir.cpp @@ -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& vfsDir::GetEntries() const diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp index d11dfa1c52..99346a4252 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp @@ -85,9 +85,15 @@ u32 dmuxOpen(Demuxer* data) break; case PADDING_STREAM: + { + stream.skip(4); + stream.get(len); + stream.skip(len); + } + break; + case PRIVATE_STREAM_2: { - // unknown stream.skip(4); stream.get(len); stream.skip(len); @@ -127,19 +133,19 @@ u32 dmuxOpen(Demuxer* data) stream.get(len); PesHeader pes(stream); - if (!pes.size && !es.hasdata()) // fatal error + if (!pes.new_au && !es.hasdata()) // fatal error { ConLog.Error("PES not found"); return; } - if (pes.size && es.hasdata()) // new AU detected + if (pes.new_au && es.hasdata()) // new AU detected { - /*if (es.hasunseen()) + if (es.hasunseen()) // hack, probably useless { stream = backup; continue; - }*/ + } es.finish(stream); // callback mem_ptr_t esMsg(a128(dmux.memAddr) + (cb_add ^= 16)); @@ -151,7 +157,7 @@ u32 dmuxOpen(Demuxer* data) cb.Branch(false); } - if (pes.size) + if (pes.new_au) { ConLog.Write("*** AVC AU detected (pts=0x%llx, dts=0x%llx)", pes.pts, pes.dts); } @@ -161,7 +167,6 @@ u32 dmuxOpen(Demuxer* data) stream = backup; continue; } - es.push(stream, len - pes.size - 3, pes); } else @@ -217,6 +222,19 @@ task: { 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); @@ -832,7 +850,9 @@ int cellDmuxPeekAuEx(u32 esHandle, mem32_t auInfoEx_ptr, mem32_t auSpecificInfo_ int cellDmuxReleaseAu(u32 esHandle) { - cellDmux.Log("cellDmuxReleaseAu(esHandle=0x%x)", esHandle); + cellDmux.Warning("(disabled) cellDmuxReleaseAu(esHandle=0x%x)", esHandle); + + return CELL_OK; ElementaryStream* es; if (!Emu.GetIdManager().GetIDData(esHandle, es)) @@ -842,7 +862,9 @@ int cellDmuxReleaseAu(u32 esHandle) if (!es->canrelease()) { + cellDmux.Error("cellDmuxReleaseAu: no AU"); return CELL_DMUX_ERROR_SEQ; + //return CELL_OK; } DemuxerTask task(dmuxReleaseAu); diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.h b/rpcs3/Emu/SysCalls/Modules/cellDmux.h index a61918b01b..fad19dd63a 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.h +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.h @@ -366,23 +366,28 @@ struct PesHeader u64 dts; u8 ch; u8 size; + bool new_au; PesHeader(DemuxerStream& stream) - : pts(0) - , dts(0) + : pts(0xffffffffffffffff) + , dts(0xffffffffffffffff) , ch(0) , size(0) + , new_au(false) { u16 header; stream.get(header); stream.get(size); + new_au = true; if (size) { + //ConLog.Write(">>>>> Pes Header (size=%d)", size); if (size < 10) { - ConLog.Error("Unknown PesHeader size"); - Emu.Pause(); + stream.skip(size); + return; } + new_au = true; u8 v; stream.get(v); if ((v & 0xF0) != 0x30) @@ -454,8 +459,8 @@ public: const u32 cbFunc; const u32 cbArg; u32 id; - bool is_finished; - bool is_running; + volatile bool is_finished; + volatile bool is_running; Demuxer(u32 addr, u32 size, u32 func, u32 arg) diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp index 45cdf7f38a..2ded407750 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp @@ -6,6 +6,7 @@ extern "C" { #include "libavcodec\avcodec.h" +#include "libavutil\imgutils.h" } #include "cellVdec.h" @@ -26,8 +27,8 @@ u32 vdecQueryAttr(CellVdecCodecType type, u32 profile, u32 spec_addr /* may be 0 // TODO: check values attr->decoderVerLower = 0x280000; // from dmux attr->decoderVerUpper = 0x260000; - attr->memSize = 64 * 1024 * 1024; - attr->cmdDepth = 15; + attr->memSize = 4 * 1024 * 1024; + attr->cmdDepth = 16; return CELL_OK; } @@ -59,6 +60,12 @@ u32 vdecOpen(VideoDecoder* data) continue; } + if (vdec.has_picture) // hack + { + Sleep(1); + continue; + } + if (!vdec.job.Pop(task)) { break; @@ -76,7 +83,10 @@ u32 vdecOpen(VideoDecoder* data) case vdecEndSeq: { - // TODO: send callback + 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; } @@ -90,6 +100,7 @@ u32 vdecOpen(VideoDecoder* data) { av_new_packet(this, size + FF_INPUT_BUFFER_PADDING_SIZE); memset(data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE); + this->size -= FF_INPUT_BUFFER_PADDING_SIZE; // ???????????????????? } ~vdecPacket() @@ -99,8 +110,13 @@ u32 vdecOpen(VideoDecoder* data) } au(task.size); - au.pts = task.pts; - au.dts = task.dts; + if (task.pts || task.dts) + { + vdec.pts = task.pts; + vdec.dts = task.dts; + } + au.pts = vdec.pts; + au.dts = vdec.dts; if (task.mode != CELL_VDEC_DEC_MODE_NORMAL) { @@ -116,6 +132,9 @@ u32 vdecOpen(VideoDecoder* data) int got_picture = 0; + //vdec.ctx->flags |= CODEC_FLAG_TRUNCATED; + //vdec.ctx->flags2 |= CODEC_FLAG2_CHUNKS; + int decode = avcodec_decode_video2(vdec.ctx, vdec.frame, &got_picture, &au); if (decode < 0) { @@ -123,7 +142,48 @@ u32 vdecOpen(VideoDecoder* data) break; } - ConLog.Write("Frame decoded (%d)", decode); + 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); + + if (got_picture) + { + ConLog.Write("got_picture (%d, vdec: pts=0x%llx, dts=0x%llx)", got_picture, vdec.pts, vdec.dts); + + vdec.pts += 3003; + vdec.dts += 3003; + + /*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.dts = task.dts; + vdec.pts = task.pts; + 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); + } } break; @@ -137,6 +197,7 @@ u32 vdecOpen(VideoDecoder* data) case vdecSetFrameRate: { ConLog.Error("TODO: vdecSetFrameRate(%d)", task.frc); + return; } default: @@ -297,13 +358,162 @@ int cellVdecDecodeAu(u32 handle, CellVdecDecodeMode mode, const mem_ptr_t format, u32 out_addr) { - cellVdec.Error("cellVdecGetPicture(handle=%d, 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; + } + + AVFrame& frame = *vdec->frame; + + u8* buf = (u8*)malloc(vdec->buf_size); + if (!buf) + { + 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, const u32 picItem_ptr_addr) +int cellVdecGetPicItem(u32 handle, mem32_t picItem_ptr) { - cellVdec.Error("cellVdecGetPicItem(handle=%d, picItem_ptr_addr=0x%x)", handle, picItem_ptr_addr); + 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 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 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; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.h b/rpcs3/Emu/SysCalls/Modules/cellVdec.h index 69de466bca..e1c37aa250 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.h +++ b/rpcs3/Emu/SysCalls/Modules/cellVdec.h @@ -2,6 +2,8 @@ #include "Utilities/SQueue.h" +#define a128(x) ((x + 127) & (~127)) + // Error Codes enum { @@ -341,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 nalUnitPresentFlags; + be_t nalUnitPresentFlags; u8 ccDataLength[2]; u8 ccData[2][CELL_VDEC_AVC_CCD_MAX]; be_t reserved[2]; }; +const int sz = sizeof(CellVdecAvcInfo); + // DIVX Profile enum DIVX_level : u8 { @@ -686,15 +690,21 @@ public: AVCodec* codec; AVCodecContext* ctx; AVFrame* frame; + AVDictionary* opts; + u32 buf_size; + u64 pts; + u64 dts; + u64 userdata; + volatile bool has_picture; - const u32 type; + const CellVdecCodecType type; const u32 profile; const u32 memAddr; const u32 memSize; const u32 cbFunc; const u32 cbArg; - VideoDecoder(u32 type, u32 profile, u32 addr, u32 size, u32 func, u32 arg) + VideoDecoder(CellVdecCodecType type, u32 profile, u32 addr, u32 size, u32 func, u32 arg) : type(type) , profile(profile) , memAddr(addr) @@ -703,6 +713,7 @@ public: , cbArg(arg) , is_finished(false) , is_running(false) + , has_picture(false) { codec = avcodec_find_decoder(AV_CODEC_ID_H264); if (!codec) @@ -718,7 +729,9 @@ public: Emu.Pause(); return; } - if (int err = avcodec_open2(ctx, codec, NULL)) // TODO: not multithread safe + 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(); @@ -731,6 +744,8 @@ public: Emu.Pause(); return; } + //memset(&out_data, 0, sizeof(out_data)); + //memset(&linesize, 0, sizeof(linesize)); } ~VideoDecoder() @@ -741,5 +756,6 @@ public: avcodec_close(ctx); av_free(ctx); } + //if (out_data[0]) av_freep(out_data[0]); } }; \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Modules/cellVpost.cpp b/rpcs3/Emu/SysCalls/Modules/cellVpost.cpp index 0154af54c1..8073080424 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVpost.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellVpost.cpp @@ -8,35 +8,186 @@ Module cellVpost(0x0008, cellVpost_init); int cellVpostQueryAttr(const mem_ptr_t cfgParam, mem_ptr_t 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 cfgParam, const mem_ptr_t 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 cfgParam, const mem_ptr_t 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 ctrlParam, u32 outPicBuff_addr, mem_ptr_t 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; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellVpost.h b/rpcs3/Emu/SysCalls/Modules/cellVpost.h index 3e54a55050..ab54a695fa 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVpost.h +++ b/rpcs3/Emu/SysCalls/Modules/cellVpost.h @@ -315,3 +315,14 @@ struct CellVpostPictureInfo be_t reserved1; be_t reserved2; }; + +class VpostInstance +{ +public: + const bool to_rgba; + + VpostInstance(bool rgba) + : to_rgba(rgba) + { + } +}; \ No newline at end of file diff --git a/rpcs3/Gui/MemoryViewer.cpp b/rpcs3/Gui/MemoryViewer.cpp index 41d2fc85fb..90e36a0175 100644 --- a/rpcs3/Gui/MemoryViewer.cpp +++ b/rpcs3/Gui/MemoryViewer.cpp @@ -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); From 9e62b330b1d2c9e27904fdaf1d3b88fc27eea957 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Sun, 2 Mar 2014 03:50:47 +0400 Subject: [PATCH 8/8] I cannot do anything --- Utilities/SMutex.h | 1 + rpcs3/Emu/SysCalls/Modules/cellAudio.cpp | 6 +- rpcs3/Emu/SysCalls/Modules/cellDmux.cpp | 1 + rpcs3/Emu/SysCalls/Modules/cellDmux.h | 5 +- rpcs3/Emu/SysCalls/Modules/cellVdec.cpp | 87 +++++++++++++++++------- rpcs3/Emu/SysCalls/Modules/cellVdec.h | 32 +++++++++ 6 files changed, 103 insertions(+), 29 deletions(-) diff --git a/Utilities/SMutex.h b/Utilities/SMutex.h index 8a2b6fb941..b92d67e614 100644 --- a/Utilities/SMutex.h +++ b/Utilities/SMutex.h @@ -26,6 +26,7 @@ template > class SMutexBase { + static_assert(sizeof(T) == sizeof(std::atomic), "Invalid SMutexBase type"); std::atomic owner; public: diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp index e25cb587b9..8c5915d6ff 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp @@ -714,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; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp index 99346a4252..aadfaf1a85 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp @@ -167,6 +167,7 @@ u32 dmuxOpen(Demuxer* data) stream = backup; continue; } + //stream = backup; es.push(stream, len - pes.size - 3, pes); } else diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.h b/rpcs3/Emu/SysCalls/Modules/cellDmux.h index fad19dd63a..51e805ab07 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.h +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.h @@ -373,12 +373,11 @@ struct PesHeader , dts(0xffffffffffffffff) , ch(0) , size(0) - , new_au(false) + , new_au(true) { u16 header; stream.get(header); stream.get(size); - new_au = true; if (size) { //ConLog.Write(">>>>> Pes Header (size=%d)", size); @@ -571,7 +570,7 @@ public: { 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()) + if (isfull()) { ConLog.Error("ElementaryStream::push(): buffer is full"); Emu.Pause(); diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp index 2ded407750..c0dd39dcfe 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp @@ -6,6 +6,7 @@ extern "C" { #include "libavcodec\avcodec.h" +#include "libavformat\avformat.h" #include "libavutil\imgutils.h" } @@ -14,6 +15,29 @@ extern "C" 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 attr) { switch (type) // TODO: check profile levels @@ -98,42 +122,66 @@ u32 vdecOpen(VideoDecoder* data) { vdecPacket(u32 size) { - av_new_packet(this, size + FF_INPUT_BUFFER_PADDING_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 -= FF_INPUT_BUFFER_PADDING_SIZE; // ???????????????????? + this->size = size + FF_INPUT_BUFFER_PADDING_SIZE; } ~vdecPacket() { - av_free_packet(this); + av_free(data); + //av_free_packet(this); } } au(task.size); - if (task.pts || task.dts) + 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; } - au.pts = vdec.pts; - au.dts = vdec.dts; - + 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) @@ -141,23 +189,11 @@ u32 vdecOpen(VideoDecoder* data) ConLog.Error("vdecDecodeAu: AU decoding error(%d)", decode); break; } - - 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); if (got_picture) { ConLog.Write("got_picture (%d, vdec: pts=0x%llx, dts=0x%llx)", got_picture, vdec.pts, vdec.dts); - - vdec.pts += 3003; - vdec.dts += 3003; - + /*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); @@ -167,15 +203,13 @@ u32 vdecOpen(VideoDecoder* data) 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.dts = task.dts; - vdec.pts = task.pts; vdec.userdata = task.userData; vdec.has_picture = true; @@ -184,6 +218,13 @@ u32 vdecOpen(VideoDecoder* data) 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; diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.h b/rpcs3/Emu/SysCalls/Modules/cellVdec.h index e1c37aa250..f2ca2320fd 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.h +++ b/rpcs3/Emu/SysCalls/Modules/cellVdec.h @@ -679,6 +679,8 @@ struct VdecTask } }; +int vdecRead(void* opaque, u8* buf, int buf_size); + class VideoDecoder { public: @@ -689,14 +691,23 @@ public: 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; @@ -714,6 +725,7 @@ public: , is_finished(false) , is_running(false) , has_picture(false) + , pos(0) { codec = avcodec_find_decoder(AV_CODEC_ID_H264); if (!codec) @@ -744,12 +756,32 @@ public: 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) {