mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-12 22:14:58 +00:00
Experimental libmixer
adec, vdec improved fixed sound
This commit is contained in:
parent
79c01316d6
commit
994ce50392
@ -15,6 +15,11 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
const u32 GetSize() const
|
||||
{
|
||||
return SQSize;
|
||||
}
|
||||
|
||||
bool Push(const T& data)
|
||||
{
|
||||
while (true)
|
||||
|
@ -23,7 +23,7 @@ void AudioDumper::WriteHeader()
|
||||
|
||||
size_t AudioDumper::WriteData(const void* buffer, size_t size)
|
||||
{
|
||||
for (u32 i = 0; i < size / 8; i++)
|
||||
/*for (u32 i = 0; i < size / 8; i++)
|
||||
{
|
||||
if (((u64*)buffer)[i]) goto process;
|
||||
}
|
||||
@ -32,7 +32,7 @@ size_t AudioDumper::WriteData(const void* buffer, size_t size)
|
||||
if (((u8*)buffer)[i + (size & ~7)]) goto process;
|
||||
}
|
||||
return size; // ignore empty data
|
||||
process:
|
||||
process:*/
|
||||
size_t ret = m_output.Write(buffer, size);
|
||||
m_header.Size += ret;
|
||||
m_header.RIFF.Size += ret;
|
||||
|
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
extern u64 get_system_time();
|
||||
|
||||
// Error codes
|
||||
enum
|
||||
{
|
||||
@ -20,16 +22,6 @@ enum
|
||||
CELL_AUDIO_ERROR_AUDIOSYSTEM_NOT_FOUND = 0x8031070e,
|
||||
CELL_AUDIO_ERROR_TAG_NOT_FOUND = 0x8031070f,
|
||||
|
||||
//libmixer Error Codes
|
||||
CELL_LIBMIXER_ERROR_NOT_INITIALIZED = 0x80310002,
|
||||
CELL_LIBMIXER_ERROR_INVALID_PARAMATER = 0x80310003,
|
||||
CELL_LIBMIXER_ERROR_NO_MEMORY = 0x80310005,
|
||||
CELL_LIBMIXER_ERROR_ALREADY_EXIST = 0x80310006,
|
||||
CELL_LIBMIXER_ERROR_FULL = 0x80310007,
|
||||
CELL_LIBMIXER_ERROR_NOT_EXIST = 0x80310008,
|
||||
CELL_LIBMIXER_ERROR_TYPE_MISMATCH = 0x80310009,
|
||||
CELL_LIBMIXER_ERROR_NOT_FOUND = 0x8031000a,
|
||||
|
||||
//libsnd3 Error Codes
|
||||
CELL_SND3_ERROR_PARAM = 0x80310301,
|
||||
CELL_SND3_ERROR_CREATE_MUTEX = 0x80310302,
|
||||
@ -108,7 +100,6 @@ struct CellAudioPortConfig
|
||||
|
||||
struct AudioPortConfig
|
||||
{
|
||||
SMutexGeneral m_mutex;
|
||||
bool m_is_audio_port_opened;
|
||||
bool m_is_audio_port_started;
|
||||
u8 channel;
|
||||
@ -121,7 +112,6 @@ struct AudioPortConfig
|
||||
|
||||
struct AudioConfig //custom structure
|
||||
{
|
||||
std::mutex m_mutex;
|
||||
enum
|
||||
{
|
||||
AUDIO_PORT_COUNT = 8,
|
||||
@ -150,7 +140,9 @@ struct AudioConfig //custom structure
|
||||
memset(&m_ports, 0, sizeof(AudioPortConfig) * AUDIO_PORT_COUNT);
|
||||
m_port_in_use = 0;
|
||||
}
|
||||
} m_config;
|
||||
};
|
||||
|
||||
extern AudioConfig m_config;
|
||||
|
||||
//libsnd3 datatypes
|
||||
struct CellSnd3DataCtx
|
||||
|
@ -34,8 +34,11 @@ struct SFuncOp
|
||||
struct SFunc
|
||||
{
|
||||
func_caller* func;
|
||||
void* ptr;
|
||||
char* name;
|
||||
Array<SFuncOp> ops;
|
||||
u64 group;
|
||||
u32 found;
|
||||
};
|
||||
|
||||
extern ArrayF<SFunc> g_static_funcs_list;
|
||||
@ -110,7 +113,7 @@ public:
|
||||
|
||||
template<typename T> __forceinline void AddFunc(u32 id, T func);
|
||||
|
||||
template<typename T> __forceinline void AddFuncSub(const u64 ops[], char* name, T func);
|
||||
template<typename T> __forceinline void AddFuncSub(const char group[8], const u64 ops[], char* name, T func);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
@ -120,13 +123,16 @@ __forceinline void Module::AddFunc(u32 id, T func)
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
__forceinline void Module::AddFuncSub(const u64 ops[], char* name, T func)
|
||||
__forceinline void Module::AddFuncSub(const char group[8], const u64 ops[], char* name, T func)
|
||||
{
|
||||
if (!ops[0]) return;
|
||||
|
||||
SFunc* sf = new SFunc;
|
||||
sf->ptr = func;
|
||||
sf->func = bind_func(func);
|
||||
sf->name = name;
|
||||
sf->group = *(u64*)group;
|
||||
sf->found = 0;
|
||||
|
||||
// TODO: check for self-inclusions, use CRC
|
||||
|
||||
|
@ -63,8 +63,6 @@ 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);
|
||||
|
||||
//if (adec.last_pts > adec.task.au.pts) adec.last_pts = adec.task.au.pts;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -266,8 +264,11 @@ u32 adecOpen(AudioDecoder* data)
|
||||
adec.reader.size = task.au.size;
|
||||
//ConLog.Write("Audio AU: size = 0x%x, pts = 0x%llx", task.au.size, task.au.pts);
|
||||
|
||||
//if (adec.last_pts > task.au.pts || adec.just_started) adec.last_pts = task.au.pts;
|
||||
if (adec.just_started) adec.last_pts = task.au.pts;
|
||||
if (adec.just_started)
|
||||
{
|
||||
adec.first_pts = task.au.pts;
|
||||
adec.last_pts = task.au.pts /*- 3816*8*/; // hack
|
||||
}
|
||||
|
||||
struct AVPacketHolder : AVPacket
|
||||
{
|
||||
@ -433,8 +434,19 @@ u32 adecOpen(AudioDecoder* data)
|
||||
|
||||
if (got_frame)
|
||||
{
|
||||
frame.pts = adec.last_pts;
|
||||
adec.last_pts += ((u64)frame.data->nb_samples) * 90000 / 48000; // ???
|
||||
u64 ts = av_frame_get_best_effort_timestamp(frame.data);
|
||||
if (ts != AV_NOPTS_VALUE)
|
||||
{
|
||||
frame.pts = ts/* - adec.first_pts*/;
|
||||
adec.last_pts = frame.pts;
|
||||
}
|
||||
else
|
||||
{
|
||||
adec.last_pts += ((u64)frame.data->nb_samples) * 90000 / 48000;
|
||||
frame.pts = adec.last_pts;
|
||||
}
|
||||
//frame.pts = adec.last_pts;
|
||||
//adec.last_pts += ((u64)frame.data->nb_samples) * 90000 / 48000; // ???
|
||||
frame.auAddr = task.au.addr;
|
||||
frame.auSize = task.au.size;
|
||||
frame.userdata = task.au.userdata;
|
||||
|
@ -1114,7 +1114,7 @@ public:
|
||||
u32 memBias;
|
||||
|
||||
AdecTask task;
|
||||
u64 last_pts;
|
||||
u64 last_pts, first_pts;
|
||||
|
||||
CPUThread* adecCb;
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
#include "Emu/SysCalls/SC_FUNC.h"
|
||||
#include "Utilities/SQueue.h"
|
||||
#include "Emu/Audio/cellAudio.h"
|
||||
#include "Emu/Audio/AudioManager.h"
|
||||
#include "Emu/Audio/AudioDumper.h"
|
||||
@ -9,7 +10,9 @@ void cellAudio_init();
|
||||
void cellAudio_unload();
|
||||
Module cellAudio(0x0011, cellAudio_init, nullptr, cellAudio_unload);
|
||||
|
||||
extern u64 get_system_time();
|
||||
static SMutexGeneral audioMutex;
|
||||
|
||||
AudioConfig m_config;
|
||||
|
||||
// libaudio Functions
|
||||
|
||||
@ -23,6 +26,7 @@ int cellAudioInit()
|
||||
}
|
||||
|
||||
m_config.m_is_audio_initialized = true;
|
||||
m_config.start_time = 0;
|
||||
m_config.counter = 0;
|
||||
|
||||
// alloc memory
|
||||
@ -43,31 +47,57 @@ int cellAudioInit()
|
||||
|
||||
ConLog.Write("Audio started");
|
||||
|
||||
m_config.start_time = get_system_time();
|
||||
|
||||
if (Ini.AudioDumpToFile.GetValue())
|
||||
m_dump.WriteHeader();
|
||||
|
||||
float buffer[2*256]; // buffer for 2 channels
|
||||
be_t<float> buffer2[8*256]; // buffer for 8 channels (max count)
|
||||
//u16 oal_buffer[2*256]; // buffer for OpenAL
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
memset(buffer2, 0, sizeof(buffer2));
|
||||
|
||||
uint oal_buffer_offset = 0;
|
||||
uint oal_buffer_size = 2 * 256;
|
||||
std::unique_ptr<u16[]> oal_buffer(new u16[oal_buffer_size]);
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
memset(buffer2, 0, sizeof(buffer2));
|
||||
memset(oal_buffer.get(), 0, oal_buffer_size * sizeof(u16));
|
||||
std::unique_ptr<u16[]> oal_buffer[32];
|
||||
SQueue<u16*, sizeof(oal_buffer) / sizeof(oal_buffer[0])> queue;
|
||||
for (u32 i = 0; i < queue.GetSize(); i++)
|
||||
{
|
||||
oal_buffer[i] = std::unique_ptr<u16[]>(new u16[oal_buffer_size]);
|
||||
memset(oal_buffer[i].get(), 0, oal_buffer_size * sizeof(u16));
|
||||
}
|
||||
queue.Clear();
|
||||
//std::unique_ptr<u16[]> oal_buf(new u16[oal_buffer_size]);
|
||||
//memset(oal_buffer.get(), 0, oal_buffer_size * sizeof(u16));
|
||||
|
||||
Array<u64> keys;
|
||||
|
||||
if(m_audio_out)
|
||||
{
|
||||
m_audio_out->Init();
|
||||
m_audio_out->Open(oal_buffer.get(), oal_buffer_size*sizeof(u16));
|
||||
m_audio_out->Open(oal_buffer[0].get(), oal_buffer_size * sizeof(u16));
|
||||
}
|
||||
|
||||
m_config.start_time = get_system_time();
|
||||
|
||||
thread iat("Internal Audio Thread", [oal_buffer_size, &queue]()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
u16* oal_buffer = nullptr;
|
||||
queue.Pop(oal_buffer);
|
||||
|
||||
if (oal_buffer)
|
||||
{
|
||||
m_audio_out->AddData(oal_buffer, oal_buffer_size * sizeof(u16));
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
iat.detach();
|
||||
|
||||
while (m_config.m_is_audio_initialized)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
@ -76,10 +106,12 @@ int cellAudioInit()
|
||||
goto abort;
|
||||
}
|
||||
|
||||
const u64 stamp0 = get_system_time();
|
||||
|
||||
// TODO: send beforemix event (in ~2,6 ms before mixing)
|
||||
|
||||
// Sleep(5); // precise time of sleeping: 5,(3) ms (or 256/48000 sec)
|
||||
if (m_config.counter * 256000000 / 48000 >= get_system_time() - m_config.start_time)
|
||||
// precise time of sleeping: 5,(3) ms (or 256/48000 sec)
|
||||
if (m_config.counter * 256000000 / 48000 >= stamp0 - m_config.start_time)
|
||||
{
|
||||
Sleep(1);
|
||||
continue;
|
||||
@ -87,6 +119,8 @@ int cellAudioInit()
|
||||
|
||||
m_config.counter++;
|
||||
|
||||
const u32 oal_pos = m_config.counter % queue.GetSize();
|
||||
|
||||
if (Emu.IsPaused())
|
||||
{
|
||||
continue;
|
||||
@ -112,13 +146,13 @@ int cellAudioInit()
|
||||
memset(Memory + buf_addr, 0, block_size * sizeof(float));
|
||||
|
||||
{
|
||||
SMutexGeneralLocker lock(port.m_mutex);
|
||||
SMutexGeneralLocker lock(audioMutex);
|
||||
port.counter = m_config.counter;
|
||||
port.tag++; // absolute index of block that will be read
|
||||
index = (position + 1) % port.block; // write new value
|
||||
}
|
||||
|
||||
u32 k = port.channel / 2;
|
||||
const u32 k = port.channel / 2;
|
||||
|
||||
if (first_mix)
|
||||
{
|
||||
@ -129,10 +163,10 @@ int cellAudioInit()
|
||||
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));
|
||||
//assert(buffer[i] >= -1.0f && buffer[i] <= 1.0f);
|
||||
//assert(buffer[i+1] >= -1.0f && buffer[i+1] <= 1.0f);
|
||||
oal_buffer[oal_pos][oal_buffer_offset + i] = (u16)(buffer[i] * ((1 << 14) - 1));
|
||||
oal_buffer[oal_pos][oal_buffer_offset + i + 1] = (u16)(buffer[i+1] * ((1 << 14) - 1));
|
||||
}
|
||||
|
||||
first_mix = false;
|
||||
@ -145,17 +179,19 @@ int cellAudioInit()
|
||||
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));
|
||||
//assert(buffer[i] >= -1.0f && buffer[i] <= 1.0f);
|
||||
//assert(buffer[i+1] >= -1.0f && buffer[i+1] <= 1.0f);
|
||||
oal_buffer[oal_pos][oal_buffer_offset + i] = (u16)(buffer[i] * ((1 << 14) - 1));
|
||||
oal_buffer[oal_pos][oal_buffer_offset + i + 1] = (u16)(buffer[i+1] * ((1 << 14) - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const u64 stamp1 = get_system_time();
|
||||
|
||||
// send aftermix event (normal audio event)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_config.m_mutex);
|
||||
SMutexGeneralLocker lock(audioMutex);
|
||||
keys.SetCount(m_config.m_keys.GetCount());
|
||||
memcpy(keys.GetPtr(), m_config.m_keys.GetPtr(), sizeof(u64) * keys.GetCount());
|
||||
}
|
||||
@ -165,18 +201,22 @@ int cellAudioInit()
|
||||
Emu.GetEventManager().SendEvent(keys[i], 0x10103000e010e07, 0, 0, 0);
|
||||
}
|
||||
|
||||
const u64 stamp2 = get_system_time();
|
||||
|
||||
oal_buffer_offset += sizeof(buffer) / sizeof(float);
|
||||
|
||||
if(oal_buffer_offset >= oal_buffer_size)
|
||||
{
|
||||
if(m_audio_out)
|
||||
{
|
||||
m_audio_out->AddData(oal_buffer.get(), oal_buffer_offset * sizeof(u16));
|
||||
queue.Push(&oal_buffer[oal_pos][0]);
|
||||
}
|
||||
|
||||
oal_buffer_offset = 0;
|
||||
}
|
||||
|
||||
const u64 stamp3 = get_system_time();
|
||||
|
||||
if(Ini.AudioDumpToFile.GetValue())
|
||||
{
|
||||
if (m_dump.WriteData(&buffer, sizeof(buffer)) != sizeof(buffer)) // write file data
|
||||
@ -185,16 +225,37 @@ int cellAudioInit()
|
||||
goto abort;
|
||||
}
|
||||
}
|
||||
|
||||
const u64 stamp4 = get_system_time();
|
||||
|
||||
//ConLog.Write("Audio perf: start=%d (access=%d, event=%d, AddData=%d, dump=%d)",
|
||||
//stamp0 - m_config.start_time, stamp1-stamp0, stamp2-stamp1, stamp3-stamp2, stamp4-stamp3);
|
||||
}
|
||||
ConLog.Write("Audio finished");
|
||||
abort:
|
||||
queue.Push(nullptr);
|
||||
while (queue.GetCount())
|
||||
{
|
||||
Sleep(1);
|
||||
}
|
||||
if(Ini.AudioDumpToFile.GetValue())
|
||||
m_dump.Finalize();
|
||||
|
||||
m_config.m_is_audio_finalized = true;
|
||||
m_config.m_is_audio_initialized = false;
|
||||
});
|
||||
t.detach();
|
||||
|
||||
while (!m_config.start_time) // waiting for initialization
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
ConLog.Warning("cellAudioInit() aborted");
|
||||
return CELL_OK;
|
||||
}
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -395,7 +456,7 @@ int cellAudioGetPortTimestamp(u32 portNum, u64 tag, mem64_t stamp)
|
||||
|
||||
AudioPortConfig& port = m_config.m_ports[portNum];
|
||||
|
||||
SMutexGeneralLocker lock(port.m_mutex);
|
||||
SMutexGeneralLocker lock(audioMutex);
|
||||
|
||||
stamp = m_config.start_time + (port.counter + (tag - port.tag)) * 256000000 / 48000;
|
||||
|
||||
@ -429,7 +490,7 @@ int cellAudioGetPortBlockTag(u32 portNum, u64 blockNo, mem64_t tag)
|
||||
return CELL_AUDIO_ERROR_PARAM;
|
||||
}
|
||||
|
||||
SMutexGeneralLocker lock(port.m_mutex);
|
||||
SMutexGeneralLocker lock(audioMutex);
|
||||
|
||||
u64 tag_base = port.tag;
|
||||
if (tag_base % port.block > blockNo)
|
||||
@ -457,7 +518,7 @@ int cellAudioCreateNotifyEventQueue(mem32_t id, mem64_t key)
|
||||
{
|
||||
cellAudio.Warning("cellAudioCreateNotifyEventQueue(id_addr=0x%x, key_addr=0x%x)", id.GetAddr(), key.GetAddr());
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_config.m_mutex);
|
||||
SMutexGeneralLocker lock(audioMutex);
|
||||
|
||||
u64 event_key = 0;
|
||||
while (Emu.GetEventManager().CheckKey((event_key << 48) | 0x80004d494f323221))
|
||||
@ -475,7 +536,6 @@ int cellAudioCreateNotifyEventQueue(mem32_t id, mem64_t key)
|
||||
return CELL_AUDIO_ERROR_EVENT_QUEUE;
|
||||
}
|
||||
|
||||
m_config.m_keys.AddCpy(event_key);
|
||||
id = cellAudio.GetNewId(eq);
|
||||
key = event_key;
|
||||
|
||||
@ -492,8 +552,15 @@ int cellAudioSetNotifyEventQueue(u64 key)
|
||||
{
|
||||
cellAudio.Warning("cellAudioSetNotifyEventQueue(key=0x%llx)", key);
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_config.m_mutex);
|
||||
SMutexGeneralLocker lock(audioMutex);
|
||||
|
||||
for (u32 i = 0; i < m_config.m_keys.GetCount(); i++) // check for duplicates
|
||||
{
|
||||
if (m_config.m_keys[i] == key)
|
||||
{
|
||||
return CELL_AUDIO_ERROR_PARAM;
|
||||
}
|
||||
}
|
||||
m_config.m_keys.AddCpy(key);
|
||||
|
||||
/*EventQueue* eq;
|
||||
@ -517,7 +584,7 @@ int cellAudioRemoveNotifyEventQueue(u64 key)
|
||||
{
|
||||
cellAudio.Warning("cellAudioRemoveNotifyEventQueue(key=0x%llx)", key);
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_config.m_mutex);
|
||||
SMutexGeneralLocker lock(audioMutex);
|
||||
|
||||
bool found = false;
|
||||
for (u32 i = 0; i < m_config.m_keys.GetCount(); i++)
|
||||
|
@ -67,9 +67,6 @@ 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);
|
||||
|
||||
//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:
|
||||
@ -208,12 +205,11 @@ u32 vdecOpen(VideoDecoder* data)
|
||||
vdec.reader.size = task.size;
|
||||
//ConLog.Write("Video AU: size = 0x%x, pts = 0x%llx, dts = 0x%llx", task.size, task.pts, task.dts);
|
||||
|
||||
//if (vdec.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;
|
||||
if (vdec.just_started)
|
||||
{
|
||||
vdec.first_pts = task.pts;
|
||||
vdec.last_pts = task.pts;
|
||||
vdec.last_dts = task.dts;
|
||||
vdec.first_dts = task.dts;
|
||||
}
|
||||
|
||||
struct AVPacketHolder : AVPacket
|
||||
@ -357,8 +353,20 @@ u32 vdecOpen(VideoDecoder* data)
|
||||
|
||||
if (got_picture)
|
||||
{
|
||||
frame.dts = vdec.last_dts; vdec.last_dts += 3003; // + duration???
|
||||
frame.pts = vdec.last_pts; vdec.last_pts += 3003;
|
||||
u64 ts = av_frame_get_best_effort_timestamp(frame.data);
|
||||
if (ts != AV_NOPTS_VALUE)
|
||||
{
|
||||
frame.pts = ts/* - vdec.first_pts*/; // ???
|
||||
vdec.last_pts = frame.pts;
|
||||
}
|
||||
else
|
||||
{
|
||||
vdec.last_pts += vdec.ctx->time_base.num * 90000 / (vdec.ctx->time_base.den / vdec.ctx->ticks_per_frame);
|
||||
frame.pts = vdec.last_pts;
|
||||
}
|
||||
//frame.pts = vdec.last_pts;
|
||||
//vdec.last_pts += 3754;
|
||||
frame.dts = (frame.pts - vdec.first_pts) + vdec.first_dts;
|
||||
frame.userdata = task.userData;
|
||||
|
||||
//ConLog.Write("got picture (pts=0x%llx, dts=0x%llx)", frame.pts, frame.dts);
|
||||
@ -726,7 +734,27 @@ int cellVdecGetPicItem(u32 handle, mem32_t picItem_ptr)
|
||||
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;
|
||||
avc->frameRateCode = CELL_VDEC_AVC_FRC_30000DIV1001; // important (!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)
|
||||
if (vdec->ctx->time_base.num == 1001)
|
||||
{
|
||||
if (vdec->ctx->time_base.den == 48000 && vdec->ctx->ticks_per_frame == 2)
|
||||
{
|
||||
avc->frameRateCode = CELL_VDEC_AVC_FRC_24000DIV1001;
|
||||
}
|
||||
else if (vdec->ctx->time_base.den == 60000 && vdec->ctx->ticks_per_frame == 2)
|
||||
{
|
||||
avc->frameRateCode = CELL_VDEC_AVC_FRC_30000DIV1001;
|
||||
}
|
||||
else
|
||||
{
|
||||
ConLog.Error("cellVdecGetPicItem: unsupported time_base.den (%d)", vdec->ctx->time_base.den);
|
||||
Emu.Pause();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ConLog.Error("cellVdecGetPicItem: unsupported time_base.num (%d)", vdec->ctx->time_base.num);
|
||||
Emu.Pause();
|
||||
}
|
||||
avc->fixed_frame_rate_flag = true;
|
||||
avc->low_delay_hrd_flag = true; // ???
|
||||
avc->entropy_coding_mode_flag = true; // ???
|
||||
|
@ -719,7 +719,8 @@ public:
|
||||
u32 memBias;
|
||||
|
||||
VdecTask task; // current task variable
|
||||
u64 last_pts, last_dts;
|
||||
u64 last_pts, first_pts, first_dts;
|
||||
AVRational rfr, afr;
|
||||
|
||||
CPUThread* vdecCb;
|
||||
|
||||
|
@ -1,15 +1,47 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
#include "Emu/SysCalls/SC_FUNC.h"
|
||||
#include "Emu/Audio/cellAudio.h"
|
||||
#include "libmixer.h"
|
||||
|
||||
void libmixer_init();
|
||||
Module libmixer("libmixer", libmixer_init);
|
||||
|
||||
int cellAANAddData(u32 handle, u32 port, u32 offset, u32 addr, u32 samples)
|
||||
CellSurMixerConfig surMixer;
|
||||
|
||||
#define SUR_PORT (7)
|
||||
u32 surMixerCb = 0;
|
||||
u32 surMixerCbArg = 0;
|
||||
u64 mixcount = 0, stamp1 = 0, stamp2 = 0;
|
||||
|
||||
int cellAANAddData(u32 aan_handle, u32 aan_port, u32 offset, u32 addr, u32 samples)
|
||||
{
|
||||
libmixer.Error("cellAANAddData(handle=0x%x, port=0x%x, offset=0x%x, addr=0x%x, samples=0x%x)",
|
||||
handle, port, offset, addr, samples);
|
||||
stamp1 = get_system_time();
|
||||
|
||||
if (aan_handle == 0x11111111 && aan_port == (2 << 16))
|
||||
{
|
||||
libmixer.Log("cellAANAddData(handle=0x%x, port=0x%x, offset=0x%x, addr=0x%x, samples=0x%x)",
|
||||
aan_handle, aan_port, offset, addr, samples);
|
||||
}
|
||||
else
|
||||
{
|
||||
libmixer.Error("cellAANAddData(handle=0x%x, port=0x%x, offset=0x%x, addr=0x%x, samples=0x%x)",
|
||||
aan_handle, aan_port, offset, addr, samples);
|
||||
Emu.Pause();
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
AudioPortConfig& port = m_config.m_ports[SUR_PORT];
|
||||
|
||||
u32 to = m_config.m_buffer + (128 * 1024 * SUR_PORT) + ((mixcount + 12) % 16) * 2 * 256 * sizeof(float) + offset;
|
||||
|
||||
if (!Memory.Copy(to, addr, 2 * samples * sizeof(float)))
|
||||
{
|
||||
return CELL_LIBMIXER_ERROR_NO_MEMORY;
|
||||
}
|
||||
|
||||
stamp2 = get_system_time();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -71,49 +103,127 @@ s32 cellSSPlayerGetState() //CellAANHandle handle
|
||||
|
||||
int cellSurMixerCreate(const mem_ptr_t<CellSurMixerConfig> config)
|
||||
{
|
||||
libmixer.Error("cellSurMixerCreate(config_addr=0x%x)", config.GetAddr());
|
||||
libmixer.Warning("cellSurMixerCreate(config_addr=0x%x)", config.GetAddr());
|
||||
surMixer = *config;
|
||||
libmixer.Warning("*** surMixer created (ch1=%d, ch2=%d, ch6=%d, ch8=%d)",
|
||||
(u32)surMixer.chStrips1, (u32)surMixer.chStrips2, (u32)surMixer.chStrips6, (u32)surMixer.chStrips8);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellSurMixerGetAANHandle(mem32_t handle)
|
||||
{
|
||||
libmixer.Error("cellSurMixerGetAANHandle(handle_addr=0x%x)", handle.GetAddr());
|
||||
libmixer.Warning("cellSurMixerGetAANHandle(handle_addr=0x%x) -> 0x11111111", handle.GetAddr());
|
||||
handle = 0x11111111;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellSurMixerChStripGetAANPortNo(mem32_t port, u32 type, u32 index)
|
||||
{
|
||||
libmixer.Error("cellSurMixerChStripGetAANPortNo(port_addr=0x%x, type=0x%x, index=0x%x)", port.GetAddr(), type, index);
|
||||
libmixer.Warning("cellSurMixerChStripGetAANPortNo(port_addr=0x%x, type=0x%x, index=0x%x) -> 0", port.GetAddr(), type, index);
|
||||
port = (type << 16) | index;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellSurMixerSetNotifyCallback(u32 func, u32 arg)
|
||||
{
|
||||
libmixer.Error("cellSurMixerSetNotifyCallback(func_addr=0x%x, arg=0x%x)", func, arg);
|
||||
libmixer.Warning("cellSurMixerSetNotifyCallback(func_addr=0x%x, arg=0x%x)", func, arg);
|
||||
surMixerCb = func;
|
||||
surMixerCbArg = arg;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellSurMixerRemoveNotifyCallback(u32 func)
|
||||
{
|
||||
libmixer.Error("cellSurMixerSetNotifyCallback(func_addr=0x%x)", func);
|
||||
libmixer.Warning("cellSurMixerSetNotifyCallback(func_addr=0x%x)", func);
|
||||
surMixerCb = 0;
|
||||
surMixerCbArg = 0;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellSurMixerStart()
|
||||
{
|
||||
libmixer.Error("cellSurMixerStart()");
|
||||
libmixer.Warning("cellSurMixerStart()");
|
||||
|
||||
AudioPortConfig& port = m_config.m_ports[SUR_PORT];
|
||||
|
||||
if (port.m_is_audio_port_opened)
|
||||
{
|
||||
return CELL_LIBMIXER_ERROR_FULL;
|
||||
}
|
||||
|
||||
port.channel = 2;
|
||||
port.block = 16;
|
||||
port.attr = 0;
|
||||
port.level = 1.0f;
|
||||
|
||||
libmixer.Warning("*** audio port opened(default, port 7)");
|
||||
|
||||
port.m_is_audio_port_opened = true;
|
||||
port.tag = 0;
|
||||
m_config.m_port_in_use++;
|
||||
port.m_is_audio_port_started = true;
|
||||
|
||||
thread t("Libmixer Thread", []()
|
||||
{
|
||||
AudioPortConfig& port = m_config.m_ports[SUR_PORT];
|
||||
|
||||
CPUThread* mixerCb = &Emu.GetCPU().AddThread(CPU_THREAD_PPU);
|
||||
|
||||
mixerCb->SetName("Libmixer Callback");
|
||||
|
||||
mixcount = 0;
|
||||
|
||||
while (port.m_is_audio_port_started)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
ConLog.Warning("Libmixer aborted");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mixcount > port.tag)
|
||||
{
|
||||
Sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
u64 stamp0 = get_system_time();
|
||||
stamp1 = 0;
|
||||
stamp2 = 0;
|
||||
|
||||
mixerCb->ExecAsCallback(surMixerCb, true, surMixerCbArg, mixcount, 256);
|
||||
|
||||
u64 stamp3 = get_system_time();
|
||||
|
||||
//ConLog.Write("Libmixer perf: start=%d (cb_before=%d, cb=%d, cb_after=%d)",
|
||||
//stamp0 - m_config.start_time, stamp1-stamp0, stamp2-stamp1, stamp3-stamp2);
|
||||
|
||||
mixcount++;
|
||||
}
|
||||
|
||||
Emu.GetCPU().RemoveThread(mixerCb->GetId());
|
||||
});
|
||||
t.detach();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellSurMixerSetParameter(u32 param, float value)
|
||||
{
|
||||
libmixer.Error("cellSurMixerSetParameter(param=0x%x, value=%f)", param, value);
|
||||
libmixer.Warning("cellSurMixerSetParameter(param=0x%x, value=%f)", param, value);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellSurMixerFinalize()
|
||||
{
|
||||
libmixer.Error("cellSurMixerFinalize()");
|
||||
libmixer.Warning("cellSurMixerFinalize()");
|
||||
|
||||
AudioPortConfig& port = m_config.m_ports[SUR_PORT];
|
||||
|
||||
port.m_is_audio_port_started = false;
|
||||
port.m_is_audio_port_opened = false;
|
||||
m_config.m_port_in_use--;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -198,7 +308,7 @@ void libmixer_init()
|
||||
0xffffffff4e800020,
|
||||
0
|
||||
};
|
||||
libmixer.AddFuncSub(cellAANAddData_table, "cellAANAddData", cellAANAddData);
|
||||
libmixer.AddFuncSub("mixerAAN", cellAANAddData_table, "cellAANAddData", cellAANAddData);
|
||||
|
||||
u64 cellAANConnect_table[39] = {
|
||||
0xfffffffff821ff71,
|
||||
@ -241,9 +351,9 @@ void libmixer_init()
|
||||
0xffffffff4e800020,
|
||||
0, // [38]
|
||||
};
|
||||
libmixer.AddFuncSub(cellAANConnect_table, "cellAANConnect", cellAANConnect);
|
||||
libmixer.AddFuncSub("mixerAAN", cellAANConnect_table, "cellAANConnect", cellAANConnect);
|
||||
cellAANConnect_table[24] = 0xffffffff812b001c;
|
||||
libmixer.AddFuncSub(cellAANConnect_table, "cellAANDisconnect", cellAANDisconnect);
|
||||
libmixer.AddFuncSub("mixerAAN", cellAANConnect_table, "cellAANDisconnect", cellAANDisconnect);
|
||||
|
||||
static const u64 cellAANAddData_table1[] = {
|
||||
// TODO
|
||||
@ -272,7 +382,7 @@ void libmixer_init()
|
||||
0xffffffff4e800020,
|
||||
0
|
||||
};
|
||||
libmixer.AddFuncSub(cellAANAddData_table1, "cellAANAddData(1)", cellAANAddData);
|
||||
libmixer.AddFuncSub("mixerAAN", cellAANAddData_table1, "cellAANAddData(1)", cellAANAddData);
|
||||
|
||||
static const u64 cellSurMixerCreate_table[] = {
|
||||
0xffffffff2f830000,
|
||||
@ -303,7 +413,7 @@ void libmixer_init()
|
||||
0xffffffff382100b0,
|
||||
0
|
||||
};
|
||||
libmixer.AddFuncSub(cellSurMixerCreate_table, "cellSurMixerCreate", cellSurMixerCreate);
|
||||
libmixer.AddFuncSub("surMixer", cellSurMixerCreate_table, "cellSurMixerCreate", cellSurMixerCreate);
|
||||
|
||||
static const u64 cellSurMixerGetAANHandle_table[] = {
|
||||
// first instruction ignored
|
||||
@ -322,7 +432,7 @@ void libmixer_init()
|
||||
0xffffffff4e800020,
|
||||
0
|
||||
};
|
||||
libmixer.AddFuncSub(cellSurMixerGetAANHandle_table, "cellSurMixerGetAANHandle", cellSurMixerGetAANHandle);
|
||||
libmixer.AddFuncSub("surMixer", cellSurMixerGetAANHandle_table, "cellSurMixerGetAANHandle", cellSurMixerGetAANHandle);
|
||||
|
||||
static const u64 cellSurMixerChStripGetAANPortNo_table[] = {
|
||||
// first instruction ignored
|
||||
@ -339,7 +449,7 @@ void libmixer_init()
|
||||
0xf000000040000000, // b
|
||||
0
|
||||
};
|
||||
libmixer.AddFuncSub(cellSurMixerChStripGetAANPortNo_table, "cellSurMixerChStripGetAANPortNo", cellSurMixerChStripGetAANPortNo);
|
||||
libmixer.AddFuncSub("surMixer", cellSurMixerChStripGetAANPortNo_table, "cellSurMixerChStripGetAANPortNo", cellSurMixerChStripGetAANPortNo);
|
||||
|
||||
static const u64 cellSurMixerSetNotifyCallback_table[] = {
|
||||
// first instruction ignored
|
||||
@ -369,7 +479,7 @@ void libmixer_init()
|
||||
0xffffffff7d234b78,
|
||||
0
|
||||
};
|
||||
libmixer.AddFuncSub(cellSurMixerSetNotifyCallback_table, "cellSurMixerSetNotifyCallback", cellSurMixerSetNotifyCallback);
|
||||
libmixer.AddFuncSub("surMixer", cellSurMixerSetNotifyCallback_table, "cellSurMixerSetNotifyCallback", cellSurMixerSetNotifyCallback);
|
||||
|
||||
static const u64 cellSurMixerRemoveNotifyCallback_table[] = {
|
||||
// first instruction ignored
|
||||
@ -389,7 +499,7 @@ void libmixer_init()
|
||||
0xffffffff4e800020,
|
||||
0
|
||||
};
|
||||
libmixer.AddFuncSub(cellSurMixerRemoveNotifyCallback_table, "cellSurMixerRemoveNotifyCallback", cellSurMixerRemoveNotifyCallback);
|
||||
libmixer.AddFuncSub("surMixer", cellSurMixerRemoveNotifyCallback_table, "cellSurMixerRemoveNotifyCallback", cellSurMixerRemoveNotifyCallback);
|
||||
|
||||
static const u64 cellSurMixerStart_table[] = {
|
||||
0xfffffffff821ff71,
|
||||
@ -414,7 +524,7 @@ void libmixer_init()
|
||||
0xffffffff4e800020,
|
||||
0
|
||||
};
|
||||
libmixer.AddFuncSub(cellSurMixerStart_table, "cellSurMixerStart", cellSurMixerStart);
|
||||
libmixer.AddFuncSub("surMixer", cellSurMixerStart_table, "cellSurMixerStart", cellSurMixerStart);
|
||||
|
||||
static const u64 cellSurMixerSetParameter_table[] = {
|
||||
0xfffffffff821ff81,
|
||||
@ -446,7 +556,7 @@ void libmixer_init()
|
||||
0xffff0000409d0054, // ble
|
||||
0
|
||||
};
|
||||
libmixer.AddFuncSub(cellSurMixerSetParameter_table, "cellSurMixerSetParameter", cellSurMixerSetParameter);
|
||||
libmixer.AddFuncSub("surMixer", cellSurMixerSetParameter_table, "cellSurMixerSetParameter", cellSurMixerSetParameter);
|
||||
|
||||
static const u64 cellSurMixerFinalize_table[] = {
|
||||
0xfffffffff821ff91,
|
||||
@ -474,5 +584,5 @@ void libmixer_init()
|
||||
0xffffffff4e800421,
|
||||
0
|
||||
};
|
||||
libmixer.AddFuncSub(cellSurMixerFinalize_table, "cellSurMixerFinalize", cellSurMixerFinalize);
|
||||
libmixer.AddFuncSub("surMixer", cellSurMixerFinalize_table, "cellSurMixerFinalize", cellSurMixerFinalize);
|
||||
}
|
@ -1,5 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
enum
|
||||
{
|
||||
//libmixer Error Codes
|
||||
CELL_LIBMIXER_ERROR_NOT_INITIALIZED = 0x80310002,
|
||||
CELL_LIBMIXER_ERROR_INVALID_PARAMATER = 0x80310003,
|
||||
CELL_LIBMIXER_ERROR_NO_MEMORY = 0x80310005,
|
||||
CELL_LIBMIXER_ERROR_ALREADY_EXIST = 0x80310006,
|
||||
CELL_LIBMIXER_ERROR_FULL = 0x80310007,
|
||||
CELL_LIBMIXER_ERROR_NOT_EXIST = 0x80310008,
|
||||
CELL_LIBMIXER_ERROR_TYPE_MISMATCH = 0x80310009,
|
||||
CELL_LIBMIXER_ERROR_NOT_FOUND = 0x8031000a,
|
||||
};
|
||||
|
||||
//Callback Functions
|
||||
typedef int (*CellSurMixerNotifyCallbackFunction)(void *arg, u32 counter, u32 samples); //Currently unused.
|
||||
|
@ -9,8 +9,6 @@ void StaticAnalyse(void* ptr, u32 size)
|
||||
{
|
||||
u32* data = (u32*)ptr; size /= 4;
|
||||
|
||||
return; // disabled
|
||||
|
||||
// TODO: optimize search
|
||||
for (u32 i = 0; i < size; i++)
|
||||
{
|
||||
@ -36,7 +34,8 @@ void StaticAnalyse(void* ptr, u32 size)
|
||||
}
|
||||
if (found)
|
||||
{
|
||||
ConLog.Success("Function '%s' hooked", wxString(g_static_funcs_list[j].name).wx_str());
|
||||
//ConLog.Success("Function '%s' hooked", wxString(g_static_funcs_list[j].name).wx_str());
|
||||
g_static_funcs_list[j].found++;
|
||||
data[i] = re(0x39600000 | j); // li r11, j
|
||||
data[i+1] = se32(0x44000003); // sc 3
|
||||
data[i+2] = se32(0x4e800020); // blr
|
||||
@ -45,6 +44,91 @@ void StaticAnalyse(void* ptr, u32 size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check function groups
|
||||
for (u32 i = 0; i < g_static_funcs_list.GetCount(); i++)
|
||||
{
|
||||
if (g_static_funcs_list[i].found) // start from some group
|
||||
{
|
||||
const u64 group = g_static_funcs_list[i].group;
|
||||
|
||||
enum GroupSearchResult : u32
|
||||
{
|
||||
GSR_SUCCESS = 0, // every function from this group has been found
|
||||
GSR_MISSING = 1, // (error) not every function found
|
||||
GSR_EXCESS = 2, // (error) some function found twice or more
|
||||
};
|
||||
u32 res = GSR_SUCCESS;
|
||||
|
||||
// analyse
|
||||
for (u32 j = i; j < g_static_funcs_list.GetCount(); j++) if (g_static_funcs_list[j].group == group)
|
||||
{
|
||||
u32 count = g_static_funcs_list[j].found;
|
||||
|
||||
if (count == 0) // not found
|
||||
{
|
||||
// check if this function has been found with different pattern
|
||||
for (u32 k = i; k < g_static_funcs_list.GetCount(); k++) if (g_static_funcs_list[k].group == group)
|
||||
{
|
||||
if (k != j && g_static_funcs_list[k].ptr == g_static_funcs_list[j].ptr)
|
||||
{
|
||||
count += g_static_funcs_list[k].found;
|
||||
}
|
||||
}
|
||||
if (count == 0)
|
||||
{
|
||||
res |= GSR_MISSING;
|
||||
ConLog.Error("Function '%s' not found", wxString(g_static_funcs_list[j].name).wx_str());
|
||||
}
|
||||
else if (count > 1)
|
||||
{
|
||||
res |= GSR_EXCESS;
|
||||
}
|
||||
}
|
||||
else if (count == 1) // found
|
||||
{
|
||||
// ensure that this function has NOT been found with different pattern
|
||||
for (u32 k = i; k < g_static_funcs_list.GetCount(); k++) if (g_static_funcs_list[k].group == group)
|
||||
{
|
||||
if (k != j && g_static_funcs_list[k].ptr == g_static_funcs_list[j].ptr)
|
||||
{
|
||||
if (g_static_funcs_list[k].found)
|
||||
{
|
||||
res |= GSR_EXCESS;
|
||||
ConLog.Error("Function '%s' hooked twice", wxString(g_static_funcs_list[j].name).wx_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
res |= GSR_EXCESS;
|
||||
ConLog.Error("Function '%s' hooked twice", wxString(g_static_funcs_list[j].name).wx_str());
|
||||
}
|
||||
}
|
||||
|
||||
// clear data
|
||||
for (u32 j = i; j < g_static_funcs_list.GetCount(); j++)
|
||||
{
|
||||
if (g_static_funcs_list[j].group == group) g_static_funcs_list[j].found = 0;
|
||||
}
|
||||
|
||||
char name[9] = "????????";
|
||||
|
||||
*(u64*)name = group;
|
||||
|
||||
if (res == GSR_SUCCESS)
|
||||
{
|
||||
ConLog.Success("Function group [%s] successfully hooked", wxString(name, 9).wx_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
ConLog.Error("Function group [%s] failed: %s%s", wxString(name, 9).wx_str(),
|
||||
wxString(res & GSR_MISSING ? "missing;" : "").wx_str(),
|
||||
wxString(res & GSR_EXCESS ? "excess;" : "").wx_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StaticExecute(u32 code)
|
||||
|
Loading…
x
Reference in New Issue
Block a user