void vdecOpen(u32 vdec_id) // TODO: call from the constructor { const auto sptr = idm::get<VideoDecoder>(vdec_id); VideoDecoder& vdec = *sptr; vdec.id = vdec_id; vdec.vdecCb = idm::make_ptr<PPUThread>(fmt::format("VideoDecoder[0x%x] Thread", vdec_id)); vdec.vdecCb->prio = 1001; vdec.vdecCb->stack_size = 0x10000; vdec.vdecCb->custom_task = [sptr](PPUThread& ppu) { VideoDecoder& vdec = *sptr; VdecTask& task = vdec.task; while (true) { if (Emu.IsStopped() || vdec.is_closed) { break; } if (!vdec.job.pop(task, &vdec.is_closed)) { break; } switch (task.type) { case vdecStartSeq: { // TODO: reset data cellVdec.warning("vdecStartSeq:"); vdec.reader = {}; vdec.frc_set = 0; vdec.just_started = true; break; } case vdecEndSeq: { // TODO: finalize cellVdec.warning("vdecEndSeq:"); vdec.cbFunc(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_SEQDONE, CELL_OK, vdec.cbArg); vdec.just_finished = true; break; } case vdecDecodeAu: { int err; vdec.reader.addr = task.addr; vdec.reader.size = task.size; //LOG_NOTICE(HLE, "Video AU: size = 0x%x, pts = 0x%llx, dts = 0x%llx", task.size, task.pts, task.dts); if (vdec.just_started) { vdec.first_pts = task.pts; vdec.last_pts = -1; vdec.first_dts = task.dts; } struct AVPacketHolder : AVPacket { AVPacketHolder(u32 size) { av_init_packet(this); if (size) { data = (u8*)av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE); memset(data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE); this->size = size + FF_INPUT_BUFFER_PADDING_SIZE; } else { data = NULL; size = 0; } } ~AVPacketHolder() { av_free(data); //av_free_packet(this); } } au(0); if (vdec.just_started && vdec.just_finished) { avcodec_flush_buffers(vdec.ctx); vdec.just_started = false; vdec.just_finished = false; } else if (vdec.just_started) // deferred initialization { AVDictionary* opts = nullptr; av_dict_set(&opts, "probesize", "4096", 0); err = avformat_open_input(&vdec.fmt, NULL, NULL, &opts); if (err || opts) { throw EXCEPTION("avformat_open_input() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0); } if (vdec.type == CELL_VDEC_CODEC_TYPE_DIVX) { err = avformat_find_stream_info(vdec.fmt, NULL); if (err || !vdec.fmt->nb_streams) { throw EXCEPTION("avformat_find_stream_info() failed (err=0x%x, nb_streams=%d)", err, vdec.fmt->nb_streams); } } else { if (!avformat_new_stream(vdec.fmt, vdec.codec)) { throw EXCEPTION("avformat_new_stream() failed"); } } vdec.ctx = vdec.fmt->streams[0]->codec; // TODO: check data opts = nullptr; av_dict_set(&opts, "refcounted_frames", "1", 0); { std::lock_guard<std::mutex> lock(g_mutex_avcodec_open2); // not multithread-safe (???) err = avcodec_open2(vdec.ctx, vdec.codec, &opts); } if (err || opts) { throw EXCEPTION("avcodec_open2() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0); } vdec.just_started = false; } bool last_frame = false; while (true) { if (Emu.IsStopped() || vdec.is_closed) { if (Emu.IsStopped()) cellVdec.warning("vdecDecodeAu: aborted"); break; } last_frame = av_read_frame(vdec.fmt, &au) < 0; if (last_frame) { //break; av_free(au.data); au.data = NULL; au.size = 0; } struct VdecFrameHolder : VdecFrame { VdecFrameHolder() { data = av_frame_alloc(); } ~VdecFrameHolder() { if (data) { av_frame_unref(data); av_frame_free(&data); } } } frame; if (!frame.data) { throw EXCEPTION("av_frame_alloc() failed"); } int got_picture = 0; int decode = avcodec_decode_video2(vdec.ctx, frame.data, &got_picture, &au); if (decode <= 0) { if (decode < 0) { cellVdec.error("vdecDecodeAu: AU decoding error(0x%x)", decode); } if (!got_picture && vdec.reader.size == 0) break; // video end? } if (got_picture) { if (frame.data->interlaced_frame) { throw EXCEPTION("Interlaced frames not supported (0x%x)", frame.data->interlaced_frame); } if (frame.data->repeat_pict) { throw EXCEPTION("Repeated frames not supported (0x%x)", frame.data->repeat_pict); } if (vdec.frc_set) { if (vdec.last_pts == -1) { u64 ts = av_frame_get_best_effort_timestamp(frame.data); if (ts != AV_NOPTS_VALUE) { vdec.last_pts = ts; } else { vdec.last_pts = 0; } } else switch (vdec.frc_set) { case CELL_VDEC_FRC_24000DIV1001: vdec.last_pts += 1001 * 90000 / 24000; break; case CELL_VDEC_FRC_24: vdec.last_pts += 90000 / 24; break; case CELL_VDEC_FRC_25: vdec.last_pts += 90000 / 25; break; case CELL_VDEC_FRC_30000DIV1001: vdec.last_pts += 1001 * 90000 / 30000; break; case CELL_VDEC_FRC_30: vdec.last_pts += 90000 / 30; break; case CELL_VDEC_FRC_50: vdec.last_pts += 90000 / 50; break; case CELL_VDEC_FRC_60000DIV1001: vdec.last_pts += 1001 * 90000 / 60000; break; case CELL_VDEC_FRC_60: vdec.last_pts += 90000 / 60; break; default: { throw EXCEPTION("Invalid frame rate code set (0x%x)", vdec.frc_set); } } frame.frc = vdec.frc_set; } else { u64 ts = av_frame_get_best_effort_timestamp(frame.data); if (ts != AV_NOPTS_VALUE) { vdec.last_pts = ts; } else if (vdec.last_pts == -1) { vdec.last_pts = 0; } else { vdec.last_pts += vdec.ctx->time_base.num * 90000 * vdec.ctx->ticks_per_frame / vdec.ctx->time_base.den; } if (vdec.ctx->time_base.num == 1) { switch ((u64)vdec.ctx->time_base.den + (u64)(vdec.ctx->ticks_per_frame - 1) * 0x100000000ull) { 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; default: { throw EXCEPTION("Unsupported time_base.den (%d/1, tpf=%d)", vdec.ctx->time_base.den, vdec.ctx->ticks_per_frame); } } } 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; } else if (vdec.ctx->time_base.den / vdec.ctx->ticks_per_frame == 60000) { frame.frc = CELL_VDEC_FRC_60000DIV1001; } else { throw EXCEPTION("Unsupported time_base.den (%d/1001, tpf=%d)", vdec.ctx->time_base.den, vdec.ctx->ticks_per_frame); } } else { throw EXCEPTION("Unsupported time_base.num (%d)", vdec.ctx->time_base.num); } } frame.pts = vdec.last_pts; frame.dts = (frame.pts - vdec.first_pts) + vdec.first_dts; frame.userdata = task.userData; //LOG_NOTICE(HLE, "got picture (pts=0x%llx, dts=0x%llx)", frame.pts, frame.dts); if (vdec.frames.push(frame, &vdec.is_closed)) { frame.data = nullptr; // to prevent destruction vdec.cbFunc(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_PICOUT, CELL_OK, vdec.cbArg); } } } vdec.cbFunc(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, vdec.cbArg); break; } case vdecSetFrameRate: { cellVdec.warning("vdecSetFrameRate(0x%x)", task.frc); vdec.frc_set = task.frc; break; } case vdecClose: { break; } default: { throw EXCEPTION("Unknown task(%d)", task.type); } } } vdec.is_finished = true; }; vdec.vdecCb->cpu_init(); vdec.vdecCb->state -= cpu_state::stop; vdec.vdecCb->safe_notify(); }
DECLARE(ppu_module_manager::sysPrxForUser)("sysPrxForUser", []() { sysPrxForUser_sys_lwmutex_init(); sysPrxForUser_sys_lwcond_init(); sysPrxForUser_sys_ppu_thread_init(); sysPrxForUser_sys_prx_init(); sysPrxForUser_sys_heap_init(); sysPrxForUser_sys_spinlock_init(); sysPrxForUser_sys_mmapper_init(); sysPrxForUser_sys_mempool_init(); sysPrxForUser_sys_spu_init(); sysPrxForUser_sys_game_init(); sysPrxForUser_sys_libc_init(); REG_VAR(sysPrxForUser, sys_prx_version); // 0x7df066cf REG_FUNC(sysPrxForUser, sys_initialize_tls); REG_FUNC(sysPrxForUser, sys_time_get_system_time); // TODO: split syscalls and liblv2 functions REG_FUNC(sysPrxForUser, sys_process_exit); REG_FUNC(sysPrxForUser, _sys_process_atexitspawn); REG_FUNC(sysPrxForUser, _sys_process_at_Exitspawn); REG_FUNC(sysPrxForUser, sys_process_is_stack); REG_FUNC(sysPrxForUser, sys_process_get_paramsfo); // 0xe75c40f2 REG_FUNC(sysPrxForUser, sys_interrupt_thread_disestablish); REG_FUNC(sysPrxForUser, sys_get_random_number);
}); sysPrxForUser_sys_lwmutex_init(); sysPrxForUser_sys_lwcond_init(); sysPrxForUser_sys_ppu_thread_init(); sysPrxForUser_sys_prx_init(); sysPrxForUser_sys_heap_init(); sysPrxForUser_sys_spinlock_init(); sysPrxForUser_sys_mmapper_init(); sysPrxForUser_sys_mempool_init(); sysPrxForUser_sys_spu_init(); sysPrxForUser_sys_game_init(); sysPrxForUser_sys_libc_init(); sysPrxForUser_sys_rsxaudio_init(); REG_VAR(sysPrxForUser, sys_prx_version); // 0x7df066cf REG_VAR(sysPrxForUser, g_ppu_atexitspawn).flag(MFF_HIDDEN); REG_VAR(sysPrxForUser, g_ppu_at_Exitspawn).flag(MFF_HIDDEN); REG_FUNC(sysPrxForUser, sys_time_get_system_time); REG_FUNC(sysPrxForUser, sys_process_exit); REG_FUNC(sysPrxForUser, _sys_process_atexitspawn); REG_FUNC(sysPrxForUser, _sys_process_at_Exitspawn); REG_FUNC(sysPrxForUser, sys_process_is_stack); REG_FUNC(sysPrxForUser, sys_process_get_paramsfo); // 0xe75c40f2 REG_FUNC(sysPrxForUser, sys_get_random_number); REG_FUNC(sysPrxForUser, console_getc); REG_FUNC(sysPrxForUser, console_putc);
// float diagonal = roundf(sqrtf((powf(wxGetDisplaySizeMM().GetWidth(), 2) + powf(wxGetDisplaySizeMM().GetHeight(), 2))) * 0.0393f); #endif return CELL_VIDEO_OUT_ERROR_VALUE_IS_NOT_SET; } s32 cellVideoOutSetCopyControl(u32 videoOut, u32 control) { cellAvconfExt.todo("cellVideoOutSetCopyControl(videoOut=%d, control=0x%x)", videoOut, control); return CELL_OK; } DECLARE(ppu_module_manager::cellAvconfExt)("cellSysutilAvconfExt", []() { REG_VAR(cellSysutilAvconfExt, g_gamma).flag(MFF_HIDDEN).init = [] { // Test *g_gamma = 1.0f; }; REG_FUNC(cellSysutilAvconfExt, cellAudioOutUnregisterDevice); REG_FUNC(cellSysutilAvconfExt, cellAudioOutGetDeviceInfo2); REG_FUNC(cellSysutilAvconfExt, cellVideoOutSetXVColor); REG_FUNC(cellSysutilAvconfExt, cellVideoOutSetupDisplay); REG_FUNC(cellSysutilAvconfExt, cellAudioInGetDeviceInfo); REG_FUNC(cellSysutilAvconfExt, cellVideoOutConvertCursorColor); REG_FUNC(cellSysutilAvconfExt, cellVideoOutGetGamma); REG_FUNC(cellSysutilAvconfExt, cellAudioInGetAvailableDeviceInfo); REG_FUNC(cellSysutilAvconfExt, cellAudioOutGetAvailableDeviceInfo); REG_FUNC(cellSysutilAvconfExt, cellVideoOutSetGamma);
s32 cellSync2QueueGetSize() { UNIMPLEMENTED_FUNC(cellSync2); return CELL_OK; } s32 cellSync2QueueGetDepth() { UNIMPLEMENTED_FUNC(cellSync2); return CELL_OK; } DECLARE(ppu_module_manager::cellSync2)("cellSync2", []() { REG_VAR(cellSync2, gCellSync2CallerThreadTypePpuThread); REG_VAR(cellSync2, gCellSync2NotifierPpuThread); REG_VAR(cellSync2, gCellSync2CallerThreadTypePpuFiber); REG_VAR(cellSync2, gCellSync2NotifierPpuFiber); REG_VAR(cellSync2, gCellSync2NotifierSpursTask); REG_VAR(cellSync2, gCellSync2NotifierSpursJobQueueJob); REG_FUNC(cellSync2, _cellSync2MutexAttributeInitialize); REG_FUNC(cellSync2, cellSync2MutexEstimateBufferSize); REG_FUNC(cellSync2, cellSync2MutexInitialize); REG_FUNC(cellSync2, cellSync2MutexFinalize); REG_FUNC(cellSync2, cellSync2MutexLock); REG_FUNC(cellSync2, cellSync2MutexTryLock); REG_FUNC(cellSync2, cellSync2MutexUnlock); REG_FUNC(cellSync2, _cellSync2CondAttributeInitialize);