A-A+
ffmpeg解码H264缺少帧的解决办法
最近用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 中午