ffmpeg解码H264缺少帧的解决办法
2016-11-20 23:07
281 查看
最近用ffmpeg解码H264裸码流文件,发现解码总是少几帧。上网查了些资料,解决了。
当使用avcodec_decode_video2时,如果第三个参数的值为1,则表示完成一帧的解码,如果为0,表示没有解码完成。此时需要计算未解码的帧数,以便再次调用avcodec_decode_video2函数。如下getFrame函数,当解码成功一帧时返回,如果没有解码,则累加。另外实现getSkippedFrame函数,将之前未解码的数据再次解码。
代码如下:
[cpp] view
plain copy
print?
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;
}
上面的函数已经统计了缓存起来的帧总数,下面根据m_skippedFrame的值再调用avcodec_decode_video2解码。
[cpp] view
plain copy
print?
int CH264Decoder::getSkippedFrame(unsigned char** yuvBuffer, unsigned char** rgbBuffer, int* size, int* width, int* height)
{
int got_picture = 0; // 找到帧标志
int len = 0;
AVPacket avpkt;
memset(&avpkt, '\0', sizeof(AVPacket));
av_init_packet(&avpkt);
// 是否还有缓存的帧
while (m_skippedFrame-- > 0)
{
// 注:avpkt要清空data和size,否则无法解码
avpkt.data = NULL;
avpkt.size = 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;
}
//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
av_packet_unref(&avpkt);
} // end of read frame
return 0;
}
2016.4.23 周日的补充:
注意,在调用avcodec_decode_video2对缓存的帧解码时,一定要将avpkt.data置为NULL,并将avpkt.size置为0,否则会解码不成功。在调用av_init_packet前,也要手工对AVPacket结构体进行清零操作。直到最后在VS环境使用该类时才发现这个问题。在解码函数avcodec_decode_video2注释中有如下说明:
* @note Codecs which have the CODEC_CAP_DELAY capability set have a delay
* between input and output, these need to be fed with avpkt->data=NULL,
* avpkt->size=0 at the end to return the remaining frames.
李迟 2015.12.12 中午
当使用avcodec_decode_video2时,如果第三个参数的值为1,则表示完成一帧的解码,如果为0,表示没有解码完成。此时需要计算未解码的帧数,以便再次调用avcodec_decode_video2函数。如下getFrame函数,当解码成功一帧时返回,如果没有解码,则累加。另外实现getSkippedFrame函数,将之前未解码的数据再次解码。
代码如下:
[cpp] view
plain copy
print?
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;
}
上面的函数已经统计了缓存起来的帧总数,下面根据m_skippedFrame的值再调用avcodec_decode_video2解码。
[cpp] view
plain copy
print?
int CH264Decoder::getSkippedFrame(unsigned char** yuvBuffer, unsigned char** rgbBuffer, int* size, int* width, int* height)
{
int got_picture = 0; // 找到帧标志
int len = 0;
AVPacket avpkt;
memset(&avpkt, '\0', sizeof(AVPacket));
av_init_packet(&avpkt);
// 是否还有缓存的帧
while (m_skippedFrame-- > 0)
{
// 注:avpkt要清空data和size,否则无法解码
avpkt.data = NULL;
avpkt.size = 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;
}
//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
av_packet_unref(&avpkt);
} // end of read frame
return 0;
}
2016.4.23 周日的补充:
注意,在调用avcodec_decode_video2对缓存的帧解码时,一定要将avpkt.data置为NULL,并将avpkt.size置为0,否则会解码不成功。在调用av_init_packet前,也要手工对AVPacket结构体进行清零操作。直到最后在VS环境使用该类时才发现这个问题。在解码函数avcodec_decode_video2注释中有如下说明:
* @note Codecs which have the CODEC_CAP_DELAY capability set have a delay
* between input and output, these need to be fed with avpkt->data=NULL,
* avpkt->size=0 at the end to return the remaining frames.
李迟 2015.12.12 中午
相关文章推荐
- ffmpeg解码H264缺少帧的解决办法
- javaweb中ffmpeg视频转码h264出现卡住不执行的解决办法(看到最后面就是答案了)
- Ubuntu7.04使用totem-xine,安装libxine1-ffmpeg后,rm文件播放无声问题的解决办法
- Ubuntu7.04使用totem-xine,安装libxine1-ffmpeg后,rm文件播放无声问题的解决办法
- Asp 出现Microsoft JScript 编译错误 (0x800A03EC) 缺少 ';'解决办法
- Ubuntu7.04使用totem-xine,安装libxine1-ffmpeg后,rm文件播放无声问题的解决办法
- Ubuntu7.04使用totem-xine,安装libxine1-ffmpeg后,rm文件播放无声问题的解决办法
- Ubuntu7.04使用totem-xine,安装libxine1-ffmpeg后,rm文件播放无声问题的解决办法
- javascript中escape编码,后台解码出错的解决办法。
- _doPostBack缺少对象解决办法
- Ubuntu7.04使用totem-xine,安装libxine1-ffmpeg后,rm文件播放无声问题的解决办法
- 用FFmpeg从视频截取任意一帧图片的解决办法~
- linux下用c语言调用mysql缺少mysql.h的解决办法
- Asp 出现Microsoft JScript 编译错误 (0x800A03EC) 缺少 ';'解决办法
- ffmpeg+x264 移植到s3c2410遇到的问题及解决办法
- 动易生成栏目时报错“您的栏目页模板有误,缺少小类模板!”,一个解决办法
- 终于找到了在asp.net使用popcalendar.js 日历时候提示出现"缺少对象“的解决办法。
- 读取XML空节点出现缺少对象错误的解决办法
- Ubuntu7.04使用totem-xine,安装libxine1-ffmpeg后,rm文件播放无声问题的解决办法
- 用FFmpeg从视频截取任意一帧图片的解决办法