From 058eb9e709d1d5c77e1ff736cb70803c0809c730 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Fri, 12 Dec 2014 03:21:34 +0300 Subject: [PATCH] Demuxer improved --- rpcs3/Emu/SysCalls/Modules/cellAdec.cpp | 65 ++--- rpcs3/Emu/SysCalls/Modules/cellDmux.cpp | 369 +++++++++++++++--------- rpcs3/Emu/SysCalls/Modules/cellDmux.h | 42 +-- rpcs3/Emu/SysCalls/Modules/cellPamf.h | 2 + rpcs3/Emu/SysCalls/Modules/cellVdec.cpp | 93 +++--- 5 files changed, 306 insertions(+), 265 deletions(-) diff --git a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp index 1dbfb57e23..8cabbae3b4 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp @@ -19,6 +19,8 @@ extern "C" Module *cellAdec = nullptr; +#define ADEC_ERROR(...) { cellAdec->Error(__VA_ARGS__); Emu.Pause(); return; } // only for decoder thread + AudioDecoder::AudioDecoder(AudioCodecType type, u32 addr, u32 size, vm::ptr func, u32 arg) : type(type) , memAddr(addr) @@ -58,38 +60,28 @@ AudioDecoder::AudioDecoder(AudioCodecType type, u32 addr, u32 size, vm::ptrError("AudioDecoder(): unknown type (0x%x)", type); - Emu.Pause(); - return; + ADEC_ERROR("AudioDecoder(): unknown type (0x%x)", type); } } if (!codec) { - cellAdec->Error("AudioDecoder(): avcodec_find_decoder() failed"); - Emu.Pause(); - return; + ADEC_ERROR("AudioDecoder(): avcodec_find_decoder() failed"); } if (!input_format) { - cellAdec->Error("AudioDecoder(): av_find_input_format() failed"); - Emu.Pause(); - return; + ADEC_ERROR("AudioDecoder(): av_find_input_format() failed"); } fmt = avformat_alloc_context(); if (!fmt) { - cellAdec->Error("AudioDecoder(): avformat_alloc_context() failed"); - Emu.Pause(); - return; + ADEC_ERROR("AudioDecoder(): avformat_alloc_context() failed"); } io_buf = (u8*)av_malloc(4096); fmt->pb = avio_alloc_context(io_buf, 256, 0, this, adecRead, NULL, NULL); if (!fmt->pb) { - cellAdec->Error("AudioDecoder(): avio_alloc_context() failed"); - Emu.Pause(); - return; + ADEC_ERROR("AudioDecoder(): avio_alloc_context() failed"); } } @@ -353,28 +345,16 @@ u32 adecOpen(AudioDecoder* data) err = avformat_open_input(&adec.fmt, NULL, adec.input_format, &opts); if (err || opts) { - cellAdec->Error("adecDecodeAu: avformat_open_input() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0); - Emu.Pause(); - break; + ADEC_ERROR("adecDecodeAu: avformat_open_input() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0); } //err = avformat_find_stream_info(adec.fmt, NULL); - //if (err) + //if (err || !adec.fmt->nb_streams) //{ - // cellAdec->Error("adecDecodeAu: avformat_find_stream_info() failed"); - // Emu.Pause(); - // break; - //} - //if (!adec.fmt->nb_streams) - //{ - // cellAdec->Error("adecDecodeAu: no stream found"); - // Emu.Pause(); - // break; + // ADEC_ERROR("adecDecodeAu: avformat_find_stream_info() failed (err=0x%x, nb_streams=%d)", err, adec.fmt->nb_streams); //} if (!avformat_new_stream(adec.fmt, adec.codec)) { - cellAdec->Error("adecDecodeAu: avformat_new_stream() failed"); - Emu.Pause(); - break; + ADEC_ERROR("adecDecodeAu: avformat_new_stream() failed"); } adec.ctx = adec.fmt->streams[0]->codec; // TODO: check data @@ -387,9 +367,7 @@ u32 adecOpen(AudioDecoder* data) } if (err || opts) { - cellAdec->Error("adecDecodeAu: avcodec_open2() failed"); - Emu.Pause(); - break; + ADEC_ERROR("adecDecodeAu: avcodec_open2() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0); } adec.just_started = false; } @@ -433,9 +411,7 @@ u32 adecOpen(AudioDecoder* data) if (!frame.data) { - cellAdec->Error("adecDecodeAu: av_frame_alloc() failed"); - Emu.Pause(); - break; + ADEC_ERROR("adecDecodeAu: av_frame_alloc() failed"); } int got_frame = 0; @@ -444,7 +420,7 @@ u32 adecOpen(AudioDecoder* data) if (decode <= 0) { - if (!last_frame && decode < 0) + if (decode < 0) { cellAdec->Error("adecDecodeAu: AU decoding error(0x%x)", decode); } @@ -469,9 +445,7 @@ u32 adecOpen(AudioDecoder* data) case AV_SAMPLE_FMT_S16P: break; default: { - cellAdec->Error("adecDecodeAu: unsupported frame format(%d)", frame.data->format); - Emu.Pause(); - break; + ADEC_ERROR("adecDecodeAu: unsupported frame format(%d)", frame.data->format); } } frame.auAddr = task.au.addr; @@ -494,13 +468,14 @@ u32 adecOpen(AudioDecoder* data) break; } - case adecClose: break; + case adecClose: + { + break; + } default: { - cellAdec->Error("Audio Decoder thread error: unknown task(%d)", task.type); - Emu.Pause(); - return; + ADEC_ERROR("Audio Decoder thread error: unknown task(%d)", task.type); } } } diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp index 57ee842309..d97603efa6 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp @@ -10,52 +10,96 @@ Module *cellDmux = nullptr; +#define DMUX_ERROR(...) { cellDmux->Error(__VA_ARGS__); Emu.Pause(); return; } // only for demuxer thread + PesHeader::PesHeader(DemuxerStream& stream) - : pts(0xffffffffffffffffull) - , dts(0xffffffffffffffffull) + : pts(CODEC_TS_INVALID) + , dts(CODEC_TS_INVALID) , size(0) , has_ts(false) + , is_ok(false) { u16 header; - stream.get(header); - stream.get(size); - if (size) + if (!stream.get(header)) + { + DMUX_ERROR("PesHeader(): end of stream (header)"); + } + if (!stream.get(size)) + { + DMUX_ERROR("PesHeader(): end of stream (size)"); + } + if (!stream.check(size)) + { + DMUX_ERROR("PesHeader(): end of stream (size=%d)", size); + } + + u8 pos = 0; + while (pos++ < size) { - u8 empty = 0; u8 v; - while (true) + if (!stream.get(v)) { - stream.get(v); - if (v != 0xFF) break; // skip padding bytes - empty++; - if (empty == size) return; - }; + return; // should never occur + } - if ((v & 0xF0) == 0x20 && (size - empty) >= 5) // pts only + if (v == 0xff) // skip padding bytes { - has_ts = true; + continue; + } + + if ((v & 0xf0) == 0x20 && (size - pos) >= 4) // pts only + { + pos += 4; pts = stream.get_ts(v); - stream.skip(size - empty - 5); + has_ts = true; + } + else if ((v & 0xf0) == 0x30 && (size - pos) >= 9) // pts and dts + { + pos += 5; + pts = stream.get_ts(v); + stream.get(v); + has_ts = true; + + if ((v & 0xf0) != 0x10) + { + cellDmux->Error("PesHeader(): dts not found (v=0x%x, size=%d, pos=%d)", v, size, pos - 1); + stream.skip(size - pos); + return; + } + pos += 4; + dts = stream.get_ts(v); } else { - has_ts = true; - if ((v & 0xF0) != 0x30 || (size - empty) < 10) - { - cellDmux->Error("PesHeader(): pts not found"); - Emu.Pause(); - } - pts = stream.get_ts(v); - stream.get(v); - if ((v & 0xF0) != 0x10) - { - cellDmux->Error("PesHeader(): dts not found"); - Emu.Pause(); - } - dts = stream.get_ts(v); - stream.skip(size - empty - 10); + cellDmux->Notice("PesHeader(): unknown code (v=0x%x, size=%d, pos=%d)", v, size, pos - 1); + stream.skip(size - pos); + pos = size; + break; } } + + is_ok = true; +} + +ElementaryStream::ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr cbFunc, u32 cbArg, u32 spec) + : dmux(dmux) + , memAddr(a128(addr)) + , memSize(size - (addr - memAddr)) + , fidMajor(fidMajor) + , fidMinor(fidMinor) + , sup1(sup1) + , sup2(sup2) + , cbFunc(cbFunc) + , cbArg(cbArg) + , spec(spec) + , put(memAddr) + , put_count(0) + , got_count(0) + , released(0) + , raw_pos(0) + , last_dts(CODEC_TS_INVALID) + , last_pts(CODEC_TS_INVALID) +{ } bool ElementaryStream::is_full(u32 space) @@ -70,7 +114,8 @@ bool ElementaryStream::is_full(u32 space) u32 first = 0; if (!entries.Peek(first, &dmux->is_closed) || !first) { - throw "es::is_full() error: entries.Peek() failed"; + assert(!"es::is_full() error: entries.Peek() failed"); + return false; } else if (first >= put) { @@ -103,10 +148,7 @@ void ElementaryStream::push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool ra { std::lock_guard lock(m_mutex); - if (is_full(size)) - { - throw "es::push_au() error: buffer is full"; - } + assert(!is_full(size)); if (put + size + 128 > memAddr + memSize) { @@ -148,7 +190,7 @@ void ElementaryStream::push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool ra } if (!entries.Push(addr, &dmux->is_closed)) { - throw "es::push_au() error: entries.Push() failed"; + assert(!"es::push_au() error: entries.Push() failed"); } } @@ -277,13 +319,13 @@ u32 dmuxOpen(Demuxer* data) DemuxerTask task; DemuxerStream stream = {}; - ElementaryStream* esALL[192]; memset(esALL, 0, sizeof(esALL)); - ElementaryStream** esAVC = &esALL[0]; // AVC (max 16) - ElementaryStream** esM2V = &esALL[16]; // MPEG-2 (max 16) + ElementaryStream* esALL[96]; memset(esALL, 0, sizeof(esALL)); + ElementaryStream** esAVC = &esALL[0]; // AVC (max 16 minus M2V count) + ElementaryStream** esM2V = &esALL[16]; // M2V (max 16 minus AVC count) ElementaryStream** esDATA = &esALL[32]; // user data (max 16) - ElementaryStream** esATX = &esALL[48]; // ATRAC3+ (max 48) - ElementaryStream** esAC3 = &esALL[96]; // AC3 (max 48) - ElementaryStream** esPCM = &esALL[144]; // LPCM (max 48) + ElementaryStream** esATX = &esALL[48]; // ATRAC3+ (max 16) + ElementaryStream** esAC3 = &esALL[64]; // AC3 (max 16) + ElementaryStream** esPCM = &esALL[80]; // LPCM (max 16) u32 cb_add = 0; @@ -299,7 +341,6 @@ u32 dmuxOpen(Demuxer* data) // default task (demuxing) (if there is no other work) be_t code; be_t len; - u8 ch; if (!stream.peek(code)) { @@ -310,53 +351,104 @@ u32 dmuxOpen(Demuxer* data) dmux.cbFunc.call(*dmux.dmuxCb, dmux.id, dmuxMsg, dmux.cbArg); dmux.is_running = false; + continue; } - else switch (code.ToLE()) + + switch (code.ToLE()) { case PACK_START_CODE: { + if (!stream.check(14)) + { + DMUX_ERROR("End of stream (PACK_START_CODE)"); + } stream.skip(14); + break; } - break; case SYSTEM_HEADER_START_CODE: { + if (!stream.check(18)) + { + DMUX_ERROR("End of stream (SYSTEM_HEADER_START_CODE)"); + } stream.skip(18); + break; } - break; case PADDING_STREAM: { + if (!stream.check(6)) + { + DMUX_ERROR("End of stream (PADDING_STREAM)"); + } stream.skip(4); stream.get(len); + + if (!stream.check(len.ToLE())) + { + DMUX_ERROR("End of stream (PADDING_STREAM, len=%d)", len.ToLE()); + } stream.skip(len); + break; } - break; case PRIVATE_STREAM_2: { + if (!stream.check(6)) + { + DMUX_ERROR("End of stream (PRIVATE_STREAM_2)"); + } stream.skip(4); stream.get(len); + + cellDmux->Notice("PRIVATE_STREAM_2 (%d)", len.ToLE()); + + if (!stream.check(len.ToLE())) + { + DMUX_ERROR("End of stream (PRIVATE_STREAM_2, len=%d)", len.ToLE()); + } stream.skip(len); + break; } - break; case PRIVATE_STREAM_1: { + // audio and user data stream DemuxerStream backup = stream; - // audio AT3+ (and probably LPCM or user data) + if (!stream.check(6)) + { + DMUX_ERROR("End of stream (PRIVATE_STREAM_1)"); + } stream.skip(4); stream.get(len); - PesHeader pes(stream); + if (!stream.check(len.ToLE())) + { + DMUX_ERROR("End of stream (PRIVATE_STREAM_1, len=%d)", len.ToLE()); + } - // read additional header: - stream.peek(ch); // ??? - //stream.skip(4); - //pes.size += 4; + const PesHeader pes(stream); + if (!pes.is_ok) + { + DMUX_ERROR("PesHeader error (PRIVATE_STREAM_1, len=%d)", len.ToLE()); + } - if (esATX[ch]) + if (len < pes.size + 4) + { + DMUX_ERROR("End of block (PRIVATE_STREAM_1, PesHeader + fid_minor, len=%d)", len.ToLE()); + } + len -= pes.size + 4; + + u8 fid_minor; + if (!stream.get(fid_minor)) + { + DMUX_ERROR("End of stream (PRIVATE_STREAM1, fid_minor)"); + } + + const u32 ch = fid_minor % 16; + if ((fid_minor & -0x10) == 0 && esATX[ch]) { ElementaryStream& es = *esATX[ch]; if (es.raw_data.size() > 1024 * 1024) @@ -366,8 +458,12 @@ u32 dmuxOpen(Demuxer* data) continue; } - stream.skip(4); - len -= 4; + if (len < 3 || !stream.check(3)) + { + DMUX_ERROR("End of block (ATX, unknown header, len=%d)", len.ToLE()); + } + len -= 3; + stream.skip(3); if (pes.has_ts) { @@ -375,7 +471,7 @@ u32 dmuxOpen(Demuxer* data) es.last_pts = pes.pts; } - es.push(stream, len - pes.size - 3); + es.push(stream, len); while (true) { @@ -386,9 +482,7 @@ u32 dmuxOpen(Demuxer* data) if (data[0] != 0x0f || data[1] != 0xd0) { - cellDmux->Error("ATX: 0x0fd0 header not found (ats=0x%llx)", ((be_t*)data)->ToLE()); - Emu.Pause(); - return; + DMUX_ERROR("ATX: 0x0fd0 header not found (ats=0x%llx)", ((be_t*)data)->ToLE()); } u32 frame_size = ((((u32)data[2] & 0x3) << 8) | (u32)data[3]) * 8 + 8; @@ -399,6 +493,8 @@ u32 dmuxOpen(Demuxer* data) es.push_au(frame_size + 8, es.last_dts, es.last_pts, stream.userdata, false /* TODO: set correct value */, 0); + cellDmux->Notice("ATX AU pushed (ats=0x%llx, frame_size=%d)", ((be_t*)data)->ToLE(), frame_size); + auto esMsg = vm::ptr::make(a128(dmux.memAddr) + (cb_add ^= 16)); esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND; esMsg->supplementalInfo = stream.userdata; @@ -407,26 +503,48 @@ u32 dmuxOpen(Demuxer* data) } else { - stream.skip(len - pes.size - 3); + cellDmux->Notice("PRIVATE_STREAM_1 (len=%d, fid_minor=0x%x)", len.ToLE(), fid_minor); + stream.skip(len); } + break; } - break; case 0x1e0: case 0x1e1: case 0x1e2: case 0x1e3: case 0x1e4: case 0x1e5: case 0x1e6: case 0x1e7: case 0x1e8: case 0x1e9: case 0x1ea: case 0x1eb: case 0x1ec: case 0x1ed: case 0x1ee: case 0x1ef: { - // video AVC - ch = code - 0x1e0; + // video stream (AVC or M2V) + DemuxerStream backup = stream; + + if (!stream.check(6)) + { + DMUX_ERROR("End of stream (video, code=0x%x)", code.ToLE()); + } + stream.skip(4); + stream.get(len); + + if (!stream.check(len.ToLE())) + { + DMUX_ERROR("End of stream (video, code=0x%x, len=%d)", code.ToLE(), len.ToLE()); + } + + const PesHeader pes(stream); + if (!pes.is_ok) + { + DMUX_ERROR("PesHeader error (video, code=0x%x, len=%d)", code.ToLE(), len.ToLE()); + } + + if (len < pes.size + 3) + { + DMUX_ERROR("End of block (video, code=0x%x, PesHeader)", code.ToLE()); + } + len -= pes.size + 3; + + const u32 ch = code.ToLE() % 16; if (esAVC[ch]) { ElementaryStream& es = *esAVC[ch]; - DemuxerStream backup = stream; - - stream.skip(4); - stream.get(len); - PesHeader pes(stream); const u32 old_size = (u32)es.raw_data.size(); if (es.isfull(old_size)) @@ -436,9 +554,9 @@ u32 dmuxOpen(Demuxer* data) continue; } - if ((pes.has_ts && old_size) || old_size >= 0x70000) + if ((pes.has_ts && old_size) || old_size >= 0x69800) { - // push AU if it becomes too big or the next packet contains ts data + // push AU if it becomes too big or the next packet contains PTS/DTS es.push_au(old_size, es.last_dts, es.last_pts, stream.userdata, false /* TODO: set correct value */, 0); // callback @@ -456,53 +574,34 @@ u32 dmuxOpen(Demuxer* data) } // reconstruction of MPEG2-PS stream for vdec module - const u32 size = len + 6 /*- pes.size - 3*/; + const u32 size = (u32)len.ToLE() + pes.size + 9; stream = backup; es.push(stream, size); } else { - stream.skip(4); - stream.get(len); + cellDmux->Notice("Video stream (code=0x%x, len=%d)", code.ToLE(), len.ToLE()); stream.skip(len); } - } - break; - - case 0x1c0: case 0x1c1: case 0x1c2: case 0x1c3: - case 0x1c4: case 0x1c5: case 0x1c6: case 0x1c7: - case 0x1c8: case 0x1c9: case 0x1ca: case 0x1cb: - case 0x1cc: case 0x1cd: case 0x1ce: case 0x1cf: - case 0x1d0: case 0x1d1: case 0x1d2: case 0x1d3: - case 0x1d4: case 0x1d5: case 0x1d6: case 0x1d7: - case 0x1d8: case 0x1d9: case 0x1da: case 0x1db: - case 0x1dc: case 0x1dd: case 0x1de: case 0x1df: - { - // unknown - cellDmux->Warning("Unknown MPEG stream found"); - stream.skip(4); - stream.get(len); - stream.skip(len); - } - break; - - case USER_DATA_START_CODE: - { - cellDmux->Error("USER_DATA_START_CODE found"); - Emu.Pause(); - return; + break; } default: { + if ((code.ToLE() & PACKET_START_CODE_MASK) == PACKET_START_CODE_PREFIX) + { + DMUX_ERROR("Unknown code found (0x%x)", code.ToLE()); + } + // search stream.skip(1); } } + continue; } - // wait for task with yielding (if no default work) + // wait for task if no work if (!dmux.job.Pop(task, &dmux.is_closed)) { break; // Emu is stopped @@ -515,7 +614,7 @@ u32 dmuxOpen(Demuxer* data) if (task.stream.discontinuity) { cellDmux->Warning("dmuxSetStream (beginning)"); - for (u32 i = 0; i < 192; i++) + for (u32 i = 0; i < sizeof(esALL) / sizeof(esALL[0]); i++) { if (esALL[i]) { @@ -527,8 +626,8 @@ u32 dmuxOpen(Demuxer* data) stream = task.stream; //LOG_NOTICE(HLE, "*** stream updated(addr=0x%x, size=0x%x, discont=%d, userdata=0x%llx)", //stream.addr, stream.size, stream.discontinuity, stream.userdata); + break; } - break; case dmuxResetStream: case dmuxResetStreamAndWaitDone: @@ -543,44 +642,55 @@ u32 dmuxOpen(Demuxer* data) //if (task.type == dmuxResetStreamAndWaitDone) //{ //} + break; } - break; case dmuxEnableEs: { ElementaryStream& es = *task.es.es_ptr; - if (es.fidMajor >= 0xe0 && - es.fidMajor <= 0xef && - es.fidMinor == 0 && - es.sup1 == 1 && - es.sup2 == 0) + + // TODO: uncomment when ready to use + if ((es.fidMajor & -0x10) == 0xe0 && es.fidMinor == 0 && es.sup1 == 1 && !es.sup2) { - esAVC[es.fidMajor - 0xe0] = task.es.es_ptr; + esAVC[es.fidMajor % 16] = task.es.es_ptr; } - else if (es.fidMajor == 0xbd && - es.fidMinor == 0 && - es.sup1 == 0 && - es.sup2 == 0) + //else if ((es.fidMajor & -0x10) == 0xe0 && es.fidMinor == 0 && !es.sup1 && !es.sup2) + //{ + // esM2V[es.fidMajor % 16] = task.es.es_ptr; + //} + else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0 && !es.sup1 && !es.sup2) { - esATX[0] = task.es.es_ptr; + esATX[es.fidMinor % 16] = task.es.es_ptr; } + //else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0x20 && !es.sup1 && !es.sup2) + //{ + // esDATA[es.fidMinor % 16] = task.es.es_ptr; + //} + //else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0x30 && !es.sup1 && !es.sup2) + //{ + // esAC3[es.fidMinor % 16] = task.es.es_ptr; + //} + //else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0x40 && !es.sup1 && !es.sup2) + //{ + // esPCM[es.fidMinor % 16] = task.es.es_ptr; + //} else { - cellDmux->Warning("dmuxEnableEs: (TODO) unsupported filter (0x%x, 0x%x, 0x%x, 0x%x)", es.fidMajor, es.fidMinor, es.sup1, es.sup2); + DMUX_ERROR("dmuxEnableEs: unknown filter (0x%x, 0x%x, 0x%x, 0x%x)", es.fidMajor, es.fidMinor, es.sup1, es.sup2); } es.dmux = &dmux; + break; } - break; case dmuxDisableEs: { ElementaryStream& es = *task.es.es_ptr; if (es.dmux != &dmux) { - cellDmux->Warning("dmuxDisableEs: invalid elementary stream"); - break; + DMUX_ERROR("dmuxDisableEs: invalid elementary stream"); } - for (u32 i = 0; i < 192; i++) + + for (u32 i = 0; i < sizeof(esALL) / sizeof(esALL[0]); i++) { if (esALL[i] == &es) { @@ -589,15 +699,15 @@ u32 dmuxOpen(Demuxer* data) } es.dmux = nullptr; Emu.GetIdManager().RemoveID(task.es.es); + break; } - break; case dmuxFlushEs: { ElementaryStream& es = *task.es.es_ptr; const u32 old_size = (u32)es.raw_data.size(); - if (old_size && (es.fidMajor & 0xf0) == 0xe0) + if (old_size && (es.fidMajor & -0x10) == 0xe0) { // TODO (it's only for AVC, some ATX data may be lost) while (es.isfull(old_size)) @@ -626,22 +736,23 @@ u32 dmuxOpen(Demuxer* data) esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_FLUSH_DONE; esMsg->supplementalInfo = stream.userdata; es.cbFunc.call(*dmux.dmuxCb, dmux.id, es.id, esMsg, es.cbArg); + break; } - break; case dmuxResetEs: { task.es.es_ptr->reset(); + break; + } + + case dmuxClose: + { + break; } - break; - - case dmuxClose: break; default: { - cellDmux->Error("Demuxer thread error: unknown task(%d)", task.type); - Emu.Pause(); - return; + DMUX_ERROR("Demuxer thread error: unknown task (0x%x)", task.type); } } } diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.h b/rpcs3/Emu/SysCalls/Modules/cellDmux.h index 5da9258bb0..e2212a3385 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.h +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.h @@ -288,15 +288,8 @@ enum PACKET_START_CODE_MASK = 0xffffff00, PACKET_START_CODE_PREFIX = 0x00000100, - USER_DATA_START_CODE = 0x000001b2, - SEQUENCE_START_CODE = 0x000001b3, - EXT_START_CODE = 0x000001b5, - SEQUENCE_END_CODE = 0x000001b7, - GOP_START_CODE = 0x000001b8, - ISO_11172_END_CODE = 0x000001b9, PACK_START_CODE = 0x000001ba, SYSTEM_HEADER_START_CODE = 0x000001bb, - PROGRAM_STREAM_MAP = 0x000001bc, PRIVATE_STREAM_1 = 0x000001bd, PADDING_STREAM = 0x000001be, PRIVATE_STREAM_2 = 0x000001bf, @@ -336,6 +329,11 @@ struct DemuxerStream size = size > count ? size - count : 0; } + bool check(u32 count) const + { + return count <= size; + } + u64 get_ts(u8 c) { u8 v[4]; get((u32&)v); @@ -345,12 +343,6 @@ struct DemuxerStream (((u64)v[1] & 0x7e) << 15) | (((u64)v[2]) << 7) | ((u64)v[3] >> 1); } - - u64 get_ts() - { - u8 v; get(v); - return get_ts(v); - } }; struct PesHeader @@ -359,6 +351,7 @@ struct PesHeader u64 dts; u8 size; bool has_ts; + bool is_ok; PesHeader(DemuxerStream& stream); }; @@ -446,6 +439,8 @@ class ElementaryStream bool is_full(u32 space); public: + ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr cbFunc, u32 cbArg, u32 spec); + Demuxer* dmux; u32 id; const u32 memAddr; @@ -465,27 +460,6 @@ public: void push(DemuxerStream& stream, u32 size); // called by demuxer thread (not multithread-safe) - ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr cbFunc, u32 cbArg, u32 spec) - : dmux(dmux) - , memAddr(a128(addr)) - , memSize(size - (addr - memAddr)) - , fidMajor(fidMajor) - , fidMinor(fidMinor) - , sup1(sup1) - , sup2(sup2) - , cbFunc(cbFunc) - , cbArg(cbArg) - , spec(spec) - , put(memAddr) - , put_count(0) - , got_count(0) - , released(0) - , raw_pos(0) - , last_dts(0xffffffffffffffffull) - , last_pts(0xffffffffffffffffull) - { - } - bool isfull(u32 space); void push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool rap, u32 specific); diff --git a/rpcs3/Emu/SysCalls/Modules/cellPamf.h b/rpcs3/Emu/SysCalls/Modules/cellPamf.h index e740ca006d..681c43ca4e 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPamf.h +++ b/rpcs3/Emu/SysCalls/Modules/cellPamf.h @@ -141,6 +141,8 @@ struct CellCodecTimeStamp be_t lower; }; +static const u64 CODEC_TS_INVALID = 0xffffffffffffffffull; + // Entry point information struct CellPamfEp { diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp index 9482895b54..95f9285f86 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp @@ -19,6 +19,8 @@ extern "C" Module *cellVdec = nullptr; +#define VDEC_ERROR(...) { cellVdec->Error(__VA_ARGS__); Emu.Pause(); return; } // only for decoder thread + VideoDecoder::VideoDecoder(CellVdecCodecType type, u32 profile, u32 addr, u32 size, vm::ptr func, u32 arg) : type(type) , profile(profile) @@ -62,38 +64,28 @@ VideoDecoder::VideoDecoder(CellVdecCodecType type, u32 profile, u32 addr, u32 si } default: { - cellVdec->Error("VideoDecoder(): unknown type (0x%x)", type); - Emu.Pause(); - return; + VDEC_ERROR("VideoDecoder(): unknown type (0x%x)", type); } } if (!codec) { - cellVdec->Error("VideoDecoder(): avcodec_find_decoder() failed"); - Emu.Pause(); - return; + VDEC_ERROR("VideoDecoder(): avcodec_find_decoder() failed"); } if (!input_format) { - cellVdec->Error("VideoDecoder(): av_find_input_format() failed"); - Emu.Pause(); - return; + VDEC_ERROR("VideoDecoder(): av_find_input_format() failed"); } fmt = avformat_alloc_context(); if (!fmt) { - cellVdec->Error("VideoDecoder(): avformat_alloc_context() failed"); - Emu.Pause(); - return; + VDEC_ERROR("VideoDecoder(): avformat_alloc_context() failed"); } io_buf = (u8*)av_malloc(4096); fmt->pb = avio_alloc_context(io_buf, 4096, 0, this, vdecRead, NULL, NULL); if (!fmt->pb) { - cellVdec->Error("VideoDecoder(): avio_alloc_context() failed"); - Emu.Pause(); - return; + VDEC_ERROR("VideoDecoder(): avio_alloc_context() failed"); } } @@ -333,46 +325,40 @@ u32 vdecOpen(VideoDecoder* data) } else if (vdec.just_started) // deferred initialization { - err = avformat_open_input(&vdec.fmt, NULL, NULL, NULL); - if (err) + AVDictionary* opts = nullptr; + av_dict_set(&opts, "probesize", "4096", 0); + err = avformat_open_input(&vdec.fmt, NULL, NULL, &opts); + if (err || opts) { - cellVdec->Error("vdecDecodeAu: avformat_open_input() failed"); - Emu.Pause(); - break; + VDEC_ERROR("vdecDecodeAu: avformat_open_input() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0); } if (vdec.type == CELL_VDEC_CODEC_TYPE_DIVX) { err = avformat_find_stream_info(vdec.fmt, NULL); if (err || !vdec.fmt->nb_streams) { - cellVdec->Error("vdecDecodeAu: avformat_find_stream_info() failed (err=0x%x)", err); - Emu.Pause(); - break; + VDEC_ERROR("vdecDecodeAu: avformat_find_stream_info() failed (err=0x%x, nb_streams=%d)", err, vdec.fmt->nb_streams); } } else { if (!avformat_new_stream(vdec.fmt, vdec.codec)) { - cellVdec->Error("vdecDecodeAu: avformat_new_stream() failed"); - Emu.Pause(); - break; + VDEC_ERROR("vdecDecodeAu: avformat_new_stream() failed"); } } vdec.ctx = vdec.fmt->streams[0]->codec; // TODO: check data - AVDictionary* opts = nullptr; + opts = nullptr; av_dict_set(&opts, "refcounted_frames", "1", 0); { std::lock_guard lock(g_mutex_avcodec_open2); // not multithread-safe (???) err = avcodec_open2(vdec.ctx, vdec.codec, &opts); } - if (err) + if (err || opts) { - cellVdec->Error("vdecDecodeAu: avcodec_open2() failed"); - Emu.Pause(); - break; + VDEC_ERROR("vdecDecodeAu: avcodec_open2() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0); } vdec.just_started = false; @@ -417,9 +403,7 @@ u32 vdecOpen(VideoDecoder* data) if (!frame.data) { - cellVdec->Error("vdecDecodeAu: av_frame_alloc() failed"); - Emu.Pause(); - break; + VDEC_ERROR("vdecDecodeAu: av_frame_alloc() failed"); } int got_picture = 0; @@ -428,7 +412,7 @@ u32 vdecOpen(VideoDecoder* data) if (decode <= 0) { - if (!last_frame && decode < 0) + if (decode < 0) { cellVdec->Error("vdecDecodeAu: AU decoding error(0x%x)", decode); } @@ -439,14 +423,12 @@ u32 vdecOpen(VideoDecoder* data) { if (frame.data->interlaced_frame) { - cellVdec->Error("vdecDecodeAu: interlaced frames not supported (0x%x)", frame.data->interlaced_frame); - Emu.Pause(); + VDEC_ERROR("vdecDecodeAu: interlaced frames not supported (0x%x)", frame.data->interlaced_frame); } if (frame.data->repeat_pict) { - cellVdec->Error("vdecDecodeAu: repeated frames not supported (0x%x)", frame.data->repeat_pict); - Emu.Pause(); + VDEC_ERROR("vdecDecodeAu: repeated frames not supported (0x%x)", frame.data->repeat_pict); } if (vdec.frc_set) @@ -467,8 +449,7 @@ u32 vdecOpen(VideoDecoder* data) case CELL_VDEC_FRC_60: vdec.last_pts += 90000 / 60; break; default: { - cellVdec->Error("vdecDecodeAu: invalid frame rate code set (0x%x)", vdec.frc_set); - Emu.Pause(); + VDEC_ERROR("vdecDecodeAu: invalid frame rate code set (0x%x)", vdec.frc_set); } } @@ -501,8 +482,7 @@ u32 vdecOpen(VideoDecoder* data) case 60: case 0x100000000ull + 120: frame.frc = CELL_VDEC_FRC_60; break; default: { - cellVdec->Error("vdecDecodeAu: unsupported time_base.den (%d/1, tpf=%d)", vdec.ctx->time_base.den, vdec.ctx->ticks_per_frame); - Emu.Pause(); + VDEC_ERROR("vdecDecodeAu: unsupported time_base.den (%d/1, tpf=%d)", vdec.ctx->time_base.den, vdec.ctx->ticks_per_frame); } } } @@ -522,14 +502,12 @@ u32 vdecOpen(VideoDecoder* data) } else { - cellVdec->Error("vdecDecodeAu: unsupported time_base.den (%d/1001, tpf=%d)", vdec.ctx->time_base.den, vdec.ctx->ticks_per_frame); - Emu.Pause(); + VDEC_ERROR("vdecDecodeAu: unsupported time_base.den (%d/1001, tpf=%d)", vdec.ctx->time_base.den, vdec.ctx->ticks_per_frame); } } else { - cellVdec->Error("vdecDecodeAu: unsupported time_base.num (%d)", vdec.ctx->time_base.num); - Emu.Pause(); + VDEC_ERROR("vdecDecodeAu: unsupported time_base.num (%d)", vdec.ctx->time_base.num); } } @@ -558,13 +536,14 @@ u32 vdecOpen(VideoDecoder* data) break; } - case vdecClose: break; + case vdecClose: + { + break; + } default: { - cellVdec->Error("Video Decoder thread error: unknown task(%d)", task.type); - Emu.Pause(); - return; + VDEC_ERROR("Video Decoder thread error: unknown task(%d)", task.type); } } } @@ -739,7 +718,7 @@ int cellVdecGetPicture(u32 handle, vm::ptr format, vm:: int err = av_image_copy_to_buffer(outBuff.get_ptr(), buf_size, frame.data, frame.linesize, vdec->ctx->pix_fmt, frame.width, frame.height, 1); if (err < 0) { - cellVdec->Error("cellVdecGetPicture: av_image_copy_to_buffer failed(%d)", err); + cellVdec->Error("cellVdecGetPicture: av_image_copy_to_buffer failed (err=0x%x)", err); Emu.Pause(); } } @@ -782,12 +761,12 @@ int cellVdecGetPicItem(u32 handle, vm::ptr picItem_ptr) info->auNum = 1; info->auPts[0].lower = (u32)vf.pts; info->auPts[0].upper = vf.pts >> 32; - info->auPts[1].lower = 0xffffffff; - info->auPts[1].upper = 0xffffffff; + info->auPts[1].lower = (u32)CODEC_TS_INVALID; + info->auPts[1].upper = (u32)CODEC_TS_INVALID; info->auDts[0].lower = (u32)vf.dts; info->auDts[0].upper = vf.dts >> 32; - info->auDts[1].lower = 0xffffffff; - info->auDts[1].upper = 0xffffffff; + info->auDts[1].lower = (u32)CODEC_TS_INVALID; + info->auDts[1].upper = (u32)CODEC_TS_INVALID; info->auUserData[0] = vf.userdata; info->auUserData[1] = 0; info->status = CELL_OK; @@ -836,7 +815,7 @@ int cellVdecGetPicItem(u32 handle, vm::ptr picItem_ptr) case CELL_VDEC_FRC_50: avc->frameRateCode = CELL_VDEC_AVC_FRC_50; break; case CELL_VDEC_FRC_60000DIV1001: avc->frameRateCode = CELL_VDEC_AVC_FRC_60000DIV1001; break; case CELL_VDEC_FRC_60: avc->frameRateCode = CELL_VDEC_AVC_FRC_60; break; - default: cellVdec->Error("cellVdecGetPicItem(AVC): unknown frc value (0x%x)", vf.frc); break; + default: cellVdec->Error("cellVdecGetPicItem(AVC): unknown frc value (0x%x)", vf.frc); } avc->fixed_frame_rate_flag = true;