2013-09-28 04:36:57 +02:00
|
|
|
#include "stdafx.h"
|
2014-06-02 19:27:24 +02:00
|
|
|
#include "Emu/System.h"
|
2015-03-06 23:58:42 +01:00
|
|
|
#include "Emu/IdManager.h"
|
2016-03-21 20:43:03 +01:00
|
|
|
#include "Emu/Cell/PPUModule.h"
|
2013-09-28 04:36:57 +02:00
|
|
|
|
2014-06-20 13:00:36 +02:00
|
|
|
std::mutex g_mutex_avcodec_open2;
|
2014-03-04 00:21:34 +01:00
|
|
|
|
2014-02-26 08:51:00 +01:00
|
|
|
extern "C"
|
|
|
|
|
{
|
2014-03-06 12:50:45 +01:00
|
|
|
#include "libavcodec/avcodec.h"
|
|
|
|
|
#include "libavutil/imgutils.h"
|
2015-04-17 15:24:22 +02:00
|
|
|
#include "libswscale/swscale.h"
|
2014-02-26 08:51:00 +01:00
|
|
|
}
|
|
|
|
|
|
2014-08-23 22:40:04 +02:00
|
|
|
#include "cellPamf.h"
|
2014-02-27 19:25:32 +01:00
|
|
|
#include "cellVdec.h"
|
|
|
|
|
|
2016-05-13 15:55:34 +02:00
|
|
|
#include <thread>
|
|
|
|
|
|
|
|
|
|
logs::channel cellVdec("cellVdec", logs::level::notice);
|
2016-03-21 20:43:03 +01:00
|
|
|
|
|
|
|
|
vm::gvar<s32> _cell_vdec_prx_ver; // ???
|
2013-09-28 04:36:57 +02:00
|
|
|
|
2015-06-24 13:53:47 +02:00
|
|
|
VideoDecoder::VideoDecoder(s32 type, u32 profile, u32 addr, u32 size, vm::ptr<CellVdecCbMsg> func, u32 arg)
|
2014-08-23 22:40:04 +02:00
|
|
|
: type(type)
|
|
|
|
|
, profile(profile)
|
|
|
|
|
, memAddr(addr)
|
|
|
|
|
, memSize(size)
|
|
|
|
|
, memBias(0)
|
|
|
|
|
, cbFunc(func)
|
|
|
|
|
, cbArg(arg)
|
|
|
|
|
, is_finished(false)
|
2014-10-18 00:20:03 +02:00
|
|
|
, is_closed(false)
|
2014-12-09 17:13:03 +01:00
|
|
|
, frc_set(0)
|
|
|
|
|
, codec(nullptr)
|
2014-08-23 22:40:04 +02:00
|
|
|
, ctx(nullptr)
|
|
|
|
|
{
|
2014-08-26 18:45:43 +02:00
|
|
|
avcodec_register_all();
|
|
|
|
|
|
2014-12-09 17:13:03 +01:00
|
|
|
switch (type)
|
|
|
|
|
{
|
|
|
|
|
case CELL_VDEC_CODEC_TYPE_MPEG2:
|
|
|
|
|
{
|
|
|
|
|
codec = avcodec_find_decoder(AV_CODEC_ID_MPEG2VIDEO);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CELL_VDEC_CODEC_TYPE_AVC:
|
|
|
|
|
{
|
|
|
|
|
codec = avcodec_find_decoder(AV_CODEC_ID_H264);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CELL_VDEC_CODEC_TYPE_DIVX:
|
|
|
|
|
{
|
|
|
|
|
codec = avcodec_find_decoder(AV_CODEC_ID_MPEG4);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
{
|
2016-07-22 14:54:35 +02:00
|
|
|
throw fmt::exception("Unknown video decoder type (0x%x)" HERE, type);
|
2014-12-09 17:13:03 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-23 22:40:04 +02:00
|
|
|
if (!codec)
|
|
|
|
|
{
|
2016-07-22 14:54:35 +02:00
|
|
|
throw fmt::exception("avcodec_find_decoder() failed (type=0x%x)" HERE, type);
|
2014-12-09 17:13:03 +01:00
|
|
|
}
|
2016-07-22 14:54:35 +02:00
|
|
|
|
|
|
|
|
ctx = avcodec_alloc_context3(codec);
|
|
|
|
|
|
|
|
|
|
if (!ctx)
|
2014-08-23 22:40:04 +02:00
|
|
|
{
|
2016-07-22 14:54:35 +02:00
|
|
|
throw fmt::exception("avcodec_alloc_context3() failed (type=0x%x)" HERE, type);
|
2014-08-23 22:40:04 +02:00
|
|
|
}
|
2016-07-22 14:54:35 +02:00
|
|
|
|
|
|
|
|
AVDictionary* opts{};
|
|
|
|
|
av_dict_set(&opts, "refcounted_frames", "1", 0);
|
|
|
|
|
|
|
|
|
|
std::lock_guard<std::mutex> lock(g_mutex_avcodec_open2);
|
|
|
|
|
|
|
|
|
|
int err = avcodec_open2(ctx, codec, &opts);
|
|
|
|
|
if (err || opts)
|
2014-08-23 22:40:04 +02:00
|
|
|
{
|
2016-07-22 14:54:35 +02:00
|
|
|
throw fmt::exception("avcodec_open2() failed (err=0x%x, opts=%d)" HERE, err, opts ? 1 : 0);
|
2014-08-23 22:40:04 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VideoDecoder::~VideoDecoder()
|
|
|
|
|
{
|
2014-10-18 19:00:21 +02:00
|
|
|
VdecFrame vf;
|
2014-12-24 23:24:17 +01:00
|
|
|
while (frames.try_pop(vf))
|
2014-10-18 00:20:03 +02:00
|
|
|
{
|
|
|
|
|
av_frame_unref(vf.data);
|
|
|
|
|
av_frame_free(&vf.data);
|
|
|
|
|
}
|
2016-07-22 14:54:35 +02:00
|
|
|
|
2014-08-23 22:40:04 +02:00
|
|
|
if (ctx)
|
|
|
|
|
{
|
|
|
|
|
avcodec_close(ctx);
|
2016-07-22 14:54:35 +02:00
|
|
|
avcodec_free_context(&ctx);
|
2014-03-02 00:50:47 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-24 13:53:47 +02:00
|
|
|
u32 vdecQueryAttr(s32 type, u32 profile, u32 spec_addr /* may be 0 */, vm::ptr<CellVdecAttr> attr)
|
2013-09-28 04:36:57 +02:00
|
|
|
{
|
2014-02-27 19:25:32 +01:00
|
|
|
switch (type) // TODO: check profile levels
|
|
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
case CELL_VDEC_CODEC_TYPE_AVC: cellVdec.warning("cellVdecQueryAttr: AVC (profile=%d)", profile); break;
|
|
|
|
|
case CELL_VDEC_CODEC_TYPE_MPEG2: cellVdec.warning("cellVdecQueryAttr: MPEG2 (profile=%d)", profile); break;
|
|
|
|
|
case CELL_VDEC_CODEC_TYPE_DIVX: cellVdec.warning("cellVdecQueryAttr: DivX (profile=%d)", profile); break;
|
2014-02-27 19:25:32 +01:00
|
|
|
default: return CELL_VDEC_ERROR_ARG;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: check values
|
|
|
|
|
attr->decoderVerLower = 0x280000; // from dmux
|
|
|
|
|
attr->decoderVerUpper = 0x260000;
|
2014-09-09 23:18:21 +02:00
|
|
|
attr->memSize = 4 * 1024 * 1024; // 4 MB
|
2014-03-01 09:38:50 +01:00
|
|
|
attr->cmdDepth = 16;
|
2013-09-28 04:36:57 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
void vdecOpen(u32 vdec_id) // TODO: call from the constructor
|
2014-02-27 19:25:32 +01:00
|
|
|
{
|
2015-08-05 17:30:32 +02:00
|
|
|
const auto sptr = idm::get<VideoDecoder>(vdec_id);
|
2014-02-27 19:25:32 +01:00
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
VideoDecoder& vdec = *sptr;
|
2014-02-27 19:25:32 +01:00
|
|
|
|
|
|
|
|
vdec.id = vdec_id;
|
|
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
vdec.vdecCb = idm::make_ptr<PPUThread>(fmt::format("VideoDecoder[0x%x] Thread", vdec_id));
|
2015-07-01 00:25:52 +02:00
|
|
|
vdec.vdecCb->prio = 1001;
|
|
|
|
|
vdec.vdecCb->stack_size = 0x10000;
|
2015-08-13 15:28:42 +02:00
|
|
|
vdec.vdecCb->custom_task = [sptr](PPUThread& ppu)
|
2014-02-27 19:25:32 +01:00
|
|
|
{
|
2015-05-27 05:11:59 +02:00
|
|
|
VideoDecoder& vdec = *sptr;
|
2014-03-04 00:21:34 +01:00
|
|
|
VdecTask& task = vdec.task;
|
2014-02-27 19:25:32 +01:00
|
|
|
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
2014-10-18 00:20:03 +02:00
|
|
|
if (Emu.IsStopped() || vdec.is_closed)
|
2014-02-27 19:25:32 +01:00
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-24 23:24:17 +01:00
|
|
|
if (!vdec.job.pop(task, &vdec.is_closed))
|
2014-02-27 19:25:32 +01:00
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (task.type)
|
|
|
|
|
{
|
|
|
|
|
case vdecStartSeq:
|
2014-08-23 22:40:04 +02:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
cellVdec.warning("vdecStartSeq:");
|
2016-07-22 14:54:35 +02:00
|
|
|
avcodec_flush_buffers(vdec.ctx);
|
2014-03-03 00:02:42 +01:00
|
|
|
|
2016-07-22 14:54:35 +02:00
|
|
|
vdec.frc_set = 0; // TODO: ???
|
|
|
|
|
vdec.last_pts = 0;
|
|
|
|
|
vdec.last_dts = 0;
|
2014-12-09 17:13:03 +01:00
|
|
|
break;
|
2014-08-23 22:40:04 +02:00
|
|
|
}
|
2014-02-27 19:25:32 +01:00
|
|
|
|
|
|
|
|
case vdecDecodeAu:
|
2016-07-22 14:54:35 +02:00
|
|
|
case vdecEndSeq:
|
2014-08-23 22:40:04 +02:00
|
|
|
{
|
2016-07-22 14:54:35 +02:00
|
|
|
AVPacket packet{};
|
2014-02-27 19:25:32 +01:00
|
|
|
|
2016-07-22 14:54:35 +02:00
|
|
|
if (task.type == vdecDecodeAu)
|
2014-08-23 22:40:04 +02:00
|
|
|
{
|
2016-07-22 14:54:35 +02:00
|
|
|
packet.pts = vdec.task.pts != -1 ? vdec.task.pts : AV_NOPTS_VALUE;
|
|
|
|
|
packet.dts = vdec.task.dts != -1 ? vdec.task.dts : AV_NOPTS_VALUE;
|
|
|
|
|
packet.data = vm::_ptr<u8>(vdec.task.addr);
|
|
|
|
|
packet.size = vdec.task.size;
|
|
|
|
|
cellVdec.trace("vdecDecodeAu: size = 0x%x, pts = 0x%llx, dts = 0x%llx", task.size, task.pts, task.dts);
|
2014-08-23 22:40:04 +02:00
|
|
|
}
|
2016-07-22 14:54:35 +02:00
|
|
|
else
|
2014-08-23 22:40:04 +02:00
|
|
|
{
|
2016-07-22 14:54:35 +02:00
|
|
|
packet.pts = AV_NOPTS_VALUE;
|
|
|
|
|
packet.dts = AV_NOPTS_VALUE;
|
|
|
|
|
packet.data = nullptr;
|
|
|
|
|
packet.size = 0;
|
|
|
|
|
cellVdec.warning("vdecEndSeq");
|
2014-08-23 22:40:04 +02:00
|
|
|
}
|
2014-03-04 00:21:34 +01:00
|
|
|
|
2014-08-23 22:40:04 +02:00
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
|
struct VdecFrameHolder : VdecFrame
|
|
|
|
|
{
|
|
|
|
|
VdecFrameHolder()
|
2014-03-04 00:21:34 +01:00
|
|
|
{
|
2014-08-23 22:40:04 +02:00
|
|
|
data = av_frame_alloc();
|
2014-03-04 00:21:34 +01:00
|
|
|
}
|
|
|
|
|
|
2014-08-23 22:40:04 +02:00
|
|
|
~VdecFrameHolder()
|
2014-03-03 00:02:42 +01:00
|
|
|
{
|
2014-08-23 22:40:04 +02:00
|
|
|
if (data)
|
2014-03-03 00:02:42 +01:00
|
|
|
{
|
2014-08-23 22:40:04 +02:00
|
|
|
av_frame_unref(data);
|
|
|
|
|
av_frame_free(&data);
|
2014-03-03 00:02:42 +01:00
|
|
|
}
|
2014-08-23 22:40:04 +02:00
|
|
|
}
|
2014-03-03 00:02:42 +01:00
|
|
|
|
2014-08-23 22:40:04 +02:00
|
|
|
} frame;
|
2014-03-03 00:02:42 +01:00
|
|
|
|
2014-08-23 22:40:04 +02:00
|
|
|
if (!frame.data)
|
|
|
|
|
{
|
2016-07-22 14:54:35 +02:00
|
|
|
throw fmt::exception("av_frame_alloc() failed" HERE);
|
2014-08-23 22:40:04 +02:00
|
|
|
}
|
2014-03-01 09:38:50 +01:00
|
|
|
|
2014-08-23 22:40:04 +02:00
|
|
|
int got_picture = 0;
|
2014-03-01 09:38:50 +01:00
|
|
|
|
2016-07-22 14:54:35 +02:00
|
|
|
int decode = avcodec_decode_video2(vdec.ctx, frame.data, &got_picture, &packet);
|
2014-03-01 09:38:50 +01:00
|
|
|
|
2016-07-22 14:54:35 +02:00
|
|
|
if (decode < 0)
|
2014-08-23 22:40:04 +02:00
|
|
|
{
|
2016-07-22 14:54:35 +02:00
|
|
|
throw fmt::exception("vdecDecodeAu: AU decoding error(0x%x)" HERE, decode);
|
2014-08-23 22:40:04 +02:00
|
|
|
}
|
2014-03-03 00:02:42 +01:00
|
|
|
|
2016-07-22 14:54:35 +02:00
|
|
|
if (got_picture == 0)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (decode != packet.size)
|
|
|
|
|
{
|
|
|
|
|
cellVdec.error("vdecDecodeAu: incorrect AU size (0x%x, decoded 0x%x)", packet.size, decode);
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-23 22:40:04 +02:00
|
|
|
if (got_picture)
|
|
|
|
|
{
|
2014-12-09 17:13:03 +01:00
|
|
|
if (frame.data->interlaced_frame)
|
|
|
|
|
{
|
2015-07-21 16:39:35 +02:00
|
|
|
throw EXCEPTION("Interlaced frames not supported (0x%x)", frame.data->interlaced_frame);
|
2014-12-09 17:13:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (frame.data->repeat_pict)
|
2014-03-03 00:02:42 +01:00
|
|
|
{
|
2015-07-21 16:39:35 +02:00
|
|
|
throw EXCEPTION("Repeated frames not supported (0x%x)", frame.data->repeat_pict);
|
2014-12-09 17:13:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (vdec.frc_set)
|
|
|
|
|
{
|
2016-07-22 14:54:35 +02:00
|
|
|
u64 amend = 0;
|
|
|
|
|
|
|
|
|
|
switch (vdec.frc_set)
|
2014-12-09 17:13:03 +01:00
|
|
|
{
|
2016-07-22 14:54:35 +02:00
|
|
|
case CELL_VDEC_FRC_24000DIV1001: amend = 1001 * 90000 / 24000; break;
|
|
|
|
|
case CELL_VDEC_FRC_24: amend = 90000 / 24; break;
|
|
|
|
|
case CELL_VDEC_FRC_25: amend = 90000 / 25; break;
|
|
|
|
|
case CELL_VDEC_FRC_30000DIV1001: amend = 1001 * 90000 / 30000; break;
|
|
|
|
|
case CELL_VDEC_FRC_30: amend = 90000 / 30; break;
|
|
|
|
|
case CELL_VDEC_FRC_50: amend = 90000 / 50; break;
|
|
|
|
|
case CELL_VDEC_FRC_60000DIV1001: amend = 1001 * 90000 / 60000; break;
|
|
|
|
|
case CELL_VDEC_FRC_60: amend = 90000 / 60; break;
|
2014-12-09 17:13:03 +01:00
|
|
|
default:
|
|
|
|
|
{
|
2015-07-21 16:39:35 +02:00
|
|
|
throw EXCEPTION("Invalid frame rate code set (0x%x)", vdec.frc_set);
|
2014-12-09 17:13:03 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-22 14:54:35 +02:00
|
|
|
vdec.last_pts += amend;
|
|
|
|
|
vdec.last_dts += amend;
|
2014-12-09 17:13:03 +01:00
|
|
|
frame.frc = vdec.frc_set;
|
2014-08-23 22:40:04 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-07-22 14:54:35 +02:00
|
|
|
const u64 amend = vdec.ctx->time_base.num * 90000 * vdec.ctx->ticks_per_frame / vdec.ctx->time_base.den;
|
|
|
|
|
vdec.last_pts += amend;
|
|
|
|
|
vdec.last_dts += amend;
|
2014-12-09 17:13:03 +01:00
|
|
|
|
|
|
|
|
if (vdec.ctx->time_base.num == 1)
|
|
|
|
|
{
|
|
|
|
|
switch ((u64)vdec.ctx->time_base.den + (u64)(vdec.ctx->ticks_per_frame - 1) * 0x100000000ull)
|
|
|
|
|
{
|
2014-12-11 20:25:11 +01:00
|
|
|
case 24: case 0x100000000ull + 48: frame.frc = CELL_VDEC_FRC_24; break;
|
|
|
|
|
case 25: case 0x100000000ull + 50: frame.frc = CELL_VDEC_FRC_25; break;
|
|
|
|
|
case 30: case 0x100000000ull + 60: frame.frc = CELL_VDEC_FRC_30; break;
|
|
|
|
|
case 50: case 0x100000000ull + 100: frame.frc = CELL_VDEC_FRC_50; break;
|
|
|
|
|
case 60: case 0x100000000ull + 120: frame.frc = CELL_VDEC_FRC_60; break;
|
2014-12-09 17:13:03 +01:00
|
|
|
default:
|
|
|
|
|
{
|
2015-07-21 16:39:35 +02:00
|
|
|
throw EXCEPTION("Unsupported time_base.den (%d/1, tpf=%d)", vdec.ctx->time_base.den, vdec.ctx->ticks_per_frame);
|
2014-12-09 17:13:03 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (vdec.ctx->time_base.num == 1001)
|
|
|
|
|
{
|
|
|
|
|
if (vdec.ctx->time_base.den / vdec.ctx->ticks_per_frame == 24000)
|
|
|
|
|
{
|
|
|
|
|
frame.frc = CELL_VDEC_FRC_24000DIV1001;
|
|
|
|
|
}
|
|
|
|
|
else if (vdec.ctx->time_base.den / vdec.ctx->ticks_per_frame == 30000)
|
|
|
|
|
{
|
|
|
|
|
frame.frc = CELL_VDEC_FRC_30000DIV1001;
|
|
|
|
|
}
|
2014-12-09 18:24:50 +01:00
|
|
|
else if (vdec.ctx->time_base.den / vdec.ctx->ticks_per_frame == 60000)
|
|
|
|
|
{
|
|
|
|
|
frame.frc = CELL_VDEC_FRC_60000DIV1001;
|
|
|
|
|
}
|
2014-12-09 17:13:03 +01:00
|
|
|
else
|
|
|
|
|
{
|
2015-07-21 16:39:35 +02:00
|
|
|
throw EXCEPTION("Unsupported time_base.den (%d/1001, tpf=%d)", vdec.ctx->time_base.den, vdec.ctx->ticks_per_frame);
|
2014-12-09 17:13:03 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2015-07-21 16:39:35 +02:00
|
|
|
throw EXCEPTION("Unsupported time_base.num (%d)", vdec.ctx->time_base.num);
|
2014-12-09 17:13:03 +01:00
|
|
|
}
|
2014-08-23 22:40:04 +02:00
|
|
|
}
|
2014-12-09 17:13:03 +01:00
|
|
|
|
2016-07-22 14:54:35 +02:00
|
|
|
frame.pts = vdec.last_pts = frame.data->pkt_pts != AV_NOPTS_VALUE ? frame.data->pkt_pts : vdec.last_pts;
|
|
|
|
|
frame.dts = vdec.last_dts = frame.data->pkt_dts != AV_NOPTS_VALUE ? frame.data->pkt_dts : vdec.last_dts;
|
2014-08-23 22:40:04 +02:00
|
|
|
frame.userdata = task.userData;
|
2014-03-19 01:32:23 +01:00
|
|
|
|
2016-07-22 14:54:35 +02:00
|
|
|
cellVdec.trace("got picture (pts=0x%llx, dts=0x%llx)", frame.pts, frame.dts);
|
2014-03-19 01:32:23 +01:00
|
|
|
|
2014-12-24 23:24:17 +01:00
|
|
|
if (vdec.frames.push(frame, &vdec.is_closed))
|
2014-10-18 00:20:03 +02:00
|
|
|
{
|
|
|
|
|
frame.data = nullptr; // to prevent destruction
|
2015-01-11 11:43:40 +01:00
|
|
|
vdec.cbFunc(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_PICOUT, CELL_OK, vdec.cbArg);
|
2014-10-18 00:20:03 +02:00
|
|
|
}
|
2014-03-01 09:38:50 +01:00
|
|
|
}
|
2016-07-22 14:54:35 +02:00
|
|
|
|
|
|
|
|
if (task.type == vdecDecodeAu)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
2014-02-27 19:25:32 +01:00
|
|
|
}
|
2014-08-23 22:40:04 +02:00
|
|
|
|
2016-07-22 14:54:35 +02:00
|
|
|
if (task.type == vdecDecodeAu)
|
|
|
|
|
{
|
|
|
|
|
vdec.cbFunc(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, vdec.cbArg);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
vdec.cbFunc(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_SEQDONE, CELL_OK, vdec.cbArg);
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-09 17:13:03 +01:00
|
|
|
break;
|
2014-08-23 22:40:04 +02:00
|
|
|
}
|
2014-02-27 19:25:32 +01:00
|
|
|
|
|
|
|
|
case vdecSetFrameRate:
|
2014-08-23 22:40:04 +02:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
cellVdec.warning("vdecSetFrameRate(0x%x)", task.frc);
|
2014-12-09 17:13:03 +01:00
|
|
|
vdec.frc_set = task.frc;
|
|
|
|
|
break;
|
2014-08-23 22:40:04 +02:00
|
|
|
}
|
2014-02-27 19:25:32 +01:00
|
|
|
|
2014-12-12 01:21:34 +01:00
|
|
|
case vdecClose:
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
2014-10-18 00:20:03 +02:00
|
|
|
|
2014-02-27 19:25:32 +01:00
|
|
|
default:
|
2014-10-18 00:20:03 +02:00
|
|
|
{
|
2016-07-22 14:54:35 +02:00
|
|
|
throw fmt::exception("Unknown task(%d)" HERE, task.type);
|
2014-10-18 00:20:03 +02:00
|
|
|
}
|
2014-02-27 19:25:32 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-04 00:21:34 +01:00
|
|
|
vdec.is_finished = true;
|
2015-07-01 00:25:52 +02:00
|
|
|
};
|
|
|
|
|
|
2016-03-21 20:43:03 +01:00
|
|
|
vdec.vdecCb->cpu_init();
|
|
|
|
|
vdec.vdecCb->state -= cpu_state::stop;
|
2016-05-13 15:55:34 +02:00
|
|
|
(*vdec.vdecCb)->lock_notify();
|
2014-02-27 19:25:32 +01:00
|
|
|
}
|
|
|
|
|
|
2015-06-22 00:27:58 +02:00
|
|
|
s32 cellVdecQueryAttr(vm::cptr<CellVdecType> type, vm::ptr<CellVdecAttr> attr)
|
2014-02-27 19:25:32 +01:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
cellVdec.warning("cellVdecQueryAttr(type=*0x%x, attr=*0x%x)", type, attr);
|
2014-02-27 19:25:32 +01:00
|
|
|
|
|
|
|
|
return vdecQueryAttr(type->codecType, type->profileLevel, 0, attr);
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-22 00:27:58 +02:00
|
|
|
s32 cellVdecQueryAttrEx(vm::cptr<CellVdecTypeEx> type, vm::ptr<CellVdecAttr> attr)
|
2013-09-28 04:36:57 +02:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
cellVdec.warning("cellVdecQueryAttrEx(type=*0x%x, attr=*0x%x)", type, attr);
|
2014-02-27 19:25:32 +01:00
|
|
|
|
|
|
|
|
return vdecQueryAttr(type->codecType, type->profileLevel, type->codecSpecificInfo_addr, attr);
|
2013-09-28 04:36:57 +02:00
|
|
|
}
|
|
|
|
|
|
2015-06-22 00:27:58 +02:00
|
|
|
s32 cellVdecOpen(vm::cptr<CellVdecType> type, vm::cptr<CellVdecResource> res, vm::cptr<CellVdecCb> cb, vm::ptr<u32> handle)
|
2013-09-28 04:36:57 +02:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
cellVdec.warning("cellVdecOpen(type=*0x%x, res=*0x%x, cb=*0x%x, handle=*0x%x)", type, res, cb, handle);
|
2014-02-27 19:25:32 +01:00
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
vdecOpen(*handle = idm::make<VideoDecoder>(type->codecType, type->profileLevel, res->memAddr, res->memSize, cb->cbFunc, cb->cbArg));
|
2014-02-27 19:25:32 +01:00
|
|
|
|
2013-09-28 04:36:57 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-22 00:27:58 +02:00
|
|
|
s32 cellVdecOpenEx(vm::cptr<CellVdecTypeEx> type, vm::cptr<CellVdecResourceEx> res, vm::cptr<CellVdecCb> cb, vm::ptr<u32> handle)
|
2013-09-28 04:36:57 +02:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
cellVdec.warning("cellVdecOpenEx(type=*0x%x, res=*0x%x, cb=*0x%x, handle=*0x%x)", type, res, cb, handle);
|
2014-02-27 19:25:32 +01:00
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
vdecOpen(*handle = idm::make<VideoDecoder>(type->codecType, type->profileLevel, res->memAddr, res->memSize, cb->cbFunc, cb->cbArg));
|
2014-02-27 19:25:32 +01:00
|
|
|
|
2013-09-28 04:36:57 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-12 22:16:30 +02:00
|
|
|
s32 cellVdecClose(u32 handle)
|
2013-09-28 04:36:57 +02:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
cellVdec.warning("cellVdecClose(handle=0x%x)", handle);
|
2014-02-27 19:25:32 +01:00
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
const auto vdec = idm::get<VideoDecoder>(handle);
|
2015-04-12 22:16:30 +02:00
|
|
|
|
|
|
|
|
if (!vdec)
|
2014-02-27 19:25:32 +01:00
|
|
|
{
|
|
|
|
|
return CELL_VDEC_ERROR_ARG;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-18 00:20:03 +02:00
|
|
|
vdec->is_closed = true;
|
2014-12-24 23:24:17 +01:00
|
|
|
vdec->job.try_push(VdecTask(vdecClose));
|
2014-02-27 19:25:32 +01:00
|
|
|
|
2014-06-29 05:21:57 +02:00
|
|
|
while (!vdec->is_finished)
|
2014-02-27 19:25:32 +01:00
|
|
|
{
|
2015-07-04 01:22:24 +02:00
|
|
|
CHECK_EMU_STATUS;
|
|
|
|
|
|
2016-05-13 15:55:34 +02:00
|
|
|
std::this_thread::sleep_for(1ms); // hack
|
2014-02-27 19:25:32 +01:00
|
|
|
}
|
|
|
|
|
|
2016-03-21 20:43:03 +01:00
|
|
|
idm::remove<PPUThread>(vdec->vdecCb->id);
|
2015-08-05 17:30:32 +02:00
|
|
|
idm::remove<VideoDecoder>(handle);
|
2013-09-28 04:36:57 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-12 22:16:30 +02:00
|
|
|
s32 cellVdecStartSeq(u32 handle)
|
2013-09-28 04:36:57 +02:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
cellVdec.trace("cellVdecStartSeq(handle=0x%x)", handle);
|
2014-02-27 19:25:32 +01:00
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
const auto vdec = idm::get<VideoDecoder>(handle);
|
2014-02-27 19:25:32 +01:00
|
|
|
|
2015-04-12 22:16:30 +02:00
|
|
|
if (!vdec)
|
2014-02-27 19:25:32 +01:00
|
|
|
{
|
|
|
|
|
return CELL_VDEC_ERROR_ARG;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-24 23:24:17 +01:00
|
|
|
vdec->job.push(VdecTask(vdecStartSeq), &vdec->is_closed);
|
2013-09-28 04:36:57 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-12 22:16:30 +02:00
|
|
|
s32 cellVdecEndSeq(u32 handle)
|
2013-09-28 04:36:57 +02:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
cellVdec.warning("cellVdecEndSeq(handle=0x%x)", handle);
|
2014-02-27 19:25:32 +01:00
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
const auto vdec = idm::get<VideoDecoder>(handle);
|
2014-02-27 19:25:32 +01:00
|
|
|
|
2015-04-12 22:16:30 +02:00
|
|
|
if (!vdec)
|
2014-02-27 19:25:32 +01:00
|
|
|
{
|
|
|
|
|
return CELL_VDEC_ERROR_ARG;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-24 23:24:17 +01:00
|
|
|
vdec->job.push(VdecTask(vdecEndSeq), &vdec->is_closed);
|
2013-09-28 04:36:57 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-22 00:27:58 +02:00
|
|
|
s32 cellVdecDecodeAu(u32 handle, CellVdecDecodeMode mode, vm::cptr<CellVdecAuInfo> auInfo)
|
2013-09-28 04:36:57 +02:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
cellVdec.trace("cellVdecDecodeAu(handle=0x%x, mode=%d, auInfo=*0x%x)", handle, mode, auInfo);
|
2014-02-27 19:25:32 +01:00
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
const auto vdec = idm::get<VideoDecoder>(handle);
|
2014-02-27 19:25:32 +01:00
|
|
|
|
2015-04-12 22:16:30 +02:00
|
|
|
if (!vdec || mode > CELL_VDEC_DEC_MODE_PB_SKIP)
|
2014-02-27 19:25:32 +01:00
|
|
|
{
|
|
|
|
|
return CELL_VDEC_ERROR_ARG;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-12 22:16:30 +02:00
|
|
|
if (mode != CELL_VDEC_DEC_MODE_NORMAL)
|
|
|
|
|
{
|
2015-07-10 16:45:16 +02:00
|
|
|
throw EXCEPTION("Unsupported decoding mode (%d)", mode);
|
2015-04-12 22:16:30 +02:00
|
|
|
}
|
|
|
|
|
|
2014-02-27 19:25:32 +01:00
|
|
|
// 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;
|
|
|
|
|
|
2014-12-24 23:24:17 +01:00
|
|
|
vdec->job.push(task, &vdec->is_closed);
|
2013-09-28 04:36:57 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-22 00:27:58 +02:00
|
|
|
s32 cellVdecGetPicture(u32 handle, vm::cptr<CellVdecPicFormat> format, vm::ptr<u8> outBuff)
|
2013-09-28 04:36:57 +02:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
cellVdec.trace("cellVdecGetPicture(handle=0x%x, format=*0x%x, outBuff=*0x%x)", handle, format, outBuff);
|
2014-03-01 09:38:50 +01:00
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
const auto vdec = idm::get<VideoDecoder>(handle);
|
2014-03-01 09:38:50 +01:00
|
|
|
|
2015-04-17 15:24:22 +02:00
|
|
|
if (!vdec || !format)
|
2014-03-01 09:38:50 +01:00
|
|
|
{
|
|
|
|
|
return CELL_VDEC_ERROR_ARG;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-18 19:00:21 +02:00
|
|
|
VdecFrame vf;
|
2014-12-24 23:24:17 +01:00
|
|
|
if (!vdec->frames.try_pop(vf))
|
2014-03-01 09:38:50 +01:00
|
|
|
{
|
2016-05-13 15:55:34 +02:00
|
|
|
//std::this_thread::sleep_for(1ms); // hack
|
2014-03-01 09:38:50 +01:00
|
|
|
return CELL_VDEC_ERROR_EMPTY;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-18 19:00:21 +02:00
|
|
|
if (!vf.data)
|
|
|
|
|
{
|
|
|
|
|
// hack
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-11 12:39:51 +01:00
|
|
|
std::unique_ptr<AVFrame, void(*)(AVFrame*)> frame(vf.data, [](AVFrame* frame)
|
2014-03-01 09:38:50 +01:00
|
|
|
{
|
2015-02-11 12:39:51 +01:00
|
|
|
av_frame_unref(frame);
|
|
|
|
|
av_frame_free(&frame);
|
|
|
|
|
});
|
2014-03-03 00:02:42 +01:00
|
|
|
|
2015-02-11 12:39:51 +01:00
|
|
|
if (outBuff)
|
|
|
|
|
{
|
2015-04-17 15:24:22 +02:00
|
|
|
const auto f = vdec->ctx->pix_fmt;
|
|
|
|
|
const auto w = vdec->ctx->width;
|
|
|
|
|
const auto h = vdec->ctx->height;
|
|
|
|
|
|
|
|
|
|
auto out_f = AV_PIX_FMT_YUV420P;
|
|
|
|
|
|
2015-04-21 21:35:11 +02:00
|
|
|
std::unique_ptr<u8[]> alpha_plane;
|
2015-04-17 15:24:22 +02:00
|
|
|
|
2015-04-17 22:16:55 +02:00
|
|
|
switch (const u32 type = format->formatType)
|
2014-03-01 09:38:50 +01:00
|
|
|
{
|
2015-04-17 15:24:22 +02:00
|
|
|
case CELL_VDEC_PICFMT_ARGB32_ILV: out_f = AV_PIX_FMT_ARGB; alpha_plane.reset(new u8[w * h]); break;
|
|
|
|
|
case CELL_VDEC_PICFMT_RGBA32_ILV: out_f = AV_PIX_FMT_RGBA; alpha_plane.reset(new u8[w * h]); break;
|
|
|
|
|
case CELL_VDEC_PICFMT_UYVY422_ILV: out_f = AV_PIX_FMT_UYVY422; break;
|
|
|
|
|
case CELL_VDEC_PICFMT_YUV420_PLANAR: out_f = AV_PIX_FMT_YUV420P; break;
|
2015-04-18 19:18:23 +02:00
|
|
|
|
|
|
|
|
default:
|
2014-03-01 09:38:50 +01:00
|
|
|
{
|
2015-07-10 16:45:16 +02:00
|
|
|
throw EXCEPTION("Unknown formatType(%d)", type);
|
2015-04-18 19:18:23 +02:00
|
|
|
}
|
2014-03-01 09:38:50 +01:00
|
|
|
}
|
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)
|
|
|
|
|
{
|
2015-07-10 16:45:16 +02:00
|
|
|
throw EXCEPTION("Unknown colorMatrixType(%d)", format->colorMatrixType);
|
2014-03-01 09:38:50 +01:00
|
|
|
}
|
|
|
|
|
|
2015-04-17 15:24:22 +02:00
|
|
|
if (alpha_plane)
|
|
|
|
|
{
|
|
|
|
|
memset(alpha_plane.get(), format->alpha, w * h);
|
|
|
|
|
}
|
2014-03-03 00:02:42 +01:00
|
|
|
|
2015-04-17 15:24:22 +02:00
|
|
|
auto in_f = AV_PIX_FMT_YUV420P;
|
2014-03-01 09:38:50 +01:00
|
|
|
|
2015-04-17 15:24:22 +02:00
|
|
|
switch (f)
|
2014-03-01 09:38:50 +01:00
|
|
|
{
|
2015-04-17 15:24:22 +02:00
|
|
|
case AV_PIX_FMT_YUV420P: in_f = alpha_plane ? AV_PIX_FMT_YUVA420P : AV_PIX_FMT_YUV420P; break;
|
2015-04-18 19:18:23 +02:00
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
{
|
2015-07-10 16:45:16 +02:00
|
|
|
throw EXCEPTION("Unknown pix_fmt(%d)", f);
|
2015-04-18 19:18:23 +02:00
|
|
|
}
|
2014-03-01 09:38:50 +01:00
|
|
|
}
|
2015-04-17 15:24:22 +02:00
|
|
|
|
|
|
|
|
std::unique_ptr<SwsContext, void(*)(SwsContext*)> sws(sws_getContext(w, h, in_f, w, h, out_f, SWS_POINT, NULL, NULL, NULL), sws_freeContext);
|
2014-03-03 00:02:42 +01:00
|
|
|
|
2015-04-17 15:24:22 +02:00
|
|
|
u8* in_data[4] = { frame->data[0], frame->data[1], frame->data[2], alpha_plane.get() };
|
|
|
|
|
int in_line[4] = { frame->linesize[0], frame->linesize[1], frame->linesize[2], w * 1 };
|
|
|
|
|
u8* out_data[4] = { outBuff.get_ptr() };
|
|
|
|
|
int out_line[4] = { w * 4 };
|
2014-03-01 09:38:50 +01:00
|
|
|
|
2015-04-17 15:24:22 +02:00
|
|
|
if (!alpha_plane)
|
2014-03-01 09:38:50 +01:00
|
|
|
{
|
2015-04-17 15:24:22 +02:00
|
|
|
out_data[1] = out_data[0] + w * h;
|
|
|
|
|
out_data[2] = out_data[0] + w * h * 5 / 4;
|
|
|
|
|
out_line[0] = w;
|
|
|
|
|
out_line[1] = w / 2;
|
|
|
|
|
out_line[2] = w / 2;
|
2014-03-01 09:38:50 +01:00
|
|
|
}
|
2015-04-17 15:24:22 +02:00
|
|
|
|
2015-04-18 01:13:43 +02:00
|
|
|
sws_scale(sws.get(), in_data, in_line, 0, h, out_data, out_line);
|
2015-04-17 15:24:22 +02:00
|
|
|
|
|
|
|
|
//const u32 buf_size = align(av_image_get_buffer_size(vdec->ctx->pix_fmt, vdec->ctx->width, vdec->ctx->height, 1), 128);
|
|
|
|
|
|
|
|
|
|
//// TODO: zero padding bytes
|
|
|
|
|
|
|
|
|
|
//int err = av_image_copy_to_buffer(outBuff.get_ptr(), buf_size, frame->data, frame->linesize, vdec->ctx->pix_fmt, frame->width, frame->height, 1);
|
|
|
|
|
//if (err < 0)
|
|
|
|
|
//{
|
|
|
|
|
// cellVdec.Fatal("cellVdecGetPicture: av_image_copy_to_buffer failed (err=0x%x)", err);
|
|
|
|
|
//}
|
2014-03-01 09:38:50 +01:00
|
|
|
}
|
|
|
|
|
|
2013-09-28 04:36:57 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-26 22:46:04 +02:00
|
|
|
s32 cellVdecGetPictureExt(u32 handle, vm::cptr<CellVdecPicFormat2> format2, vm::ptr<u8> outBuff, u32 arg4)
|
2013-09-28 04:36:57 +02:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
cellVdec.warning("cellVdecGetPictureExt(handle=0x%x, format2=*0x%x, outBuff=*0x%x, arg4=*0x%x)", handle, format2, outBuff, arg4);
|
2014-03-01 09:38:50 +01:00
|
|
|
|
2015-04-17 15:24:22 +02:00
|
|
|
if (arg4 || format2->unk0 || format2->unk1)
|
|
|
|
|
{
|
2015-07-10 16:45:16 +02:00
|
|
|
throw EXCEPTION("Unknown arguments (arg4=*0x%x, unk0=0x%x, unk1=0x%x)", arg4, format2->unk0, format2->unk1);
|
2015-04-17 15:24:22 +02:00
|
|
|
}
|
|
|
|
|
|
2015-09-26 22:46:04 +02:00
|
|
|
vm::var<CellVdecPicFormat> format;
|
2015-04-17 15:24:22 +02:00
|
|
|
format->formatType = format2->formatType;
|
|
|
|
|
format->colorMatrixType = format2->colorMatrixType;
|
|
|
|
|
format->alpha = format2->alpha;
|
|
|
|
|
|
|
|
|
|
return cellVdecGetPicture(handle, format, outBuff);
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-14 23:52:22 +02:00
|
|
|
s32 cellVdecGetPicItem(u32 handle, vm::pptr<CellVdecPicItem> picItem)
|
2013-09-28 04:36:57 +02:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
cellVdec.trace("cellVdecGetPicItem(handle=0x%x, picItem=**0x%x)", handle, picItem);
|
2015-04-12 22:16:30 +02:00
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
const auto vdec = idm::get<VideoDecoder>(handle);
|
2014-03-01 09:38:50 +01:00
|
|
|
|
2015-04-12 22:16:30 +02:00
|
|
|
if (!vdec)
|
2014-03-01 09:38:50 +01:00
|
|
|
{
|
|
|
|
|
return CELL_VDEC_ERROR_ARG;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-18 19:00:21 +02:00
|
|
|
VdecFrame vf;
|
2014-12-24 23:24:17 +01:00
|
|
|
if (!vdec->frames.try_peek(vf))
|
2014-03-01 09:38:50 +01:00
|
|
|
{
|
2016-05-13 15:55:34 +02:00
|
|
|
//std::this_thread::sleep_for(1ms); // hack
|
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;
|
|
|
|
|
|
2016-05-13 15:55:34 +02:00
|
|
|
const vm::ptr<CellVdecPicItem> info = vm::cast(vdec->memAddr + vdec->memBias);
|
2014-03-04 00:21:34 +01:00
|
|
|
|
|
|
|
|
vdec->memBias += 512;
|
|
|
|
|
if (vdec->memBias + 512 > vdec->memSize)
|
2014-03-04 20:18:17 +01:00
|
|
|
{
|
2014-03-04 00:21:34 +01:00
|
|
|
vdec->memBias = 0;
|
2014-03-04 20:18:17 +01:00
|
|
|
}
|
2014-03-01 09:38:50 +01:00
|
|
|
|
|
|
|
|
info->codecType = vdec->type;
|
|
|
|
|
info->startAddr = 0x00000123; // invalid value (no address for picture)
|
2015-01-11 13:13:18 +01:00
|
|
|
info->size = align(av_image_get_buffer_size(vdec->ctx->pix_fmt, vdec->ctx->width, vdec->ctx->height, 1), 128);
|
2014-03-01 09:38:50 +01:00
|
|
|
info->auNum = 1;
|
2015-06-24 13:53:47 +02:00
|
|
|
info->auPts[0].lower = (u32)(vf.pts);
|
|
|
|
|
info->auPts[0].upper = (u32)(vf.pts >> 32);
|
2014-12-12 01:21:34 +01:00
|
|
|
info->auPts[1].lower = (u32)CODEC_TS_INVALID;
|
|
|
|
|
info->auPts[1].upper = (u32)CODEC_TS_INVALID;
|
2015-06-24 13:53:47 +02:00
|
|
|
info->auDts[0].lower = (u32)(vf.dts);
|
|
|
|
|
info->auDts[0].upper = (u32)(vf.dts >> 32);
|
2014-12-12 01:21:34 +01:00
|
|
|
info->auDts[1].lower = (u32)CODEC_TS_INVALID;
|
|
|
|
|
info->auDts[1].upper = (u32)CODEC_TS_INVALID;
|
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;
|
2016-01-14 16:03:08 +01:00
|
|
|
info->picInfo_addr = info.addr() + SIZE_32(CellVdecPicItem);
|
2014-03-01 09:38:50 +01:00
|
|
|
|
2014-12-09 17:13:03 +01:00
|
|
|
if (vdec->type == CELL_VDEC_CODEC_TYPE_AVC)
|
|
|
|
|
{
|
2016-05-13 15:55:34 +02:00
|
|
|
const vm::ptr<CellVdecAvcInfo> avc = vm::cast(info.addr() + SIZE_32(CellVdecPicItem));
|
2014-12-09 17:13:03 +01:00
|
|
|
|
|
|
|
|
avc->horizontalSize = frame.width;
|
|
|
|
|
avc->verticalSize = frame.height;
|
2016-07-22 14:54:35 +02:00
|
|
|
|
2014-12-09 17:13:03 +01:00
|
|
|
switch (frame.pict_type)
|
2014-03-31 12:04:34 +02:00
|
|
|
{
|
2014-12-09 17:13:03 +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;
|
2016-01-12 22:57:16 +01:00
|
|
|
default: cellVdec.error("cellVdecGetPicItem(AVC): unknown pict_type value (0x%x)", frame.pict_type);
|
2014-03-31 12:04:34 +02:00
|
|
|
}
|
2016-07-22 14:54:35 +02:00
|
|
|
|
2014-12-09 17:13:03 +01:00
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
switch (vf.frc)
|
2014-03-31 12:04:34 +02:00
|
|
|
{
|
2014-12-09 17:13:03 +01:00
|
|
|
case CELL_VDEC_FRC_24000DIV1001: avc->frameRateCode = CELL_VDEC_AVC_FRC_24000DIV1001; break;
|
|
|
|
|
case CELL_VDEC_FRC_24: avc->frameRateCode = CELL_VDEC_AVC_FRC_24; break;
|
|
|
|
|
case CELL_VDEC_FRC_25: avc->frameRateCode = CELL_VDEC_AVC_FRC_25; break;
|
|
|
|
|
case CELL_VDEC_FRC_30000DIV1001: avc->frameRateCode = CELL_VDEC_AVC_FRC_30000DIV1001; break;
|
|
|
|
|
case CELL_VDEC_FRC_30: avc->frameRateCode = CELL_VDEC_AVC_FRC_30; break;
|
|
|
|
|
case CELL_VDEC_FRC_50: avc->frameRateCode = CELL_VDEC_AVC_FRC_50; break;
|
|
|
|
|
case CELL_VDEC_FRC_60000DIV1001: avc->frameRateCode = CELL_VDEC_AVC_FRC_60000DIV1001; break;
|
|
|
|
|
case CELL_VDEC_FRC_60: avc->frameRateCode = CELL_VDEC_AVC_FRC_60; break;
|
2016-01-12 22:57:16 +01:00
|
|
|
default: cellVdec.error("cellVdecGetPicItem(AVC): unknown frc value (0x%x)", vf.frc);
|
2014-03-31 12:04:34 +02:00
|
|
|
}
|
2014-12-09 17:13:03 +01:00
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
else if (vdec->type == CELL_VDEC_CODEC_TYPE_DIVX)
|
|
|
|
|
{
|
2016-07-22 14:54:35 +02:00
|
|
|
const vm::ptr<CellVdecDivxInfo> dvx = vm::cast(info.addr() + SIZE_32(CellVdecPicItem));
|
2014-12-09 17:13:03 +01:00
|
|
|
|
|
|
|
|
switch (frame.pict_type)
|
2014-03-31 12:04:34 +02:00
|
|
|
{
|
2014-12-09 17:13:03 +01:00
|
|
|
case AV_PICTURE_TYPE_I: dvx->pictureType = CELL_VDEC_DIVX_VCT_I; break;
|
|
|
|
|
case AV_PICTURE_TYPE_P: dvx->pictureType = CELL_VDEC_DIVX_VCT_P; break;
|
|
|
|
|
case AV_PICTURE_TYPE_B: dvx->pictureType = CELL_VDEC_DIVX_VCT_B; break;
|
2016-01-12 22:57:16 +01:00
|
|
|
default: cellVdec.error("cellVdecGetPicItem(DivX): unknown pict_type value (0x%x)", frame.pict_type);
|
2014-12-09 17:13:03 +01:00
|
|
|
}
|
2016-07-22 14:54:35 +02:00
|
|
|
|
2014-12-09 17:13:03 +01:00
|
|
|
dvx->horizontalSize = frame.width;
|
|
|
|
|
dvx->verticalSize = frame.height;
|
|
|
|
|
dvx->pixelAspectRatio = CELL_VDEC_DIVX_ARI_PAR_1_1; // ???
|
|
|
|
|
dvx->parHeight = 0;
|
|
|
|
|
dvx->parWidth = 0;
|
|
|
|
|
dvx->colourDescription = false; // ???
|
|
|
|
|
dvx->colourPrimaries = CELL_VDEC_DIVX_CP_ITU_R_BT_709; // ???
|
|
|
|
|
dvx->transferCharacteristics = CELL_VDEC_DIVX_TC_ITU_R_BT_709; // ???
|
|
|
|
|
dvx->matrixCoefficients = CELL_VDEC_DIVX_MXC_ITU_R_BT_709; // ???
|
|
|
|
|
dvx->pictureStruct = CELL_VDEC_DIVX_PSTR_FRAME; // ???
|
2016-07-22 14:54:35 +02:00
|
|
|
|
2014-12-09 17:13:03 +01:00
|
|
|
switch (vf.frc)
|
|
|
|
|
{
|
|
|
|
|
case CELL_VDEC_FRC_24000DIV1001: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_24000DIV1001; break;
|
|
|
|
|
case CELL_VDEC_FRC_24: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_24; break;
|
|
|
|
|
case CELL_VDEC_FRC_25: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_25; break;
|
|
|
|
|
case CELL_VDEC_FRC_30000DIV1001: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_30000DIV1001; break;
|
|
|
|
|
case CELL_VDEC_FRC_30: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_30; break;
|
|
|
|
|
case CELL_VDEC_FRC_50: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_50; break;
|
|
|
|
|
case CELL_VDEC_FRC_60000DIV1001: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_60000DIV1001; break;
|
|
|
|
|
case CELL_VDEC_FRC_60: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_60; break;
|
2016-01-12 22:57:16 +01:00
|
|
|
default: cellVdec.error("cellVdecGetPicItem(DivX): unknown frc value (0x%x)", vf.frc);
|
2014-03-31 12:04:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
2014-12-09 17:13:03 +01:00
|
|
|
else if (vdec->type == CELL_VDEC_CODEC_TYPE_MPEG2)
|
2014-03-31 12:04:34 +02:00
|
|
|
{
|
2016-07-22 14:54:35 +02:00
|
|
|
const vm::ptr<CellVdecMpeg2Info> mp2 = vm::cast(info.addr() + SIZE_32(CellVdecPicItem));
|
|
|
|
|
|
|
|
|
|
std::memset(mp2.get_ptr(), 0, sizeof(CellVdecMpeg2Info));
|
|
|
|
|
mp2->horizontal_size = frame.width;
|
|
|
|
|
mp2->vertical_size = frame.height;
|
|
|
|
|
mp2->aspect_ratio_information = CELL_VDEC_MPEG2_ARI_SAR_1_1; // ???
|
|
|
|
|
|
|
|
|
|
switch (vf.frc)
|
|
|
|
|
{
|
|
|
|
|
case CELL_VDEC_FRC_24000DIV1001: mp2->frame_rate_code = CELL_VDEC_MPEG2_FRC_24000DIV1001; break;
|
|
|
|
|
case CELL_VDEC_FRC_24: mp2->frame_rate_code = CELL_VDEC_MPEG2_FRC_24; break;
|
|
|
|
|
case CELL_VDEC_FRC_25: mp2->frame_rate_code = CELL_VDEC_MPEG2_FRC_25; break;
|
|
|
|
|
case CELL_VDEC_FRC_30000DIV1001: mp2->frame_rate_code = CELL_VDEC_MPEG2_FRC_30000DIV1001; break;
|
|
|
|
|
case CELL_VDEC_FRC_30: mp2->frame_rate_code = CELL_VDEC_MPEG2_FRC_30; break;
|
|
|
|
|
case CELL_VDEC_FRC_50: mp2->frame_rate_code = CELL_VDEC_MPEG2_FRC_50; break;
|
|
|
|
|
case CELL_VDEC_FRC_60000DIV1001: mp2->frame_rate_code = CELL_VDEC_MPEG2_FRC_60000DIV1001; break;
|
|
|
|
|
case CELL_VDEC_FRC_60: mp2->frame_rate_code = CELL_VDEC_MPEG2_FRC_60; break;
|
|
|
|
|
default: cellVdec.error("cellVdecGetPicItem(MPEG2): unknown frc value (0x%x)", vf.frc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mp2->progressive_sequence = true; // ???
|
|
|
|
|
mp2->low_delay = true; // ???
|
|
|
|
|
mp2->video_format = CELL_VDEC_MPEG2_VF_UNSPECIFIED; // ???
|
|
|
|
|
mp2->colour_description = false; // ???
|
|
|
|
|
|
|
|
|
|
switch (frame.pict_type)
|
|
|
|
|
{
|
|
|
|
|
case AV_PICTURE_TYPE_I: mp2->picture_coding_type[0] = CELL_VDEC_MPEG2_PCT_I; break;
|
|
|
|
|
case AV_PICTURE_TYPE_P: mp2->picture_coding_type[0] = CELL_VDEC_MPEG2_PCT_P; break;
|
|
|
|
|
case AV_PICTURE_TYPE_B: mp2->picture_coding_type[0] = CELL_VDEC_MPEG2_PCT_B; break;
|
|
|
|
|
default: cellVdec.error("cellVdecGetPicItem(MPEG2): unknown pict_type value (0x%x)", frame.pict_type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mp2->picture_coding_type[1] = CELL_VDEC_MPEG2_PCT_FORBIDDEN; // ???
|
|
|
|
|
mp2->picture_structure[0] = CELL_VDEC_MPEG2_PSTR_FRAME;
|
|
|
|
|
mp2->picture_structure[1] = CELL_VDEC_MPEG2_PSTR_FRAME;
|
2014-12-09 17:13:03 +01:00
|
|
|
|
2016-07-22 14:54:35 +02:00
|
|
|
// ...
|
2014-03-31 12:04:34 +02:00
|
|
|
}
|
2014-03-01 09:38:50 +01:00
|
|
|
|
2015-04-12 22:16:30 +02:00
|
|
|
*picItem = info;
|
2013-09-28 04:36:57 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-12 22:16:30 +02:00
|
|
|
s32 cellVdecSetFrameRate(u32 handle, CellVdecFrameRate frc)
|
2013-09-28 04:36:57 +02:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
cellVdec.trace("cellVdecSetFrameRate(handle=0x%x, frc=0x%x)", handle, frc);
|
2014-02-27 19:25:32 +01:00
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
const auto vdec = idm::get<VideoDecoder>(handle);
|
2014-02-27 19:25:32 +01:00
|
|
|
|
2015-04-12 22:16:30 +02:00
|
|
|
if (!vdec)
|
2014-02-27 19:25:32 +01:00
|
|
|
{
|
|
|
|
|
return CELL_VDEC_ERROR_ARG;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: check frc value and set frame rate
|
|
|
|
|
VdecTask task(vdecSetFrameRate);
|
|
|
|
|
task.frc = frc;
|
|
|
|
|
|
2014-12-24 23:24:17 +01:00
|
|
|
vdec->job.push(task, &vdec->is_closed);
|
2013-09-28 04:36:57 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-21 20:43:03 +01:00
|
|
|
DECLARE(ppu_module_manager::cellVdec)("libvdec", []()
|
2013-09-28 04:36:57 +02:00
|
|
|
{
|
2016-03-21 20:43:03 +01:00
|
|
|
REG_VAR(libvdec, _cell_vdec_prx_ver); // 0x085a7ecb
|
|
|
|
|
|
|
|
|
|
REG_FUNC(libvdec, cellVdecQueryAttr);
|
|
|
|
|
REG_FUNC(libvdec, cellVdecQueryAttrEx);
|
|
|
|
|
REG_FUNC(libvdec, cellVdecOpen);
|
|
|
|
|
REG_FUNC(libvdec, cellVdecOpenEx);
|
|
|
|
|
//REG_FUNC(libvdec, cellVdecOpenExt); // 0xef4d8ad7
|
|
|
|
|
REG_FUNC(libvdec, cellVdecClose);
|
|
|
|
|
REG_FUNC(libvdec, cellVdecStartSeq);
|
|
|
|
|
//REG_FUNC(libvdec, cellVdecStartSeqExt); // 0xebb8e70a
|
|
|
|
|
REG_FUNC(libvdec, cellVdecEndSeq);
|
|
|
|
|
REG_FUNC(libvdec, cellVdecDecodeAu);
|
|
|
|
|
REG_FUNC(libvdec, cellVdecGetPicture);
|
|
|
|
|
REG_FUNC(libvdec, cellVdecGetPictureExt); // 0xa21aa896
|
|
|
|
|
REG_FUNC(libvdec, cellVdecGetPicItem);
|
|
|
|
|
//REG_FUNC(libvdec, cellVdecGetPicItemExt); // 0x2cbd9806
|
|
|
|
|
REG_FUNC(libvdec, cellVdecSetFrameRate);
|
|
|
|
|
//REG_FUNC(libvdec, cellVdecSetFrameRateExt); // 0xcffc42a5
|
2015-02-18 17:22:06 +01:00
|
|
|
});
|