mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-01-30 12:32:43 +00:00
Audio decoding
This commit is contained in:
parent
c4d9223034
commit
38bfbe2c40
@ -23,16 +23,22 @@ void AudioDumper::WriteHeader()
|
||||
|
||||
size_t AudioDumper::WriteData(const void* buffer, size_t size)
|
||||
{
|
||||
for (u32 i = 0; i < size / 8; i++)
|
||||
{
|
||||
if (((u64*)buffer)[i]) goto process;
|
||||
}
|
||||
for (u32 i = 0; i < size % 8; i++)
|
||||
{
|
||||
if (((u8*)buffer)[i + (size & ~7)]) goto process;
|
||||
}
|
||||
return size; // ignore empty data
|
||||
process:
|
||||
size_t ret = m_output.Write(buffer, size);
|
||||
m_header.Size += ret;
|
||||
m_header.RIFF.Size += ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void AudioDumper::UpdateHeader(size_t size)
|
||||
{
|
||||
m_header.Size += size;
|
||||
m_header.RIFF.Size += size;
|
||||
}
|
||||
|
||||
void AudioDumper::Finalize()
|
||||
{
|
||||
m_output.Seek(0);
|
||||
|
@ -64,6 +64,5 @@ public:
|
||||
bool Init();
|
||||
void WriteHeader();
|
||||
size_t WriteData(const void* buffer, size_t size);
|
||||
void UpdateHeader(size_t size);
|
||||
void Finalize();
|
||||
};
|
||||
|
@ -9,6 +9,7 @@ extern "C"
|
||||
{
|
||||
#include "libavcodec/avcodec.h"
|
||||
#include "libavformat/avformat.h"
|
||||
#include "libswresample/swresample.h"
|
||||
}
|
||||
|
||||
#include "cellAdec.h"
|
||||
@ -16,7 +17,7 @@ extern "C"
|
||||
void cellAdec_init();
|
||||
Module cellAdec(0x0006, cellAdec_init);
|
||||
|
||||
int adecRead(void* opaque, u8* buf, int buf_size)
|
||||
int adecRawRead(void* opaque, u8* buf, int buf_size)
|
||||
{
|
||||
AudioDecoder& adec = *(AudioDecoder*)opaque;
|
||||
|
||||
@ -61,8 +62,9 @@ next:
|
||||
|
||||
adec.reader.addr = adec.task.au.addr;
|
||||
adec.reader.size = adec.task.au.size;
|
||||
//ConLog.Write("Audio AU: size = 0x%x, pts = 0x%llx", adec.task.au.size, adec.task.au.pts);
|
||||
|
||||
adec.last_pts = adec.task.au.pts;
|
||||
if (adec.last_pts > adec.task.au.pts) adec.last_pts = adec.task.au.pts;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -95,6 +97,89 @@ next:
|
||||
}
|
||||
}
|
||||
|
||||
int adecRead(void* opaque, u8* buf, int buf_size)
|
||||
{
|
||||
AudioDecoder& adec = *(AudioDecoder*)opaque;
|
||||
|
||||
int res = 0;
|
||||
|
||||
if (adec.reader.rem_size && adec.reader.rem)
|
||||
{
|
||||
if (buf_size < (int)adec.reader.rem_size)
|
||||
{
|
||||
ConLog.Error("adecRead: too small buf_size (rem_size = %d, buf_size = %d)", adec.reader.rem_size, buf_size);
|
||||
Emu.Pause();
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(buf, adec.reader.rem, adec.reader.rem_size);
|
||||
free(adec.reader.rem);
|
||||
adec.reader.rem = nullptr;
|
||||
buf += adec.reader.rem_size;
|
||||
buf_size -= adec.reader.rem_size;
|
||||
res += adec.reader.rem_size;
|
||||
adec.reader.rem_size = 0;
|
||||
}
|
||||
|
||||
while (buf_size)
|
||||
{
|
||||
u8 header[8];
|
||||
if (adecRawRead(opaque, header, 8) < 8) break;
|
||||
if (header[0] != 0x0f || header[1] != 0xd0)
|
||||
{
|
||||
ConLog.Error("adecRead: 0x0FD0 header not found");
|
||||
Emu.Pause();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!adec.reader.init)
|
||||
{
|
||||
OMAHeader oma(1 /* atrac3p id */, header[2], header[3]);
|
||||
if (buf_size < sizeof(oma) + 8)
|
||||
{
|
||||
ConLog.Error("adecRead: OMAHeader writing failed");
|
||||
Emu.Pause();
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(buf, &oma, sizeof(oma));
|
||||
buf += sizeof(oma);
|
||||
buf_size -= sizeof(oma);
|
||||
res += sizeof(oma);
|
||||
|
||||
adec.reader.init = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
|
||||
u32 size = (((header[2] & 0x3) << 8) | header[3]) * 8 + 8; // data to be read before next header
|
||||
|
||||
//ConLog.Write("*** audio block read: size = 0x%x", size);
|
||||
|
||||
if (buf_size < (int)size)
|
||||
{
|
||||
if (adecRawRead(opaque, buf, buf_size) < buf_size) break; // ???
|
||||
res += buf_size;
|
||||
size -= buf_size;
|
||||
buf_size = 0;
|
||||
|
||||
adec.reader.rem = (u8*)malloc(size);
|
||||
adec.reader.rem_size = size;
|
||||
if (adecRawRead(opaque, adec.reader.rem, size) < (int)size) break; // ???
|
||||
}
|
||||
else
|
||||
{
|
||||
if (adecRawRead(opaque, buf, size) < (int)size) break; // ???
|
||||
buf += size;
|
||||
buf_size -= size;
|
||||
res += size;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
u32 adecOpen(AudioDecoder* data)
|
||||
{
|
||||
AudioDecoder& adec = *data;
|
||||
@ -146,6 +231,10 @@ u32 adecOpen(AudioDecoder* data)
|
||||
|
||||
adec.reader.addr = 0;
|
||||
adec.reader.size = 0;
|
||||
adec.reader.init = false;
|
||||
if (adec.reader.rem) free(adec.reader.rem);
|
||||
adec.reader.rem = nullptr;
|
||||
adec.reader.rem_size = 0;
|
||||
adec.is_running = true;
|
||||
adec.just_started = true;
|
||||
}
|
||||
@ -175,8 +264,9 @@ u32 adecOpen(AudioDecoder* data)
|
||||
|
||||
adec.reader.addr = task.au.addr;
|
||||
adec.reader.size = task.au.size;
|
||||
//ConLog.Write("Audio AU: size = 0x%x, pts = 0x%llx", task.au.size, task.au.pts);
|
||||
|
||||
adec.last_pts = task.au.pts;
|
||||
if (adec.last_pts > task.au.pts || adec.just_started) adec.last_pts = task.au.pts;
|
||||
|
||||
struct AVPacketHolder : AVPacket
|
||||
{
|
||||
@ -212,11 +302,11 @@ u32 adecOpen(AudioDecoder* data)
|
||||
if (Memory.CopyToReal(buf, task.au.addr, task.au.size)) dump.Write(buf, task.au.size);
|
||||
free(buf);
|
||||
dump.Close();
|
||||
}
|
||||
}*/
|
||||
|
||||
if (adec.just_started) // deferred initialization
|
||||
{
|
||||
err = avformat_open_input(&adec.fmt, NULL, NULL, NULL);
|
||||
err = avformat_open_input(&adec.fmt, NULL, av_find_input_format("oma"), NULL);
|
||||
if (err)
|
||||
{
|
||||
ConLog.Error("adecDecodeAu: avformat_open_input() failed");
|
||||
@ -230,7 +320,7 @@ u32 adecOpen(AudioDecoder* data)
|
||||
Emu.Pause();
|
||||
break;
|
||||
}
|
||||
err = avformat_find_stream_info(adec.fmt, NULL);
|
||||
/*err = avformat_find_stream_info(adec.fmt, NULL);
|
||||
if (err)
|
||||
{
|
||||
ConLog.Error("adecDecodeAu: avformat_find_stream_info() failed");
|
||||
@ -242,6 +332,12 @@ u32 adecOpen(AudioDecoder* data)
|
||||
ConLog.Error("adecDecodeAu: no stream found");
|
||||
Emu.Pause();
|
||||
break;
|
||||
}*/
|
||||
if (!avformat_new_stream(adec.fmt, codec))
|
||||
{
|
||||
ConLog.Error("adecDecodeAu: avformat_new_stream() failed");
|
||||
Emu.Pause();
|
||||
break;
|
||||
}
|
||||
adec.ctx = adec.fmt->streams[0]->codec; // TODO: check data
|
||||
|
||||
@ -259,7 +355,7 @@ u32 adecOpen(AudioDecoder* data)
|
||||
break;
|
||||
}
|
||||
adec.just_started = false;
|
||||
}*/
|
||||
}
|
||||
|
||||
bool last_frame = false;
|
||||
|
||||
@ -271,7 +367,7 @@ u32 adecOpen(AudioDecoder* data)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!adec.ctx) // fake
|
||||
/*if (!adec.ctx) // fake
|
||||
{
|
||||
AdecFrame frame;
|
||||
frame.pts = task.au.pts;
|
||||
@ -285,7 +381,7 @@ u32 adecOpen(AudioDecoder* data)
|
||||
adec.adecCb->ExecAsCallback(adec.cbFunc, false, adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg);
|
||||
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
|
||||
last_frame = av_read_frame(adec.fmt, &au) < 0;
|
||||
if (last_frame)
|
||||
@ -336,13 +432,16 @@ u32 adecOpen(AudioDecoder* data)
|
||||
|
||||
if (got_frame)
|
||||
{
|
||||
ConLog.Write("got_frame (%d, pts=0x%llx, dts=0x%llx)", got_frame, au.pts, au.dts);
|
||||
|
||||
frame.pts = task.au.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 = 32768; // ????
|
||||
frame.size = frame.data->nb_samples * frame.data->channels * sizeof(float);
|
||||
|
||||
//ConLog.Write("got audio frame (pts=0x%llx, nb_samples=%d, ch=%d, sample_rate=%d)",
|
||||
//frame.pts, frame.data->nb_samples, frame.data->channels, frame.data->sample_rate);
|
||||
|
||||
adec.frames.Push(frame);
|
||||
frame.data = nullptr; // to prevent destruction
|
||||
|
||||
@ -569,26 +668,69 @@ int cellAdecGetPcm(u32 handle, u32 outBuffer_addr)
|
||||
|
||||
AdecFrame af;
|
||||
adec->frames.Pop(af);
|
||||
//AVFrame& frame = *af.data;
|
||||
AVFrame* frame = af.data;
|
||||
|
||||
int result = CELL_OK;
|
||||
|
||||
if (!Memory.IsGoodAddr(outBuffer_addr, af.size))
|
||||
{
|
||||
result = CELL_ADEC_ERROR_FATAL;
|
||||
goto end;
|
||||
}
|
||||
else
|
||||
|
||||
if (!af.data) // fake: empty data
|
||||
{
|
||||
// copy data
|
||||
if (!af.data) // fake: empty data
|
||||
{
|
||||
u8* buf = (u8*)malloc(4096);
|
||||
memset(buf, 0, 4096);
|
||||
Memory.CopyFromReal(outBuffer_addr, buf, 4096);
|
||||
free(buf);
|
||||
return CELL_OK;
|
||||
}
|
||||
/*u8* buf = (u8*)malloc(4096);
|
||||
memset(buf, 0, 4096);
|
||||
Memory.CopyFromReal(outBuffer_addr, buf, 4096);
|
||||
free(buf);*/
|
||||
goto end;
|
||||
}
|
||||
// copy data
|
||||
SwrContext* swr = nullptr;
|
||||
u8* out = nullptr;
|
||||
|
||||
if (frame->format != AV_SAMPLE_FMT_FLTP)
|
||||
{
|
||||
ConLog.Error("cellAdecGetPcm(%d): unsupported frame format(%d)", handle, frame->format);
|
||||
Emu.Pause();
|
||||
goto end;
|
||||
}
|
||||
|
||||
out = (u8*)malloc(af.size);
|
||||
|
||||
/*swr = swr_alloc_set_opts(NULL, AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_FLT, 48000,
|
||||
frame->channel_layout, (AVSampleFormat)frame->format, frame->sample_rate, 0, NULL);
|
||||
|
||||
if (!swr)
|
||||
{
|
||||
ConLog.Error("cellAdecGetPcm(%d): swr_alloc_set_opts() failed", handle);
|
||||
Emu.Pause();
|
||||
goto end;
|
||||
}
|
||||
// something is wrong
|
||||
swr_convert(swr, &out, frame->nb_samples, (const u8**)frame->extended_data, frame->nb_samples); */
|
||||
|
||||
// reverse byte order, extract data:
|
||||
float* in_f[2];
|
||||
in_f[0] = (float*)frame->extended_data[0];
|
||||
in_f[1] = (float*)frame->extended_data[1];
|
||||
be_t<float>* out_f = (be_t<float>*)out;
|
||||
for (u32 i = 0; i < af.size / 8; i++)
|
||||
{
|
||||
out_f[i*2] = in_f[0][i];
|
||||
out_f[i*2+1] = in_f[1][i];
|
||||
}
|
||||
|
||||
if (!Memory.CopyFromReal(outBuffer_addr, out, af.size))
|
||||
{
|
||||
ConLog.Error("cellAdecGetPcm(%d): data copying failed (addr=0x%x)", handle, outBuffer_addr);
|
||||
Emu.Pause();
|
||||
}
|
||||
|
||||
end:
|
||||
if (out) free(out);
|
||||
if (swr) swr_free(&swr);
|
||||
|
||||
if (af.data)
|
||||
{
|
||||
@ -620,7 +762,7 @@ int cellAdecGetPcmItem(u32 handle, mem32_t pcmItem_ptr)
|
||||
return CELL_ADEC_ERROR_EMPTY;
|
||||
}
|
||||
|
||||
//AVFrame& frame = *af.data;
|
||||
AVFrame* frame = af.data;
|
||||
|
||||
mem_ptr_t<CellAdecPcmItem> pcm(adec->memAddr + adec->memBias);
|
||||
|
||||
@ -635,16 +777,17 @@ int cellAdecGetPcmItem(u32 handle, mem32_t pcmItem_ptr)
|
||||
pcm->startAddr = 0x00000312; // invalid address (no output)
|
||||
pcm->size = af.size;
|
||||
pcm->status = CELL_OK;
|
||||
pcm->auInfo.pts.lower = af.pts; // ???
|
||||
pcm->auInfo.pts.lower = af.pts;
|
||||
pcm->auInfo.pts.upper = af.pts >> 32;
|
||||
pcm->auInfo.size = af.auSize;
|
||||
pcm->auInfo.startAddr = af.auAddr;
|
||||
pcm->auInfo.userData = af.userdata;
|
||||
|
||||
mem_ptr_t<CellAdecAtracXInfo> atx(pcm.GetAddr() + sizeof(CellAdecPcmItem));
|
||||
atx->samplingFreq = 48000; // ???
|
||||
atx->nbytes = 2048; // ???
|
||||
atx->samplingFreq = frame->sample_rate; // ???
|
||||
atx->nbytes = frame->nb_samples * frame->channels * sizeof(float); // ???
|
||||
atx->channelConfigIndex = CELL_ADEC_CH_STEREO; // ???
|
||||
if (frame->channels != 2) ConLog.Error("cellAdecGetPcmItem: unsupported channel count (%d)", frame->channels);
|
||||
|
||||
pcmItem_ptr = pcm.GetAddr();
|
||||
|
||||
|
@ -1036,6 +1036,40 @@ struct AdecFrame
|
||||
|
||||
int adecRead(void* opaque, u8* buf, int buf_size);
|
||||
|
||||
struct OMAHeader // OMA Header
|
||||
{
|
||||
u32 magic; // 0x01334145
|
||||
u16 size; // 96 << 8
|
||||
u16 unk0; // 0xffff
|
||||
u64 unk1; // 0x00500f0100000000ULL
|
||||
u64 unk2; // 0xcef5000000000400ULL
|
||||
u64 unk3; // 0x1c458024329192d2ULL
|
||||
u8 codecId; // 1 for ATRAC3P
|
||||
u8 reserved0; // 0
|
||||
u8 code1;
|
||||
u8 code2;
|
||||
u32 reserved1; // 0
|
||||
u64 reserved[7]; // 0
|
||||
|
||||
OMAHeader(u8 id, u8 code1, u8 code2)
|
||||
: magic(0x01334145)
|
||||
, size(96 << 8)
|
||||
, unk0(0xffff)
|
||||
, unk1(0x00500f0100000000ULL)
|
||||
, unk2(0xcef5000000000400ULL)
|
||||
, unk3(0x1c458024329192d2ULL)
|
||||
, codecId(id)
|
||||
, reserved0(0)
|
||||
, code1(code1)
|
||||
, code2(code2)
|
||||
, reserved1(0)
|
||||
{
|
||||
memset(reserved, 0, sizeof(reserved));
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(OMAHeader) == 96, "Wrong OMAHeader size");
|
||||
|
||||
class AudioDecoder
|
||||
{
|
||||
public:
|
||||
@ -1053,6 +1087,21 @@ public:
|
||||
{
|
||||
u32 addr;
|
||||
u32 size;
|
||||
bool init;
|
||||
u8* rem;
|
||||
u32 rem_size;
|
||||
|
||||
AudioReader()
|
||||
: rem(nullptr)
|
||||
, rem_size(0)
|
||||
{
|
||||
}
|
||||
|
||||
~AudioReader()
|
||||
{
|
||||
if (rem) free(rem);
|
||||
rem = nullptr;
|
||||
}
|
||||
} reader;
|
||||
|
||||
SQueue<AdecFrame> frames;
|
||||
|
@ -118,29 +118,37 @@ int cellAudioInit()
|
||||
index = (position + 1) % port.block; // write new value
|
||||
}
|
||||
|
||||
u32 k = port.channel / 2;
|
||||
|
||||
if (first_mix)
|
||||
{
|
||||
for (u32 i = 0; i < (sizeof(buffer) / sizeof(float)); i++)
|
||||
for (u32 i = 0; i < (sizeof(buffer) / sizeof(float)); i += 2)
|
||||
{
|
||||
// reverse byte order (TODO: use port.m_param.level)
|
||||
buffer[i] = buffer2[i];
|
||||
buffer[i] = buffer2[i*k];
|
||||
buffer[i+1] = buffer2[i*k+1];
|
||||
|
||||
// convert the data from float to u16
|
||||
assert(buffer[i] >= -4.0f && buffer[i] <= 4.0f);
|
||||
assert(buffer[i+1] >= -4.0f && buffer[i+1] <= 4.0f);
|
||||
oal_buffer[oal_buffer_offset + i] = (u16)(buffer[i] * ((1 << 13) - 1));
|
||||
oal_buffer[oal_buffer_offset + i + 1] = (u16)(buffer[i+1] * ((1 << 13) - 1));
|
||||
}
|
||||
|
||||
first_mix = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (u32 i = 0; i < (sizeof(buffer) / sizeof(float)); i++)
|
||||
for (u32 i = 0; i < (sizeof(buffer) / sizeof(float)); i += 2)
|
||||
{
|
||||
buffer[i] = (buffer[i] + buffer2[i]) * 0.5; // TODO: valid mixing
|
||||
buffer[i] = (buffer[i] + buffer2[i*k]) * 0.5; // TODO: valid mixing
|
||||
buffer[i+1] = (buffer[i+1] + buffer2[i*k+1]) * 0.5;
|
||||
|
||||
// convert the data from float to u16
|
||||
assert(buffer[i] >= -4.0f && buffer[i] <= 4.0f);
|
||||
assert(buffer[i+1] >= -4.0f && buffer[i+1] <= 4.0f);
|
||||
oal_buffer[oal_buffer_offset + i] = (u16)(buffer[i] * ((1 << 13) - 1));
|
||||
oal_buffer[oal_buffer_offset + i + 1] = (u16)(buffer[i+1] * ((1 << 13) - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -176,8 +184,6 @@ int cellAudioInit()
|
||||
ConLog.Error("Port aborted: cannot write file!");
|
||||
goto abort;
|
||||
}
|
||||
|
||||
m_dump.UpdateHeader(sizeof(buffer));
|
||||
}
|
||||
}
|
||||
ConLog.Write("Audio finished");
|
||||
|
@ -18,9 +18,9 @@ void dmuxQueryEsAttr(u32 info_addr /* may be 0 */, const mem_ptr_t<CellCodecEsFi
|
||||
const u32 esSpecificInfo_addr, mem_ptr_t<CellDmuxEsAttr> attr)
|
||||
{
|
||||
if (esFilterId->filterIdMajor >= 0xe0)
|
||||
attr->memSize = 0x3000000; // 0x45fa49 from ps3
|
||||
attr->memSize = 0x2000000/2; // 0x45fa49 from ps3
|
||||
else
|
||||
attr->memSize = 0x200000; // 0x73d9 from ps3
|
||||
attr->memSize = 0x80000; // 0x73d9 from ps3
|
||||
|
||||
cellDmux.Warning("*** filter(0x%x, 0x%x, 0x%x, 0x%x)", (u32)esFilterId->filterIdMajor, (u32)esFilterId->filterIdMinor,
|
||||
(u32)esFilterId->supplementalInfo1, (u32)esFilterId->supplementalInfo2);
|
||||
@ -131,7 +131,7 @@ u32 dmuxOpen(Demuxer* data)
|
||||
}
|
||||
|
||||
// read additional header:
|
||||
stream.peek(ch);
|
||||
stream.peek(ch); // ???
|
||||
//stream.skip(4);
|
||||
//pes.size += 4;
|
||||
|
||||
@ -148,26 +148,18 @@ u32 dmuxOpen(Demuxer* data)
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
/*if (es.hasunseen()) // hack, probably useless
|
||||
if (es.hasunseen()) // hack, probably useless
|
||||
{
|
||||
stream = backup;
|
||||
continue;
|
||||
}*/
|
||||
|
||||
//ConLog.Write("*** AT3+ AU sent (pts=0x%llx, dts=0x%llx)", pes.pts, pes.dts);
|
||||
}
|
||||
|
||||
stream.skip(4);
|
||||
len -= 4;
|
||||
u32 abc;
|
||||
stream.peek(abc);
|
||||
if (abc == 0x5548D00F)
|
||||
{
|
||||
stream.skip(8);
|
||||
len -= 8;
|
||||
}
|
||||
|
||||
es.push(stream, len - pes.size - 3, pes);
|
||||
es.finish(stream);
|
||||
//ConLog.Write("*** AT3+ AU sent (len=0x%x, pts=0x%llx)", len - pes.size - 3, pes.pts);
|
||||
|
||||
mem_ptr_t<CellDmuxEsMsg> esMsg(a128(dmux.memAddr) + (cb_add ^= 16));
|
||||
esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND;
|
||||
@ -213,11 +205,11 @@ u32 dmuxOpen(Demuxer* data)
|
||||
|
||||
if (pes.new_au && es.hasdata()) // new AU detected
|
||||
{
|
||||
/*if (es.hasunseen()) // hack, probably useless
|
||||
if (es.hasunseen()) // hack, probably useless
|
||||
{
|
||||
stream = backup;
|
||||
continue;
|
||||
}*/
|
||||
}
|
||||
es.finish(stream);
|
||||
// callback
|
||||
mem_ptr_t<CellDmuxEsMsg> esMsg(a128(dmux.memAddr) + (cb_add ^= 16));
|
||||
@ -298,7 +290,7 @@ u32 dmuxOpen(Demuxer* data)
|
||||
{
|
||||
case dmuxSetStream:
|
||||
{
|
||||
if (stream.discontinuity)
|
||||
if (task.stream.discontinuity)
|
||||
{
|
||||
for (u32 i = 0; i < 192; i++)
|
||||
{
|
||||
|
@ -541,7 +541,7 @@ public:
|
||||
|
||||
const u32 GetMaxAU() const
|
||||
{
|
||||
return 640 * 1024 + 128;
|
||||
return (fidMajor == 0xbd) ? 2048 : 640 * 1024 + 128;
|
||||
}
|
||||
|
||||
volatile bool hasunseen()
|
||||
@ -573,6 +573,11 @@ public:
|
||||
peek_addr = last_addr;
|
||||
}
|
||||
|
||||
mem_ptr_t<CellDmuxAuInfo> info(last_addr);
|
||||
/*if (fidMajor == 0xbd) ConLog.Warning("es::finish(): (%s) size = 0x%x, info_addr=0x%x, pts = 0x%x",
|
||||
wxString(fidMajor == 0xbd ? "ATRAC3P Audio" : "Video AVC").wx_str(),
|
||||
(u32)info->auSize, last_addr, (u32)info->ptsLower);*/
|
||||
|
||||
u32 new_addr = a128(last_addr + 128 + last_size);
|
||||
if ((new_addr + GetMaxAU()) > (memAddr + memSize))
|
||||
{
|
||||
@ -681,6 +686,11 @@ public:
|
||||
wxString(no_ex ? "" : "Ex").wx_str(), peek_addr, first_addr, last_addr, last_size);*/
|
||||
if (!peek_addr) return false;
|
||||
|
||||
mem_ptr_t<CellDmuxAuInfo> info(peek_addr);
|
||||
/*if (fidMajor == 0xbd) ConLog.Warning("es::peek(%sAu(Ex)): (%s) size = 0x%x, info = 0x%x, pts = 0x%x",
|
||||
wxString(update_index ? "Get" : "Peek").wx_str(),
|
||||
wxString(fidMajor == 0xbd ? "ATRAC3P Audio" : "Video AVC").wx_str(), (u32)info->auSize, peek_addr, (u32)info->ptsLower);*/
|
||||
|
||||
out_data = peek_addr;
|
||||
out_spec = out_data + sizeof(CellDmuxAuInfoEx);
|
||||
if (no_ex) out_data += 64;
|
||||
|
@ -66,9 +66,10 @@ next:
|
||||
|
||||
vdec.reader.addr = vdec.task.addr;
|
||||
vdec.reader.size = vdec.task.size;
|
||||
//ConLog.Write("Video AU: size = 0x%x, pts = 0x%llx, dts = 0x%llx", vdec.task.size, vdec.task.pts, vdec.task.dts);
|
||||
|
||||
vdec.last_pts = vdec.task.pts;
|
||||
vdec.last_dts = vdec.task.dts;
|
||||
if (vdec.last_pts > vdec.task.pts) vdec.last_pts = vdec.task.pts;
|
||||
if (vdec.last_dts > vdec.task.dts) vdec.last_dts = vdec.task.dts;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -205,9 +206,10 @@ u32 vdecOpen(VideoDecoder* data)
|
||||
|
||||
vdec.reader.addr = task.addr;
|
||||
vdec.reader.size = task.size;
|
||||
//ConLog.Write("Video AU: size = 0x%x, pts = 0x%llx, dts = 0x%llx", task.size, task.pts, task.dts);
|
||||
|
||||
vdec.last_pts = task.pts;
|
||||
vdec.last_dts = task.dts;
|
||||
if (vdec.last_pts > task.pts || vdec.just_started) vdec.last_pts = task.pts;
|
||||
if (vdec.last_dts > task.dts || vdec.just_started) vdec.last_dts = task.dts;
|
||||
|
||||
struct AVPacketHolder : AVPacket
|
||||
{
|
||||
@ -350,11 +352,12 @@ u32 vdecOpen(VideoDecoder* data)
|
||||
|
||||
if (got_picture)
|
||||
{
|
||||
//ConLog.Write("got_picture (%d, vdec: pts=0x%llx, dts=0x%llx)", got_picture, au.pts, au.dts);
|
||||
|
||||
frame.dts = vdec.last_dts; vdec.last_dts += 3003; // + duration???
|
||||
frame.pts = vdec.last_pts; vdec.last_pts += 3003;
|
||||
frame.userdata = task.userData;
|
||||
|
||||
//ConLog.Write("got picture (pts=0x%llx, dts=0x%llx)", frame.pts, frame.dts);
|
||||
|
||||
vdec.frames.Push(frame); // !!!!!!!!
|
||||
frame.data = nullptr; // to prevent destruction
|
||||
|
||||
|
@ -1,6 +1,12 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
#include "Emu/SysCalls/SC_FUNC.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "libswscale/swscale.h"
|
||||
}
|
||||
|
||||
#include "cellVpost.h"
|
||||
|
||||
void cellVpost_init();
|
||||
@ -93,13 +99,15 @@ int cellVpostExec(u32 handle, const u32 inPicBuff_addr, const mem_ptr_t<CellVpos
|
||||
|
||||
u32 w = ctrlParam->inWidth;
|
||||
u32 h = ctrlParam->inHeight;
|
||||
u32 ow = ctrlParam->outWidth;
|
||||
u32 oh = ctrlParam->outHeight;
|
||||
|
||||
if (!Memory.IsGoodAddr(inPicBuff_addr, w*h*3/2))
|
||||
{
|
||||
return CELL_VPOST_ERROR_E_ARG_INPICBUF_INVALID;
|
||||
}
|
||||
|
||||
if (!Memory.IsGoodAddr(outPicBuff_addr, w*h*4))
|
||||
if (!Memory.IsGoodAddr(outPicBuff_addr, ow*oh*4))
|
||||
{
|
||||
return CELL_VPOST_ERROR_E_ARG_OUTPICBUF_INVALID;
|
||||
}
|
||||
@ -110,13 +118,21 @@ int cellVpostExec(u32 handle, const u32 inPicBuff_addr, const mem_ptr_t<CellVpos
|
||||
}
|
||||
|
||||
ctrlParam->inWindow; // ignored
|
||||
if (ctrlParam->inWindow.x) ConLog.Warning("*** inWindow.x = %d", (u32)ctrlParam->inWindow.x);
|
||||
if (ctrlParam->inWindow.y) ConLog.Warning("*** inWindow.y = %d", (u32)ctrlParam->inWindow.y);
|
||||
if (ctrlParam->inWindow.width != w) ConLog.Warning("*** inWindow.width = %d", (u32)ctrlParam->inWindow.width);
|
||||
if (ctrlParam->inWindow.height != h) ConLog.Warning("*** inWindow.height = %d", (u32)ctrlParam->inWindow.height);
|
||||
ctrlParam->outWindow; // ignored
|
||||
if (ctrlParam->outWindow.x) ConLog.Warning("*** outWindow.x = %d", (u32)ctrlParam->outWindow.x);
|
||||
if (ctrlParam->outWindow.y) ConLog.Warning("*** outWindow.y = %d", (u32)ctrlParam->outWindow.y);
|
||||
if (ctrlParam->outWindow.width != ow) ConLog.Warning("*** outWindow.width = %d", (u32)ctrlParam->outWindow.width);
|
||||
if (ctrlParam->outWindow.height != oh) ConLog.Warning("*** outWindow.height = %d", (u32)ctrlParam->outWindow.height);
|
||||
ctrlParam->execType; // ignored
|
||||
ctrlParam->scalerType; // ignored
|
||||
ctrlParam->ipcType; // ignored
|
||||
|
||||
picInfo->inWidth = ctrlParam->inWidth; // copy
|
||||
picInfo->inHeight = ctrlParam->inHeight; // copy
|
||||
picInfo->inWidth = w; // copy
|
||||
picInfo->inHeight = h; // copy
|
||||
picInfo->inDepth = CELL_VPOST_PIC_DEPTH_8; // fixed
|
||||
picInfo->inScanType = CELL_VPOST_SCAN_TYPE_P; // TODO
|
||||
picInfo->inPicFmt = CELL_VPOST_PIC_FMT_IN_YUV420_PLANAR; // fixed
|
||||
@ -125,24 +141,25 @@ int cellVpostExec(u32 handle, const u32 inPicBuff_addr, const mem_ptr_t<CellVpos
|
||||
picInfo->inQuantRange = ctrlParam->inQuantRange; // copy
|
||||
picInfo->inColorMatrix = ctrlParam->inColorMatrix; // copy
|
||||
|
||||
picInfo->outWidth = picInfo->inWidth; // TODO (resampling)
|
||||
picInfo->outHeight = picInfo->inHeight; // TODO
|
||||
picInfo->outWidth = ow; // copy
|
||||
picInfo->outHeight = oh; // copy
|
||||
picInfo->outDepth = CELL_VPOST_PIC_DEPTH_8; // fixed
|
||||
picInfo->outScanType = CELL_VPOST_SCAN_TYPE_P; // TODO
|
||||
picInfo->outPicFmt = CELL_VPOST_PIC_FMT_OUT_RGBA_ILV; // TODO
|
||||
picInfo->outChromaPosType = ctrlParam->inChromaPosType; // ???
|
||||
picInfo->outPicStruct = picInfo->inPicStruct; // ???
|
||||
picInfo->outQuantRange = ctrlParam->inQuantRange; // ???
|
||||
picInfo->outColorMatrix = ctrlParam->inColorMatrix; // ???
|
||||
picInfo->outChromaPosType = ctrlParam->inChromaPosType; // ignored
|
||||
picInfo->outPicStruct = picInfo->inPicStruct; // ignored
|
||||
picInfo->outQuantRange = ctrlParam->inQuantRange; // ignored
|
||||
picInfo->outColorMatrix = ctrlParam->inColorMatrix; // ignored
|
||||
|
||||
picInfo->userData = ctrlParam->userData; // copy
|
||||
picInfo->reserved1 = 0;
|
||||
picInfo->reserved2 = 0;
|
||||
|
||||
|
||||
u8* pY = (u8*)malloc(w*h); // color planes
|
||||
u8* pU = (u8*)malloc(w*h/4);
|
||||
u8* pV = (u8*)malloc(w*h/4);
|
||||
u32* res = (u32*)malloc(w*h*4); // RGBA interleaved output
|
||||
u8* pA = (u8*)malloc(w*h);
|
||||
u32* res = (u32*)malloc(ow*oh*4); // RGBA interleaved output
|
||||
const u8 alpha = ctrlParam->outAlpha;
|
||||
|
||||
if (!Memory.CopyToReal(pY, inPicBuff_addr, w*h))
|
||||
@ -163,6 +180,20 @@ int cellVpostExec(u32 handle, const u32 inPicBuff_addr, const mem_ptr_t<CellVpos
|
||||
Emu.Pause();
|
||||
}
|
||||
|
||||
memset(pA, alpha, w*h);
|
||||
|
||||
SwsContext* sws = sws_getContext(w, h, AV_PIX_FMT_YUVA420P, ow, oh, AV_PIX_FMT_RGBA, SWS_BILINEAR, NULL, NULL, NULL);
|
||||
|
||||
u8* in_data[4] = { pY, pU, pV, pA };
|
||||
int in_line[4] = { w, w/2, w/2, w };
|
||||
u8* out_data[4] = { (u8*)res, NULL, NULL, NULL };
|
||||
int out_line[4] = { ow*4, 0, 0, 0 };
|
||||
|
||||
sws_scale(sws, in_data, in_line, 0, h, out_data, out_line);
|
||||
|
||||
sws_freeContext(sws);
|
||||
|
||||
/*
|
||||
for (u32 i = 0; i < h; i++) for (u32 j = 0; j < w; j++)
|
||||
{
|
||||
float Cr = pV[(i/2)*(w/2)+j/2] - 128;
|
||||
@ -179,9 +210,9 @@ int cellVpostExec(u32 handle, const u32 inPicBuff_addr, const mem_ptr_t<CellVpos
|
||||
if (B < 0) B = 0;
|
||||
if (B > 255) B = 255;
|
||||
res[i*w+j] = ((u32)alpha << 24) | (B << 16) | (G << 8) | (R);
|
||||
}
|
||||
}*/
|
||||
|
||||
if (!Memory.CopyFromReal(outPicBuff_addr, res, w*h*4))
|
||||
if (!Memory.CopyFromReal(outPicBuff_addr, res, ow*oh*4))
|
||||
{
|
||||
cellVpost.Error("cellVpostExec: data copying failed(result)");
|
||||
Emu.Pause();
|
||||
@ -190,6 +221,7 @@ int cellVpostExec(u32 handle, const u32 inPicBuff_addr, const mem_ptr_t<CellVpos
|
||||
free(pY);
|
||||
free(pU);
|
||||
free(pV);
|
||||
free(pA);
|
||||
free(res);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -160,22 +160,44 @@ int sys_cond_wait(u32 cond_id, u64 timeout)
|
||||
|
||||
if (mutex->m_mutex.GetOwner() != tid)
|
||||
{
|
||||
sys_cond.Warning("sys_cond_wait(cond_id=%d) failed (EPERM)", cond_id);
|
||||
return CELL_EPERM;
|
||||
}
|
||||
|
||||
cond->m_queue.push(tid);
|
||||
|
||||
if (mutex->recursive != 1)
|
||||
{
|
||||
sys_cond.Warning("sys_cond_wait(cond_id=%d): associated mutex had wrong recursive value (%d)", cond_id, mutex->recursive);
|
||||
}
|
||||
mutex->recursive = 0;
|
||||
mutex->m_mutex.unlock(tid);
|
||||
mutex->m_mutex.unlock(tid, mutex->protocol == SYS_SYNC_PRIORITY ? mutex->m_queue.pop_prio() : mutex->m_queue.pop());
|
||||
|
||||
u32 counter = 0;
|
||||
const u32 max_counter = timeout ? (timeout / 1000) : ~0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (cond->signal.GetOwner() == tid)
|
||||
if (cond->signal.unlock(tid, tid) == SMR_OK)
|
||||
{
|
||||
mutex->m_mutex.lock(tid);
|
||||
if (SMutexResult res = mutex->m_mutex.trylock(tid))
|
||||
{
|
||||
if (res != SMR_FAILED)
|
||||
{
|
||||
goto abort;
|
||||
}
|
||||
mutex->m_queue.push(tid);
|
||||
|
||||
switch (mutex->m_mutex.lock(tid))
|
||||
{
|
||||
case SMR_OK:
|
||||
mutex->m_queue.invalidate(tid);
|
||||
case SMR_SIGNAL:
|
||||
break;
|
||||
default:
|
||||
goto abort;
|
||||
}
|
||||
}
|
||||
mutex->recursive = 1;
|
||||
cond->signal.unlock(tid);
|
||||
return CELL_OK;
|
||||
@ -186,13 +208,16 @@ int sys_cond_wait(u32 cond_id, u64 timeout)
|
||||
if (counter++ > max_counter)
|
||||
{
|
||||
cond->m_queue.invalidate(tid);
|
||||
GetCurrentPPUThread().owned_mutexes--;
|
||||
GetCurrentPPUThread().owned_mutexes--; // ???
|
||||
return CELL_ETIMEDOUT;
|
||||
}
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
ConLog.Warning("sys_cond_wait(id=%d) aborted", cond_id);
|
||||
return CELL_OK;
|
||||
goto abort;
|
||||
}
|
||||
}
|
||||
|
||||
abort:
|
||||
ConLog.Warning("sys_cond_wait(id=%d) aborted", cond_id);
|
||||
return CELL_OK;
|
||||
}
|
@ -63,7 +63,7 @@ int sys_mutex_destroy(u32 mutex_id)
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if ((u32&)mutex->cond_count) // check if associated condition variable exists
|
||||
if (mutex->cond_count) // check if associated condition variable exists
|
||||
{
|
||||
return CELL_EPERM;
|
||||
}
|
||||
@ -99,9 +99,7 @@ int sys_mutex_lock(u32 mutex_id, u64 timeout)
|
||||
PPUThread& t = GetCurrentPPUThread();
|
||||
u32 tid = t.GetId();
|
||||
|
||||
_mm_mfence();
|
||||
u32 owner = mutex->m_mutex.GetOwner();
|
||||
if (owner == tid)
|
||||
if (mutex->m_mutex.unlock(tid, tid) == SMR_OK)
|
||||
{
|
||||
if (mutex->is_recursive)
|
||||
{
|
||||
@ -116,7 +114,7 @@ int sys_mutex_lock(u32 mutex_id, u64 timeout)
|
||||
return CELL_EDEADLK;
|
||||
}
|
||||
}
|
||||
else if (owner)
|
||||
else if (u32 owner = mutex->m_mutex.GetOwner())
|
||||
{
|
||||
if (CPUThread* tt = Emu.GetCPU().GetThread(owner))
|
||||
{
|
||||
@ -170,9 +168,7 @@ int sys_mutex_trylock(u32 mutex_id)
|
||||
PPUThread& t = GetCurrentPPUThread();
|
||||
u32 tid = t.GetId();
|
||||
|
||||
_mm_mfence();
|
||||
u32 owner = mutex->m_mutex.GetOwner();
|
||||
if (owner == tid)
|
||||
if (mutex->m_mutex.unlock(tid, tid) == SMR_OK)
|
||||
{
|
||||
if (mutex->is_recursive)
|
||||
{
|
||||
@ -187,7 +183,7 @@ int sys_mutex_trylock(u32 mutex_id)
|
||||
return CELL_EDEADLK;
|
||||
}
|
||||
}
|
||||
else if (owner)
|
||||
else if (u32 owner = mutex->m_mutex.GetOwner())
|
||||
{
|
||||
if (CPUThread* tt = Emu.GetCPU().GetThread(owner))
|
||||
{
|
||||
@ -219,8 +215,7 @@ int sys_mutex_unlock(u32 mutex_id)
|
||||
PPUThread& t = GetCurrentPPUThread();
|
||||
u32 tid = t.GetId();
|
||||
|
||||
_mm_mfence();
|
||||
if (mutex->m_mutex.GetOwner() == tid)
|
||||
if (mutex->m_mutex.unlock(tid, tid) == SMR_OK)
|
||||
{
|
||||
if (!mutex->recursive || (mutex->recursive != 1 && !mutex->is_recursive))
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user