fix pmp video quality issue.

We have no more decoding errors on imcomplete frame now.
This commit is contained in:
kaienfr committed 2014-04-07 18:26:52 +02:00
1 parent 4792b6dc3b
commit edffdf2050
1 file changed
+151 -65
+151 -65
View File
@@ -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;