2013-09-28 04:36:57 +02:00
|
|
|
#include "stdafx.h"
|
|
|
|
|
#include "Emu/SysCalls/SysCalls.h"
|
|
|
|
|
#include "Emu/SysCalls/SC_FUNC.h"
|
2014-02-27 19:25:32 +01:00
|
|
|
#include "cellPamf.h"
|
2013-09-28 04:36:57 +02:00
|
|
|
|
2014-02-26 08:51:00 +01:00
|
|
|
extern "C"
|
|
|
|
|
{
|
2014-02-27 19:25:32 +01:00
|
|
|
#include "libavcodec\avcodec.h"
|
2014-03-02 00:50:47 +01:00
|
|
|
#include "libavformat\avformat.h"
|
2014-03-01 09:38:50 +01:00
|
|
|
#include "libavutil\imgutils.h"
|
2014-02-26 08:51:00 +01:00
|
|
|
}
|
|
|
|
|
|
2014-02-27 19:25:32 +01:00
|
|
|
#include "cellVdec.h"
|
|
|
|
|
|
2013-09-28 04:36:57 +02:00
|
|
|
void cellVdec_init();
|
|
|
|
|
Module cellVdec(0x0005, cellVdec_init);
|
|
|
|
|
|
2014-03-02 00:50:47 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-27 19:25:32 +01:00
|
|
|
u32 vdecQueryAttr(CellVdecCodecType type, u32 profile, u32 spec_addr /* may be 0 */, mem_ptr_t<CellVdecAttr> attr)
|
2013-09-28 04:36:57 +02:00
|
|
|
{
|
2014-02-27 19:25:32 +01:00
|
|
|
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;
|
2014-03-01 09:38:50 +01:00
|
|
|
attr->memSize = 4 * 1024 * 1024;
|
|
|
|
|
attr->cmdDepth = 16;
|
2013-09-28 04:36:57 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-27 19:25:32 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-01 09:38:50 +01:00
|
|
|
if (vdec.has_picture) // hack
|
|
|
|
|
{
|
|
|
|
|
Sleep(1);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-27 19:25:32 +01:00
|
|
|
if (!vdec.job.Pop(task))
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (task.type)
|
|
|
|
|
{
|
|
|
|
|
case vdecStartSeq:
|
|
|
|
|
{
|
|
|
|
|
// TODO: reset data
|
|
|
|
|
ConLog.Warning("vdecStartSeq()");
|
|
|
|
|
vdec.is_running = true;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case vdecEndSeq:
|
|
|
|
|
{
|
2014-03-01 09:38:50 +01:00
|
|
|
Callback cb;
|
|
|
|
|
cb.SetAddr(vdec.cbFunc);
|
|
|
|
|
cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_SEQDONE, 0, vdec.cbArg);
|
|
|
|
|
cb.Branch(false);
|
2014-02-27 19:25:32 +01:00
|
|
|
ConLog.Warning("vdecEndSeq()");
|
|
|
|
|
vdec.is_running = false;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case vdecDecodeAu:
|
|
|
|
|
{
|
|
|
|
|
struct vdecPacket : AVPacket
|
|
|
|
|
{
|
|
|
|
|
vdecPacket(u32 size)
|
|
|
|
|
{
|
2014-03-02 00:50:47 +01:00
|
|
|
av_init_packet(this);
|
|
|
|
|
data = (u8*)av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
|
2014-02-27 19:25:32 +01:00
|
|
|
memset(data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
|
2014-03-02 00:50:47 +01:00
|
|
|
this->size = size + FF_INPUT_BUFFER_PADDING_SIZE;
|
2014-02-27 19:25:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~vdecPacket()
|
|
|
|
|
{
|
2014-03-02 00:50:47 +01:00
|
|
|
av_free(data);
|
|
|
|
|
//av_free_packet(this);
|
2014-02-27 19:25:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} au(task.size);
|
|
|
|
|
|
2014-03-02 00:50:47 +01:00
|
|
|
if ((task.pts || task.dts) && task.pts != ~0 && task.dts != ~0)
|
2014-03-01 09:38:50 +01:00
|
|
|
{
|
|
|
|
|
vdec.pts = task.pts;
|
|
|
|
|
vdec.dts = task.dts;
|
2014-03-02 00:50:47 +01:00
|
|
|
au.pts = vdec.pts;
|
|
|
|
|
au.dts = vdec.dts;
|
|
|
|
|
au.flags = AV_PKT_FLAG_KEY;
|
2014-03-01 09:38:50 +01:00
|
|
|
}
|
2014-03-02 00:50:47 +01:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
au.pts = vdec.pts;
|
|
|
|
|
au.dts = vdec.dts;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-27 19:25:32 +01:00
|
|
|
if (task.mode != CELL_VDEC_DEC_MODE_NORMAL)
|
|
|
|
|
{
|
|
|
|
|
ConLog.Error("vdecDecodeAu: unsupported decoding mode(%d)", task.mode);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-02 00:50:47 +01:00
|
|
|
vdec.reader.addr = task.addr;
|
|
|
|
|
vdec.reader.size = task.size;
|
|
|
|
|
|
2014-02-27 19:25:32 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-02 00:50:47 +01:00
|
|
|
/*{
|
|
|
|
|
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();
|
|
|
|
|
}*/
|
|
|
|
|
|
2014-02-27 19:25:32 +01:00
|
|
|
int got_picture = 0;
|
|
|
|
|
|
2014-03-01 09:38:50 +01:00
|
|
|
//vdec.ctx->flags |= CODEC_FLAG_TRUNCATED;
|
|
|
|
|
//vdec.ctx->flags2 |= CODEC_FLAG2_CHUNKS;
|
2014-03-02 00:50:47 +01:00
|
|
|
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);
|
|
|
|
|
|
2014-03-01 09:38:50 +01:00
|
|
|
|
2014-02-27 19:25:32 +01:00
|
|
|
int decode = avcodec_decode_video2(vdec.ctx, vdec.frame, &got_picture, &au);
|
|
|
|
|
if (decode < 0)
|
|
|
|
|
{
|
|
|
|
|
ConLog.Error("vdecDecodeAu: AU decoding error(%d)", decode);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2014-03-01 09:38:50 +01:00
|
|
|
|
|
|
|
|
if (got_picture)
|
|
|
|
|
{
|
|
|
|
|
ConLog.Write("got_picture (%d, vdec: pts=0x%llx, dts=0x%llx)", got_picture, vdec.pts, vdec.dts);
|
2014-03-02 00:50:47 +01:00
|
|
|
|
2014-03-01 09:38:50 +01:00
|
|
|
/*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;
|
|
|
|
|
}
|
2014-03-02 00:50:47 +01:00
|
|
|
|
2014-03-01 09:38:50 +01:00
|
|
|
vdec.buf_size = err;
|
|
|
|
|
|
|
|
|
|
av_image_copy(vdec.out_data, vdec.linesize, (const u8**)(vdec.frame->data), vdec.frame->linesize,
|
|
|
|
|
vdec.ctx->pix_fmt, vdec.ctx->width, vdec.ctx->height);*/
|
|
|
|
|
vdec.buf_size = a128(av_image_get_buffer_size(vdec.ctx->pix_fmt, vdec.ctx->width, vdec.ctx->height, 1));
|
|
|
|
|
|
|
|
|
|
vdec.userdata = task.userData;
|
|
|
|
|
vdec.has_picture = true;
|
|
|
|
|
|
|
|
|
|
Callback cb;
|
|
|
|
|
cb.SetAddr(vdec.cbFunc);
|
|
|
|
|
cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_PICOUT, 0, vdec.cbArg);
|
|
|
|
|
cb.Branch(false);
|
|
|
|
|
}
|
2014-03-02 00:50:47 +01:00
|
|
|
|
|
|
|
|
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);
|
2014-02-27 19:25:32 +01:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case vdecClose:
|
|
|
|
|
{
|
|
|
|
|
vdec.is_finished = true;
|
|
|
|
|
ConLog.Write("Video Decoder exit");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case vdecSetFrameRate:
|
|
|
|
|
{
|
|
|
|
|
ConLog.Error("TODO: vdecSetFrameRate(%d)", task.frc);
|
2014-03-01 09:38:50 +01:00
|
|
|
return;
|
2014-02-27 19:25:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
ConLog.Error("Video Decoder error: unknown task(%d)", task.type);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ConLog.Warning("Video Decoder aborted");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
t.detach();
|
|
|
|
|
|
|
|
|
|
return vdec_id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int cellVdecQueryAttr(const mem_ptr_t<CellVdecType> type, mem_ptr_t<CellVdecAttr> attr)
|
|
|
|
|
{
|
|
|
|
|
cellVdec.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);
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-20 03:16:17 +01:00
|
|
|
int cellVdecQueryAttrEx(const mem_ptr_t<CellVdecTypeEx> type, mem_ptr_t<CellVdecAttr> attr)
|
2013-09-28 04:36:57 +02:00
|
|
|
{
|
2014-02-27 19:25:32 +01:00
|
|
|
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);
|
2013-09-28 04:36:57 +02:00
|
|
|
}
|
|
|
|
|
|
2014-02-20 03:16:17 +01:00
|
|
|
int cellVdecOpen(const mem_ptr_t<CellVdecType> type, const mem_ptr_t<CellVdecResource> res, const mem_ptr_t<CellVdecCb> cb, mem32_t handle)
|
2013-09-28 04:36:57 +02:00
|
|
|
{
|
2014-02-27 19:25:32 +01:00
|
|
|
cellVdec.Warning("cellVdecOpen(type_addr=0x%x, res_addr=0x%x, cb_addr=0x%x, handle_addr=0x%x)",
|
2014-02-20 03:16:17 +01:00
|
|
|
type.GetAddr(), res.GetAddr(), cb.GetAddr(), handle.GetAddr());
|
2014-02-27 19:25:32 +01:00
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
|
2013-09-28 04:36:57 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-20 03:16:17 +01:00
|
|
|
int cellVdecOpenEx(const mem_ptr_t<CellVdecTypeEx> type, const mem_ptr_t<CellVdecResourceEx> res, const mem_ptr_t<CellVdecCb> cb, mem32_t handle)
|
2013-09-28 04:36:57 +02:00
|
|
|
{
|
2014-02-27 19:25:32 +01:00
|
|
|
cellVdec.Warning("cellVdecOpenEx(type_addr=0x%x, res_addr=0x%x, cb_addr=0x%x, handle_addr=0x%x)",
|
2014-02-20 03:16:17 +01:00
|
|
|
type.GetAddr(), res.GetAddr(), cb.GetAddr(), handle.GetAddr());
|
2014-02-27 19:25:32 +01:00
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
|
2013-09-28 04:36:57 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-20 03:16:17 +01:00
|
|
|
int cellVdecClose(u32 handle)
|
2013-09-28 04:36:57 +02:00
|
|
|
{
|
2014-02-27 19:25:32 +01:00
|
|
|
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);
|
2013-09-28 04:36:57 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-20 03:16:17 +01:00
|
|
|
int cellVdecStartSeq(u32 handle)
|
2013-09-28 04:36:57 +02:00
|
|
|
{
|
2014-02-27 19:25:32 +01:00
|
|
|
cellVdec.Log("cellVdecStartSeq(handle=%d)", handle);
|
|
|
|
|
|
|
|
|
|
VideoDecoder* vdec;
|
|
|
|
|
if (!Emu.GetIdManager().GetIDData(handle, vdec))
|
|
|
|
|
{
|
|
|
|
|
return CELL_VDEC_ERROR_ARG;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vdec->job.Push(VdecTask(vdecStartSeq));
|
2013-09-28 04:36:57 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-20 03:16:17 +01:00
|
|
|
int cellVdecEndSeq(u32 handle)
|
2013-09-28 04:36:57 +02:00
|
|
|
{
|
2014-02-27 19:25:32 +01:00
|
|
|
cellVdec.Log("cellVdecEndSeq(handle=%d)", handle);
|
|
|
|
|
|
|
|
|
|
VideoDecoder* vdec;
|
|
|
|
|
if (!Emu.GetIdManager().GetIDData(handle, vdec))
|
|
|
|
|
{
|
|
|
|
|
return CELL_VDEC_ERROR_ARG;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vdec->job.Push(VdecTask(vdecEndSeq));
|
2013-09-28 04:36:57 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-20 03:16:17 +01:00
|
|
|
int cellVdecDecodeAu(u32 handle, CellVdecDecodeMode mode, const mem_ptr_t<CellVdecAuInfo> auInfo)
|
2013-09-28 04:36:57 +02:00
|
|
|
{
|
2014-02-27 19:25:32 +01:00
|
|
|
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);
|
2013-09-28 04:36:57 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-20 03:16:17 +01:00
|
|
|
int cellVdecGetPicture(u32 handle, const mem_ptr_t<CellVdecPicFormat> format, u32 out_addr)
|
2013-09-28 04:36:57 +02:00
|
|
|
{
|
2014-03-01 09:38:50 +01:00
|
|
|
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;
|
2013-09-28 04:36:57 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-01 09:38:50 +01:00
|
|
|
int cellVdecGetPicItem(u32 handle, mem32_t picItem_ptr)
|
2013-09-28 04:36:57 +02:00
|
|
|
{
|
2014-03-01 09:38:50 +01:00
|
|
|
cellVdec.Warning("cellVdecGetPicItem(handle=%d, picItem_ptr_addr=0x%x)", handle, picItem_ptr.GetAddr());
|
|
|
|
|
|
|
|
|
|
VideoDecoder* vdec;
|
|
|
|
|
if (!Emu.GetIdManager().GetIDData(handle, vdec))
|
|
|
|
|
{
|
|
|
|
|
return CELL_VDEC_ERROR_ARG;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!picItem_ptr.IsGood())
|
|
|
|
|
{
|
|
|
|
|
return CELL_VDEC_ERROR_FATAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!vdec->has_picture)
|
|
|
|
|
{
|
|
|
|
|
return CELL_VDEC_ERROR_EMPTY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mem_ptr_t<CellVdecPicItem> info(vdec->memAddr);
|
|
|
|
|
|
|
|
|
|
info->codecType = vdec->type;
|
|
|
|
|
info->startAddr = 0x00000123; // invalid value (no address for picture)
|
|
|
|
|
info->size = vdec->buf_size;
|
|
|
|
|
info->auNum = 1;
|
|
|
|
|
info->auPts[0].lower = vdec->pts;
|
|
|
|
|
info->auPts[0].upper = vdec->pts >> 32;
|
|
|
|
|
info->auPts[1].lower = 0xffffffff;
|
|
|
|
|
info->auPts[1].upper = 0xffffffff;
|
|
|
|
|
info->auDts[0].lower = vdec->dts;
|
|
|
|
|
info->auDts[0].upper = vdec->dts >> 32;
|
|
|
|
|
info->auDts[1].lower = 0xffffffff;
|
|
|
|
|
info->auDts[1].upper = 0xffffffff;
|
|
|
|
|
info->auUserData[0] = vdec->userdata;
|
|
|
|
|
info->auUserData[1] = 0;
|
|
|
|
|
info->status = CELL_OK;
|
|
|
|
|
info->attr = CELL_VDEC_PICITEM_ATTR_NORMAL;
|
|
|
|
|
info->picInfo_addr = vdec->memAddr + sizeof(CellVdecPicItem);
|
|
|
|
|
|
|
|
|
|
mem_ptr_t<CellVdecAvcInfo> avc(vdec->memAddr + sizeof(CellVdecPicItem));
|
|
|
|
|
|
|
|
|
|
avc->horizontalSize = vdec->frame->width; // ???
|
|
|
|
|
avc->verticalSize = vdec->frame->height;
|
|
|
|
|
switch (vdec->frame->pict_type)
|
|
|
|
|
{
|
|
|
|
|
case AV_PICTURE_TYPE_I: avc->pictureType[0] = CELL_VDEC_AVC_PCT_I; break;
|
|
|
|
|
case AV_PICTURE_TYPE_P: avc->pictureType[0] = CELL_VDEC_AVC_PCT_P; break;
|
|
|
|
|
case AV_PICTURE_TYPE_B: avc->pictureType[0] = CELL_VDEC_AVC_PCT_B; break;
|
|
|
|
|
default: avc->pictureType[0] = CELL_VDEC_AVC_PCT_UNKNOWN; break; // ???
|
|
|
|
|
}
|
|
|
|
|
avc->pictureType[1] = CELL_VDEC_AVC_PCT_UNKNOWN; // ???
|
|
|
|
|
avc->idrPictureFlag = false; // ???
|
|
|
|
|
avc->aspect_ratio_idc = CELL_VDEC_AVC_ARI_SAR_UNSPECIFIED; // ???
|
|
|
|
|
avc->sar_height = 0;
|
|
|
|
|
avc->sar_width = 0;
|
|
|
|
|
avc->pic_struct = CELL_VDEC_AVC_PSTR_FRAME; // ???
|
|
|
|
|
avc->picOrderCount[0] = 0; // ???
|
|
|
|
|
avc->picOrderCount[1] = 0;
|
|
|
|
|
avc->vui_parameters_present_flag = true; // ???
|
|
|
|
|
avc->frame_mbs_only_flag = true; // ??? progressive
|
|
|
|
|
avc->video_signal_type_present_flag = true; // ???
|
|
|
|
|
avc->video_format = CELL_VDEC_AVC_VF_COMPONENT; // ???
|
|
|
|
|
avc->video_full_range_flag = false; // ???
|
|
|
|
|
avc->colour_description_present_flag = true;
|
|
|
|
|
avc->colour_primaries = CELL_VDEC_AVC_CP_ITU_R_BT_709_5; // ???
|
|
|
|
|
avc->transfer_characteristics = CELL_VDEC_AVC_TC_ITU_R_BT_709_5;
|
|
|
|
|
avc->matrix_coefficients = CELL_VDEC_AVC_MXC_ITU_R_BT_709_5; // important
|
|
|
|
|
avc->timing_info_present_flag = true;
|
|
|
|
|
avc->frameRateCode = CELL_VDEC_AVC_FRC_30000DIV1001; // important (!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)
|
|
|
|
|
avc->fixed_frame_rate_flag = true;
|
|
|
|
|
avc->low_delay_hrd_flag = true; // ???
|
|
|
|
|
avc->entropy_coding_mode_flag = true; // ???
|
|
|
|
|
avc->nalUnitPresentFlags = 0; // ???
|
|
|
|
|
avc->ccDataLength[0] = 0;
|
|
|
|
|
avc->ccDataLength[1] = 0;
|
|
|
|
|
avc->reserved[0] = 0;
|
|
|
|
|
avc->reserved[1] = 0;
|
|
|
|
|
|
|
|
|
|
picItem_ptr = info.GetAddr();
|
|
|
|
|
|
2013-09-28 04:36:57 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-20 03:16:17 +01:00
|
|
|
int cellVdecSetFrameRate(u32 handle, CellVdecFrameRate frc)
|
2013-09-28 04:36:57 +02:00
|
|
|
{
|
2014-02-27 19:25:32 +01:00
|
|
|
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);
|
2013-09-28 04:36:57 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void cellVdec_init()
|
|
|
|
|
{
|
|
|
|
|
cellVdec.AddFunc(0xff6f6ebe, cellVdecQueryAttr);
|
|
|
|
|
cellVdec.AddFunc(0xc982a84a, cellVdecQueryAttrEx);
|
|
|
|
|
cellVdec.AddFunc(0xb6bbcd5d, cellVdecOpen);
|
|
|
|
|
cellVdec.AddFunc(0x0053e2d8, cellVdecOpenEx);
|
|
|
|
|
cellVdec.AddFunc(0x16698e83, cellVdecClose);
|
|
|
|
|
cellVdec.AddFunc(0xc757c2aa, cellVdecStartSeq);
|
|
|
|
|
cellVdec.AddFunc(0x824433f0, cellVdecEndSeq);
|
|
|
|
|
cellVdec.AddFunc(0x2bf4ddd2, cellVdecDecodeAu);
|
|
|
|
|
cellVdec.AddFunc(0x807c861a, cellVdecGetPicture);
|
|
|
|
|
cellVdec.AddFunc(0x17c702b9, cellVdecGetPicItem);
|
|
|
|
|
cellVdec.AddFunc(0xe13ef6fc, cellVdecSetFrameRate);
|
2014-02-27 19:25:32 +01:00
|
|
|
|
|
|
|
|
avcodec_register_all();
|
2013-09-28 04:36:57 +02:00
|
|
|
}
|