h264编解码末尾丢帧问题原因和解决

作者: Don_ | 来源:发表于2016-04-04 18:09 被阅读1110次

    相关

    x264编码
    ffmpeg解码
    ffmpeg编码

    问题

    编解码h264流时,会发现末尾丢帧。以ffmpeg为例,调用如下接口
    int avcodec_encode_video2 ( AVCodecContext * avctx, AVPacket * avpkt, const AVFrame * frame, int * got_packet_ptr )

    Encode a frame of video.
    Takes input raw video data from frame and writes the next output packet, if available, to avpkt. The output packet does not necessarily contain data for the most recent frame, as encoders can delay and reorder input frames internally as needed.

    int avcodec_decode_video2 ( AVCodecContext * avctx, AVFrame * picture, int * got_picture_ptr, const AVPacket * avpkt )

    Decode the video frame of size avpkt->size from avpkt->data into picture.
    Some decoders may support multiple frames in a single AVPacket, such decoders would then just decode the first frame.

    官网api的提到:

    Takes input raw video data from frame and writes the next output packet, if available, to avpkt. The output packet does not necessarily contain data for the most recent frame, as encoders can delay and reorder input frames internally as needed.

    原因:

    拿编码来说,丢帧形式如下图:

    这被称为编码延迟。延迟原因又分为两种,一是计算延迟,二是缓存延迟。
    所以:
    h->frames.i_delay =
    param->i_sync_lookahead + // 前向考虑帧数
    max ( param->i_bframe, // B帧数量
    param->rc.i_lookahead) + // 码率控制前向考虑帧数
    另外编码时,通过设置参数将编码和获取的帧间隔缩小到0,参考“zerolatency"的tune值中参数的设置。

    解决

    编码延迟就需要在编码所有yuv数据之后必须flush。
    int vflush_encoder(AVFormatContext *fmt_ctx, unsigned int stream_index) { int ret = 0; int got_frame; AVPacket enc_pkt; if (!(fmt_ctx->streams[stream_index]->codec->codec->capabilities & CODEC_CAP_DELAY)) return 0; av_init_packet(&enc_pkt); while (IS_GOING) { enc_pkt.data = NULL; enc_pkt.size = 0; ret = avcodec_encode_video2(fmt_ctx->streams[stream_index]->codec, &enc_pkt, NULL, &got_frame); if (ret < 0) break; if (!got_frame) { ret = 0; break; } ret = av_write_frame(fmt_ctx, &enc_pkt); printf("Flush Encoder: Succeed to encode 1 frame!\tsize:%5d\n", enc_pkt.size); av_free_packet(&enc_pkt); if (ret < 0) break; } return ret; }

    解码同理,在av_read_frame到没有avpacket可以读取之后,要继续调用avcodec_encode_video2,将视频末尾帧解码出来。

    相关文章

      网友评论

      • 爱玩保龄球:我在调用的时候发现会崩溃,跟踪到ffmpeg 里面,发现崩溃在libx264.c 里面
        static int encode_nals(AVCodecContext *ctx, AVPacket *pkt,
        const x264_nal_t *nals, int nnal)
        {
        X264Context *x4 = ctx->priv_data;
        uint8_t *p;
        int i, size = x4->sei_size, ret;

        if (!nnal)
        return 0;

        for (i = 0; i < nnal; i++)
        size += nals[i].i_payload;

        if ((ret = ff_alloc_packet2(ctx, pkt, size, 0)) < 0)
        return ret;

        p = pkt->data;

        /* Write the SEI as part of the first frame. */
        if (x4->sei_size > 0 && nnal > 0) {
        if (x4->sei_size > size) {
        av_log(ctx, AV_LOG_ERROR, "Error: nal buffer is too small\n");
        return -1;
        }
        memcpy(p, x4->sei, x4->sei_size);
        p += x4->sei_size;
        x4->sei_size = 0;
        av_freep(&x4->sei);
        }

        for (i = 0; i < nnal; i++){
        memcpy(p, nals[i].p_payload, nals[i].i_payload);
        p += nals[i].i_payload;
        }

        return 1;
        }


        崩溃在 “ memcpy(p, nals[i].p_payload, nals[i].i_payload);” 这一行,您又遇到吗?

      本文标题:h264编解码末尾丢帧问题原因和解决

      本文链接:https://www.haomeiwen.com/subject/frhdlttx.html