问题描述
在网上下载了x265的源码,编译并安装了相关的include和lib文件,然后在雷神那里下载了一个最小x265应用的源码:https://blog.csdn.net/leixiaohua1020/article/details/42079101
下载下来后用g++ simplest_x265_encoder.cpp
编译,报下面的错误,当然这很容易看出来是没有加链接库的原因。
root@localhost:~/simplest_encoder/simplest_x265_encoder# g++ simplest_x265_encoder.cpp
/usr/bin/ld: /tmp/ccWHthlJ.o: in function `main':
simplest_x265_encoder.cpp:(.text+0xb4): undefined reference to `x265_param_alloc'
/usr/bin/ld: simplest_x265_encoder.cpp:(.text+0xc0): undefined reference to `x265_param_default'
/usr/bin/ld: simplest_x265_encoder.cpp:(.text+0x110): undefined reference to `x265_encoder_open_32'
/usr/bin/ld: simplest_x265_encoder.cpp:(.text+0x150): undefined reference to `x265_picture_alloc'
/usr/bin/ld: simplest_x265_encoder.cpp:(.text+0x160): undefined reference to `x265_picture_init'
/usr/bin/ld: simplest_x265_encoder.cpp:(.text+0x4cc): undefined reference to `x265_encoder_encode'
/usr/bin/ld: simplest_x265_encoder.cpp:(.text+0x574): undefined reference to `x265_encoder_encode'
/usr/bin/ld: simplest_x265_encoder.cpp:(.text+0x600): undefined reference to `x265_encoder_close'
/usr/bin/ld: simplest_x265_encoder.cpp:(.text+0x608): undefined reference to `x265_picture_free'
/usr/bin/ld: simplest_x265_encoder.cpp:(.text+0x610): undefined reference to `x265_param_free'
collect2: error: ld returned 1 exit status
当我加上链接库编译g++ simplest_x265_encoder.cpp -lx265
出现如下结果:
root@localhost:~/simplest_encoder/simplest_x265_encoder# g++ simplest_x265_encoder.cpp -lx265
/usr/bin/ld: /tmp/ccF8r4R9.o: in function `main':
simplest_x265_encoder.cpp:(.text+0x110): undefined reference to `x265_encoder_open_32'
collect2: error: ld returned 1 exit status
发现问题
我去雷神的源码里找了半天,所有的include文件都找了都没有x265_encoder_open_32
这个东西,踌躇了很久。当时唯一确定的是雷神的代码是没问题的,因为我在虚拟机上编译都能通过,放到嵌入式板子里不能通过。于是就再去看看源码,发现一个奇怪的地方,在编译生成的/usr/local/include/x265.
h文件里面:
/* Force a link error in the case of linking against an incompatible API version.
* Glue #defines exist to force correct macro expansion; the final output of the macro
* is x265_encoder_open_##X265_BUILD (for purposes of dlopen). */
#define x265_encoder_glue1(x, y) x ## y
#define x265_encoder_glue2(x, y) x265_encoder_glue1(x, y)
#define x265_encoder_open x265_encoder_glue2(x265_encoder_open_, X265_BUILD)
其中的x265_encoder_glue2(x265_encoder_open_, X265_BUILD)
这句就是造成undefined reference to x265_encoder_open_32'
的关键,因为在你编译后的/usr/local/include/x265_config.h
文件下有这个定义:
/* Incremented each time public API is changed, X265_BUILD is used as
* the shared library SONAME on platforms which support it. It also
* prevents linking against a different version of the static lib */
#define X265_BUILD 199
而且在每个平台下编译后的X265_BUILD
结果都不一样,因此不能简单的去别的地方复制。
解决问题
所以最终的办法是将雷神源码里的x265_config.h
文件删除。再编译就能通过啦:
g++ simplest_x265_encoder.cpp -lx265
然后看下编译出来的程序链接库信息:
root@localhost:~/simplest_encoder/simplest_x265_encoder# ldd a.out
linux-vdso.so.1 (0x0000007f8cd6c000)
libx265.so.201 => not found
libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x0000007f8cbb4000)
/lib/ld-linux-aarch64.so.1 (0x0000007f8cd3c000)
root@localhost:~/simplest_encoder/simplest_x265_encoder#
这里面说我的libx265.so
找不到,那是因为/usr/local/lib
不在查找路径下,所以将这个路径加进去:
vim /etc/ld.so.conf.d/usr-libs.conf # 在这个文件下写 /usr/local/lib
ldconfig # 使配置生效
最后就可以运行啦!!!!!!
RK3399运行结果:
x265 [info]: frame I: 1, Avg QP:28.32 kb/s: 375.60
x265 [info]: frame P: 13, Avg QP:28.88 kb/s: 546.22
x265 [info]: frame B: 36, Avg QP:34.70 kb/s: 94.83
x265 [info]: Weighted P-Frames: Y:0.0% UV:0.0%
x265 [info]: consecutive B-frames: 7.1% 7.1% 28.6% 35.7% 21.4%
我在rk3399上运行的编码帧率只有9帧左右,在虚拟机上编码的帧率有29帧左右。相差了3倍,而且这只是640*360的分辨率而已。由此可见H.265在实时编码的速度上还是太慢。
问题反思
#define x265_encoder_glue1(x, y) x ## y
#define x265_encoder_glue2(x, y) x265_encoder_glue1(x, y)
#define x265_encoder_open x265_encoder_glue2(x265_encoder_open_, X265_BUILD)
这三句代码是怎样将x265_encoder_open_, X265_BUILD
结合在一块的呢?
主要就是靠#define x265_encoder_glue1(x, y) x ## y
吧。
在c++
和 ANSI/ISO C
中: #
和 ##
预处理运算符都是可用的。#
运算符会把 replacement-text
令牌转换为用引号引起来的字符串。
#include <iostream>
using namespace std;
#define MKSTR( x ) #x
int main ()
{
cout << MKSTR(HELLO C++) << endl;
return 0;
}
上面的运行结果是:HELLO C++
。
原理大概就是MKSTR(HELLO C++
相当于"HELLO C++"
。
另外:##
运算符用于连接两个令牌。下面是一个实例:
#define CONCAT( x, y ) x ## y