From cb694f944c7281258fdffc9535d9457133c06a6a Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Tue, 9 Dec 2014 19:13:03 +0300 Subject: [PATCH] Added DivX and MP3 support --- rpcs3/Emu/SysCalls/Modules/cellAdec.cpp | 185 ++++++++----- rpcs3/Emu/SysCalls/Modules/cellAdec.h | 2 + rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp | 5 + rpcs3/Emu/SysCalls/Modules/cellVdec.cpp | 335 ++++++++++++++++------- rpcs3/Emu/SysCalls/Modules/cellVdec.h | 4 + 5 files changed, 375 insertions(+), 156 deletions(-) diff --git a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp index 9ae92e6dc6..4c22615d2e 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp @@ -31,23 +31,52 @@ AudioDecoder::AudioDecoder(AudioCodecType type, u32 addr, u32 size, vm::ptrError("AudioDecoder(): unknown type (0x%x)", type); + Emu.Pause(); + return; + } + } + if (!codec) { - cellAdec->Error("AudioDecoder(): avcodec_find_decoder(ATRAC3P) failed"); + cellAdec->Error("AudioDecoder(): avcodec_find_decoder() failed"); + Emu.Pause(); + return; + } + if (!input_format) + { + cellAdec->Error("AudioDecoder(): av_find_input_format() failed"); Emu.Pause(); return; } fmt = avformat_alloc_context(); if (!fmt) { - cellAdec->Error("AudioDecoder(): avformat_alloc_context failed"); + cellAdec->Error("AudioDecoder(): avformat_alloc_context() failed"); Emu.Pause(); return; } @@ -55,7 +84,7 @@ AudioDecoder::AudioDecoder(AudioCodecType type, u32 addr, u32 size, vm::ptrpb = avio_alloc_context(io_buf, 256, 0, this, adecRead, NULL, NULL); if (!fmt->pb) { - cellAdec->Error("AudioDecoder(): avio_alloc_context failed"); + cellAdec->Error("AudioDecoder(): avio_alloc_context() failed"); Emu.Pause(); return; } @@ -93,7 +122,7 @@ int adecRead(void* opaque, u8* buf, int buf_size) int res = 0; next: - if (adec.reader.has_ats) + if (adec.type == CELL_ADEC_TYPE_ATRACX_2CH && adec.reader.has_ats) { u8 code1 = vm::read8(adec.reader.addr + 2); u8 code2 = vm::read8(adec.reader.addr + 3); @@ -106,7 +135,7 @@ next: adec.reader.has_ats = false; } - if (!adec.reader.init) + if (adec.type == CELL_ADEC_TYPE_ATRACX_2CH && !adec.reader.init) { OMAHeader oma(1 /* atrac3p id */, adec.sample_rate, adec.channels, adec.frame_size); if (buf_size < sizeof(oma)) @@ -244,12 +273,15 @@ u32 adecOpen(AudioDecoder* data) adec.reader.has_ats = false; adec.just_started = true; - adec.channels = task.at3p.channels; - adec.frame_size = task.at3p.frame_size; - adec.sample_rate = task.at3p.sample_rate; - adec.use_ats_headers = task.at3p.ats_header == 1; + if (adec.type == CELL_ADEC_TYPE_ATRACX_2CH) + { + adec.channels = task.at3p.channels; + adec.frame_size = task.at3p.frame_size; + adec.sample_rate = task.at3p.sample_rate; + adec.use_ats_headers = task.at3p.ats_header == 1; + } + break; } - break; case adecEndSeq: { @@ -258,8 +290,8 @@ u32 adecOpen(AudioDecoder* data) adec.cbFunc.call(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_SEQDONE, CELL_OK, adec.cbArg); adec.just_finished = true; + break; } - break; case adecDecodeAu: { @@ -273,7 +305,8 @@ u32 adecOpen(AudioDecoder* data) if (adec.just_started) { adec.first_pts = task.au.pts; - adec.last_pts = task.au.pts - 0x10000; // hack? + adec.last_pts = task.au.pts; + if (adec.type == CELL_ADEC_TYPE_ATRACX_2CH) adec.last_pts -= 0x10000; // hack } struct AVPacketHolder : AVPacket @@ -313,21 +346,13 @@ u32 adecOpen(AudioDecoder* data) { AVDictionary* opts = nullptr; av_dict_set(&opts, "probesize", "96", 0); - err = avformat_open_input(&adec.fmt, NULL, av_find_input_format("oma"), &opts); + err = avformat_open_input(&adec.fmt, NULL, adec.input_format, &opts); if (err || opts) { cellAdec->Error("adecDecodeAu: avformat_open_input() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0); Emu.Pause(); break; } - - AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_ATRAC3P); // ??? - if (!codec) - { - cellAdec->Error("adecDecodeAu: avcodec_find_decoder() failed"); - Emu.Pause(); - break; - } //err = avformat_find_stream_info(adec.fmt, NULL); //if (err) //{ @@ -341,7 +366,7 @@ u32 adecOpen(AudioDecoder* data) // Emu.Pause(); // break; //} - if (!avformat_new_stream(adec.fmt, codec)) + if (!avformat_new_stream(adec.fmt, adec.codec)) { cellAdec->Error("adecDecodeAu: avformat_new_stream() failed"); Emu.Pause(); @@ -354,7 +379,7 @@ u32 adecOpen(AudioDecoder* data) { std::lock_guard lock(g_mutex_avcodec_open2); // not multithread-safe (???) - err = avcodec_open2(adec.ctx, codec, &opts); + err = avcodec_open2(adec.ctx, adec.codec, &opts); } if (err || opts) { @@ -424,34 +449,34 @@ u32 adecOpen(AudioDecoder* data) if (got_frame) { - u64 ts = av_frame_get_best_effort_timestamp(frame.data); - if (ts != AV_NOPTS_VALUE) - { - frame.pts = ts/* - adec.first_pts*/; - adec.last_pts = frame.pts; - } - else - { - adec.last_pts += ((u64)frame.data->nb_samples) * 90000 / frame.data->sample_rate; - frame.pts = adec.last_pts; - } - //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); + //u64 ts = av_frame_get_best_effort_timestamp(frame.data); + //if (ts != AV_NOPTS_VALUE) + //{ + // frame.pts = ts/* - adec.first_pts*/; + // adec.last_pts = frame.pts; + //} + adec.last_pts += ((u64)frame.data->nb_samples) * 90000 / frame.data->sample_rate; + frame.pts = adec.last_pts; - if (frame.data->format != AV_SAMPLE_FMT_FLTP) + s32 nbps = av_get_bytes_per_sample((AVSampleFormat)frame.data->format); + switch (frame.data->format) { - cellAdec->Error("adecDecodeaAu: unsupported frame format(%d)", frame.data->format); + case AV_SAMPLE_FMT_FLTP: break; + case AV_SAMPLE_FMT_S16P: break; + default: + { + cellAdec->Error("adecDecodeAu: unsupported frame format(%d)", frame.data->format); Emu.Pause(); break; } + } + frame.auAddr = task.au.addr; + frame.auSize = task.au.size; + frame.userdata = task.au.userdata; + frame.size = frame.data->nb_samples * frame.data->channels * nbps; //LOG_NOTICE(HLE, "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)); + //frame.pts, frame.data->nb_samples, frame.data->channels, frame.data->sample_rate, nbps); if (adec.frames.Push(frame, &adec.is_closed)) { @@ -462,8 +487,8 @@ u32 adecOpen(AudioDecoder* data) } adec.cbFunc.call(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_AUDONE, task.au.auInfo_addr, adec.cbArg); + break; } - break; case adecClose: break; @@ -492,12 +517,12 @@ bool adecCheckType(AudioCodecType type) { case CELL_ADEC_TYPE_ATRACX: cellAdec->Notice("adecCheckType: ATRAC3plus"); break; case CELL_ADEC_TYPE_ATRACX_2CH: cellAdec->Notice("adecCheckType: ATRAC3plus 2ch"); break; + case CELL_ADEC_TYPE_MP3: cellAdec->Notice("adecCheckType: MP3"); break; case CELL_ADEC_TYPE_ATRACX_6CH: case CELL_ADEC_TYPE_ATRACX_8CH: case CELL_ADEC_TYPE_LPCM_PAMF: case CELL_ADEC_TYPE_AC3: - case CELL_ADEC_TYPE_MP3: case CELL_ADEC_TYPE_ATRAC3: case CELL_ADEC_TYPE_MPEG_L2: case CELL_ADEC_TYPE_CELP: @@ -608,6 +633,13 @@ int cellAdecStartSeq(u32 handle, u32 param_addr) task.at3p.sample_rate, task.at3p.channel_config, task.at3p.channels, task.at3p.frame_size, (u32&)task.at3p.extra_config, task.at3p.output, task.at3p.downmix, task.at3p.ats_header); break; } + case CELL_ADEC_TYPE_MP3: + { + auto param = vm::ptr::make(param_addr); + + cellAdec->Todo("*** CellAdecParamMP3: bw_pcm=%d", param->bw_pcm.ToLE()); + break; + } default: { cellAdec->Todo("cellAdecStartSeq(): Unimplemented audio codec type(%d)", adec->type); @@ -678,7 +710,7 @@ int cellAdecGetPcm(u32 handle, vm::ptr outBuffer) if (outBuffer) { // reverse byte order: - if (frame->channels == 1) + if (frame->format == AV_SAMPLE_FMT_FLTP && frame->channels == 1) { float* in_f = (float*)frame->extended_data[0]; for (u32 i = 0; i < af.size / 4; i++) @@ -686,7 +718,7 @@ int cellAdecGetPcm(u32 handle, vm::ptr outBuffer) outBuffer[i] = in_f[i]; } } - else if (frame->channels == 2) + else if (frame->format == AV_SAMPLE_FMT_FLTP && frame->channels == 2) { float* in_f[2]; in_f[0] = (float*)frame->extended_data[0]; @@ -697,9 +729,28 @@ int cellAdecGetPcm(u32 handle, vm::ptr outBuffer) outBuffer[i * 2 + 1] = in_f[1][i]; } } + else if (frame->format = AV_SAMPLE_FMT_S16P && frame->channels == 1) + { + s16* in_i = (s16*)frame->extended_data[0]; + for (u32 i = 0; i < af.size / 2; i++) + { + outBuffer[i] = (float)in_i[i] / 0x8000; + } + } + else if (frame->format = AV_SAMPLE_FMT_S16P && frame->channels == 2) + { + s16* in_i[2]; + in_i[0] = (s16*)frame->extended_data[0]; + in_i[1] = (s16*)frame->extended_data[1]; + for (u32 i = 0; i < af.size / 4; i++) + { + outBuffer[i * 2 + 0] = (float)in_i[0][i] / 0x8000; + outBuffer[i * 2 + 1] = (float)in_i[1][i] / 0x8000; + } + } else { - cellAdec->Error("cellAdecGetPcm(): unsupported channel count (%d)", frame->channels); + cellAdec->Error("cellAdecGetPcm(): unsupported frame format (channels=%d, format=%d)", frame->channels, frame->format); Emu.Pause(); } } @@ -747,21 +798,31 @@ int cellAdecGetPcmItem(u32 handle, vm::ptr pcmItem_ptr) pcm->auInfo.startAddr = af.auAddr; pcm->auInfo.userData = af.userdata; - auto atx = vm::ptr::make(pcm.addr() + sizeof(CellAdecPcmItem)); - atx->samplingFreq = frame->sample_rate; - atx->nbytes = frame->nb_samples * sizeof(float); - if (frame->channels == 1) + if (adec->type == CELL_ADEC_TYPE_ATRACX_2CH) { - atx->channelConfigIndex = 1; + auto atx = vm::ptr::make(pcm.addr() + sizeof(CellAdecPcmItem)); + + atx->samplingFreq = frame->sample_rate; + atx->nbytes = frame->nb_samples * sizeof(float); + if (frame->channels == 1) + { + atx->channelConfigIndex = 1; + } + else if (frame->channels == 2) + { + atx->channelConfigIndex = 2; + } + else + { + cellAdec->Error("cellAdecGetPcmItem(): unsupported channel count (%d)", frame->channels); + Emu.Pause(); + } } - else if (frame->channels == 2) + else if (adec->type == CELL_ADEC_TYPE_MP3) { - atx->channelConfigIndex = 2; - } - else - { - cellAdec->Error("cellAdecGetPcmItem(): unsupported channel count (%d)", frame->channels); - Emu.Pause(); + auto mp3 = vm::ptr::make(pcm.addr() + sizeof(CellAdecPcmItem)); + + memset(mp3.get_ptr(), 0, sizeof(CellAdecMP3Info)); } *pcmItem_ptr = pcm.addr(); diff --git a/rpcs3/Emu/SysCalls/Modules/cellAdec.h b/rpcs3/Emu/SysCalls/Modules/cellAdec.h index 414d986dee..9b8528d74b 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAdec.h +++ b/rpcs3/Emu/SysCalls/Modules/cellAdec.h @@ -1100,6 +1100,8 @@ public: bool just_started; bool just_finished; + AVCodec* codec; + AVInputFormat* input_format; AVCodecContext* ctx; AVFormatContext* fmt; u8* io_buf; diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp index 4248c35d74..d4735492da 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp @@ -568,6 +568,8 @@ s64 spursInit( } else while (true) { + if (Emu.IsStopped()) break; + spurs->m.xD64.exchange(0); if (spurs->m.exception.ToBE() == 0) { @@ -629,6 +631,9 @@ s64 spursInit( return; } } + + if (Emu.IsStopped()) continue; + if (s32 res = sys_lwmutex_unlock(spurs->get_lwmutex())) { assert(!"sys_lwmutex_unlock() failed"); diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp index 12b28591c8..5db5ca92b9 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp @@ -31,23 +31,59 @@ VideoDecoder::VideoDecoder(CellVdecCodecType type, u32 profile, u32 addr, u32 si , is_closed(false) , just_started(false) , just_finished(false) + , frc_set(0) + , codec(nullptr) + , input_format(nullptr) , ctx(nullptr) , vdecCb(nullptr) { av_register_all(); avcodec_register_all(); - AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_H264); + switch (type) + { + case CELL_VDEC_CODEC_TYPE_MPEG2: + { + codec = avcodec_find_decoder(AV_CODEC_ID_MPEG2VIDEO); + input_format = av_find_input_format("mpeg"); + break; + } + case CELL_VDEC_CODEC_TYPE_AVC: + { + codec = avcodec_find_decoder(AV_CODEC_ID_H264); + input_format = av_find_input_format("mpeg"); + break; + } + case CELL_VDEC_CODEC_TYPE_DIVX: + { + codec = avcodec_find_decoder(AV_CODEC_ID_MPEG4); + input_format = av_find_input_format("mpeg"); + break; + } + default: + { + cellVdec->Error("VideoDecoder(): unknown type (0x%x)", type); + Emu.Pause(); + return; + } + } + if (!codec) { - cellVdec->Error("VideoDecoder(): avcodec_find_decoder(H264) failed"); + cellVdec->Error("VideoDecoder(): avcodec_find_decoder() failed"); + Emu.Pause(); + return; + } + if (!input_format) + { + cellVdec->Error("VideoDecoder(): av_find_input_format() failed"); Emu.Pause(); return; } fmt = avformat_alloc_context(); if (!fmt) { - cellVdec->Error("VideoDecoder(): avformat_alloc_context failed"); + cellVdec->Error("VideoDecoder(): avformat_alloc_context() failed"); Emu.Pause(); return; } @@ -55,7 +91,7 @@ VideoDecoder::VideoDecoder(CellVdecCodecType type, u32 profile, u32 addr, u32 si fmt->pb = avio_alloc_context(io_buf, 4096, 0, this, vdecRead, NULL, NULL); if (!fmt->pb) { - cellVdec->Error("VideoDecoder(): avio_alloc_context failed"); + cellVdec->Error("VideoDecoder(): avio_alloc_context() failed"); Emu.Pause(); return; } @@ -163,8 +199,8 @@ u32 vdecQueryAttr(CellVdecCodecType type, u32 profile, u32 spec_addr /* may be 0 switch (type) // TODO: check profile levels { case CELL_VDEC_CODEC_TYPE_AVC: cellVdec->Warning("cellVdecQueryAttr: AVC (profile=%d)", profile); break; - case CELL_VDEC_CODEC_TYPE_MPEG2: cellVdec->Todo("MPEG2 not supported"); break; - case CELL_VDEC_CODEC_TYPE_DIVX: cellVdec->Todo("DIVX not supported"); 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; default: return CELL_VDEC_ERROR_ARG; } @@ -225,9 +261,10 @@ u32 vdecOpen(VideoDecoder* data) cellVdec->Warning("vdecStartSeq:"); vdec.reader = {}; + vdec.frc_set = 0; vdec.just_started = true; + break; } - break; case vdecEndSeq: { @@ -237,8 +274,8 @@ u32 vdecOpen(VideoDecoder* data) vdec.cbFunc.call(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_SEQDONE, CELL_OK, vdec.cbArg); vdec.just_finished = true; + break; } - break; case vdecDecodeAu: { @@ -257,7 +294,7 @@ u32 vdecOpen(VideoDecoder* data) if (vdec.just_started) { vdec.first_pts = task.pts; - vdec.last_pts = task.pts; + vdec.last_pts = -1; vdec.first_dts = task.dts; } @@ -296,38 +333,31 @@ u32 vdecOpen(VideoDecoder* data) } else if (vdec.just_started) // deferred initialization { - err = avformat_open_input(&vdec.fmt, NULL, av_find_input_format("mpeg"), NULL); + err = avformat_open_input(&vdec.fmt, NULL, NULL, NULL); if (err) { cellVdec->Error("vdecDecodeAu: avformat_open_input() failed"); Emu.Pause(); break; } - AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_H264); // ??? - if (!codec) + if (vdec.type == CELL_VDEC_CODEC_TYPE_DIVX) { - cellVdec->Error("vdecDecodeAu: avcodec_find_decoder() failed"); - Emu.Pause(); - break; + err = avformat_find_stream_info(vdec.fmt, NULL); + if (err || !vdec.fmt->nb_streams) + { + cellVdec->Error("vdecDecodeAu: avformat_find_stream_info() failed (err=0x%x)", err); + Emu.Pause(); + break; + } } - /*err = avformat_find_stream_info(vdec.fmt, NULL); - if (err) + else { - LOG_ERROR(HLE, "vdecDecodeAu: avformat_find_stream_info() failed"); - Emu.Pause(); - break; - } - if (!vdec.fmt->nb_streams) - { - LOG_ERROR(HLE, "vdecDecodeAu: no stream found"); - Emu.Pause(); - break; - }*/ - if (!avformat_new_stream(vdec.fmt, codec)) - { - cellVdec->Error("vdecDecodeAu: avformat_new_stream() failed"); - Emu.Pause(); - break; + if (!avformat_new_stream(vdec.fmt, vdec.codec)) + { + cellVdec->Error("vdecDecodeAu: avformat_new_stream() failed"); + Emu.Pause(); + break; + } } vdec.ctx = vdec.fmt->streams[0]->codec; // TODO: check data @@ -336,7 +366,7 @@ u32 vdecOpen(VideoDecoder* data) { std::lock_guard lock(g_mutex_avcodec_open2); // not multithread-safe (???) - err = avcodec_open2(vdec.ctx, codec, &opts); + err = avcodec_open2(vdec.ctx, vdec.codec, &opts); } if (err) { @@ -344,6 +374,7 @@ u32 vdecOpen(VideoDecoder* data) Emu.Pause(); break; } + vdec.just_started = false; } @@ -406,19 +437,99 @@ u32 vdecOpen(VideoDecoder* data) if (got_picture) { - u64 ts = av_frame_get_best_effort_timestamp(frame.data); - if (ts != AV_NOPTS_VALUE) + if (frame.data->interlaced_frame) { - frame.pts = ts/* - vdec.first_pts*/; // ??? - vdec.last_pts = frame.pts; + cellVdec->Error("vdecDecodeAu: interlaced frames not supported (0x%x)", frame.data->interlaced_frame); + Emu.Pause(); + } + + if (frame.data->repeat_pict) + { + cellVdec->Error("vdecDecodeAu: repeated frames not supported (0x%x)", frame.data->repeat_pict); + Emu.Pause(); + } + + if (vdec.frc_set) + { + if (vdec.last_pts == -1) + { + vdec.last_pts = 0x8000; //av_frame_get_best_effort_timestamp(frame.data); + } + 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: + { + cellVdec->Error("vdecDecodeAu: invalid frame rate code set (0x%x)", vdec.frc_set); + Emu.Pause(); + } + } + + frame.frc = vdec.frc_set; } 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; + 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 48 + 0x100000000: frame.frc = CELL_VDEC_FRC_24; break; + case 25: case 50 + 0x100000000: frame.frc = CELL_VDEC_FRC_25; break; + case 30: case 60 + 0x100000000: frame.frc = CELL_VDEC_FRC_30; break; + case 50: case 100 + 0x100000000: frame.frc = CELL_VDEC_FRC_50; break; + case 60: case 120 + 0x100000000: frame.frc = CELL_VDEC_FRC_60; break; + default: + { + cellVdec->Error("vdecDecodeAu: unsupported time_base.den (%d/1, tpf=%d)", vdec.ctx->time_base.den, vdec.ctx->ticks_per_frame); + Emu.Pause(); + } + } + } + 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 + { + cellVdec->Error("vdecDecodeAu: unsupported time_base.den (%d/1001, tpf=%d)", vdec.ctx->time_base.den, vdec.ctx->ticks_per_frame); + Emu.Pause(); + } + } + else + { + cellVdec->Error("vdecDecodeAu: unsupported time_base.num (%d)", vdec.ctx->time_base.num); + Emu.Pause(); + } } - //frame.pts = vdec.last_pts; - //vdec.last_pts += 3754; + + frame.pts = vdec.last_pts; frame.dts = (frame.pts - vdec.first_pts) + vdec.first_dts; frame.userdata = task.userData; @@ -433,15 +544,15 @@ u32 vdecOpen(VideoDecoder* data) } vdec.cbFunc.call(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, vdec.cbArg); + break; } - break; case vdecSetFrameRate: { - cellVdec->Error("TODO: vdecSetFrameRate(%d)", task.frc); - Emu.Pause(); + cellVdec->Error("vdecSetFrameRate(0x%x)", task.frc); + vdec.frc_set = task.frc; + break; } - break; case vdecClose: break; @@ -679,67 +790,103 @@ int cellVdecGetPicItem(u32 handle, vm::ptr picItem_ptr) info->attr = CELL_VDEC_PICITEM_ATTR_NORMAL; info->picInfo_addr = info.addr() + sizeof(CellVdecPicItem); - auto avc = vm::ptr::make(info.addr() + sizeof(CellVdecPicItem)); + if (vdec->type == CELL_VDEC_CODEC_TYPE_AVC) + { + auto avc = vm::ptr::make(info.addr() + sizeof(CellVdecPicItem)); - avc->horizontalSize = frame.width; - avc->verticalSize = frame.height; - switch (frame.pict_type) - { - 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; - default: avc->pictureType[0] = CELL_VDEC_AVC_PCT_UNKNOWN; break; // ??? + avc->horizontalSize = frame.width; + avc->verticalSize = frame.height; + switch (frame.pict_type) + { + 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; + default: cellVdec->Error("cellVdecGetPicItem(AVC): unknown pict_type value (0x%x)", frame.pict_type); + } + 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) + { + 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; + default: cellVdec->Error("cellVdecGetPicItem(AVC): unknown frc value (0x%x)", vf.frc); break; + } + + 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; } - 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; - if (vdec->ctx->time_base.num == 1001) + else if (vdec->type == CELL_VDEC_CODEC_TYPE_DIVX) { - if (vdec->ctx->time_base.den == 48000 && vdec->ctx->ticks_per_frame == 2) + auto dvx = vm::ptr::make(info.addr() + sizeof(CellVdecPicItem)); + + switch (frame.pict_type) { - avc->frameRateCode = CELL_VDEC_AVC_FRC_24000DIV1001; + 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; + default: cellVdec->Error("cellVdecGetPicItem(DivX): unknown pict_type value (0x%x)", frame.pict_type); } - else if (vdec->ctx->time_base.den == 60000 && vdec->ctx->ticks_per_frame == 2) + 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; // ??? + switch (vf.frc) { - avc->frameRateCode = CELL_VDEC_AVC_FRC_30000DIV1001; - } - else - { - cellVdec->Error("cellVdecGetPicItem: unsupported time_base.den (%d)", vdec->ctx->time_base.den); - Emu.Pause(); + 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; + default: cellVdec->Error("cellVdecGetPicItem(DivX): unknown frc value (0x%x)", vf.frc); } } - else + else if (vdec->type == CELL_VDEC_CODEC_TYPE_MPEG2) { - cellVdec->Error("cellVdecGetPicItem: unsupported time_base.num (%d)", vdec->ctx->time_base.num); + auto mp2 = vm::ptr::make(info.addr() + sizeof(CellVdecPicItem)); + + cellVdec->Todo("cellVdecGetPicItem(MPEG2)"); Emu.Pause(); } - 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; - - *picItem_ptr = info.addr(); + *picItem_ptr = info.addr(); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.h b/rpcs3/Emu/SysCalls/Modules/cellVdec.h index 144c0766ad..5ea31ff840 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.h +++ b/rpcs3/Emu/SysCalls/Modules/cellVdec.h @@ -685,6 +685,7 @@ struct VdecFrame u64 dts; u64 pts; u64 userdata; + u32 frc; }; int vdecRead(void* opaque, u8* buf, int buf_size); @@ -699,6 +700,8 @@ public: bool just_started; bool just_finished; + AVCodec* codec; + AVInputFormat* input_format; AVCodecContext* ctx; AVFormatContext* fmt; u8* io_buf; @@ -721,6 +724,7 @@ public: VdecTask task; // current task variable u64 last_pts, first_pts, first_dts; + u32 frc_set; // frame rate overwriting AVRational rfr, afr; PPUThread* vdecCb;