ffmpeg解码H264缺少帧的解决办法 | 迟思堂工作室
A-A+

ffmpeg解码H264缺少帧的解决办法

2015-12-12 12:18 业余研究, 流媒体学习 暂无评论 阅读 2,527 次

最近用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 中午



如果本文对阁下有帮助,不妨赞助笔者以输出更多好文章,谢谢!
donate



标签:

给我留言