int cellPngDecOpen(u32 mainHandle, mem32_t subHandle, mem_ptr_t<CellPngDecSrc> src, u32 openInfo) { cellPngDec.Warning("cellPngDecOpen(mainHandle=0x%x, subHandle=0x%x, src_addr=0x%x, openInfo=0x%x)", mainHandle, subHandle.GetAddr(), src.GetAddr(), openInfo); if (!subHandle.IsGood() || !src.IsGood()) return CELL_PNGDEC_ERROR_ARG; CellPngDecSubHandle *current_subHandle = new CellPngDecSubHandle; current_subHandle->fd = NULL; current_subHandle->src = *src; switch(src->srcSelect.ToBE()) { case const_se_t<u32, CELL_PNGDEC_BUFFER>::value: current_subHandle->fileSize = src->streamSize.ToLE(); break; case const_se_t<u32, CELL_PNGDEC_FILE>::value: // Get file descriptor MemoryAllocator<be_t<u32>> fd; int ret = cellFsOpen(src->fileName_addr, 0, fd.GetAddr(), NULL, 0); current_subHandle->fd = fd->ToLE(); if(ret != CELL_OK) return CELL_PNGDEC_ERROR_OPEN_FILE; // Get size of file MemoryAllocator<CellFsStat> sb; // Alloc a CellFsStat struct ret = cellFsFstat(current_subHandle->fd, sb.GetAddr()); if(ret != CELL_OK) return ret; current_subHandle->fileSize = sb->st_size; // Get CellFsStat.st_size break; } // From now, every u32 subHandle argument is a pointer to a CellPngDecSubHandle struct. subHandle = cellPngDec.GetNewId(current_subHandle); return CELL_OK; }
// Utility Functions int cellAudioCreateNotifyEventQueue(mem32_t id, mem64_t key) { cellAudio.Warning("cellAudioCreateNotifyEventQueue(id_addr=0x%x, key_addr=0x%x)", id.GetAddr(), key.GetAddr()); if (Emu.GetEventManager().CheckKey(0x80004d494f323221)) { return CELL_AUDIO_ERROR_EVENT_QUEUE; } EventQueue* eq = new EventQueue(SYS_SYNC_FIFO, SYS_PPU_QUEUE, 0x80004d494f323221, 0x80004d494f323221, 32); if (!Emu.GetEventManager().RegisterKey(eq, 0x80004d494f323221)) { delete eq; return CELL_AUDIO_ERROR_EVENT_QUEUE; } id = cellAudio.GetNewId(eq); key = 0x80004d494f323221; return CELL_OK; }
int cellJpgDecOpen(u32 mainHandle, mem32_t subHandle, mem_ptr_t<CellJpgDecSrc> src, mem_ptr_t<CellJpgDecOpnInfo> openInfo) { cellJpgDec.Warning("cellJpgDecOpen(mainHandle=0x%x, subHandle=0x%x, src_addr=0x%x, openInfo=0x%x)", mainHandle, subHandle.GetAddr(), src.GetAddr(), openInfo); CellJpgDecSubHandle *current_subHandle = new CellJpgDecSubHandle; // Get file descriptor MemoryAllocator<be_t<u32>> fd; int ret = cellFsOpen(src->fileName, 0, fd, NULL, 0); current_subHandle->fd = fd->ToLE(); if(ret != CELL_OK) return CELL_JPGDEC_ERROR_OPEN_FILE; // Get size of file MemoryAllocator<CellFsStat> sb; // Alloc a CellFsStat struct ret = cellFsFstat(current_subHandle->fd, sb.GetAddr()); if(ret != CELL_OK) return ret; current_subHandle->fileSize = sb->st_size; // Get CellFsStat.st_size // From now, every u32 subHandle argument is a pointer to a CellPngDecSubHandle struct. subHandle = cellJpgDec.GetNewId(current_subHandle); return CELL_OK; }
u32 adecOpen(AudioDecoder* data) { AudioDecoder& adec = *data; adec.adecCb = &Emu.GetCPU().AddThread(CPU_THREAD_PPU); u32 adec_id = cellAdec.GetNewId(data); adec.id = adec_id; adec.adecCb->SetName("Audio Decoder[" + std::to_string(adec_id) + "] Callback"); thread t("Audio Decoder[" + std::to_string(adec_id) + "] Thread", [&]() { ConLog.Write("Audio Decoder enter()"); AdecTask& task = adec.task; while (true) { if (Emu.IsStopped()) { break; } if (adec.job.IsEmpty() && adec.is_running) { Sleep(1); continue; } /*if (adec.frames.GetCount() >= 50) { Sleep(1); continue; }*/ if (!adec.job.Pop(task)) { break; } switch (task.type) { case adecStartSeq: { // TODO: reset data ConLog.Warning("adecStartSeq:"); adec.reader.addr = 0; adec.reader.size = 0; adec.reader.init = false; if (adec.reader.rem) free(adec.reader.rem); adec.reader.rem = nullptr; adec.reader.rem_size = 0; adec.is_running = true; adec.just_started = true; } break; case adecEndSeq: { // TODO: finalize ConLog.Warning("adecEndSeq:"); /*Callback cb; cb.SetAddr(adec.cbFunc); cb.Handle(adec.id, CELL_ADEC_MSG_TYPE_SEQDONE, CELL_OK, adec.cbArg); cb.Branch(true); // ???*/ adec.adecCb->ExecAsCallback(adec.cbFunc, true, adec.id, CELL_ADEC_MSG_TYPE_SEQDONE, CELL_OK, adec.cbArg); avcodec_close(adec.ctx); avformat_close_input(&adec.fmt); adec.is_running = false; } break; case adecDecodeAu: { int err = 0; adec.reader.addr = task.au.addr; adec.reader.size = task.au.size; //ConLog.Write("Audio AU: size = 0x%x, pts = 0x%llx", task.au.size, task.au.pts); //if (adec.last_pts > task.au.pts || adec.just_started) adec.last_pts = task.au.pts; if (adec.just_started) adec.last_pts = task.au.pts; 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); /*{ wxFile dump; dump.Open(wxString::Format("audio pts-0x%llx.dump", task.au.pts), wxFile::write); u8* buf = (u8*)malloc(task.au.size); if (Memory.CopyToReal(buf, task.au.addr, task.au.size)) dump.Write(buf, task.au.size); free(buf); dump.Close(); }*/ if (adec.just_started) // deferred initialization { err = avformat_open_input(&adec.fmt, NULL, av_find_input_format("oma"), NULL); if (err) { ConLog.Error("adecDecodeAu: avformat_open_input() failed"); Emu.Pause(); break; } AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_ATRAC3P); // ??? if (!codec) { ConLog.Error("adecDecodeAu: avcodec_find_decoder() failed"); Emu.Pause(); break; } /*err = avformat_find_stream_info(adec.fmt, NULL); if (err) { ConLog.Error("adecDecodeAu: avformat_find_stream_info() failed"); Emu.Pause(); break; } if (!adec.fmt->nb_streams) { ConLog.Error("adecDecodeAu: no stream found"); Emu.Pause(); break; }*/ if (!avformat_new_stream(adec.fmt, codec)) { ConLog.Error("adecDecodeAu: avformat_new_stream() failed"); Emu.Pause(); break; } adec.ctx = adec.fmt->streams[0]->codec; // TODO: check data AVDictionary* opts = nullptr; av_dict_set(&opts, "refcounted_frames", "1", 0); { SMutexGeneralLocker lock(g_mutex_avcodec_open2); // not multithread-safe err = avcodec_open2(adec.ctx, codec, &opts); } if (err) { ConLog.Error("adecDecodeAu: avcodec_open2() failed"); Emu.Pause(); break; } adec.just_started = false; } bool last_frame = false; while (true) { if (Emu.IsStopped()) { ConLog.Warning("adecDecodeAu aborted"); return; } /*if (!adec.ctx) // fake { AdecFrame frame; frame.pts = task.au.pts; frame.auAddr = task.au.addr; frame.auSize = task.au.size; frame.userdata = task.au.userdata; frame.size = 4096; frame.data = nullptr; adec.frames.Push(frame); adec.adecCb->ExecAsCallback(adec.cbFunc, false, adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg); break; }*/ last_frame = av_read_frame(adec.fmt, &au) < 0; if (last_frame) { //break; av_free(au.data); au.data = NULL; au.size = 0; } struct AdecFrameHolder : AdecFrame { AdecFrameHolder() { data = av_frame_alloc(); } ~AdecFrameHolder() { if (data) { av_frame_unref(data); av_frame_free(&data); } } } frame; if (!frame.data) { ConLog.Error("adecDecodeAu: av_frame_alloc() failed"); Emu.Pause(); break; } int got_frame = 0; int decode = avcodec_decode_audio4(adec.ctx, frame.data, &got_frame, &au); if (decode <= 0) { if (!last_frame && decode < 0) { ConLog.Error("adecDecodeAu: AU decoding error(0x%x)", decode); } if (!got_frame && adec.reader.size == 0) break; } if (got_frame) { frame.pts = adec.last_pts; adec.last_pts += ((u64)frame.data->nb_samples) * 90000 / 48000; // ??? frame.auAddr = task.au.addr; frame.auSize = task.au.size; frame.userdata = task.au.userdata; frame.size = frame.data->nb_samples * frame.data->channels * sizeof(float); if (frame.data->format != AV_SAMPLE_FMT_FLTP) { ConLog.Error("adecDecodeaAu: unsupported frame format(%d)", frame.data->format); Emu.Pause(); break; } if (frame.data->channels != 2) { ConLog.Error("adecDecodeAu: unsupported channel count (%d)", frame.data->channels); Emu.Pause(); break; } //ConLog.Write("got audio frame (pts=0x%llx, nb_samples=%d, ch=%d, sample_rate=%d, nbps=%d)", //frame.pts, frame.data->nb_samples, frame.data->channels, frame.data->sample_rate, //av_get_bytes_per_sample((AVSampleFormat)frame.data->format)); adec.frames.Push(frame); frame.data = nullptr; // to prevent destruction /*Callback cb; cb.SetAddr(adec.cbFunc); cb.Handle(adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg); cb.Branch(false);*/ adec.adecCb->ExecAsCallback(adec.cbFunc, false, adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg); } } /*Callback cb; cb.SetAddr(adec.cbFunc); cb.Handle(adec.id, CELL_ADEC_MSG_TYPE_AUDONE, task.au.auInfo_addr, adec.cbArg); cb.Branch(false);*/ adec.adecCb->ExecAsCallback(adec.cbFunc, false, adec.id, CELL_ADEC_MSG_TYPE_AUDONE, task.au.auInfo_addr, adec.cbArg); } break; case adecClose: { adec.is_finished = true; ConLog.Write("Audio Decoder exit"); return; } default: ConLog.Error("Audio Decoder error: unknown task(%d)", task.type); } } adec.is_finished = true; ConLog.Warning("Audio Decoder aborted"); }); t.detach(); return adec_id; }
int cellFsOpen(u32 path_addr, int flags, mem32_t fd, mem32_t arg, u64 size) { const wxString& path = Memory.ReadString(path_addr); sys_fs.Log("cellFsOpen(path=\"%s\", flags=0x%x, fd_addr=0x%x, arg_addr=0x%x, size=0x%llx)", path.wx_str(), flags, fd.GetAddr(), arg.GetAddr(), size); const wxString& ppath = path; //ConLog.Warning("path: %s [%s]", ppath.wx_str(), path.wx_str()); s32 _oflags = flags; if(flags & CELL_O_CREAT) { _oflags &= ~CELL_O_CREAT; Emu.GetVFS().CreateFile(ppath); } vfsOpenMode o_mode; switch(flags & CELL_O_ACCMODE) { case CELL_O_RDONLY: _oflags &= ~CELL_O_RDONLY; o_mode = vfsRead; break; case CELL_O_WRONLY: _oflags &= ~CELL_O_WRONLY; if(flags & CELL_O_APPEND) { _oflags &= ~CELL_O_APPEND; o_mode = vfsWriteAppend; } else if(flags & CELL_O_EXCL) { _oflags &= ~CELL_O_EXCL; o_mode = vfsWriteExcl; } else //if (flags & CELL_O_TRUNC) { _oflags &= ~CELL_O_TRUNC; o_mode = vfsWrite; } break; case CELL_O_RDWR: _oflags &= ~CELL_O_RDWR; if (flags & CELL_O_TRUNC) { _oflags &= ~CELL_O_TRUNC; //truncate file before opening it as read/write Emu.GetVFS().OpenFile(ppath, vfsWrite); } o_mode = vfsReadWrite; break; } if(_oflags != 0) { sys_fs.Error("\"%s\" has unknown flags! flags: 0x%08x", ppath.wx_str(), flags); return CELL_EINVAL; } vfsFileBase* stream = Emu.GetVFS().OpenFile(ppath, o_mode); if(!stream || !stream->IsOpened()) { sys_fs.Error("\"%s\" not found! flags: 0x%08x", ppath.wx_str(), flags); return CELL_ENOENT; } fd = sys_fs.GetNewId(stream, IDFlag_File); ConLog.Warning("*** cellFsOpen(path=\"%s\"): fd = %d", path.wx_str(), fd.GetValue()); return CELL_OK; }
u32 vdecOpen(VideoDecoder* data) { VideoDecoder& vdec = *data; vdec.vdecCb = &Emu.GetCPU().AddThread(CPU_THREAD_PPU); u32 vdec_id = cellVdec.GetNewId(data); vdec.id = vdec_id; vdec.vdecCb->SetName("Video Decoder[" + std::to_string(vdec_id) + "] Callback"); thread t("Video Decoder[" + std::to_string(vdec_id) + "] Thread", [&]() { ConLog.Write("Video Decoder enter()"); VdecTask& task = vdec.task; while (true) { if (Emu.IsStopped()) { break; } if (vdec.job.IsEmpty() && vdec.is_running) { Sleep(1); continue; } if (vdec.frames.GetSize() >= 50) { Sleep(1); continue; } if (!vdec.job.Pop(task)) { break; } switch (task.type) { case vdecStartSeq: { // TODO: reset data ConLog.Warning("vdecStartSeq:"); vdec.reader.addr = 0; vdec.reader.size = 0; vdec.is_running = true; vdec.just_started = true; } break; case vdecEndSeq: { // TODO: finalize ConLog.Warning("vdecEndSeq:"); vdec.vdecCb->ExecAsCallback(vdec.cbFunc, false, vdec.id, CELL_VDEC_MSG_TYPE_SEQDONE, CELL_OK, vdec.cbArg); /*Callback cb; cb.SetAddr(vdec.cbFunc); cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_SEQDONE, CELL_OK, vdec.cbArg); cb.Branch(true); // ???*/ avcodec_close(vdec.ctx); avformat_close_input(&vdec.fmt); vdec.is_running = false; } break; case vdecDecodeAu: { int err; if (task.mode != CELL_VDEC_DEC_MODE_NORMAL) { ConLog.Error("vdecDecodeAu: unsupported decoding mode(%d)", task.mode); break; } vdec.reader.addr = task.addr; vdec.reader.size = task.size; //ConLog.Write("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 = task.pts; 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) // deferred initialization { err = avformat_open_input(&vdec.fmt, NULL, av_find_input_format("mpeg"), NULL); if (err) { ConLog.Error("vdecDecodeAu: avformat_open_input() failed"); Emu.Pause(); break; } AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_H264); // ??? if (!codec) { ConLog.Error("vdecDecodeAu: avcodec_find_decoder() failed"); Emu.Pause(); break; } /*err = avformat_find_stream_info(vdec.fmt, NULL); if (err) { ConLog.Error("vdecDecodeAu: avformat_find_stream_info() failed"); Emu.Pause(); break; } if (!vdec.fmt->nb_streams) { ConLog.Error("vdecDecodeAu: no stream found"); Emu.Pause(); break; }*/ if (!avformat_new_stream(vdec.fmt, codec)) { ConLog.Error("vdecDecodeAu: avformat_new_stream() failed"); Emu.Pause(); break; } vdec.ctx = vdec.fmt->streams[0]->codec; // TODO: check data AVDictionary* opts = nullptr; av_dict_set(&opts, "refcounted_frames", "1", 0); { SMutexGeneralLocker lock(g_mutex_avcodec_open2); // not multithread-safe err = avcodec_open2(vdec.ctx, codec, &opts); } if (err) { ConLog.Error("vdecDecodeAu: avcodec_open2() failed"); Emu.Pause(); break; } //vdec.ctx->flags |= CODEC_FLAG_TRUNCATED; //vdec.ctx->flags2 |= CODEC_FLAG2_CHUNKS; vdec.just_started = false; } bool last_frame = false; while (true) { if (Emu.IsStopped()) { ConLog.Warning("vdecDecodeAu aborted"); return; } last_frame = av_read_frame(vdec.fmt, &au) < 0; if (last_frame) { //break; av_free(au.data); au.data = NULL; au.size = 0; } struct VdecFrameHolder : VdecFrame { VdecFrameHolder() { data = av_frame_alloc(); } ~VdecFrameHolder() { if (data) { av_frame_unref(data); av_frame_free(&data); } } } frame; if (!frame.data) { ConLog.Error("vdecDecodeAu: av_frame_alloc() failed"); Emu.Pause(); break; } int got_picture = 0; int decode = avcodec_decode_video2(vdec.ctx, frame.data, &got_picture, &au); if (decode <= 0) { if (!last_frame && decode < 0) { ConLog.Error("vdecDecodeAu: AU decoding error(0x%x)", decode); } if (!got_picture && vdec.reader.size == 0) break; // video end? } if (got_picture) { u64 ts = av_frame_get_best_effort_timestamp(frame.data); if (ts != AV_NOPTS_VALUE) { frame.pts = ts/* - vdec.first_pts*/; // ??? vdec.last_pts = frame.pts; } else { vdec.last_pts += vdec.ctx->time_base.num * 90000 / (vdec.ctx->time_base.den / vdec.ctx->ticks_per_frame); frame.pts = vdec.last_pts; } //frame.pts = vdec.last_pts; //vdec.last_pts += 3754; frame.dts = (frame.pts - vdec.first_pts) + vdec.first_dts; frame.userdata = task.userData; //ConLog.Write("got picture (pts=0x%llx, dts=0x%llx)", frame.pts, frame.dts); vdec.frames.Push(frame); // !!!!!!!! frame.data = nullptr; // to prevent destruction vdec.vdecCb->ExecAsCallback(vdec.cbFunc, false, vdec.id, CELL_VDEC_MSG_TYPE_PICOUT, CELL_OK, vdec.cbArg); /*Callback cb; cb.SetAddr(vdec.cbFunc); cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_PICOUT, CELL_OK, vdec.cbArg); cb.Branch(false);*/ } } vdec.vdecCb->ExecAsCallback(vdec.cbFunc, false, vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, vdec.cbArg); /*Callback cb; cb.SetAddr(vdec.cbFunc); cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, vdec.cbArg); cb.Branch(false);*/ } break; case vdecClose: { vdec.is_finished = true; ConLog.Write("Video Decoder exit"); return; } case vdecSetFrameRate: { ConLog.Error("TODO: vdecSetFrameRate(%d)", task.frc); } break; default: ConLog.Error("Video Decoder error: unknown task(%d)", task.type); } } vdec.is_finished = true; ConLog.Warning("Video Decoder aborted"); }); t.detach(); return vdec_id; }