ffmpeg编码后的.264数据长啥样

ffmpeg中利用avcodec_encode_video2函数将YUV数据编码成.264数据:

/**
 * 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.
 *
 * @param avctx     codec context
 * @param avpkt     output AVPacket.
 *                  The user can supply an output buffer by setting
 *                  avpkt->data and avpkt->size prior to calling the
 *                  function, but if the size of the user-provided data is not
 *                  large enough, encoding will fail. All other AVPacket fields
 *                  will be reset by the encoder using av_init_packet(). If
 *                  avpkt->data is NULL, the encoder will allocate it.
 *                  The encoder will set avpkt->size to the size of the
 *                  output packet. The returned data (if any) belongs to the
 *                  caller, he is responsible for freeing it.
 *
 *                  If this function fails or produces no output, avpkt will be
 *                  freed using av_free_packet() (i.e. avpkt->destruct will be
 *                  called to free the user supplied buffer).
 * @param[in] frame AVFrame containing the raw video data to be encoded.
 *                  May be NULL when flushing an encoder that has the
 *                  CODEC_CAP_DELAY capability set.
 * @param[out] got_packet_ptr This field is set to 1 by libavcodec if the
 *                            output packet is non-empty, and to 0 if it is
 *                            empty. If the function returns an error, the
 *                            packet can be assumed to be invalid, and the
 *                            value of got_packet_ptr is undefined and should
 *                            not be used.
 * @return          0 on success, negative error code on failure
 */
int avcodec_encode_video2(AVCodecContext *avctx, 
                          AVPacket *avpkt,
                          const AVFrame *frame, 
                          int *got_packet_ptr);
  • *AVCodecContext avctx
    用来保存编码参数等。
    参数初始化举例:
    pCodecCtx->bit_rate       = 1024*1024;
    pCodecCtx->width         = m_nScreenWidth;
    pCodecCtx->height        = m_nScreenHeight;
    pCodecCtx->time_base.num = 1;
    pCodecCtx->time_base.den = 25;
    pCodecCtx->gop_size      = 25;
    pCodecCtx->max_b_frames  = 1;
    pCodecCtx->pix_fmt       = AV_PIX_FMT_YUV420P;
  • *AVPacket avpkt
    输出的编码数据。

  • *const AVFrame frame
    该参数中包括输入的YUV数据等。

  • *int got_packet_ptr
    这个参数用于表明是否生成了编码数据。
    需要说明的是: 不是输入一个YUV数据,就会输出一个编码数据。
    编码器内部需要进行帧内预测、帧间预测等各种算法之后,才会输出一个编码数据。

调用实例:

    AVCodec        *pCodec    = NULL;
    AVCodecContext *pCodecCtx = NULL;
    AVFrame *pFrame = NULL;
    AVPacket pkt;

    AVCodecID codec_id = AV_CODEC_ID_H264;

    avcodec_register_all();

    pCodec = avcodec_find_encoder(codec_id);
    if (!pCodec) 
    {
        printf("Codec not found\n");
        return -1;
    }

    pCodecCtx = avcodec_alloc_context3(pCodec);
    if (!pCodecCtx) 
    {
        printf("Could not allocate video codec context\n");
        return -1;
    }

...
        pFrame->data[0] = m_pYUVBuffer;               // Y
        pFrame->data[1] = m_pYUVBuffer + m_nUOffset;  // U 
        pFrame->data[2] = m_pYUVBuffer + m_nVOffset;  // V

        av_init_packet(&pkt);
        pkt.data = NULL;    // packet data will be allocated by the encoder

        pFrame->pts= ...;

        /* encode the image */
        nRet = avcodec_encode_video2(pCodecCtx, &pkt, pFrame, &got_packet);
        if (nRet < 0) 
        {
            printf("Error encoding frame\n");
            return -1;
        }

        if (got_packet)  // 获取到编码数据
        {
            {
                printf("Succeed to encode frame: %5d\tsize:%5d\n", nVideoFrameCnt, pkt.size);

                av_free_packet(&pkt);
            }  
        }

        Sleep(40);
    }

调用avcodec_encode_video2输出的编码序列到底长啥样呢?

H.264编码序列 (ES码流)

(以上码流分析工具为:H264VideoESViewer)
可以看出序列的顺序:
SPS -> PPS -> SEI -> I帧 -> ...个P帧->SPS -> PPS -> SEI -> I帧 -> ...
另外需要注意的是:
SEI和I帧的start code是 0x00 0x00 0x01, 而其他的都是0x00 0x00 0x00 0x01

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容