h.265编码库x265实例

x265是一个开源的H.265编码库。API接口方面与x264很相像。本文介绍其在x86 linux及windows 7的编译方法,并给出实例。

一、编译

1、Linux平台

x265编译需要使用到yasm,到http://www.tortall.net/projects/yasm/releases/下载,最新版本为1.3.1。编译命令如下:

1
# ./configure;make;make install

x265库下载:https://bitbucket.org/multicoreware/x265/downloads,最新版本为1.7。
解压后,进入源码目录的build目录,选择linux。

1
2
# cd x265_1.7/build/linux
# ./make-Makefiles.bash

配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
BIN_INSTALL_DIR                  /home/latelee/bin/x265-1.7
CHECKED_BUILD                    OFF
CMAKE_BUILD_TYPE                 Release
CMAKE_INSTALL_PREFIX             /home/latelee/bin/x265-1.7
DETAILED_CU_STATS                OFF
ENABLE_AGGRESSIVE_CHECKS         OFF
ENABLE_ASSEMBLY                  ON
ENABLE_CLI                       ON
ENABLE_PIC                       OFF
ENABLE_PPA                       OFF
ENABLE_SHARED                    OFF  # 不要动态库
ENABLE_TESTS                     OFF
ENABLE_VTUNE                     OFF

ENABLE_SHARED: Build shared library
Press [enter] to edit option                                                  CMake Version 3.3.1
Press [c] to configure
Press [h] for help           Press [q] to quit without generating
Press [t] to toggle advanced mode (Currently Off)

按c配置,再按g保存并退出。

2、Windows平台

0、安装cmake的windows版本,地址:http://www.cmake.org/download/。在安装过程要记得添加cmake到PATH。
1、进入build目录,根据编译器版本选择不同的工程目录,比如64bit的VS2010,就进入vc10-x86_64目录。双击:build-all.bat。
2、之后出现配置界面时,点击configure,再点击generate,然后关闭窗口。其它不同做。
3、等待cmd窗口编译完成,完成后会自动关闭。
4、在Debug或Release目录找到h265编码器x265.exe,另外还有dll和lib文件。头文件要到源码中找。
注:编译Windows平台,纯粹是为了得到x265.exe文件。

二、实例

下面给出使用的示例。

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
162
163
164
165
/**
x265库编码要使用以下库
-lpthread -ldl

ffprobe信息:
Input #0, hevc, from 'test.h265':
Duration: N/A, bitrate: N/A
Stream #0:0: Video: hevc (Main), yuv420p(tv), 176x144, 25 fps, 25 tbr, 1200k
tbn, 25 tbc
*/

#include <stdio.h>
#include <stdlib.h>

#include "x265.h"

int x265_encode(const char* infile, int width, int height, int type, const char* outfile)
{
FILE *fp_src = NULL;
FILE *fp_dst = NULL;
unsigned int luma_size = 0;
unsigned int chroma_size = 0;
//int buff_size = 0;
char *buff = NULL;
uint32_t i_nal=0;
int i_frame=0;
int ret = 0;

x265_param param;
x265_nal *nal = NULL;
x265_encoder *handle = NULL;
x265_picture *pic_in = NULL;

int csp = type; // X265_CSP_I420;

fp_src = fopen(infile, "rb");
fp_dst = fopen(outfile, "wb");
if(fp_src==NULL || fp_dst==NULL)
{
perror("Error open yuv files:");
return -1;
}

x265_param_default(?m);
param.bRepeatHeaders = 1;//write sps,pps before keyframe
param.internalCsp = csp;
param.sourceWidth = width;
param.sourceHeight = height;
param.fpsNum = 25; // 帧率
param.fpsDenom = 1; // 帧率

handle = x265_encoder_open(?m);
if(handle == NULL)
{
printf("x265_encoder_open err\n");
goto out;
}

pic_in = x265_picture_alloc();
if (pic_in == NULL)
{
goto out;
}
x265_picture_init(?m, pic_in);

// Y分量大小
luma_size = param.sourceWidth * param.sourceHeight;
// 分量一帧YUV的空间
switch (csp)
{
case X265_CSP_I444:
buff = (char *)malloc(luma_size*3);
pic_in->planes[0] = buff;
pic_in->planes[1] = buff + luma_size;
pic_in->planes[2] = buff + luma_size*2;
pic_in->stride[0] = width;
pic_in->stride[1] = width;
pic_in->stride[2] = width;
break;
case X265_CSP_I420:
buff = (char *)malloc(luma_size*3/2);
pic_in->planes[0] = buff;
pic_in->planes[1] = buff + luma_size;
pic_in->planes[2] = buff + luma_size*5/4;
pic_in->stride[0] = width;
pic_in->stride[1] = width/2;
pic_in->stride[2] = width/2;
break;
default:
printf("Colorspace Not Support.\n");
goto out;
}

// 计算总帧数
fseek(fp_src, 0, SEEK_END);
switch(csp)
{
case X265_CSP_I444:
i_frame = ftell(fp_src) / (luma_size*3);
chroma_size = luma_size;
break;
case X265_CSP_I420:
i_frame = ftell(fp_src) / (luma_size*3/2);
chroma_size = luma_size / 4;
break;
default:
printf("Colorspace Not Support.\n");
return -1;
}
fseek(fp_src,0,SEEK_SET);
printf("framecnt: %d, y: %d u: %d\n", i_frame, luma_size, chroma_size);

for(int i=0; i < i_frame; i++)
{
switch(csp)
{
case X265_CSP_I444:
case X265_CSP_I420:
if (fread(pic_in->planes[0], 1, luma_size, fp_src) != luma_size)
break;
if (fread(pic_in->planes[1], 1, chroma_size, fp_src) != chroma_size)
break;
if (fread(pic_in->planes[2], 1, chroma_size, fp_src) != chroma_size)
break;
break;
default:
printf("Colorspace Not Support.\n");
goto out;
}

ret = x265_encoder_encode(handle, &nal, &i_nal, pic_in, NULL);
printf("encode frame: %5d framesize: %d nal: %d\n", i+1, ret, i_nal);
if (ret < 0)
{
printf("Error encode frame: %d.\n", i+1);
goto out;
}

for(uint32_t j = 0; j < i_nal; j++)
{
fwrite(nal[j].payload, 1, nal[j].sizeBytes, fp_dst);
}
}
// Flush Decoder
while((ret = x265_encoder_encode(handle, &nal, &i_nal, NULL, NULL)))
{
static int cnt = 1;
printf("flush frame: %d\n", cnt++);
for(uint32_t j=0; j < i_nal; j++)
{
fwrite(nal[j].payload, 1, nal[j].sizeBytes, fp_dst);
}
}

out:
x265_encoder_close(handle);
x265_picture_free(pic_in);
if (buff)
free(buff);

fclose(fp_src);
fclose(fp_dst);

return 0;
}

使用方法:

1
x265_encode("../src/suzie_qcif_176x144_yuv420p.yuv", 176, 144, 1, "test.h265");

Makefile见上一文章所述。

李迟 2015.9.14 中午