源码编译

1
2
3
4
5
6
7
8
git clone https://code.videolan.org/videolan/x264.git

cd x264/source
mkdir build

cd build
cmake .. -DCMAKE_BUILD_TYPE=Debug -G "MinGW Makefiles"
make -j8

编译成功的话应该会产出三个文件,一个静态库 libx265.a,一个动态库 libx265.dll 以及该动态库的导入库 libx265.dll.a

新建编码demo项目

拷贝 libx265.ax265.hx265_config.h 至demo目录中

这里 encoder.cpp 还是用的雷霄骅–雷神的代码,致敬!https://blog.csdn.net/leixiaohua1020/article/details/42079101

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/**
* 最简单的基于X265的视频编码器
* Simplest X265 Encoder
*
* 雷霄骅 Lei Xiaohua
* leixiaohua1020@126.com
* 中国传媒大学/数字电视技术
* Communication University of China / Digital TV Technology
* http://blog.csdn.net/leixiaohua1020
*
* 本程序可以YUV格式的像素数据编码为H.265码流,是最简单的
* 基于libx265的视频编码器
*
* This software encode YUV data to H.265 bitstream.
* It's the simplest encoder example based on libx265.
*/
#include <stdio.h>
#include <stdlib.h>

#if defined ( __cplusplus)
extern "C"
{
#include "x265.h"
};
#else
#include "x265.h"
#endif

int main(int argc, char** argv){
int i,j;
FILE *fp_src=NULL;
FILE *fp_dst=NULL;
int y_size;
int buff_size;
char *buff=NULL;
int ret;
x265_nal *pNals=NULL;
uint32_t iNal=0;

x265_param* pParam=NULL;
x265_encoder* pHandle=NULL;
x265_picture *pPic_in=NULL;

//Encode 50 frame
//if set 0, encode all frame
int frame_num=50;
int csp=X265_CSP_I420;
int width=640,height=360;

fp_src=fopen("cuc_ieschool_640x360_yuv420p.yuv","rb");
//fp_src=fopen("../cuc_ieschool_640x360_yuv444p.yuv","rb");

fp_dst=fopen("cuc_ieschool.h265","wb");
//Check
if(fp_src==NULL||fp_dst==NULL){
return -1;
}

pParam=x265_param_alloc();
x265_param_default(pParam);
pParam->bRepeatHeaders=1;//write sps,pps before keyframe
pParam->internalCsp=csp;
pParam->sourceWidth=width;
pParam->sourceHeight=height;
pParam->fpsNum=25;
pParam->fpsDenom=1;
//Init
pHandle=x265_encoder_open(pParam);
if(pHandle==NULL){
printf("x265_encoder_open err\n");
return 0;
}
y_size = pParam->sourceWidth * pParam->sourceHeight;

pPic_in = x265_picture_alloc();
x265_picture_init(pParam,pPic_in);
switch(csp){
case X265_CSP_I444:{
buff=(char *)malloc(y_size*3);
pPic_in->planes[0]=buff;
pPic_in->planes[1]=buff+y_size;
pPic_in->planes[2]=buff+y_size*2;
pPic_in->stride[0]=width;
pPic_in->stride[1]=width;
pPic_in->stride[2]=width;
break;
}
case X265_CSP_I420:{
buff=(char *)malloc(y_size*3/2);
pPic_in->planes[0]=buff;
pPic_in->planes[1]=buff+y_size;
pPic_in->planes[2]=buff+y_size*5/4;
pPic_in->stride[0]=width;
pPic_in->stride[1]=width/2;
pPic_in->stride[2]=width/2;
break;
}
default:{
printf("Colorspace Not Support.\n");
return -1;
}
}

//detect frame number
if(frame_num==0){
fseek(fp_src,0,SEEK_END);
switch(csp){
case X265_CSP_I444:frame_num=ftell(fp_src)/(y_size*3);break;
case X265_CSP_I420:frame_num=ftell(fp_src)/(y_size*3/2);break;
default:printf("Colorspace Not Support.\n");return -1;
}
fseek(fp_src,0,SEEK_SET);
}

//Loop to Encode
for( i=0;i<frame_num;i++){
switch(csp){
case X265_CSP_I444:{
fread(pPic_in->planes[0],1,y_size,fp_src); //Y
fread(pPic_in->planes[1],1,y_size,fp_src); //U
fread(pPic_in->planes[2],1,y_size,fp_src); //V
break;}
case X265_CSP_I420:{
fread(pPic_in->planes[0],1,y_size,fp_src); //Y
fread(pPic_in->planes[1],1,y_size/4,fp_src); //U
fread(pPic_in->planes[2],1,y_size/4,fp_src); //V
break;}
default:{
printf("Colorspace Not Support.\n");
return -1;}
}

ret=x265_encoder_encode(pHandle,&pNals,&iNal,pPic_in,NULL);
printf("Succeed encode %5d frames\n",i);

for(j=0;j<iNal;j++){
fwrite(pNals[j].payload,1,pNals[j].sizeBytes,fp_dst);
}
}
//Flush Decoder
while(1){
ret=x265_encoder_encode(pHandle,&pNals,&iNal,NULL,NULL);
if(ret==0){
break;
}
printf("Flush 1 frame.\n");

for(j=0;j<iNal;j++){
fwrite(pNals[j].payload,1,pNals[j].sizeBytes,fp_dst);
}
}

x265_encoder_close(pHandle);
x265_picture_free(pPic_in);
x265_param_free(pParam);
free(buff);
fclose(fp_src);
fclose(fp_dst);

return 0;
}
1
2
3
4
5
6
7
8
9
10
11
cmake_minimum_required(VERSION 3.5)

project(encoder)

aux_source_directory(. SRC)

include_directories(.)
link_directories(.)

add_executable(encoder ${SRC})
target_link_libraries(encoder x265)

编译

1
2
3
4
mkdir build
cd build
cmake .. -G "MinGW Makefiles"
make

运行

编码参数

1. General Parameters

  • bRepeatHeaders:

pParam->bRepeatHeaders 是一个重要的参数,它决定了在每个关键帧(I 帧)之前是否重复输出视频参数集(VPS)、序列参数集(SPS)和图像参数集(PPS)头信息。这个选项可以影响编码后的流的兼容性和解码器的处理方式。

参数说明

  • bRepeatHeaders:
    • 类型: int
    • 默认值: false (0)
    • 功能: 如果设置为 1(true),则在每个关键帧前都会输出 VPS、SPS 和 PPS 头信息。这样可以确保即使在流的中间部分,有新的解码器接入,也能够正确解析视频流。

使用场景

  • 设置为 true(1):

    • 在流媒体应用中,尤其是实时流媒体传输时,设置为 true 可以提高流的兼容性,因为接收端可能在不同的时间点开始接收流。
    • 适合于需要支持随机访问的场景,比如视频点播。
  • 设置为 false(0):

    • 对于文件存储或后期处理,通常不需要在每个关键帧前重复输出头信息,这样可以减少比特流的大小。

在视频编码中,VPS、SPS 和 PPS 是三种重要的参数集,它们用于描述视频流的基本特性和编码设置。以下是对这三种参数集的分别介绍:

1. VPS (Video Parameter Set)

  • 定义: VPS 是视频参数集,包含了整个视频流的全局设置和信息。
  • 功能: VPS 提供了有关编码视频的整体配置,包括编码器的能力、视频的分辨率、帧率、色彩空间等信息。它是 H.265/HEVC 编码标准中的一部分。
  • 重要性: VPS 通常在视频流的开始部分出现,解码器需要解析 VPS 以了解如何正确解码后续的视频数据。

2. SPS (Sequence Parameter Set)

  • 定义: SPS 是序列参数集,描述了一个编码序列的特性。
  • 功能: SPS 包含了关于视频序列的具体信息,比如视频的分辨率、帧率、码率控制方式、色彩格式等。它可以用于多个图像(包括 I 帧和 P 帧)的编码。
  • 重要性: 通过 SPS,解码器可以理解如何处理整个视频序列中的帧,确保解码的正确性。

3. PPS (Picture Parameter Set)

  • 定义: PPS 是图像参数集,提供了关于单个图像的编码信息。
  • 功能: PPS 包含了特定于某一图像的编码设置,如滤波器类型、块大小、运动补偿等。每个 PPS 可以与多个图像(通常是 P 帧和 B 帧)关联。
  • 重要性: PPS 允许在同一视频序列中使用不同的编码参数,以便优化特定图像的压缩效果。

总结

  • VPS: 提供视频流的全局信息。
  • SPS: 描述整个编码序列的特性。
  • PPS: 针对单个图像的具体编码设置。

这三种参数集共同作用,确保视频编码和解码过程的高效和准确。

  • sourceWidth: 输入视频的宽度。
  • sourceHeight: 输入视频的高度。
  • fpsNum: 输入视频的帧率分子。
  • fpsDenom: 输入视频的帧率分母。

2. Bitrate Control

  • rcMethod: 选择码率控制方法,如 CQP(Constant QP)、ABR(Average Bitrate)或 VBR(Variable Bitrate)。
  • bitrate: 设置目标比特率(仅在 ABR/VBR 模式下有效)。
  • vbvMaxBitrate: 设置 VBV(Video Buffering Verifier)最大比特率。
  • vbvBufferSize: 设置 VBV 缓冲区大小。

3. Quality Control

  • qp: 设置固定的 QP 值(适用于 CQP 方法)。
  • maxCuSize: 设置最大编码单元(CU)的大小。
  • minCuSize: 设置最小编码单元(CU)的大小。

4. Rate Control and Quality

  • lookaheadDepth: 设置编码器的前瞻深度,影响编码器对未来帧的预测能力。
  • bEnableRQT: 启用或禁用 RQT(Recursive Quadtree)分割。

5. Deblocking and Filtering

  • bEnableDeblock: 启用或禁用去块滤波器。
  • deblockingFilterAlpha: 设置去块滤波器的 Alpha 参数。
  • deblockingFilterBeta: 设置去块滤波器的 Beta 参数。

6. Parallel Processing

  • numThreads: 设置编码时使用的线程数,影响编码速度。

7. Other Parameters

  • internalBitDepth: 设置内部处理的位深度,通常为 8、10 或 12。
  • bEnableSao: 启用或禁用 SAO(Sample Adaptive Offset)。