mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-01-30 12:32:43 +00:00
halfplement cellRec
This commit is contained in:
parent
bcd77ac65e
commit
6cc1466baa
@ -1,74 +1,461 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/Cell/lv2/sys_memory.h"
|
||||
#include "Emu/Cell/timers.hpp"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "cellRec.h"
|
||||
#include "cellSysutil.h"
|
||||
|
||||
LOG_CHANNEL(cellRec);
|
||||
|
||||
enum
|
||||
template<>
|
||||
void fmt_class_string<CellRecError>::format(std::string& out, u64 arg)
|
||||
{
|
||||
CELL_REC_STATUS_UNLOAD = 0,
|
||||
CELL_REC_STATUS_OPEN = 1,
|
||||
CELL_REC_STATUS_START = 2,
|
||||
CELL_REC_STATUS_STOP = 3,
|
||||
CELL_REC_STATUS_CLOSE = 4,
|
||||
CELL_REC_STATUS_ERR = 10
|
||||
format_enum(out, arg, [](auto error)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
STR_CASE(CELL_REC_ERROR_OUT_OF_MEMORY);
|
||||
STR_CASE(CELL_REC_ERROR_FATAL);
|
||||
STR_CASE(CELL_REC_ERROR_INVALID_VALUE);
|
||||
STR_CASE(CELL_REC_ERROR_FILE_OPEN);
|
||||
STR_CASE(CELL_REC_ERROR_FILE_WRITE);
|
||||
STR_CASE(CELL_REC_ERROR_INVALID_STATE);
|
||||
STR_CASE(CELL_REC_ERROR_FILE_NO_DATA);
|
||||
}
|
||||
|
||||
return unknown;
|
||||
});
|
||||
}
|
||||
|
||||
// Helper to distinguish video type
|
||||
enum : s32
|
||||
{
|
||||
VIDEO_TYPE_MPEG4 = 0x0000,
|
||||
VIDEO_TYPE_AVC_MP = 0x1000,
|
||||
VIDEO_TYPE_AVC_BL = 0x2000,
|
||||
VIDEO_TYPE_MJPEG = 0x3000,
|
||||
VIDEO_TYPE_M4HD = 0x4000,
|
||||
};
|
||||
|
||||
struct CellRecSpursParam
|
||||
// Helper to distinguish video quality
|
||||
enum : s32
|
||||
{
|
||||
vm::bptr<struct CellSpurs> pSpurs;
|
||||
be_t<s32> spu_usage_rate;
|
||||
u8 priority[8];
|
||||
VIDEO_QUALITY_0 = 0x000, // small
|
||||
VIDEO_QUALITY_1 = 0x100, // middle
|
||||
VIDEO_QUALITY_2 = 0x200, // large
|
||||
VIDEO_QUALITY_3 = 0x300,
|
||||
VIDEO_QUALITY_4 = 0x400,
|
||||
VIDEO_QUALITY_5 = 0x500,
|
||||
VIDEO_QUALITY_6 = 0x600,
|
||||
VIDEO_QUALITY_7 = 0x700,
|
||||
};
|
||||
|
||||
struct CellRecOption
|
||||
enum class rec_state : u32
|
||||
{
|
||||
be_t<s32> option;
|
||||
union
|
||||
{
|
||||
be_t<s32> ppu_thread_priority;
|
||||
be_t<s32> spu_thread_priority;
|
||||
be_t<s32> capture_priority;
|
||||
be_t<s32> use_system_spu;
|
||||
be_t<s32> fit_to_youtube;
|
||||
be_t<s32> xmb_bgm;
|
||||
be_t<s32> mpeg4_fast_encode;
|
||||
be_t<u32> ring_sec;
|
||||
be_t<s32> video_input;
|
||||
be_t<s32> audio_input;
|
||||
be_t<s32> audio_input_mix_vol;
|
||||
be_t<s32> reduce_memsize;
|
||||
be_t<s32> show_xmb;
|
||||
vm::bptr<char> metadata_filename;
|
||||
vm::bptr<CellRecSpursParam> pSpursParam;
|
||||
be_t<u64> dummy;
|
||||
} value;
|
||||
closed = 0x2710,
|
||||
open = 0x2711,
|
||||
};
|
||||
|
||||
struct CellRecParam
|
||||
struct rec_param
|
||||
{
|
||||
be_t<s32> videoFmt;
|
||||
be_t<s32> audioFmt;
|
||||
be_t<s32> numOfOpt;
|
||||
vm::bptr<CellRecOption> pOpt;
|
||||
s32 ppu_thread_priority = CELL_REC_PARAM_PPU_THREAD_PRIORITY_DEFAULT;
|
||||
s32 spu_thread_priority = CELL_REC_PARAM_SPU_THREAD_PRIORITY_DEFAULT;
|
||||
s32 capture_priority = CELL_REC_PARAM_CAPTURE_PRIORITY_HIGHEST;
|
||||
s32 use_system_spu = CELL_REC_PARAM_USE_SYSTEM_SPU_DISABLE;
|
||||
s32 fit_to_youtube = 0;
|
||||
s32 xmb_bgm = CELL_REC_PARAM_XMB_BGM_DISABLE;
|
||||
s32 mpeg4_fast_encode = CELL_REC_PARAM_MPEG4_FAST_ENCODE_DISABLE;
|
||||
u32 ring_sec = 10; // TODO
|
||||
s32 video_input = CELL_REC_PARAM_VIDEO_INPUT_DISABLE;
|
||||
s32 audio_input = CELL_REC_PARAM_AUDIO_INPUT_DISABLE;
|
||||
s32 audio_input_mix_vol = CELL_REC_PARAM_AUDIO_INPUT_MIX_VOL_MIN;
|
||||
s32 reduce_memsize = CELL_REC_PARAM_REDUCE_MEMSIZE_DISABLE;
|
||||
s32 show_xmb = 0;
|
||||
std::string filename;
|
||||
std::string metadata_filename;
|
||||
CellRecSpursParam spurs_param{};
|
||||
struct
|
||||
{
|
||||
std::string game_title;
|
||||
std::string movie_title;
|
||||
std::string description;
|
||||
std::string userdata;
|
||||
} movie_metadata{};
|
||||
struct
|
||||
{
|
||||
bool is_set = false;
|
||||
u32 type;
|
||||
u64 start_time;
|
||||
u64 end_time;
|
||||
std::string title;
|
||||
std::vector<std::string> tags;
|
||||
} scene_metadata{};
|
||||
};
|
||||
|
||||
using CellRecCallback = void(s32 recStatus, s32 recError, vm::ptr<void> userdata);
|
||||
|
||||
struct rec_info
|
||||
{
|
||||
vm::ptr<CellRecCallback> cb{};
|
||||
vm::ptr<void> cbUserData{};
|
||||
atomic_t<rec_state> state = rec_state::closed;
|
||||
rec_param param{};
|
||||
|
||||
vm::bptr<u8> video_input_buffer{};
|
||||
vm::bptr<u8> audio_input_buffer{};
|
||||
|
||||
u32 pitch = 4 * 1280; // TODO: remember to handle the pitch for CELL_REC_PARAM_VIDEO_INPUT_YUV420PLANAR_16_9
|
||||
u32 width = 1280;
|
||||
u32 height = 720;
|
||||
|
||||
u64 recording_time_start = 0; // TODO: proper time measurements
|
||||
u64 recording_time_end = 0; // TODO: proper time measurements
|
||||
u64 recording_time_total = 0; // TODO: proper time measurements
|
||||
|
||||
shared_mutex mutex;
|
||||
};
|
||||
|
||||
bool create_path(std::string& out, std::string dir_name, std::string file_name)
|
||||
{
|
||||
out.clear();
|
||||
|
||||
if (dir_name.size() + file_name.size() > CELL_REC_MAX_PATH_LEN)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
out = dir_name;
|
||||
|
||||
if (!out.empty() && out.back() != '/')
|
||||
{
|
||||
out += '/';
|
||||
}
|
||||
|
||||
out += file_name;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 cellRecQueryMemSize(vm::cptr<CellRecParam> pParam); // Forward declaration
|
||||
|
||||
error_code cellRecOpen(vm::cptr<char> pDirName, vm::cptr<char> pFileName, vm::cptr<CellRecParam> pParam, u32 container, vm::ptr<CellRecCallback> cb, vm::ptr<void> cbUserData)
|
||||
{
|
||||
cellRec.todo("cellRecOpen(pDirName=%s, pFileName=%s, pParam=*0x%x, container=0x%x, cb=*0x%x, cbUserData=*0x%x)", pDirName, pFileName, pParam, container, cb, cbUserData);
|
||||
|
||||
auto& rec = g_fxo->get<rec_info>();
|
||||
|
||||
if (rec.state != rec_state::closed)
|
||||
{
|
||||
return CELL_REC_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (!pParam || !pDirName || !pFileName)
|
||||
{
|
||||
return CELL_REC_ERROR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
const u32 mem_size = cellRecQueryMemSize(pParam);
|
||||
|
||||
if (container == SYS_MEMORY_CONTAINER_ID_INVALID)
|
||||
{
|
||||
if (mem_size != 0)
|
||||
{
|
||||
return CELL_REC_ERROR_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE: Most likely tries to allocate a complete container. But we use g_fxo instead.
|
||||
// TODO: how much data do we actually need ?
|
||||
rec.video_input_buffer = vm::cast(vm::alloc(mem_size, vm::main));
|
||||
rec.audio_input_buffer = vm::cast(vm::alloc(mem_size, vm::main));
|
||||
|
||||
if (!rec.video_input_buffer || !rec.audio_input_buffer)
|
||||
{
|
||||
return CELL_REC_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
switch (pParam->videoFmt)
|
||||
{
|
||||
case CELL_REC_PARAM_VIDEO_FMT_MPEG4_SMALL_512K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_MPEG4_SMALL_768K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_MPEG4_MIDDLE_512K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_MPEG4_MIDDLE_768K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_MPEG4_LARGE_512K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_MPEG4_LARGE_768K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_MPEG4_LARGE_1024K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_MPEG4_LARGE_1536K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_MPEG4_LARGE_2048K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_AVC_MP_SMALL_512K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_AVC_MP_SMALL_768K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_AVC_MP_MIDDLE_512K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_AVC_MP_MIDDLE_768K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_AVC_MP_MIDDLE_1024K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_AVC_MP_MIDDLE_1536K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_AVC_BL_SMALL_512K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_AVC_BL_SMALL_768K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_AVC_BL_MIDDLE_512K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_AVC_BL_MIDDLE_768K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_AVC_BL_MIDDLE_1024K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_AVC_BL_MIDDLE_1536K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_MJPEG_SMALL_5000K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_MJPEG_MIDDLE_5000K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_MJPEG_LARGE_11000K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_MJPEG_HD720_11000K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_MJPEG_HD720_20000K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_MJPEG_HD720_25000K_30FPS:
|
||||
case 0x3791:
|
||||
case 0x37a1:
|
||||
case 0x3790:
|
||||
case 0x37a0:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_M4HD_SMALL_768K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_M4HD_MIDDLE_768K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_M4HD_LARGE_1536K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_M4HD_LARGE_2048K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_M4HD_HD720_2048K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_M4HD_HD720_5000K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_M4HD_HD720_11000K_30FPS:
|
||||
case CELL_REC_PARAM_VIDEO_FMT_YOUTUBE:
|
||||
break;
|
||||
default:
|
||||
return CELL_REC_ERROR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
const s32 video_type = pParam->videoFmt & 0xf000;
|
||||
const s32 video_quality = pParam->videoFmt & 0xf00;
|
||||
|
||||
switch (pParam->audioFmt)
|
||||
{
|
||||
case CELL_REC_PARAM_AUDIO_FMT_AAC_96K:
|
||||
case CELL_REC_PARAM_AUDIO_FMT_AAC_128K:
|
||||
case CELL_REC_PARAM_AUDIO_FMT_AAC_64K:
|
||||
{
|
||||
// Do not allow MJPEG or AVC_MP video format
|
||||
if (video_type == VIDEO_TYPE_AVC_MP || video_type == VIDEO_TYPE_MJPEG)
|
||||
{
|
||||
return CELL_REC_ERROR_INVALID_VALUE;
|
||||
}
|
||||
[[fallthrough]];
|
||||
}
|
||||
case CELL_REC_PARAM_AUDIO_FMT_ULAW_384K:
|
||||
case CELL_REC_PARAM_AUDIO_FMT_ULAW_768K:
|
||||
{
|
||||
// Do not allow AVC_MP video format
|
||||
if (video_type == VIDEO_TYPE_AVC_MP)
|
||||
{
|
||||
return CELL_REC_ERROR_INVALID_VALUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CELL_REC_PARAM_AUDIO_FMT_PCM_384K:
|
||||
case CELL_REC_PARAM_AUDIO_FMT_PCM_768K:
|
||||
case CELL_REC_PARAM_AUDIO_FMT_PCM_1536K:
|
||||
{
|
||||
// Only allow MJPEG video format
|
||||
if (video_type != VIDEO_TYPE_MJPEG)
|
||||
{
|
||||
return CELL_REC_ERROR_INVALID_VALUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return CELL_REC_ERROR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
rec.param = {};
|
||||
|
||||
u32 spurs_param = 0;
|
||||
bool abort_loop = false;
|
||||
|
||||
for (s32 i = 0; i < pParam->numOfOpt; i++)
|
||||
{
|
||||
const auto& opt = pParam->pOpt[i];
|
||||
ensure(!!opt);
|
||||
|
||||
switch (opt->option)
|
||||
{
|
||||
case CELL_REC_OPTION_PPU_THREAD_PRIORITY:
|
||||
{
|
||||
if (opt->value.ppu_thread_priority > 0xbff)
|
||||
{
|
||||
return CELL_REC_ERROR_INVALID_VALUE;
|
||||
}
|
||||
rec.param.ppu_thread_priority = opt->value.ppu_thread_priority;
|
||||
break;
|
||||
}
|
||||
case CELL_REC_OPTION_SPU_THREAD_PRIORITY:
|
||||
{
|
||||
if (opt->value.spu_thread_priority - 0x10U > 0xef)
|
||||
{
|
||||
return CELL_REC_ERROR_INVALID_VALUE;
|
||||
}
|
||||
rec.param.spu_thread_priority = opt->value.spu_thread_priority;
|
||||
break;
|
||||
}
|
||||
case CELL_REC_OPTION_CAPTURE_PRIORITY:
|
||||
{
|
||||
rec.param.capture_priority = opt->value.capture_priority;
|
||||
break;
|
||||
}
|
||||
case CELL_REC_OPTION_USE_SYSTEM_SPU:
|
||||
{
|
||||
// TODO: Seems differ if video_quality is VIDEO_QUALITY_6 or VIDEO_QUALITY_7
|
||||
rec.param.use_system_spu = opt->value.use_system_spu;
|
||||
break;
|
||||
}
|
||||
case CELL_REC_OPTION_FIT_TO_YOUTUBE:
|
||||
{
|
||||
rec.param.fit_to_youtube = opt->value.fit_to_youtube;
|
||||
break;
|
||||
}
|
||||
case CELL_REC_OPTION_XMB_BGM:
|
||||
{
|
||||
rec.param.xmb_bgm = opt->value.xmb_bgm;
|
||||
break;
|
||||
}
|
||||
case CELL_REC_OPTION_RING_SEC:
|
||||
{
|
||||
rec.param.ring_sec = opt->value.ring_sec;
|
||||
break;
|
||||
}
|
||||
case CELL_REC_OPTION_MPEG4_FAST_ENCODE:
|
||||
{
|
||||
rec.param.mpeg4_fast_encode = opt->value.mpeg4_fast_encode;
|
||||
break;
|
||||
}
|
||||
case CELL_REC_OPTION_VIDEO_INPUT:
|
||||
{
|
||||
const u32 v_input = (opt->value.video_input & 0xffU);
|
||||
if (v_input > CELL_REC_PARAM_VIDEO_INPUT_YUV420PLANAR_16_9)
|
||||
{
|
||||
return CELL_REC_ERROR_INVALID_VALUE;
|
||||
}
|
||||
rec.param.video_input = v_input;
|
||||
break;
|
||||
}
|
||||
case CELL_REC_OPTION_AUDIO_INPUT:
|
||||
{
|
||||
if (opt->value.audio_input == CELL_REC_PARAM_AUDIO_INPUT_DISABLE)
|
||||
{
|
||||
rec.param.audio_input_mix_vol = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
rec.param.audio_input_mix_vol = 100;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CELL_REC_OPTION_AUDIO_INPUT_MIX_VOL:
|
||||
{
|
||||
rec.param.audio_input_mix_vol = opt->value.audio_input_mix_vol;
|
||||
break;
|
||||
}
|
||||
case CELL_REC_OPTION_REDUCE_MEMSIZE:
|
||||
{
|
||||
rec.param.reduce_memsize = opt->value.reduce_memsize != CELL_REC_PARAM_REDUCE_MEMSIZE_DISABLE;
|
||||
break;
|
||||
}
|
||||
case CELL_REC_OPTION_SHOW_XMB:
|
||||
{
|
||||
rec.param.show_xmb = (opt->value.show_xmb != 0);
|
||||
break;
|
||||
}
|
||||
case CELL_REC_OPTION_METADATA_FILENAME:
|
||||
{
|
||||
if (opt->value.metadata_filename)
|
||||
{
|
||||
std::string path;
|
||||
if (!create_path(path, pDirName.get_ptr(), opt->value.metadata_filename.get_ptr()))
|
||||
{
|
||||
return CELL_REC_ERROR_INVALID_VALUE;
|
||||
}
|
||||
rec.param.metadata_filename = path;
|
||||
}
|
||||
else
|
||||
{
|
||||
abort_loop = true; // TODO: Apparently this doesn't return an error but goes to the callback section instead...
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CELL_REC_OPTION_SPURS:
|
||||
{
|
||||
spurs_param = opt->value.pSpursParam.addr();
|
||||
|
||||
if (!opt->value.pSpursParam || !opt->value.pSpursParam->pSpurs) // TODO: check both or only pSpursParam ?
|
||||
{
|
||||
return CELL_REC_ERROR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
if (opt->value.pSpursParam->spu_usage_rate < 1 || opt->value.pSpursParam->spu_usage_rate > 100)
|
||||
{
|
||||
return CELL_REC_ERROR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
rec.param.spurs_param.spu_usage_rate = opt->value.pSpursParam->spu_usage_rate;
|
||||
[[fallthrough]];
|
||||
}
|
||||
case 100:
|
||||
{
|
||||
if (spurs_param)
|
||||
{
|
||||
// TODO:
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (abort_loop)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: The abort_loop variable I chose is actually a goto to the callback section at the end of the function.
|
||||
if (!abort_loop)
|
||||
{
|
||||
if (rec.param.video_input != CELL_REC_PARAM_VIDEO_INPUT_DISABLE)
|
||||
{
|
||||
if (video_type == VIDEO_TYPE_MJPEG || video_type == VIDEO_TYPE_M4HD)
|
||||
{
|
||||
if (rec.param.video_input != CELL_REC_PARAM_VIDEO_INPUT_YUV420PLANAR_16_9)
|
||||
{
|
||||
return CELL_REC_ERROR_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
else if (rec.param.video_input == CELL_REC_PARAM_VIDEO_INPUT_YUV420PLANAR_16_9)
|
||||
{
|
||||
return CELL_REC_ERROR_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!create_path(rec.param.filename, pDirName.get_ptr(), pFileName.get_ptr()))
|
||||
{
|
||||
return CELL_REC_ERROR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
if (!rec.param.filename.starts_with("/dev_hdd0") && !rec.param.filename.starts_with("/dev_hdd1"))
|
||||
{
|
||||
return CELL_REC_ERROR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
//if (spurs_param)
|
||||
//{
|
||||
// if (error_code error = cellSpurs_0xD9A9C592();
|
||||
// {
|
||||
// return error;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
if (!cb)
|
||||
{
|
||||
return CELL_REC_ERROR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
rec.cb = cb;
|
||||
rec.cbUserData = cbUserData;
|
||||
|
||||
@ -87,8 +474,30 @@ error_code cellRecClose(s32 isDiscard)
|
||||
|
||||
auto& rec = g_fxo->get<rec_info>();
|
||||
|
||||
if (rec.state != rec_state::open)
|
||||
{
|
||||
return CELL_REC_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
sysutil_register_cb([=, &rec](ppu_thread& ppu) -> s32
|
||||
{
|
||||
if (isDiscard)
|
||||
{
|
||||
// TODO: remove recording
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: save recording
|
||||
}
|
||||
|
||||
vm::dealloc(rec.video_input_buffer.addr(), vm::main);
|
||||
vm::dealloc(rec.audio_input_buffer.addr(), vm::main);
|
||||
|
||||
rec.param = {};
|
||||
|
||||
// TODO: Sets status CELL_REC_ERROR_FILE_NO_DATA if the start time AND end time are out of scope
|
||||
|
||||
// Sets status CELL_REC_STATUS_ERR on error
|
||||
rec.cb(ppu, CELL_REC_STATUS_CLOSE, CELL_OK, rec.cbUserData);
|
||||
return CELL_OK;
|
||||
});
|
||||
@ -96,19 +505,24 @@ error_code cellRecClose(s32 isDiscard)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
void cellRecGetInfo(s32 info, vm::ptr<u64> pValue)
|
||||
{
|
||||
cellRec.todo("cellRecGetInfo(info=0x%x, pValue=*0x%x)", info, pValue);
|
||||
}
|
||||
|
||||
error_code cellRecStop()
|
||||
{
|
||||
cellRec.todo("cellRecStop()");
|
||||
|
||||
auto& rec = g_fxo->get<rec_info>();
|
||||
|
||||
if (rec.state != rec_state::open)
|
||||
{
|
||||
return CELL_REC_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
sysutil_register_cb([=, &rec](ppu_thread& ppu) -> s32
|
||||
{
|
||||
// TODO: stop recording
|
||||
rec.recording_time_end = get_system_time();
|
||||
rec.recording_time_total += (rec.recording_time_end - rec.recording_time_start);
|
||||
|
||||
// Sets status CELL_REC_STATUS_ERR on error
|
||||
rec.cb(ppu, CELL_REC_STATUS_STOP, CELL_OK, rec.cbUserData);
|
||||
return CELL_OK;
|
||||
});
|
||||
@ -122,8 +536,18 @@ error_code cellRecStart()
|
||||
|
||||
auto& rec = g_fxo->get<rec_info>();
|
||||
|
||||
if (rec.state != rec_state::open)
|
||||
{
|
||||
return CELL_REC_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
sysutil_register_cb([=, &rec](ppu_thread& ppu) -> s32
|
||||
{
|
||||
// TODO: start recording
|
||||
rec.recording_time_start = get_system_time();
|
||||
rec.recording_time_end = rec.recording_time_start;
|
||||
|
||||
// Sets status CELL_REC_STATUS_ERR on error
|
||||
rec.cb(ppu, CELL_REC_STATUS_START, CELL_OK, rec.cbUserData);
|
||||
return CELL_OK;
|
||||
});
|
||||
@ -133,13 +557,347 @@ error_code cellRecStart()
|
||||
|
||||
u32 cellRecQueryMemSize(vm::cptr<CellRecParam> pParam)
|
||||
{
|
||||
cellRec.todo("cellRecQueryMemSize(pParam=*0x%x)", pParam);
|
||||
return 1 * 1024 * 1024; // dummy memory size
|
||||
cellRec.notice("cellRecQueryMemSize(pParam=*0x%x)", pParam);
|
||||
|
||||
if (!pParam)
|
||||
{
|
||||
return 0x900000;
|
||||
}
|
||||
|
||||
u32 video_size = 0x600000; // 6 MB
|
||||
u32 audio_size = 0x100000; // 1 MB
|
||||
u32 external_input_size = 0;
|
||||
u32 reduce_memsize = 0;
|
||||
|
||||
s32 video_type = pParam->videoFmt & 0xf000;
|
||||
s32 video_quality = pParam->videoFmt & 0xf00;
|
||||
|
||||
switch (video_type)
|
||||
{
|
||||
case VIDEO_TYPE_MPEG4:
|
||||
{
|
||||
switch (video_quality)
|
||||
{
|
||||
case VIDEO_QUALITY_0:
|
||||
case VIDEO_QUALITY_3:
|
||||
video_size = 0x600000; // 6 MB
|
||||
break;
|
||||
case VIDEO_QUALITY_1:
|
||||
video_size = 0x700000; // 7 MB
|
||||
break;
|
||||
case VIDEO_QUALITY_2:
|
||||
video_size = 0x800000; // 8 MB
|
||||
break;
|
||||
default:
|
||||
video_size = 0x900000; // 9 MB
|
||||
break;
|
||||
}
|
||||
|
||||
audio_size = 0x100000; // 1 MB
|
||||
break;
|
||||
}
|
||||
case VIDEO_TYPE_AVC_BL:
|
||||
case VIDEO_TYPE_AVC_MP:
|
||||
{
|
||||
switch (video_quality)
|
||||
{
|
||||
case VIDEO_QUALITY_0:
|
||||
case VIDEO_QUALITY_3:
|
||||
video_size = 0x800000; // 8 MB
|
||||
break;
|
||||
default:
|
||||
video_size = 0x900000; // 9 MB
|
||||
break;
|
||||
}
|
||||
|
||||
audio_size = 0x100000; // 1 MB
|
||||
break;
|
||||
}
|
||||
case VIDEO_TYPE_M4HD:
|
||||
{
|
||||
switch (video_quality)
|
||||
{
|
||||
case VIDEO_QUALITY_0:
|
||||
case VIDEO_QUALITY_1:
|
||||
video_size = 0x600000; // 6 MB
|
||||
break;
|
||||
case VIDEO_QUALITY_2:
|
||||
video_size = 0x700000; // 7 MB
|
||||
break;
|
||||
default:
|
||||
video_size = 0x1000000; // 16 MB
|
||||
break;
|
||||
}
|
||||
|
||||
audio_size = 0x100000; // 1 MB
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
switch (video_quality)
|
||||
{
|
||||
case VIDEO_QUALITY_0:
|
||||
video_size = 0x300000; // 3 MB
|
||||
break;
|
||||
case VIDEO_QUALITY_1:
|
||||
case VIDEO_QUALITY_2:
|
||||
video_size = 0x400000; // 4 MB
|
||||
break;
|
||||
case VIDEO_QUALITY_6:
|
||||
video_size = 0x700000; // 7 MB
|
||||
break;
|
||||
default:
|
||||
video_size = 0xd00000; // 14 MB
|
||||
break;
|
||||
}
|
||||
|
||||
audio_size = 0; // 0 MB
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (s32 i = 0; i < pParam->numOfOpt; i++)
|
||||
{
|
||||
const auto& opt = pParam->pOpt[i];
|
||||
ensure(!!opt);
|
||||
|
||||
switch (opt->option)
|
||||
{
|
||||
case CELL_REC_OPTION_REDUCE_MEMSIZE:
|
||||
{
|
||||
if (opt->value.reduce_memsize == CELL_REC_PARAM_REDUCE_MEMSIZE_DISABLE)
|
||||
{
|
||||
reduce_memsize = 0; // 0 MB
|
||||
}
|
||||
else
|
||||
{
|
||||
if (video_type == VIDEO_TYPE_M4HD && (video_quality == VIDEO_QUALITY_1 || video_quality == VIDEO_QUALITY_2))
|
||||
{
|
||||
reduce_memsize = 0x200000; // 2 MB
|
||||
}
|
||||
else
|
||||
{
|
||||
reduce_memsize = 0x300000; // 3 MB
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CELL_REC_OPTION_VIDEO_INPUT:
|
||||
case CELL_REC_OPTION_AUDIO_INPUT:
|
||||
{
|
||||
if (opt->value.audio_input != CELL_REC_PARAM_AUDIO_INPUT_DISABLE)
|
||||
{
|
||||
if (video_type == VIDEO_TYPE_MJPEG || (video_type == VIDEO_TYPE_M4HD && video_quality != VIDEO_QUALITY_6))
|
||||
{
|
||||
external_input_size = 0x100000; // 1MB
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CELL_REC_OPTION_AUDIO_INPUT_MIX_VOL:
|
||||
{
|
||||
// NOTE: Doesn't seem to check opt->value.audio_input
|
||||
if (video_type == VIDEO_TYPE_MJPEG || (video_type == VIDEO_TYPE_M4HD && video_quality != VIDEO_QUALITY_6))
|
||||
{
|
||||
external_input_size = 0x100000; // 1MB
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
u32 size = video_size + audio_size + external_input_size;
|
||||
|
||||
if (size > reduce_memsize)
|
||||
{
|
||||
size -= reduce_memsize;
|
||||
}
|
||||
else
|
||||
{
|
||||
size = 0;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void cellRecGetInfo(s32 info, vm::ptr<u64> pValue)
|
||||
{
|
||||
cellRec.todo("cellRecGetInfo(info=0x%x, pValue=*0x%x)", info, pValue);
|
||||
|
||||
if (!pValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
*pValue = 0;
|
||||
|
||||
auto& rec = g_fxo->get<rec_info>();
|
||||
|
||||
switch (info)
|
||||
{
|
||||
case CELL_REC_INFO_VIDEO_INPUT_ADDR:
|
||||
{
|
||||
*pValue = rec.video_input_buffer.addr();
|
||||
break;
|
||||
}
|
||||
case CELL_REC_INFO_VIDEO_INPUT_WIDTH:
|
||||
{
|
||||
*pValue = rec.width;
|
||||
break;
|
||||
}
|
||||
case CELL_REC_INFO_VIDEO_INPUT_PITCH:
|
||||
{
|
||||
*pValue = rec.pitch;
|
||||
break;
|
||||
}
|
||||
case CELL_REC_INFO_VIDEO_INPUT_HEIGHT:
|
||||
{
|
||||
*pValue = rec.height;
|
||||
break;
|
||||
}
|
||||
case CELL_REC_INFO_AUDIO_INPUT_ADDR:
|
||||
{
|
||||
*pValue = rec.audio_input_buffer.addr();
|
||||
break;
|
||||
}
|
||||
case CELL_REC_INFO_MOVIE_TIME_MSEC:
|
||||
{
|
||||
if (rec.state == rec_state::open)
|
||||
{
|
||||
*pValue = rec.recording_time_total;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CELL_REC_INFO_SPURS_SYSTEMWORKLOAD_ID:
|
||||
{
|
||||
if (rec.param.spurs_param.pSpurs)
|
||||
{
|
||||
// TODO
|
||||
//cellSpurs_0xE279681F();
|
||||
}
|
||||
*pValue = 0xffffffff;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
error_code cellRecSetInfo(s32 setInfo, u64 value)
|
||||
{
|
||||
cellRec.todo("cellRecSetInfo(setInfo=0x%x, value=0x%x)", setInfo, value);
|
||||
|
||||
auto& rec = g_fxo->get<rec_info>();
|
||||
|
||||
if (rec.state != rec_state::open)
|
||||
{
|
||||
return CELL_REC_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
switch (setInfo)
|
||||
{
|
||||
case CELL_REC_SETINFO_MOVIE_START_TIME_MSEC:
|
||||
{
|
||||
rec.param.scene_metadata.start_time = value;
|
||||
break;
|
||||
}
|
||||
case CELL_REC_SETINFO_MOVIE_END_TIME_MSEC:
|
||||
{
|
||||
rec.param.scene_metadata.end_time = value;
|
||||
break;
|
||||
}
|
||||
case CELL_REC_SETINFO_MOVIE_META:
|
||||
{
|
||||
if (!value)
|
||||
{
|
||||
return CELL_REC_ERROR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
vm::ptr<CellRecMovieMetadata> movie_metadata = vm::cast(value);
|
||||
|
||||
if (!movie_metadata || !movie_metadata->gameTitle || !movie_metadata->movieTitle ||
|
||||
strnlen(movie_metadata->gameTitle.get_ptr(), CELL_REC_MOVIE_META_GAME_TITLE_LEN) >= CELL_REC_MOVIE_META_GAME_TITLE_LEN ||
|
||||
strnlen(movie_metadata->movieTitle.get_ptr(), CELL_REC_MOVIE_META_MOVIE_TITLE_LEN) >= CELL_REC_MOVIE_META_MOVIE_TITLE_LEN)
|
||||
{
|
||||
return CELL_REC_ERROR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
if ((movie_metadata->description && strnlen(movie_metadata->description.get_ptr(), CELL_REC_MOVIE_META_DESCRIPTION_LEN) >= CELL_REC_MOVIE_META_DESCRIPTION_LEN) ||
|
||||
(movie_metadata->userdata && strnlen(movie_metadata->userdata.get_ptr(), CELL_REC_MOVIE_META_USERDATA_LEN) >= CELL_REC_MOVIE_META_USERDATA_LEN))
|
||||
{
|
||||
return CELL_REC_ERROR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
rec.param.movie_metadata = {};
|
||||
rec.param.movie_metadata.game_title = std::string{movie_metadata->gameTitle.get_ptr()};
|
||||
rec.param.movie_metadata.movie_title = std::string{movie_metadata->movieTitle.get_ptr()};
|
||||
|
||||
if (movie_metadata->description)
|
||||
{
|
||||
rec.param.movie_metadata.description = std::string{movie_metadata->description.get_ptr()};
|
||||
}
|
||||
|
||||
if (movie_metadata->userdata)
|
||||
{
|
||||
rec.param.movie_metadata.userdata = std::string{movie_metadata->userdata.get_ptr()};
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case CELL_REC_SETINFO_SCEME_META:
|
||||
{
|
||||
if (!value)
|
||||
{
|
||||
return CELL_REC_ERROR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
vm::ptr<CellRecSceneMetadata> scene_metadata = vm::cast(value);
|
||||
|
||||
if (!scene_metadata || !scene_metadata->title ||
|
||||
scene_metadata->type > CELL_REC_SCENE_META_TYPE_CLIP_USER ||
|
||||
scene_metadata->tagNum > CELL_REC_SCENE_META_TAG_NUM ||
|
||||
strnlen(scene_metadata->title.get_ptr(), CELL_REC_SCENE_META_TITLE_LEN) >= CELL_REC_SCENE_META_TITLE_LEN)
|
||||
{
|
||||
return CELL_REC_ERROR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
for (usz i = 0; i < scene_metadata->tagNum; i++)
|
||||
{
|
||||
if (!scene_metadata->tag[i] ||
|
||||
strnlen(scene_metadata->tag[i].get_ptr(), CELL_REC_SCENE_META_TAG_LEN) >= CELL_REC_SCENE_META_TAG_LEN)
|
||||
{
|
||||
return CELL_REC_ERROR_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
rec.param.scene_metadata = {};
|
||||
rec.param.scene_metadata.is_set = true;
|
||||
rec.param.scene_metadata.type = scene_metadata->type;
|
||||
rec.param.scene_metadata.start_time = scene_metadata->startTime;
|
||||
rec.param.scene_metadata.end_time = scene_metadata->endTime;
|
||||
rec.param.scene_metadata.title = std::string{scene_metadata->title.get_ptr()};
|
||||
rec.param.scene_metadata.tags.resize(scene_metadata->tagNum);
|
||||
|
||||
for (usz i = 0; i < scene_metadata->tagNum; i++)
|
||||
{
|
||||
if (scene_metadata->tag[i])
|
||||
{
|
||||
rec.param.scene_metadata.tags[i] = std::string{scene_metadata->tag[i].get_ptr()};
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return CELL_REC_ERROR_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
244
rpcs3/Emu/Cell/Modules/cellRec.h
Normal file
244
rpcs3/Emu/Cell/Modules/cellRec.h
Normal file
@ -0,0 +1,244 @@
|
||||
#pragma once
|
||||
|
||||
enum CellRecError : u32
|
||||
{
|
||||
CELL_REC_ERROR_OUT_OF_MEMORY = 0x8002c501,
|
||||
CELL_REC_ERROR_FATAL = 0x8002c502,
|
||||
CELL_REC_ERROR_INVALID_VALUE = 0x8002c503,
|
||||
CELL_REC_ERROR_FILE_OPEN = 0x8002c504,
|
||||
CELL_REC_ERROR_FILE_WRITE = 0x8002c505,
|
||||
CELL_REC_ERROR_INVALID_STATE = 0x8002c506,
|
||||
CELL_REC_ERROR_FILE_NO_DATA = 0x8002c507
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CELL_REC_STATUS_UNLOAD = 0,
|
||||
CELL_REC_STATUS_OPEN = 1,
|
||||
CELL_REC_STATUS_START = 2,
|
||||
CELL_REC_STATUS_STOP = 3,
|
||||
CELL_REC_STATUS_CLOSE = 4,
|
||||
CELL_REC_STATUS_ERR = 10
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CELL_REC_MIN_MEMORY_CONTAINER_SIZE = 0,
|
||||
CELL_REC_MAX_MEMORY_CONTAINER_SIZE = 16 * 1024 * 1024, // 9 * 1024 * 1024 if SDK < 0x300000
|
||||
|
||||
CELL_REC_MAX_PATH_LEN = 1023,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CELL_REC_PARAM_PPU_THREAD_PRIORITY_DEFAULT = 400,
|
||||
CELL_REC_PARAM_SPU_THREAD_PRIORITY_DEFAULT = 60,
|
||||
|
||||
CELL_REC_PARAM_CAPTURE_PRIORITY_HIGHEST = 0,
|
||||
CELL_REC_PARAM_CAPTURE_PRIORITY_EXCEPT_NOTIFICATION = 1,
|
||||
CELL_REC_PARAM_CAPTURE_PRIORITY_GAME_SCREEN = 2,
|
||||
|
||||
CELL_REC_PARAM_USE_SYSTEM_SPU_DISABLE = 0,
|
||||
CELL_REC_PARAM_USE_SYSTEM_SPU_ENABLE = 1,
|
||||
|
||||
CELL_REC_PARAM_XMB_BGM_DISABLE = 0,
|
||||
CELL_REC_PARAM_XMB_BGM_ENABLE = 1,
|
||||
|
||||
CELL_REC_PARAM_MPEG4_FAST_ENCODE_DISABLE = 0,
|
||||
CELL_REC_PARAM_MPEG4_FAST_ENCODE_ENABLE = 1,
|
||||
|
||||
CELL_REC_PARAM_VIDEO_INPUT_DISABLE = 0,
|
||||
CELL_REC_PARAM_VIDEO_INPUT_ARGB_4_3 = 1,
|
||||
CELL_REC_PARAM_VIDEO_INPUT_ARGB_16_9 = 2,
|
||||
CELL_REC_PARAM_VIDEO_INPUT_RGBA_4_3 = 3,
|
||||
CELL_REC_PARAM_VIDEO_INPUT_RGBA_16_9 = 4,
|
||||
CELL_REC_PARAM_VIDEO_INPUT_YUV420PLANAR_16_9 = 5,
|
||||
|
||||
CELL_REC_PARAM_AUDIO_INPUT_DISABLE = 0,
|
||||
CELL_REC_PARAM_AUDIO_INPUT_ENABLE = 1,
|
||||
|
||||
CELL_REC_PARAM_AUDIO_INPUT_MIX_VOL_MIN = 0,
|
||||
CELL_REC_PARAM_AUDIO_INPUT_MIX_VOL_MAX = 100,
|
||||
|
||||
CELL_REC_PARAM_REDUCE_MEMSIZE_DISABLE = 0,
|
||||
CELL_REC_PARAM_REDUCE_MEMSIZE_ENABLE = 1,
|
||||
|
||||
// SMALL = 320x240 (4:3) or 368x208 (16:9)
|
||||
// MIDDLE = 368x272 (4:3) or 480x272 (16:9)
|
||||
// LARGE = 480x368 (4:3) or 640x368 (16:9)
|
||||
// HD720 = 1280x720 (16:9)
|
||||
|
||||
// PS3 playable format; all
|
||||
// PSP playable format: MPEG4 + SMALL, AVC + SMALL, AVC + MIDDLE
|
||||
|
||||
CELL_REC_PARAM_VIDEO_FMT_MPEG4_SMALL_512K_30FPS = 0x0000,
|
||||
CELL_REC_PARAM_VIDEO_FMT_MPEG4_SMALL_768K_30FPS = 0x0010,
|
||||
CELL_REC_PARAM_VIDEO_FMT_MPEG4_MIDDLE_512K_30FPS = 0x0100,
|
||||
CELL_REC_PARAM_VIDEO_FMT_MPEG4_MIDDLE_768K_30FPS = 0x0110,
|
||||
CELL_REC_PARAM_VIDEO_FMT_MPEG4_LARGE_512K_30FPS = 0x0200,
|
||||
CELL_REC_PARAM_VIDEO_FMT_MPEG4_LARGE_768K_30FPS = 0x0210,
|
||||
CELL_REC_PARAM_VIDEO_FMT_MPEG4_LARGE_1024K_30FPS = 0x0220,
|
||||
CELL_REC_PARAM_VIDEO_FMT_MPEG4_LARGE_1536K_30FPS = 0x0230,
|
||||
CELL_REC_PARAM_VIDEO_FMT_MPEG4_LARGE_2048K_30FPS = 0x0240,
|
||||
|
||||
CELL_REC_PARAM_VIDEO_FMT_AVC_MP_SMALL_512K_30FPS = 0x1000,
|
||||
CELL_REC_PARAM_VIDEO_FMT_AVC_MP_SMALL_768K_30FPS = 0x1010,
|
||||
CELL_REC_PARAM_VIDEO_FMT_AVC_MP_MIDDLE_512K_30FPS = 0x1100,
|
||||
CELL_REC_PARAM_VIDEO_FMT_AVC_MP_MIDDLE_768K_30FPS = 0x1110,
|
||||
CELL_REC_PARAM_VIDEO_FMT_AVC_MP_MIDDLE_1024K_30FPS = 0x1120,
|
||||
CELL_REC_PARAM_VIDEO_FMT_AVC_MP_MIDDLE_1536K_30FPS = 0x1130,
|
||||
|
||||
CELL_REC_PARAM_VIDEO_FMT_AVC_BL_SMALL_512K_30FPS = 0x2000,
|
||||
CELL_REC_PARAM_VIDEO_FMT_AVC_BL_SMALL_768K_30FPS = 0x2010,
|
||||
CELL_REC_PARAM_VIDEO_FMT_AVC_BL_MIDDLE_512K_30FPS = 0x2100,
|
||||
CELL_REC_PARAM_VIDEO_FMT_AVC_BL_MIDDLE_768K_30FPS = 0x2110,
|
||||
CELL_REC_PARAM_VIDEO_FMT_AVC_BL_MIDDLE_1024K_30FPS = 0x2120,
|
||||
CELL_REC_PARAM_VIDEO_FMT_AVC_BL_MIDDLE_1536K_30FPS = 0x2130,
|
||||
|
||||
CELL_REC_PARAM_VIDEO_FMT_MJPEG_SMALL_5000K_30FPS = 0x3060,
|
||||
CELL_REC_PARAM_VIDEO_FMT_MJPEG_MIDDLE_5000K_30FPS = 0x3160,
|
||||
CELL_REC_PARAM_VIDEO_FMT_MJPEG_LARGE_11000K_30FPS = 0x3270,
|
||||
CELL_REC_PARAM_VIDEO_FMT_MJPEG_HD720_11000K_30FPS = 0x3670,
|
||||
CELL_REC_PARAM_VIDEO_FMT_MJPEG_HD720_20000K_30FPS = 0x3680,
|
||||
CELL_REC_PARAM_VIDEO_FMT_MJPEG_HD720_25000K_30FPS = 0x3690,
|
||||
|
||||
CELL_REC_PARAM_VIDEO_FMT_M4HD_SMALL_768K_30FPS = 0x4010,
|
||||
CELL_REC_PARAM_VIDEO_FMT_M4HD_MIDDLE_768K_30FPS = 0x4110,
|
||||
CELL_REC_PARAM_VIDEO_FMT_M4HD_LARGE_1536K_30FPS = 0x4230,
|
||||
CELL_REC_PARAM_VIDEO_FMT_M4HD_LARGE_2048K_30FPS = 0x4240,
|
||||
CELL_REC_PARAM_VIDEO_FMT_M4HD_HD720_2048K_30FPS = 0x4640,
|
||||
CELL_REC_PARAM_VIDEO_FMT_M4HD_HD720_5000K_30FPS = 0x4660,
|
||||
CELL_REC_PARAM_VIDEO_FMT_M4HD_HD720_11000K_30FPS = 0x4670,
|
||||
|
||||
CELL_REC_PARAM_AUDIO_FMT_AAC_96K = 0x0000,
|
||||
CELL_REC_PARAM_AUDIO_FMT_AAC_128K = 0x0001,
|
||||
CELL_REC_PARAM_AUDIO_FMT_AAC_64K = 0x0002,
|
||||
|
||||
CELL_REC_PARAM_AUDIO_FMT_ULAW_384K = 0x1007,
|
||||
CELL_REC_PARAM_AUDIO_FMT_ULAW_768K = 0x1008,
|
||||
|
||||
CELL_REC_PARAM_AUDIO_FMT_PCM_384K = 0x2007,
|
||||
CELL_REC_PARAM_AUDIO_FMT_PCM_768K = 0x2008,
|
||||
CELL_REC_PARAM_AUDIO_FMT_PCM_1536K = 0x2009,
|
||||
|
||||
CELL_REC_PARAM_VIDEO_FMT_YOUTUBE = 0x0310,
|
||||
CELL_REC_PARAM_VIDEO_FMT_YOUTUBE_LARGE = CELL_REC_PARAM_VIDEO_FMT_MPEG4_LARGE_2048K_30FPS,
|
||||
CELL_REC_PARAM_VIDEO_FMT_YOUTUBE_HD720 = CELL_REC_PARAM_VIDEO_FMT_M4HD_HD720_5000K_30FPS,
|
||||
CELL_REC_PARAM_AUDIO_FMT_YOUTUBE = CELL_REC_PARAM_AUDIO_FMT_AAC_64K,
|
||||
|
||||
CELL_REC_PARAM_VIDEO_FMT_YOUTUBE_MJPEG = CELL_REC_PARAM_VIDEO_FMT_MJPEG_HD720_11000K_30FPS,
|
||||
CELL_REC_PARAM_AUDIO_FMT_YOUTUBE_MJPEG = CELL_REC_PARAM_AUDIO_FMT_PCM_768K,
|
||||
|
||||
CELL_REC_AUDIO_BLOCK_SAMPLES = 256,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CELL_REC_INFO_VIDEO_INPUT_ADDR = 0,
|
||||
CELL_REC_INFO_VIDEO_INPUT_WIDTH = 1,
|
||||
CELL_REC_INFO_VIDEO_INPUT_PITCH = 2,
|
||||
CELL_REC_INFO_VIDEO_INPUT_HEIGHT = 3,
|
||||
CELL_REC_INFO_AUDIO_INPUT_ADDR = 4,
|
||||
CELL_REC_INFO_MOVIE_TIME_MSEC = 5,
|
||||
CELL_REC_INFO_SPURS_SYSTEMWORKLOAD_ID = 6,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CELL_REC_SETINFO_MOVIE_START_TIME_MSEC = 100,
|
||||
CELL_REC_SETINFO_MOVIE_END_TIME_MSEC = 101,
|
||||
CELL_REC_SETINFO_MOVIE_META = 200,
|
||||
CELL_REC_SETINFO_SCEME_META = 201,
|
||||
|
||||
CELL_REC_MOVIE_META_GAME_TITLE_LEN = 128,
|
||||
CELL_REC_MOVIE_META_MOVIE_TITLE_LEN = 128,
|
||||
CELL_REC_MOVIE_META_DESCRIPTION_LEN = 384,
|
||||
CELL_REC_MOVIE_META_USERDATA_LEN = 64,
|
||||
|
||||
CELL_REC_SCENE_META_TYPE_CHAPTER = 0,
|
||||
CELL_REC_SCENE_META_TYPE_CLIP_HIGHLIGHT = 1,
|
||||
CELL_REC_SCENE_META_TYPE_CLIP_USER = 2,
|
||||
|
||||
CELL_REC_SCENE_META_TITLE_LEN = 128,
|
||||
CELL_REC_SCENE_META_TAG_NUM = 6,
|
||||
CELL_REC_SCENE_META_TAG_LEN = 64,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CELL_REC_OPTION_PPU_THREAD_PRIORITY = 1,
|
||||
CELL_REC_OPTION_SPU_THREAD_PRIORITY = 2,
|
||||
CELL_REC_OPTION_CAPTURE_PRIORITY = 3,
|
||||
CELL_REC_OPTION_USE_SYSTEM_SPU = 4,
|
||||
CELL_REC_OPTION_FIT_TO_YOUTUBE = 5,
|
||||
CELL_REC_OPTION_XMB_BGM = 6,
|
||||
CELL_REC_OPTION_RING_SEC = 7,
|
||||
CELL_REC_OPTION_MPEG4_FAST_ENCODE = 8,
|
||||
CELL_REC_OPTION_VIDEO_INPUT = 9,
|
||||
CELL_REC_OPTION_AUDIO_INPUT = 10,
|
||||
CELL_REC_OPTION_AUDIO_INPUT_MIX_VOL = 11,
|
||||
CELL_REC_OPTION_REDUCE_MEMSIZE = 12,
|
||||
CELL_REC_OPTION_SHOW_XMB = 13,
|
||||
CELL_REC_OPTION_METADATA_FILENAME = 14,
|
||||
CELL_REC_OPTION_SPURS = 15,
|
||||
};
|
||||
|
||||
struct CellRecSpursParam
|
||||
{
|
||||
vm::bptr<struct CellSpurs> pSpurs;
|
||||
be_t<s32> spu_usage_rate;
|
||||
u8 priority[8];
|
||||
};
|
||||
|
||||
struct CellRecOption
|
||||
{
|
||||
be_t<s32> option;
|
||||
union
|
||||
{
|
||||
be_t<s32> ppu_thread_priority; // CELL_REC_OPTION_PPU_THREAD_PRIORITY
|
||||
be_t<s32> spu_thread_priority; // CELL_REC_OPTION_SPU_THREAD_PRIORITY
|
||||
be_t<s32> capture_priority; // CELL_REC_OPTION_CAPTURE_PRIORITY
|
||||
be_t<s32> use_system_spu; // CELL_REC_OPTION_USE_SYSTEM_SPU
|
||||
be_t<s32> fit_to_youtube; // CELL_REC_OPTION_FIT_TO_YOUTUBE
|
||||
be_t<s32> xmb_bgm; // CELL_REC_OPTION_XMB_BGM
|
||||
be_t<s32> mpeg4_fast_encode; // CELL_REC_OPTION_MPEG4_FAST_ENCODE
|
||||
be_t<u32> ring_sec; // CELL_REC_OPTION_RING_SEC
|
||||
be_t<s32> video_input; // CELL_REC_OPTION_VIDEO_INPUT
|
||||
be_t<s32> audio_input; // CELL_REC_OPTION_AUDIO_INPUT
|
||||
be_t<s32> audio_input_mix_vol; // CELL_REC_OPTION_AUDIO_INPUT_MIX_VOL
|
||||
be_t<s32> reduce_memsize; // CELL_REC_OPTION_REDUCE_MEMSIZE
|
||||
be_t<s32> show_xmb; // CELL_REC_OPTION_SHOW_XMB
|
||||
vm::bptr<char> metadata_filename; // CELL_REC_OPTION_METADATA_FILENAME
|
||||
vm::bptr<CellRecSpursParam> pSpursParam; // CELL_REC_OPTION_SPURS
|
||||
be_t<u64> dummy; // -
|
||||
} value;
|
||||
};
|
||||
|
||||
struct CellRecParam
|
||||
{
|
||||
be_t<s32> videoFmt;
|
||||
be_t<s32> audioFmt;
|
||||
be_t<s32> numOfOpt;
|
||||
vm::bpptr<CellRecOption> pOpt;
|
||||
};
|
||||
|
||||
struct CellRecMovieMetadata
|
||||
{
|
||||
vm::bptr<char> gameTitle;
|
||||
vm::bptr<char> movieTitle;
|
||||
vm::bptr<char> description;
|
||||
vm::bptr<char> userdata;
|
||||
};
|
||||
|
||||
struct CellRecSceneMetadata
|
||||
{
|
||||
be_t<u32> type;
|
||||
be_t<u64> startTime;
|
||||
be_t<u64> endTime;
|
||||
u8 unk[4]; // NOTE: there seems to be undocumented padding
|
||||
vm::bptr<char> title;
|
||||
be_t<u32> tagNum;
|
||||
vm::bpptr<char> tag;
|
||||
};
|
||||
|
||||
using CellRecCallback = void(s32 recStatus, s32 recError, vm::ptr<void> userdata);
|
@ -454,6 +454,7 @@
|
||||
<ClInclude Include="Emu\cache_utils.hpp" />
|
||||
<ClInclude Include="Emu\Cell\lv2\sys_crypto_engine.h" />
|
||||
<ClInclude Include="Emu\Cell\Modules\cellCrossController.h" />
|
||||
<ClInclude Include="Emu\Cell\Modules\cellRec.h" />
|
||||
<ClInclude Include="Emu\Cell\Modules\cellRemotePlay.h" />
|
||||
<ClInclude Include="Emu\Cell\Modules\cellSsl.h" />
|
||||
<ClInclude Include="Emu\Cell\Modules\cellStorage.h" />
|
||||
|
@ -2101,6 +2101,9 @@
|
||||
<ClInclude Include="Emu\RSX\Common\buffer_stream.hpp">
|
||||
<Filter>Emu\GPU\RSX\Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\Cell\Modules\cellRec.h">
|
||||
<Filter>Emu\Cell\Modules</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Emu\RSX\Common\Interpreter\FragmentInterpreter.glsl">
|
||||
|
Loading…
x
Reference in New Issue
Block a user