Added DivX and MP3 support

This commit is contained in:
Nekotekina 2014-12-09 19:13:03 +03:00
parent 1ba5b27f45
commit cb694f944c
5 changed files with 375 additions and 156 deletions

View file

@ -31,23 +31,52 @@ AudioDecoder::AudioDecoder(AudioCodecType type, u32 addr, u32 size, vm::ptr<Cell
, is_finished(false) , is_finished(false)
, just_started(false) , just_started(false)
, just_finished(false) , just_finished(false)
, codec(nullptr)
, input_format(nullptr)
, ctx(nullptr) , ctx(nullptr)
, fmt(nullptr) , fmt(nullptr)
{ {
av_register_all(); av_register_all();
avcodec_register_all(); avcodec_register_all();
AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_ATRAC3P); switch (type)
{
case CELL_ADEC_TYPE_ATRACX_2CH:
{
codec = avcodec_find_decoder(AV_CODEC_ID_ATRAC3P);
input_format = av_find_input_format("oma");
break;
}
case CELL_ADEC_TYPE_MP3:
{
codec = avcodec_find_decoder(AV_CODEC_ID_MP3);
input_format = av_find_input_format("mp3");
break;
}
default:
{
cellAdec->Error("AudioDecoder(): unknown type (0x%x)", type);
Emu.Pause();
return;
}
}
if (!codec) 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(); Emu.Pause();
return; return;
} }
fmt = avformat_alloc_context(); fmt = avformat_alloc_context();
if (!fmt) if (!fmt)
{ {
cellAdec->Error("AudioDecoder(): avformat_alloc_context failed"); cellAdec->Error("AudioDecoder(): avformat_alloc_context() failed");
Emu.Pause(); Emu.Pause();
return; return;
} }
@ -55,7 +84,7 @@ AudioDecoder::AudioDecoder(AudioCodecType type, u32 addr, u32 size, vm::ptr<Cell
fmt->pb = avio_alloc_context(io_buf, 256, 0, this, adecRead, NULL, NULL); fmt->pb = avio_alloc_context(io_buf, 256, 0, this, adecRead, NULL, NULL);
if (!fmt->pb) if (!fmt->pb)
{ {
cellAdec->Error("AudioDecoder(): avio_alloc_context failed"); cellAdec->Error("AudioDecoder(): avio_alloc_context() failed");
Emu.Pause(); Emu.Pause();
return; return;
} }
@ -93,7 +122,7 @@ int adecRead(void* opaque, u8* buf, int buf_size)
int res = 0; int res = 0;
next: 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 code1 = vm::read8(adec.reader.addr + 2);
u8 code2 = vm::read8(adec.reader.addr + 3); u8 code2 = vm::read8(adec.reader.addr + 3);
@ -106,7 +135,7 @@ next:
adec.reader.has_ats = false; 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); OMAHeader oma(1 /* atrac3p id */, adec.sample_rate, adec.channels, adec.frame_size);
if (buf_size < sizeof(oma)) if (buf_size < sizeof(oma))
@ -244,12 +273,15 @@ u32 adecOpen(AudioDecoder* data)
adec.reader.has_ats = false; adec.reader.has_ats = false;
adec.just_started = true; adec.just_started = true;
if (adec.type == CELL_ADEC_TYPE_ATRACX_2CH)
{
adec.channels = task.at3p.channels; adec.channels = task.at3p.channels;
adec.frame_size = task.at3p.frame_size; adec.frame_size = task.at3p.frame_size;
adec.sample_rate = task.at3p.sample_rate; adec.sample_rate = task.at3p.sample_rate;
adec.use_ats_headers = task.at3p.ats_header == 1; adec.use_ats_headers = task.at3p.ats_header == 1;
} }
break; break;
}
case adecEndSeq: 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.cbFunc.call(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_SEQDONE, CELL_OK, adec.cbArg);
adec.just_finished = true; adec.just_finished = true;
}
break; break;
}
case adecDecodeAu: case adecDecodeAu:
{ {
@ -273,7 +305,8 @@ u32 adecOpen(AudioDecoder* data)
if (adec.just_started) if (adec.just_started)
{ {
adec.first_pts = task.au.pts; 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 struct AVPacketHolder : AVPacket
@ -313,21 +346,13 @@ u32 adecOpen(AudioDecoder* data)
{ {
AVDictionary* opts = nullptr; AVDictionary* opts = nullptr;
av_dict_set(&opts, "probesize", "96", 0); 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) if (err || opts)
{ {
cellAdec->Error("adecDecodeAu: avformat_open_input() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0); cellAdec->Error("adecDecodeAu: avformat_open_input() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0);
Emu.Pause(); Emu.Pause();
break; 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); //err = avformat_find_stream_info(adec.fmt, NULL);
//if (err) //if (err)
//{ //{
@ -341,7 +366,7 @@ u32 adecOpen(AudioDecoder* data)
// Emu.Pause(); // Emu.Pause();
// break; // break;
//} //}
if (!avformat_new_stream(adec.fmt, codec)) if (!avformat_new_stream(adec.fmt, adec.codec))
{ {
cellAdec->Error("adecDecodeAu: avformat_new_stream() failed"); cellAdec->Error("adecDecodeAu: avformat_new_stream() failed");
Emu.Pause(); Emu.Pause();
@ -354,7 +379,7 @@ u32 adecOpen(AudioDecoder* data)
{ {
std::lock_guard<std::mutex> lock(g_mutex_avcodec_open2); std::lock_guard<std::mutex> lock(g_mutex_avcodec_open2);
// not multithread-safe (???) // not multithread-safe (???)
err = avcodec_open2(adec.ctx, codec, &opts); err = avcodec_open2(adec.ctx, adec.codec, &opts);
} }
if (err || opts) if (err || opts)
{ {
@ -424,34 +449,34 @@ u32 adecOpen(AudioDecoder* data)
if (got_frame) if (got_frame)
{ {
u64 ts = av_frame_get_best_effort_timestamp(frame.data); //u64 ts = av_frame_get_best_effort_timestamp(frame.data);
if (ts != AV_NOPTS_VALUE) //if (ts != AV_NOPTS_VALUE)
{ //{
frame.pts = ts/* - adec.first_pts*/; // frame.pts = ts/* - adec.first_pts*/;
adec.last_pts = frame.pts; // adec.last_pts = frame.pts;
} //}
else
{
adec.last_pts += ((u64)frame.data->nb_samples) * 90000 / frame.data->sample_rate; adec.last_pts += ((u64)frame.data->nb_samples) * 90000 / frame.data->sample_rate;
frame.pts = adec.last_pts; 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);
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(); Emu.Pause();
break; 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)", //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, //frame.pts, frame.data->nb_samples, frame.data->channels, frame.data->sample_rate, nbps);
//av_get_bytes_per_sample((AVSampleFormat)frame.data->format));
if (adec.frames.Push(frame, &adec.is_closed)) 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); adec.cbFunc.call(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_AUDONE, task.au.auInfo_addr, adec.cbArg);
}
break; break;
}
case adecClose: 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: cellAdec->Notice("adecCheckType: ATRAC3plus"); break;
case CELL_ADEC_TYPE_ATRACX_2CH: cellAdec->Notice("adecCheckType: ATRAC3plus 2ch"); 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_6CH:
case CELL_ADEC_TYPE_ATRACX_8CH: case CELL_ADEC_TYPE_ATRACX_8CH:
case CELL_ADEC_TYPE_LPCM_PAMF: case CELL_ADEC_TYPE_LPCM_PAMF:
case CELL_ADEC_TYPE_AC3: case CELL_ADEC_TYPE_AC3:
case CELL_ADEC_TYPE_MP3:
case CELL_ADEC_TYPE_ATRAC3: case CELL_ADEC_TYPE_ATRAC3:
case CELL_ADEC_TYPE_MPEG_L2: case CELL_ADEC_TYPE_MPEG_L2:
case CELL_ADEC_TYPE_CELP: 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); 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; break;
} }
case CELL_ADEC_TYPE_MP3:
{
auto param = vm::ptr<const CellAdecParamMP3>::make(param_addr);
cellAdec->Todo("*** CellAdecParamMP3: bw_pcm=%d", param->bw_pcm.ToLE());
break;
}
default: default:
{ {
cellAdec->Todo("cellAdecStartSeq(): Unimplemented audio codec type(%d)", adec->type); cellAdec->Todo("cellAdecStartSeq(): Unimplemented audio codec type(%d)", adec->type);
@ -678,7 +710,7 @@ int cellAdecGetPcm(u32 handle, vm::ptr<float> outBuffer)
if (outBuffer) if (outBuffer)
{ {
// reverse byte order: // 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]; float* in_f = (float*)frame->extended_data[0];
for (u32 i = 0; i < af.size / 4; i++) for (u32 i = 0; i < af.size / 4; i++)
@ -686,7 +718,7 @@ int cellAdecGetPcm(u32 handle, vm::ptr<float> outBuffer)
outBuffer[i] = in_f[i]; 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]; float* in_f[2];
in_f[0] = (float*)frame->extended_data[0]; in_f[0] = (float*)frame->extended_data[0];
@ -697,9 +729,28 @@ int cellAdecGetPcm(u32 handle, vm::ptr<float> outBuffer)
outBuffer[i * 2 + 1] = in_f[1][i]; 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 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(); Emu.Pause();
} }
} }
@ -747,7 +798,10 @@ int cellAdecGetPcmItem(u32 handle, vm::ptr<u32> pcmItem_ptr)
pcm->auInfo.startAddr = af.auAddr; pcm->auInfo.startAddr = af.auAddr;
pcm->auInfo.userData = af.userdata; pcm->auInfo.userData = af.userdata;
if (adec->type == CELL_ADEC_TYPE_ATRACX_2CH)
{
auto atx = vm::ptr<CellAdecAtracXInfo>::make(pcm.addr() + sizeof(CellAdecPcmItem)); auto atx = vm::ptr<CellAdecAtracXInfo>::make(pcm.addr() + sizeof(CellAdecPcmItem));
atx->samplingFreq = frame->sample_rate; atx->samplingFreq = frame->sample_rate;
atx->nbytes = frame->nb_samples * sizeof(float); atx->nbytes = frame->nb_samples * sizeof(float);
if (frame->channels == 1) if (frame->channels == 1)
@ -763,6 +817,13 @@ int cellAdecGetPcmItem(u32 handle, vm::ptr<u32> pcmItem_ptr)
cellAdec->Error("cellAdecGetPcmItem(): unsupported channel count (%d)", frame->channels); cellAdec->Error("cellAdecGetPcmItem(): unsupported channel count (%d)", frame->channels);
Emu.Pause(); Emu.Pause();
} }
}
else if (adec->type == CELL_ADEC_TYPE_MP3)
{
auto mp3 = vm::ptr<CellAdecMP3Info>::make(pcm.addr() + sizeof(CellAdecPcmItem));
memset(mp3.get_ptr(), 0, sizeof(CellAdecMP3Info));
}
*pcmItem_ptr = pcm.addr(); *pcmItem_ptr = pcm.addr();
return CELL_OK; return CELL_OK;

View file

@ -1100,6 +1100,8 @@ public:
bool just_started; bool just_started;
bool just_finished; bool just_finished;
AVCodec* codec;
AVInputFormat* input_format;
AVCodecContext* ctx; AVCodecContext* ctx;
AVFormatContext* fmt; AVFormatContext* fmt;
u8* io_buf; u8* io_buf;

View file

@ -568,6 +568,8 @@ s64 spursInit(
} }
else while (true) else while (true)
{ {
if (Emu.IsStopped()) break;
spurs->m.xD64.exchange(0); spurs->m.xD64.exchange(0);
if (spurs->m.exception.ToBE() == 0) if (spurs->m.exception.ToBE() == 0)
{ {
@ -629,6 +631,9 @@ s64 spursInit(
return; return;
} }
} }
if (Emu.IsStopped()) continue;
if (s32 res = sys_lwmutex_unlock(spurs->get_lwmutex())) if (s32 res = sys_lwmutex_unlock(spurs->get_lwmutex()))
{ {
assert(!"sys_lwmutex_unlock() failed"); assert(!"sys_lwmutex_unlock() failed");

View file

@ -31,23 +31,59 @@ VideoDecoder::VideoDecoder(CellVdecCodecType type, u32 profile, u32 addr, u32 si
, is_closed(false) , is_closed(false)
, just_started(false) , just_started(false)
, just_finished(false) , just_finished(false)
, frc_set(0)
, codec(nullptr)
, input_format(nullptr)
, ctx(nullptr) , ctx(nullptr)
, vdecCb(nullptr) , vdecCb(nullptr)
{ {
av_register_all(); av_register_all();
avcodec_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) 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(); Emu.Pause();
return; return;
} }
fmt = avformat_alloc_context(); fmt = avformat_alloc_context();
if (!fmt) if (!fmt)
{ {
cellVdec->Error("VideoDecoder(): avformat_alloc_context failed"); cellVdec->Error("VideoDecoder(): avformat_alloc_context() failed");
Emu.Pause(); Emu.Pause();
return; 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); fmt->pb = avio_alloc_context(io_buf, 4096, 0, this, vdecRead, NULL, NULL);
if (!fmt->pb) if (!fmt->pb)
{ {
cellVdec->Error("VideoDecoder(): avio_alloc_context failed"); cellVdec->Error("VideoDecoder(): avio_alloc_context() failed");
Emu.Pause(); Emu.Pause();
return; return;
} }
@ -163,8 +199,8 @@ u32 vdecQueryAttr(CellVdecCodecType type, u32 profile, u32 spec_addr /* may be 0
switch (type) // TODO: check profile levels 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_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_MPEG2: cellVdec->Warning("cellVdecQueryAttr: MPEG2 (profile=%d)", profile); break;
case CELL_VDEC_CODEC_TYPE_DIVX: cellVdec->Todo("DIVX not supported"); break; case CELL_VDEC_CODEC_TYPE_DIVX: cellVdec->Warning("cellVdecQueryAttr: DivX (profile=%d)", profile); break;
default: return CELL_VDEC_ERROR_ARG; default: return CELL_VDEC_ERROR_ARG;
} }
@ -225,9 +261,10 @@ u32 vdecOpen(VideoDecoder* data)
cellVdec->Warning("vdecStartSeq:"); cellVdec->Warning("vdecStartSeq:");
vdec.reader = {}; vdec.reader = {};
vdec.frc_set = 0;
vdec.just_started = true; vdec.just_started = true;
}
break; break;
}
case vdecEndSeq: 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.cbFunc.call(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_SEQDONE, CELL_OK, vdec.cbArg);
vdec.just_finished = true; vdec.just_finished = true;
}
break; break;
}
case vdecDecodeAu: case vdecDecodeAu:
{ {
@ -257,7 +294,7 @@ u32 vdecOpen(VideoDecoder* data)
if (vdec.just_started) if (vdec.just_started)
{ {
vdec.first_pts = task.pts; vdec.first_pts = task.pts;
vdec.last_pts = task.pts; vdec.last_pts = -1;
vdec.first_dts = task.dts; vdec.first_dts = task.dts;
} }
@ -296,39 +333,32 @@ u32 vdecOpen(VideoDecoder* data)
} }
else if (vdec.just_started) // deferred initialization 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) if (err)
{ {
cellVdec->Error("vdecDecodeAu: avformat_open_input() failed"); cellVdec->Error("vdecDecodeAu: avformat_open_input() failed");
Emu.Pause(); Emu.Pause();
break; break;
} }
AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_H264); // ??? if (vdec.type == CELL_VDEC_CODEC_TYPE_DIVX)
if (!codec)
{ {
cellVdec->Error("vdecDecodeAu: avcodec_find_decoder() failed"); 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(); Emu.Pause();
break; break;
} }
/*err = avformat_find_stream_info(vdec.fmt, NULL);
if (err)
{
LOG_ERROR(HLE, "vdecDecodeAu: avformat_find_stream_info() failed");
Emu.Pause();
break;
} }
if (!vdec.fmt->nb_streams) else
{ {
LOG_ERROR(HLE, "vdecDecodeAu: no stream found"); if (!avformat_new_stream(vdec.fmt, vdec.codec))
Emu.Pause();
break;
}*/
if (!avformat_new_stream(vdec.fmt, codec))
{ {
cellVdec->Error("vdecDecodeAu: avformat_new_stream() failed"); cellVdec->Error("vdecDecodeAu: avformat_new_stream() failed");
Emu.Pause(); Emu.Pause();
break; break;
} }
}
vdec.ctx = vdec.fmt->streams[0]->codec; // TODO: check data vdec.ctx = vdec.fmt->streams[0]->codec; // TODO: check data
AVDictionary* opts = nullptr; AVDictionary* opts = nullptr;
@ -336,7 +366,7 @@ u32 vdecOpen(VideoDecoder* data)
{ {
std::lock_guard<std::mutex> lock(g_mutex_avcodec_open2); std::lock_guard<std::mutex> lock(g_mutex_avcodec_open2);
// not multithread-safe (???) // not multithread-safe (???)
err = avcodec_open2(vdec.ctx, codec, &opts); err = avcodec_open2(vdec.ctx, vdec.codec, &opts);
} }
if (err) if (err)
{ {
@ -344,6 +374,7 @@ u32 vdecOpen(VideoDecoder* data)
Emu.Pause(); Emu.Pause();
break; break;
} }
vdec.just_started = false; vdec.just_started = false;
} }
@ -406,19 +437,99 @@ u32 vdecOpen(VideoDecoder* data)
if (got_picture) if (got_picture)
{ {
u64 ts = av_frame_get_best_effort_timestamp(frame.data); if (frame.data->interlaced_frame)
if (ts != AV_NOPTS_VALUE)
{ {
frame.pts = ts/* - vdec.first_pts*/; // ??? cellVdec->Error("vdecDecodeAu: interlaced frames not supported (0x%x)", frame.data->interlaced_frame);
vdec.last_pts = frame.pts; 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 else
{ {
vdec.last_pts += vdec.ctx->time_base.num * 90000 / (vdec.ctx->time_base.den / vdec.ctx->ticks_per_frame); u64 ts = av_frame_get_best_effort_timestamp(frame.data);
frame.pts = vdec.last_pts; if (ts != AV_NOPTS_VALUE)
{
vdec.last_pts = ts;
} }
//frame.pts = vdec.last_pts; else if (vdec.last_pts == -1)
//vdec.last_pts += 3754; {
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;
frame.dts = (frame.pts - vdec.first_pts) + vdec.first_dts; frame.dts = (frame.pts - vdec.first_pts) + vdec.first_dts;
frame.userdata = task.userData; 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); vdec.cbFunc.call(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, vdec.cbArg);
}
break; break;
}
case vdecSetFrameRate: case vdecSetFrameRate:
{ {
cellVdec->Error("TODO: vdecSetFrameRate(%d)", task.frc); cellVdec->Error("vdecSetFrameRate(0x%x)", task.frc);
Emu.Pause(); vdec.frc_set = task.frc;
}
break; break;
}
case vdecClose: break; case vdecClose: break;
@ -679,6 +790,8 @@ int cellVdecGetPicItem(u32 handle, vm::ptr<u32> picItem_ptr)
info->attr = CELL_VDEC_PICITEM_ATTR_NORMAL; info->attr = CELL_VDEC_PICITEM_ATTR_NORMAL;
info->picInfo_addr = info.addr() + sizeof(CellVdecPicItem); info->picInfo_addr = info.addr() + sizeof(CellVdecPicItem);
if (vdec->type == CELL_VDEC_CODEC_TYPE_AVC)
{
auto avc = vm::ptr<CellVdecAvcInfo>::make(info.addr() + sizeof(CellVdecPicItem)); auto avc = vm::ptr<CellVdecAvcInfo>::make(info.addr() + sizeof(CellVdecPicItem));
avc->horizontalSize = frame.width; avc->horizontalSize = frame.width;
@ -688,7 +801,7 @@ int cellVdecGetPicItem(u32 handle, vm::ptr<u32> picItem_ptr)
case AV_PICTURE_TYPE_I: avc->pictureType[0] = CELL_VDEC_AVC_PCT_I; break; 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_P: avc->pictureType[0] = CELL_VDEC_AVC_PCT_P; break;
case AV_PICTURE_TYPE_B: avc->pictureType[0] = CELL_VDEC_AVC_PCT_B; 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; // ??? default: cellVdec->Error("cellVdecGetPicItem(AVC): unknown pict_type value (0x%x)", frame.pict_type);
} }
avc->pictureType[1] = CELL_VDEC_AVC_PCT_UNKNOWN; // ??? avc->pictureType[1] = CELL_VDEC_AVC_PCT_UNKNOWN; // ???
avc->idrPictureFlag = false; // ??? avc->idrPictureFlag = false; // ???
@ -708,27 +821,20 @@ int cellVdecGetPicItem(u32 handle, vm::ptr<u32> picItem_ptr)
avc->transfer_characteristics = CELL_VDEC_AVC_TC_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->matrix_coefficients = CELL_VDEC_AVC_MXC_ITU_R_BT_709_5; // important
avc->timing_info_present_flag = true; avc->timing_info_present_flag = true;
if (vdec->ctx->time_base.num == 1001)
switch (vf.frc)
{ {
if (vdec->ctx->time_base.den == 48000 && vdec->ctx->ticks_per_frame == 2) 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;
avc->frameRateCode = CELL_VDEC_AVC_FRC_24000DIV1001; 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;
else if (vdec->ctx->time_base.den == 60000 && vdec->ctx->ticks_per_frame == 2) 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;
avc->frameRateCode = CELL_VDEC_AVC_FRC_30000DIV1001; 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;
else default: cellVdec->Error("cellVdecGetPicItem(AVC): unknown frc value (0x%x)", vf.frc); break;
{
cellVdec->Error("cellVdecGetPicItem: unsupported time_base.den (%d)", vdec->ctx->time_base.den);
Emu.Pause();
}
}
else
{
cellVdec->Error("cellVdecGetPicItem: unsupported time_base.num (%d)", vdec->ctx->time_base.num);
Emu.Pause();
} }
avc->fixed_frame_rate_flag = true; avc->fixed_frame_rate_flag = true;
avc->low_delay_hrd_flag = true; // ??? avc->low_delay_hrd_flag = true; // ???
avc->entropy_coding_mode_flag = true; // ??? avc->entropy_coding_mode_flag = true; // ???
@ -737,9 +843,50 @@ int cellVdecGetPicItem(u32 handle, vm::ptr<u32> picItem_ptr)
avc->ccDataLength[1] = 0; avc->ccDataLength[1] = 0;
avc->reserved[0] = 0; avc->reserved[0] = 0;
avc->reserved[1] = 0; avc->reserved[1] = 0;
}
else if (vdec->type == CELL_VDEC_CODEC_TYPE_DIVX)
{
auto dvx = vm::ptr<CellVdecDivxInfo>::make(info.addr() + sizeof(CellVdecPicItem));
switch (frame.pict_type)
{
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);
}
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)
{
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 if (vdec->type == CELL_VDEC_CODEC_TYPE_MPEG2)
{
auto mp2 = vm::ptr<CellVdecMpeg2Info>::make(info.addr() + sizeof(CellVdecPicItem));
cellVdec->Todo("cellVdecGetPicItem(MPEG2)");
Emu.Pause();
}
*picItem_ptr = info.addr(); *picItem_ptr = info.addr();
return CELL_OK; return CELL_OK;
} }

View file

@ -685,6 +685,7 @@ struct VdecFrame
u64 dts; u64 dts;
u64 pts; u64 pts;
u64 userdata; u64 userdata;
u32 frc;
}; };
int vdecRead(void* opaque, u8* buf, int buf_size); int vdecRead(void* opaque, u8* buf, int buf_size);
@ -699,6 +700,8 @@ public:
bool just_started; bool just_started;
bool just_finished; bool just_finished;
AVCodec* codec;
AVInputFormat* input_format;
AVCodecContext* ctx; AVCodecContext* ctx;
AVFormatContext* fmt; AVFormatContext* fmt;
u8* io_buf; u8* io_buf;
@ -721,6 +724,7 @@ public:
VdecTask task; // current task variable VdecTask task; // current task variable
u64 last_pts, first_pts, first_dts; u64 last_pts, first_pts, first_dts;
u32 frc_set; // frame rate overwriting
AVRational rfr, afr; AVRational rfr, afr;
PPUThread* vdecCb; PPUThread* vdecCb;