It can play video, but it can't

I don't know how to disable aggressive data caching that occures in
vdecRead(). Also ReleaseAu function is disabled because it breaks
everything.
This commit is contained in:
Nekotekina 2014-03-04 03:21:34 +04:00
parent c064c701e2
commit 8a4c67deab
7 changed files with 630 additions and 135 deletions

View file

@ -3,6 +3,8 @@
#include "Emu/SysCalls/SC_FUNC.h"
#include "cellPamf.h"
extern SMutexGeneral g_mutex_avcodec_open2;
extern "C"
{
#include "libavcodec\avcodec.h"
@ -14,6 +16,33 @@ extern "C"
void cellAdec_init();
Module cellAdec(0x0006, cellAdec_init);
int adecRead(void* opaque, u8* buf, int buf_size)
{
AudioDecoder& adec = *(AudioDecoder*)opaque;
if (adec.reader.size < (u32)buf_size)
{
buf_size = adec.reader.size;
}
if (!buf_size)
{
return 0;
}
else if (!Memory.CopyToReal(buf, adec.reader.addr, buf_size))
{
ConLog.Error("adecRead: data reading failed (buf_size=0x%x)", buf_size);
Emu.Pause();
return 0;
}
else
{
adec.reader.addr += buf_size;
adec.reader.size -= buf_size;
return 0 + buf_size;
}
}
u32 adecOpen(AudioDecoder* data)
{
AudioDecoder& adec = *data;
@ -56,16 +85,205 @@ u32 adecOpen(AudioDecoder* data)
{
case adecStartSeq:
{
// TODO: reset data
ConLog.Warning("adecStartSeq:");
adec.reader.addr = 0;
adec.reader.size = 0;
adec.is_running = true;
adec.just_started = true;
}
break;
case adecEndSeq:
{
// TODO: finalize
ConLog.Warning("adecEndSeq:");
Callback cb;
cb.SetAddr(adec.cbFunc);
cb.Handle(adec.id, CELL_ADEC_MSG_TYPE_SEQDONE, CELL_OK, adec.cbArg);
cb.Branch(true); // ???
avcodec_close(adec.ctx);
avformat_close_input(&adec.fmt);
adec.is_running = false;
}
break;
case adecDecodeAu:
{
int err;
adec.reader.addr = task.au.addr;
adec.reader.size = task.au.size;
u64 last_pts = task.au.pts;
struct AVPacketHolder : AVPacket
{
AVPacketHolder(u32 size)
{
av_init_packet(this);
if (size)
{
data = (u8*)av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
memset(data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
this->size = size + FF_INPUT_BUFFER_PADDING_SIZE;
}
else
{
data = NULL;
size = 0;
}
}
~AVPacketHolder()
{
av_free(data);
//av_free_packet(this);
}
} au(0);
/*{
wxFile dump;
dump.Open(wxString::Format("audio pts-0x%llx.dump", task.au.pts), wxFile::write);
u8* buf = (u8*)malloc(task.au.size);
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);
if (err)
{
ConLog.Error("adecDecodeAu: avformat_open_input() failed");
Emu.Pause();
break;
}
err = avformat_find_stream_info(adec.fmt, NULL);
if (err)
{
ConLog.Error("adecDecodeAu: avformat_find_stream_info() failed");
Emu.Pause();
break;
}
if (!adec.fmt->nb_streams)
{
ConLog.Error("adecDecodeAu: no stream found");
Emu.Pause();
break;
}
adec.ctx = adec.fmt->streams[0]->codec; // TODO: check data
AVCodec* codec = avcodec_find_decoder(adec.ctx->codec_id); // ???
if (!codec)
{
ConLog.Error("adecDecodeAu: avcodec_find_decoder() failed");
Emu.Pause();
break;
}
AVDictionary* opts;
av_dict_set(&opts, "refcounted_frames", "1", 0);
{
SMutexGeneralLocker lock(g_mutex_avcodec_open2);
// not multithread-safe
err = avcodec_open2(adec.ctx, codec, &opts);
}
if (err)
{
ConLog.Error("adecDecodeAu: avcodec_open2() failed");
Emu.Pause();
break;
}
adec.just_started = false;
}
while (av_read_frame(adec.fmt, &au) >= 0)*/ while (true)
{
if (!adec.ctx) // fake
{
AdecFrame frame;
frame.pts = task.au.pts;
frame.auAddr = task.au.addr;
frame.auSize = task.au.size;
frame.userdata = task.au.userdata;
frame.size = 2048;
frame.data = nullptr;
adec.frames.Push(frame);
Callback cb;
cb.SetAddr(adec.cbFunc);
cb.Handle(adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg);
cb.Branch(false);
break;
}
struct VdecFrameHolder : AdecFrame
{
VdecFrameHolder()
{
data = av_frame_alloc();
}
~VdecFrameHolder()
{
if (data)
{
av_frame_unref(data);
av_frame_free(&data);
}
}
} frame;
if (!frame.data)
{
ConLog.Error("adecDecodeAu: av_frame_alloc() failed");
Emu.Pause();
break;
}
int got_frame = 0;
int decode = avcodec_decode_audio4(adec.ctx, frame.data, &got_frame, &au);
if (decode < 0)
{
ConLog.Error("adecDecodeAu: AU decoding error(0x%x)", decode);
break;
}
if (got_frame)
{
ConLog.Write("got_frame (%d, vdec: pts=0x%llx, dts=0x%llx)", got_frame, au.pts, au.dts);
frame.pts = task.au.pts; // ???
frame.auAddr = task.au.addr;
frame.auSize = task.au.size;
frame.userdata = task.au.userdata;
frame.size = 32768; // ????
adec.frames.Push(frame);
frame.data = nullptr; // to prevent destruction
Callback cb;
cb.SetAddr(adec.cbFunc);
cb.Handle(adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg);
cb.Branch(false);
}
}
Callback cb;
cb.SetAddr(adec.cbFunc);
cb.Handle(adec.id, CELL_ADEC_MSG_TYPE_AUDONE, task.au.auInfo_addr, adec.cbArg);
cb.Branch(false);
}
break;
@ -78,9 +296,9 @@ u32 adecOpen(AudioDecoder* data)
default:
ConLog.Error("Audio Decoder error: unknown task(%d)", task.type);
return;
}
}
adec.is_finished = true;
ConLog.Warning("Audio Decoder aborted");
});
@ -196,31 +414,158 @@ int cellAdecClose(u32 handle)
int cellAdecStartSeq(u32 handle, u32 param_addr)
{
cellAdec.Error("cellAdecStartSeq(handle=%d, param_addr=0x%x)", handle, param_addr);
cellAdec.Log("cellAdecStartSeq(handle=%d, param_addr=0x%x)", handle, param_addr);
AudioDecoder* adec;
if (!Emu.GetIdManager().GetIDData(handle, adec))
{
return CELL_ADEC_ERROR_ARG;
}
AdecTask task(adecStartSeq);
/*if (adec->type == CELL_ADEC_TYPE_ATRACX_2CH)
{
}
else*/
{
cellAdec.Warning("cellAdecStartSeq: (TODO) initialization");
}
adec->job.Push(task);
return CELL_OK;
}
int cellAdecEndSeq(u32 handle)
{
cellAdec.Error("cellAdecEndSeq(handle=%d)", handle);
cellAdec.Warning("cellAdecEndSeq(handle=%d)", handle);
AudioDecoder* adec;
if (!Emu.GetIdManager().GetIDData(handle, adec))
{
return CELL_ADEC_ERROR_ARG;
}
adec->job.Push(AdecTask(adecEndSeq));
return CELL_OK;
}
int cellAdecDecodeAu(u32 handle, mem_ptr_t<CellAdecAuInfo> auInfo)
{
cellAdec.Error("cellAdecDecodeAu(handle=%d, auInfo_addr=0x%x)", handle, auInfo.GetAddr());
cellAdec.Log("cellAdecDecodeAu(handle=%d, auInfo_addr=0x%x)", handle, auInfo.GetAddr());
AudioDecoder* adec;
if (!Emu.GetIdManager().GetIDData(handle, adec))
{
return CELL_ADEC_ERROR_ARG;
}
if (!auInfo.IsGood())
{
return CELL_ADEC_ERROR_FATAL;
}
AdecTask task(adecDecodeAu);
task.au.auInfo_addr = auInfo.GetAddr();
task.au.addr = auInfo->startAddr;
task.au.size = auInfo->size;
task.au.pts = ((u64)auInfo->pts.upper << 32) | (u64)auInfo->pts.lower;
task.au.userdata = auInfo->userData;
adec->job.Push(task);
return CELL_OK;
}
int cellAdecGetPcm(u32 handle, u32 outBuffer_addr)
{
cellAdec.Error("cellAdecGetPcm(handle=%d, outBuffer_addr=0x%x)", handle, outBuffer_addr);
return CELL_OK;
cellAdec.Log("cellAdecGetPcm(handle=%d, outBuffer_addr=0x%x)", handle, outBuffer_addr);
AudioDecoder* adec;
if (!Emu.GetIdManager().GetIDData(handle, adec))
{
return CELL_ADEC_ERROR_ARG;
}
if (adec->frames.IsEmpty())
{
return CELL_ADEC_ERROR_EMPTY;
}
AdecFrame af;
adec->frames.Pop(af);
//AVFrame& frame = *af.data;
int result = CELL_OK;
if (!Memory.IsGoodAddr(outBuffer_addr, af.size))
{
result = CELL_ADEC_ERROR_FATAL;
}
else
{
// copy data
if (!af.data) // fake: empty data
{
return CELL_OK;
}
}
if (af.data)
{
av_frame_unref(af.data);
av_frame_free(&af.data);
}
return result;
}
int cellAdecGetPcmItem(u32 handle, u32 pcmItem_ptr_addr)
int cellAdecGetPcmItem(u32 handle, mem32_t pcmItem_ptr)
{
cellAdec.Error("cellAdecGetPcmItem(handle=%d, pcmItem_ptr_addr=0x%x)", handle, pcmItem_ptr_addr);
cellAdec.Log("cellAdecGetPcmItem(handle=%d, pcmItem_ptr_addr=0x%x)", handle, pcmItem_ptr.GetAddr());
AudioDecoder* adec;
if (!Emu.GetIdManager().GetIDData(handle, adec))
{
return CELL_ADEC_ERROR_ARG;
}
if (!pcmItem_ptr.IsGood())
{
return CELL_ADEC_ERROR_FATAL;
}
AdecFrame& af = adec->frames.Peek();
if (adec->frames.IsEmpty())
{
return CELL_ADEC_ERROR_EMPTY;
}
//AVFrame& frame = *af.data;
mem_ptr_t<CellAdecPcmItem> pcm(adec->memAddr + adec->memBias);
adec->memBias += 512;
if (adec->memBias + 512 > adec->memSize)
adec->memBias = 0;
pcm->pcmHandle = 0; // ???
pcm->pcmAttr.bsiInfo_addr = pcm.GetAddr() + sizeof(CellAdecPcmItem);
pcm->startAddr = 0x00000312; // invalid address (no output)
pcm->size = af.size;
pcm->status = CELL_OK;
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->channelConfigIndex = CELL_ADEC_CH_STEREO; // ???
pcmItem_ptr = pcm.GetAddr();
return CELL_OK;
}