diff --git a/Core/HW/BufferQueue.h b/Core/HW/BufferQueue.h index 0ceb0985e3..3c58005357 100644 --- a/Core/HW/BufferQueue.h +++ b/Core/HW/BufferQueue.h @@ -17,6 +17,7 @@ #pragma once +#include #include #include "Common/ChunkFile.h" @@ -60,11 +61,12 @@ struct BufferQueue { return bufQueueSize - getQueueSize(); } - bool push(unsigned char *buf, int addsize) { + bool push(const unsigned char *buf, int addsize, s64 pts = 0) { int queuesz = getQueueSize(); int space = bufQueueSize - queuesz; if (space < addsize || addsize < 0) return false; + savePts(pts); if (end + addsize <= bufQueueSize) { memcpy(bufQueue + end, buf, addsize); end += addsize; @@ -77,12 +79,15 @@ struct BufferQueue { return true; } - int pop_front(unsigned char *buf, int wantedsize) { + int pop_front(unsigned char *buf, int wantedsize, s64 *pts = NULL) { if (wantedsize <= 0) return 0; int bytesgot = getQueueSize(); if (wantedsize < bytesgot) bytesgot = wantedsize; + if (pts != NULL) { + *pts = findPts(bytesgot); + } if (buf) { if (start + bytesgot <= bufQueueSize) { memcpy(buf, bufQueue + start, bytesgot); @@ -120,14 +125,59 @@ struct BufferQueue { } void DoState(PointerWrap &p) { + auto s = p.Section("BufferQueue", 0, 1); + p.Do(bufQueueSize); p.Do(start); p.Do(end); - if (bufQueue) + if (bufQueue) { p.DoArray(bufQueue, bufQueueSize); + } + + if (s >= 1) { + p.Do(ptsMarks); + } + } + +private: + void savePts(u64 pts) { + if (pts != 0) { + ptsMarks[end] = pts; + } + } + + u64 findPts(std::map::iterator earliest, std::map::iterator latest) { + u64 pts = 0; + // Take the first one, that is the pts of this packet. + if (earliest != latest) { + pts = earliest->second; + } + ptsMarks.erase(earliest, latest); + return pts; + } + + u64 findPts(int packetSize) { + auto earliest = ptsMarks.lower_bound(start); + auto latest = ptsMarks.lower_bound(start + packetSize); + + u64 pts = findPts(earliest, latest); + + // If it wraps around, we have to look at the other half too. + if (start + packetSize > bufQueueSize) { + earliest = ptsMarks.begin(); + latest = ptsMarks.lower_bound(start + packetSize - bufQueueSize); + u64 pts2 = findPts(earliest, latest); + if (pts2 != 0) { + pts = pts2; + } + } + + return pts; } unsigned char* bufQueue; int start, end; int bufQueueSize; + + std::map ptsMarks; }; diff --git a/Core/HW/MediaEngine.cpp b/Core/HW/MediaEngine.cpp index d93ffe51d8..a2151b73a1 100644 --- a/Core/HW/MediaEngine.cpp +++ b/Core/HW/MediaEngine.cpp @@ -319,7 +319,7 @@ void MediaEngine::closeContext() m_buffer = 0; } -bool MediaEngine::loadStream(u8* buffer, int readSize, int RingbufferSize) +bool MediaEngine::loadStream(const u8 *buffer, int readSize, int RingbufferSize) { closeMedia(); @@ -336,7 +336,7 @@ bool MediaEngine::loadStream(u8* buffer, int readSize, int RingbufferSize) return true; } -int MediaEngine::addStreamData(u8* buffer, int addSize) { +int MediaEngine::addStreamData(const u8 *buffer, int addSize) { int size = addSize; if (size > 0 && m_pdata) { if (!m_pdata->push(buffer, size)) @@ -762,7 +762,13 @@ int MediaEngine::getNextAudioFrame(u8 **buf, int *headerCode1, int *headerCode2) // Demux now (rather than on add data) so that we select the right stream. m_demux->demux(m_audioStream); - return m_demux->getNextAudioFrame(buf, headerCode1, headerCode2); + s64 pts = 0; + int result = m_demux->getNextAudioFrame(buf, headerCode1, headerCode2, &pts); + if (pts != 0) { + // m_audiopts is supposed to be after the returned frame. + m_audiopts = pts - m_firstTimeStamp + 4180; + } + return result; } int MediaEngine::getAudioSamples(u32 bufferPtr) { diff --git a/Core/HW/MediaEngine.h b/Core/HW/MediaEngine.h index f749bb1d5f..28442d18e0 100644 --- a/Core/HW/MediaEngine.h +++ b/Core/HW/MediaEngine.h @@ -41,7 +41,7 @@ struct AVFormatContext; struct AVCodecContext; #endif -inline s64 getMpegTimeStamp(u8* buf) { +inline s64 getMpegTimeStamp(const u8 *buf) { return (s64)buf[5] | ((s64)buf[4] << 8) | ((s64)buf[3] << 16) | ((s64)buf[2] << 24) | ((s64)buf[1] << 32) | ((s64)buf[0] << 36); } @@ -59,13 +59,13 @@ public: ~MediaEngine(); void closeMedia(); - bool loadStream(u8* buffer, int readSize, int RingbufferSize); + bool loadStream(const u8 *buffer, int readSize, int RingbufferSize); // open the mpeg context bool openContext(); void closeContext(); // Returns number of packets actually added. I guess the buffer might be full. - int addStreamData(u8* buffer, int addSize); + int addStreamData(const u8 *buffer, int addSize); bool seekTo(s64 timestamp, int videoPixelMode); bool setVideoStream(int streamNum, bool force = false); diff --git a/Core/HW/MpegDemux.cpp b/Core/HW/MpegDemux.cpp index f346c3e84b..b42403630f 100644 --- a/Core/HW/MpegDemux.cpp +++ b/Core/HW/MpegDemux.cpp @@ -145,7 +145,7 @@ int MpegDemux::demuxStream(bool bdemux, int startCode, int channel) length = readPesHeader(pesHeader, length, startCode); if (pesHeader.channel == channel || channel < 0) { channel = pesHeader.channel; - m_audioStream.push(m_buf + m_index, length); + m_audioStream.push(m_buf + m_index, length, pesHeader.pts); } skip(length); } else { @@ -234,7 +234,7 @@ static int getNextHeaderPosition(u8* audioStream, int curpos, int limit, int fra return -1; } -int MpegDemux::getNextAudioFrame(u8 **buf, int *headerCode1, int *headerCode2) +int MpegDemux::getNextAudioFrame(u8 **buf, int *headerCode1, int *headerCode2, s64 *pts) { int gotsize; int frameSize; @@ -247,7 +247,7 @@ int MpegDemux::getNextAudioFrame(u8 **buf, int *headerCode1, int *headerCode2) } else { audioPos = gotsize; } - m_audioStream.pop_front(0, audioPos); + m_audioStream.pop_front(0, audioPos, pts); if (buf) { *buf = m_audioFrame + 8; } diff --git a/Core/HW/MpegDemux.h b/Core/HW/MpegDemux.h index 11f2bccf82..f52904b867 100644 --- a/Core/HW/MpegDemux.h +++ b/Core/HW/MpegDemux.h @@ -18,7 +18,7 @@ public: void demux(int audioChannel); // return its framesize - int getNextAudioFrame(u8 **buf, int *headerCode1, int *headerCode2); + int getNextAudioFrame(u8 **buf, int *headerCode1, int *headerCode2, s64 *pts = NULL); bool hasNextAudioFrame(int *gotsizeOut, int *frameSizeOut, int *headerCode1, int *headerCode2); inline int getRemainSize() {