mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-25 04:02:42 +01:00
cellAdec draft
This commit is contained in:
parent
c978fe377d
commit
c064c701e2
@ -19,11 +19,6 @@ public:
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_mutex.GetOwner() == m_mutex.GetDeadValue())
|
||||
{
|
||||
return false;
|
||||
@ -31,6 +26,10 @@ public:
|
||||
|
||||
if (m_count >= SQSize)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Sleep(1);
|
||||
continue;
|
||||
}
|
||||
@ -51,11 +50,6 @@ public:
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_mutex.GetOwner() == m_mutex.GetDeadValue())
|
||||
{
|
||||
return false;
|
||||
@ -63,6 +57,10 @@ public:
|
||||
|
||||
if (!m_count)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Sleep(1);
|
||||
continue;
|
||||
}
|
||||
@ -96,4 +94,10 @@ public:
|
||||
SMutexLocker lock(m_mutex);
|
||||
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 "Emu/SysCalls/SysCalls.h"
|
||||
#include "Emu/SysCalls/SC_FUNC.h"
|
||||
#include "cellPamf.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "libavcodec\avcodec.h"
|
||||
#include "libavformat\avformat.h"
|
||||
}
|
||||
|
||||
#include "cellAdec.h"
|
||||
|
||||
void 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int cellAdecEndSeq(u32 handle)
|
||||
{
|
||||
cellAdec.Error("cellAdecEndSeq(handle=0x%x)", handle);
|
||||
cellAdec.Error("cellAdecEndSeq(handle=%d)", handle);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -73,4 +235,7 @@ void cellAdec_init()
|
||||
cellAdec.AddFunc(0x1529e506, cellAdecDecodeAu);
|
||||
cellAdec.AddFunc(0x97ff2af1, cellAdecGetPcm);
|
||||
cellAdec.AddFunc(0xbd75f78b, cellAdecGetPcmItem);
|
||||
|
||||
av_register_all();
|
||||
avcodec_register_all();
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "cellPamf.h"
|
||||
|
||||
#include "Utilities/SQueue.h"
|
||||
|
||||
// Error Codes
|
||||
enum
|
||||
@ -341,6 +342,17 @@ struct CellAdecResource
|
||||
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
|
||||
enum CellAdecMsgType
|
||||
{
|
||||
@ -348,12 +360,14 @@ enum CellAdecMsgType
|
||||
CELL_ADEC_MSG_TYPE_PCMOUT,
|
||||
CELL_ADEC_MSG_TYPE_ERROR,
|
||||
CELL_ADEC_MSG_TYPE_SEQDONE,
|
||||
};
|
||||
};
|
||||
|
||||
typedef mem_func_ptr_t<int (*)(u32 handle, CellAdecMsgType msgType, int msgData, u32 cbArg)> CellAdecCbMsg;
|
||||
|
||||
struct CellAdecCb
|
||||
{
|
||||
be_t<mem_func_ptr_t<int (*)(u32 handle, CellAdecMsgType msgType, int msgData, u32 cbArg_addr)>> cbFunc;
|
||||
be_t<u32> cbArg_addr;
|
||||
be_t<u32> cbFunc;
|
||||
be_t<u32> cbArg;
|
||||
};
|
||||
|
||||
typedef CellCodecTimeStamp CellAdecTimeStamp;
|
||||
@ -399,17 +413,6 @@ struct CellAdecLpcmInfo
|
||||
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
|
||||
enum CELP_ExcitationMode
|
||||
{
|
||||
@ -985,3 +988,67 @@ struct CellAdecMpmcInfo
|
||||
be_t<u32> lfePresent;
|
||||
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)
|
||||
{
|
||||
if (esFilterId->filterIdMajor >= 0xe0)
|
||||
attr->memSize = 0x600000; // 0x45fa49 from ps3
|
||||
attr->memSize = 0x6000000; // 0x45fa49 from ps3
|
||||
else
|
||||
attr->memSize = 0x10000; // 0x73d9 from ps3
|
||||
|
||||
@ -159,7 +159,7 @@ u32 dmuxOpen(Demuxer* data)
|
||||
|
||||
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())
|
||||
@ -167,8 +167,10 @@ u32 dmuxOpen(Demuxer* data)
|
||||
stream = backup;
|
||||
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
|
||||
{
|
||||
|
@ -373,7 +373,7 @@ struct PesHeader
|
||||
, dts(0xffffffffffffffff)
|
||||
, ch(0)
|
||||
, size(0)
|
||||
, new_au(true)
|
||||
, new_au(false)
|
||||
{
|
||||
u16 header;
|
||||
stream.get(header);
|
||||
|
@ -19,22 +19,54 @@ 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;
|
||||
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)
|
||||
{
|
||||
return AVERROR_EOF;
|
||||
return res;
|
||||
}
|
||||
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;
|
||||
return res;
|
||||
}
|
||||
else
|
||||
{
|
||||
vdec.reader.addr += 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)
|
||||
{
|
||||
// TODO: default task (not needed?)
|
||||
Sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (vdec.has_picture) // hack
|
||||
if (vdec.frames.GetCount() >= 50)
|
||||
{
|
||||
Sleep(1);
|
||||
continue;
|
||||
@ -100,55 +131,34 @@ u32 vdecOpen(VideoDecoder* data)
|
||||
case vdecStartSeq:
|
||||
{
|
||||
// TODO: reset data
|
||||
ConLog.Warning("vdecStartSeq()");
|
||||
ConLog.Warning("vdecStartSeq:");
|
||||
|
||||
vdec.reader.addr = 0;
|
||||
vdec.reader.size = 0;
|
||||
vdec.is_running = true;
|
||||
vdec.just_started = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case vdecEndSeq:
|
||||
{
|
||||
ConLog.Warning("vdecEndSeq:");
|
||||
|
||||
Callback cb;
|
||||
cb.SetAddr(vdec.cbFunc);
|
||||
cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_SEQDONE, 0, vdec.cbArg);
|
||||
cb.Branch(false);
|
||||
ConLog.Warning("vdecEndSeq()");
|
||||
cb.Branch(true); // ???
|
||||
|
||||
avcodec_close(vdec.ctx);
|
||||
avformat_close_input(&vdec.fmt);
|
||||
|
||||
vdec.is_running = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case vdecDecodeAu:
|
||||
{
|
||||
struct vdecPacket : AVPacket
|
||||
{
|
||||
vdecPacket(u32 size)
|
||||
{
|
||||
av_init_packet(this);
|
||||
data = (u8*)av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
|
||||
memset(data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
|
||||
this->size = size + FF_INPUT_BUFFER_PADDING_SIZE;
|
||||
}
|
||||
|
||||
~vdecPacket()
|
||||
{
|
||||
av_free(data);
|
||||
//av_free_packet(this);
|
||||
}
|
||||
|
||||
} au(task.size);
|
||||
|
||||
if ((task.pts || task.dts) && task.pts != ~0 && task.dts != ~0)
|
||||
{
|
||||
vdec.pts = task.pts;
|
||||
vdec.dts = task.dts;
|
||||
au.pts = vdec.pts;
|
||||
au.dts = vdec.dts;
|
||||
au.flags = AV_PKT_FLAG_KEY;
|
||||
}
|
||||
else
|
||||
{
|
||||
au.pts = vdec.pts;
|
||||
au.dts = vdec.dts;
|
||||
}
|
||||
int err;
|
||||
|
||||
if (task.mode != CELL_VDEC_DEC_MODE_NORMAL)
|
||||
{
|
||||
@ -159,11 +169,34 @@ u32 vdecOpen(VideoDecoder* data)
|
||||
vdec.reader.addr = task.addr;
|
||||
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);
|
||||
break;
|
||||
}
|
||||
AVPacketHolder(u32 size)
|
||||
{
|
||||
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;
|
||||
@ -172,54 +205,108 @@ u32 vdecOpen(VideoDecoder* data)
|
||||
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)
|
||||
if (vdec.just_started) // deferred initialization
|
||||
{
|
||||
ConLog.Error("vdecDecodeAu: AU decoding error(%d)", decode);
|
||||
break;
|
||||
}
|
||||
|
||||
if (got_picture)
|
||||
{
|
||||
ConLog.Write("got_picture (%d, vdec: pts=0x%llx, dts=0x%llx)", got_picture, vdec.pts, vdec.dts);
|
||||
|
||||
/*if (vdec.out_data[0]) av_freep(vdec.out_data[0]);
|
||||
|
||||
int err = av_image_alloc(vdec.out_data, vdec.linesize, vdec.ctx->width, vdec.ctx->height, vdec.ctx->pix_fmt, 1);
|
||||
if (err < 0)
|
||||
err = avformat_open_input(&vdec.fmt, NULL, NULL, NULL);
|
||||
if (err)
|
||||
{
|
||||
ConLog.Error("vdecDecodeAu: av_image_alloc failed(%d)", err);
|
||||
ConLog.Error("vdecDecodeAu: avformat_open_input() failed");
|
||||
Emu.Pause();
|
||||
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);*/
|
||||
vdec.buf_size = a128(av_image_get_buffer_size(vdec.ctx->pix_fmt, vdec.ctx->width, vdec.ctx->height, 1));
|
||||
|
||||
vdec.userdata = task.userData;
|
||||
vdec.has_picture = true;
|
||||
|
||||
Callback cb;
|
||||
cb.SetAddr(vdec.cbFunc);
|
||||
cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_PICOUT, 0, vdec.cbArg);
|
||||
cb.Branch(false);
|
||||
{
|
||||
static SMutexGeneral g_mutex_avcodec_open2;
|
||||
SMutexGeneralLocker lock(g_mutex_avcodec_open2);
|
||||
// not multithread-safe
|
||||
err = avcodec_open2(vdec.ctx, codec, &vdec.opts);
|
||||
}
|
||||
if (err)
|
||||
{
|
||||
ConLog.Error("vdecDecodeAu: avcodec_open2() failed");
|
||||
Emu.Pause();
|
||||
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;
|
||||
cb.SetAddr(vdec.cbFunc);
|
||||
@ -331,7 +418,7 @@ int cellVdecClose(u32 handle)
|
||||
|
||||
vdec->job.Push(VdecTask(vdecClose));
|
||||
|
||||
while (!vdec->is_finished)
|
||||
while (!vdec->is_finished || !vdec->frames.IsEmpty())
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
@ -361,7 +448,7 @@ int cellVdecStartSeq(u32 handle)
|
||||
|
||||
int cellVdecEndSeq(u32 handle)
|
||||
{
|
||||
cellVdec.Log("cellVdecEndSeq(handle=%d)", handle);
|
||||
cellVdec.Warning("cellVdecEndSeq(handle=%d)", handle);
|
||||
|
||||
VideoDecoder* vdec;
|
||||
if (!Emu.GetIdManager().GetIDData(handle, vdec))
|
||||
@ -369,6 +456,28 @@ int cellVdecEndSeq(u32 handle)
|
||||
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));
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
if (!vdec->has_picture)
|
||||
if (vdec->frames.IsEmpty())
|
||||
{
|
||||
return CELL_VDEC_ERROR_EMPTY;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@ -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);
|
||||
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;
|
||||
VdecFrame vf;
|
||||
|
||||
u8* buf = (u8*)malloc(vdec->buf_size);
|
||||
if (!buf)
|
||||
{
|
||||
cellVdec.Error("cellVdecGetPicture: malloc failed (out of memory)");
|
||||
Emu.Pause();
|
||||
return CELL_OK;
|
||||
}
|
||||
vdec->frames.Pop(vf);
|
||||
|
||||
AVFrame& frame = *vf.data;
|
||||
|
||||
u8* buf = (u8*)malloc(buf_size);
|
||||
|
||||
// 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)
|
||||
{
|
||||
cellVdec.Error("cellVdecGetPicture: av_image_copy_to_buffer failed(%d)", err);
|
||||
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");
|
||||
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);
|
||||
*/
|
||||
|
||||
av_frame_unref(vf.data);
|
||||
av_frame_free(&vf.data);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
vdec->has_picture = false;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellVdecGetPicItem(u32 handle, mem32_t picItem_ptr)
|
||||
{
|
||||
cellVdec.Warning("cellVdecGetPicItem(handle=%d, picItem_ptr_addr=0x%x)", handle, picItem_ptr.GetAddr());
|
||||
cellVdec.Log("cellVdecGetPicItem(handle=%d, picItem_ptr_addr=0x%x)", handle, picItem_ptr.GetAddr());
|
||||
|
||||
VideoDecoder* vdec;
|
||||
if (!Emu.GetIdManager().GetIDData(handle, vdec))
|
||||
@ -489,26 +593,31 @@ int cellVdecGetPicItem(u32 handle, mem32_t picItem_ptr)
|
||||
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;
|
||||
}
|
||||
|
||||
AVFrame& frame = *vf.data;
|
||||
|
||||
mem_ptr_t<CellVdecPicItem> info(vdec->memAddr);
|
||||
|
||||
info->codecType = vdec->type;
|
||||
info->startAddr = 0x00000123; // invalid value (no address for picture)
|
||||
info->size = vdec->buf_size;
|
||||
info->size = a128(av_image_get_buffer_size(vdec->ctx->pix_fmt, vdec->ctx->width, vdec->ctx->height, 1));
|
||||
info->auNum = 1;
|
||||
info->auPts[0].lower = vdec->pts;
|
||||
info->auPts[0].upper = vdec->pts >> 32;
|
||||
info->auPts[0].lower = vf.pts;
|
||||
info->auPts[0].upper = vf.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[0].lower = vf.dts;
|
||||
info->auDts[0].upper = vf.dts >> 32;
|
||||
info->auDts[1].lower = 0xffffffff;
|
||||
info->auDts[1].upper = 0xffffffff;
|
||||
info->auUserData[0] = vdec->userdata;
|
||||
info->auUserData[0] = vf.userdata;
|
||||
info->auUserData[1] = 0;
|
||||
info->status = CELL_OK;
|
||||
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));
|
||||
|
||||
avc->horizontalSize = vdec->frame->width; // ???
|
||||
avc->verticalSize = vdec->frame->height;
|
||||
switch (vdec->frame->pict_type)
|
||||
avc->horizontalSize = frame.width;
|
||||
avc->verticalSize = frame.height;
|
||||
switch (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;
|
||||
@ -590,5 +699,6 @@ void cellVdec_init()
|
||||
cellVdec.AddFunc(0x17c702b9, cellVdecGetPicItem);
|
||||
cellVdec.AddFunc(0xe13ef6fc, cellVdecSetFrameRate);
|
||||
|
||||
av_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);
|
||||
|
||||
class VideoDecoder
|
||||
@ -688,19 +696,12 @@ public:
|
||||
u32 id;
|
||||
volatile bool is_running;
|
||||
volatile bool is_finished;
|
||||
bool just_started;
|
||||
|
||||
AVCodec* codec;
|
||||
AVCodecContext* ctx;
|
||||
AVFormatContext* fmt;
|
||||
AVFrame* frame;
|
||||
AVDictionary* opts;
|
||||
AVFormatContext* fmt;
|
||||
u8* io_buf;
|
||||
u32 buf_size;
|
||||
u64 pts;
|
||||
u64 dts;
|
||||
u64 pos;
|
||||
u64 userdata;
|
||||
volatile bool has_picture;
|
||||
|
||||
struct VideoReader
|
||||
{
|
||||
@ -708,6 +709,8 @@ public:
|
||||
u32 size;
|
||||
} reader;
|
||||
|
||||
SQueue<VdecFrame> frames;
|
||||
|
||||
const CellVdecCodecType type;
|
||||
const u32 profile;
|
||||
const u32 memAddr;
|
||||
@ -724,38 +727,24 @@ public:
|
||||
, cbArg(arg)
|
||||
, is_finished(false)
|
||||
, is_running(false)
|
||||
, has_picture(false)
|
||||
, pos(0)
|
||||
, just_started(false)
|
||||
{
|
||||
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)
|
||||
{
|
||||
ConLog.Error("VideoDecoder(): avcodec_find_decoder failed");
|
||||
ConLog.Error("vdecDecodeAu: avcodec_find_decoder(H264) failed");
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
ctx = avcodec_alloc_context3(codec);
|
||||
ctx = nullptr; /*avcodec_alloc_context3(codec);
|
||||
if (!ctx)
|
||||
{
|
||||
ConLog.Error("VideoDecoder(): avcodec_alloc_context3 failed");
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
opts = nullptr;
|
||||
int err = avcodec_open2(ctx, codec, &opts);
|
||||
if (err) // TODO: not multithread safe
|
||||
{
|
||||
ConLog.Error("VideoDecoder(): avcodec_open2 failed(%d)", err);
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
frame = av_frame_alloc();
|
||||
if (!frame)
|
||||
{
|
||||
ConLog.Error("VideoDecoder(): av_frame_alloc failed");
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
fmt = avformat_alloc_context();
|
||||
if (!fmt)
|
||||
{
|
||||
@ -771,23 +760,32 @@ public:
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
//memset(&out_data, 0, sizeof(out_data));
|
||||
//memset(&linesize, 0, sizeof(linesize));
|
||||
}
|
||||
|
||||
~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->pb) av_free(fmt->pb);
|
||||
avformat_free_context(fmt);
|
||||
}
|
||||
if (frame) av_frame_free(&frame);
|
||||
if (ctx)
|
||||
if (!is_finished && ctx)
|
||||
{
|
||||
avcodec_close(ctx);
|
||||
av_free(ctx);
|
||||
//avcodec_close(ctx); // crashes
|
||||
//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->reserved2 = 0;
|
||||
|
||||
u8* pY = (u8*)malloc(w*h);
|
||||
u8* pY = (u8*)malloc(w*h); // color planes
|
||||
u8* pU = (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;
|
||||
|
||||
if (!Memory.CopyToReal(pY, inPicBuff_addr, w*h))
|
||||
{
|
||||
cellVpost.Error("cellVpostExec: data copying failed(pY)");
|
||||
Emu.Pause();
|
||||
}
|
||||
|
||||
if (!Memory.CopyToReal(pU, inPicBuff_addr + w*h, w*h/4))
|
||||
{
|
||||
cellVpost.Error("cellVpostExec: data copying failed(pU)");
|
||||
Emu.Pause();
|
||||
}
|
||||
|
||||
if (!Memory.CopyToReal(pV, inPicBuff_addr + w*h + w*h/4, w*h/4))
|
||||
{
|
||||
cellVpost.Error("cellVpostExec: data copying failed(pV)");
|
||||
Emu.Pause();
|
||||
}
|
||||
|
||||
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 Cr = pV[(i/2)*(w/2)+j/2] - 128;
|
||||
float Cb = pU[(i/2)*(w/2)+j/2] - 128;
|
||||
float Y = pY[i*w+j];
|
||||
|
||||
int R = Y + 1.5701f * Cr;
|
||||
|
Loading…
Reference in New Issue
Block a user