一、环境准备
- 安装交叉编译工具链
根据目标ARM架构选择对应工具链(如arm-linux-gnueabihf-):# Ubuntu/Debian系统 sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf# 验证安装 arm-linux-gnueabihf-gcc --version
或者手动指定交叉工具链
export PATH=$PATH:/home/user/Desktop/output/host/bin
- 创建工作目录
mkdir x264 && cd x264
二、下载x264源码
cd x264
git clone https://code.videolan.org/videolan/x264.git
三、配置编译参数
通过./configure
指定交叉编译参数:
# 禁止生成共享动态库
./configure --cross-prefix=arm-linux- --host=arm-linux --enable-static --disable-shared --disable-asm --prefix=$(pwd)/output
./configure \--cross-prefix=arm-linux-gnueabihf- \--host=arm-linux \--enable-static \--disable-shared \--disable-asm \--prefix=$(pwd)/output
# 允许生成共享动态库
./configure \--cross-prefix=arm-linux-gnueabihf- \--host=arm-linux \--enable-static \--enable-shared \--disable-asm \--prefix=$(pwd)/output
参数说明:
--cross-prefix
:交叉编译器前缀--host
:目标平台--disable-asm
:禁用ARM汇编优化(部分架构可能不兼容)--prefix
:指定安装路径
四、编译与安装
make -j$(nproc) # 并行编译
make install # 安装到output目录
五、验证编译结果
编译成功后,在output
目录下生成:
bin/x264
:可执行文件lib/libx264.a
:静态库include/x264.h
:头文件
六、编写测试程序
使用 x264 API 将 YUV 视频帧编码为 H.264 数据流。
创建test_x264.c
测试代码:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <x264.h>#define WIDTH 320//640
#define HEIGHT 240//480
#define FPS 30
#define TOTAL_FRAMES 10//100 // 编码帧数int main() {// 1. 初始化参数结构体x264_param_t param;if (x264_param_default_preset(¶m, "medium", NULL) < 0) {fprintf(stderr, "Failed to apply preset\n");return -1;}// 2. 设置编码参数param.i_width = WIDTH;param.i_height = HEIGHT;param.i_fps_num = FPS;param.i_fps_den = 1;param.i_keyint_max = FPS * 2; // 关键帧间隔(2秒)param.b_vfr_input = 0;param.b_repeat_headers = 1; // 在每个关键帧前添加SPS/PPSparam.b_annexb = 1; // 输出annex-b格式// 3. 应用配置if (x264_param_apply_profile(¶m, "high") < 0) {fprintf(stderr, "Failed to apply profile\n");return -1;}// 4. 打开编码器x264_t *encoder = x264_encoder_open(¶m);if (!encoder) {fprintf(stderr, "Failed to open encoder\n");return -1;}// 5. 创建输入图像x264_picture_t pic_in, pic_out;x264_picture_alloc(&pic_in, param.i_csp, param.i_width, param.i_height);x264_picture_init(&pic_out);// 6. 准备输出文件FILE *outfile = fopen("test.264", "wb");if (!outfile) {perror("Failed to open output file");return -1;}printf("Start encoding %dx%d video at %d fps...\n", WIDTH, HEIGHT, FPS);// 7. 编码循环for (int i = 0; i < TOTAL_FRAMES; i++) {// 生成测试图像(渐变彩条)uint8_t *y = pic_in.img.plane[0];uint8_t *u = pic_in.img.plane[1];uint8_t *v = pic_in.img.plane[2];// Y分量(亮度)for (int h = 0; h < HEIGHT; h++) {for (int w = 0; w < WIDTH; w++) {y[h * pic_in.img.i_stride[0] + w] = w * 255 / WIDTH;}}// UV分量(色度)for (int h = 0; h < HEIGHT/2; h++) {for (int w = 0; w < WIDTH/2; w++) {u[h * pic_in.img.i_stride[1] + w] = 128 + (h * 128 / (HEIGHT/2));v[h * pic_in.img.i_stride[2] + w] = 128 + (w * 128 / (WIDTH/2));}}pic_in.i_pts = i; // 设置时间戳// 执行编码x264_nal_t *nals;int i_nal;int frame_size = x264_encoder_encode(encoder, &nals, &i_nal, &pic_in, &pic_out);if (frame_size < 0) {fprintf(stderr, "Encoding error at frame %d\n", i);break;}// 8. 写入输出文件for (int j = 0; j < i_nal; j++) {fwrite(nals[j].p_payload, 1, nals[j].i_payload, outfile);}if (frame_size > 0) {printf("Frame %4d: size=%6d bytes, type=%s, qp=%d\n", i, frame_size,(pic_out.i_type == X264_TYPE_IDR) ? "IDR" :(pic_out.i_type == X264_TYPE_I) ? "I" :(pic_out.i_type == X264_TYPE_P) ? "P" : "B",pic_out.i_qpplus1 - 1);}}// 9. 刷新编码器(处理延迟帧)while (1) {x264_nal_t *nals;int i_nal;int frame_size = x264_encoder_encode(encoder, &nals, &i_nal, NULL, &pic_out);if (frame_size <= 0) break;for (int j = 0; j < i_nal; j++) {fwrite(nals[j].p_payload, 1, nals[j].i_payload, outfile);}printf("Flush frame: size=%d bytes\n", frame_size);}// 10. 清理资源x264_encoder_close(encoder);x264_picture_clean(&pic_in);fclose(outfile);printf("\nEncoding completed. Output saved to test.264\n");printf("You can verify with:\n");printf(" ffplay test.264\n");printf(" ffprobe test.264\n");return 0;
}
-
参数配置:
x264_param_default_preset()
:应用预设配置(medium/fast/placebo等)x264_param_apply_profile()
:设置编码规格(baseline/main/high)
-
图像处理:
x264_picture_alloc()
:分配YUV420P图像内存- 手动生成渐变彩条测试图案(实际应用应从文件/摄像头获取)
-
编码核心:
x264_encoder_encode()
:执行帧编码- 输出NAL单元包含:SPS/PPS/IDR帧/P帧等
-
输出处理:
- 写入annex-b格式的原始H.264流
- 最后刷新编码器获取延迟帧
其它功能
- 从文件读取YUV:
FILE *yuv_file = fopen("input.yuv", "rb");
fread(pic_in.img.plane[0], 1, WIDTH*HEIGHT, yuv_file); // Y
fread(pic_in.img.plane[1], 1, WIDTH*HEIGHT/4, yuv_file); // U
fread(pic_in.img.plane[2], 1, WIDTH*HEIGHT/4, yuv_file); // V
- 调整编码参数:
// 提高编码质量
param.rc.i_rc_method = X264_RC_CRF;
param.rc.f_rf_constant = 22.0; // 0-51, 值越小质量越好// 启用B帧
param.i_bframe = 3;// 开启心理视觉优化
param.analyse.b_psy = 1;
- 实时编码统计:
x264_stats_t stats;
param.b_stats = 1;
x264_encoder_encode(encoder, &nals, &i_nal, &pic_in, &pic_out);
x264_encoder_get_stats(encoder, &stats, 0);
printf("PSNR: Y=%.2f dB, U=%.2f dB, V=%.2f dB\n", stats.f_psnr_avg[0], stats.f_psnr_avg[1], stats.f_psnr_avg[2]);
七、交叉编译测试程序
arm-linux-gnueabihf-gcc test_x264.c -o test_x264 \-I$(pwd)/output/include \-L$(pwd)/output/lib \-lx264 -lpthread -lm
八、部署与测试
- 复制文件到ARM设备
scp test_x264 root@192.168.1.100:/tmp/ # 替换为实际IP scp output/lib/libx264.so.* root@192.168.1.100:/lib/
将输出的/lib目录下的库文件
拷贝到开发板的/lib/目录下
将输出的/bin目录下的可执行文件
拷贝到开发板的/bin/目录下
文件需要赋权限
测试指令
-
在ARM设备上运行
# 设置库路径 export LD_LIBRARY_PATH=/lib:$LD_LIBRARY_PATH# 执行测试 /tmp/test_x264
-
输出
# 使用FFmpeg播放生成的视频
ffplay test.264
# 查看视频信息
ffprobe test.264
# 检查编码统计
ffmpeg -i test.264 -f null -
常见问题及解决方案
-
编译报错:
undefined reference to 'sqrt'
解决:在链接命令中添加-lm
(数学库)。 -
运行报错:
libx264.so.x: cannot open shared object file
解决:确保库文件已复制到ARM设备的/lib
目录,并执行ldconfig
刷新缓存。 -
性能优化
-
若ARM设备支持NEON指令集,可启用汇编优化:
./configure --enable-neon # 根据架构选择--enable-*选项
./configure --enable-shared --prefix=/home/ubuntu/x264_install/ --host=arm-linux-gnueabihf --disable-asm--prefix=/home/ubuntu//x264_install/ :指定编译后存放路径--host=arm-linux-gnueabihf :指定交叉编译链,用户需要修改为自己的交叉编译器--enable-shared :允许共享--disable-asm:跳过汇编
-