mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-25 12:12:50 +01:00
cellAdec draft
This commit is contained in:
parent
c978fe377d
commit
c064c701e2
@ -19,11 +19,6 @@ public:
|
|||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (Emu.IsStopped())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_mutex.GetOwner() == m_mutex.GetDeadValue())
|
if (m_mutex.GetOwner() == m_mutex.GetDeadValue())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -31,6 +26,10 @@ public:
|
|||||||
|
|
||||||
if (m_count >= SQSize)
|
if (m_count >= SQSize)
|
||||||
{
|
{
|
||||||
|
if (Emu.IsStopped())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
Sleep(1);
|
Sleep(1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -51,11 +50,6 @@ public:
|
|||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (Emu.IsStopped())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_mutex.GetOwner() == m_mutex.GetDeadValue())
|
if (m_mutex.GetOwner() == m_mutex.GetDeadValue())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -63,6 +57,10 @@ public:
|
|||||||
|
|
||||||
if (!m_count)
|
if (!m_count)
|
||||||
{
|
{
|
||||||
|
if (Emu.IsStopped())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
Sleep(1);
|
Sleep(1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -96,4 +94,10 @@ public:
|
|||||||
SMutexLocker lock(m_mutex);
|
SMutexLocker lock(m_mutex);
|
||||||
m_count = 0;
|
m_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
T& Peek(u32 pos = 0)
|
||||||
|
{
|
||||||
|
SMutexLocker lock(m_mutex);
|
||||||
|
return m_data[(m_pos + pos) % SQSize];
|
||||||
|
}
|
||||||
};
|
};
|
@ -1,64 +1,226 @@
|
|||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "Emu/SysCalls/SysCalls.h"
|
#include "Emu/SysCalls/SysCalls.h"
|
||||||
#include "Emu/SysCalls/SC_FUNC.h"
|
#include "Emu/SysCalls/SC_FUNC.h"
|
||||||
|
#include "cellPamf.h"
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#include "libavcodec\avcodec.h"
|
||||||
|
#include "libavformat\avformat.h"
|
||||||
|
}
|
||||||
|
|
||||||
#include "cellAdec.h"
|
#include "cellAdec.h"
|
||||||
|
|
||||||
void cellAdec_init();
|
void cellAdec_init();
|
||||||
Module cellAdec(0x0006, cellAdec_init);
|
Module cellAdec(0x0006, cellAdec_init);
|
||||||
|
|
||||||
|
u32 adecOpen(AudioDecoder* data)
|
||||||
|
{
|
||||||
|
AudioDecoder& adec = *data;
|
||||||
|
|
||||||
|
u32 adec_id = cellAdec.GetNewId(data);
|
||||||
|
|
||||||
|
adec.id = adec_id;
|
||||||
|
|
||||||
|
thread t("Audio Decoder[" + std::to_string(adec_id) + "] Thread", [&]()
|
||||||
|
{
|
||||||
|
ConLog.Write("Audio Decoder enter()");
|
||||||
|
|
||||||
|
AdecTask task;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (Emu.IsStopped())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (adec.job.IsEmpty() && adec.is_running)
|
||||||
|
{
|
||||||
|
Sleep(1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (adec.frames.GetCount() >= 50)
|
||||||
|
{
|
||||||
|
Sleep(1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!adec.job.Pop(task))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (task.type)
|
||||||
|
{
|
||||||
|
case adecStartSeq:
|
||||||
|
{
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case adecEndSeq:
|
||||||
|
{
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case adecDecodeAu:
|
||||||
|
{
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case adecClose:
|
||||||
|
{
|
||||||
|
adec.is_finished = true;
|
||||||
|
ConLog.Write("Audio Decoder exit");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
ConLog.Error("Audio Decoder error: unknown task(%d)", task.type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ConLog.Warning("Audio Decoder aborted");
|
||||||
|
});
|
||||||
|
|
||||||
|
t.detach();
|
||||||
|
|
||||||
|
return adec_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool adecCheckType(AudioCodecType type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case CELL_ADEC_TYPE_ATRACX: ConLog.Write("*** (???) type: ATRAC3plus"); break;
|
||||||
|
case CELL_ADEC_TYPE_ATRACX_2CH: ConLog.Write("*** type: ATRAC3plus 2ch"); break;
|
||||||
|
|
||||||
|
case CELL_ADEC_TYPE_ATRACX_6CH:
|
||||||
|
case CELL_ADEC_TYPE_ATRACX_8CH:
|
||||||
|
case CELL_ADEC_TYPE_LPCM_PAMF:
|
||||||
|
case CELL_ADEC_TYPE_AC3:
|
||||||
|
case CELL_ADEC_TYPE_MP3:
|
||||||
|
case CELL_ADEC_TYPE_ATRAC3:
|
||||||
|
case CELL_ADEC_TYPE_MPEG_L2:
|
||||||
|
case CELL_ADEC_TYPE_CELP:
|
||||||
|
case CELL_ADEC_TYPE_M4AAC:
|
||||||
|
case CELL_ADEC_TYPE_CELP8:
|
||||||
|
cellAdec.Error("Unimplemented audio codec type (%d)", type);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
int cellAdecQueryAttr(mem_ptr_t<CellAdecType> type, mem_ptr_t<CellAdecAttr> attr)
|
int cellAdecQueryAttr(mem_ptr_t<CellAdecType> type, mem_ptr_t<CellAdecAttr> attr)
|
||||||
{
|
{
|
||||||
cellAdec.Error("cellAdecQueryAttr(type_addr=0x%x, attr_addr=0x%x)", type.GetAddr(), attr.GetAddr());
|
cellAdec.Warning("cellAdecQueryAttr(type_addr=0x%x, attr_addr=0x%x)", type.GetAddr(), attr.GetAddr());
|
||||||
|
|
||||||
|
if (!type.IsGood() || !attr.IsGood())
|
||||||
|
{
|
||||||
|
return CELL_ADEC_ERROR_FATAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!adecCheckType(type->audioCodecType)) return CELL_ADEC_ERROR_ARG;
|
||||||
|
|
||||||
|
// TODO: check values
|
||||||
|
attr->adecVerLower = 0x280000; // from dmux
|
||||||
|
attr->adecVerUpper = 0x260000;
|
||||||
|
attr->workMemSize = 4 * 1024 * 1024;
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cellAdecOpen(mem_ptr_t<CellAdecType> type, mem_ptr_t<CellAdecResource> res, mem_ptr_t<CellAdecCb> cb, mem32_t handle)
|
int cellAdecOpen(mem_ptr_t<CellAdecType> type, mem_ptr_t<CellAdecResource> res, mem_ptr_t<CellAdecCb> cb, mem32_t handle)
|
||||||
{
|
{
|
||||||
cellAdec.Error("cellAdecOpen(type_addr=0x%x, res_addr=0x%x, cb_addr=0x%x, handle_addr=0x%x)",
|
cellAdec.Warning("cellAdecOpen(type_addr=0x%x, res_addr=0x%x, cb_addr=0x%x, handle_addr=0x%x)",
|
||||||
type.GetAddr(), res.GetAddr(), cb.GetAddr(), handle.GetAddr());
|
type.GetAddr(), res.GetAddr(), cb.GetAddr(), handle.GetAddr());
|
||||||
|
|
||||||
|
if (!type.IsGood() || !res.IsGood() || !cb.IsGood() || !handle.IsGood())
|
||||||
|
{
|
||||||
|
return CELL_ADEC_ERROR_FATAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!adecCheckType(type->audioCodecType)) return CELL_ADEC_ERROR_ARG;
|
||||||
|
|
||||||
|
handle = adecOpen(new AudioDecoder(type->audioCodecType, res->startAddr, res->totalMemSize, cb->cbFunc, cb->cbArg));
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cellAdecOpenEx(mem_ptr_t<CellAdecType> type, mem_ptr_t<CellAdecResourceEx> res, mem_ptr_t<CellAdecCb> cb, mem32_t handle)
|
int cellAdecOpenEx(mem_ptr_t<CellAdecType> type, mem_ptr_t<CellAdecResourceEx> res, mem_ptr_t<CellAdecCb> cb, mem32_t handle)
|
||||||
{
|
{
|
||||||
cellAdec.Error("cellAdecOpenEx(type_addr=0x%x, res_addr=0x%x, cb_addr=0x%x, handle_addr=0x%x)",
|
cellAdec.Warning("cellAdecOpenEx(type_addr=0x%x, res_addr=0x%x, cb_addr=0x%x, handle_addr=0x%x)",
|
||||||
type.GetAddr(), res.GetAddr(), cb.GetAddr(), handle.GetAddr());
|
type.GetAddr(), res.GetAddr(), cb.GetAddr(), handle.GetAddr());
|
||||||
|
|
||||||
|
if (!type.IsGood() || !res.IsGood() || !cb.IsGood() || !handle.IsGood())
|
||||||
|
{
|
||||||
|
return CELL_ADEC_ERROR_FATAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!adecCheckType(type->audioCodecType)) return CELL_ADEC_ERROR_ARG;
|
||||||
|
|
||||||
|
handle = adecOpen(new AudioDecoder(type->audioCodecType, res->startAddr, res->totalMemSize, cb->cbFunc, cb->cbArg));
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cellAdecClose(u32 handle)
|
int cellAdecClose(u32 handle)
|
||||||
{
|
{
|
||||||
cellAdec.Error("cellAdecClose(handle=0x%x)", handle);
|
cellAdec.Warning("cellAdecClose(handle=%d)", handle);
|
||||||
|
|
||||||
|
AudioDecoder* adec;
|
||||||
|
if (!Emu.GetIdManager().GetIDData(handle, adec))
|
||||||
|
{
|
||||||
|
return CELL_ADEC_ERROR_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
adec->job.Push(AdecTask(adecClose));
|
||||||
|
|
||||||
|
while (!adec->is_finished || !adec->frames.IsEmpty())
|
||||||
|
{
|
||||||
|
if (Emu.IsStopped())
|
||||||
|
{
|
||||||
|
ConLog.Warning("cellAdecClose(%d) aborted", handle);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Emu.GetIdManager().RemoveID(handle);
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cellAdecStartSeq(u32 handle, u32 param_addr)
|
int cellAdecStartSeq(u32 handle, u32 param_addr)
|
||||||
{
|
{
|
||||||
cellAdec.Error("cellAdecStartSeq(handle=0x%x, param_addr=0x%x)", handle, param_addr);
|
cellAdec.Error("cellAdecStartSeq(handle=%d, param_addr=0x%x)", handle, param_addr);
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cellAdecEndSeq(u32 handle)
|
int cellAdecEndSeq(u32 handle)
|
||||||
{
|
{
|
||||||
cellAdec.Error("cellAdecEndSeq(handle=0x%x)", handle);
|
cellAdec.Error("cellAdecEndSeq(handle=%d)", handle);
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cellAdecDecodeAu(u32 handle, mem_ptr_t<CellAdecAuInfo> auInfo)
|
int cellAdecDecodeAu(u32 handle, mem_ptr_t<CellAdecAuInfo> auInfo)
|
||||||
{
|
{
|
||||||
cellAdec.Error("cellAdecDecodeAu(handle=0x%x, auInfo_addr=0x%x)", handle, auInfo.GetAddr());
|
cellAdec.Error("cellAdecDecodeAu(handle=%d, auInfo_addr=0x%x)", handle, auInfo.GetAddr());
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cellAdecGetPcm(u32 handle, u32 outBuffer_addr)
|
int cellAdecGetPcm(u32 handle, u32 outBuffer_addr)
|
||||||
{
|
{
|
||||||
cellAdec.Error("cellAdecGetPcm(handle=0x%x, outBuffer_addr=0x%x)", handle, outBuffer_addr);
|
cellAdec.Error("cellAdecGetPcm(handle=%d, outBuffer_addr=0x%x)", handle, outBuffer_addr);
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cellAdecGetPcmItem(u32 handle, u32 pcmItem_ptr_addr)
|
int cellAdecGetPcmItem(u32 handle, u32 pcmItem_ptr_addr)
|
||||||
{
|
{
|
||||||
cellAdec.Error("cellAdecGetPcmItem(handle=0x%x, pcmItem_ptr_addr=0x%x)", handle, pcmItem_ptr_addr);
|
cellAdec.Error("cellAdecGetPcmItem(handle=%d, pcmItem_ptr_addr=0x%x)", handle, pcmItem_ptr_addr);
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,4 +235,7 @@ void cellAdec_init()
|
|||||||
cellAdec.AddFunc(0x1529e506, cellAdecDecodeAu);
|
cellAdec.AddFunc(0x1529e506, cellAdecDecodeAu);
|
||||||
cellAdec.AddFunc(0x97ff2af1, cellAdecGetPcm);
|
cellAdec.AddFunc(0x97ff2af1, cellAdecGetPcm);
|
||||||
cellAdec.AddFunc(0xbd75f78b, cellAdecGetPcmItem);
|
cellAdec.AddFunc(0xbd75f78b, cellAdecGetPcmItem);
|
||||||
|
|
||||||
|
av_register_all();
|
||||||
|
avcodec_register_all();
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "cellPamf.h"
|
|
||||||
|
#include "Utilities/SQueue.h"
|
||||||
|
|
||||||
// Error Codes
|
// Error Codes
|
||||||
enum
|
enum
|
||||||
@ -341,6 +342,17 @@ struct CellAdecResource
|
|||||||
be_t<u32> ppuThreadStackSize;
|
be_t<u32> ppuThreadStackSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CellAdecResourceEx
|
||||||
|
{
|
||||||
|
be_t<u32> totalMemSize;
|
||||||
|
be_t<u32> startAddr;
|
||||||
|
be_t<u32> ppuThreadPriority;
|
||||||
|
be_t<u32> ppuThreadStackSize;
|
||||||
|
be_t<u32> spurs_addr;
|
||||||
|
u8 priority[8];
|
||||||
|
be_t<u32> maxContention;
|
||||||
|
};
|
||||||
|
|
||||||
// Callback Messages
|
// Callback Messages
|
||||||
enum CellAdecMsgType
|
enum CellAdecMsgType
|
||||||
{
|
{
|
||||||
@ -348,12 +360,14 @@ enum CellAdecMsgType
|
|||||||
CELL_ADEC_MSG_TYPE_PCMOUT,
|
CELL_ADEC_MSG_TYPE_PCMOUT,
|
||||||
CELL_ADEC_MSG_TYPE_ERROR,
|
CELL_ADEC_MSG_TYPE_ERROR,
|
||||||
CELL_ADEC_MSG_TYPE_SEQDONE,
|
CELL_ADEC_MSG_TYPE_SEQDONE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef mem_func_ptr_t<int (*)(u32 handle, CellAdecMsgType msgType, int msgData, u32 cbArg)> CellAdecCbMsg;
|
||||||
|
|
||||||
struct CellAdecCb
|
struct CellAdecCb
|
||||||
{
|
{
|
||||||
be_t<mem_func_ptr_t<int (*)(u32 handle, CellAdecMsgType msgType, int msgData, u32 cbArg_addr)>> cbFunc;
|
be_t<u32> cbFunc;
|
||||||
be_t<u32> cbArg_addr;
|
be_t<u32> cbArg;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef CellCodecTimeStamp CellAdecTimeStamp;
|
typedef CellCodecTimeStamp CellAdecTimeStamp;
|
||||||
@ -399,17 +413,6 @@ struct CellAdecLpcmInfo
|
|||||||
be_t<u32> outputDataSize;
|
be_t<u32> outputDataSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CellAdecResourceEx
|
|
||||||
{
|
|
||||||
be_t<u32> totalMemSize;
|
|
||||||
be_t<u32> startAddr;
|
|
||||||
be_t<u32> ppuThreadPriority;
|
|
||||||
be_t<u32> ppuThreadStackSize;
|
|
||||||
be_t<u32> spurs_addr;
|
|
||||||
u8 priority[8];
|
|
||||||
be_t<u32> maxContention;
|
|
||||||
};
|
|
||||||
|
|
||||||
// CELP Excitation Mode
|
// CELP Excitation Mode
|
||||||
enum CELP_ExcitationMode
|
enum CELP_ExcitationMode
|
||||||
{
|
{
|
||||||
@ -985,3 +988,67 @@ struct CellAdecMpmcInfo
|
|||||||
be_t<u32> lfePresent;
|
be_t<u32> lfePresent;
|
||||||
be_t<u32> channelCoufiguration;
|
be_t<u32> channelCoufiguration;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Audio Decoder Thread Classes */
|
||||||
|
|
||||||
|
enum AdecJobType : u32
|
||||||
|
{
|
||||||
|
adecStartSeq,
|
||||||
|
adecEndSeq,
|
||||||
|
adecDecodeAu,
|
||||||
|
adecClose,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AdecTask
|
||||||
|
{
|
||||||
|
AdecJobType type;
|
||||||
|
// ...
|
||||||
|
|
||||||
|
AdecTask(AdecJobType type)
|
||||||
|
: type(type)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
AdecTask()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AdecFrame
|
||||||
|
{
|
||||||
|
// under construction
|
||||||
|
u64 pts;
|
||||||
|
u64 userdata;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AudioDecoder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SQueue<AdecTask> job;
|
||||||
|
u32 id;
|
||||||
|
volatile bool is_running;
|
||||||
|
volatile bool is_finished;
|
||||||
|
|
||||||
|
SQueue<AdecFrame> frames;
|
||||||
|
|
||||||
|
const AudioCodecType type;
|
||||||
|
const u32 memAddr;
|
||||||
|
const u32 memSize;
|
||||||
|
const u32 cbFunc;
|
||||||
|
const u32 cbArg;
|
||||||
|
|
||||||
|
AudioDecoder(AudioCodecType type, u32 addr, u32 size, u32 func, u32 arg)
|
||||||
|
: type(type)
|
||||||
|
, memAddr(addr)
|
||||||
|
, memSize(size)
|
||||||
|
, cbFunc(func)
|
||||||
|
, cbArg(arg)
|
||||||
|
, is_running(false)
|
||||||
|
, is_finished(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~AudioDecoder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
@ -18,7 +18,7 @@ void dmuxQueryEsAttr(u32 info_addr /* may be 0 */, const mem_ptr_t<CellCodecEsFi
|
|||||||
const u32 esSpecificInfo_addr, mem_ptr_t<CellDmuxEsAttr> attr)
|
const u32 esSpecificInfo_addr, mem_ptr_t<CellDmuxEsAttr> attr)
|
||||||
{
|
{
|
||||||
if (esFilterId->filterIdMajor >= 0xe0)
|
if (esFilterId->filterIdMajor >= 0xe0)
|
||||||
attr->memSize = 0x600000; // 0x45fa49 from ps3
|
attr->memSize = 0x6000000; // 0x45fa49 from ps3
|
||||||
else
|
else
|
||||||
attr->memSize = 0x10000; // 0x73d9 from ps3
|
attr->memSize = 0x10000; // 0x73d9 from ps3
|
||||||
|
|
||||||
@ -159,7 +159,7 @@ u32 dmuxOpen(Demuxer* data)
|
|||||||
|
|
||||||
if (pes.new_au)
|
if (pes.new_au)
|
||||||
{
|
{
|
||||||
ConLog.Write("*** AVC AU detected (pts=0x%llx, dts=0x%llx)", pes.pts, pes.dts);
|
//ConLog.Write("*** AVC AU detected (pts=0x%llx, dts=0x%llx)", pes.pts, pes.dts);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (es.isfull())
|
if (es.isfull())
|
||||||
@ -167,8 +167,10 @@ u32 dmuxOpen(Demuxer* data)
|
|||||||
stream = backup;
|
stream = backup;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
//stream = backup;
|
|
||||||
es.push(stream, len - pes.size - 3, pes);
|
//hack: reconstruction of MPEG2-PS stream for vdec module (seems it works without it too)
|
||||||
|
stream = backup;
|
||||||
|
es.push(stream, len + 6 /*- pes.size - 3*/, pes);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -373,7 +373,7 @@ struct PesHeader
|
|||||||
, dts(0xffffffffffffffff)
|
, dts(0xffffffffffffffff)
|
||||||
, ch(0)
|
, ch(0)
|
||||||
, size(0)
|
, size(0)
|
||||||
, new_au(true)
|
, new_au(false)
|
||||||
{
|
{
|
||||||
u16 header;
|
u16 header;
|
||||||
stream.get(header);
|
stream.get(header);
|
||||||
|
@ -19,22 +19,54 @@ int vdecRead(void* opaque, u8* buf, int buf_size)
|
|||||||
{
|
{
|
||||||
VideoDecoder& vdec = *(VideoDecoder*)opaque;
|
VideoDecoder& vdec = *(VideoDecoder*)opaque;
|
||||||
|
|
||||||
if (vdec.reader.size < (u32)buf_size) buf_size = vdec.reader.size;
|
int res = 0;
|
||||||
|
|
||||||
|
/*if (vdec.reader.header_size)
|
||||||
|
{
|
||||||
|
assert(vdec.reader.header_size == 14);
|
||||||
|
res = buf_size;
|
||||||
|
if (vdec.reader.header_size < (u32)buf_size)
|
||||||
|
res = vdec.reader.header_size;
|
||||||
|
|
||||||
|
buf[0] = 0;
|
||||||
|
buf[1] = 0;
|
||||||
|
buf[2] = 1;
|
||||||
|
buf[3] = 0xba;
|
||||||
|
buf[4] = 0x44;
|
||||||
|
buf[5] = 0;
|
||||||
|
buf[6] = 0x07;
|
||||||
|
buf[7] = 0xaa;
|
||||||
|
buf[8] = 0x75;
|
||||||
|
buf[9] = 0xb1;
|
||||||
|
buf[10] = 0x07;
|
||||||
|
buf[11] = 0x53;
|
||||||
|
buf[12] = 0x03;
|
||||||
|
buf[13] = 0xf8;
|
||||||
|
vdec.reader.header_size -= res;
|
||||||
|
buf_size -= res;
|
||||||
|
buf += res;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
if (vdec.reader.size < (u32)buf_size)
|
||||||
|
{
|
||||||
|
buf_size = vdec.reader.size;
|
||||||
|
}
|
||||||
|
|
||||||
if (!buf_size)
|
if (!buf_size)
|
||||||
{
|
{
|
||||||
return AVERROR_EOF;
|
return res;
|
||||||
}
|
}
|
||||||
else if (!Memory.CopyToReal(buf, vdec.reader.addr, buf_size))
|
else if (!Memory.CopyToReal(buf, vdec.reader.addr, buf_size))
|
||||||
{
|
{
|
||||||
ConLog.Error("vdecRead: data reading failed (buf_size=0x%x)", buf_size);
|
ConLog.Error("vdecRead: data reading failed (buf_size=0x%x)", buf_size);
|
||||||
Emu.Pause();
|
Emu.Pause();
|
||||||
return 0;
|
return res;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
vdec.reader.addr += buf_size;
|
vdec.reader.addr += buf_size;
|
||||||
vdec.reader.size -= buf_size;
|
vdec.reader.size -= buf_size;
|
||||||
return buf_size;
|
return res + buf_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,12 +111,11 @@ u32 vdecOpen(VideoDecoder* data)
|
|||||||
|
|
||||||
if (vdec.job.IsEmpty() && vdec.is_running)
|
if (vdec.job.IsEmpty() && vdec.is_running)
|
||||||
{
|
{
|
||||||
// TODO: default task (not needed?)
|
|
||||||
Sleep(1);
|
Sleep(1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vdec.has_picture) // hack
|
if (vdec.frames.GetCount() >= 50)
|
||||||
{
|
{
|
||||||
Sleep(1);
|
Sleep(1);
|
||||||
continue;
|
continue;
|
||||||
@ -100,55 +131,34 @@ u32 vdecOpen(VideoDecoder* data)
|
|||||||
case vdecStartSeq:
|
case vdecStartSeq:
|
||||||
{
|
{
|
||||||
// TODO: reset data
|
// TODO: reset data
|
||||||
ConLog.Warning("vdecStartSeq()");
|
ConLog.Warning("vdecStartSeq:");
|
||||||
|
|
||||||
|
vdec.reader.addr = 0;
|
||||||
|
vdec.reader.size = 0;
|
||||||
vdec.is_running = true;
|
vdec.is_running = true;
|
||||||
|
vdec.just_started = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case vdecEndSeq:
|
case vdecEndSeq:
|
||||||
{
|
{
|
||||||
|
ConLog.Warning("vdecEndSeq:");
|
||||||
|
|
||||||
Callback cb;
|
Callback cb;
|
||||||
cb.SetAddr(vdec.cbFunc);
|
cb.SetAddr(vdec.cbFunc);
|
||||||
cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_SEQDONE, 0, vdec.cbArg);
|
cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_SEQDONE, 0, vdec.cbArg);
|
||||||
cb.Branch(false);
|
cb.Branch(true); // ???
|
||||||
ConLog.Warning("vdecEndSeq()");
|
|
||||||
|
avcodec_close(vdec.ctx);
|
||||||
|
avformat_close_input(&vdec.fmt);
|
||||||
|
|
||||||
vdec.is_running = false;
|
vdec.is_running = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case vdecDecodeAu:
|
case vdecDecodeAu:
|
||||||
{
|
{
|
||||||
struct vdecPacket : AVPacket
|
int err;
|
||||||
{
|
|
||||||
vdecPacket(u32 size)
|
|
||||||
{
|
|
||||||
av_init_packet(this);
|
|
||||||
data = (u8*)av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
|
|
||||||
memset(data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
|
|
||||||
this->size = size + FF_INPUT_BUFFER_PADDING_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
~vdecPacket()
|
|
||||||
{
|
|
||||||
av_free(data);
|
|
||||||
//av_free_packet(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
} au(task.size);
|
|
||||||
|
|
||||||
if ((task.pts || task.dts) && task.pts != ~0 && task.dts != ~0)
|
|
||||||
{
|
|
||||||
vdec.pts = task.pts;
|
|
||||||
vdec.dts = task.dts;
|
|
||||||
au.pts = vdec.pts;
|
|
||||||
au.dts = vdec.dts;
|
|
||||||
au.flags = AV_PKT_FLAG_KEY;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
au.pts = vdec.pts;
|
|
||||||
au.dts = vdec.dts;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (task.mode != CELL_VDEC_DEC_MODE_NORMAL)
|
if (task.mode != CELL_VDEC_DEC_MODE_NORMAL)
|
||||||
{
|
{
|
||||||
@ -159,11 +169,34 @@ u32 vdecOpen(VideoDecoder* data)
|
|||||||
vdec.reader.addr = task.addr;
|
vdec.reader.addr = task.addr;
|
||||||
vdec.reader.size = task.size;
|
vdec.reader.size = task.size;
|
||||||
|
|
||||||
if (!Memory.CopyToReal(au.data, task.addr, task.size))
|
u64 last_pts = task.pts, last_dts = task.dts;
|
||||||
|
|
||||||
|
struct AVPacketHolder : AVPacket
|
||||||
{
|
{
|
||||||
ConLog.Error("vdecDecodeAu: AU data accessing failed(addr=0x%x, size=0x%x)", task.addr, task.size);
|
AVPacketHolder(u32 size)
|
||||||
break;
|
{
|
||||||
}
|
av_init_packet(this);
|
||||||
|
|
||||||
|
if (size)
|
||||||
|
{
|
||||||
|
data = (u8*)av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
|
||||||
|
memset(data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
|
||||||
|
this->size = size + FF_INPUT_BUFFER_PADDING_SIZE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data = NULL;
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~AVPacketHolder()
|
||||||
|
{
|
||||||
|
av_free(data);
|
||||||
|
//av_free_packet(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
} au(0);
|
||||||
|
|
||||||
/*{
|
/*{
|
||||||
wxFile dump;
|
wxFile dump;
|
||||||
@ -172,54 +205,108 @@ u32 vdecOpen(VideoDecoder* data)
|
|||||||
dump.Close();
|
dump.Close();
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
int got_picture = 0;
|
if (vdec.just_started) // deferred initialization
|
||||||
|
|
||||||
//vdec.ctx->flags |= CODEC_FLAG_TRUNCATED;
|
|
||||||
//vdec.ctx->flags2 |= CODEC_FLAG2_CHUNKS;
|
|
||||||
vdec.ctx->flags2 |= CODEC_FLAG2_LOCAL_HEADER;
|
|
||||||
vdec.ctx->codec_tag = *(u32*)"DAVC";
|
|
||||||
//vdec.ctx->stream_codec_tag = *(u32*)"DAVC";
|
|
||||||
|
|
||||||
//avcodec_get_frame_defaults(vdec.frame);
|
|
||||||
|
|
||||||
|
|
||||||
int decode = avcodec_decode_video2(vdec.ctx, vdec.frame, &got_picture, &au);
|
|
||||||
if (decode < 0)
|
|
||||||
{
|
{
|
||||||
ConLog.Error("vdecDecodeAu: AU decoding error(%d)", decode);
|
err = avformat_open_input(&vdec.fmt, NULL, NULL, NULL);
|
||||||
break;
|
if (err)
|
||||||
}
|
|
||||||
|
|
||||||
if (got_picture)
|
|
||||||
{
|
|
||||||
ConLog.Write("got_picture (%d, vdec: pts=0x%llx, dts=0x%llx)", got_picture, vdec.pts, vdec.dts);
|
|
||||||
|
|
||||||
/*if (vdec.out_data[0]) av_freep(vdec.out_data[0]);
|
|
||||||
|
|
||||||
int err = av_image_alloc(vdec.out_data, vdec.linesize, vdec.ctx->width, vdec.ctx->height, vdec.ctx->pix_fmt, 1);
|
|
||||||
if (err < 0)
|
|
||||||
{
|
{
|
||||||
ConLog.Error("vdecDecodeAu: av_image_alloc failed(%d)", err);
|
ConLog.Error("vdecDecodeAu: avformat_open_input() failed");
|
||||||
Emu.Pause();
|
Emu.Pause();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
err = avformat_find_stream_info(vdec.fmt, NULL);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
ConLog.Error("vdecDecodeAu: avformat_find_stream_info() failed");
|
||||||
|
Emu.Pause();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!vdec.fmt->nb_streams)
|
||||||
|
{
|
||||||
|
ConLog.Error("vdecDecodeAu: no stream found");
|
||||||
|
Emu.Pause();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
vdec.ctx = vdec.fmt->streams[0]->codec; // TODO: check data
|
||||||
|
|
||||||
vdec.buf_size = err;
|
AVCodec* codec = avcodec_find_decoder(vdec.ctx->codec_id); // ???
|
||||||
|
if (!codec)
|
||||||
|
{
|
||||||
|
ConLog.Error("vdecDecodeAu: avcodec_find_decoder() failed");
|
||||||
|
Emu.Pause();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
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);*/
|
static SMutexGeneral g_mutex_avcodec_open2;
|
||||||
vdec.buf_size = a128(av_image_get_buffer_size(vdec.ctx->pix_fmt, vdec.ctx->width, vdec.ctx->height, 1));
|
SMutexGeneralLocker lock(g_mutex_avcodec_open2);
|
||||||
|
// not multithread-safe
|
||||||
vdec.userdata = task.userData;
|
err = avcodec_open2(vdec.ctx, codec, &vdec.opts);
|
||||||
vdec.has_picture = true;
|
}
|
||||||
|
if (err)
|
||||||
Callback cb;
|
{
|
||||||
cb.SetAddr(vdec.cbFunc);
|
ConLog.Error("vdecDecodeAu: avcodec_open2() failed");
|
||||||
cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_PICOUT, 0, vdec.cbArg);
|
Emu.Pause();
|
||||||
cb.Branch(false);
|
return;
|
||||||
|
}
|
||||||
|
vdec.just_started = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConLog.Write("Frame decoded (pts=0x%llx, dts=0x%llx, addr=0x%x, result=0x%x)", au.pts, au.dts, task.addr, decode);
|
while (av_read_frame(vdec.fmt, &au) >= 0)
|
||||||
|
{
|
||||||
|
struct VdecFrameHolder : VdecFrame
|
||||||
|
{
|
||||||
|
VdecFrameHolder()
|
||||||
|
{
|
||||||
|
data = av_frame_alloc();
|
||||||
|
}
|
||||||
|
|
||||||
|
~VdecFrameHolder()
|
||||||
|
{
|
||||||
|
if (data)
|
||||||
|
{
|
||||||
|
av_frame_unref(data);
|
||||||
|
av_frame_free(&data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} frame;
|
||||||
|
|
||||||
|
if (!frame.data)
|
||||||
|
{
|
||||||
|
ConLog.Error("vdecDecodeAu: av_frame_alloc() failed");
|
||||||
|
Emu.Pause();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int got_picture = 0;
|
||||||
|
|
||||||
|
int decode = avcodec_decode_video2(vdec.ctx, frame.data, &got_picture, &au);
|
||||||
|
|
||||||
|
if (decode < 0)
|
||||||
|
{
|
||||||
|
ConLog.Error("vdecDecodeAu: AU decoding error(0x%x)", decode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (got_picture)
|
||||||
|
{
|
||||||
|
ConLog.Write("got_picture (%d, vdec: pts=0x%llx, dts=0x%llx)", got_picture, au.pts, au.dts);
|
||||||
|
|
||||||
|
frame.dts = last_dts; last_dts += 3003; // + duration???
|
||||||
|
frame.pts = last_pts; last_pts += 3003;
|
||||||
|
frame.userdata = task.userData;
|
||||||
|
vdec.frames.Push(frame);
|
||||||
|
frame.data = nullptr; // to prevent destruction
|
||||||
|
|
||||||
|
Callback cb;
|
||||||
|
cb.SetAddr(vdec.cbFunc);
|
||||||
|
cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_PICOUT, 0, vdec.cbArg);
|
||||||
|
cb.Branch(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ConLog.Write("AU decoded (pts=0x%llx, dts=0x%llx, addr=0x%x, size=0x%x)", task.pts, task.dts, task.addr, task.size);
|
||||||
|
|
||||||
Callback cb;
|
Callback cb;
|
||||||
cb.SetAddr(vdec.cbFunc);
|
cb.SetAddr(vdec.cbFunc);
|
||||||
@ -331,7 +418,7 @@ int cellVdecClose(u32 handle)
|
|||||||
|
|
||||||
vdec->job.Push(VdecTask(vdecClose));
|
vdec->job.Push(VdecTask(vdecClose));
|
||||||
|
|
||||||
while (!vdec->is_finished)
|
while (!vdec->is_finished || !vdec->frames.IsEmpty())
|
||||||
{
|
{
|
||||||
if (Emu.IsStopped())
|
if (Emu.IsStopped())
|
||||||
{
|
{
|
||||||
@ -361,7 +448,7 @@ int cellVdecStartSeq(u32 handle)
|
|||||||
|
|
||||||
int cellVdecEndSeq(u32 handle)
|
int cellVdecEndSeq(u32 handle)
|
||||||
{
|
{
|
||||||
cellVdec.Log("cellVdecEndSeq(handle=%d)", handle);
|
cellVdec.Warning("cellVdecEndSeq(handle=%d)", handle);
|
||||||
|
|
||||||
VideoDecoder* vdec;
|
VideoDecoder* vdec;
|
||||||
if (!Emu.GetIdManager().GetIDData(handle, vdec))
|
if (!Emu.GetIdManager().GetIDData(handle, vdec))
|
||||||
@ -369,6 +456,28 @@ int cellVdecEndSeq(u32 handle)
|
|||||||
return CELL_VDEC_ERROR_ARG;
|
return CELL_VDEC_ERROR_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*if (!vdec->job.IsEmpty())
|
||||||
|
{
|
||||||
|
Sleep(1);
|
||||||
|
return CELL_VDEC_ERROR_BUSY; // ???
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vdec->frames.IsEmpty())
|
||||||
|
{
|
||||||
|
Sleep(1);
|
||||||
|
return CELL_VDEC_ERROR_BUSY; // ???
|
||||||
|
}*/
|
||||||
|
|
||||||
|
while (!vdec->job.IsEmpty() || !vdec->frames.IsEmpty())
|
||||||
|
{
|
||||||
|
if (Emu.IsStopped())
|
||||||
|
{
|
||||||
|
ConLog.Warning("cellVdecEndSeq(%d) aborted", handle);
|
||||||
|
return CELL_OK;
|
||||||
|
}
|
||||||
|
Sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
vdec->job.Push(VdecTask(vdecEndSeq));
|
vdec->job.Push(VdecTask(vdecEndSeq));
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
@ -399,7 +508,7 @@ int cellVdecDecodeAu(u32 handle, CellVdecDecodeMode mode, const mem_ptr_t<CellVd
|
|||||||
|
|
||||||
int cellVdecGetPicture(u32 handle, const mem_ptr_t<CellVdecPicFormat> format, u32 out_addr)
|
int cellVdecGetPicture(u32 handle, const mem_ptr_t<CellVdecPicFormat> format, u32 out_addr)
|
||||||
{
|
{
|
||||||
cellVdec.Warning("cellVdecGetPicture(handle=%d, format_addr=0x%x, out_addr=0x%x)", handle, format.GetAddr(), out_addr);
|
cellVdec.Log("cellVdecGetPicture(handle=%d, format_addr=0x%x, out_addr=0x%x)", handle, format.GetAddr(), out_addr);
|
||||||
|
|
||||||
VideoDecoder* vdec;
|
VideoDecoder* vdec;
|
||||||
if (!Emu.GetIdManager().GetIDData(handle, vdec))
|
if (!Emu.GetIdManager().GetIDData(handle, vdec))
|
||||||
@ -412,14 +521,16 @@ int cellVdecGetPicture(u32 handle, const mem_ptr_t<CellVdecPicFormat> format, u3
|
|||||||
return CELL_VDEC_ERROR_FATAL;
|
return CELL_VDEC_ERROR_FATAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vdec->has_picture)
|
if (vdec->frames.IsEmpty())
|
||||||
{
|
{
|
||||||
return CELL_VDEC_ERROR_EMPTY;
|
return CELL_VDEC_ERROR_EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (out_addr)
|
if (out_addr)
|
||||||
{
|
{
|
||||||
if (!Memory.IsGoodAddr(out_addr, vdec->buf_size))
|
u32 buf_size = a128(av_image_get_buffer_size(vdec->ctx->pix_fmt, vdec->ctx->width, vdec->ctx->height, 1));
|
||||||
|
|
||||||
|
if (!Memory.IsGoodAddr(out_addr, buf_size))
|
||||||
{
|
{
|
||||||
return CELL_VDEC_ERROR_FATAL;
|
return CELL_VDEC_ERROR_FATAL;
|
||||||
}
|
}
|
||||||
@ -429,54 +540,47 @@ int cellVdecGetPicture(u32 handle, const mem_ptr_t<CellVdecPicFormat> format, u3
|
|||||||
cellVdec.Error("cellVdecGetPicture: TODO: unknown formatType(%d)", (u32)format->formatType);
|
cellVdec.Error("cellVdecGetPicture: TODO: unknown formatType(%d)", (u32)format->formatType);
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format->colorMatrixType != CELL_VDEC_COLOR_MATRIX_TYPE_BT709)
|
if (format->colorMatrixType != CELL_VDEC_COLOR_MATRIX_TYPE_BT709)
|
||||||
{
|
{
|
||||||
cellVdec.Error("cellVdecGetPicture: TODO: unknown colorMatrixType(%d)", (u32)format->colorMatrixType);
|
cellVdec.Error("cellVdecGetPicture: TODO: unknown colorMatrixType(%d)", (u32)format->colorMatrixType);
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
AVFrame& frame = *vdec->frame;
|
VdecFrame vf;
|
||||||
|
|
||||||
u8* buf = (u8*)malloc(vdec->buf_size);
|
vdec->frames.Pop(vf);
|
||||||
if (!buf)
|
|
||||||
{
|
AVFrame& frame = *vf.data;
|
||||||
cellVdec.Error("cellVdecGetPicture: malloc failed (out of memory)");
|
|
||||||
Emu.Pause();
|
u8* buf = (u8*)malloc(buf_size);
|
||||||
return CELL_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: zero padding bytes
|
// 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);
|
int err = av_image_copy_to_buffer(buf, buf_size, frame.data, frame.linesize, vdec->ctx->pix_fmt, frame.width, frame.height, 1);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
{
|
{
|
||||||
cellVdec.Error("cellVdecGetPicture: av_image_copy_to_buffer failed(%d)", err);
|
cellVdec.Error("cellVdecGetPicture: av_image_copy_to_buffer failed(%d)", err);
|
||||||
Emu.Pause();
|
Emu.Pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Memory.CopyFromReal(out_addr, buf, vdec->buf_size))
|
if (!Memory.CopyFromReal(out_addr, buf, buf_size))
|
||||||
{
|
{
|
||||||
cellVdec.Error("cellVdecGetPicture: data copying failed");
|
cellVdec.Error("cellVdecGetPicture: data copying failed");
|
||||||
Emu.Pause();
|
Emu.Pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
av_frame_unref(vf.data);
|
||||||
u32 size0 = frame.linesize[0] * frame.height;
|
av_frame_free(&vf.data);
|
||||||
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);
|
free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
vdec->has_picture = false;
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cellVdecGetPicItem(u32 handle, mem32_t picItem_ptr)
|
int cellVdecGetPicItem(u32 handle, mem32_t picItem_ptr)
|
||||||
{
|
{
|
||||||
cellVdec.Warning("cellVdecGetPicItem(handle=%d, picItem_ptr_addr=0x%x)", handle, picItem_ptr.GetAddr());
|
cellVdec.Log("cellVdecGetPicItem(handle=%d, picItem_ptr_addr=0x%x)", handle, picItem_ptr.GetAddr());
|
||||||
|
|
||||||
VideoDecoder* vdec;
|
VideoDecoder* vdec;
|
||||||
if (!Emu.GetIdManager().GetIDData(handle, vdec))
|
if (!Emu.GetIdManager().GetIDData(handle, vdec))
|
||||||
@ -489,26 +593,31 @@ int cellVdecGetPicItem(u32 handle, mem32_t picItem_ptr)
|
|||||||
return CELL_VDEC_ERROR_FATAL;
|
return CELL_VDEC_ERROR_FATAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vdec->has_picture)
|
VdecFrame& vf = vdec->frames.Peek();
|
||||||
|
|
||||||
|
if (vdec->frames.IsEmpty())
|
||||||
{
|
{
|
||||||
|
Sleep(1);
|
||||||
return CELL_VDEC_ERROR_EMPTY;
|
return CELL_VDEC_ERROR_EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AVFrame& frame = *vf.data;
|
||||||
|
|
||||||
mem_ptr_t<CellVdecPicItem> info(vdec->memAddr);
|
mem_ptr_t<CellVdecPicItem> info(vdec->memAddr);
|
||||||
|
|
||||||
info->codecType = vdec->type;
|
info->codecType = vdec->type;
|
||||||
info->startAddr = 0x00000123; // invalid value (no address for picture)
|
info->startAddr = 0x00000123; // invalid value (no address for picture)
|
||||||
info->size = vdec->buf_size;
|
info->size = a128(av_image_get_buffer_size(vdec->ctx->pix_fmt, vdec->ctx->width, vdec->ctx->height, 1));
|
||||||
info->auNum = 1;
|
info->auNum = 1;
|
||||||
info->auPts[0].lower = vdec->pts;
|
info->auPts[0].lower = vf.pts;
|
||||||
info->auPts[0].upper = vdec->pts >> 32;
|
info->auPts[0].upper = vf.pts >> 32;
|
||||||
info->auPts[1].lower = 0xffffffff;
|
info->auPts[1].lower = 0xffffffff;
|
||||||
info->auPts[1].upper = 0xffffffff;
|
info->auPts[1].upper = 0xffffffff;
|
||||||
info->auDts[0].lower = vdec->dts;
|
info->auDts[0].lower = vf.dts;
|
||||||
info->auDts[0].upper = vdec->dts >> 32;
|
info->auDts[0].upper = vf.dts >> 32;
|
||||||
info->auDts[1].lower = 0xffffffff;
|
info->auDts[1].lower = 0xffffffff;
|
||||||
info->auDts[1].upper = 0xffffffff;
|
info->auDts[1].upper = 0xffffffff;
|
||||||
info->auUserData[0] = vdec->userdata;
|
info->auUserData[0] = vf.userdata;
|
||||||
info->auUserData[1] = 0;
|
info->auUserData[1] = 0;
|
||||||
info->status = CELL_OK;
|
info->status = CELL_OK;
|
||||||
info->attr = CELL_VDEC_PICITEM_ATTR_NORMAL;
|
info->attr = CELL_VDEC_PICITEM_ATTR_NORMAL;
|
||||||
@ -516,9 +625,9 @@ int cellVdecGetPicItem(u32 handle, mem32_t picItem_ptr)
|
|||||||
|
|
||||||
mem_ptr_t<CellVdecAvcInfo> avc(vdec->memAddr + sizeof(CellVdecPicItem));
|
mem_ptr_t<CellVdecAvcInfo> avc(vdec->memAddr + sizeof(CellVdecPicItem));
|
||||||
|
|
||||||
avc->horizontalSize = vdec->frame->width; // ???
|
avc->horizontalSize = frame.width;
|
||||||
avc->verticalSize = vdec->frame->height;
|
avc->verticalSize = frame.height;
|
||||||
switch (vdec->frame->pict_type)
|
switch (frame.pict_type)
|
||||||
{
|
{
|
||||||
case AV_PICTURE_TYPE_I: avc->pictureType[0] = CELL_VDEC_AVC_PCT_I; break;
|
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_P: avc->pictureType[0] = CELL_VDEC_AVC_PCT_P; break;
|
||||||
@ -590,5 +699,6 @@ void cellVdec_init()
|
|||||||
cellVdec.AddFunc(0x17c702b9, cellVdecGetPicItem);
|
cellVdec.AddFunc(0x17c702b9, cellVdecGetPicItem);
|
||||||
cellVdec.AddFunc(0xe13ef6fc, cellVdecSetFrameRate);
|
cellVdec.AddFunc(0xe13ef6fc, cellVdecSetFrameRate);
|
||||||
|
|
||||||
|
av_register_all();
|
||||||
avcodec_register_all();
|
avcodec_register_all();
|
||||||
}
|
}
|
@ -679,6 +679,14 @@ struct VdecTask
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct VdecFrame
|
||||||
|
{
|
||||||
|
AVFrame* data;
|
||||||
|
u64 dts;
|
||||||
|
u64 pts;
|
||||||
|
u64 userdata;
|
||||||
|
};
|
||||||
|
|
||||||
int vdecRead(void* opaque, u8* buf, int buf_size);
|
int vdecRead(void* opaque, u8* buf, int buf_size);
|
||||||
|
|
||||||
class VideoDecoder
|
class VideoDecoder
|
||||||
@ -688,19 +696,12 @@ public:
|
|||||||
u32 id;
|
u32 id;
|
||||||
volatile bool is_running;
|
volatile bool is_running;
|
||||||
volatile bool is_finished;
|
volatile bool is_finished;
|
||||||
|
bool just_started;
|
||||||
|
|
||||||
AVCodec* codec;
|
|
||||||
AVCodecContext* ctx;
|
AVCodecContext* ctx;
|
||||||
AVFormatContext* fmt;
|
|
||||||
AVFrame* frame;
|
|
||||||
AVDictionary* opts;
|
AVDictionary* opts;
|
||||||
|
AVFormatContext* fmt;
|
||||||
u8* io_buf;
|
u8* io_buf;
|
||||||
u32 buf_size;
|
|
||||||
u64 pts;
|
|
||||||
u64 dts;
|
|
||||||
u64 pos;
|
|
||||||
u64 userdata;
|
|
||||||
volatile bool has_picture;
|
|
||||||
|
|
||||||
struct VideoReader
|
struct VideoReader
|
||||||
{
|
{
|
||||||
@ -708,6 +709,8 @@ public:
|
|||||||
u32 size;
|
u32 size;
|
||||||
} reader;
|
} reader;
|
||||||
|
|
||||||
|
SQueue<VdecFrame> frames;
|
||||||
|
|
||||||
const CellVdecCodecType type;
|
const CellVdecCodecType type;
|
||||||
const u32 profile;
|
const u32 profile;
|
||||||
const u32 memAddr;
|
const u32 memAddr;
|
||||||
@ -724,38 +727,24 @@ public:
|
|||||||
, cbArg(arg)
|
, cbArg(arg)
|
||||||
, is_finished(false)
|
, is_finished(false)
|
||||||
, is_running(false)
|
, is_running(false)
|
||||||
, has_picture(false)
|
, just_started(false)
|
||||||
, pos(0)
|
|
||||||
{
|
{
|
||||||
codec = avcodec_find_decoder(AV_CODEC_ID_H264);
|
opts = nullptr;
|
||||||
|
av_dict_set(&opts, "refcounted_frames", "1", 0);
|
||||||
|
AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_H264);
|
||||||
if (!codec)
|
if (!codec)
|
||||||
{
|
{
|
||||||
ConLog.Error("VideoDecoder(): avcodec_find_decoder failed");
|
ConLog.Error("vdecDecodeAu: avcodec_find_decoder(H264) failed");
|
||||||
Emu.Pause();
|
Emu.Pause();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ctx = avcodec_alloc_context3(codec);
|
ctx = nullptr; /*avcodec_alloc_context3(codec);
|
||||||
if (!ctx)
|
if (!ctx)
|
||||||
{
|
{
|
||||||
ConLog.Error("VideoDecoder(): avcodec_alloc_context3 failed");
|
ConLog.Error("VideoDecoder(): avcodec_alloc_context3 failed");
|
||||||
Emu.Pause();
|
Emu.Pause();
|
||||||
return;
|
return;
|
||||||
}
|
}*/
|
||||||
opts = nullptr;
|
|
||||||
int err = avcodec_open2(ctx, codec, &opts);
|
|
||||||
if (err) // TODO: not multithread safe
|
|
||||||
{
|
|
||||||
ConLog.Error("VideoDecoder(): avcodec_open2 failed(%d)", err);
|
|
||||||
Emu.Pause();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
frame = av_frame_alloc();
|
|
||||||
if (!frame)
|
|
||||||
{
|
|
||||||
ConLog.Error("VideoDecoder(): av_frame_alloc failed");
|
|
||||||
Emu.Pause();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fmt = avformat_alloc_context();
|
fmt = avformat_alloc_context();
|
||||||
if (!fmt)
|
if (!fmt)
|
||||||
{
|
{
|
||||||
@ -771,23 +760,32 @@ public:
|
|||||||
Emu.Pause();
|
Emu.Pause();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//memset(&out_data, 0, sizeof(out_data));
|
|
||||||
//memset(&linesize, 0, sizeof(linesize));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~VideoDecoder()
|
~VideoDecoder()
|
||||||
{
|
{
|
||||||
if (io_buf) av_free(io_buf);
|
if (!is_finished && ctx)
|
||||||
|
{
|
||||||
|
for (u32 i = frames.GetCount() - 1; ~i; i--)
|
||||||
|
{
|
||||||
|
VdecFrame& vf = frames.Peek(i);
|
||||||
|
av_frame_unref(vf.data);
|
||||||
|
av_frame_free(&vf.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (io_buf)
|
||||||
|
{
|
||||||
|
av_free(io_buf);
|
||||||
|
}
|
||||||
if (fmt)
|
if (fmt)
|
||||||
{
|
{
|
||||||
|
if (fmt->pb) av_free(fmt->pb);
|
||||||
avformat_free_context(fmt);
|
avformat_free_context(fmt);
|
||||||
}
|
}
|
||||||
if (frame) av_frame_free(&frame);
|
if (!is_finished && ctx)
|
||||||
if (ctx)
|
|
||||||
{
|
{
|
||||||
avcodec_close(ctx);
|
//avcodec_close(ctx); // crashes
|
||||||
av_free(ctx);
|
//avformat_close_input(&fmt);
|
||||||
}
|
}
|
||||||
//if (out_data[0]) av_freep(out_data[0]);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
@ -139,31 +139,34 @@ int cellVpostExec(u32 handle, const u32 inPicBuff_addr, const mem_ptr_t<CellVpos
|
|||||||
picInfo->reserved1 = 0;
|
picInfo->reserved1 = 0;
|
||||||
picInfo->reserved2 = 0;
|
picInfo->reserved2 = 0;
|
||||||
|
|
||||||
u8* pY = (u8*)malloc(w*h);
|
u8* pY = (u8*)malloc(w*h); // color planes
|
||||||
u8* pU = (u8*)malloc(w*h/4);
|
u8* pU = (u8*)malloc(w*h/4);
|
||||||
u8* pV = (u8*)malloc(w*h/4);
|
u8* pV = (u8*)malloc(w*h/4);
|
||||||
u32* res = (u32*)malloc(w*h*4);
|
u32* res = (u32*)malloc(w*h*4); // RGBA interleaved output
|
||||||
const u8 alpha = ctrlParam->outAlpha;
|
const u8 alpha = ctrlParam->outAlpha;
|
||||||
|
|
||||||
if (!Memory.CopyToReal(pY, inPicBuff_addr, w*h))
|
if (!Memory.CopyToReal(pY, inPicBuff_addr, w*h))
|
||||||
{
|
{
|
||||||
cellVpost.Error("cellVpostExec: data copying failed(pY)");
|
cellVpost.Error("cellVpostExec: data copying failed(pY)");
|
||||||
|
Emu.Pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Memory.CopyToReal(pU, inPicBuff_addr + w*h, w*h/4))
|
if (!Memory.CopyToReal(pU, inPicBuff_addr + w*h, w*h/4))
|
||||||
{
|
{
|
||||||
cellVpost.Error("cellVpostExec: data copying failed(pU)");
|
cellVpost.Error("cellVpostExec: data copying failed(pU)");
|
||||||
|
Emu.Pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Memory.CopyToReal(pV, inPicBuff_addr + w*h + w*h/4, w*h/4))
|
if (!Memory.CopyToReal(pV, inPicBuff_addr + w*h + w*h/4, w*h/4))
|
||||||
{
|
{
|
||||||
cellVpost.Error("cellVpostExec: data copying failed(pV)");
|
cellVpost.Error("cellVpostExec: data copying failed(pV)");
|
||||||
|
Emu.Pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u32 i = 0; i < h; i++) for (u32 j = 0; j < w; j++)
|
for (u32 i = 0; i < h; i++) for (u32 j = 0; j < w; j++)
|
||||||
{
|
{
|
||||||
float Cr = pV[(i/2)*(w/2)+j/2];
|
float Cr = pV[(i/2)*(w/2)+j/2] - 128;
|
||||||
float Cb = pU[(i/2)*(w/2)+j/2];
|
float Cb = pU[(i/2)*(w/2)+j/2] - 128;
|
||||||
float Y = pY[i*w+j];
|
float Y = pY[i*w+j];
|
||||||
|
|
||||||
int R = Y + 1.5701f * Cr;
|
int R = Y + 1.5701f * Cr;
|
||||||
|
Loading…
Reference in New Issue
Block a user