mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-18 17:00:30 +02:00
fix pmp video quality issue.
We have no more decoding errors on imcomplete frame now.
This commit is contained in:
1 parent
4792b6dc3b
commit
edffdf2050
1 file changed
+151
-65
+151
-65
@@ -813,6 +813,88 @@ bool InitPmp(MpegContext * ctx){
|
||||
#endif
|
||||
}
|
||||
|
||||
class H264Frames{
|
||||
public:
|
||||
int size;
|
||||
u8* stream;
|
||||
|
||||
H264Frames() :size(0), stream(NULL){};
|
||||
|
||||
H264Frames(u8* str, int sz) :size(sz){
|
||||
stream = new u8[size];
|
||||
memcpy(stream, str, size);
|
||||
};
|
||||
|
||||
H264Frames(H264Frames *frame){
|
||||
size = frame->size;
|
||||
stream = new u8[size];
|
||||
memcpy(stream, frame->stream, size);
|
||||
};
|
||||
|
||||
~H264Frames(){
|
||||
size = 0;
|
||||
if (stream){
|
||||
delete[] stream;
|
||||
stream = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
void add(H264Frames *p){
|
||||
add(p->stream, p->size);
|
||||
};
|
||||
|
||||
void add(u8* str, int sz){
|
||||
int newsize = size + sz;
|
||||
auto newstream = new u8[newsize];
|
||||
// join two streams
|
||||
memcpy(newstream, stream, size);
|
||||
memcpy(newstream + size, str, sz);
|
||||
// delete old stream
|
||||
if (stream)
|
||||
delete[] stream;
|
||||
// replace with new stream
|
||||
stream = newstream;
|
||||
size = newsize;
|
||||
};
|
||||
|
||||
void remove(int pos){
|
||||
// remove stream from begining to pos
|
||||
if (pos == 0){
|
||||
// nothing to remove
|
||||
}
|
||||
else if (pos >= size){
|
||||
// we remove all
|
||||
size = 0;
|
||||
if (stream){
|
||||
delete[] stream;
|
||||
stream = NULL;
|
||||
}
|
||||
}
|
||||
else{
|
||||
// we remove the front part
|
||||
size -= pos;
|
||||
auto str = new u8[size];
|
||||
memcpy(str, stream + pos, size);
|
||||
delete[] stream;
|
||||
stream = str;
|
||||
}
|
||||
};
|
||||
#ifndef USE_FFMPEG
|
||||
#define FF_INPUT_BUFFER_PADDING_SIZE 16
|
||||
#endif
|
||||
void addpadding(){
|
||||
auto str = new u8[size + FF_INPUT_BUFFER_PADDING_SIZE];
|
||||
memcpy(str, stream, size);
|
||||
memset(str + size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
|
||||
size += FF_INPUT_BUFFER_PADDING_SIZE;
|
||||
delete[] stream;
|
||||
stream = str;
|
||||
}
|
||||
};
|
||||
|
||||
// collect pmp video frames
|
||||
static H264Frames *pmpframes = new H264Frames();
|
||||
|
||||
// decode pmp video to RGBA format
|
||||
bool decodePmpVideo(PSPPointer<SceMpegRingBuffer> ringbuffer, u32 pmpctxAddr){
|
||||
// the current video is pmp iff pmp_videoSource is a valide addresse
|
||||
@@ -836,75 +918,79 @@ bool decodePmpVideo(PSPPointer<SceMpegRingBuffer> ringbuffer, u32 pmpctxAddr){
|
||||
auto pFrameRGB = mediaengine->m_pFrameRGB;
|
||||
auto pCodecCtx = mediaengine->m_pCodecCtxs[0];
|
||||
|
||||
// decode all blocks
|
||||
// joint all blocks into H264Frames
|
||||
SceMpegLLI lli;
|
||||
for (int i = 0; i < pmp_nBlocks; i++){
|
||||
Memory::ReadStruct(pmp_videoSource, &lli);
|
||||
|
||||
// initialize packet
|
||||
AVPacket packet;
|
||||
av_new_packet(&packet, pCodecCtx->width*pCodecCtx->height);
|
||||
|
||||
// set packet to source block
|
||||
packet.data = Memory::GetPointer(lli.pSrc);
|
||||
packet.size = lli.iSize;
|
||||
|
||||
// reuse pFrame and pFrameRGB
|
||||
int got_picture = 0;
|
||||
av_frame_unref(pFrame);
|
||||
av_frame_unref(pFrameRGB);
|
||||
|
||||
// hook pFrameRGB output to buffer
|
||||
avpicture_fill((AVPicture *)pFrameRGB, mediaengine->m_buffer, pmp_want_pix_fmt, pCodecCtx->width, pCodecCtx->height);
|
||||
|
||||
// decode video frame
|
||||
auto len = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, &packet);
|
||||
DEBUG_LOG(ME, "got_picture %d", got_picture);
|
||||
if (got_picture){
|
||||
SwsContext *img_convert_ctx = NULL;
|
||||
img_convert_ctx = sws_getContext(
|
||||
pCodecCtx->width,
|
||||
pCodecCtx->height,
|
||||
pCodecCtx->pix_fmt,
|
||||
pCodecCtx->width,
|
||||
pCodecCtx->height,
|
||||
pmp_want_pix_fmt,
|
||||
SWS_BILINEAR,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
if (!img_convert_ctx) {
|
||||
ERROR_LOG(ME, "Cannot initialize sws conversion context");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert to RGBA
|
||||
int swsRet = sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data,
|
||||
pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
|
||||
if (swsRet < 0){
|
||||
ERROR_LOG(ME, "sws_scale: Error while converting %d", swsRet);
|
||||
return false;
|
||||
}
|
||||
|
||||
// update timestamp
|
||||
if (av_frame_get_best_effort_timestamp(mediaengine->m_pFrame) != AV_NOPTS_VALUE)
|
||||
mediaengine->m_videopts = av_frame_get_best_effort_timestamp(mediaengine->m_pFrame) + av_frame_get_pkt_duration(mediaengine->m_pFrame) - mediaengine->m_firstTimeStamp;
|
||||
else
|
||||
mediaengine->m_videopts += av_frame_get_pkt_duration(mediaengine->m_pFrame);
|
||||
|
||||
// push the decoded frame into pmp_queue
|
||||
pmp_queue.push_back(pFrameRGB);
|
||||
|
||||
// write frame into ppm file
|
||||
// SaveFrame(pNewFrameRGB, pCodecCtx->width, pCodecCtx->height);
|
||||
|
||||
// free some pointers
|
||||
sws_freeContext(img_convert_ctx);
|
||||
av_free_packet(&packet);
|
||||
|
||||
// get next block
|
||||
pmp_videoSource += sizeof(SceMpegLLI);
|
||||
}
|
||||
// add source block into pmpframes
|
||||
pmpframes->add(Memory::GetPointer(lli.pSrc), lli.iSize);
|
||||
// get next block
|
||||
pmp_videoSource += sizeof(SceMpegLLI);
|
||||
}
|
||||
|
||||
pmpframes->addpadding();
|
||||
|
||||
// initialize packet
|
||||
AVPacket packet;
|
||||
av_new_packet(&packet, pCodecCtx->width*pCodecCtx->height);
|
||||
|
||||
// set packet to source block
|
||||
packet.data = pmpframes->stream;
|
||||
packet.size = pmpframes->size;
|
||||
|
||||
// reuse pFrame and pFrameRGB
|
||||
int got_picture = 0;
|
||||
av_frame_unref(pFrame);
|
||||
av_frame_unref(pFrameRGB);
|
||||
|
||||
// hook pFrameRGB output to buffer
|
||||
avpicture_fill((AVPicture *)pFrameRGB, mediaengine->m_buffer, pmp_want_pix_fmt, pCodecCtx->width, pCodecCtx->height);
|
||||
|
||||
// decode video frame
|
||||
auto len = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, &packet);
|
||||
DEBUG_LOG(ME, "got_picture %d", got_picture);
|
||||
if (got_picture){
|
||||
SwsContext *img_convert_ctx = NULL;
|
||||
img_convert_ctx = sws_getContext(
|
||||
pCodecCtx->width,
|
||||
pCodecCtx->height,
|
||||
pCodecCtx->pix_fmt,
|
||||
pCodecCtx->width,
|
||||
pCodecCtx->height,
|
||||
pmp_want_pix_fmt,
|
||||
SWS_BILINEAR,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
if (!img_convert_ctx) {
|
||||
ERROR_LOG(ME, "Cannot initialize sws conversion context");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert to RGBA
|
||||
int swsRet = sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data,
|
||||
pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
|
||||
if (swsRet < 0){
|
||||
ERROR_LOG(ME, "sws_scale: Error while converting %d", swsRet);
|
||||
return false;
|
||||
}
|
||||
// free sws context
|
||||
sws_freeContext(img_convert_ctx);
|
||||
|
||||
// update timestamp
|
||||
if (av_frame_get_best_effort_timestamp(mediaengine->m_pFrame) != AV_NOPTS_VALUE)
|
||||
mediaengine->m_videopts = av_frame_get_best_effort_timestamp(mediaengine->m_pFrame) + av_frame_get_pkt_duration(mediaengine->m_pFrame) - mediaengine->m_firstTimeStamp;
|
||||
else
|
||||
mediaengine->m_videopts += av_frame_get_pkt_duration(mediaengine->m_pFrame);
|
||||
|
||||
// push the decoded frame into pmp_queue
|
||||
pmp_queue.push_back(pFrameRGB);
|
||||
|
||||
// write frame into ppm file
|
||||
// SaveFrame(pNewFrameRGB, pCodecCtx->width, pCodecCtx->height);
|
||||
}
|
||||
// free some pointers
|
||||
av_free_packet(&packet);
|
||||
pmpframes->~H264Frames();
|
||||
// must reset pmp_VideoSource address to zero after decoding.
|
||||
pmp_videoSource = 0;
|
||||
return true;
|
||||
|
||||
Reference in new issue
Block a user