mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 10:42:36 +01:00
cellVdec: implement CELL_VDEC_ERROR_SEQ
This commit is contained in:
parent
8d781a737b
commit
c6f3f386df
@ -62,15 +62,80 @@ void fmt_class_string<CellVdecError>::format(std::string& out, u64 arg)
|
||||
});
|
||||
}
|
||||
|
||||
vm::gvar<s32> _cell_vdec_prx_ver; // ???
|
||||
// The general sequence control flow has these possible transitions:
|
||||
// closed -> dormant
|
||||
// dormant -> ready
|
||||
// dormant -> closed
|
||||
// ready -> ending
|
||||
// ready -> resetting
|
||||
// ready -> closed
|
||||
// ending -> dormant
|
||||
// resetting -> ready
|
||||
enum class sequence_state : u32
|
||||
{
|
||||
closed = 0, // Also called non-existent. Needs to be opened before anything can be done with it.
|
||||
dormant = 1, // Waiting for the next sequence. The last picture and pic-item can be aqcuired in this state.
|
||||
ready = 2, // Ready for decoding. Can also restart sequences in this state.
|
||||
ending = 3, // Ending a sequence. Goes to dormant afterwards.
|
||||
resetting = 4, // Stops the current sequence and starts a new one. The pictures of the old sequence are flushed
|
||||
invalid = 5, // Any other value is invalid
|
||||
};
|
||||
|
||||
constexpr struct vdec_start_seq_t{} vdec_start_seq{};
|
||||
constexpr struct vdec_close_t{} vdec_close{};
|
||||
template<>
|
||||
void fmt_class_string<sequence_state>::format(std::string& out, u64 arg)
|
||||
{
|
||||
format_enum(out, arg, [](auto error)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
STR_CASE(sequence_state::closed);
|
||||
STR_CASE(sequence_state::dormant);
|
||||
STR_CASE(sequence_state::ready);
|
||||
STR_CASE(sequence_state::ending);
|
||||
STR_CASE(sequence_state::resetting);
|
||||
STR_CASE(sequence_state::invalid);
|
||||
}
|
||||
|
||||
return unknown;
|
||||
});
|
||||
}
|
||||
|
||||
vm::gvar<s32> _cell_vdec_prx_ver; // TODO: this should probably specify the VDEC module that was loaded. E.g. CELL_SYSMODULE_VDEC_MPEG2
|
||||
|
||||
enum class vdec_cmd_type : u32
|
||||
{
|
||||
start_sequence,
|
||||
end_sequence,
|
||||
close,
|
||||
au_decode,
|
||||
framerate,
|
||||
};
|
||||
|
||||
struct vdec_cmd
|
||||
{
|
||||
s32 mode;
|
||||
CellVdecAuInfo au;
|
||||
explicit vdec_cmd(vdec_cmd_type _type)
|
||||
: type(_type)
|
||||
{
|
||||
ensure(_type != vdec_cmd_type::au_decode);
|
||||
ensure(_type != vdec_cmd_type::framerate);
|
||||
}
|
||||
|
||||
explicit vdec_cmd(vdec_cmd_type _type, s32 _mode, CellVdecAuInfo _au)
|
||||
: type(_type), mode(_mode), au(std::move(_au))
|
||||
{
|
||||
ensure(_type == vdec_cmd_type::au_decode);
|
||||
}
|
||||
|
||||
explicit vdec_cmd(vdec_cmd_type _type, s32 _framerate)
|
||||
: type(_type), framerate(_framerate)
|
||||
{
|
||||
ensure(_type == vdec_cmd_type::framerate);
|
||||
}
|
||||
|
||||
vdec_cmd_type type{};
|
||||
s32 mode{};
|
||||
s32 framerate{};
|
||||
CellVdecAuInfo au{};
|
||||
};
|
||||
|
||||
struct vdec_frame
|
||||
@ -103,6 +168,10 @@ struct vdec_context final
|
||||
static const u32 id_step = 0x00000100;
|
||||
static const u32 id_count = 1024;
|
||||
|
||||
atomic_t<bool> abort_decode = false; // Used for thread interaction
|
||||
atomic_t<bool> is_running = false; // Used for thread interaction
|
||||
atomic_t<sequence_state> seq_state = sequence_state::closed;
|
||||
|
||||
const AVCodec* codec{};
|
||||
AVCodecContext* ctx{};
|
||||
SwsContext* sws{};
|
||||
@ -121,12 +190,12 @@ struct vdec_context final
|
||||
u64 next_dts{};
|
||||
atomic_t<u32> ppu_tid{};
|
||||
|
||||
std::deque<vdec_frame> out;
|
||||
atomic_t<u32> out_max = 60;
|
||||
std::deque<vdec_frame> out_queue;
|
||||
const u32 out_max = 60;
|
||||
|
||||
atomic_t<u32> au_count{0};
|
||||
|
||||
lf_queue<std::variant<vdec_start_seq_t, vdec_close_t, vdec_cmd, CellVdecFrameRate>> in_cmd;
|
||||
lf_queue<vdec_cmd> in_cmd;
|
||||
|
||||
AVRational log_time_base{}; // Used to reduce log spam
|
||||
|
||||
@ -197,6 +266,8 @@ struct vdec_context final
|
||||
}
|
||||
fmt::throw_exception("avcodec_open2() failed (err=0x%x='%s', opts=%s)", err, utils::av_error_to_string(err), dict_content);
|
||||
}
|
||||
|
||||
seq_state = sequence_state::dormant;
|
||||
}
|
||||
|
||||
~vdec_context()
|
||||
@ -212,7 +283,7 @@ struct vdec_context final
|
||||
|
||||
ppu_tid.release(ppu.id);
|
||||
|
||||
for (auto slice = in_cmd.pop_all();; [&]
|
||||
for (auto slice = in_cmd.pop_all(); thread_ctrl::state() != thread_state::aborting; [&]
|
||||
{
|
||||
if (slice)
|
||||
{
|
||||
@ -229,82 +300,99 @@ struct vdec_context final
|
||||
}())
|
||||
{
|
||||
// pcmd can be nullptr
|
||||
auto* pcmd = slice.get();
|
||||
auto* cmd = slice.get();
|
||||
|
||||
if (thread_ctrl::state() == thread_state::aborting)
|
||||
if (!cmd)
|
||||
{
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
else if (std::get_if<vdec_start_seq_t>(pcmd))
|
||||
|
||||
switch (cmd->type)
|
||||
{
|
||||
case vdec_cmd_type::start_sequence:
|
||||
{
|
||||
std::lock_guard lock{mutex};
|
||||
|
||||
if (seq_state == sequence_state::resetting)
|
||||
{
|
||||
cellVdec.trace("Reset sequence...");
|
||||
}
|
||||
else
|
||||
{
|
||||
cellVdec.trace("Start sequence...");
|
||||
}
|
||||
|
||||
avcodec_flush_buffers(ctx);
|
||||
|
||||
out_queue.clear(); // Flush image queue
|
||||
log_time_base = {};
|
||||
|
||||
frc_set = 0; // TODO: ???
|
||||
next_pts = 0;
|
||||
next_dts = 0;
|
||||
cellVdec.trace("Start sequence...");
|
||||
|
||||
abort_decode = false;
|
||||
is_running = true;
|
||||
break;
|
||||
}
|
||||
else if (auto* cmd = std::get_if<vdec_cmd>(pcmd))
|
||||
case vdec_cmd_type::end_sequence:
|
||||
{
|
||||
cellVdec.trace("End sequence...");
|
||||
|
||||
{
|
||||
std::lock_guard lock{mutex};
|
||||
seq_state = sequence_state::dormant;
|
||||
}
|
||||
|
||||
cb_func(ppu, vid, CELL_VDEC_MSG_TYPE_SEQDONE, CELL_OK, cb_arg);
|
||||
lv2_obj::sleep(ppu);
|
||||
break;
|
||||
}
|
||||
case vdec_cmd_type::au_decode:
|
||||
{
|
||||
AVPacket packet{};
|
||||
packet.pos = -1;
|
||||
|
||||
u64 au_usrd{};
|
||||
|
||||
if (cmd->mode != -1)
|
||||
const u32 au_mode = cmd->mode;
|
||||
const u32 au_addr = cmd->au.startAddr;
|
||||
const u32 au_size = cmd->au.size;
|
||||
const u64 au_pts = u64{cmd->au.pts.upper} << 32 | cmd->au.pts.lower;
|
||||
const u64 au_dts = u64{cmd->au.dts.upper} << 32 | cmd->au.dts.lower;
|
||||
au_usrd = cmd->au.userData;
|
||||
|
||||
packet.data = vm::_ptr<u8>(au_addr);
|
||||
packet.size = au_size;
|
||||
packet.pts = au_pts != umax ? au_pts : s64{smin};
|
||||
packet.dts = au_dts != umax ? au_dts : s64{smin};
|
||||
|
||||
if (next_pts == 0 && au_pts != umax)
|
||||
{
|
||||
const u32 au_mode = cmd->mode;
|
||||
const u32 au_addr = cmd->au.startAddr;
|
||||
const u32 au_size = cmd->au.size;
|
||||
const u64 au_pts = u64{cmd->au.pts.upper} << 32 | cmd->au.pts.lower;
|
||||
const u64 au_dts = u64{cmd->au.dts.upper} << 32 | cmd->au.dts.lower;
|
||||
au_usrd = cmd->au.userData;
|
||||
|
||||
packet.data = vm::_ptr<u8>(au_addr);
|
||||
packet.size = au_size;
|
||||
packet.pts = au_pts != umax ? au_pts : s64{smin};
|
||||
packet.dts = au_dts != umax ? au_dts : s64{smin};
|
||||
|
||||
if (next_pts == 0 && au_pts != umax)
|
||||
{
|
||||
next_pts = au_pts;
|
||||
}
|
||||
|
||||
if (next_dts == 0 && au_dts != umax)
|
||||
{
|
||||
next_dts = au_dts;
|
||||
}
|
||||
|
||||
ctx->skip_frame =
|
||||
au_mode == CELL_VDEC_DEC_MODE_NORMAL ? AVDISCARD_DEFAULT :
|
||||
au_mode == CELL_VDEC_DEC_MODE_B_SKIP ? AVDISCARD_NONREF : AVDISCARD_NONINTRA;
|
||||
|
||||
cellVdec.trace("AU decoding: size=0x%x, pts=0x%llx, dts=0x%llx, userdata=0x%llx", au_size, au_pts, au_dts, au_usrd);
|
||||
}
|
||||
else
|
||||
{
|
||||
packet.pts = smin;
|
||||
packet.dts = smin;
|
||||
cellVdec.trace("End sequence...");
|
||||
next_pts = au_pts;
|
||||
}
|
||||
|
||||
while (out_max)
|
||||
if (next_dts == 0 && au_dts != umax)
|
||||
{
|
||||
if (cmd->mode == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
next_dts = au_dts;
|
||||
}
|
||||
|
||||
ctx->skip_frame =
|
||||
au_mode == CELL_VDEC_DEC_MODE_NORMAL ? AVDISCARD_DEFAULT :
|
||||
au_mode == CELL_VDEC_DEC_MODE_B_SKIP ? AVDISCARD_NONREF : AVDISCARD_NONINTRA;
|
||||
|
||||
cellVdec.trace("AU decoding: size=0x%x, pts=0x%llx, dts=0x%llx, userdata=0x%llx", au_size, au_pts, au_dts, au_usrd);
|
||||
|
||||
while (thread_ctrl::state() != thread_state::aborting && !abort_decode)
|
||||
{
|
||||
if (int ret = avcodec_send_packet(ctx, &packet); ret < 0)
|
||||
{
|
||||
char av_error[AV_ERROR_MAX_STRING_SIZE];
|
||||
char av_error[AV_ERROR_MAX_STRING_SIZE]{};
|
||||
av_make_error_string(av_error, AV_ERROR_MAX_STRING_SIZE, ret);
|
||||
fmt::throw_exception("AU queuing error(0x%x): %s", ret, av_error);
|
||||
}
|
||||
|
||||
while (true)
|
||||
while (!abort_decode)
|
||||
{
|
||||
// Keep receiving frames
|
||||
vdec_frame frame;
|
||||
@ -317,7 +405,7 @@ struct vdec_context final
|
||||
|
||||
if (int ret = avcodec_receive_frame(ctx, frame.avf.get()); ret < 0)
|
||||
{
|
||||
if (ret == AVERROR(EAGAIN))
|
||||
if (ret == AVERROR(EAGAIN) || ret == AVERROR(EOF))
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -433,43 +521,78 @@ struct vdec_context final
|
||||
|
||||
cellVdec.trace("Got picture (pts=0x%llx[0x%llx], dts=0x%llx[0x%llx])", frame.pts, frame->pts, frame.dts, frame->pkt_dts);
|
||||
|
||||
std::lock_guard{mutex}, out.push_back(std::move(frame));
|
||||
{
|
||||
std::lock_guard lock{mutex};
|
||||
out_queue.push_back(std::move(frame));
|
||||
}
|
||||
|
||||
cb_func(ppu, vid, CELL_VDEC_MSG_TYPE_PICOUT, CELL_OK, cb_arg);
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
// Wait until there is free space in the image queue.
|
||||
// Do this after pushing the frame to the queue. That way the game can consume the frame and we can move on.
|
||||
u32 elapsed = 0;
|
||||
while (thread_ctrl::state() != thread_state::aborting && !abort_decode)
|
||||
{
|
||||
{
|
||||
std::lock_guard lock{mutex};
|
||||
|
||||
if (out_queue.size() <= out_max)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
thread_ctrl::wait_for(1000);
|
||||
|
||||
if (elapsed++ >= 5000) // 5 seconds
|
||||
{
|
||||
cellVdec.error("Video au decode has been waiting for a consumer for 5 seconds.");
|
||||
elapsed = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd->mode != -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (out_max)
|
||||
if (thread_ctrl::state() != thread_state::aborting && !abort_decode)
|
||||
{
|
||||
cb_func(ppu, vid, cmd->mode != -1 ? CELL_VDEC_MSG_TYPE_AUDONE : CELL_VDEC_MSG_TYPE_SEQDONE, CELL_OK, cb_arg);
|
||||
cb_func(ppu, vid, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, cb_arg);
|
||||
lv2_obj::sleep(ppu);
|
||||
}
|
||||
else cellVdec.error("AU decoding: abort_decode = %d", abort_decode.load());
|
||||
|
||||
if (cmd->mode != -1)
|
||||
{
|
||||
au_count--;
|
||||
}
|
||||
au_count--;
|
||||
|
||||
while (thread_ctrl::state() != thread_state::aborting && out_max && (std::lock_guard{mutex}, out.size() > out_max))
|
||||
{
|
||||
thread_ctrl::wait_for(1000);
|
||||
}
|
||||
cellVdec.trace("AU decoding: done");
|
||||
break;
|
||||
}
|
||||
else if (auto* frc = std::get_if<CellVdecFrameRate>(pcmd))
|
||||
case vdec_cmd_type::framerate:
|
||||
{
|
||||
frc_set = *frc;
|
||||
frc_set = cmd->framerate;
|
||||
break;
|
||||
}
|
||||
else if (std::get_if<vdec_close_t>(pcmd))
|
||||
case vdec_cmd_type::close:
|
||||
{
|
||||
std::lock_guard lock{mutex};
|
||||
out_queue.clear();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fmt::throw_exception("Unknown vdec_cmd_type (%d)", static_cast<u32>(cmd->type));
|
||||
break;
|
||||
}
|
||||
|
||||
std::lock_guard lock{mutex};
|
||||
if (seq_state == sequence_state::closed)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the state is closed at the end
|
||||
std::lock_guard lock{mutex};
|
||||
seq_state = sequence_state::closed;
|
||||
}
|
||||
};
|
||||
|
||||
@ -646,13 +769,13 @@ error_code cellVdecQueryAttrEx(vm::cptr<CellVdecTypeEx> type, vm::ptr<CellVdecAt
|
||||
template <typename T, typename U>
|
||||
static error_code vdecOpen(ppu_thread& ppu, T type, U res, vm::cptr<CellVdecCb> cb, vm::ptr<u32> handle)
|
||||
{
|
||||
if (!type || !res || !cb || !handle)
|
||||
if (!type || !res || !cb || !handle || !cb->cbFunc)
|
||||
{
|
||||
return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
if (res->ppuThreadPriority + 0u > 3071 || res->spuThreadPriority + 0u > 255 || res->ppuThreadStackSize < 4096
|
||||
|| type->codecType + 0u > 0xd)
|
||||
if (!res->memAddr || res->ppuThreadPriority + 0u >= 3072 || res->spuThreadPriority + 0u >= 256 || res->ppuThreadStackSize < 4096
|
||||
|| type->codecType + 0u >= 0xe)
|
||||
{
|
||||
return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
@ -712,18 +835,25 @@ error_code cellVdecClose(ppu_thread& ppu, u32 handle)
|
||||
{
|
||||
cellVdec.warning("cellVdecClose(handle=0x%x)", handle);
|
||||
|
||||
const auto vdec = idm::get<vdec_context>(handle);
|
||||
auto vdec = idm::get<vdec_context>(handle);
|
||||
|
||||
if (!vdec)
|
||||
{
|
||||
return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
// TODO: return CELL_VDEC_ERROR_SEQ
|
||||
{
|
||||
std::lock_guard lock{vdec->mutex};
|
||||
|
||||
if (vdec->seq_state == sequence_state::closed)
|
||||
{
|
||||
return { CELL_VDEC_ERROR_SEQ, vdec->seq_state.load() };
|
||||
}
|
||||
}
|
||||
|
||||
lv2_obj::sleep(ppu);
|
||||
vdec->out_max = 0;
|
||||
vdec->in_cmd.push(vdec_close);
|
||||
vdec->abort_decode = true;
|
||||
vdec->in_cmd.push(vdec_cmd(vdec_cmd_type::close));
|
||||
|
||||
while (!vdec->ppu_tid)
|
||||
{
|
||||
@ -737,6 +867,9 @@ error_code cellVdecClose(ppu_thread& ppu, u32 handle)
|
||||
ppu_execute<&sys_interrupt_thread_disestablish>(ppu, tid);
|
||||
}
|
||||
|
||||
std::lock_guard lock{vdec->mutex};
|
||||
vdec->seq_state = sequence_state::closed;
|
||||
|
||||
if (!idm::remove_verify<vdec_context>(handle, std::move(vdec)))
|
||||
{
|
||||
// Other thread removed it beforehead
|
||||
@ -757,9 +890,55 @@ error_code cellVdecStartSeq(u32 handle)
|
||||
return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
// TODO: return CELL_VDEC_ERROR_SEQ
|
||||
sequence_state old_state{};
|
||||
|
||||
{
|
||||
std::lock_guard lock{vdec->mutex};
|
||||
old_state = vdec->seq_state;
|
||||
|
||||
if (old_state != sequence_state::dormant && old_state != sequence_state::ready)
|
||||
{
|
||||
return { CELL_VDEC_ERROR_SEQ, old_state };
|
||||
}
|
||||
|
||||
if (old_state == sequence_state::ready)
|
||||
{
|
||||
vdec->seq_state = sequence_state::resetting;
|
||||
}
|
||||
}
|
||||
|
||||
vdec->abort_decode = true;
|
||||
vdec->is_running = false;
|
||||
vdec->in_cmd.push(vdec_cmd(vdec_cmd_type::start_sequence));
|
||||
|
||||
// Wait until the thread is ready
|
||||
u32 elapsed = 0;
|
||||
while (thread_ctrl::state() != thread_state::aborting)
|
||||
{
|
||||
if (vdec->is_running)
|
||||
{
|
||||
break;
|
||||
}
|
||||
thread_ctrl::wait_for(1000);
|
||||
|
||||
if (elapsed++ >= 5000) // 5 seconds
|
||||
{
|
||||
cellVdec.error("Timeout in cellVdecStartSeq.");
|
||||
elapsed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::lock_guard lock{vdec->mutex};
|
||||
|
||||
if (false) // TODO: set to old state in case of error
|
||||
{
|
||||
vdec->seq_state = old_state;
|
||||
}
|
||||
else
|
||||
{
|
||||
vdec->seq_state = sequence_state::ready;
|
||||
}
|
||||
|
||||
vdec->in_cmd.push(vdec_start_seq);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -774,9 +953,19 @@ error_code cellVdecEndSeq(u32 handle)
|
||||
return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
// TODO: return CELL_VDEC_ERROR_SEQ
|
||||
{
|
||||
std::lock_guard lock{vdec->mutex};
|
||||
|
||||
if (vdec->seq_state != sequence_state::ready)
|
||||
{
|
||||
return { CELL_VDEC_ERROR_SEQ, vdec->seq_state.load() };
|
||||
}
|
||||
|
||||
vdec->seq_state = sequence_state::ending;
|
||||
}
|
||||
|
||||
vdec->in_cmd.push(vdec_cmd(vdec_cmd_type::end_sequence));
|
||||
|
||||
vdec->in_cmd.push(vdec_cmd{-1});
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -786,18 +975,39 @@ error_code cellVdecDecodeAu(u32 handle, CellVdecDecodeMode mode, vm::cptr<CellVd
|
||||
|
||||
const auto vdec = idm::get<vdec_context>(handle);
|
||||
|
||||
if (!auInfo || !vdec || mode < 0 || mode > CELL_VDEC_DEC_MODE_PB_SKIP)
|
||||
if (!vdec || !auInfo || !auInfo->pts.upper || !auInfo->startAddr)
|
||||
{
|
||||
return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard lock{vdec->mutex};
|
||||
|
||||
if (vdec->seq_state != sequence_state::ready)
|
||||
{
|
||||
return { CELL_VDEC_ERROR_SEQ, vdec->seq_state.load() };
|
||||
}
|
||||
}
|
||||
|
||||
if (mode < 0 || mode > CELL_VDEC_DEC_MODE_PB_SKIP)
|
||||
{
|
||||
return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
//if ((mode == (CELL_VDEC_DEC_MODE_B_SKIP | CELL_VDEC_DEC_MODE_PB_SKIP) && something != 3) ||
|
||||
// (mode == CELL_VDEC_DEC_MODE_PB_SKIP && something != 1))
|
||||
//{
|
||||
// return CELL_VDEC_ERROR_ARG;
|
||||
//}
|
||||
|
||||
if (!vdec->au_count.try_inc(4))
|
||||
{
|
||||
return CELL_VDEC_ERROR_BUSY;
|
||||
}
|
||||
|
||||
// TODO: check info
|
||||
vdec->in_cmd.push(vdec_cmd{mode, *auInfo});
|
||||
vdec->in_cmd.push(vdec_cmd(vdec_cmd_type::au_decode, mode, *auInfo));
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -818,33 +1028,34 @@ error_code cellVdecGetPicture(u32 handle, vm::cptr<CellVdecPicFormat> format, vm
|
||||
return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
// TODO: return CELL_VDEC_ERROR_SEQ
|
||||
{
|
||||
std::lock_guard lock{vdec->mutex};
|
||||
|
||||
if (vdec->seq_state == sequence_state::closed || vdec->seq_state > sequence_state::ending)
|
||||
{
|
||||
return { CELL_VDEC_ERROR_SEQ, vdec->seq_state.load() };
|
||||
}
|
||||
}
|
||||
|
||||
if (format->formatType > 4 || (format->formatType <= CELL_VDEC_PICFMT_RGBA32_ILV && format->colorMatrixType > CELL_VDEC_COLOR_MATRIX_TYPE_BT709))
|
||||
{
|
||||
return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
// TODO: something like this is checked here, maybe only if outBuff[0] != 0
|
||||
//if (outBuff && outBuff[0] != 8 && outBuff[0] != 12)
|
||||
//{
|
||||
// return CELL_VDEC_ERROR_ARG;
|
||||
//}
|
||||
|
||||
vdec_frame frame;
|
||||
bool notify = false;
|
||||
{
|
||||
std::lock_guard lock(vdec->mutex);
|
||||
|
||||
if (vdec->out.empty())
|
||||
if (vdec->out_queue.empty())
|
||||
{
|
||||
return CELL_VDEC_ERROR_EMPTY;
|
||||
}
|
||||
|
||||
frame = std::move(vdec->out.front());
|
||||
frame = std::move(vdec->out_queue.front());
|
||||
|
||||
vdec->out.pop_front();
|
||||
if (vdec->out.size() + 1 == vdec->out_max)
|
||||
vdec->out_queue.pop_front();
|
||||
if (vdec->out_queue.size() + 1 == vdec->out_max)
|
||||
notify = true;
|
||||
}
|
||||
|
||||
@ -869,7 +1080,6 @@ error_code cellVdecGetPicture(u32 handle, vm::cptr<CellVdecPicFormat> format, vm
|
||||
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;
|
||||
|
||||
default:
|
||||
{
|
||||
fmt::throw_exception("Unknown formatType (%d)", type);
|
||||
@ -935,6 +1145,16 @@ error_code cellVdecGetPictureExt(u32 handle, vm::cptr<CellVdecPicFormat2> format
|
||||
{
|
||||
cellVdec.warning("cellVdecGetPictureExt(handle=0x%x, format2=*0x%x, outBuff=*0x%x, arg4=*0x%x)", handle, format2, outBuff, arg4);
|
||||
|
||||
if (!handle || !format2)
|
||||
{
|
||||
return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
if (arg4 && arg4 != 8 && arg4 != 12)
|
||||
{
|
||||
return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
if (arg4 || format2->unk0 || format2->unk1)
|
||||
{
|
||||
fmt::throw_exception("Unknown arguments (arg4=*0x%x, unk0=0x%x, unk1=0x%x)", arg4, format2->unk0, format2->unk1);
|
||||
@ -959,7 +1179,14 @@ error_code cellVdecGetPicItem(u32 handle, vm::pptr<CellVdecPicItem> picItem)
|
||||
return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
// TODO: return CELL_VDEC_ERROR_SEQ
|
||||
{
|
||||
std::lock_guard lock{vdec->mutex};
|
||||
|
||||
if (vdec->seq_state == sequence_state::closed || vdec->seq_state > sequence_state::ending)
|
||||
{
|
||||
return { CELL_VDEC_ERROR_SEQ, vdec->seq_state.load() };
|
||||
}
|
||||
}
|
||||
|
||||
struct all_info_t
|
||||
{
|
||||
@ -976,7 +1203,7 @@ error_code cellVdecGetPicItem(u32 handle, vm::pptr<CellVdecPicItem> picItem)
|
||||
{
|
||||
std::lock_guard lock(vdec->mutex);
|
||||
|
||||
for (auto& picture : vdec->out)
|
||||
for (auto& picture : vdec->out_queue)
|
||||
{
|
||||
if (!picture.PicItemRecieved)
|
||||
{
|
||||
@ -1180,9 +1407,14 @@ error_code cellVdecSetFrameRate(u32 handle, CellVdecFrameRate frameRateCode)
|
||||
return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
// TODO: return CELL_VDEC_ERROR_SEQ
|
||||
std::lock_guard lock{vdec->mutex};
|
||||
|
||||
vdec->in_cmd.push(CellVdecFrameRate{ frameRateCode & 0x87 });
|
||||
if (vdec->seq_state == sequence_state::closed || vdec->seq_state >= sequence_state::invalid)
|
||||
{
|
||||
return { CELL_VDEC_ERROR_SEQ, vdec->seq_state.load() };
|
||||
}
|
||||
|
||||
vdec->in_cmd.push(vdec_cmd(vdec_cmd_type::framerate, frameRateCode & 0x87));
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -1198,6 +1430,12 @@ error_code cellVdecStartSeqExt()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellVdecGetInputStatus()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellVdec);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellVdecGetPicItemEx()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellVdec);
|
||||
@ -1227,7 +1465,12 @@ error_code cellVdecSetPts(u32 handle, vm::ptr<void> unk)
|
||||
return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
// TODO: return CELL_VDEC_ERROR_SEQ
|
||||
std::lock_guard lock{vdec->mutex};
|
||||
|
||||
if (vdec->seq_state == sequence_state::closed || vdec->seq_state >= sequence_state::invalid)
|
||||
{
|
||||
return { CELL_VDEC_ERROR_SEQ, vdec->seq_state.load() };
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -1260,6 +1503,7 @@ DECLARE(ppu_module_manager::cellVdec)("libvdec", []()
|
||||
REG_FUNC(libvdec, cellVdecEndSeq);
|
||||
REG_FUNC(libvdec, cellVdecDecodeAu);
|
||||
REG_FUNC(libvdec, cellVdecDecodeAuEx2);
|
||||
REG_FUNC(libvdec, cellVdecGetInputStatus);
|
||||
REG_FUNC(libvdec, cellVdecGetPicture);
|
||||
REG_FUNC(libvdec, cellVdecGetPictureExt); // 0xa21aa896
|
||||
REG_FUNC(libvdec, cellVdecGetPicItem);
|
||||
|
Loading…
Reference in New Issue
Block a user