文章目录

  • 前言
  • 一、x265 x86编译
  • 二、x265 编码YUV(YUYV)
    • 1. V4L2获取YUV
    • 2. YUV格式转换
    • 3. H265编码
  • 总结
  • 参考

前言

使用x265对uvc camera视频进行265编码


一、x265 x86编译

  1. 获取x265源码
    去libx265官网上下载源码,地址:http://ftp.videolan.org/pub/videolan/x265/x265_3.2.tar.gz
    tar xvf x265_3.2.tar.gz

  2. 编译libx265源码
    安装cmake,cmake-curses-gui
    sudo apt-get install cmake
    sudo apt install cmake-curses-gui
    cd x265_3.2/build/linux
    sh make-Makefiles.bash
    修改BIN_INSTALL_DIR、CMAKE_INSTALL_PREFIX
    修改BIN_INSTALL_DIR: /project/x265/x265_3.2/build/linux/__install/bin
    CMAKE_INSTALL_PREFIX: /project/x265/x265_3.2/build/linux
    make
    make install
    编译将libx265.a和include目录头文件准备好

二、x265 编码YUV(YUYV)

1. V4L2获取YUV

参考v4l2采集YUV数据

2. YUV格式转换

uvc camera输出yuv视频格式为YUYV(YUV422)格式,需将YUYV格式转换成YUV420格式再使用x265进行编码
YUYV->YUV420代码如下:

int YUV422ToYUV420(unsigned char *yuv422, unsigned char *yuv420, int width, int height)
{int y_size = width * height;int i, j, k=0;//Yfor (i = 0; i < y_size; i++){yuv420[i] = yuv422[i * 2];}//Ufor (i = 0; i < height; i++){if ((i % 2) != 0){continue;}   for (j = 0; j < (width / 2); j++){if ((4 * j + 1) > (2 * width))break;yuv420[y_size + k * 2 * width / 4 + j] = yuv422[i * 2 * width + 4 * j + 1];}k++;}//Vk = 0;for (i = 0; i < height; i++){if ((i % 2) == 0)continue;for (j = 0; j < (width / 2); j++){if ((4 * j + 3) > (2 * width))break;yuv420[y_size + y_size / 4 + k * 2 * width / 4 + j] = yuv422[i * 2 * width + 4 * j + 3];}k++;}return 0;
}

3. H265编码

编码流程:

  1. x265_param编码参数设置
  2. x265_encoder_open打开编码器
  3. 分配x265_picture用于编码源YUV数据
  4. 为x265_picture的planes分配存放Y,U,V数据内存空间
  5. 使用x265_encoder_headers编码vps, sps, pps(可省略)
  6. 使用x265_encoder_encode对YUV420数据进行编码
  7. 保存编码后265数据,验证编码结果

头文件

#include "x265.h"

数据结构定义

typedef struct x265_encoder_param
{char *buff;uint32_t i_nal;x265_nal *nal;x265_encoder *handler;x265_picture *picInput;x265_picture *picOutput;x265_param *param;
} X265_ENCODER_PARAM;typedef struct x265_sps_pps_vps
{int width;int height;int bitRate;int fps;unsigned char *sps;int sps_len;unsigned char *pps;int pps_len;unsigned char *vps;int vps_len;} X265_SPS_PPS_VPS;typedef struct x265_encoder
{pthread_t thdId;/*编码线程ID*/int thdRunFlag;uint32_t pixelformat;/*yuv视频格式*/int rc_mode;/*编码模式*/X265_ENCODER_PARAM encParam;/*参数*/X265_SPS_PPS_VPS spsPpsVps;/*vps pps sps*/int saveFile;FILE *fp;
} X265_ENCODER;
static X265_ENCODER gstX265Encoder;int X265EncodeParamInit(X265_ENCODER *encoder)
{int y_size = 0;int rc_mode = encoder->rc_mode;uint32_t pixel_format = encoder->pixelformat;X265_ENCODER_PARAM *x265 = &encoder->encParam;X265_SPS_PPS_VPS *sps_pps_vps = &encoder->spsPpsVps;x265->param = x265_param_alloc();x265_param_default(x265->param);x265_param_default_preset(x265->param, "ultrafast", "zerolatency");x265->param->frameNumThreads = 0;x265->param->sourceWidth = sps_pps_vps->width;x265->param->sourceHeight = sps_pps_vps->height;x265->param->totalFrames = 0;x265->param->bAnnexB = 1;x265->param->bRepeatHeaders = 1;x265->param->keyframeMin = 0;x265->param->keyframeMax = sps_pps_vps->fps * 2;x265->param->internalCsp = X265_CSP_I420;//muxing parametersx265->param->fpsDenom = 1;x265->param->fpsNum = sps_pps_vps->fps;#if 1//x265->param.rc.lookahead = 0;x265->param->rc.bitrate = sps_pps_vps->bitRate;x265->param->rc.rateControlMode = rc_mode;switch (rc_mode){case X265_RC_ABR://x265->param.rc.b_filler = 1;x265->param->rc.vbvMaxBitrate = sps_pps_vps->bitRate;x265->param->rc.vbvBufferSize = sps_pps_vps->bitRate;break;case X265_RC_CQP:x265->param->rc.qp = 32;break;case X265_RC_CRF:x265->param->rc.rfConstantMin = 25;x265->param->rc.rfConstantMax = 45;break;default:break;}
#endif//encoder openx265->handler = x265_encoder_open(x265->param);if (x265->handler == NULL){ERROR("x265_encoder_open ERROR");return -1;}x265->picInput = x265_picture_alloc();x265_picture_init(x265->param, x265->picInput);y_size = sps_pps_vps->width * sps_pps_vps->height;switch (pixel_format){case V4L2_PIX_FMT_YUV420:x265->buff =(char *)malloc(y_size * 3 / 2);x265->picInput->planes[0] = x265->buff;x265->picInput->planes[1] = x265->buff + y_size;x265->picInput->planes[2] = x265->buff + y_size * 5 / 4;x265->picInput->stride[0] = sps_pps_vps->width;x265->picInput->stride[1] = sps_pps_vps->width / 2;x265->picInput->stride[2] = sps_pps_vps->width / 2;break;default:break;}x265->picInput->pts = 0;x265->i_nal = 0;x265_encoder_headers(x265->handler, &x265->nal, &x265->i_nal);// get sps ppsif (x265->i_nal > 0){for (uint32_t i = 0; i < x265->i_nal; i++){if (x265->nal[i].type == NAL_UNIT_VPS){sps_pps_vps->vps = new unsigned char[x265->nal[i].sizeBytes];;sps_pps_vps->vps_len = x265->nal[i].sizeBytes;memcpy(sps_pps_vps->vps, x265->nal[i].payload, sps_pps_vps->vps_len);DEBUG("vps: %02x %02x %02x %02x %02x",sps_pps_vps->vps[0], sps_pps_vps->vps[1],sps_pps_vps->vps[2], sps_pps_vps->vps[3],sps_pps_vps->vps[4]);}else if (x265->nal[i].type == NAL_UNIT_SPS){sps_pps_vps->sps = new unsigned char[x265->nal[i].sizeBytes];sps_pps_vps->sps_len = x265->nal[i].sizeBytes;memcpy(sps_pps_vps->sps, x265->nal[i].payload, sps_pps_vps->sps_len);DEBUG("sps: %02x %02x %02x %02x %02x",sps_pps_vps->sps[0], sps_pps_vps->sps[1],sps_pps_vps->sps[2], sps_pps_vps->sps[3],sps_pps_vps->sps[4]);}else if (x265->nal[i].type == NAL_UNIT_PPS){sps_pps_vps->pps = new unsigned char[x265->nal[i].sizeBytes];;sps_pps_vps->pps_len = x265->nal[i].sizeBytes;memcpy(sps_pps_vps->pps, x265->nal[i].payload, sps_pps_vps->pps_len);DEBUG("pps: %02x %02x %02x %02x %02x",sps_pps_vps->pps[0], sps_pps_vps->pps[1],sps_pps_vps->pps[2], sps_pps_vps->pps[3],sps_pps_vps->pps[4]);}}}return 0;
}int X265EncodeYUV(X265_ENCODER *coder, unsigned char *yuvData)
{int num,i;unsigned char *data = yuvData;X265_ENCODER_PARAM *enc = &coder->encParam;X265_SPS_PPS_VPS *spsPpsVps = &coder->spsPpsVps;int y_size = spsPpsVps->width * spsPpsVps->height;switch (coder->pixelformat){case V4L2_PIX_FMT_YUV420:memcpy(enc->picInput->planes[0], data, y_size); // copy ymemcpy(enc->picInput->planes[1], data + y_size, y_size / 4);memcpy(enc->picInput->planes[2], data + y_size + y_size / 4, y_size / 4);break;default:break;}enc->i_nal = 0;x265_encoder_encode(enc->handler, &enc->nal, &enc->i_nal, enc->picInput, NULL);enc->picInput->pts++;for (uint32_t i = 0; i < enc->i_nal; i++){/* H265RtmpAcceptFrame(RING_BUFF_RTMP,enc->nal[i].type,enc->nal[i].payload,enc->nal[i].sizeBytes);*/if (coder->fp && coder->saveFile){fwrite(enc->nal[i].payload, enc->nal[i].sizeBytes, 1, coder->fp);fflush(coder->fp);}}return 0;
}void *X265EncodeThread(void *args)
{int ret = -1;int buffId = 0;YUV_RING_BUFFER *ringBuff = NULL;X265_ENCODER *encoder = NULL;YUV_NODE yuvNode;int yuv420Size = 0;int width = 0;int height = 0;unsigned char *yuv420 = NULL;char cName[128] = {0};snprintf(cName, sizeof(cName) - 1, "%s", "X265EncodeThread");prctl(PR_SET_NAME, (unsigned long)cName, 0, 0, 0);encoder = (X265_ENCODER *)args;if (!encoder){return NULL;}width = encoder->spsPpsVps.width;height = encoder->spsPpsVps.height;yuv420Size = width * height * 3 / 2;yuv420 = (unsigned char *)malloc(yuv420Size);if (yuv420 == NULL){ERROR("malloc yuv420 memory error!");goto __exit;}ringBuff = YUVRingBufferHandle(buffId);if (ringBuff == NULL){ERROR("YUVRingBufferHandle error");goto __exit;}ret = X265EncodeParamInit(encoder);if (0 != ret){ERROR("X264_EncodeInit error");goto __exit;}DEBUG("%s have been created, Id(%lu)", __func__, pthread_self());while (encoder->thdRunFlag){usleep(100);memset(&yuvNode, 0, sizeof(YUV_NODE));if (YUVRingBufferGet(ringBuff, &yuvNode) > 0){YUV422ToYUV420(yuvNode.yuvData, yuv420, width, height);X265EncodeYUV(encoder, yuv420);free(yuvNode.yuvData);yuvNode.yuvData = NULL;}}__exit:if (yuv420){free(yuv420);yuv420 = NULL;}DEBUG("%s will exit, Id(%lu)", __func__, pthread_self());return NULL;
}int X265EncodeInit(int width, int height)
{int ret = -1;X265_ENCODER *encoder = &gstX265Encoder;memset(encoder, 0, sizeof(X265_ENCODER));encoder->spsPpsVps.width = width;encoder->spsPpsVps.height = height;encoder->spsPpsVps.fps = 15; //real frame rateencoder->spsPpsVps.bitRate = 512;encoder->pixelformat = V4L2_PIX_FMT_YUV420;encoder->rc_mode = X265_RC_ABR;encoder->saveFile = 1;encoder->fp = fopen("test.h265", "wb");if (!encoder->fp){ERROR("open test.h265 error");}encoder->thdRunFlag = 1;ret = pthread_create(&encoder->thdId, NULL, X265EncodeThread, (void *)encoder);if (0 != ret){ERROR("Create X265EncodeThread error");return -1;}return 0;
}void X265EnocdeDestroy()
{X265_ENCODER *encoder = &gstX265Encoder;if (encoder->thdId > 0){encoder->thdRunFlag = 0;pthread_join(encoder->thdId, 0);encoder->thdId  = 0;}if (encoder->fp){fclose(encoder->fp);encoder->fp = NULL;}if (encoder->spsPpsVps.sps){free(encoder->spsPpsVps.sps);encoder->spsPpsVps.sps = NULL;}if (encoder->spsPpsVps.pps){free(encoder->spsPpsVps.pps);encoder->spsPpsVps.pps = NULL;}if (encoder->encParam.handler){x265_encoder_close(encoder->encParam.handler);encoder->encParam.handler = NULL;}if (encoder->encParam.param){x265_param_free(encoder->encParam.param);encoder->encParam.param = NULL;}if (encoder->encParam.picInput){x265_picture_free(encoder->encParam.picInput);encoder->encParam.picInput = NULL;}if (encoder->encParam.buff){free(encoder->encParam.buff);encoder->encParam.buff = NULL;}
}

总结

以上就是今天要讲的内容,本文仅仅简单介绍了x265的使用,而x265提供了大量能使我们快速便捷地处理数据的函数和方法。

参考

最简单的视频编码器:基于libx265(编码YUV为H.265)
在linux下源码编译x265

使用libx265对YUV进行h265编码相关推荐

  1. x265将yuv转h265(七)

    1.下载x265 code # git clone https://github.com/videolan/x265.git2.编译 # cd x265-master/build/linux # ./ ...

  2. H265编码等级以及图像的基础知识

    1. H265编码等级 H264编码profile & level控制 .H265编码初探 H265 profile H265 Profile & Level & Tier 介 ...

  3. H264和h265编码

    未压缩的码流:一秒钟码流大小:640x480x1.5x15x8=55296000 (是55MB)其中 1.5是yuv占用1.5倍,rgb是3倍,8是一个字节是八位bit H264的建议码流是500kp ...

  4. FFmpeg支持H265编码

    目前FFmpeg已经能够支持H265编码,我们可以通过configure添加 --enable-gpl --enable-libx265来配置. 这就需要我们的系统环境中已经安装了libx265,且其 ...

  5. ffmpeg使用h264、h265编码转换

    1.编译x264 git clone https://code.videolan.org/videolan/x264.git cd x264 ./configure --enable-shared - ...

  6. YUV通过MediaCodec编码H264

    Camear_MainActivity.java,主界面类 import android.app.Activity; import android.graphics.ImageFormat; impo ...

  7. 如何让ffplay或者ffmpeg支持H265编码的rtmp/http-flv 实时直播流

    很多初学者不知道ffplay或者ffmpeg是不支持flv封装的rtmp/http-flv流的,其原因是flv不支持H265编码payload的,因为当时制定flv封装协议的时候,H265还没出来,现 ...

  8. 流媒体播放器播放h264编码视频与h265编码视频哪个更清晰?

    h265编码是h264编码的升级版,h265目前在视频点播方面使用的更加普遍,而在视频直播方面,由于难以达到h265编码的解码速度,运用起来还是有些难度的,还需要看未来我们的流媒体技术的发展.那么既然 ...

  9. H265编码视频播放器EasyPlayer.JS控制台出现VideoJS:WARN警告信息是什么原因?

    H265编码的压倒性优势致使其不断在音视频行业完善发展,TSINGSEE青犀视频在不断开发H265播放器的不同使用方法,并且期望在未来运用于更多场景当中(h264编码视频与h265编码视频哪个更清晰) ...

  10. H265编码 SPS分析

    学习目标: H265编码分析 学习内容: H265出现的原因: 我们视频的分辨率 从 720p到1080p,而且电视的屏幕也越来越大 视频帧率从30帧 到60帧,再到120帧 这就会导致我们cpu在编 ...

最新文章

  1. 转载:CRONTAB格式,命令
  2. react 父子组件传值
  3. 腾讯初探AI+农业 获国际AI温室种植大赛亚军
  4. linux搭建springBoot环境,SpringBoot Linux服务化部署
  5. mysql 查找课程最高分_mysql 查询 学生id最高分的科目和日期
  6. 需要规范日志格式_Node开发的日志规范
  7. 还有 2 天,这场大咖云集的启智开发者大会即将启动!
  8. 【Oracle】Oracle通过表名查询触发器
  9. Kubernetes 一键部署实践
  10. 怎么解除极域课堂的控制
  11. c语言单片机仿真keil,如何在keil中仿真stm32单片机
  12. cloudera mysql_安装cloudera manager使用mysql作为元数据库
  13. 读取raw格式数据,OpenCV显示
  14. 加油吧红牛,功能饮料暴风来袭
  15. 使用高德SDK开发安卓地图应用软件
  16. Java继承(extends )
  17. Bloom Filter(布隆过滤器)的概念和原理(转)
  18. redis 哨兵模式踩坑
  19. Activiti介绍
  20. rtems 文件系统(15)-jffs2 研究(5)--测试打印记录mkdir,嵌套mkdir

热门文章

  1. JAVAFX的table样式修改
  2. QT qml ListView 分页/翻页
  3. 相似图片搜索原理和JAVA代码实现
  4. 清理FLASH_RECOVERY_AREA
  5. 转:socks5协议详解
  6. 《数字图像处理》空间滤波学习感悟1:空间滤波原理
  7. jmail设置端口php,PHP调用Jmail组件发送邮件
  8. linux 查看 文件夹代销,速达常见问题集
  9. 使用CAD手机看图软件打开图纸压缩包的方法技巧
  10. 推荐一款开源的加解密算法 --- XXTEA