mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-13 22:40:29 +02:00
Merge pull request #2143 from unknownbrackets/mpeg-fix
Improvements to sceMpeg: fix end cutoff, early audio end, and minor
This commit is contained in:
commit
30536fa7cf
7 files changed
+131
-76
No files matched your search
@@ -493,6 +493,11 @@ public:
|
||||
|
||||
bool GetIDType(SceUID handle, int *type) const
|
||||
{
|
||||
if (handle < handleOffset || handle >= handleOffset+maxCount || !occupied[handle-handleOffset])
|
||||
{
|
||||
ERROR_LOG(HLE, "Kernel: Bad object handle %i (%08x)", handle, handle);
|
||||
return false;
|
||||
}
|
||||
KernelObject *t = pool[handle - handleOffset];
|
||||
*type = t->GetIDType();
|
||||
return true;
|
||||
|
||||
+42
-17
@@ -182,6 +182,7 @@ struct MpegContext {
|
||||
MediaEngine *mediaengine;
|
||||
};
|
||||
|
||||
static bool isMpegInit;
|
||||
static u32 streamIdGen;
|
||||
static bool isCurrentMpegAnalyzed;
|
||||
static int actionPostPut;
|
||||
@@ -299,6 +300,7 @@ void __MpegInit(bool useMediaEngine_) {
|
||||
lastMpegHandle = 0;
|
||||
streamIdGen = 1;
|
||||
isCurrentMpegAnalyzed = false;
|
||||
isMpegInit = false;
|
||||
actionPostPut = __KernelRegisterActionType(PostPutAction::Create);
|
||||
}
|
||||
|
||||
@@ -306,6 +308,7 @@ void __MpegDoState(PointerWrap &p) {
|
||||
p.Do(lastMpegHandle);
|
||||
p.Do(streamIdGen);
|
||||
p.Do(isCurrentMpegAnalyzed);
|
||||
p.Do(isMpegInit);
|
||||
p.Do(actionPostPut);
|
||||
__KernelRestoreActionType(actionPostPut, PostPutAction::Create);
|
||||
|
||||
@@ -322,15 +325,20 @@ void __MpegShutdown() {
|
||||
mpegMap.clear();
|
||||
}
|
||||
|
||||
u32 sceMpegInit()
|
||||
{
|
||||
if (!g_Config.bUseMediaEngine){
|
||||
u32 sceMpegInit() {
|
||||
if (!g_Config.bUseMediaEngine) {
|
||||
WARN_LOG(HLE, "Media Engine disabled");
|
||||
return -1;
|
||||
}
|
||||
|
||||
WARN_LOG(HLE, "sceMpegInit()");
|
||||
return 0;
|
||||
if (isMpegInit) {
|
||||
WARN_LOG(HLE, "sceMpegInit(): already initialized");
|
||||
return ERROR_MPEG_ALREADY_INIT;
|
||||
}
|
||||
|
||||
INFO_LOG(HLE, "sceMpegInit()");
|
||||
isMpegInit = true;
|
||||
return hleDelayResult(0, "mpeg init", 750);
|
||||
}
|
||||
|
||||
u32 sceMpegRingbufferQueryMemSize(int packets)
|
||||
@@ -351,7 +359,7 @@ u32 sceMpegRingbufferConstruct(u32 ringbufferAddr, u32 numPackets, u32 data, u32
|
||||
|
||||
u32 sceMpegCreate(u32 mpegAddr, u32 dataPtr, u32 size, u32 ringbufferAddr, u32 frameWidth, u32 mode, u32 ddrTop)
|
||||
{
|
||||
if (!g_Config.bUseMediaEngine){
|
||||
if (!g_Config.bUseMediaEngine) {
|
||||
WARN_LOG(HLE, "Media Engine disabled");
|
||||
return -1;
|
||||
}
|
||||
@@ -410,7 +418,7 @@ u32 sceMpegCreate(u32 mpegAddr, u32 dataPtr, u32 size, u32 ringbufferAddr, u32 f
|
||||
|
||||
INFO_LOG(HLE, "%08x=sceMpegCreate(%08x, %08x, %i, %08x, %i, %i, %i)",
|
||||
mpegHandle, mpegAddr, dataPtr, size, ringbufferAddr, frameWidth, mode, ddrTop);
|
||||
return 0;
|
||||
return hleDelayResult(0, "mpeg create", 29000);
|
||||
}
|
||||
|
||||
int sceMpegDelete(u32 mpeg)
|
||||
@@ -621,8 +629,8 @@ u32 sceMpegAvcDecode(u32 mpeg, u32 auAddr, u32 frameWidth, u32 bufferAddr, u32 i
|
||||
SceMpegRingBuffer ringbuffer;
|
||||
Memory::ReadStruct(ctx->mpegRingbufferAddr, &ringbuffer);
|
||||
|
||||
if (ringbuffer.packetsRead == 0) {
|
||||
// empty!
|
||||
if (ringbuffer.packetsRead == 0 || ctx->mediaengine->IsVideoEnd()) {
|
||||
WARN_LOG(HLE, "sceMpegAvcDecode(%08x, %08x, %d, %08x, %08x): mpeg buffer empty", mpeg, auAddr, frameWidth, bufferAddr, initAddr);
|
||||
return hleDelayResult(MPEG_AVC_DECODE_ERROR_FATAL, "mpeg buffer empty", avcEmptyDelayMs);
|
||||
}
|
||||
|
||||
@@ -632,14 +640,15 @@ u32 sceMpegAvcDecode(u32 mpeg, u32 auAddr, u32 frameWidth, u32 bufferAddr, u32 i
|
||||
|
||||
if (ctx->mediaengine->stepVideo(ctx->videoPixelMode)) {
|
||||
ctx->mediaengine->writeVideoImage(Memory::GetPointer(buffer), frameWidth, ctx->videoPixelMode);
|
||||
ctx->avc.avcFrameStatus = 1;
|
||||
ctx->videoFrameCount++;
|
||||
} else {
|
||||
ctx->avc.avcFrameStatus = 0;
|
||||
}
|
||||
ringbuffer.packetsFree = std::max(0, ringbuffer.packets - ctx->mediaengine->getBufferedSize() / 2048);
|
||||
|
||||
avcAu.pts = ctx->mediaengine->getVideoTimeStamp();
|
||||
|
||||
ctx->avc.avcFrameStatus = 1;
|
||||
ctx->videoFrameCount++;
|
||||
|
||||
ctx->avc.avcDecodeResult = MPEG_AVC_DECODE_SUCCESS;
|
||||
|
||||
// Flush structs back to memory
|
||||
@@ -920,9 +929,13 @@ u32 sceMpegRingbufferPut(u32 ringbufferAddr, u32 numPackets, u32 available)
|
||||
|
||||
// Execute callback function as a direct MipsCall, no blocking here so no messing around with wait states etc
|
||||
if (ringbuffer.callback_addr) {
|
||||
PostPutAction *action = (PostPutAction *) __KernelCreateAction(actionPostPut);
|
||||
PostPutAction *action = (PostPutAction *)__KernelCreateAction(actionPostPut);
|
||||
action->setRingAddr(ringbufferAddr);
|
||||
u32 args[3] = {(u32)ringbuffer.data, numPackets, (u32)ringbuffer.callback_args};
|
||||
// TODO: Should 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.
|
||||
u32 packetsThisRound = std::min(numPackets, (u32)ringbuffer.packets);
|
||||
u32 args[3] = {(u32)ringbuffer.data, packetsThisRound, (u32)ringbuffer.callback_args};
|
||||
__KernelDirectMipsCall(ringbuffer.callback_addr, action, args, 3, false);
|
||||
} else {
|
||||
ERROR_LOG(HLE, "sceMpegRingbufferPut: callback_addr zero");
|
||||
@@ -946,6 +959,9 @@ int sceMpegGetAvcAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr)
|
||||
|
||||
if (mpegRingbuffer.packetsRead == 0 || mpegRingbuffer.packetsFree == mpegRingbuffer.packets) {
|
||||
DEBUG_LOG(HLE, "PSP_ERROR_MPEG_NO_DATA=sceMpegGetAvcAu(%08x, %08x, %08x, %08x)", mpeg, streamId, auAddr, attrAddr);
|
||||
sceAu.pts = -1;
|
||||
sceAu.dts = -1;
|
||||
sceAu.write(auAddr);
|
||||
// TODO: Does this really reschedule?
|
||||
return hleDelayResult(PSP_ERROR_MPEG_NO_DATA, "mpeg get avc", mpegDecodeErrorDelayMs);
|
||||
}
|
||||
@@ -974,6 +990,7 @@ int sceMpegGetAvcAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr)
|
||||
int result = 0;
|
||||
|
||||
sceAu.pts = ctx->mediaengine->getVideoTimeStamp();
|
||||
sceAu.dts = sceAu.pts - videoTimestampStep;
|
||||
if (ctx->mediaengine->IsVideoEnd()) {
|
||||
INFO_LOG(HLE, "video end reach. pts: %i dts: %i", (int)sceAu.pts, (int)ctx->mediaengine->getLastTimeStamp());
|
||||
mpegRingbuffer.packetsFree = mpegRingbuffer.packets;
|
||||
@@ -997,9 +1014,16 @@ int sceMpegGetAvcAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr)
|
||||
|
||||
u32 sceMpegFinish()
|
||||
{
|
||||
ERROR_LOG(HLE, "sceMpegFinish(...)");
|
||||
if (!isMpegInit)
|
||||
{
|
||||
WARN_LOG(HLE, "sceMpegFinish(...): not initialized");
|
||||
return ERROR_MPEG_NOT_YET_INIT;
|
||||
}
|
||||
|
||||
INFO_LOG(HLE, "sceMpegFinish(...)");
|
||||
isMpegInit = false;
|
||||
//__MpegFinish();
|
||||
return 0;
|
||||
return hleDelayResult(0, "mpeg finish", 250);
|
||||
}
|
||||
|
||||
u32 sceMpegQueryMemSize()
|
||||
@@ -1029,7 +1053,8 @@ int sceMpegGetAtracAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr)
|
||||
streamInfo->second.needsReset = false;
|
||||
}
|
||||
|
||||
if (mpegRingbuffer.packetsFree == mpegRingbuffer.packets) {
|
||||
// The audio can end earlier than the video does.
|
||||
if (mpegRingbuffer.packetsFree == mpegRingbuffer.packets || (ctx->mediaengine->IsAudioEnd() && !ctx->mediaengine->IsVideoEnd())) {
|
||||
DEBUG_LOG(HLE, "PSP_ERROR_MPEG_NO_DATA=sceMpegGetAtracAu(%08x, %08x, %08x, %08x)", mpeg, streamId, auAddr, attrAddr);
|
||||
// TODO: Does this really delay?
|
||||
return hleDelayResult(PSP_ERROR_MPEG_NO_DATA, "mpeg get atrac", mpegDecodeErrorDelayMs);
|
||||
|
||||
@@ -40,6 +40,8 @@ enum {
|
||||
ERROR_PSMFPLAYER_NO_MORE_DATA = 0x8061600c,
|
||||
|
||||
ERROR_MPEG_NO_DATA = 0x80618001,
|
||||
ERROR_MPEG_ALREADY_INIT = 0x80618005,
|
||||
ERROR_MPEG_NOT_YET_INIT = 0x80618009,
|
||||
};
|
||||
|
||||
// MPEG statics.
|
||||
|
||||
@@ -555,8 +555,7 @@ u32 scePsmfQueryStreamOffset(u32 bufferAddr, u32 offsetAddr)
|
||||
if (Memory::IsValidAddress(offsetAddr)) {
|
||||
Memory::Write_U32(bswap32(Memory::Read_U32(bufferAddr + PSMF_STREAM_OFFSET_OFFSET)), offsetAddr);
|
||||
}
|
||||
// return 0 breaks history mode in Saint Seiya Omega
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 scePsmfQueryStreamSize(u32 bufferAddr, u32 sizeAddr)
|
||||
|
||||
+67
-50
@@ -81,7 +81,7 @@ static int getPixelFormatBytes(int pspFormat)
|
||||
}
|
||||
}
|
||||
|
||||
MediaEngine::MediaEngine(): m_streamSize(0), m_readSize(0), m_pdata(0) {
|
||||
MediaEngine::MediaEngine(): m_streamSize(0), m_readSize(0), m_decodedPos(0), m_pdata(0) {
|
||||
m_pFormatCtx = 0;
|
||||
m_pCodecCtx = 0;
|
||||
m_pFrame = 0;
|
||||
@@ -91,10 +91,8 @@ MediaEngine::MediaEngine(): m_streamSize(0), m_readSize(0), m_pdata(0) {
|
||||
m_buffer = 0;
|
||||
m_demux = 0;
|
||||
m_audioContext = 0;
|
||||
m_pdata = 0;
|
||||
m_streamSize = 0;
|
||||
m_readSize = 0;
|
||||
m_isVideoEnd = false;
|
||||
m_isAudioEnd = false;
|
||||
}
|
||||
|
||||
MediaEngine::~MediaEngine() {
|
||||
@@ -109,14 +107,14 @@ void MediaEngine::closeMedia() {
|
||||
av_free(m_pFrameRGB);
|
||||
if (m_pFrame)
|
||||
av_free(m_pFrame);
|
||||
if (m_pIOContext && ((AVIOContext*)m_pIOContext)->buffer)
|
||||
av_free(((AVIOContext*)m_pIOContext)->buffer);
|
||||
if (m_pIOContext && m_pIOContext->buffer)
|
||||
av_free(m_pIOContext->buffer);
|
||||
if (m_pIOContext)
|
||||
av_free(m_pIOContext);
|
||||
if (m_pCodecCtx)
|
||||
avcodec_close((AVCodecContext*)m_pCodecCtx);
|
||||
avcodec_close(m_pCodecCtx);
|
||||
if (m_pFormatCtx)
|
||||
avformat_close_input((AVFormatContext**)&m_pFormatCtx);
|
||||
avformat_close_input(&m_pFormatCtx);
|
||||
#endif // USE_FFMPEG
|
||||
if (m_pdata)
|
||||
delete [] m_pdata;
|
||||
@@ -133,16 +131,17 @@ void MediaEngine::closeMedia() {
|
||||
m_demux = 0;
|
||||
Atrac3plus_Decoder::CloseContext(&m_audioContext);
|
||||
m_isVideoEnd = false;
|
||||
m_isAudioEnd = false;
|
||||
}
|
||||
|
||||
int _MpegReadbuffer(void *opaque, uint8_t *buf, int buf_size)
|
||||
{
|
||||
MediaEngine *mpeg = (MediaEngine*)opaque;
|
||||
int size = std::min(mpeg->m_bufSize, buf_size);
|
||||
size = std::max(std::min((mpeg->m_readSize - mpeg->m_decodePos), size), 0);
|
||||
size = std::max(std::min((mpeg->m_readSize - mpeg->m_decodeNextPos), size), 0);
|
||||
if (size > 0)
|
||||
memcpy(buf, mpeg->m_pdata + mpeg->m_decodePos, size);
|
||||
mpeg->m_decodePos += size;
|
||||
memcpy(buf, mpeg->m_pdata + mpeg->m_decodeNextPos, size);
|
||||
mpeg->m_decodeNextPos += size;
|
||||
return size;
|
||||
}
|
||||
|
||||
@@ -151,13 +150,13 @@ int64_t _MpegSeekbuffer(void *opaque, int64_t offset, int whence)
|
||||
MediaEngine *mpeg = (MediaEngine*)opaque;
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
mpeg->m_decodePos = offset;
|
||||
mpeg->m_decodeNextPos = offset;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
mpeg->m_decodePos += offset;
|
||||
mpeg->m_decodeNextPos += offset;
|
||||
break;
|
||||
case SEEK_END:
|
||||
mpeg->m_decodePos = mpeg->m_streamSize - (u32)offset;
|
||||
mpeg->m_decodeNextPos = mpeg->m_streamSize - (u32)offset;
|
||||
break;
|
||||
}
|
||||
return offset;
|
||||
@@ -181,21 +180,20 @@ bool MediaEngine::openContext() {
|
||||
|
||||
u8* tempbuf = (u8*)av_malloc(m_bufSize);
|
||||
|
||||
AVFormatContext *pFormatCtx = avformat_alloc_context();
|
||||
m_pFormatCtx = (void*)pFormatCtx;
|
||||
m_pIOContext = (void*)avio_alloc_context(tempbuf, m_bufSize, 0, (void*)this, _MpegReadbuffer, NULL, _MpegSeekbuffer);
|
||||
pFormatCtx->pb = (AVIOContext*)m_pIOContext;
|
||||
m_pFormatCtx = avformat_alloc_context();
|
||||
m_pIOContext = avio_alloc_context(tempbuf, m_bufSize, 0, (void*)this, _MpegReadbuffer, NULL, _MpegSeekbuffer);
|
||||
m_pFormatCtx->pb = m_pIOContext;
|
||||
|
||||
// Open video file
|
||||
if(avformat_open_input((AVFormatContext**)&m_pFormatCtx, NULL, NULL, NULL) != 0)
|
||||
return false;
|
||||
|
||||
if(avformat_find_stream_info(pFormatCtx, NULL) < 0)
|
||||
if(avformat_find_stream_info(m_pFormatCtx, NULL) < 0)
|
||||
return false;
|
||||
|
||||
// Find the first video stream
|
||||
for(int i = 0; i < (int)pFormatCtx->nb_streams; i++) {
|
||||
if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
|
||||
for(int i = 0; i < (int)m_pFormatCtx->nb_streams; i++) {
|
||||
if(m_pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
|
||||
m_videoStream = i;
|
||||
break;
|
||||
}
|
||||
@@ -204,17 +202,16 @@ bool MediaEngine::openContext() {
|
||||
return false;
|
||||
|
||||
// Get a pointer to the codec context for the video stream
|
||||
m_pCodecCtx = (void*)pFormatCtx->streams[m_videoStream]->codec;
|
||||
AVCodecContext *pCodecCtx = (AVCodecContext*)m_pCodecCtx;
|
||||
m_pCodecCtx = m_pFormatCtx->streams[m_videoStream]->codec;
|
||||
|
||||
// Find the decoder for the video stream
|
||||
AVCodec *pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
|
||||
AVCodec *pCodec = avcodec_find_decoder(m_pCodecCtx->codec_id);
|
||||
if(pCodec == NULL)
|
||||
return false;
|
||||
|
||||
// Open codec
|
||||
AVDictionary *optionsDict = 0;
|
||||
if(avcodec_open2(pCodecCtx, pCodec, &optionsDict)<0)
|
||||
if(avcodec_open2(m_pCodecCtx, pCodec, &optionsDict)<0)
|
||||
return false; // Could not open codec
|
||||
|
||||
setVideoDim();
|
||||
@@ -225,6 +222,8 @@ bool MediaEngine::openContext() {
|
||||
m_audioPos = 0;
|
||||
m_audioContext = Atrac3plus_Decoder::OpenContext();
|
||||
m_isVideoEnd = false;
|
||||
m_isAudioEnd = false;
|
||||
m_decodedPos = mpegoffset;
|
||||
#endif // USE_FFMPEG
|
||||
return true;
|
||||
}
|
||||
@@ -238,7 +237,7 @@ bool MediaEngine::loadStream(u8* buffer, int readSize, int StreamSize)
|
||||
m_videopts = 0;
|
||||
m_audiopts = 0;
|
||||
m_bufSize = 0x2000;
|
||||
m_decodePos = 0;
|
||||
m_decodeNextPos = 0;
|
||||
m_readSize = readSize;
|
||||
m_streamSize = StreamSize;
|
||||
m_pdata = new u8[StreamSize];
|
||||
@@ -269,7 +268,7 @@ bool MediaEngine::loadFile(const char* filename)
|
||||
m_videopts = 0;
|
||||
m_audiopts = 0;
|
||||
m_bufSize = 0x2000;
|
||||
m_decodePos = 0;
|
||||
m_decodeNextPos = 0;
|
||||
m_readSize = infosize;
|
||||
m_streamSize = infosize;
|
||||
m_pdata = buf;
|
||||
@@ -300,12 +299,11 @@ bool MediaEngine::setVideoDim(int width, int height)
|
||||
if (!m_pCodecCtx)
|
||||
return false;
|
||||
#ifdef USE_FFMPEG
|
||||
AVCodecContext *pCodecCtx = (AVCodecContext*)m_pCodecCtx;
|
||||
if (width == 0 && height == 0)
|
||||
{
|
||||
// use the orignal video size
|
||||
m_desWidth = pCodecCtx->width;
|
||||
m_desHeight = pCodecCtx->height;
|
||||
m_desWidth = m_pCodecCtx->width;
|
||||
m_desHeight = m_pCodecCtx->height;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -333,16 +331,15 @@ bool MediaEngine::setVideoDim(int width, int height)
|
||||
|
||||
void MediaEngine::updateSwsFormat(int videoPixelMode) {
|
||||
#ifdef USE_FFMPEG
|
||||
AVCodecContext *pCodecCtx = (AVCodecContext*)m_pCodecCtx;
|
||||
AVPixelFormat swsDesired = getSwsFormat(videoPixelMode);
|
||||
if (swsDesired != m_sws_fmt) {
|
||||
m_sws_fmt = swsDesired;
|
||||
m_sws_ctx = sws_getCachedContext
|
||||
(
|
||||
m_sws_ctx,
|
||||
pCodecCtx->width,
|
||||
pCodecCtx->height,
|
||||
pCodecCtx->pix_fmt,
|
||||
m_pCodecCtx->width,
|
||||
m_pCodecCtx->height,
|
||||
m_pCodecCtx->pix_fmt,
|
||||
m_desWidth,
|
||||
m_desHeight,
|
||||
(AVPixelFormat)m_sws_fmt,
|
||||
@@ -365,33 +362,47 @@ bool MediaEngine::stepVideo(int videoPixelMode) {
|
||||
// Update the linesize for the new format too. We started with the largest size, so it should fit.
|
||||
m_pFrameRGB->linesize[0] = getPixelFormatBytes(videoPixelMode) * m_desWidth;
|
||||
|
||||
AVFormatContext *pFormatCtx = (AVFormatContext*)m_pFormatCtx;
|
||||
AVCodecContext *pCodecCtx = (AVCodecContext*)m_pCodecCtx;
|
||||
AVFrame *pFrame = (AVFrame*)m_pFrame;
|
||||
AVFrame *pFrameRGB = (AVFrame*)m_pFrameRGB;
|
||||
if ((!m_pFrame)||(!m_pFrameRGB))
|
||||
return false;
|
||||
AVPacket packet;
|
||||
int frameFinished;
|
||||
bool bGetFrame = false;
|
||||
while(av_read_frame(pFormatCtx, &packet)>=0) {
|
||||
if(packet.stream_index == m_videoStream) {
|
||||
// Decode video frame
|
||||
avcodec_decode_video2(pCodecCtx, m_pFrame, &frameFinished, &packet);
|
||||
sws_scale(m_sws_ctx, m_pFrame->data, m_pFrame->linesize, 0,
|
||||
pCodecCtx->height, m_pFrameRGB->data, m_pFrameRGB->linesize);
|
||||
|
||||
if(frameFinished) {
|
||||
while (!bGetFrame) {
|
||||
bool dataEnd = av_read_frame(m_pFormatCtx, &packet) < 0;
|
||||
if (!dataEnd) {
|
||||
if (packet.pos != -1) {
|
||||
m_decodedPos = packet.pos;
|
||||
} else {
|
||||
// Packet doesn't know where it is in the file, let's try to approximate.
|
||||
m_decodedPos += packet.size;
|
||||
}
|
||||
}
|
||||
|
||||
// Even if we've read all frames, some may have been re-ordered frames at the end.
|
||||
// Still need to decode those, so keep calling avcodec_decode_video2().
|
||||
if (dataEnd || packet.stream_index == m_videoStream) {
|
||||
// avcodec_decode_video2() gives us the re-ordered frames with a NULL packet.
|
||||
if (dataEnd)
|
||||
av_free_packet(&packet);
|
||||
|
||||
int result = avcodec_decode_video2(m_pCodecCtx, m_pFrame, &frameFinished, &packet);
|
||||
if (frameFinished) {
|
||||
sws_scale(m_sws_ctx, m_pFrame->data, m_pFrame->linesize, 0,
|
||||
m_pCodecCtx->height, m_pFrameRGB->data, m_pFrameRGB->linesize);
|
||||
|
||||
int firstTimeStamp = bswap32(*(int*)(m_pdata + 86));
|
||||
m_videopts = pFrame->pkt_dts + pFrame->pkt_duration - firstTimeStamp;
|
||||
m_videopts = m_pFrame->pkt_dts + av_frame_get_pkt_duration(m_pFrame) - firstTimeStamp;
|
||||
bGetFrame = true;
|
||||
}
|
||||
if (result <= 0 && dataEnd) {
|
||||
m_isVideoEnd = !bGetFrame && m_readSize >= m_streamSize;
|
||||
if (m_isVideoEnd)
|
||||
m_decodedPos = m_readSize;
|
||||
break;
|
||||
}
|
||||
}
|
||||
av_free_packet(&packet);
|
||||
if (bGetFrame) break;
|
||||
}
|
||||
if (!bGetFrame && m_readSize >= m_streamSize)
|
||||
m_isVideoEnd = true;
|
||||
return bGetFrame;
|
||||
#else
|
||||
return true;
|
||||
@@ -541,6 +552,10 @@ static int getNextHeaderPosition(u8* audioStream, int curpos, int limit, int fra
|
||||
return -1;
|
||||
}
|
||||
|
||||
int MediaEngine::getBufferedSize() {
|
||||
return std::max(0, m_readSize - (int)m_decodedPos);
|
||||
}
|
||||
|
||||
int MediaEngine::getAudioSamples(u8* buffer) {
|
||||
if (!m_demux) {
|
||||
return 0;
|
||||
@@ -549,6 +564,7 @@ int MediaEngine::getAudioSamples(u8* buffer) {
|
||||
int audioSize = m_demux->getaudioStream(&audioStream);
|
||||
if (m_audioPos >= audioSize || !isHeader(audioStream, m_audioPos))
|
||||
{
|
||||
m_isAudioEnd = m_demux->getFilePosition() >= m_streamSize;
|
||||
return 0;
|
||||
}
|
||||
u8 headerCode1 = audioStream[2];
|
||||
@@ -576,6 +592,7 @@ int MediaEngine::getAudioSamples(u8* buffer) {
|
||||
} else
|
||||
m_audioPos = audioSize;
|
||||
m_audiopts += 4180;
|
||||
m_decodedPos += frameSize;
|
||||
return outbytes;
|
||||
}
|
||||
|
||||
|
||||
+12
-6
@@ -32,6 +32,9 @@
|
||||
|
||||
struct SwsContext;
|
||||
struct AVFrame;
|
||||
struct AVIOContext;
|
||||
struct AVFormatContext;
|
||||
struct AVCodecContext;
|
||||
|
||||
class MediaEngine
|
||||
{
|
||||
@@ -45,7 +48,7 @@ public:
|
||||
// Returns number of packets actually added.
|
||||
int addStreamData(u8* buffer, int addSize);
|
||||
int getRemainSize() { return m_streamSize - m_readSize;}
|
||||
int getBufferedSize() { return m_readSize - m_decodePos; }
|
||||
int getBufferedSize();
|
||||
|
||||
bool stepVideo(int videoPixelMode);
|
||||
bool writeVideoImage(u8* buffer, int frameWidth = 512, int videoPixelMode = 3);
|
||||
@@ -58,7 +61,8 @@ public:
|
||||
s64 getAudioTimeStamp();
|
||||
s64 getLastTimeStamp();
|
||||
|
||||
bool IsVideoEnd() { return m_isVideoEnd;}
|
||||
bool IsVideoEnd() { return m_isVideoEnd; }
|
||||
bool IsAudioEnd() { return m_isAudioEnd; }
|
||||
|
||||
void DoState(PointerWrap &p) {
|
||||
p.Do(m_streamSize);
|
||||
@@ -72,11 +76,11 @@ private:
|
||||
|
||||
public:
|
||||
|
||||
void *m_pFormatCtx;
|
||||
void *m_pCodecCtx;
|
||||
AVFormatContext *m_pFormatCtx;
|
||||
AVCodecContext *m_pCodecCtx;
|
||||
AVFrame *m_pFrame;
|
||||
AVFrame *m_pFrameRGB;
|
||||
void *m_pIOContext;
|
||||
AVIOContext *m_pIOContext;
|
||||
int m_videoStream;
|
||||
SwsContext *m_sws_ctx;
|
||||
int m_sws_fmt;
|
||||
@@ -86,7 +90,8 @@ public:
|
||||
int m_desHeight;
|
||||
int m_streamSize;
|
||||
int m_readSize;
|
||||
int m_decodePos;
|
||||
int m_decodeNextPos;
|
||||
s64 m_decodedPos;
|
||||
int m_bufSize;
|
||||
s64 m_videopts;
|
||||
u8* m_pdata;
|
||||
@@ -97,4 +102,5 @@ public:
|
||||
s64 m_audiopts;
|
||||
|
||||
bool m_isVideoEnd;
|
||||
bool m_isAudioEnd;
|
||||
};
|
||||
+2
-1
@@ -15,8 +15,9 @@ public:
|
||||
|
||||
void demux();
|
||||
|
||||
// return it's size
|
||||
// return its size
|
||||
int getaudioStream(u8 **audioStream);
|
||||
int getFilePosition() { return m_index; }
|
||||
private:
|
||||
struct PesHeader {
|
||||
long pts;
|
||||
|
||||
Reference in new issue
Block a user