mirror of https://github.com/RPCS3/rpcs3.git
Demuxer improved
This commit is contained in:
parent
8557614322
commit
058eb9e709
|
@ -19,6 +19,8 @@ extern "C"
|
||||||
|
|
||||||
Module *cellAdec = nullptr;
|
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)
|
AudioDecoder::AudioDecoder(AudioCodecType type, u32 addr, u32 size, vm::ptr<CellAdecCbMsg> func, u32 arg)
|
||||||
: type(type)
|
: type(type)
|
||||||
, memAddr(addr)
|
, memAddr(addr)
|
||||||
|
@ -58,38 +60,28 @@ AudioDecoder::AudioDecoder(AudioCodecType type, u32 addr, u32 size, vm::ptr<Cell
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
cellAdec->Error("AudioDecoder(): unknown type (0x%x)", type);
|
ADEC_ERROR("AudioDecoder(): unknown type (0x%x)", type);
|
||||||
Emu.Pause();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!codec)
|
if (!codec)
|
||||||
{
|
{
|
||||||
cellAdec->Error("AudioDecoder(): avcodec_find_decoder() failed");
|
ADEC_ERROR("AudioDecoder(): avcodec_find_decoder() failed");
|
||||||
Emu.Pause();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (!input_format)
|
if (!input_format)
|
||||||
{
|
{
|
||||||
cellAdec->Error("AudioDecoder(): av_find_input_format() failed");
|
ADEC_ERROR("AudioDecoder(): av_find_input_format() failed");
|
||||||
Emu.Pause();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
fmt = avformat_alloc_context();
|
fmt = avformat_alloc_context();
|
||||||
if (!fmt)
|
if (!fmt)
|
||||||
{
|
{
|
||||||
cellAdec->Error("AudioDecoder(): avformat_alloc_context() failed");
|
ADEC_ERROR("AudioDecoder(): avformat_alloc_context() failed");
|
||||||
Emu.Pause();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
io_buf = (u8*)av_malloc(4096);
|
io_buf = (u8*)av_malloc(4096);
|
||||||
fmt->pb = avio_alloc_context(io_buf, 256, 0, this, adecRead, NULL, NULL);
|
fmt->pb = avio_alloc_context(io_buf, 256, 0, this, adecRead, NULL, NULL);
|
||||||
if (!fmt->pb)
|
if (!fmt->pb)
|
||||||
{
|
{
|
||||||
cellAdec->Error("AudioDecoder(): avio_alloc_context() failed");
|
ADEC_ERROR("AudioDecoder(): avio_alloc_context() failed");
|
||||||
Emu.Pause();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,28 +345,16 @@ u32 adecOpen(AudioDecoder* data)
|
||||||
err = avformat_open_input(&adec.fmt, NULL, adec.input_format, &opts);
|
err = avformat_open_input(&adec.fmt, NULL, adec.input_format, &opts);
|
||||||
if (err || opts)
|
if (err || opts)
|
||||||
{
|
{
|
||||||
cellAdec->Error("adecDecodeAu: avformat_open_input() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0);
|
ADEC_ERROR("adecDecodeAu: avformat_open_input() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0);
|
||||||
Emu.Pause();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
//err = avformat_find_stream_info(adec.fmt, NULL);
|
//err = avformat_find_stream_info(adec.fmt, NULL);
|
||||||
//if (err)
|
//if (err || !adec.fmt->nb_streams)
|
||||||
//{
|
//{
|
||||||
// cellAdec->Error("adecDecodeAu: avformat_find_stream_info() failed");
|
// ADEC_ERROR("adecDecodeAu: avformat_find_stream_info() failed (err=0x%x, nb_streams=%d)", err, adec.fmt->nb_streams);
|
||||||
// Emu.Pause();
|
|
||||||
// break;
|
|
||||||
//}
|
|
||||||
//if (!adec.fmt->nb_streams)
|
|
||||||
//{
|
|
||||||
// cellAdec->Error("adecDecodeAu: no stream found");
|
|
||||||
// Emu.Pause();
|
|
||||||
// break;
|
|
||||||
//}
|
//}
|
||||||
if (!avformat_new_stream(adec.fmt, adec.codec))
|
if (!avformat_new_stream(adec.fmt, adec.codec))
|
||||||
{
|
{
|
||||||
cellAdec->Error("adecDecodeAu: avformat_new_stream() failed");
|
ADEC_ERROR("adecDecodeAu: avformat_new_stream() failed");
|
||||||
Emu.Pause();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
adec.ctx = adec.fmt->streams[0]->codec; // TODO: check data
|
adec.ctx = adec.fmt->streams[0]->codec; // TODO: check data
|
||||||
|
|
||||||
|
@ -387,9 +367,7 @@ u32 adecOpen(AudioDecoder* data)
|
||||||
}
|
}
|
||||||
if (err || opts)
|
if (err || opts)
|
||||||
{
|
{
|
||||||
cellAdec->Error("adecDecodeAu: avcodec_open2() failed");
|
ADEC_ERROR("adecDecodeAu: avcodec_open2() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0);
|
||||||
Emu.Pause();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
adec.just_started = false;
|
adec.just_started = false;
|
||||||
}
|
}
|
||||||
|
@ -433,9 +411,7 @@ u32 adecOpen(AudioDecoder* data)
|
||||||
|
|
||||||
if (!frame.data)
|
if (!frame.data)
|
||||||
{
|
{
|
||||||
cellAdec->Error("adecDecodeAu: av_frame_alloc() failed");
|
ADEC_ERROR("adecDecodeAu: av_frame_alloc() failed");
|
||||||
Emu.Pause();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int got_frame = 0;
|
int got_frame = 0;
|
||||||
|
@ -444,7 +420,7 @@ u32 adecOpen(AudioDecoder* data)
|
||||||
|
|
||||||
if (decode <= 0)
|
if (decode <= 0)
|
||||||
{
|
{
|
||||||
if (!last_frame && decode < 0)
|
if (decode < 0)
|
||||||
{
|
{
|
||||||
cellAdec->Error("adecDecodeAu: AU decoding error(0x%x)", decode);
|
cellAdec->Error("adecDecodeAu: AU decoding error(0x%x)", decode);
|
||||||
}
|
}
|
||||||
|
@ -469,9 +445,7 @@ u32 adecOpen(AudioDecoder* data)
|
||||||
case AV_SAMPLE_FMT_S16P: break;
|
case AV_SAMPLE_FMT_S16P: break;
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
cellAdec->Error("adecDecodeAu: unsupported frame format(%d)", frame.data->format);
|
ADEC_ERROR("adecDecodeAu: unsupported frame format(%d)", frame.data->format);
|
||||||
Emu.Pause();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
frame.auAddr = task.au.addr;
|
frame.auAddr = task.au.addr;
|
||||||
|
@ -494,13 +468,14 @@ u32 adecOpen(AudioDecoder* data)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case adecClose: break;
|
case adecClose:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
cellAdec->Error("Audio Decoder thread error: unknown task(%d)", task.type);
|
ADEC_ERROR("Audio Decoder thread error: unknown task(%d)", task.type);
|
||||||
Emu.Pause();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,52 +10,96 @@
|
||||||
|
|
||||||
Module *cellDmux = nullptr;
|
Module *cellDmux = nullptr;
|
||||||
|
|
||||||
|
#define DMUX_ERROR(...) { cellDmux->Error(__VA_ARGS__); Emu.Pause(); return; } // only for demuxer thread
|
||||||
|
|
||||||
PesHeader::PesHeader(DemuxerStream& stream)
|
PesHeader::PesHeader(DemuxerStream& stream)
|
||||||
: pts(0xffffffffffffffffull)
|
: pts(CODEC_TS_INVALID)
|
||||||
, dts(0xffffffffffffffffull)
|
, dts(CODEC_TS_INVALID)
|
||||||
, size(0)
|
, size(0)
|
||||||
, has_ts(false)
|
, has_ts(false)
|
||||||
|
, is_ok(false)
|
||||||
{
|
{
|
||||||
u16 header;
|
u16 header;
|
||||||
stream.get(header);
|
if (!stream.get(header))
|
||||||
stream.get(size);
|
|
||||||
if (size)
|
|
||||||
{
|
{
|
||||||
u8 empty = 0;
|
DMUX_ERROR("PesHeader(): end of stream (header)");
|
||||||
u8 v;
|
}
|
||||||
while (true)
|
if (!stream.get(size))
|
||||||
{
|
{
|
||||||
stream.get(v);
|
DMUX_ERROR("PesHeader(): end of stream (size)");
|
||||||
if (v != 0xFF) break; // skip padding bytes
|
}
|
||||||
empty++;
|
if (!stream.check(size))
|
||||||
if (empty == size) return;
|
{
|
||||||
};
|
DMUX_ERROR("PesHeader(): end of stream (size=%d)", size);
|
||||||
|
}
|
||||||
|
|
||||||
if ((v & 0xF0) == 0x20 && (size - empty) >= 5) // pts only
|
u8 pos = 0;
|
||||||
|
while (pos++ < size)
|
||||||
|
{
|
||||||
|
u8 v;
|
||||||
|
if (!stream.get(v))
|
||||||
{
|
{
|
||||||
has_ts = true;
|
return; // should never occur
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v == 0xff) // skip padding bytes
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((v & 0xf0) == 0x20 && (size - pos) >= 4) // pts only
|
||||||
|
{
|
||||||
|
pos += 4;
|
||||||
pts = stream.get_ts(v);
|
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
|
else
|
||||||
{
|
{
|
||||||
has_ts = true;
|
cellDmux->Notice("PesHeader(): unknown code (v=0x%x, size=%d, pos=%d)", v, size, pos - 1);
|
||||||
if ((v & 0xF0) != 0x30 || (size - empty) < 10)
|
stream.skip(size - pos);
|
||||||
{
|
pos = size;
|
||||||
cellDmux->Error("PesHeader(): pts not found");
|
break;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
bool ElementaryStream::is_full(u32 space)
|
||||||
|
@ -70,7 +114,8 @@ bool ElementaryStream::is_full(u32 space)
|
||||||
u32 first = 0;
|
u32 first = 0;
|
||||||
if (!entries.Peek(first, &dmux->is_closed) || !first)
|
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)
|
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);
|
std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
|
|
||||||
if (is_full(size))
|
assert(!is_full(size));
|
||||||
{
|
|
||||||
throw "es::push_au() error: buffer is full";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (put + size + 128 > memAddr + memSize)
|
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))
|
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;
|
DemuxerTask task;
|
||||||
DemuxerStream stream = {};
|
DemuxerStream stream = {};
|
||||||
ElementaryStream* esALL[192]; memset(esALL, 0, sizeof(esALL));
|
ElementaryStream* esALL[96]; memset(esALL, 0, sizeof(esALL));
|
||||||
ElementaryStream** esAVC = &esALL[0]; // AVC (max 16)
|
ElementaryStream** esAVC = &esALL[0]; // AVC (max 16 minus M2V count)
|
||||||
ElementaryStream** esM2V = &esALL[16]; // MPEG-2 (max 16)
|
ElementaryStream** esM2V = &esALL[16]; // M2V (max 16 minus AVC count)
|
||||||
ElementaryStream** esDATA = &esALL[32]; // user data (max 16)
|
ElementaryStream** esDATA = &esALL[32]; // user data (max 16)
|
||||||
ElementaryStream** esATX = &esALL[48]; // ATRAC3+ (max 48)
|
ElementaryStream** esATX = &esALL[48]; // ATRAC3+ (max 16)
|
||||||
ElementaryStream** esAC3 = &esALL[96]; // AC3 (max 48)
|
ElementaryStream** esAC3 = &esALL[64]; // AC3 (max 16)
|
||||||
ElementaryStream** esPCM = &esALL[144]; // LPCM (max 48)
|
ElementaryStream** esPCM = &esALL[80]; // LPCM (max 16)
|
||||||
|
|
||||||
u32 cb_add = 0;
|
u32 cb_add = 0;
|
||||||
|
|
||||||
|
@ -299,7 +341,6 @@ u32 dmuxOpen(Demuxer* data)
|
||||||
// default task (demuxing) (if there is no other work)
|
// default task (demuxing) (if there is no other work)
|
||||||
be_t<u32> code;
|
be_t<u32> code;
|
||||||
be_t<u16> len;
|
be_t<u16> len;
|
||||||
u8 ch;
|
|
||||||
|
|
||||||
if (!stream.peek(code))
|
if (!stream.peek(code))
|
||||||
{
|
{
|
||||||
|
@ -310,53 +351,104 @@ u32 dmuxOpen(Demuxer* data)
|
||||||
dmux.cbFunc.call(*dmux.dmuxCb, dmux.id, dmuxMsg, dmux.cbArg);
|
dmux.cbFunc.call(*dmux.dmuxCb, dmux.id, dmuxMsg, dmux.cbArg);
|
||||||
|
|
||||||
dmux.is_running = false;
|
dmux.is_running = false;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else switch (code.ToLE())
|
|
||||||
|
switch (code.ToLE())
|
||||||
{
|
{
|
||||||
case PACK_START_CODE:
|
case PACK_START_CODE:
|
||||||
{
|
{
|
||||||
|
if (!stream.check(14))
|
||||||
|
{
|
||||||
|
DMUX_ERROR("End of stream (PACK_START_CODE)");
|
||||||
|
}
|
||||||
stream.skip(14);
|
stream.skip(14);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case SYSTEM_HEADER_START_CODE:
|
case SYSTEM_HEADER_START_CODE:
|
||||||
{
|
{
|
||||||
|
if (!stream.check(18))
|
||||||
|
{
|
||||||
|
DMUX_ERROR("End of stream (SYSTEM_HEADER_START_CODE)");
|
||||||
|
}
|
||||||
stream.skip(18);
|
stream.skip(18);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case PADDING_STREAM:
|
case PADDING_STREAM:
|
||||||
{
|
{
|
||||||
|
if (!stream.check(6))
|
||||||
|
{
|
||||||
|
DMUX_ERROR("End of stream (PADDING_STREAM)");
|
||||||
|
}
|
||||||
stream.skip(4);
|
stream.skip(4);
|
||||||
stream.get(len);
|
stream.get(len);
|
||||||
|
|
||||||
|
if (!stream.check(len.ToLE()))
|
||||||
|
{
|
||||||
|
DMUX_ERROR("End of stream (PADDING_STREAM, len=%d)", len.ToLE());
|
||||||
|
}
|
||||||
stream.skip(len);
|
stream.skip(len);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case PRIVATE_STREAM_2:
|
case PRIVATE_STREAM_2:
|
||||||
{
|
{
|
||||||
|
if (!stream.check(6))
|
||||||
|
{
|
||||||
|
DMUX_ERROR("End of stream (PRIVATE_STREAM_2)");
|
||||||
|
}
|
||||||
stream.skip(4);
|
stream.skip(4);
|
||||||
stream.get(len);
|
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);
|
stream.skip(len);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case PRIVATE_STREAM_1:
|
case PRIVATE_STREAM_1:
|
||||||
{
|
{
|
||||||
|
// audio and user data stream
|
||||||
DemuxerStream backup = 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.skip(4);
|
||||||
stream.get(len);
|
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:
|
const PesHeader pes(stream);
|
||||||
stream.peek(ch); // ???
|
if (!pes.is_ok)
|
||||||
//stream.skip(4);
|
{
|
||||||
//pes.size += 4;
|
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];
|
ElementaryStream& es = *esATX[ch];
|
||||||
if (es.raw_data.size() > 1024 * 1024)
|
if (es.raw_data.size() > 1024 * 1024)
|
||||||
|
@ -366,8 +458,12 @@ u32 dmuxOpen(Demuxer* data)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.skip(4);
|
if (len < 3 || !stream.check(3))
|
||||||
len -= 4;
|
{
|
||||||
|
DMUX_ERROR("End of block (ATX, unknown header, len=%d)", len.ToLE());
|
||||||
|
}
|
||||||
|
len -= 3;
|
||||||
|
stream.skip(3);
|
||||||
|
|
||||||
if (pes.has_ts)
|
if (pes.has_ts)
|
||||||
{
|
{
|
||||||
|
@ -375,7 +471,7 @@ u32 dmuxOpen(Demuxer* data)
|
||||||
es.last_pts = pes.pts;
|
es.last_pts = pes.pts;
|
||||||
}
|
}
|
||||||
|
|
||||||
es.push(stream, len - pes.size - 3);
|
es.push(stream, len);
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
@ -386,9 +482,7 @@ u32 dmuxOpen(Demuxer* data)
|
||||||
|
|
||||||
if (data[0] != 0x0f || data[1] != 0xd0)
|
if (data[0] != 0x0f || data[1] != 0xd0)
|
||||||
{
|
{
|
||||||
cellDmux->Error("ATX: 0x0fd0 header not found (ats=0x%llx)", ((be_t<u64>*)data)->ToLE());
|
DMUX_ERROR("ATX: 0x0fd0 header not found (ats=0x%llx)", ((be_t<u64>*)data)->ToLE());
|
||||||
Emu.Pause();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 frame_size = ((((u32)data[2] & 0x3) << 8) | (u32)data[3]) * 8 + 8;
|
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);
|
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));
|
auto esMsg = vm::ptr<CellDmuxEsMsg>::make(a128(dmux.memAddr) + (cb_add ^= 16));
|
||||||
esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND;
|
esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND;
|
||||||
esMsg->supplementalInfo = stream.userdata;
|
esMsg->supplementalInfo = stream.userdata;
|
||||||
|
@ -407,26 +503,48 @@ u32 dmuxOpen(Demuxer* data)
|
||||||
}
|
}
|
||||||
else
|
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 0x1e0: case 0x1e1: case 0x1e2: case 0x1e3:
|
||||||
case 0x1e4: case 0x1e5: case 0x1e6: case 0x1e7:
|
case 0x1e4: case 0x1e5: case 0x1e6: case 0x1e7:
|
||||||
case 0x1e8: case 0x1e9: case 0x1ea: case 0x1eb:
|
case 0x1e8: case 0x1e9: case 0x1ea: case 0x1eb:
|
||||||
case 0x1ec: case 0x1ed: case 0x1ee: case 0x1ef:
|
case 0x1ec: case 0x1ed: case 0x1ee: case 0x1ef:
|
||||||
{
|
{
|
||||||
// video AVC
|
// video stream (AVC or M2V)
|
||||||
ch = code - 0x1e0;
|
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])
|
if (esAVC[ch])
|
||||||
{
|
{
|
||||||
ElementaryStream& es = *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();
|
const u32 old_size = (u32)es.raw_data.size();
|
||||||
if (es.isfull(old_size))
|
if (es.isfull(old_size))
|
||||||
|
@ -436,9 +554,9 @@ u32 dmuxOpen(Demuxer* data)
|
||||||
continue;
|
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);
|
es.push_au(old_size, es.last_dts, es.last_pts, stream.userdata, false /* TODO: set correct value */, 0);
|
||||||
|
|
||||||
// callback
|
// callback
|
||||||
|
@ -456,53 +574,34 @@ u32 dmuxOpen(Demuxer* data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// reconstruction of MPEG2-PS stream for vdec module
|
// 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;
|
stream = backup;
|
||||||
es.push(stream, size);
|
es.push(stream, size);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
stream.skip(4);
|
cellDmux->Notice("Video stream (code=0x%x, len=%d)", code.ToLE(), len.ToLE());
|
||||||
stream.get(len);
|
|
||||||
stream.skip(len);
|
stream.skip(len);
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
|
if ((code.ToLE() & PACKET_START_CODE_MASK) == PACKET_START_CODE_PREFIX)
|
||||||
|
{
|
||||||
|
DMUX_ERROR("Unknown code found (0x%x)", code.ToLE());
|
||||||
|
}
|
||||||
|
|
||||||
// search
|
// search
|
||||||
stream.skip(1);
|
stream.skip(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for task with yielding (if no default work)
|
// wait for task if no work
|
||||||
if (!dmux.job.Pop(task, &dmux.is_closed))
|
if (!dmux.job.Pop(task, &dmux.is_closed))
|
||||||
{
|
{
|
||||||
break; // Emu is stopped
|
break; // Emu is stopped
|
||||||
|
@ -515,7 +614,7 @@ u32 dmuxOpen(Demuxer* data)
|
||||||
if (task.stream.discontinuity)
|
if (task.stream.discontinuity)
|
||||||
{
|
{
|
||||||
cellDmux->Warning("dmuxSetStream (beginning)");
|
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])
|
if (esALL[i])
|
||||||
{
|
{
|
||||||
|
@ -527,8 +626,8 @@ u32 dmuxOpen(Demuxer* data)
|
||||||
stream = task.stream;
|
stream = task.stream;
|
||||||
//LOG_NOTICE(HLE, "*** stream updated(addr=0x%x, size=0x%x, discont=%d, userdata=0x%llx)",
|
//LOG_NOTICE(HLE, "*** stream updated(addr=0x%x, size=0x%x, discont=%d, userdata=0x%llx)",
|
||||||
//stream.addr, stream.size, stream.discontinuity, stream.userdata);
|
//stream.addr, stream.size, stream.discontinuity, stream.userdata);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case dmuxResetStream:
|
case dmuxResetStream:
|
||||||
case dmuxResetStreamAndWaitDone:
|
case dmuxResetStreamAndWaitDone:
|
||||||
|
@ -543,44 +642,55 @@ u32 dmuxOpen(Demuxer* data)
|
||||||
//if (task.type == dmuxResetStreamAndWaitDone)
|
//if (task.type == dmuxResetStreamAndWaitDone)
|
||||||
//{
|
//{
|
||||||
//}
|
//}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case dmuxEnableEs:
|
case dmuxEnableEs:
|
||||||
{
|
{
|
||||||
ElementaryStream& es = *task.es.es_ptr;
|
ElementaryStream& es = *task.es.es_ptr;
|
||||||
if (es.fidMajor >= 0xe0 &&
|
|
||||||
es.fidMajor <= 0xef &&
|
// TODO: uncomment when ready to use
|
||||||
es.fidMinor == 0 &&
|
if ((es.fidMajor & -0x10) == 0xe0 && es.fidMinor == 0 && es.sup1 == 1 && !es.sup2)
|
||||||
es.sup1 == 1 &&
|
|
||||||
es.sup2 == 0)
|
|
||||||
{
|
{
|
||||||
esAVC[es.fidMajor - 0xe0] = task.es.es_ptr;
|
esAVC[es.fidMajor % 16] = task.es.es_ptr;
|
||||||
}
|
}
|
||||||
else if (es.fidMajor == 0xbd &&
|
//else if ((es.fidMajor & -0x10) == 0xe0 && es.fidMinor == 0 && !es.sup1 && !es.sup2)
|
||||||
es.fidMinor == 0 &&
|
//{
|
||||||
es.sup1 == 0 &&
|
// esM2V[es.fidMajor % 16] = task.es.es_ptr;
|
||||||
es.sup2 == 0)
|
//}
|
||||||
|
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
|
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;
|
es.dmux = &dmux;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case dmuxDisableEs:
|
case dmuxDisableEs:
|
||||||
{
|
{
|
||||||
ElementaryStream& es = *task.es.es_ptr;
|
ElementaryStream& es = *task.es.es_ptr;
|
||||||
if (es.dmux != &dmux)
|
if (es.dmux != &dmux)
|
||||||
{
|
{
|
||||||
cellDmux->Warning("dmuxDisableEs: invalid elementary stream");
|
DMUX_ERROR("dmuxDisableEs: invalid elementary stream");
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
for (u32 i = 0; i < 192; i++)
|
|
||||||
|
for (u32 i = 0; i < sizeof(esALL) / sizeof(esALL[0]); i++)
|
||||||
{
|
{
|
||||||
if (esALL[i] == &es)
|
if (esALL[i] == &es)
|
||||||
{
|
{
|
||||||
|
@ -589,15 +699,15 @@ u32 dmuxOpen(Demuxer* data)
|
||||||
}
|
}
|
||||||
es.dmux = nullptr;
|
es.dmux = nullptr;
|
||||||
Emu.GetIdManager().RemoveID(task.es.es);
|
Emu.GetIdManager().RemoveID(task.es.es);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case dmuxFlushEs:
|
case dmuxFlushEs:
|
||||||
{
|
{
|
||||||
ElementaryStream& es = *task.es.es_ptr;
|
ElementaryStream& es = *task.es.es_ptr;
|
||||||
|
|
||||||
const u32 old_size = (u32)es.raw_data.size();
|
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)
|
// TODO (it's only for AVC, some ATX data may be lost)
|
||||||
while (es.isfull(old_size))
|
while (es.isfull(old_size))
|
||||||
|
@ -626,22 +736,23 @@ u32 dmuxOpen(Demuxer* data)
|
||||||
esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_FLUSH_DONE;
|
esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_FLUSH_DONE;
|
||||||
esMsg->supplementalInfo = stream.userdata;
|
esMsg->supplementalInfo = stream.userdata;
|
||||||
es.cbFunc.call(*dmux.dmuxCb, dmux.id, es.id, esMsg, es.cbArg);
|
es.cbFunc.call(*dmux.dmuxCb, dmux.id, es.id, esMsg, es.cbArg);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case dmuxResetEs:
|
case dmuxResetEs:
|
||||||
{
|
{
|
||||||
task.es.es_ptr->reset();
|
task.es.es_ptr->reset();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case dmuxClose: break;
|
case dmuxClose:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
cellDmux->Error("Demuxer thread error: unknown task(%d)", task.type);
|
DMUX_ERROR("Demuxer thread error: unknown task (0x%x)", task.type);
|
||||||
Emu.Pause();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -288,15 +288,8 @@ enum
|
||||||
PACKET_START_CODE_MASK = 0xffffff00,
|
PACKET_START_CODE_MASK = 0xffffff00,
|
||||||
PACKET_START_CODE_PREFIX = 0x00000100,
|
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,
|
PACK_START_CODE = 0x000001ba,
|
||||||
SYSTEM_HEADER_START_CODE = 0x000001bb,
|
SYSTEM_HEADER_START_CODE = 0x000001bb,
|
||||||
PROGRAM_STREAM_MAP = 0x000001bc,
|
|
||||||
PRIVATE_STREAM_1 = 0x000001bd,
|
PRIVATE_STREAM_1 = 0x000001bd,
|
||||||
PADDING_STREAM = 0x000001be,
|
PADDING_STREAM = 0x000001be,
|
||||||
PRIVATE_STREAM_2 = 0x000001bf,
|
PRIVATE_STREAM_2 = 0x000001bf,
|
||||||
|
@ -336,6 +329,11 @@ struct DemuxerStream
|
||||||
size = size > count ? size - count : 0;
|
size = size > count ? size - count : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool check(u32 count) const
|
||||||
|
{
|
||||||
|
return count <= size;
|
||||||
|
}
|
||||||
|
|
||||||
u64 get_ts(u8 c)
|
u64 get_ts(u8 c)
|
||||||
{
|
{
|
||||||
u8 v[4]; get((u32&)v);
|
u8 v[4]; get((u32&)v);
|
||||||
|
@ -345,12 +343,6 @@ struct DemuxerStream
|
||||||
(((u64)v[1] & 0x7e) << 15) |
|
(((u64)v[1] & 0x7e) << 15) |
|
||||||
(((u64)v[2]) << 7) | ((u64)v[3] >> 1);
|
(((u64)v[2]) << 7) | ((u64)v[3] >> 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 get_ts()
|
|
||||||
{
|
|
||||||
u8 v; get(v);
|
|
||||||
return get_ts(v);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PesHeader
|
struct PesHeader
|
||||||
|
@ -359,6 +351,7 @@ struct PesHeader
|
||||||
u64 dts;
|
u64 dts;
|
||||||
u8 size;
|
u8 size;
|
||||||
bool has_ts;
|
bool has_ts;
|
||||||
|
bool is_ok;
|
||||||
|
|
||||||
PesHeader(DemuxerStream& stream);
|
PesHeader(DemuxerStream& stream);
|
||||||
};
|
};
|
||||||
|
@ -446,6 +439,8 @@ class ElementaryStream
|
||||||
bool is_full(u32 space);
|
bool is_full(u32 space);
|
||||||
|
|
||||||
public:
|
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;
|
Demuxer* dmux;
|
||||||
u32 id;
|
u32 id;
|
||||||
const u32 memAddr;
|
const u32 memAddr;
|
||||||
|
@ -465,27 +460,6 @@ public:
|
||||||
|
|
||||||
void push(DemuxerStream& stream, u32 size); // called by demuxer thread (not multithread-safe)
|
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);
|
bool isfull(u32 space);
|
||||||
|
|
||||||
void push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool rap, u32 specific);
|
void push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool rap, u32 specific);
|
||||||
|
|
|
@ -141,6 +141,8 @@ struct CellCodecTimeStamp
|
||||||
be_t<u32> lower;
|
be_t<u32> lower;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const u64 CODEC_TS_INVALID = 0xffffffffffffffffull;
|
||||||
|
|
||||||
// Entry point information
|
// Entry point information
|
||||||
struct CellPamfEp
|
struct CellPamfEp
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,6 +19,8 @@ extern "C"
|
||||||
|
|
||||||
Module *cellVdec = nullptr;
|
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)
|
VideoDecoder::VideoDecoder(CellVdecCodecType type, u32 profile, u32 addr, u32 size, vm::ptr<CellVdecCbMsg> func, u32 arg)
|
||||||
: type(type)
|
: type(type)
|
||||||
, profile(profile)
|
, profile(profile)
|
||||||
|
@ -62,38 +64,28 @@ VideoDecoder::VideoDecoder(CellVdecCodecType type, u32 profile, u32 addr, u32 si
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
cellVdec->Error("VideoDecoder(): unknown type (0x%x)", type);
|
VDEC_ERROR("VideoDecoder(): unknown type (0x%x)", type);
|
||||||
Emu.Pause();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!codec)
|
if (!codec)
|
||||||
{
|
{
|
||||||
cellVdec->Error("VideoDecoder(): avcodec_find_decoder() failed");
|
VDEC_ERROR("VideoDecoder(): avcodec_find_decoder() failed");
|
||||||
Emu.Pause();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (!input_format)
|
if (!input_format)
|
||||||
{
|
{
|
||||||
cellVdec->Error("VideoDecoder(): av_find_input_format() failed");
|
VDEC_ERROR("VideoDecoder(): av_find_input_format() failed");
|
||||||
Emu.Pause();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
fmt = avformat_alloc_context();
|
fmt = avformat_alloc_context();
|
||||||
if (!fmt)
|
if (!fmt)
|
||||||
{
|
{
|
||||||
cellVdec->Error("VideoDecoder(): avformat_alloc_context() failed");
|
VDEC_ERROR("VideoDecoder(): avformat_alloc_context() failed");
|
||||||
Emu.Pause();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
io_buf = (u8*)av_malloc(4096);
|
io_buf = (u8*)av_malloc(4096);
|
||||||
fmt->pb = avio_alloc_context(io_buf, 4096, 0, this, vdecRead, NULL, NULL);
|
fmt->pb = avio_alloc_context(io_buf, 4096, 0, this, vdecRead, NULL, NULL);
|
||||||
if (!fmt->pb)
|
if (!fmt->pb)
|
||||||
{
|
{
|
||||||
cellVdec->Error("VideoDecoder(): avio_alloc_context() failed");
|
VDEC_ERROR("VideoDecoder(): avio_alloc_context() failed");
|
||||||
Emu.Pause();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,46 +325,40 @@ u32 vdecOpen(VideoDecoder* data)
|
||||||
}
|
}
|
||||||
else if (vdec.just_started) // deferred initialization
|
else if (vdec.just_started) // deferred initialization
|
||||||
{
|
{
|
||||||
err = avformat_open_input(&vdec.fmt, NULL, NULL, NULL);
|
AVDictionary* opts = nullptr;
|
||||||
if (err)
|
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");
|
VDEC_ERROR("vdecDecodeAu: avformat_open_input() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0);
|
||||||
Emu.Pause();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (vdec.type == CELL_VDEC_CODEC_TYPE_DIVX)
|
if (vdec.type == CELL_VDEC_CODEC_TYPE_DIVX)
|
||||||
{
|
{
|
||||||
err = avformat_find_stream_info(vdec.fmt, NULL);
|
err = avformat_find_stream_info(vdec.fmt, NULL);
|
||||||
if (err || !vdec.fmt->nb_streams)
|
if (err || !vdec.fmt->nb_streams)
|
||||||
{
|
{
|
||||||
cellVdec->Error("vdecDecodeAu: avformat_find_stream_info() failed (err=0x%x)", err);
|
VDEC_ERROR("vdecDecodeAu: avformat_find_stream_info() failed (err=0x%x, nb_streams=%d)", err, vdec.fmt->nb_streams);
|
||||||
Emu.Pause();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!avformat_new_stream(vdec.fmt, vdec.codec))
|
if (!avformat_new_stream(vdec.fmt, vdec.codec))
|
||||||
{
|
{
|
||||||
cellVdec->Error("vdecDecodeAu: avformat_new_stream() failed");
|
VDEC_ERROR("vdecDecodeAu: avformat_new_stream() failed");
|
||||||
Emu.Pause();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vdec.ctx = vdec.fmt->streams[0]->codec; // TODO: check data
|
vdec.ctx = vdec.fmt->streams[0]->codec; // TODO: check data
|
||||||
|
|
||||||
AVDictionary* opts = nullptr;
|
opts = nullptr;
|
||||||
av_dict_set(&opts, "refcounted_frames", "1", 0);
|
av_dict_set(&opts, "refcounted_frames", "1", 0);
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(g_mutex_avcodec_open2);
|
std::lock_guard<std::mutex> lock(g_mutex_avcodec_open2);
|
||||||
// not multithread-safe (???)
|
// not multithread-safe (???)
|
||||||
err = avcodec_open2(vdec.ctx, vdec.codec, &opts);
|
err = avcodec_open2(vdec.ctx, vdec.codec, &opts);
|
||||||
}
|
}
|
||||||
if (err)
|
if (err || opts)
|
||||||
{
|
{
|
||||||
cellVdec->Error("vdecDecodeAu: avcodec_open2() failed");
|
VDEC_ERROR("vdecDecodeAu: avcodec_open2() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0);
|
||||||
Emu.Pause();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vdec.just_started = false;
|
vdec.just_started = false;
|
||||||
|
@ -417,9 +403,7 @@ u32 vdecOpen(VideoDecoder* data)
|
||||||
|
|
||||||
if (!frame.data)
|
if (!frame.data)
|
||||||
{
|
{
|
||||||
cellVdec->Error("vdecDecodeAu: av_frame_alloc() failed");
|
VDEC_ERROR("vdecDecodeAu: av_frame_alloc() failed");
|
||||||
Emu.Pause();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int got_picture = 0;
|
int got_picture = 0;
|
||||||
|
@ -428,7 +412,7 @@ u32 vdecOpen(VideoDecoder* data)
|
||||||
|
|
||||||
if (decode <= 0)
|
if (decode <= 0)
|
||||||
{
|
{
|
||||||
if (!last_frame && decode < 0)
|
if (decode < 0)
|
||||||
{
|
{
|
||||||
cellVdec->Error("vdecDecodeAu: AU decoding error(0x%x)", decode);
|
cellVdec->Error("vdecDecodeAu: AU decoding error(0x%x)", decode);
|
||||||
}
|
}
|
||||||
|
@ -439,14 +423,12 @@ u32 vdecOpen(VideoDecoder* data)
|
||||||
{
|
{
|
||||||
if (frame.data->interlaced_frame)
|
if (frame.data->interlaced_frame)
|
||||||
{
|
{
|
||||||
cellVdec->Error("vdecDecodeAu: interlaced frames not supported (0x%x)", frame.data->interlaced_frame);
|
VDEC_ERROR("vdecDecodeAu: interlaced frames not supported (0x%x)", frame.data->interlaced_frame);
|
||||||
Emu.Pause();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frame.data->repeat_pict)
|
if (frame.data->repeat_pict)
|
||||||
{
|
{
|
||||||
cellVdec->Error("vdecDecodeAu: repeated frames not supported (0x%x)", frame.data->repeat_pict);
|
VDEC_ERROR("vdecDecodeAu: repeated frames not supported (0x%x)", frame.data->repeat_pict);
|
||||||
Emu.Pause();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vdec.frc_set)
|
if (vdec.frc_set)
|
||||||
|
@ -467,8 +449,7 @@ u32 vdecOpen(VideoDecoder* data)
|
||||||
case CELL_VDEC_FRC_60: vdec.last_pts += 90000 / 60; break;
|
case CELL_VDEC_FRC_60: vdec.last_pts += 90000 / 60; break;
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
cellVdec->Error("vdecDecodeAu: invalid frame rate code set (0x%x)", vdec.frc_set);
|
VDEC_ERROR("vdecDecodeAu: invalid frame rate code set (0x%x)", vdec.frc_set);
|
||||||
Emu.Pause();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -501,8 +482,7 @@ u32 vdecOpen(VideoDecoder* data)
|
||||||
case 60: case 0x100000000ull + 120: frame.frc = CELL_VDEC_FRC_60; break;
|
case 60: case 0x100000000ull + 120: frame.frc = CELL_VDEC_FRC_60; break;
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
cellVdec->Error("vdecDecodeAu: unsupported time_base.den (%d/1, tpf=%d)", vdec.ctx->time_base.den, vdec.ctx->ticks_per_frame);
|
VDEC_ERROR("vdecDecodeAu: unsupported time_base.den (%d/1, tpf=%d)", vdec.ctx->time_base.den, vdec.ctx->ticks_per_frame);
|
||||||
Emu.Pause();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -522,14 +502,12 @@ u32 vdecOpen(VideoDecoder* data)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cellVdec->Error("vdecDecodeAu: unsupported time_base.den (%d/1001, tpf=%d)", vdec.ctx->time_base.den, vdec.ctx->ticks_per_frame);
|
VDEC_ERROR("vdecDecodeAu: unsupported time_base.den (%d/1001, tpf=%d)", vdec.ctx->time_base.den, vdec.ctx->ticks_per_frame);
|
||||||
Emu.Pause();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cellVdec->Error("vdecDecodeAu: unsupported time_base.num (%d)", vdec.ctx->time_base.num);
|
VDEC_ERROR("vdecDecodeAu: unsupported time_base.num (%d)", vdec.ctx->time_base.num);
|
||||||
Emu.Pause();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -558,13 +536,14 @@ u32 vdecOpen(VideoDecoder* data)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case vdecClose: break;
|
case vdecClose:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
cellVdec->Error("Video Decoder thread error: unknown task(%d)", task.type);
|
VDEC_ERROR("Video Decoder thread error: unknown task(%d)", task.type);
|
||||||
Emu.Pause();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -739,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);
|
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)
|
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();
|
Emu.Pause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -782,12 +761,12 @@ int cellVdecGetPicItem(u32 handle, vm::ptr<u32> picItem_ptr)
|
||||||
info->auNum = 1;
|
info->auNum = 1;
|
||||||
info->auPts[0].lower = (u32)vf.pts;
|
info->auPts[0].lower = (u32)vf.pts;
|
||||||
info->auPts[0].upper = vf.pts >> 32;
|
info->auPts[0].upper = vf.pts >> 32;
|
||||||
info->auPts[1].lower = 0xffffffff;
|
info->auPts[1].lower = (u32)CODEC_TS_INVALID;
|
||||||
info->auPts[1].upper = 0xffffffff;
|
info->auPts[1].upper = (u32)CODEC_TS_INVALID;
|
||||||
info->auDts[0].lower = (u32)vf.dts;
|
info->auDts[0].lower = (u32)vf.dts;
|
||||||
info->auDts[0].upper = vf.dts >> 32;
|
info->auDts[0].upper = vf.dts >> 32;
|
||||||
info->auDts[1].lower = 0xffffffff;
|
info->auDts[1].lower = (u32)CODEC_TS_INVALID;
|
||||||
info->auDts[1].upper = 0xffffffff;
|
info->auDts[1].upper = (u32)CODEC_TS_INVALID;
|
||||||
info->auUserData[0] = vf.userdata;
|
info->auUserData[0] = vf.userdata;
|
||||||
info->auUserData[1] = 0;
|
info->auUserData[1] = 0;
|
||||||
info->status = CELL_OK;
|
info->status = CELL_OK;
|
||||||
|
@ -836,7 +815,7 @@ int cellVdecGetPicItem(u32 handle, vm::ptr<u32> picItem_ptr)
|
||||||
case CELL_VDEC_FRC_50: avc->frameRateCode = CELL_VDEC_AVC_FRC_50; 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_60000DIV1001: avc->frameRateCode = CELL_VDEC_AVC_FRC_60000DIV1001; break;
|
||||||
case CELL_VDEC_FRC_60: avc->frameRateCode = CELL_VDEC_AVC_FRC_60; 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); break;
|
default: cellVdec->Error("cellVdecGetPicItem(AVC): unknown frc value (0x%x)", vf.frc);
|
||||||
}
|
}
|
||||||
|
|
||||||
avc->fixed_frame_rate_flag = true;
|
avc->fixed_frame_rate_flag = true;
|
||||||
|
|
Loading…
Reference in New Issue