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

762 lines
18 KiB
C++
Raw Normal View History

#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"
SMutexGeneral g_mutex_avcodec_open2;
extern "C"
{
2014-03-06 12:50:45 +01:00
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/imgutils.h"
}
2014-02-27 19:25:32 +01:00
#include "cellVdec.h"
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;
2014-03-03 00:02:42 +01:00
int res = 0;
2014-03-07 22:31:08 +01:00
if (vdec.reader.size < (u32)buf_size && !vdec.just_started)
2014-03-03 00:02:42 +01:00
{
while (vdec.job.IsEmpty())
{
if (Emu.IsStopped())
{
ConLog.Warning("vdecRead() aborted");
return 0;
}
Sleep(1);
}
switch (vdec.job.Peek().type)
{
case vdecEndSeq:
{
buf_size = vdec.reader.size;
}
break;
case vdecDecodeAu:
{
if (!Memory.CopyToReal(buf, vdec.reader.addr, vdec.reader.size))
{
ConLog.Error("vdecRead: data reading failed (reader.size=0x%x)", vdec.reader.size);
Emu.Pause();
return 0;
}
buf += vdec.reader.size;
buf_size -= vdec.reader.size;
res += vdec.reader.size;
/*Callback cb;
cb.SetAddr(vdec.cbFunc);
cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, vdec.cbArg);
cb.Branch(false);*/
vdec.vdecCb->ExecAsCallback(vdec.cbFunc, false, vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, vdec.cbArg);
vdec.job.Pop(vdec.task);
vdec.reader.addr = vdec.task.addr;
vdec.reader.size = vdec.task.size;
vdec.last_pts = vdec.task.pts;
vdec.last_dts = vdec.task.dts;
}
break;
default:
ConLog.Error("vdecRead(): sequence error (task %d)", vdec.job.Peek().type);
return 0;
}
2014-03-07 22:31:08 +01:00
}
else if (vdec.reader.size < (u32)buf_size)
{
buf_size = vdec.reader.size;
2014-03-03 00:02:42 +01:00
}
2014-03-02 00:50:47 +01:00
if (!buf_size)
{
2014-03-03 00:02:42 +01:00
return res;
2014-03-02 00:50:47 +01:00
}
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;
2014-03-02 00:50:47 +01:00
}
else
{
vdec.reader.addr += buf_size;
vdec.reader.size -= buf_size;
2014-03-03 00:02:42 +01:00
return res + buf_size;
2014-03-02 00:50:47 +01:00
}
}
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)
{
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;
return CELL_OK;
}
2014-02-27 19:25:32 +01:00
u32 vdecOpen(VideoDecoder* data)
{
VideoDecoder& vdec = *data;
vdec.vdecCb = &Emu.GetCPU().AddThread(CPU_THREAD_PPU);
2014-02-27 19:25:32 +01:00
u32 vdec_id = cellVdec.GetNewId(data);
vdec.id = vdec_id;
2014-03-07 22:31:08 +01:00
vdec.vdecCb->SetName("Video Decoder[" + std::to_string(vdec_id) + "] Callback");
2014-02-27 19:25:32 +01:00
thread t("Video Decoder[" + std::to_string(vdec_id) + "] Thread", [&]()
{
ConLog.Write("Video Decoder enter()");
VdecTask& task = vdec.task;
2014-02-27 19:25:32 +01:00
while (true)
{
if (Emu.IsStopped())
{
break;
}
if (vdec.job.IsEmpty() && vdec.is_running)
{
Sleep(1);
continue;
}
2014-03-03 00:02:42 +01:00
if (vdec.frames.GetCount() >= 50)
2014-03-01 09:38:50 +01:00
{
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
2014-03-03 00:02:42 +01:00
ConLog.Warning("vdecStartSeq:");
vdec.reader.addr = 0;
vdec.reader.size = 0;
2014-02-27 19:25:32 +01:00
vdec.is_running = true;
2014-03-03 00:02:42 +01:00
vdec.just_started = true;
2014-02-27 19:25:32 +01:00
}
break;
case vdecEndSeq:
{
// TODO: finalize
2014-03-03 00:02:42 +01:00
ConLog.Warning("vdecEndSeq:");
vdec.vdecCb->ExecAsCallback(vdec.cbFunc, false, vdec.id, CELL_VDEC_MSG_TYPE_SEQDONE, CELL_OK, vdec.cbArg);
/*Callback cb;
2014-03-01 09:38:50 +01:00
cb.SetAddr(vdec.cbFunc);
cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_SEQDONE, CELL_OK, vdec.cbArg);
cb.Branch(true); // ???*/
2014-03-03 00:02:42 +01:00
avcodec_close(vdec.ctx);
avformat_close_input(&vdec.fmt);
2014-02-27 19:25:32 +01:00
vdec.is_running = false;
}
break;
case vdecDecodeAu:
{
2014-03-03 00:02:42 +01:00
int err;
2014-03-02 00:50:47 +01:00
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;
vdec.last_pts = task.pts;
vdec.last_dts = task.dts;
2014-03-03 00:02:42 +01:00
struct AVPacketHolder : AVPacket
2014-02-27 19:25:32 +01:00
{
2014-03-03 00:02:42 +01:00
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);
2014-02-27 19:25:32 +01:00
2014-03-03 00:02:42 +01:00
if (vdec.just_started) // deferred initialization
2014-02-27 19:25:32 +01:00
{
2014-03-03 00:02:42 +01:00
err = avformat_open_input(&vdec.fmt, NULL, NULL, NULL);
if (err)
{
ConLog.Error("vdecDecodeAu: avformat_open_input() failed");
Emu.Pause();
break;
2014-03-03 00:02:42 +01:00
}
err = avformat_find_stream_info(vdec.fmt, NULL);
if (err)
{
ConLog.Error("vdecDecodeAu: avformat_find_stream_info() failed");
Emu.Pause();
break;
2014-03-03 00:02:42 +01:00
}
if (!vdec.fmt->nb_streams)
{
ConLog.Error("vdecDecodeAu: no stream found");
Emu.Pause();
break;
2014-03-03 00:02:42 +01:00
}
vdec.ctx = vdec.fmt->streams[0]->codec; // TODO: check data
AVCodec* codec = avcodec_find_decoder(vdec.ctx->codec_id); // ???
if (!codec)
{
ConLog.Error("vdecDecodeAu: avcodec_find_decoder() failed");
Emu.Pause();
break;
2014-03-03 00:02:42 +01:00
}
AVDictionary* opts = nullptr;
av_dict_set(&opts, "refcounted_frames", "1", 0);
2014-03-03 00:02:42 +01:00
{
SMutexGeneralLocker lock(g_mutex_avcodec_open2);
// not multithread-safe
err = avcodec_open2(vdec.ctx, codec, &opts);
2014-03-03 00:02:42 +01:00
}
if (err)
{
ConLog.Error("vdecDecodeAu: avcodec_open2() failed");
Emu.Pause();
break;
2014-03-03 00:02:42 +01:00
}
//vdec.ctx->flags |= CODEC_FLAG_TRUNCATED;
//vdec.ctx->flags2 |= CODEC_FLAG2_CHUNKS;
2014-03-03 00:02:42 +01:00
vdec.just_started = false;
2014-02-27 19:25:32 +01:00
}
2014-03-01 09:38:50 +01:00
bool last_frame = false;
while (true)
2014-03-01 09:38:50 +01:00
{
if (Emu.IsStopped())
{
ConLog.Warning("vdecDecodeAu aborted");
return;
}
last_frame = av_read_frame(vdec.fmt, &au) < 0;
if (last_frame)
{
//break;
av_free(au.data);
au.data = NULL;
au.size = 0;
}
2014-03-03 00:02:42 +01:00
struct VdecFrameHolder : VdecFrame
{
VdecFrameHolder()
{
data = av_frame_alloc();
}
~VdecFrameHolder()
{
if (data)
{
av_frame_unref(data);
av_frame_free(&data);
}
}
} frame;
if (!frame.data)
2014-03-01 09:38:50 +01:00
{
2014-03-03 00:02:42 +01:00
ConLog.Error("vdecDecodeAu: av_frame_alloc() failed");
2014-03-01 09:38:50 +01:00
Emu.Pause();
break;
2014-03-01 09:38:50 +01:00
}
2014-03-03 00:02:42 +01:00
int got_picture = 0;
2014-03-01 09:38:50 +01:00
2014-03-03 00:02:42 +01:00
int decode = avcodec_decode_video2(vdec.ctx, frame.data, &got_picture, &au);
2014-03-01 09:38:50 +01:00
if (decode <= 0)
2014-03-03 00:02:42 +01:00
{
if (!last_frame && decode < 0)
{
ConLog.Error("vdecDecodeAu: AU decoding error(0x%x)", decode);
break;
}
if (!got_picture && vdec.reader.size == 0) break; // video end?
2014-03-03 00:02:42 +01:00
}
if (got_picture)
{
//ConLog.Write("got_picture (%d, vdec: pts=0x%llx, dts=0x%llx)", got_picture, au.pts, au.dts);
2014-03-03 00:02:42 +01:00
frame.dts = vdec.last_dts; vdec.last_dts += 3003; // + duration???
frame.pts = vdec.last_pts; vdec.last_pts += 3003;
2014-03-03 00:02:42 +01:00
frame.userdata = task.userData;
vdec.frames.Push(frame); // !!!!!!!!
2014-03-03 00:02:42 +01:00
frame.data = nullptr; // to prevent destruction
vdec.vdecCb->ExecAsCallback(vdec.cbFunc, false, vdec.id, CELL_VDEC_MSG_TYPE_PICOUT, CELL_OK, vdec.cbArg);
/*Callback cb;
2014-03-03 00:02:42 +01:00
cb.SetAddr(vdec.cbFunc);
cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_PICOUT, CELL_OK, vdec.cbArg);
cb.Branch(false);*/
2014-03-03 00:02:42 +01:00
}
2014-03-01 09:38:50 +01:00
}
2014-03-03 00:02:42 +01:00
vdec.vdecCb->ExecAsCallback(vdec.cbFunc, false, vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, vdec.cbArg);
/*Callback cb;
2014-03-02 00:50:47 +01:00
cb.SetAddr(vdec.cbFunc);
cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, 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);
}
break;
2014-02-27 19:25:32 +01:00
default:
ConLog.Error("Video Decoder error: unknown task(%d)", task.type);
}
}
vdec.is_finished = true;
2014-02-27 19:25:32 +01:00
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);
}
int cellVdecQueryAttrEx(const mem_ptr_t<CellVdecTypeEx> type, mem_ptr_t<CellVdecAttr> attr)
{
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);
}
int cellVdecOpen(const mem_ptr_t<CellVdecType> type, const mem_ptr_t<CellVdecResource> res, const mem_ptr_t<CellVdecCb> cb, mem32_t handle)
{
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)",
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));
return CELL_OK;
}
int cellVdecOpenEx(const mem_ptr_t<CellVdecTypeEx> type, const mem_ptr_t<CellVdecResourceEx> res, const mem_ptr_t<CellVdecCb> cb, mem32_t handle)
{
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)",
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));
return CELL_OK;
}
int cellVdecClose(u32 handle)
{
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));
2014-03-03 00:02:42 +01:00
while (!vdec->is_finished || !vdec->frames.IsEmpty())
2014-02-27 19:25:32 +01:00
{
if (Emu.IsStopped())
{
ConLog.Warning("cellVdecClose(%d) aborted", handle);
break;
}
Sleep(1);
}
if (vdec->vdecCb) Emu.GetCPU().RemoveThread(vdec->vdecCb->GetId());
2014-02-27 19:25:32 +01:00
Emu.GetIdManager().RemoveID(handle);
return CELL_OK;
}
int cellVdecStartSeq(u32 handle)
{
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));
return CELL_OK;
}
int cellVdecEndSeq(u32 handle)
{
2014-03-03 00:02:42 +01:00
cellVdec.Warning("cellVdecEndSeq(handle=%d)", handle);
2014-02-27 19:25:32 +01:00
VideoDecoder* vdec;
if (!Emu.GetIdManager().GetIDData(handle, vdec))
{
return CELL_VDEC_ERROR_ARG;
}
2014-03-03 00:02:42 +01:00
/*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);
}
2014-02-27 19:25:32 +01:00
vdec->job.Push(VdecTask(vdecEndSeq));
return CELL_OK;
}
int cellVdecDecodeAu(u32 handle, CellVdecDecodeMode mode, const mem_ptr_t<CellVdecAuInfo> auInfo)
{
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);
return CELL_OK;
}
int cellVdecGetPicture(u32 handle, const mem_ptr_t<CellVdecPicFormat> format, u32 out_addr)
{
2014-03-03 00:02:42 +01:00
cellVdec.Log("cellVdecGetPicture(handle=%d, format_addr=0x%x, out_addr=0x%x)", handle, format.GetAddr(), out_addr);
2014-03-01 09:38:50 +01:00
VideoDecoder* vdec;
if (!Emu.GetIdManager().GetIDData(handle, vdec))
{
return CELL_VDEC_ERROR_ARG;
}
if (!format.IsGood())
{
return CELL_VDEC_ERROR_FATAL;
}
2014-03-03 00:02:42 +01:00
if (vdec->frames.IsEmpty())
2014-03-01 09:38:50 +01:00
{
return CELL_VDEC_ERROR_EMPTY;
}
if (out_addr)
{
2014-03-03 00:02:42 +01:00
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))
2014-03-01 09:38:50 +01:00
{
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;
}
2014-03-03 00:02:42 +01:00
2014-03-01 09:38:50 +01:00
if (format->colorMatrixType != CELL_VDEC_COLOR_MATRIX_TYPE_BT709)
{
cellVdec.Error("cellVdecGetPicture: TODO: unknown colorMatrixType(%d)", (u32)format->colorMatrixType);
return CELL_OK;
}
2014-03-03 00:02:42 +01:00
VdecFrame vf;
2014-03-01 09:38:50 +01:00
2014-03-03 00:02:42 +01:00
vdec->frames.Pop(vf);
AVFrame& frame = *vf.data;
u8* buf = (u8*)malloc(buf_size);
2014-03-01 09:38:50 +01:00
// TODO: zero padding bytes
2014-03-03 00:02:42 +01:00
int err = av_image_copy_to_buffer(buf, buf_size, frame.data, frame.linesize, vdec->ctx->pix_fmt, frame.width, frame.height, 1);
2014-03-01 09:38:50 +01:00
if (err < 0)
{
cellVdec.Error("cellVdecGetPicture: av_image_copy_to_buffer failed(%d)", err);
Emu.Pause();
}
2014-03-03 00:02:42 +01:00
if (!Memory.CopyFromReal(out_addr, buf, buf_size))
2014-03-01 09:38:50 +01:00
{
cellVdec.Error("cellVdecGetPicture: data copying failed");
Emu.Pause();
}
2014-03-03 00:02:42 +01:00
av_frame_unref(vf.data);
av_frame_free(&vf.data);
2014-03-01 09:38:50 +01:00
free(buf);
}
return CELL_OK;
}
2014-03-01 09:38:50 +01:00
int cellVdecGetPicItem(u32 handle, mem32_t picItem_ptr)
{
2014-03-03 00:02:42 +01:00
cellVdec.Log("cellVdecGetPicItem(handle=%d, picItem_ptr_addr=0x%x)", handle, picItem_ptr.GetAddr());
2014-03-01 09:38:50 +01:00
VideoDecoder* vdec;
if (!Emu.GetIdManager().GetIDData(handle, vdec))
{
return CELL_VDEC_ERROR_ARG;
}
if (!picItem_ptr.IsGood())
{
return CELL_VDEC_ERROR_FATAL;
}
2014-03-03 00:02:42 +01:00
VdecFrame& vf = vdec->frames.Peek();
if (vdec->frames.IsEmpty())
2014-03-01 09:38:50 +01:00
{
2014-03-03 00:02:42 +01:00
Sleep(1);
2014-03-01 09:38:50 +01:00
return CELL_VDEC_ERROR_EMPTY;
}
2014-03-03 00:02:42 +01:00
AVFrame& frame = *vf.data;
mem_ptr_t<CellVdecPicItem> info(vdec->memAddr + vdec->memBias);
vdec->memBias += 512;
if (vdec->memBias + 512 > vdec->memSize)
{
vdec->memBias = 0;
}
2014-03-01 09:38:50 +01:00
info->codecType = vdec->type;
info->startAddr = 0x00000123; // invalid value (no address for picture)
2014-03-03 00:02:42 +01:00
info->size = a128(av_image_get_buffer_size(vdec->ctx->pix_fmt, vdec->ctx->width, vdec->ctx->height, 1));
2014-03-01 09:38:50 +01:00
info->auNum = 1;
2014-03-03 00:02:42 +01:00
info->auPts[0].lower = vf.pts;
info->auPts[0].upper = vf.pts >> 32;
2014-03-01 09:38:50 +01:00
info->auPts[1].lower = 0xffffffff;
info->auPts[1].upper = 0xffffffff;
2014-03-03 00:02:42 +01:00
info->auDts[0].lower = vf.dts;
info->auDts[0].upper = vf.dts >> 32;
2014-03-01 09:38:50 +01:00
info->auDts[1].lower = 0xffffffff;
info->auDts[1].upper = 0xffffffff;
2014-03-03 00:02:42 +01:00
info->auUserData[0] = vf.userdata;
2014-03-01 09:38:50 +01:00
info->auUserData[1] = 0;
info->status = CELL_OK;
info->attr = CELL_VDEC_PICITEM_ATTR_NORMAL;
info->picInfo_addr = info.GetAddr() + sizeof(CellVdecPicItem);
2014-03-01 09:38:50 +01:00
mem_ptr_t<CellVdecAvcInfo> avc(info.GetAddr() + sizeof(CellVdecPicItem));
2014-03-01 09:38:50 +01:00
2014-03-03 00:02:42 +01:00
avc->horizontalSize = frame.width;
avc->verticalSize = frame.height;
switch (frame.pict_type)
2014-03-01 09:38:50 +01:00
{
case AV_PICTURE_TYPE_I: avc->pictureType[0] = CELL_VDEC_AVC_PCT_I; break;
case AV_PICTURE_TYPE_P: avc->pictureType[0] = CELL_VDEC_AVC_PCT_P; break;
case AV_PICTURE_TYPE_B: avc->pictureType[0] = CELL_VDEC_AVC_PCT_B; break;
default: avc->pictureType[0] = CELL_VDEC_AVC_PCT_UNKNOWN; break; // ???
}
avc->pictureType[1] = CELL_VDEC_AVC_PCT_UNKNOWN; // ???
avc->idrPictureFlag = false; // ???
avc->aspect_ratio_idc = CELL_VDEC_AVC_ARI_SAR_UNSPECIFIED; // ???
avc->sar_height = 0;
avc->sar_width = 0;
avc->pic_struct = CELL_VDEC_AVC_PSTR_FRAME; // ???
avc->picOrderCount[0] = 0; // ???
avc->picOrderCount[1] = 0;
avc->vui_parameters_present_flag = true; // ???
avc->frame_mbs_only_flag = true; // ??? progressive
avc->video_signal_type_present_flag = true; // ???
avc->video_format = CELL_VDEC_AVC_VF_COMPONENT; // ???
avc->video_full_range_flag = false; // ???
avc->colour_description_present_flag = true;
avc->colour_primaries = CELL_VDEC_AVC_CP_ITU_R_BT_709_5; // ???
avc->transfer_characteristics = CELL_VDEC_AVC_TC_ITU_R_BT_709_5;
avc->matrix_coefficients = CELL_VDEC_AVC_MXC_ITU_R_BT_709_5; // important
avc->timing_info_present_flag = true;
avc->frameRateCode = CELL_VDEC_AVC_FRC_30000DIV1001; // important (!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)
avc->fixed_frame_rate_flag = true;
avc->low_delay_hrd_flag = true; // ???
avc->entropy_coding_mode_flag = true; // ???
avc->nalUnitPresentFlags = 0; // ???
avc->ccDataLength[0] = 0;
avc->ccDataLength[1] = 0;
avc->reserved[0] = 0;
avc->reserved[1] = 0;
picItem_ptr = info.GetAddr();
return CELL_OK;
}
int cellVdecSetFrameRate(u32 handle, CellVdecFrameRate frc)
{
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);
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
2014-03-03 00:02:42 +01:00
av_register_all();
2014-02-27 19:25:32 +01:00
avcodec_register_all();
}