一、环境准备
- 安装交叉编译工具链
根据目标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/PPS
param.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:跳过汇编