最近用ffmpeg解码H264裸码流文件,发现解码总是少几帧。上网查了些资料,解决了。 当使用avcodec_decode_video2时,如果第三个参数的值为1,则表示完成一帧的解码,如果为0,表示没有解码完成。此时需要计算未解码的帧数,以便再次调用avcodec_decode_video2函数。如下getFrame函数,当解码成功一帧时返回,如果没有解码,则累加。另外实现getSkippedFrame函数,将之前未解码的数据再次解码。
代码如下:
int CH264Decoder::getFrame(unsigned char** yuvBuffer, unsigned char** rgbBuffer, int* size, int* width, int* height)
{
int got_picture = 0; // 找到帧标志
int len = 0;
AVPacket avpkt;
av_init_packet(&avpkt);
//int frame = 0;
// av_read_fram返回下一帧,发生错误或文件结束返回<0
while (av_read_frame(m_fmtctx, &avpkt) >= 0)
{
// 解码视频流
if (avpkt.stream_index == m_videoStream)
{
len = avcodec_decode_video2(m_avctx, m_picture, &got_picture, &avpkt);
if (len < 0)
{
debug("error while decoding frame.\n");
return -1;
}
if (got_picture)
{
m_picWidth = m_avctx->width;
m_picHeight = m_avctx->height;
// 传出原始数据指针,由于内部已经申请了,不用再开辟数据
if (yuvBuffer != NULL)
{
*yuvBuffer = m_picture->data[0];
if (size != NULL)
{
*size = len; // to check
}
}
if (rgbBuffer != NULL)
{
*rgbBuffer = convertToRgb();
if (size != NULL)
{
*size = m_picWidth * m_picHeight * 3; // 上面指定了rgb24,所以是w*h*3
}
}
//printf("frame fmt: %d\n", m_picture->format);
if (width != NULL)
{
*width = m_picWidth;
}
if (height != NULL)
{
*height = m_picHeight;
}
//printf("bit_rate: %d width: %d height:%d\n", m_avctx->bit_rate, m_avctx->width, m_avctx->height);
return 1;
} // end of got picture
else
{
m_skippedFrame++;
//debug("skipped count: %d\n", m_skippedFrame);
}
} // end of video stream
av_free_packet(&avpkt);
} // end of read frame
return 0;
}
int CH264Decoder::getSkippedFrame(unsigned char** yuvBuffer, unsigned char** rgbBuffer, int* size, int* width, int* height)
{
int got_picture = 0; // 找到帧标志
int len = 0;
AVPacket avpkt;
av_init_packet(&avpkt);
// 是否还有缓存的帧
while (m_skippedFrame-- > 0)
{
// 解码视频流
len = avcodec_decode_video2(m_avctx, m_picture, &got_picture, &avpkt);
if (len < 0)
{
debug("error while decoding frame.\n");
return -1;
}
if (got_picture)
{
// 传出原始数据指针,由于内部已经申请了,不用再开辟数据
if (yuvBuffer != NULL)
{
*yuvBuffer = m_picture->data[0];
}
if (rgbBuffer != NULL)
{
*rgbBuffer = convertToRgb();
}
//printf("frame fmt: %d\n", m_picture->format);
if (size != NULL)
{
*size = len;
}
m_picWidth = m_avctx->width;
m_picHeight = m_avctx->height;
if (width != NULL)
{
*width = m_picWidth;
}
if (height != NULL)
{
*height = m_picHeight;
}
return 1;
} // end of got picture
av_free_packet(&avpkt);
} // end of read frame
return 0;
}
李迟 2015.12.12 中午