h264编码基础

h264编码基础h264 编码 h264 编码 10 年屹立 优秀的东西总是一直在发光 相对于 RGB 和 YUV 将数据成几百倍的压缩 初始化包含进来的数据格式 出去的数据格式 一般我们的数据如果为 BGR 格式 一个像素是有三个字节组成的 那么一副图像比如 720P 是有多大呢 3

大家好,我是讯享网,很高兴认识大家。

h264编码

    h264编码10年屹立,优秀的东西总是一直在发光,相对于RGB和YUV,将数据成几百倍的压缩。

    初始化包含进来的数据格式,出去的数据格式,一般我们的数据如果为BGR格式,一个像素是有三个字节组成的,那么一副图像比如720P是有多大呢,12807203 = 字节 ,一秒钟20帧数 ,那就是 *20 = 55,296,000 字节,也就是一秒钟52M字节,一分钟产生的图像数据为 3120M字节,也就是3G 左右,第一步为转码为YUV420P,这个格式为RGB的一半,经过h264 编码压缩,比如压缩为每秒钟比特率为3Mbit,一分钟也就是180Mbit,字节为22M多,也就是3G 和 22M byte的对比。压缩比到了 141:1。

    除了直接用libx264 编码,也可以用ffmpeg,实际上ffmpeg封装了libx264 libx265,甚至像intel Gpu qsv 和 cuda 硬件编码。这里使用软编码作为示例。

ffmpeg的作者之一Bellard 贝拉是一位极其著名优秀的软件工程师,qemu 的作者,同时也出品了quickjs,有兴趣可以看看他写的东西。


讯享网

1、编码初始化

int Encodeh264::Encoder_Init(AVCodecID codec_id, int in_w, int in_h, int fps, AVPixelFormat src_pix_fmt, int dst_w, int dst_h, AVPixelFormat dst_pix_fmt ) { 
    //<---------------找到编码器--------------------> _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; } //编码指定 _pCodecCtx->bit_rate = 200*1000; //这个需要传进来 _pCodecCtx->width = in_w; _pCodecCtx->height = in_h; _pCodecCtx->time_base.num = 1; _pCodecCtx->time_base.den = fps; _pCodecCtx->framerate.num = fps; _pCodecCtx->framerate.den = 1; _pCodecCtx->gop_size = fps; _pCodecCtx->max_b_frames = 0; //b帧指定为0 _pCodecCtx->pix_fmt = dst_pix_fmt; //线程指定 _pCodecCtx->thread_count = 2; av_opt_set(_pCodecCtx->priv_data, "preset", "ultrafast", 0); av_opt_set(_pCodecCtx->priv_data, "tune", "zerolatency", 0); av_opt_set(_pCodecCtx->priv_data, "preset", "ultrafast", 0); _pCodecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; //<--------------打开编码器--------------------> if (avcodec_open2(_pCodecCtx, _pCodec, NULL) < 0) { 
    printf("Could not open codec\n"); return -1; } //<---------------申请src数据封装格式--------------------> _AVFrame = av_frame_alloc(); if (!_AVFrame) { 
    printf("_AVFrame Could mot allocate video frame\n"); return -1; } _AVFrame->format = src_pix_fmt; _AVFrame->width = in_w; _AVFrame->height = in_h; int ret = av_frame_get_buffer(_AVFrame, 0); if (ret < 0) { 
    printf(" _AVFrame Could not allocate the video frame data\n"); return -1; } /* make sure the frame data is writable */ ret = av_frame_make_writable(_AVFrame); if (ret < 0) { 
    printf("_AVFrame set frame writable fail"); return -1; } _AVFrame->pts = 0; //<---------------申请YUV420P数据封装格式--------------------> _YUVFrame = av_frame_alloc(); if (!_YUVFrame) { 
    printf("_YUVFrame Could mot allocate video frame\n"); return -1; } _YUVFrame->format = dst_pix_fmt; _YUVFrame->width = dst_w; _YUVFrame->height = dst_h; ret = av_frame_get_buffer(_YUVFrame, 0); if (ret < 0) { 
    printf("_YUVFrame Could not allocate the video frame data\n"); return -1; } /* make sure the frame data is writable */ ret = av_frame_make_writable(_YUVFrame); if (ret < 0) { 
    printf("_YUVFrame set frame writable fail"); return -1; } _YUVFrame->pts = 0; //<---------------申请编码后数据包--------------------> _img_converT_ctx = sws_getContext(in_w, in_h, src_pix_fmt, dst_w, dst_h, dst_pix_fmt, SWS_BICUBIC, NULL, NULL, NULL); return 0; } 

讯享网

SWS_BICUBIC 这个参数是可以修改的,大变小和小变大可以选择不同的参数,ffmpeg这个开源库做得非常好,算法异常优秀,这个图像转换可以把能把比较模糊和扭曲的图像变得更符合常规,看起来更为自然。

讯享网 av_opt_set(_pCodecCtx->priv_data, "preset", "ultrafast", 0); av_opt_set(_pCodecCtx->priv_data, "tune", "zerolatency", 0); av_opt_set(_pCodecCtx->priv_data, "preset", "ultrafast", 0); 

这三句话是用来实时编码用的,可以修改,具体看ffmpeg的帮助。如果存文件,可以将编码从ultrafast 改成 slow等在码率不变的情况下更加清晰。图像的编码首先是把BGR24这种图像转成YUV420P,然后将YUV420P压缩成h26x

编码

AVPacket *Encodeh264::Encode_H264(uint8_t *data) { 
    sws_scale(_img_converT_ctx, &data, _AVFrame->linesize, 0, _AVFrame->height, _YUVFrame->data, _YUVFrame->linesize); int ret = avcodec_send_frame(_pCodecCtx, _YUVFrame); if (ret < 0) { 
    printf("Error sending a frame for encoding :%d \n", ret); return NULL; } else { 
    AVPacket *pkt = av_packet_alloc(); ret = avcodec_receive_packet(_pCodecCtx, pkt); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { 
    av_packet_free(&pkt); return NULL; } else if (ret < 0) { 
    av_packet_free(&pkt); printf("Error during encoding\n"); return NULL; } else { 
    //编码完成 _AVFrame->pts++; _YUVFrame->pts++; /*= v_framenum++;*/ return pkt; } } } 

调用

讯享网Encodeh264 v_264_obj; if (v_264_obj.Encoder_Init(AV_CODEC_ID_H264, CANVAS_WIDTH, CANVAS_HEIGHT, fps, AV_PIX_FMT_BGR24, CANVAS_WIDTH, CANVAS_HEIGHT, AV_PIX_FMT_YUV420P) != 0) { 
    std::cout << "Error ini h264 encoder" << std::endl; return -1; } AVPacket *pkt = v_264_obj.Encode_H264(v_srcImg.data); 

不要忘了释放pkt。

小讯
上一篇 2025-02-06 15:45
下一篇 2025-03-20 15:41

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/128062.html