mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-22 20:45:22 +00:00
Merge pull request #888 from Nekotekina/master
DivX, MP3 codecs activated, cellPamf and cellDmux improvements
This commit is contained in:
commit
b48159b104
9 changed files with 984 additions and 595 deletions
|
@ -19,6 +19,8 @@ extern "C"
|
|||
|
||||
Module *cellAdec = nullptr;
|
||||
|
||||
#define ADEC_ERROR(...) { cellAdec->Error(__VA_ARGS__); Emu.Pause(); return; } // only for decoder thread
|
||||
|
||||
AudioDecoder::AudioDecoder(AudioCodecType type, u32 addr, u32 size, vm::ptr<CellAdecCbMsg> func, u32 arg)
|
||||
: type(type)
|
||||
, memAddr(addr)
|
||||
|
@ -31,33 +33,55 @@ AudioDecoder::AudioDecoder(AudioCodecType type, u32 addr, u32 size, vm::ptr<Cell
|
|||
, is_finished(false)
|
||||
, just_started(false)
|
||||
, just_finished(false)
|
||||
, codec(nullptr)
|
||||
, input_format(nullptr)
|
||||
, ctx(nullptr)
|
||||
, fmt(nullptr)
|
||||
{
|
||||
av_register_all();
|
||||
avcodec_register_all();
|
||||
|
||||
AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_ATRAC3P);
|
||||
switch (type)
|
||||
{
|
||||
case CELL_ADEC_TYPE_ATRACX:
|
||||
case CELL_ADEC_TYPE_ATRACX_2CH:
|
||||
case CELL_ADEC_TYPE_ATRACX_6CH:
|
||||
case CELL_ADEC_TYPE_ATRACX_8CH:
|
||||
{
|
||||
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:
|
||||
{
|
||||
ADEC_ERROR("AudioDecoder(): unknown type (0x%x)", type);
|
||||
}
|
||||
}
|
||||
|
||||
if (!codec)
|
||||
{
|
||||
cellAdec->Error("AudioDecoder(): avcodec_find_decoder(ATRAC3P) failed");
|
||||
Emu.Pause();
|
||||
return;
|
||||
ADEC_ERROR("AudioDecoder(): avcodec_find_decoder() failed");
|
||||
}
|
||||
if (!input_format)
|
||||
{
|
||||
ADEC_ERROR("AudioDecoder(): av_find_input_format() failed");
|
||||
}
|
||||
fmt = avformat_alloc_context();
|
||||
if (!fmt)
|
||||
{
|
||||
cellAdec->Error("AudioDecoder(): avformat_alloc_context failed");
|
||||
Emu.Pause();
|
||||
return;
|
||||
ADEC_ERROR("AudioDecoder(): avformat_alloc_context() failed");
|
||||
}
|
||||
io_buf = (u8*)av_malloc(4096);
|
||||
fmt->pb = avio_alloc_context(io_buf, 256, 0, this, adecRead, NULL, NULL);
|
||||
if (!fmt->pb)
|
||||
{
|
||||
cellAdec->Error("AudioDecoder(): avio_alloc_context failed");
|
||||
Emu.Pause();
|
||||
return;
|
||||
ADEC_ERROR("AudioDecoder(): avio_alloc_context() failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,11 +117,11 @@ int adecRead(void* opaque, u8* buf, int buf_size)
|
|||
int res = 0;
|
||||
|
||||
next:
|
||||
if (adec.reader.has_ats)
|
||||
if (adecIsAtracX(adec.type) && adec.reader.has_ats)
|
||||
{
|
||||
u8 code1 = vm::read8(adec.reader.addr + 2);
|
||||
u8 code2 = vm::read8(adec.reader.addr + 3);
|
||||
adec.channels = (code1 >> 2) & 0x7;
|
||||
adec.ch_cfg = (code1 >> 2) & 0x7;
|
||||
adec.frame_size = ((((u32)code1 & 0x3) << 8) | (u32)code2) * 8 + 8;
|
||||
adec.sample_rate = at3freq[code1 >> 5];
|
||||
|
||||
|
@ -106,9 +130,9 @@ next:
|
|||
adec.reader.has_ats = false;
|
||||
}
|
||||
|
||||
if (!adec.reader.init)
|
||||
if (adecIsAtracX(adec.type) && !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.ch_cfg, adec.frame_size);
|
||||
if (buf_size < sizeof(oma))
|
||||
{
|
||||
cellAdec->Error("adecRead(): OMAHeader writing failed");
|
||||
|
@ -244,12 +268,16 @@ 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 (adecIsAtracX(adec.type))
|
||||
{
|
||||
adec.ch_cfg = task.at3p.channel_config;
|
||||
adec.ch_out = 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 +286,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 +301,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 (adecIsAtracX(adec.type)) adec.last_pts -= 0x10000; // hack
|
||||
}
|
||||
|
||||
struct AVPacketHolder : AVPacket
|
||||
|
@ -313,39 +342,19 @@ 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;
|
||||
ADEC_ERROR("adecDecodeAu: avformat_open_input() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0);
|
||||
}
|
||||
//err = avformat_find_stream_info(adec.fmt, NULL);
|
||||
//if (err)
|
||||
//if (err || !adec.fmt->nb_streams)
|
||||
//{
|
||||
// cellAdec->Error("adecDecodeAu: avformat_find_stream_info() failed");
|
||||
// Emu.Pause();
|
||||
// break;
|
||||
// ADEC_ERROR("adecDecodeAu: avformat_find_stream_info() failed (err=0x%x, nb_streams=%d)", err, adec.fmt->nb_streams);
|
||||
//}
|
||||
//if (!adec.fmt->nb_streams)
|
||||
//{
|
||||
// cellAdec->Error("adecDecodeAu: no stream found");
|
||||
// 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();
|
||||
break;
|
||||
ADEC_ERROR("adecDecodeAu: avformat_new_stream() failed");
|
||||
}
|
||||
adec.ctx = adec.fmt->streams[0]->codec; // TODO: check data
|
||||
|
||||
|
@ -354,13 +363,11 @@ u32 adecOpen(AudioDecoder* data)
|
|||
{
|
||||
std::lock_guard<std::mutex> 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)
|
||||
{
|
||||
cellAdec->Error("adecDecodeAu: avcodec_open2() failed");
|
||||
Emu.Pause();
|
||||
break;
|
||||
ADEC_ERROR("adecDecodeAu: avcodec_open2() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0);
|
||||
}
|
||||
adec.just_started = false;
|
||||
}
|
||||
|
@ -404,9 +411,7 @@ u32 adecOpen(AudioDecoder* data)
|
|||
|
||||
if (!frame.data)
|
||||
{
|
||||
cellAdec->Error("adecDecodeAu: av_frame_alloc() failed");
|
||||
Emu.Pause();
|
||||
break;
|
||||
ADEC_ERROR("adecDecodeAu: av_frame_alloc() failed");
|
||||
}
|
||||
|
||||
int got_frame = 0;
|
||||
|
@ -415,7 +420,7 @@ u32 adecOpen(AudioDecoder* data)
|
|||
|
||||
if (decode <= 0)
|
||||
{
|
||||
if (!last_frame && decode < 0)
|
||||
if (decode < 0)
|
||||
{
|
||||
cellAdec->Error("adecDecodeAu: AU decoding error(0x%x)", decode);
|
||||
}
|
||||
|
@ -424,34 +429,32 @@ u32 adecOpen(AudioDecoder* data)
|
|||
|
||||
if (got_frame)
|
||||
{
|
||||
u64 ts = av_frame_get_best_effort_timestamp(frame.data);
|
||||
if (ts != AV_NOPTS_VALUE)
|
||||
//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;
|
||||
|
||||
s32 nbps = av_get_bytes_per_sample((AVSampleFormat)frame.data->format);
|
||||
switch (frame.data->format)
|
||||
{
|
||||
frame.pts = ts/* - adec.first_pts*/;
|
||||
adec.last_pts = frame.pts;
|
||||
}
|
||||
else
|
||||
case AV_SAMPLE_FMT_FLTP: break;
|
||||
case AV_SAMPLE_FMT_S16P: break;
|
||||
default:
|
||||
{
|
||||
adec.last_pts += ((u64)frame.data->nb_samples) * 90000 / frame.data->sample_rate;
|
||||
frame.pts = adec.last_pts;
|
||||
ADEC_ERROR("adecDecodeAu: unsupported frame format(%d)", frame.data->format);
|
||||
}
|
||||
}
|
||||
//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)
|
||||
{
|
||||
cellAdec->Error("adecDecodeaAu: unsupported frame format(%d)", frame.data->format);
|
||||
Emu.Pause();
|
||||
break;
|
||||
}
|
||||
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,16 +465,17 @@ 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;
|
||||
case adecClose:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
cellAdec->Error("Audio Decoder thread error: unknown task(%d)", task.type);
|
||||
Emu.Pause();
|
||||
return;
|
||||
ADEC_ERROR("Audio Decoder thread error: unknown task(%d)", task.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -490,23 +494,25 @@ bool adecCheckType(AudioCodecType type)
|
|||
{
|
||||
switch (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_ATRACX: cellAdec->Notice("adecCheckType(): ATRAC3plus"); break;
|
||||
case CELL_ADEC_TYPE_ATRACX_2CH: cellAdec->Notice("adecCheckType(): ATRAC3plus 2ch"); break;
|
||||
case CELL_ADEC_TYPE_ATRACX_6CH: cellAdec->Notice("adecCheckType(): ATRAC3plus 6ch"); break;
|
||||
case CELL_ADEC_TYPE_ATRACX_8CH: cellAdec->Notice("adecCheckType(): ATRAC3plus 8ch"); 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:
|
||||
case CELL_ADEC_TYPE_M4AAC:
|
||||
case CELL_ADEC_TYPE_CELP8:
|
||||
{
|
||||
cellAdec->Todo("Unimplemented audio codec type (%d)", type);
|
||||
Emu.Pause();
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
default: return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -592,7 +598,10 @@ int cellAdecStartSeq(u32 handle, u32 param_addr)
|
|||
|
||||
switch (adec->type)
|
||||
{
|
||||
case CELL_ADEC_TYPE_ATRACX:
|
||||
case CELL_ADEC_TYPE_ATRACX_2CH:
|
||||
case CELL_ADEC_TYPE_ATRACX_6CH:
|
||||
case CELL_ADEC_TYPE_ATRACX_8CH:
|
||||
{
|
||||
auto param = vm::ptr<const CellAdecParamAtracX>::make(param_addr);
|
||||
|
||||
|
@ -608,6 +617,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<const CellAdecParamMP3>::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 +694,7 @@ int cellAdecGetPcm(u32 handle, vm::ptr<float> 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 +702,7 @@ int cellAdecGetPcm(u32 handle, vm::ptr<float> 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 +713,70 @@ int cellAdecGetPcm(u32 handle, vm::ptr<float> outBuffer)
|
|||
outBuffer[i * 2 + 1] = in_f[1][i];
|
||||
}
|
||||
}
|
||||
else if (frame->format == AV_SAMPLE_FMT_FLTP && frame->channels == 6)
|
||||
{
|
||||
float* in_f[6];
|
||||
in_f[0] = (float*)frame->extended_data[0];
|
||||
in_f[1] = (float*)frame->extended_data[1];
|
||||
in_f[2] = (float*)frame->extended_data[2];
|
||||
in_f[3] = (float*)frame->extended_data[3];
|
||||
in_f[4] = (float*)frame->extended_data[4];
|
||||
in_f[5] = (float*)frame->extended_data[5];
|
||||
for (u32 i = 0; i < af.size / 24; i++)
|
||||
{
|
||||
outBuffer[i * 6 + 0] = in_f[0][i];
|
||||
outBuffer[i * 6 + 1] = in_f[1][i];
|
||||
outBuffer[i * 6 + 2] = in_f[2][i];
|
||||
outBuffer[i * 6 + 3] = in_f[3][i];
|
||||
outBuffer[i * 6 + 4] = in_f[4][i];
|
||||
outBuffer[i * 6 + 5] = in_f[5][i];
|
||||
}
|
||||
}
|
||||
else if (frame->format == AV_SAMPLE_FMT_FLTP && frame->channels == 8)
|
||||
{
|
||||
float* in_f[8];
|
||||
in_f[0] = (float*)frame->extended_data[0];
|
||||
in_f[1] = (float*)frame->extended_data[1];
|
||||
in_f[2] = (float*)frame->extended_data[2];
|
||||
in_f[3] = (float*)frame->extended_data[3];
|
||||
in_f[4] = (float*)frame->extended_data[4];
|
||||
in_f[5] = (float*)frame->extended_data[5];
|
||||
in_f[6] = (float*)frame->extended_data[6];
|
||||
in_f[7] = (float*)frame->extended_data[7];
|
||||
for (u32 i = 0; i < af.size / 24; i++)
|
||||
{
|
||||
outBuffer[i * 8 + 0] = in_f[0][i];
|
||||
outBuffer[i * 8 + 1] = in_f[1][i];
|
||||
outBuffer[i * 8 + 2] = in_f[2][i];
|
||||
outBuffer[i * 8 + 3] = in_f[3][i];
|
||||
outBuffer[i * 8 + 4] = in_f[4][i];
|
||||
outBuffer[i * 8 + 5] = in_f[5][i];
|
||||
outBuffer[i * 8 + 6] = in_f[6][i];
|
||||
outBuffer[i * 8 + 7] = in_f[7][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 +824,40 @@ int cellAdecGetPcmItem(u32 handle, vm::ptr<u32> pcmItem_ptr)
|
|||
pcm->auInfo.startAddr = af.auAddr;
|
||||
pcm->auInfo.userData = af.userdata;
|
||||
|
||||
auto atx = vm::ptr<CellAdecAtracXInfo>::make(pcm.addr() + sizeof(CellAdecPcmItem));
|
||||
atx->samplingFreq = frame->sample_rate;
|
||||
atx->nbytes = frame->nb_samples * sizeof(float);
|
||||
if (frame->channels == 1)
|
||||
if (adecIsAtracX(adec->type))
|
||||
{
|
||||
atx->channelConfigIndex = 1;
|
||||
auto atx = vm::ptr<CellAdecAtracXInfo>::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 if (frame->channels == 6)
|
||||
{
|
||||
atx->channelConfigIndex = 6;
|
||||
}
|
||||
else if (frame->channels == 8)
|
||||
{
|
||||
atx->channelConfigIndex = 7;
|
||||
}
|
||||
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<CellAdecMP3Info>::make(pcm.addr() + sizeof(CellAdecPcmItem));
|
||||
|
||||
// TODO
|
||||
memset(mp3.get_ptr(), 0, sizeof(CellAdecMP3Info));
|
||||
}
|
||||
|
||||
*pcmItem_ptr = pcm.addr();
|
||||
|
|
|
@ -284,6 +284,14 @@ enum AudioCodecType
|
|||
CELL_ADEC_TYPE_RESERVED25,
|
||||
};
|
||||
|
||||
static bool adecIsAtracX(const AudioCodecType type)
|
||||
{
|
||||
return type == CELL_ADEC_TYPE_ATRACX
|
||||
|| type == CELL_ADEC_TYPE_ATRACX_2CH
|
||||
|| type == CELL_ADEC_TYPE_ATRACX_6CH
|
||||
|| type == CELL_ADEC_TYPE_ATRACX_8CH;
|
||||
}
|
||||
|
||||
// Output Channel Number
|
||||
enum CellAdecChannel
|
||||
{
|
||||
|
@ -1100,6 +1108,8 @@ public:
|
|||
bool just_started;
|
||||
bool just_finished;
|
||||
|
||||
AVCodec* codec;
|
||||
AVInputFormat* input_format;
|
||||
AVCodecContext* ctx;
|
||||
AVFormatContext* fmt;
|
||||
u8* io_buf;
|
||||
|
@ -1130,7 +1140,8 @@ public:
|
|||
AdecTask task;
|
||||
u64 last_pts, first_pts;
|
||||
|
||||
u32 channels;
|
||||
u32 ch_out;
|
||||
u32 ch_cfg;
|
||||
u32 frame_size;
|
||||
u32 sample_rate;
|
||||
bool use_ats_headers;
|
||||
|
|
|
@ -10,52 +10,96 @@
|
|||
|
||||
Module *cellDmux = nullptr;
|
||||
|
||||
#define DMUX_ERROR(...) { cellDmux->Error(__VA_ARGS__); Emu.Pause(); return; } // only for demuxer thread
|
||||
|
||||
PesHeader::PesHeader(DemuxerStream& stream)
|
||||
: pts(0xffffffffffffffffull)
|
||||
, dts(0xffffffffffffffffull)
|
||||
: pts(CODEC_TS_INVALID)
|
||||
, dts(CODEC_TS_INVALID)
|
||||
, size(0)
|
||||
, has_ts(false)
|
||||
, is_ok(false)
|
||||
{
|
||||
u16 header;
|
||||
stream.get(header);
|
||||
stream.get(size);
|
||||
if (size)
|
||||
if (!stream.get(header))
|
||||
{
|
||||
DMUX_ERROR("PesHeader(): end of stream (header)");
|
||||
}
|
||||
if (!stream.get(size))
|
||||
{
|
||||
DMUX_ERROR("PesHeader(): end of stream (size)");
|
||||
}
|
||||
if (!stream.check(size))
|
||||
{
|
||||
DMUX_ERROR("PesHeader(): end of stream (size=%d)", size);
|
||||
}
|
||||
|
||||
u8 pos = 0;
|
||||
while (pos++ < size)
|
||||
{
|
||||
u8 empty = 0;
|
||||
u8 v;
|
||||
while (true)
|
||||
if (!stream.get(v))
|
||||
{
|
||||
stream.get(v);
|
||||
if (v != 0xFF) break; // skip padding bytes
|
||||
empty++;
|
||||
if (empty == size) return;
|
||||
};
|
||||
return; // should never occur
|
||||
}
|
||||
|
||||
if ((v & 0xF0) == 0x20 && (size - empty) >= 5) // pts only
|
||||
if (v == 0xff) // skip padding bytes
|
||||
{
|
||||
has_ts = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((v & 0xf0) == 0x20 && (size - pos) >= 4) // pts only
|
||||
{
|
||||
pos += 4;
|
||||
pts = stream.get_ts(v);
|
||||
stream.skip(size - empty - 5);
|
||||
has_ts = true;
|
||||
}
|
||||
else if ((v & 0xf0) == 0x30 && (size - pos) >= 9) // pts and dts
|
||||
{
|
||||
pos += 5;
|
||||
pts = stream.get_ts(v);
|
||||
stream.get(v);
|
||||
has_ts = true;
|
||||
|
||||
if ((v & 0xf0) != 0x10)
|
||||
{
|
||||
cellDmux->Error("PesHeader(): dts not found (v=0x%x, size=%d, pos=%d)", v, size, pos - 1);
|
||||
stream.skip(size - pos);
|
||||
return;
|
||||
}
|
||||
pos += 4;
|
||||
dts = stream.get_ts(v);
|
||||
}
|
||||
else
|
||||
{
|
||||
has_ts = true;
|
||||
if ((v & 0xF0) != 0x30 || (size - empty) < 10)
|
||||
{
|
||||
cellDmux->Error("PesHeader(): pts not found");
|
||||
Emu.Pause();
|
||||
}
|
||||
pts = stream.get_ts(v);
|
||||
stream.get(v);
|
||||
if ((v & 0xF0) != 0x10)
|
||||
{
|
||||
cellDmux->Error("PesHeader(): dts not found");
|
||||
Emu.Pause();
|
||||
}
|
||||
dts = stream.get_ts(v);
|
||||
stream.skip(size - empty - 10);
|
||||
cellDmux->Warning("PesHeader(): unknown code (v=0x%x, size=%d, pos=%d)", v, size, pos - 1);
|
||||
stream.skip(size - pos);
|
||||
pos = size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
is_ok = true;
|
||||
}
|
||||
|
||||
ElementaryStream::ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr<CellDmuxCbEsMsg> cbFunc, u32 cbArg, u32 spec)
|
||||
: dmux(dmux)
|
||||
, memAddr(a128(addr))
|
||||
, memSize(size - (addr - memAddr))
|
||||
, fidMajor(fidMajor)
|
||||
, fidMinor(fidMinor)
|
||||
, sup1(sup1)
|
||||
, sup2(sup2)
|
||||
, cbFunc(cbFunc)
|
||||
, cbArg(cbArg)
|
||||
, spec(spec)
|
||||
, put(memAddr)
|
||||
, put_count(0)
|
||||
, got_count(0)
|
||||
, released(0)
|
||||
, raw_pos(0)
|
||||
, last_dts(CODEC_TS_INVALID)
|
||||
, last_pts(CODEC_TS_INVALID)
|
||||
{
|
||||
}
|
||||
|
||||
bool ElementaryStream::is_full(u32 space)
|
||||
|
@ -70,7 +114,8 @@ bool ElementaryStream::is_full(u32 space)
|
|||
u32 first = 0;
|
||||
if (!entries.Peek(first, &dmux->is_closed) || !first)
|
||||
{
|
||||
throw "es::is_full() error: entries.Peek() failed";
|
||||
assert(!"es::is_full() error: entries.Peek() failed");
|
||||
return false;
|
||||
}
|
||||
else if (first >= put)
|
||||
{
|
||||
|
@ -103,10 +148,7 @@ void ElementaryStream::push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool ra
|
|||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
if (is_full(size))
|
||||
{
|
||||
throw "es::push_au() error: buffer is full";
|
||||
}
|
||||
assert(!is_full(size));
|
||||
|
||||
if (put + size + 128 > memAddr + memSize)
|
||||
{
|
||||
|
@ -148,7 +190,7 @@ void ElementaryStream::push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool ra
|
|||
}
|
||||
if (!entries.Push(addr, &dmux->is_closed))
|
||||
{
|
||||
throw "es::push_au() error: entries.Push() failed";
|
||||
assert(!"es::push_au() error: entries.Push() failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -277,13 +319,13 @@ u32 dmuxOpen(Demuxer* data)
|
|||
|
||||
DemuxerTask task;
|
||||
DemuxerStream stream = {};
|
||||
ElementaryStream* esALL[192]; memset(esALL, 0, sizeof(esALL));
|
||||
ElementaryStream** esAVC = &esALL[0]; // AVC (max 16)
|
||||
ElementaryStream** esM2V = &esALL[16]; // MPEG-2 (max 16)
|
||||
ElementaryStream* esALL[96]; memset(esALL, 0, sizeof(esALL));
|
||||
ElementaryStream** esAVC = &esALL[0]; // AVC (max 16 minus M2V count)
|
||||
ElementaryStream** esM2V = &esALL[16]; // M2V (max 16 minus AVC count)
|
||||
ElementaryStream** esDATA = &esALL[32]; // user data (max 16)
|
||||
ElementaryStream** esATX = &esALL[48]; // ATRAC3+ (max 48)
|
||||
ElementaryStream** esAC3 = &esALL[96]; // AC3 (max 48)
|
||||
ElementaryStream** esPCM = &esALL[144]; // LPCM (max 48)
|
||||
ElementaryStream** esATX = &esALL[48]; // ATRAC3+ (max 16)
|
||||
ElementaryStream** esAC3 = &esALL[64]; // AC3 (max 16)
|
||||
ElementaryStream** esPCM = &esALL[80]; // LPCM (max 16)
|
||||
|
||||
u32 cb_add = 0;
|
||||
|
||||
|
@ -299,7 +341,6 @@ u32 dmuxOpen(Demuxer* data)
|
|||
// default task (demuxing) (if there is no other work)
|
||||
be_t<u32> code;
|
||||
be_t<u16> len;
|
||||
u8 ch;
|
||||
|
||||
if (!stream.peek(code))
|
||||
{
|
||||
|
@ -310,53 +351,104 @@ u32 dmuxOpen(Demuxer* data)
|
|||
dmux.cbFunc.call(*dmux.dmuxCb, dmux.id, dmuxMsg, dmux.cbArg);
|
||||
|
||||
dmux.is_running = false;
|
||||
continue;
|
||||
}
|
||||
else switch (code.ToLE())
|
||||
|
||||
switch (code.ToLE())
|
||||
{
|
||||
case PACK_START_CODE:
|
||||
{
|
||||
if (!stream.check(14))
|
||||
{
|
||||
DMUX_ERROR("End of stream (PACK_START_CODE)");
|
||||
}
|
||||
stream.skip(14);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case SYSTEM_HEADER_START_CODE:
|
||||
{
|
||||
if (!stream.check(18))
|
||||
{
|
||||
DMUX_ERROR("End of stream (SYSTEM_HEADER_START_CODE)");
|
||||
}
|
||||
stream.skip(18);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case PADDING_STREAM:
|
||||
{
|
||||
if (!stream.check(6))
|
||||
{
|
||||
DMUX_ERROR("End of stream (PADDING_STREAM)");
|
||||
}
|
||||
stream.skip(4);
|
||||
stream.get(len);
|
||||
|
||||
if (!stream.check(len.ToLE()))
|
||||
{
|
||||
DMUX_ERROR("End of stream (PADDING_STREAM, len=%d)", len.ToLE());
|
||||
}
|
||||
stream.skip(len);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case PRIVATE_STREAM_2:
|
||||
{
|
||||
if (!stream.check(6))
|
||||
{
|
||||
DMUX_ERROR("End of stream (PRIVATE_STREAM_2)");
|
||||
}
|
||||
stream.skip(4);
|
||||
stream.get(len);
|
||||
|
||||
cellDmux->Notice("PRIVATE_STREAM_2 (%d)", len.ToLE());
|
||||
|
||||
if (!stream.check(len.ToLE()))
|
||||
{
|
||||
DMUX_ERROR("End of stream (PRIVATE_STREAM_2, len=%d)", len.ToLE());
|
||||
}
|
||||
stream.skip(len);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case PRIVATE_STREAM_1:
|
||||
{
|
||||
// audio and user data stream
|
||||
DemuxerStream backup = stream;
|
||||
|
||||
// audio AT3+ (and probably LPCM or user data)
|
||||
if (!stream.check(6))
|
||||
{
|
||||
DMUX_ERROR("End of stream (PRIVATE_STREAM_1)");
|
||||
}
|
||||
stream.skip(4);
|
||||
stream.get(len);
|
||||
|
||||
PesHeader pes(stream);
|
||||
if (!stream.check(len.ToLE()))
|
||||
{
|
||||
DMUX_ERROR("End of stream (PRIVATE_STREAM_1, len=%d)", len.ToLE());
|
||||
}
|
||||
|
||||
// read additional header:
|
||||
stream.peek(ch); // ???
|
||||
//stream.skip(4);
|
||||
//pes.size += 4;
|
||||
const PesHeader pes(stream);
|
||||
if (!pes.is_ok)
|
||||
{
|
||||
DMUX_ERROR("PesHeader error (PRIVATE_STREAM_1, len=%d)", len.ToLE());
|
||||
}
|
||||
|
||||
if (esATX[ch])
|
||||
if (len < pes.size + 4)
|
||||
{
|
||||
DMUX_ERROR("End of block (PRIVATE_STREAM_1, PesHeader + fid_minor, len=%d)", len.ToLE());
|
||||
}
|
||||
len -= pes.size + 4;
|
||||
|
||||
u8 fid_minor;
|
||||
if (!stream.get(fid_minor))
|
||||
{
|
||||
DMUX_ERROR("End of stream (PRIVATE_STREAM1, fid_minor)");
|
||||
}
|
||||
|
||||
const u32 ch = fid_minor % 16;
|
||||
if ((fid_minor & -0x10) == 0 && esATX[ch])
|
||||
{
|
||||
ElementaryStream& es = *esATX[ch];
|
||||
if (es.raw_data.size() > 1024 * 1024)
|
||||
|
@ -366,8 +458,12 @@ u32 dmuxOpen(Demuxer* data)
|
|||
continue;
|
||||
}
|
||||
|
||||
stream.skip(4);
|
||||
len -= 4;
|
||||
if (len < 3 || !stream.check(3))
|
||||
{
|
||||
DMUX_ERROR("End of block (ATX, unknown header, len=%d)", len.ToLE());
|
||||
}
|
||||
len -= 3;
|
||||
stream.skip(3);
|
||||
|
||||
if (pes.has_ts)
|
||||
{
|
||||
|
@ -375,7 +471,7 @@ u32 dmuxOpen(Demuxer* data)
|
|||
es.last_pts = pes.pts;
|
||||
}
|
||||
|
||||
es.push(stream, len - pes.size - 3);
|
||||
es.push(stream, len);
|
||||
|
||||
while (true)
|
||||
{
|
||||
|
@ -386,9 +482,7 @@ u32 dmuxOpen(Demuxer* data)
|
|||
|
||||
if (data[0] != 0x0f || data[1] != 0xd0)
|
||||
{
|
||||
cellDmux->Error("ATX: 0x0fd0 header not found (ats=0x%llx)", ((be_t<u64>*)data)->ToLE());
|
||||
Emu.Pause();
|
||||
return;
|
||||
DMUX_ERROR("ATX: 0x0fd0 header not found (ats=0x%llx)", ((be_t<u64>*)data)->ToLE());
|
||||
}
|
||||
|
||||
u32 frame_size = ((((u32)data[2] & 0x3) << 8) | (u32)data[3]) * 8 + 8;
|
||||
|
@ -399,6 +493,8 @@ u32 dmuxOpen(Demuxer* data)
|
|||
|
||||
es.push_au(frame_size + 8, es.last_dts, es.last_pts, stream.userdata, false /* TODO: set correct value */, 0);
|
||||
|
||||
//cellDmux->Notice("ATX AU pushed (ats=0x%llx, frame_size=%d)", ((be_t<u64>*)data)->ToLE(), frame_size);
|
||||
|
||||
auto esMsg = vm::ptr<CellDmuxEsMsg>::make(a128(dmux.memAddr) + (cb_add ^= 16));
|
||||
esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND;
|
||||
esMsg->supplementalInfo = stream.userdata;
|
||||
|
@ -407,26 +503,48 @@ u32 dmuxOpen(Demuxer* data)
|
|||
}
|
||||
else
|
||||
{
|
||||
stream.skip(len - pes.size - 3);
|
||||
cellDmux->Notice("PRIVATE_STREAM_1 (len=%d, fid_minor=0x%x)", len.ToLE(), fid_minor);
|
||||
stream.skip(len);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x1e0: case 0x1e1: case 0x1e2: case 0x1e3:
|
||||
case 0x1e4: case 0x1e5: case 0x1e6: case 0x1e7:
|
||||
case 0x1e8: case 0x1e9: case 0x1ea: case 0x1eb:
|
||||
case 0x1ec: case 0x1ed: case 0x1ee: case 0x1ef:
|
||||
{
|
||||
// video AVC
|
||||
ch = code - 0x1e0;
|
||||
// video stream (AVC or M2V)
|
||||
DemuxerStream backup = stream;
|
||||
|
||||
if (!stream.check(6))
|
||||
{
|
||||
DMUX_ERROR("End of stream (video, code=0x%x)", code.ToLE());
|
||||
}
|
||||
stream.skip(4);
|
||||
stream.get(len);
|
||||
|
||||
if (!stream.check(len.ToLE()))
|
||||
{
|
||||
DMUX_ERROR("End of stream (video, code=0x%x, len=%d)", code.ToLE(), len.ToLE());
|
||||
}
|
||||
|
||||
const PesHeader pes(stream);
|
||||
if (!pes.is_ok)
|
||||
{
|
||||
DMUX_ERROR("PesHeader error (video, code=0x%x, len=%d)", code.ToLE(), len.ToLE());
|
||||
}
|
||||
|
||||
if (len < pes.size + 3)
|
||||
{
|
||||
DMUX_ERROR("End of block (video, code=0x%x, PesHeader)", code.ToLE());
|
||||
}
|
||||
len -= pes.size + 3;
|
||||
|
||||
const u32 ch = code.ToLE() % 16;
|
||||
if (esAVC[ch])
|
||||
{
|
||||
ElementaryStream& es = *esAVC[ch];
|
||||
DemuxerStream backup = stream;
|
||||
|
||||
stream.skip(4);
|
||||
stream.get(len);
|
||||
PesHeader pes(stream);
|
||||
|
||||
const u32 old_size = (u32)es.raw_data.size();
|
||||
if (es.isfull(old_size))
|
||||
|
@ -436,9 +554,9 @@ u32 dmuxOpen(Demuxer* data)
|
|||
continue;
|
||||
}
|
||||
|
||||
if ((pes.has_ts && old_size) || old_size >= 0x70000)
|
||||
if ((pes.has_ts && old_size) || old_size >= 0x69800)
|
||||
{
|
||||
// push AU if it becomes too big or the next packet contains ts data
|
||||
// push AU if it becomes too big or the next packet contains PTS/DTS
|
||||
es.push_au(old_size, es.last_dts, es.last_pts, stream.userdata, false /* TODO: set correct value */, 0);
|
||||
|
||||
// callback
|
||||
|
@ -456,53 +574,34 @@ u32 dmuxOpen(Demuxer* data)
|
|||
}
|
||||
|
||||
// reconstruction of MPEG2-PS stream for vdec module
|
||||
const u32 size = len + 6 /*- pes.size - 3*/;
|
||||
const u32 size = (u32)len.ToLE() + pes.size + 9;
|
||||
stream = backup;
|
||||
es.push(stream, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
stream.skip(4);
|
||||
stream.get(len);
|
||||
cellDmux->Notice("Video stream (code=0x%x, len=%d)", code.ToLE(), len.ToLE());
|
||||
stream.skip(len);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x1c0: case 0x1c1: case 0x1c2: case 0x1c3:
|
||||
case 0x1c4: case 0x1c5: case 0x1c6: case 0x1c7:
|
||||
case 0x1c8: case 0x1c9: case 0x1ca: case 0x1cb:
|
||||
case 0x1cc: case 0x1cd: case 0x1ce: case 0x1cf:
|
||||
case 0x1d0: case 0x1d1: case 0x1d2: case 0x1d3:
|
||||
case 0x1d4: case 0x1d5: case 0x1d6: case 0x1d7:
|
||||
case 0x1d8: case 0x1d9: case 0x1da: case 0x1db:
|
||||
case 0x1dc: case 0x1dd: case 0x1de: case 0x1df:
|
||||
{
|
||||
// unknown
|
||||
cellDmux->Warning("Unknown MPEG stream found");
|
||||
stream.skip(4);
|
||||
stream.get(len);
|
||||
stream.skip(len);
|
||||
}
|
||||
break;
|
||||
|
||||
case USER_DATA_START_CODE:
|
||||
{
|
||||
cellDmux->Error("USER_DATA_START_CODE found");
|
||||
Emu.Pause();
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
if ((code.ToLE() & PACKET_START_CODE_MASK) == PACKET_START_CODE_PREFIX)
|
||||
{
|
||||
DMUX_ERROR("Unknown code found (0x%x)", code.ToLE());
|
||||
}
|
||||
|
||||
// search
|
||||
stream.skip(1);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// wait for task with yielding (if no default work)
|
||||
// wait for task if no work
|
||||
if (!dmux.job.Pop(task, &dmux.is_closed))
|
||||
{
|
||||
break; // Emu is stopped
|
||||
|
@ -515,7 +614,7 @@ u32 dmuxOpen(Demuxer* data)
|
|||
if (task.stream.discontinuity)
|
||||
{
|
||||
cellDmux->Warning("dmuxSetStream (beginning)");
|
||||
for (u32 i = 0; i < 192; i++)
|
||||
for (u32 i = 0; i < sizeof(esALL) / sizeof(esALL[0]); i++)
|
||||
{
|
||||
if (esALL[i])
|
||||
{
|
||||
|
@ -527,8 +626,8 @@ u32 dmuxOpen(Demuxer* data)
|
|||
stream = task.stream;
|
||||
//LOG_NOTICE(HLE, "*** stream updated(addr=0x%x, size=0x%x, discont=%d, userdata=0x%llx)",
|
||||
//stream.addr, stream.size, stream.discontinuity, stream.userdata);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case dmuxResetStream:
|
||||
case dmuxResetStreamAndWaitDone:
|
||||
|
@ -543,44 +642,55 @@ u32 dmuxOpen(Demuxer* data)
|
|||
//if (task.type == dmuxResetStreamAndWaitDone)
|
||||
//{
|
||||
//}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case dmuxEnableEs:
|
||||
{
|
||||
ElementaryStream& es = *task.es.es_ptr;
|
||||
if (es.fidMajor >= 0xe0 &&
|
||||
es.fidMajor <= 0xef &&
|
||||
es.fidMinor == 0 &&
|
||||
es.sup1 == 1 &&
|
||||
es.sup2 == 0)
|
||||
|
||||
// TODO: uncomment when ready to use
|
||||
if ((es.fidMajor & -0x10) == 0xe0 && es.fidMinor == 0 && es.sup1 == 1 && !es.sup2)
|
||||
{
|
||||
esAVC[es.fidMajor - 0xe0] = task.es.es_ptr;
|
||||
esAVC[es.fidMajor % 16] = task.es.es_ptr;
|
||||
}
|
||||
else if (es.fidMajor == 0xbd &&
|
||||
es.fidMinor == 0 &&
|
||||
es.sup1 == 0 &&
|
||||
es.sup2 == 0)
|
||||
//else if ((es.fidMajor & -0x10) == 0xe0 && es.fidMinor == 0 && !es.sup1 && !es.sup2)
|
||||
//{
|
||||
// esM2V[es.fidMajor % 16] = task.es.es_ptr;
|
||||
//}
|
||||
else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0 && !es.sup1 && !es.sup2)
|
||||
{
|
||||
esATX[0] = task.es.es_ptr;
|
||||
esATX[es.fidMinor % 16] = task.es.es_ptr;
|
||||
}
|
||||
//else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0x20 && !es.sup1 && !es.sup2)
|
||||
//{
|
||||
// esDATA[es.fidMinor % 16] = task.es.es_ptr;
|
||||
//}
|
||||
//else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0x30 && !es.sup1 && !es.sup2)
|
||||
//{
|
||||
// esAC3[es.fidMinor % 16] = task.es.es_ptr;
|
||||
//}
|
||||
//else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0x40 && !es.sup1 && !es.sup2)
|
||||
//{
|
||||
// esPCM[es.fidMinor % 16] = task.es.es_ptr;
|
||||
//}
|
||||
else
|
||||
{
|
||||
cellDmux->Warning("dmuxEnableEs: (TODO) unsupported filter (0x%x, 0x%x, 0x%x, 0x%x)", es.fidMajor, es.fidMinor, es.sup1, es.sup2);
|
||||
DMUX_ERROR("dmuxEnableEs: unknown filter (0x%x, 0x%x, 0x%x, 0x%x)", es.fidMajor, es.fidMinor, es.sup1, es.sup2);
|
||||
}
|
||||
es.dmux = &dmux;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case dmuxDisableEs:
|
||||
{
|
||||
ElementaryStream& es = *task.es.es_ptr;
|
||||
if (es.dmux != &dmux)
|
||||
{
|
||||
cellDmux->Warning("dmuxDisableEs: invalid elementary stream");
|
||||
break;
|
||||
DMUX_ERROR("dmuxDisableEs: invalid elementary stream");
|
||||
}
|
||||
for (u32 i = 0; i < 192; i++)
|
||||
|
||||
for (u32 i = 0; i < sizeof(esALL) / sizeof(esALL[0]); i++)
|
||||
{
|
||||
if (esALL[i] == &es)
|
||||
{
|
||||
|
@ -589,15 +699,15 @@ u32 dmuxOpen(Demuxer* data)
|
|||
}
|
||||
es.dmux = nullptr;
|
||||
Emu.GetIdManager().RemoveID(task.es.es);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case dmuxFlushEs:
|
||||
{
|
||||
ElementaryStream& es = *task.es.es_ptr;
|
||||
|
||||
const u32 old_size = (u32)es.raw_data.size();
|
||||
if (old_size && (es.fidMajor & 0xf0) == 0xe0)
|
||||
if (old_size && (es.fidMajor & -0x10) == 0xe0)
|
||||
{
|
||||
// TODO (it's only for AVC, some ATX data may be lost)
|
||||
while (es.isfull(old_size))
|
||||
|
@ -626,22 +736,23 @@ u32 dmuxOpen(Demuxer* data)
|
|||
esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_FLUSH_DONE;
|
||||
esMsg->supplementalInfo = stream.userdata;
|
||||
es.cbFunc.call(*dmux.dmuxCb, dmux.id, es.id, esMsg, es.cbArg);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case dmuxResetEs:
|
||||
{
|
||||
task.es.es_ptr->reset();
|
||||
break;
|
||||
}
|
||||
|
||||
case dmuxClose:
|
||||
{
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case dmuxClose: break;
|
||||
|
||||
default:
|
||||
{
|
||||
cellDmux->Error("Demuxer thread error: unknown task(%d)", task.type);
|
||||
Emu.Pause();
|
||||
return;
|
||||
DMUX_ERROR("Demuxer thread error: unknown task (0x%x)", task.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -288,15 +288,8 @@ enum
|
|||
PACKET_START_CODE_MASK = 0xffffff00,
|
||||
PACKET_START_CODE_PREFIX = 0x00000100,
|
||||
|
||||
USER_DATA_START_CODE = 0x000001b2,
|
||||
SEQUENCE_START_CODE = 0x000001b3,
|
||||
EXT_START_CODE = 0x000001b5,
|
||||
SEQUENCE_END_CODE = 0x000001b7,
|
||||
GOP_START_CODE = 0x000001b8,
|
||||
ISO_11172_END_CODE = 0x000001b9,
|
||||
PACK_START_CODE = 0x000001ba,
|
||||
SYSTEM_HEADER_START_CODE = 0x000001bb,
|
||||
PROGRAM_STREAM_MAP = 0x000001bc,
|
||||
PRIVATE_STREAM_1 = 0x000001bd,
|
||||
PADDING_STREAM = 0x000001be,
|
||||
PRIVATE_STREAM_2 = 0x000001bf,
|
||||
|
@ -336,6 +329,11 @@ struct DemuxerStream
|
|||
size = size > count ? size - count : 0;
|
||||
}
|
||||
|
||||
bool check(u32 count) const
|
||||
{
|
||||
return count <= size;
|
||||
}
|
||||
|
||||
u64 get_ts(u8 c)
|
||||
{
|
||||
u8 v[4]; get((u32&)v);
|
||||
|
@ -345,12 +343,6 @@ struct DemuxerStream
|
|||
(((u64)v[1] & 0x7e) << 15) |
|
||||
(((u64)v[2]) << 7) | ((u64)v[3] >> 1);
|
||||
}
|
||||
|
||||
u64 get_ts()
|
||||
{
|
||||
u8 v; get(v);
|
||||
return get_ts(v);
|
||||
}
|
||||
};
|
||||
|
||||
struct PesHeader
|
||||
|
@ -359,6 +351,7 @@ struct PesHeader
|
|||
u64 dts;
|
||||
u8 size;
|
||||
bool has_ts;
|
||||
bool is_ok;
|
||||
|
||||
PesHeader(DemuxerStream& stream);
|
||||
};
|
||||
|
@ -446,6 +439,8 @@ class ElementaryStream
|
|||
bool is_full(u32 space);
|
||||
|
||||
public:
|
||||
ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr<CellDmuxCbEsMsg> cbFunc, u32 cbArg, u32 spec);
|
||||
|
||||
Demuxer* dmux;
|
||||
u32 id;
|
||||
const u32 memAddr;
|
||||
|
@ -465,27 +460,6 @@ public:
|
|||
|
||||
void push(DemuxerStream& stream, u32 size); // called by demuxer thread (not multithread-safe)
|
||||
|
||||
ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr<CellDmuxCbEsMsg> cbFunc, u32 cbArg, u32 spec)
|
||||
: dmux(dmux)
|
||||
, memAddr(a128(addr))
|
||||
, memSize(size - (addr - memAddr))
|
||||
, fidMajor(fidMajor)
|
||||
, fidMinor(fidMinor)
|
||||
, sup1(sup1)
|
||||
, sup2(sup2)
|
||||
, cbFunc(cbFunc)
|
||||
, cbArg(cbArg)
|
||||
, spec(spec)
|
||||
, put(memAddr)
|
||||
, put_count(0)
|
||||
, got_count(0)
|
||||
, released(0)
|
||||
, raw_pos(0)
|
||||
, last_dts(0xffffffffffffffffull)
|
||||
, last_pts(0xffffffffffffffffull)
|
||||
{
|
||||
}
|
||||
|
||||
bool isfull(u32 space);
|
||||
|
||||
void push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool rap, u32 specific);
|
||||
|
|
|
@ -1,157 +1,201 @@
|
|||
#include "stdafx.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/SysCalls/Modules.h"
|
||||
|
||||
#include "cellPamf.h"
|
||||
|
||||
Module *cellPamf = nullptr;
|
||||
|
||||
int pamfStreamTypeToEsFilterId(u8 type, u8 ch, vm::ptr<CellCodecEsFilterId> pEsFilterId)
|
||||
s32 pamfStreamTypeToEsFilterId(u8 type, u8 ch, CellCodecEsFilterId& pEsFilterId)
|
||||
{
|
||||
//TODO: convert type and ch to EsFilterId
|
||||
pEsFilterId->filterIdMajor = 0;
|
||||
pEsFilterId->filterIdMinor = 0;
|
||||
pEsFilterId->supplementalInfo1 = 0;
|
||||
pEsFilterId->supplementalInfo2 = 0;
|
||||
|
||||
// convert type and ch to EsFilterId
|
||||
assert(ch < 16);
|
||||
pEsFilterId.supplementalInfo1 = type == CELL_PAMF_STREAM_TYPE_AVC;
|
||||
pEsFilterId.supplementalInfo2 = 0;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case CELL_PAMF_STREAM_TYPE_AVC:
|
||||
{
|
||||
if (ch < 16)
|
||||
{
|
||||
pEsFilterId->filterIdMajor = 0xe0 + ch;
|
||||
pEsFilterId->filterIdMinor = 0;
|
||||
pEsFilterId->supplementalInfo1 = 0x01;
|
||||
pEsFilterId->supplementalInfo2 = 0;
|
||||
}
|
||||
else
|
||||
cellPamf->Error("pamfStreamTypeToEsFilterId: invalid CELL_PAMF_STREAM_TYPE_AVC channel (ch=%d)", ch);
|
||||
}
|
||||
break;
|
||||
case CELL_PAMF_STREAM_TYPE_ATRAC3PLUS:
|
||||
if (ch == 0)
|
||||
{
|
||||
pEsFilterId->filterIdMajor = 0xbd;
|
||||
pEsFilterId->filterIdMinor = 0;
|
||||
pEsFilterId->supplementalInfo1 = 0;
|
||||
pEsFilterId->supplementalInfo2 = 0;
|
||||
}
|
||||
else
|
||||
cellPamf->Todo("pamfStreamTypeToEsFilterId: CELL_PAMF_STREAM_TYPE_ATRAC3PLUS (ch=%d)", ch);
|
||||
break;
|
||||
case CELL_PAMF_STREAM_TYPE_PAMF_LPCM:
|
||||
if (ch == 0)
|
||||
{
|
||||
pEsFilterId->filterIdMajor = 0xbd;
|
||||
pEsFilterId->filterIdMinor = 0x40;
|
||||
pEsFilterId->supplementalInfo1 = 0;
|
||||
pEsFilterId->supplementalInfo2 = 0;
|
||||
}
|
||||
else
|
||||
cellPamf->Todo("pamfStreamTypeToEsFilterId: CELL_PAMF_STREAM_TYPE_LPCM (ch=%d)", ch);
|
||||
break;
|
||||
case CELL_PAMF_STREAM_TYPE_USER_DATA:
|
||||
if (ch == 0)
|
||||
{
|
||||
pEsFilterId->filterIdMajor = 0xbd;
|
||||
pEsFilterId->filterIdMinor = 0x20;
|
||||
pEsFilterId->supplementalInfo1 = 0;
|
||||
pEsFilterId->supplementalInfo2 = 0;
|
||||
}
|
||||
else
|
||||
cellPamf->Todo("pamfStreamTypeToEsFilterId: CELL_PAMF_STREAM_TYPE_USER_DATA (ch=%d)", ch);
|
||||
break;
|
||||
case CELL_PAMF_STREAM_TYPE_AC3:
|
||||
cellPamf->Todo("pamfStreamTypeToEsFilterId: CELL_PAMF_STREAM_TYPE_AC3 (ch=%d)", ch);
|
||||
{
|
||||
// code = 0x1b
|
||||
pEsFilterId.filterIdMajor = 0xe0 | ch;
|
||||
pEsFilterId.filterIdMinor = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_PAMF_STREAM_TYPE_M2V:
|
||||
cellPamf->Todo("pamfStreamTypeToEsFilterId: CELL_PAMF_STREAM_TYPE_M2V (ch=%d)", ch);
|
||||
{
|
||||
// code = 0x02
|
||||
pEsFilterId.filterIdMajor = 0xe0 | ch;
|
||||
pEsFilterId.filterIdMinor = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_PAMF_STREAM_TYPE_ATRAC3PLUS:
|
||||
{
|
||||
// code = 0xdc
|
||||
pEsFilterId.filterIdMajor = 0xbd;
|
||||
pEsFilterId.filterIdMinor = ch;
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_PAMF_STREAM_TYPE_PAMF_LPCM:
|
||||
{
|
||||
// code = 0x80
|
||||
pEsFilterId.filterIdMajor = 0xbd;
|
||||
pEsFilterId.filterIdMinor = 0x40 | ch;
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_PAMF_STREAM_TYPE_AC3:
|
||||
{
|
||||
// code = 0x81
|
||||
pEsFilterId.filterIdMajor = 0xbd;
|
||||
pEsFilterId.filterIdMinor = 0x30 | ch;
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_PAMF_STREAM_TYPE_USER_DATA:
|
||||
{
|
||||
// code = 0xdd
|
||||
pEsFilterId.filterIdMajor = 0xbd;
|
||||
pEsFilterId.filterIdMinor = 0x20 | ch;
|
||||
break;
|
||||
}
|
||||
|
||||
case 6:
|
||||
{
|
||||
// code = 0xff
|
||||
pEsFilterId.filterIdMajor = 0xe0 | ch;
|
||||
pEsFilterId.filterIdMinor = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case 7:
|
||||
{
|
||||
// code = 0xff
|
||||
pEsFilterId.filterIdMajor = 0xbd;
|
||||
pEsFilterId.filterIdMinor = ch;
|
||||
break;
|
||||
}
|
||||
|
||||
case 8:
|
||||
{
|
||||
// code = 0xff
|
||||
pEsFilterId.filterIdMajor = 0xbd;
|
||||
pEsFilterId.filterIdMinor = 0x10 | ch;
|
||||
break;
|
||||
}
|
||||
|
||||
case 9:
|
||||
{
|
||||
// code = 0xff
|
||||
pEsFilterId.filterIdMajor = 0xbd;
|
||||
pEsFilterId.filterIdMinor = 0x20 | ch;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
cellPamf->Error("pamfStreamTypeToEsFilterId(): unknown type (%d, ch=%d)", type, ch);
|
||||
Emu.Pause();
|
||||
return CELL_PAMF_ERROR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
u8 pamfGetStreamType(vm::ptr<CellPamfReader> pSelf, u8 stream)
|
||||
{
|
||||
//TODO: get stream type correctly
|
||||
switch (pSelf->pAddr->stream_headers[stream].type)
|
||||
// TODO: get stream type correctly
|
||||
auto& header = pSelf->pAddr->stream_headers[stream];
|
||||
|
||||
switch (header.type)
|
||||
{
|
||||
case 0x1b: return CELL_PAMF_STREAM_TYPE_AVC;
|
||||
case 0x02: return CELL_PAMF_STREAM_TYPE_M2V;
|
||||
case 0xdc: return CELL_PAMF_STREAM_TYPE_ATRAC3PLUS;
|
||||
case 0x80: return CELL_PAMF_STREAM_TYPE_PAMF_LPCM;
|
||||
case 0x81: return CELL_PAMF_STREAM_TYPE_AC3;
|
||||
case 0xdd: return CELL_PAMF_STREAM_TYPE_USER_DATA;
|
||||
default:
|
||||
cellPamf->Todo("pamfGetStreamType: unsupported stream type found(0x%x)", pSelf->pAddr->stream_headers[stream].type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cellPamf->Todo("pamfGetStreamType(): unsupported stream type found(0x%x)", header.type);
|
||||
Emu.Pause();
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
u8 pamfGetStreamChannel(vm::ptr<CellPamfReader> pSelf, u8 stream)
|
||||
{
|
||||
//TODO: get stream channel correctly
|
||||
// TODO: get stream channel correctly
|
||||
auto& header = pSelf->pAddr->stream_headers[stream];
|
||||
|
||||
switch (pSelf->pAddr->stream_headers[stream].type)
|
||||
switch (header.type)
|
||||
{
|
||||
case 0x1b:
|
||||
if ((pSelf->pAddr->stream_headers[stream].stream_id >= 0xe0) && (pSelf->pAddr->stream_headers[stream].stream_id <= 0xef))
|
||||
{
|
||||
return pSelf->pAddr->stream_headers[stream].stream_id - 0xe0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cellPamf->Error("pamfGetStreamChannel: stream type 0x%x got invalid stream id=0x%x",
|
||||
pSelf->pAddr->stream_headers[stream].type, pSelf->pAddr->stream_headers[stream].stream_id);
|
||||
return 0;
|
||||
}
|
||||
case 0xdc:
|
||||
cellPamf->Todo("pamfGetStreamChannel: CELL_PAMF_STREAM_TYPE_ATRAC3PLUS");
|
||||
return 0;
|
||||
case 0x80:
|
||||
cellPamf->Todo("pamfGetStreamChannel: CELL_PAMF_STREAM_TYPE_PAMF_LPCM");
|
||||
return 0;
|
||||
case 0x1b: // AVC
|
||||
case 0x02: // M2V
|
||||
{
|
||||
assert((header.fid_major & 0xf0) == 0xe0 && header.fid_minor == 0);
|
||||
return header.fid_major % 16;
|
||||
}
|
||||
|
||||
case 0xdc: // ATRAC3PLUS
|
||||
{
|
||||
assert(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0);
|
||||
return header.fid_minor % 16;
|
||||
}
|
||||
|
||||
case 0x80: // LPCM
|
||||
{
|
||||
assert(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x40);
|
||||
return header.fid_minor % 16;
|
||||
}
|
||||
case 0x81: // AC3
|
||||
{
|
||||
assert(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x30);
|
||||
return header.fid_minor % 16;
|
||||
}
|
||||
case 0xdd:
|
||||
cellPamf->Todo("pamfGetStreamChannel: CELL_PAMF_STREAM_TYPE_USER_DATA");
|
||||
return 0;
|
||||
default:
|
||||
cellPamf->Todo("pamfGetStreamType: unsupported stream type found(0x%x)", pSelf->pAddr->stream_headers[stream].type);
|
||||
return 0;
|
||||
{
|
||||
assert(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x20);
|
||||
return header.fid_minor % 16;
|
||||
}
|
||||
}
|
||||
|
||||
cellPamf->Todo("pamfGetStreamChannel(): unsupported stream type found(0x%x)", header.type);
|
||||
Emu.Pause();
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
int cellPamfGetHeaderSize(vm::ptr<PamfHeader> pAddr, u64 fileSize, vm::ptr<u64> pSize)
|
||||
s32 cellPamfGetHeaderSize(vm::ptr<PamfHeader> pAddr, u64 fileSize, vm::ptr<u64> pSize)
|
||||
{
|
||||
cellPamf->Warning("cellPamfGetHeaderSize(pAddr=0x%x, fileSize=%d, pSize_addr=0x%x)", pAddr.addr(), fileSize, pSize.addr());
|
||||
|
||||
//if ((u32)pAddr->magic != 0x464d4150)
|
||||
//return CELL_PAMF_ERROR_UNKNOWN_TYPE;
|
||||
//if ((u32)pAddr->magic != 0x464d4150) return CELL_PAMF_ERROR_UNKNOWN_TYPE;
|
||||
|
||||
const u64 offset = (u64)pAddr->data_offset << 11;
|
||||
*pSize = offset;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfGetHeaderSize2(vm::ptr<PamfHeader> pAddr, u64 fileSize, u32 attribute, vm::ptr<u64> pSize)
|
||||
s32 cellPamfGetHeaderSize2(vm::ptr<PamfHeader> pAddr, u64 fileSize, u32 attribute, vm::ptr<u64> pSize)
|
||||
{
|
||||
cellPamf->Warning("cellPamfGetHeaderSize2(pAddr=0x%x, fileSize=%d, attribute=0x%x, pSize_addr=0x%x)", pAddr.addr(), fileSize, attribute, pSize.addr());
|
||||
|
||||
//if ((u32)pAddr->magic != 0x464d4150)
|
||||
//return CELL_PAMF_ERROR_UNKNOWN_TYPE;
|
||||
//if ((u32)pAddr->magic != 0x464d4150) return CELL_PAMF_ERROR_UNKNOWN_TYPE;
|
||||
|
||||
const u64 offset = (u64)pAddr->data_offset << 11;
|
||||
*pSize = offset;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfGetStreamOffsetAndSize(vm::ptr<PamfHeader> pAddr, u64 fileSize, vm::ptr<u64> pOffset, vm::ptr<u64> pSize)
|
||||
s32 cellPamfGetStreamOffsetAndSize(vm::ptr<PamfHeader> pAddr, u64 fileSize, vm::ptr<u64> pOffset, vm::ptr<u64> pSize)
|
||||
{
|
||||
cellPamf->Warning("cellPamfGetStreamOffsetAndSize(pAddr=0x%x, fileSize=%d, pOffset_addr=0x%x, pSize_addr=0x%x)", pAddr.addr(), fileSize, pOffset.addr(), pSize.addr());
|
||||
|
||||
//if ((u32)pAddr->magic != 0x464d4150)
|
||||
//return CELL_PAMF_ERROR_UNKNOWN_TYPE;
|
||||
//if ((u32)pAddr->magic != 0x464d4150) return CELL_PAMF_ERROR_UNKNOWN_TYPE;
|
||||
|
||||
const u64 offset = (u64)pAddr->data_offset << 11;
|
||||
*pOffset = offset;
|
||||
|
@ -160,14 +204,15 @@ int cellPamfGetStreamOffsetAndSize(vm::ptr<PamfHeader> pAddr, u64 fileSize, vm::
|
|||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfVerify(vm::ptr<PamfHeader> pAddr, u64 fileSize)
|
||||
s32 cellPamfVerify(vm::ptr<PamfHeader> pAddr, u64 fileSize)
|
||||
{
|
||||
cellPamf->Warning("cellPamfVerify(pAddr=0x%x, fileSize=%d)", pAddr.addr(), fileSize);
|
||||
cellPamf->Todo("cellPamfVerify(pAddr=0x%x, fileSize=%d)", pAddr.addr(), fileSize);
|
||||
|
||||
// TODO
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfReaderInitialize(vm::ptr<CellPamfReader> pSelf, vm::ptr<const PamfHeader> pAddr, u64 fileSize, u32 attribute)
|
||||
s32 cellPamfReaderInitialize(vm::ptr<CellPamfReader> pSelf, vm::ptr<const PamfHeader> pAddr, u64 fileSize, u32 attribute)
|
||||
{
|
||||
cellPamf->Warning("cellPamfReaderInitialize(pSelf=0x%x, pAddr=0x%x, fileSize=%d, attribute=0x%x)", pSelf.addr(), pAddr.addr(), fileSize, attribute);
|
||||
|
||||
|
@ -175,7 +220,7 @@ int cellPamfReaderInitialize(vm::ptr<CellPamfReader> pSelf, vm::ptr<const PamfHe
|
|||
{
|
||||
pSelf->fileSize = fileSize;
|
||||
}
|
||||
else //if fileSize is unknown
|
||||
else // if fileSize is unknown
|
||||
{
|
||||
pSelf->fileSize = ((u64)pAddr->data_offset << 11) + ((u64)pAddr->data_size << 11);
|
||||
}
|
||||
|
@ -183,70 +228,59 @@ int cellPamfReaderInitialize(vm::ptr<CellPamfReader> pSelf, vm::ptr<const PamfHe
|
|||
|
||||
if (attribute & CELL_PAMF_ATTRIBUTE_VERIFY_ON)
|
||||
{
|
||||
//TODO
|
||||
// TODO
|
||||
cellPamf->Todo("cellPamfReaderInitialize(): verification");
|
||||
}
|
||||
|
||||
pSelf->stream = 0; //??? currently set stream
|
||||
pSelf->stream = 0; // currently set stream
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfReaderGetPresentationStartTime(vm::ptr<CellPamfReader> pSelf, vm::ptr<CellCodecTimeStamp> pTimeStamp)
|
||||
s32 cellPamfReaderGetPresentationStartTime(vm::ptr<CellPamfReader> pSelf, vm::ptr<CellCodecTimeStamp> pTimeStamp)
|
||||
{
|
||||
cellPamf->Warning("cellPamfReaderGetPresentationStartTime(pSelf=0x%x, pTimeStamp_addr=0x%x)", pSelf.addr(), pTimeStamp.addr());
|
||||
|
||||
if (!pSelf->pAddr) {
|
||||
return CELL_PAMF_ERROR_INVALID_PAMF;
|
||||
}
|
||||
// always returns CELL_OK
|
||||
|
||||
pTimeStamp->upper = (u32)(u16)pSelf->pAddr->start_pts_high;
|
||||
pTimeStamp->lower = pSelf->pAddr->start_pts_low;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfReaderGetPresentationEndTime(vm::ptr<CellPamfReader> pSelf, vm::ptr<CellCodecTimeStamp> pTimeStamp)
|
||||
s32 cellPamfReaderGetPresentationEndTime(vm::ptr<CellPamfReader> pSelf, vm::ptr<CellCodecTimeStamp> pTimeStamp)
|
||||
{
|
||||
cellPamf->Warning("cellPamfReaderGetPresentationEndTime(pSelf=0x%x, pTimeStamp_addr=0x%x)", pSelf.addr(), pTimeStamp.addr());
|
||||
|
||||
if (!pSelf->pAddr) {
|
||||
return CELL_PAMF_ERROR_INVALID_PAMF;
|
||||
}
|
||||
// always returns CELL_OK
|
||||
|
||||
pTimeStamp->upper = (u32)(u16)pSelf->pAddr->end_pts_high;
|
||||
pTimeStamp->lower = pSelf->pAddr->end_pts_low;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfReaderGetMuxRateBound(vm::ptr<CellPamfReader> pSelf)
|
||||
u32 cellPamfReaderGetMuxRateBound(vm::ptr<CellPamfReader> pSelf)
|
||||
{
|
||||
cellPamf->Warning("cellPamfReaderGetMuxRateBound(pSelf=0x%x)", pSelf.addr());
|
||||
|
||||
if (!pSelf->pAddr) {
|
||||
return CELL_PAMF_ERROR_INVALID_PAMF;
|
||||
}
|
||||
|
||||
// cannot return error code
|
||||
return pSelf->pAddr->mux_rate_max;
|
||||
}
|
||||
|
||||
int cellPamfReaderGetNumberOfStreams(vm::ptr<CellPamfReader> pSelf)
|
||||
u8 cellPamfReaderGetNumberOfStreams(vm::ptr<CellPamfReader> pSelf)
|
||||
{
|
||||
cellPamf->Warning("cellPamfReaderGetNumberOfStreams(pSelf=0x%x)", pSelf.addr());
|
||||
|
||||
if (!pSelf->pAddr) {
|
||||
return CELL_PAMF_ERROR_INVALID_PAMF;
|
||||
}
|
||||
|
||||
// cannot return error code
|
||||
return pSelf->pAddr->stream_count;
|
||||
}
|
||||
|
||||
int cellPamfReaderGetNumberOfSpecificStreams(vm::ptr<CellPamfReader> pSelf, u8 streamType)
|
||||
u8 cellPamfReaderGetNumberOfSpecificStreams(vm::ptr<CellPamfReader> pSelf, u8 streamType)
|
||||
{
|
||||
cellPamf->Warning("cellPamfReaderGetNumberOfSpecificStreams(pSelf=0x%x, streamType=%d)", pSelf.addr(), streamType);
|
||||
|
||||
if (!pSelf->pAddr) {
|
||||
return CELL_PAMF_ERROR_INVALID_PAMF;
|
||||
}
|
||||
// cannot return error code
|
||||
|
||||
int counts[6] = {0, 0, 0, 0, 0, 0};
|
||||
u8 counts[256] = {};
|
||||
|
||||
for (u8 i = 0; i < pSelf->pAddr->stream_count; i++)
|
||||
{
|
||||
|
@ -261,46 +295,48 @@ int cellPamfReaderGetNumberOfSpecificStreams(vm::ptr<CellPamfReader> pSelf, u8 s
|
|||
case CELL_PAMF_STREAM_TYPE_PAMF_LPCM:
|
||||
case CELL_PAMF_STREAM_TYPE_AC3:
|
||||
case CELL_PAMF_STREAM_TYPE_USER_DATA:
|
||||
{
|
||||
return counts[streamType];
|
||||
case CELL_PAMF_STREAM_TYPE_VIDEO:
|
||||
return counts[CELL_PAMF_STREAM_TYPE_AVC] + counts[CELL_PAMF_STREAM_TYPE_M2V];
|
||||
case CELL_PAMF_STREAM_TYPE_AUDIO:
|
||||
return counts[CELL_PAMF_STREAM_TYPE_ATRAC3PLUS] + counts[CELL_PAMF_STREAM_TYPE_PAMF_LPCM] + counts[CELL_PAMF_STREAM_TYPE_AC3];
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
case CELL_PAMF_STREAM_TYPE_VIDEO:
|
||||
{
|
||||
return counts[CELL_PAMF_STREAM_TYPE_AVC] + counts[CELL_PAMF_STREAM_TYPE_M2V];
|
||||
}
|
||||
|
||||
case CELL_PAMF_STREAM_TYPE_AUDIO:
|
||||
{
|
||||
return counts[CELL_PAMF_STREAM_TYPE_ATRAC3PLUS] + counts[CELL_PAMF_STREAM_TYPE_PAMF_LPCM] + counts[CELL_PAMF_STREAM_TYPE_AC3];
|
||||
}
|
||||
}
|
||||
|
||||
cellPamf->Todo("cellPamfReaderGetNumberOfSpecificStreams(): unsupported stream type (0x%x)", streamType);
|
||||
Emu.Pause();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cellPamfReaderSetStreamWithIndex(vm::ptr<CellPamfReader> pSelf, u8 streamIndex)
|
||||
s32 cellPamfReaderSetStreamWithIndex(vm::ptr<CellPamfReader> pSelf, u8 streamIndex)
|
||||
{
|
||||
cellPamf->Warning("cellPamfReaderSetStreamWithIndex(pSelf=0x%x, streamIndex=%d)", pSelf.addr(), streamIndex);
|
||||
|
||||
if (!pSelf->pAddr) {
|
||||
return CELL_PAMF_ERROR_INVALID_PAMF;
|
||||
}
|
||||
|
||||
if (streamIndex < pSelf->pAddr->stream_count)
|
||||
if (streamIndex >= pSelf->pAddr->stream_count)
|
||||
{
|
||||
pSelf->stream = streamIndex;
|
||||
return CELL_OK;
|
||||
return CELL_PAMF_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
cellPamf->Error("cellPamfReaderSetStreamWithIndex: CELL_PAMF_ERROR_INVALID_ARG");
|
||||
return CELL_PAMF_ERROR_INVALID_ARG;
|
||||
pSelf->stream = streamIndex;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfReaderSetStreamWithTypeAndChannel(vm::ptr<CellPamfReader> pSelf, u8 streamType, u8 ch)
|
||||
s32 cellPamfReaderSetStreamWithTypeAndChannel(vm::ptr<CellPamfReader> pSelf, u8 streamType, u8 ch)
|
||||
{
|
||||
cellPamf->Warning("cellPamfReaderSetStreamWithTypeAndChannel(pSelf=0x%x, streamType=%d, ch=%d)", pSelf.addr(), streamType, ch);
|
||||
|
||||
if (!pSelf->pAddr) {
|
||||
return CELL_PAMF_ERROR_INVALID_PAMF;
|
||||
}
|
||||
|
||||
if (streamType > 5)
|
||||
// it probably doesn't support "any audio" or "any video" argument
|
||||
if (streamType > 5 || ch >= 16)
|
||||
{
|
||||
cellPamf->Error("cellPamfReaderSetStreamWithTypeAndChannel: invalid stream type(%d)", streamType);
|
||||
//it probably doesn't support "any audio" or "any video" argument
|
||||
cellPamf->Error("cellPamfReaderSetStreamWithTypeAndChannel(): invalid arguments (streamType=%d, ch=%d)", streamType, ch);
|
||||
Emu.Pause();
|
||||
return CELL_PAMF_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
|
@ -319,14 +355,10 @@ int cellPamfReaderSetStreamWithTypeAndChannel(vm::ptr<CellPamfReader> pSelf, u8
|
|||
return CELL_PAMF_ERROR_STREAM_NOT_FOUND;
|
||||
}
|
||||
|
||||
int cellPamfReaderSetStreamWithTypeAndIndex(vm::ptr<CellPamfReader> pSelf, u8 streamType, u8 streamIndex)
|
||||
s32 cellPamfReaderSetStreamWithTypeAndIndex(vm::ptr<CellPamfReader> pSelf, u8 streamType, u8 streamIndex)
|
||||
{
|
||||
cellPamf->Warning("cellPamfReaderSetStreamWithTypeAndIndex(pSelf=0x%x, streamType=%d, streamIndex=%d)", pSelf.addr(), streamType, streamIndex);
|
||||
|
||||
if (!pSelf->pAddr) {
|
||||
return CELL_PAMF_ERROR_INVALID_PAMF;
|
||||
}
|
||||
|
||||
u32 found = 0;
|
||||
|
||||
for (u8 i = 0; i < pSelf->pAddr->stream_count; i++)
|
||||
|
@ -340,23 +372,31 @@ int cellPamfReaderSetStreamWithTypeAndIndex(vm::ptr<CellPamfReader> pSelf, u8 st
|
|||
else switch(streamType)
|
||||
{
|
||||
case CELL_PAMF_STREAM_TYPE_VIDEO:
|
||||
if (type == CELL_PAMF_STREAM_TYPE_AVC || type == CELL_PAMF_STREAM_TYPE_M2V)
|
||||
{
|
||||
if (type == CELL_PAMF_STREAM_TYPE_AVC || type == CELL_PAMF_STREAM_TYPE_M2V)
|
||||
{
|
||||
found++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_PAMF_STREAM_TYPE_AUDIO:
|
||||
{
|
||||
if (type == CELL_PAMF_STREAM_TYPE_ATRAC3PLUS || type == CELL_PAMF_STREAM_TYPE_AC3 || type == CELL_PAMF_STREAM_TYPE_PAMF_LPCM)
|
||||
{
|
||||
found++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
if (streamType > 5)
|
||||
{
|
||||
return CELL_PAMF_ERROR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found > streamIndex)
|
||||
{
|
||||
|
@ -368,46 +408,57 @@ int cellPamfReaderSetStreamWithTypeAndIndex(vm::ptr<CellPamfReader> pSelf, u8 st
|
|||
return CELL_PAMF_ERROR_STREAM_NOT_FOUND;
|
||||
}
|
||||
|
||||
int cellPamfStreamTypeToEsFilterId(u8 type, u8 ch, vm::ptr<CellCodecEsFilterId> pEsFilterId)
|
||||
s32 cellPamfStreamTypeToEsFilterId(u8 type, u8 ch, vm::ptr<CellCodecEsFilterId> pEsFilterId)
|
||||
{
|
||||
cellPamf->Warning("cellPamfStreamTypeToEsFilterId(type=%d, ch=%d, pEsFilterId_addr=0x%x)", type, ch, pEsFilterId.addr());
|
||||
|
||||
if (!pEsFilterId)
|
||||
{
|
||||
return CELL_PAMF_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
return pamfStreamTypeToEsFilterId(type, ch, pEsFilterId);
|
||||
return pamfStreamTypeToEsFilterId(type, ch, *pEsFilterId);
|
||||
}
|
||||
|
||||
int cellPamfReaderGetStreamIndex(vm::ptr<CellPamfReader> pSelf)
|
||||
s32 cellPamfReaderGetStreamIndex(vm::ptr<CellPamfReader> pSelf)
|
||||
{
|
||||
cellPamf->Log("cellPamfReaderGetStreamIndex(pSelf=0x%x)", pSelf.addr());
|
||||
|
||||
// seems that CELL_PAMF_ERROR_INVALID_PAMF must be already written in pSelf->stream if it's the case
|
||||
return pSelf->stream;
|
||||
}
|
||||
|
||||
int cellPamfReaderGetStreamTypeAndChannel(vm::ptr<CellPamfReader> pSelf, vm::ptr<u8> pType, vm::ptr<u8> pCh)
|
||||
s32 cellPamfReaderGetStreamTypeAndChannel(vm::ptr<CellPamfReader> pSelf, vm::ptr<u8> pType, vm::ptr<u8> pCh)
|
||||
{
|
||||
cellPamf->Warning("cellPamfReaderGetStreamTypeAndChannel(pSelf=0x%x (stream=%d), pType_addr=0x%x, pCh_addr=0x%x",
|
||||
pSelf.addr(), pSelf->stream, pType.addr(), pCh.addr());
|
||||
|
||||
// unclear
|
||||
|
||||
*pType = pamfGetStreamType(pSelf, pSelf->stream);
|
||||
*pCh = pamfGetStreamChannel(pSelf, pSelf->stream);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfReaderGetEsFilterId(vm::ptr<CellPamfReader> pSelf, vm::ptr<CellCodecEsFilterId> pEsFilterId)
|
||||
s32 cellPamfReaderGetEsFilterId(vm::ptr<CellPamfReader> pSelf, vm::ptr<CellCodecEsFilterId> pEsFilterId)
|
||||
{
|
||||
cellPamf->Warning("cellPamfReaderGetEsFilterId(pSelf=0x%x (stream=%d), pEsFilterId_addr=0x%x)", pSelf.addr(), pSelf->stream, pEsFilterId.addr());
|
||||
|
||||
return pamfStreamTypeToEsFilterId(pamfGetStreamType(pSelf, pSelf->stream),
|
||||
pamfGetStreamChannel(pSelf, pSelf->stream), pEsFilterId);
|
||||
// always returns CELL_OK
|
||||
|
||||
auto& header = pSelf->pAddr->stream_headers[pSelf->stream];
|
||||
pEsFilterId->filterIdMajor = header.fid_major;
|
||||
pEsFilterId->filterIdMinor = header.fid_minor;
|
||||
pEsFilterId->supplementalInfo1 = header.type == 0x1b ? 1 : 0;
|
||||
pEsFilterId->supplementalInfo2 = 0;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfReaderGetStreamInfo(vm::ptr<CellPamfReader> pSelf, u32 pInfo_addr, u32 size)
|
||||
s32 cellPamfReaderGetStreamInfo(vm::ptr<CellPamfReader> pSelf, u32 pInfo_addr, u32 size)
|
||||
{
|
||||
cellPamf->Warning("cellPamfReaderGetStreamInfo(pSelf=0x%x, stream=%d, pInfo_addr=0x%x, size=%d)", pSelf.addr(), pSelf->stream, pInfo_addr, size);
|
||||
|
||||
if (!pSelf->pAddr) {
|
||||
return CELL_PAMF_ERROR_INVALID_PAMF;
|
||||
}
|
||||
|
||||
// TODO (many parameters are wrong)
|
||||
memset(vm::get_ptr<void>(pInfo_addr), 0, size);
|
||||
|
||||
switch (pamfGetStreamType(pSelf, pSelf->stream))
|
||||
|
@ -509,58 +560,46 @@ int cellPamfReaderGetStreamInfo(vm::ptr<CellPamfReader> pSelf, u32 pInfo_addr, u
|
|||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfReaderGetNumberOfEp(vm::ptr<CellPamfReader> pSelf)
|
||||
u32 cellPamfReaderGetNumberOfEp(vm::ptr<CellPamfReader> pSelf)
|
||||
{
|
||||
cellPamf->Warning("cellPamfReaderGetNumberOfEp(pSelf=0x%x, stream=%d)", pSelf.addr(), pSelf->stream);
|
||||
|
||||
if (!pSelf->pAddr) {
|
||||
return CELL_PAMF_ERROR_INVALID_PAMF;
|
||||
}
|
||||
|
||||
// cannot return error code
|
||||
return pSelf->pAddr->stream_headers[pSelf->stream].ep_num;
|
||||
}
|
||||
|
||||
int cellPamfReaderGetEpIteratorWithIndex(vm::ptr<CellPamfReader> pSelf, u32 epIndex, vm::ptr<CellPamfEpIterator> pIt)
|
||||
s32 cellPamfReaderGetEpIteratorWithIndex(vm::ptr<CellPamfReader> pSelf, u32 epIndex, vm::ptr<CellPamfEpIterator> pIt)
|
||||
{
|
||||
cellPamf->Todo("cellPamfReaderGetEpIteratorWithIndex(pSelf=0x%x, stream=%d, epIndex=%d, pIt_addr=0x%x)", pSelf.addr(), pSelf->stream, epIndex, pIt.addr());
|
||||
|
||||
if (!pSelf->pAddr) {
|
||||
return CELL_PAMF_ERROR_INVALID_PAMF;
|
||||
}
|
||||
|
||||
//TODO:
|
||||
// TODO
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfReaderGetEpIteratorWithTimeStamp(vm::ptr<CellPamfReader> pSelf, vm::ptr<CellCodecTimeStamp> pTimeStamp, vm::ptr<CellPamfEpIterator> pIt)
|
||||
s32 cellPamfReaderGetEpIteratorWithTimeStamp(vm::ptr<CellPamfReader> pSelf, vm::ptr<CellCodecTimeStamp> pTimeStamp, vm::ptr<CellPamfEpIterator> pIt)
|
||||
{
|
||||
cellPamf->Todo("cellPamfReaderGetEpIteratorWithTimeStamp(pSelf=0x%x, pTimeStamp_addr=0x%x, pIt_addr=0x%x)", pSelf.addr(), pTimeStamp.addr(), pIt.addr());
|
||||
|
||||
if (!pSelf->pAddr) {
|
||||
return CELL_PAMF_ERROR_INVALID_PAMF;
|
||||
}
|
||||
|
||||
//TODO:
|
||||
|
||||
// TODO
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfEpIteratorGetEp(vm::ptr<CellPamfEpIterator> pIt, vm::ptr<CellPamfEp> pEp)
|
||||
s32 cellPamfEpIteratorGetEp(vm::ptr<CellPamfEpIterator> pIt, vm::ptr<CellPamfEp> pEp)
|
||||
{
|
||||
cellPamf->Todo("cellPamfEpIteratorGetEp(pIt_addr=0x%x, pEp_addr=0x%x)", pIt.addr(), pEp.addr());
|
||||
|
||||
//TODO:
|
||||
|
||||
// always returns CELL_OK
|
||||
// TODO
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfEpIteratorMove(vm::ptr<CellPamfEpIterator> pIt, s32 steps, vm::ptr<CellPamfEp> pEp)
|
||||
s32 cellPamfEpIteratorMove(vm::ptr<CellPamfEpIterator> pIt, s32 steps, vm::ptr<CellPamfEp> pEp)
|
||||
{
|
||||
cellPamf->Todo("cellPamfEpIteratorMove(pIt_addr=0x%x, steps=%d, pEp_addr=0x%x)", pIt.addr(), steps, pEp.addr());
|
||||
|
||||
//TODO:
|
||||
|
||||
return CELL_OK;
|
||||
// cannot return error code
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cellPamf_init(Module *pxThis)
|
||||
|
|
|
@ -141,6 +141,8 @@ struct CellCodecTimeStamp
|
|||
be_t<u32> lower;
|
||||
};
|
||||
|
||||
static const u64 CODEC_TS_INVALID = 0xffffffffffffffffull;
|
||||
|
||||
// Entry point information
|
||||
struct CellPamfEp
|
||||
{
|
||||
|
@ -168,7 +170,8 @@ struct CellCodecEsFilterId
|
|||
};
|
||||
|
||||
// AVC (MPEG4 AVC Video) Specific Information
|
||||
struct CellPamfAvcInfo {
|
||||
struct CellPamfAvcInfo
|
||||
{
|
||||
u8 profileIdc;
|
||||
u8 levelIdc;
|
||||
u8 frameMbsOnlyFlag;
|
||||
|
@ -196,7 +199,8 @@ struct CellPamfAvcInfo {
|
|||
};
|
||||
|
||||
// M2V (MPEG2 Video) Specific Information
|
||||
struct CellPamfM2vInfo {
|
||||
struct CellPamfM2vInfo
|
||||
{
|
||||
u8 profileAndLevelIndication;
|
||||
bool progressiveSequence;
|
||||
u8 videoSignalInfoFlag;
|
||||
|
@ -216,27 +220,32 @@ struct CellPamfM2vInfo {
|
|||
};
|
||||
|
||||
// LPCM Audio Specific Information
|
||||
struct CellPamfLpcmInfo {
|
||||
struct CellPamfLpcmInfo
|
||||
{
|
||||
be_t<u32> samplingFrequency;
|
||||
u8 numberOfChannels;
|
||||
be_t<u16> bitsPerSample;
|
||||
};
|
||||
|
||||
// ATRAC3+ Audio Specific Information
|
||||
struct CellPamfAtrac3plusInfo {
|
||||
struct CellPamfAtrac3plusInfo
|
||||
{
|
||||
be_t<u32> samplingFrequency;
|
||||
u8 numberOfChannels;
|
||||
};
|
||||
|
||||
// AC3 Audio Specific Information
|
||||
struct CellPamfAc3Info {
|
||||
struct CellPamfAc3Info
|
||||
{
|
||||
be_t<u32> samplingFrequency;
|
||||
u8 numberOfChannels;
|
||||
};
|
||||
|
||||
#pragma pack(push, 1) //file data
|
||||
#pragma pack(push, 1) // file data
|
||||
|
||||
struct PamfStreamHeader_AVC { //AVC specific information
|
||||
// AVC specific information
|
||||
struct PamfStreamHeader_AVC
|
||||
{
|
||||
u8 profileIdc;
|
||||
u8 levelIdc;
|
||||
u8 unk0;
|
||||
|
@ -256,11 +265,15 @@ struct PamfStreamHeader_AVC { //AVC specific information
|
|||
u32 unk12; //0
|
||||
};
|
||||
|
||||
struct PamfStreamHeader_M2V { //M2V specific information
|
||||
u8 unknown[32]; //no information yet
|
||||
// M2V specific information
|
||||
struct PamfStreamHeader_M2V
|
||||
{
|
||||
u8 unknown[32];
|
||||
};
|
||||
|
||||
struct PamfStreamHeader_Audio { //Audio specific information
|
||||
// Audio specific information
|
||||
struct PamfStreamHeader_Audio
|
||||
{
|
||||
u16 unknown; //== 0
|
||||
u8 channels; //number of channels (1, 2, 6 or 8)
|
||||
u8 freq; //== 1 (always 48000)
|
||||
|
@ -268,14 +281,14 @@ struct PamfStreamHeader_Audio { //Audio specific information
|
|||
u8 reserved[27]; //probably nothing
|
||||
};
|
||||
|
||||
struct PamfStreamHeader //48 bytes
|
||||
struct PamfStreamHeader
|
||||
{
|
||||
//TODO: look for correct beginning of stream header
|
||||
u8 type; //0x1B for video (AVC), 0xDC ATRAC3+, 0x80 LPCM, 0xDD userdata
|
||||
u8 unknown[3]; //0
|
||||
//TODO: examine stream_ch encoding
|
||||
u8 stream_id;
|
||||
u8 private_stream_id;
|
||||
u8 fid_major;
|
||||
u8 fid_minor;
|
||||
u8 unknown1; //?????
|
||||
u8 unknown2; //?????
|
||||
//Entry Point Info
|
||||
|
@ -285,6 +298,8 @@ struct PamfStreamHeader //48 bytes
|
|||
u8 data[32];
|
||||
};
|
||||
|
||||
static_assert(sizeof(PamfStreamHeader) == 48, "Invalid PamfStreamHeader size");
|
||||
|
||||
struct PamfHeader
|
||||
{
|
||||
u32 magic; //"PAMF"
|
||||
|
@ -317,21 +332,25 @@ struct PamfHeader
|
|||
PamfStreamHeader stream_headers[256];
|
||||
};
|
||||
|
||||
struct PamfEpHeader { //12 bytes
|
||||
struct PamfEpHeader
|
||||
{
|
||||
be_t<u16> value0; //mixed indexN (probably left 2 bits) and nThRefPictureOffset
|
||||
be_t<u16> pts_high;
|
||||
be_t<u32> pts_low;
|
||||
be_t<u32> rpnOffset;
|
||||
};
|
||||
|
||||
static_assert(sizeof(PamfEpHeader) == 12, "Invalid PamfEpHeader size");
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
// not directly accessed by virtual CPU, fields are unknown
|
||||
struct CellPamfReader
|
||||
{
|
||||
//this struct can be used in any way, if it is not accessed directly by virtual CPU
|
||||
//be_t<u64> internalData[16];
|
||||
vm::ptr<const PamfHeader> pAddr;
|
||||
int stream;
|
||||
s32 stream;
|
||||
u64 fileSize;
|
||||
u32 internalData[28];
|
||||
};
|
||||
};
|
||||
|
||||
static_assert(sizeof(CellPamfReader) == 128, "Invalid CellPamfReader size");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -19,6 +19,8 @@ extern "C"
|
|||
|
||||
Module *cellVdec = nullptr;
|
||||
|
||||
#define VDEC_ERROR(...) { cellVdec->Error(__VA_ARGS__); Emu.Pause(); return; } // only for decoder thread
|
||||
|
||||
VideoDecoder::VideoDecoder(CellVdecCodecType type, u32 profile, u32 addr, u32 size, vm::ptr<CellVdecCbMsg> func, u32 arg)
|
||||
: type(type)
|
||||
, profile(profile)
|
||||
|
@ -31,33 +33,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:
|
||||
{
|
||||
VDEC_ERROR("VideoDecoder(): unknown type (0x%x)", type);
|
||||
}
|
||||
}
|
||||
|
||||
if (!codec)
|
||||
{
|
||||
cellVdec->Error("VideoDecoder(): avcodec_find_decoder(H264) failed");
|
||||
Emu.Pause();
|
||||
return;
|
||||
VDEC_ERROR("VideoDecoder(): avcodec_find_decoder() failed");
|
||||
}
|
||||
if (!input_format)
|
||||
{
|
||||
VDEC_ERROR("VideoDecoder(): av_find_input_format() failed");
|
||||
}
|
||||
fmt = avformat_alloc_context();
|
||||
if (!fmt)
|
||||
{
|
||||
cellVdec->Error("VideoDecoder(): avformat_alloc_context failed");
|
||||
Emu.Pause();
|
||||
return;
|
||||
VDEC_ERROR("VideoDecoder(): avformat_alloc_context() failed");
|
||||
}
|
||||
io_buf = (u8*)av_malloc(4096);
|
||||
fmt->pb = avio_alloc_context(io_buf, 4096, 0, this, vdecRead, NULL, NULL);
|
||||
if (!fmt->pb)
|
||||
{
|
||||
cellVdec->Error("VideoDecoder(): avio_alloc_context failed");
|
||||
Emu.Pause();
|
||||
return;
|
||||
VDEC_ERROR("VideoDecoder(): avio_alloc_context() failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,8 +191,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 +253,10 @@ u32 vdecOpen(VideoDecoder* data)
|
|||
cellVdec->Warning("vdecStartSeq:");
|
||||
|
||||
vdec.reader = {};
|
||||
vdec.frc_set = 0;
|
||||
vdec.just_started = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case vdecEndSeq:
|
||||
{
|
||||
|
@ -237,8 +266,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 +286,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,54 +325,42 @@ u32 vdecOpen(VideoDecoder* data)
|
|||
}
|
||||
else if (vdec.just_started) // deferred initialization
|
||||
{
|
||||
err = avformat_open_input(&vdec.fmt, NULL, av_find_input_format("mpeg"), NULL);
|
||||
if (err)
|
||||
AVDictionary* opts = nullptr;
|
||||
av_dict_set(&opts, "probesize", "4096", 0);
|
||||
err = avformat_open_input(&vdec.fmt, NULL, NULL, &opts);
|
||||
if (err || opts)
|
||||
{
|
||||
cellVdec->Error("vdecDecodeAu: avformat_open_input() failed");
|
||||
Emu.Pause();
|
||||
break;
|
||||
VDEC_ERROR("vdecDecodeAu: avformat_open_input() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0);
|
||||
}
|
||||
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)
|
||||
{
|
||||
VDEC_ERROR("vdecDecodeAu: avformat_find_stream_info() failed (err=0x%x, nb_streams=%d)", err, vdec.fmt->nb_streams);
|
||||
}
|
||||
}
|
||||
/*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))
|
||||
{
|
||||
VDEC_ERROR("vdecDecodeAu: avformat_new_stream() failed");
|
||||
}
|
||||
}
|
||||
vdec.ctx = vdec.fmt->streams[0]->codec; // TODO: check data
|
||||
|
||||
AVDictionary* opts = nullptr;
|
||||
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, codec, &opts);
|
||||
err = avcodec_open2(vdec.ctx, vdec.codec, &opts);
|
||||
}
|
||||
if (err)
|
||||
if (err || opts)
|
||||
{
|
||||
cellVdec->Error("vdecDecodeAu: avcodec_open2() failed");
|
||||
Emu.Pause();
|
||||
break;
|
||||
VDEC_ERROR("vdecDecodeAu: avcodec_open2() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0);
|
||||
}
|
||||
|
||||
vdec.just_started = false;
|
||||
}
|
||||
|
||||
|
@ -386,9 +403,7 @@ u32 vdecOpen(VideoDecoder* data)
|
|||
|
||||
if (!frame.data)
|
||||
{
|
||||
cellVdec->Error("vdecDecodeAu: av_frame_alloc() failed");
|
||||
Emu.Pause();
|
||||
break;
|
||||
VDEC_ERROR("vdecDecodeAu: av_frame_alloc() failed");
|
||||
}
|
||||
|
||||
int got_picture = 0;
|
||||
|
@ -397,7 +412,7 @@ u32 vdecOpen(VideoDecoder* data)
|
|||
|
||||
if (decode <= 0)
|
||||
{
|
||||
if (!last_frame && decode < 0)
|
||||
if (decode < 0)
|
||||
{
|
||||
cellVdec->Error("vdecDecodeAu: AU decoding error(0x%x)", decode);
|
||||
}
|
||||
|
@ -406,19 +421,97 @@ 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;
|
||||
VDEC_ERROR("vdecDecodeAu: interlaced frames not supported (0x%x)", frame.data->interlaced_frame);
|
||||
}
|
||||
|
||||
if (frame.data->repeat_pict)
|
||||
{
|
||||
VDEC_ERROR("vdecDecodeAu: repeated frames not supported (0x%x)", frame.data->repeat_pict);
|
||||
}
|
||||
|
||||
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:
|
||||
{
|
||||
VDEC_ERROR("vdecDecodeAu: invalid frame rate code set (0x%x)", vdec.frc_set);
|
||||
}
|
||||
}
|
||||
|
||||
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 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:
|
||||
{
|
||||
VDEC_ERROR("vdecDecodeAu: 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
|
||||
{
|
||||
VDEC_ERROR("vdecDecodeAu: unsupported time_base.den (%d/1001, tpf=%d)", vdec.ctx->time_base.den, vdec.ctx->ticks_per_frame);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
VDEC_ERROR("vdecDecodeAu: unsupported time_base.num (%d)", vdec.ctx->time_base.num);
|
||||
}
|
||||
}
|
||||
//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,23 +526,24 @@ 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->Warning("vdecSetFrameRate(0x%x)", task.frc);
|
||||
vdec.frc_set = task.frc;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case vdecClose: break;
|
||||
case vdecClose:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
cellVdec->Error("Video Decoder thread error: unknown task(%d)", task.type);
|
||||
Emu.Pause();
|
||||
return;
|
||||
VDEC_ERROR("Video Decoder thread error: unknown task(%d)", task.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -624,7 +718,7 @@ int cellVdecGetPicture(u32 handle, vm::ptr<const CellVdecPicFormat> format, vm::
|
|||
int err = av_image_copy_to_buffer(outBuff.get_ptr(), buf_size, frame.data, frame.linesize, vdec->ctx->pix_fmt, frame.width, frame.height, 1);
|
||||
if (err < 0)
|
||||
{
|
||||
cellVdec->Error("cellVdecGetPicture: av_image_copy_to_buffer failed(%d)", err);
|
||||
cellVdec->Error("cellVdecGetPicture: av_image_copy_to_buffer failed (err=0x%x)", err);
|
||||
Emu.Pause();
|
||||
}
|
||||
}
|
||||
|
@ -667,79 +761,115 @@ int cellVdecGetPicItem(u32 handle, vm::ptr<u32> picItem_ptr)
|
|||
info->auNum = 1;
|
||||
info->auPts[0].lower = (u32)vf.pts;
|
||||
info->auPts[0].upper = vf.pts >> 32;
|
||||
info->auPts[1].lower = 0xffffffff;
|
||||
info->auPts[1].upper = 0xffffffff;
|
||||
info->auPts[1].lower = (u32)CODEC_TS_INVALID;
|
||||
info->auPts[1].upper = (u32)CODEC_TS_INVALID;
|
||||
info->auDts[0].lower = (u32)vf.dts;
|
||||
info->auDts[0].upper = vf.dts >> 32;
|
||||
info->auDts[1].lower = 0xffffffff;
|
||||
info->auDts[1].upper = 0xffffffff;
|
||||
info->auDts[1].lower = (u32)CODEC_TS_INVALID;
|
||||
info->auDts[1].upper = (u32)CODEC_TS_INVALID;
|
||||
info->auUserData[0] = vf.userdata;
|
||||
info->auUserData[1] = 0;
|
||||
info->status = CELL_OK;
|
||||
info->attr = CELL_VDEC_PICITEM_ATTR_NORMAL;
|
||||
info->picInfo_addr = info.addr() + sizeof(CellVdecPicItem);
|
||||
|
||||
auto avc = vm::ptr<CellVdecAvcInfo>::make(info.addr() + sizeof(CellVdecPicItem));
|
||||
if (vdec->type == CELL_VDEC_CODEC_TYPE_AVC)
|
||||
{
|
||||
auto avc = vm::ptr<CellVdecAvcInfo>::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);
|
||||
}
|
||||
|
||||
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<CellVdecDivxInfo>::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<CellVdecMpeg2Info>::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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue