diff --git a/Core/HLE/sceMpeg.cpp b/Core/HLE/sceMpeg.cpp index 67d7222cba37..f6ed065760fd 100644 --- a/Core/HLE/sceMpeg.cpp +++ b/Core/HLE/sceMpeg.cpp @@ -667,6 +667,7 @@ static int sceMpegRegistStream(u32 mpeg, u32 streamType, u32 streamNum) switch (streamType) { case MPEG_AVC_STREAM: ctx->avcRegistered = true; + ctx->mediaengine->addVideoStream(streamNum); // TODO: Probably incorrect? ctx->mediaengine->setVideoStream(streamNum); break; @@ -1495,6 +1496,9 @@ void PostPutAction::run(MipsCall &call) { // Program signals that it has written data to the ringbuffer and gets a callback ? static u32 sceMpegRingbufferPut(u32 ringbufferAddr, int numPackets, int available) { + // Generally, program will call sceMpegRingbufferAvailableSize() before this func. + // Still need to check available? + numPackets = std::min(numPackets, available); if (numPackets <= 0) { DEBUG_LOG(ME, "sceMpegRingbufferPut(%08x, %i, %i): no packets to enqueue", ringbufferAddr, numPackets, available); @@ -1518,15 +1522,21 @@ static u32 sceMpegRingbufferPut(u32 ringbufferAddr, int numPackets, int availabl if (ringbuffer->callback_addr != 0) { DEBUG_LOG(ME, "sceMpegRingbufferPut(%08x, %i, %i)", ringbufferAddr, numPackets, available); - PostPutAction *action = (PostPutAction *)__KernelCreateAction(actionPostPut); - action->setRingAddr(ringbufferAddr); - // TODO: Should call this multiple times until we get numPackets. + // Call this multiple times until we get numPackets. // Normally this would be if it did not read enough, but also if available > packets. // Should ultimately return the TOTAL number of returned packets. int writeOffset = ringbuffer->packetsWritePos % (s32)ringbuffer->packets; - u32 packetsThisRound = std::min(numPackets, (s32)ringbuffer->packets - writeOffset); - u32 args[3] = {(u32)ringbuffer->data + (u32)writeOffset * 2048, packetsThisRound, (u32)ringbuffer->callback_args}; - hleEnqueueCall(ringbuffer->callback_addr, 3, args, action); + u32 packetsThisRound = 0; + while (numPackets) { + PostPutAction *action = (PostPutAction *)__KernelCreateAction(actionPostPut); + action->setRingAddr(ringbufferAddr); + + packetsThisRound = std::min(numPackets, (s32)ringbuffer->packets - writeOffset); + numPackets -= packetsThisRound; + u32 args[3] = { (u32)ringbuffer->data + (u32)writeOffset * 2048, packetsThisRound, (u32)ringbuffer->callback_args }; + hleEnqueueCall(ringbuffer->callback_addr, 3, args, action); + writeOffset = (writeOffset + packetsThisRound) % (s32)ringbuffer->packets; + } } else { ERROR_LOG_REPORT(ME, "sceMpegRingbufferPut: callback_addr zero"); } diff --git a/Core/HW/MediaEngine.cpp b/Core/HW/MediaEngine.cpp index 6b1d646bd122..0a1e50f52707 100644 --- a/Core/HW/MediaEngine.cpp +++ b/Core/HW/MediaEngine.cpp @@ -132,6 +132,8 @@ MediaEngine::MediaEngine(): m_pdata(0) { m_videoStream = -1; m_audioStream = -1; + m_expectedVideoStreams = 0; + m_desWidth = 0; m_desHeight = 0; m_decodingsize = 0; @@ -169,7 +171,7 @@ void MediaEngine::closeMedia() { } void MediaEngine::DoState(PointerWrap &p) { - auto s = p.Section("MediaEngine", 1, 5); + auto s = p.Section("MediaEngine", 1, 6); if (!s) return; @@ -187,6 +189,11 @@ void MediaEngine::DoState(PointerWrap &p) { } else { m_mpegheaderReadPos = m_mpegheaderSize; } + if (s >= 6) { + Do(p, m_expectedVideoStreams); + } else { + m_expectedVideoStreams = 0; + } Do(p, m_ringbuffersize); @@ -258,20 +265,22 @@ bool MediaEngine::SetupStreams() { } // Looking good. Let's add those streams. - const AVCodec *h264_codec = avcodec_find_decoder(AV_CODEC_ID_H264); + int videoStreamNum = -1; for (int i = 0; i < numStreams; i++) { const u8 *const currentStreamAddr = m_mpegheader + 0x82 + i * 16; int streamId = currentStreamAddr[0]; // We only set video streams. We demux the audio stream separately. if ((streamId & PSMF_VIDEO_STREAM_ID) == PSMF_VIDEO_STREAM_ID) { - AVStream *stream = avformat_new_stream(m_pFormatCtx, h264_codec); - stream->id = 0x00000100 | streamId; - stream->request_probe = 0; - stream->need_parsing = AVSTREAM_PARSE_FULL; - // We could set the width here, but we don't need to. + ++videoStreamNum; + addVideoStream(videoStreamNum, streamId); } } + // Add the streams to meet the expectation. + for (int i = videoStreamNum + 1; i < m_expectedVideoStreams; i++) { + addVideoStream(i); + } + #endif return true; @@ -386,6 +395,38 @@ bool MediaEngine::reloadStream() return loadStream(m_mpegheader, 2048, m_ringbuffersize); } +bool MediaEngine::addVideoStream(int streamNum, int streamId) { +#ifdef USE_FFMPEG + if (m_pFormatCtx) { + // no need to add an existing stream. + if ((u32)streamNum < m_pFormatCtx->nb_streams) + return true; + const AVCodec *h264_codec = avcodec_find_decoder(AV_CODEC_ID_H264); + if (!h264_codec) + return false; + AVStream *stream = avformat_new_stream(m_pFormatCtx, h264_codec); + if (stream) { + // Reference ISO/IEC 13818-1. + if (streamId == -1) + streamId = PSMF_VIDEO_STREAM_ID | streamNum; + + stream->id = 0x00000100 | streamId; + stream->request_probe = 0; + stream->need_parsing = AVSTREAM_PARSE_FULL; + // We could set the width here, but we don't need to. + if (streamNum >= m_expectedVideoStreams) { + ++m_expectedVideoStreams; + } + return true; + } + } +#endif + if (streamNum >= m_expectedVideoStreams) { + ++m_expectedVideoStreams; + } + return false; +} + int MediaEngine::addStreamData(const u8 *buffer, int addSize) { int size = addSize; if (size > 0 && m_pdata) { diff --git a/Core/HW/MediaEngine.h b/Core/HW/MediaEngine.h index ff3a03242440..7e9bc2c585f9 100644 --- a/Core/HW/MediaEngine.h +++ b/Core/HW/MediaEngine.h @@ -59,6 +59,7 @@ class MediaEngine void closeMedia(); bool loadStream(const u8 *buffer, int readSize, int RingbufferSize); bool reloadStream(); + bool addVideoStream(int streamNum, int streamId = -1); // open the mpeg context bool openContext(bool keepReadPos = false); void closeContext(); @@ -114,6 +115,7 @@ class MediaEngine int m_sws_fmt; u8 *m_buffer; int m_videoStream; + int m_expectedVideoStreams; // Used by the demuxer. int m_audioStream;