开源的 H.264/AVC 视频编码器库-x264 的交叉编译 和 程序测试

一、环境准备

  1. 安装交叉编译工具链
    根据目标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

在这里插入图片描述

  1. 创建工作目录
    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(&param, "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(&param, "high") < 0) {fprintf(stderr, "Failed to apply profile\n");return -1;}// 4. 打开编码器x264_t *encoder = x264_encoder_open(&param);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;
}
  1. 参数配置

    • x264_param_default_preset():应用预设配置(medium/fast/placebo等)
    • x264_param_apply_profile():设置编码规格(baseline/main/high)
  2. 图像处理

    • x264_picture_alloc():分配YUV420P图像内存
    • 手动生成渐变彩条测试图案(实际应用应从文件/摄像头获取)
  3. 编码核心

    • x264_encoder_encode():执行帧编码
    • 输出NAL单元包含:SPS/PPS/IDR帧/P帧等
  4. 输出处理

    • 写入annex-b格式的原始H.264流
    • 最后刷新编码器获取延迟帧

其它功能

  1. 从文件读取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
  1. 调整编码参数
// 提高编码质量
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;
  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

在这里插入图片描述
在这里插入图片描述

八、部署与测试

  1. 复制文件到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/目录下
文件需要赋权限
在这里插入图片描述
测试指令
在这里插入图片描述

  1. 在ARM设备上运行

    # 设置库路径
    export LD_LIBRARY_PATH=/lib:$LD_LIBRARY_PATH# 执行测试
    /tmp/test_x264
    
  2. 输出

在这里插入图片描述
在这里插入图片描述

# 使用FFmpeg播放生成的视频
ffplay test.264

在这里插入图片描述


# 查看视频信息
ffprobe test.264

在这里插入图片描述

# 检查编码统计
ffmpeg -i test.264 -f null -

在这里插入图片描述

常见问题及解决方案

  1. 编译报错:undefined reference to 'sqrt'
    解决:在链接命令中添加-lm(数学库)。

  2. 运行报错:libx264.so.x: cannot open shared object file
    解决:确保库文件已复制到ARM设备的/lib目录,并执行ldconfig刷新缓存。

  3. 性能优化

    • 若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:跳过汇编
      

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/89130.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/89130.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自由学习记录(69)

RectToPolar() 是 将直角坐标系 (笛卡尔坐标系) 的 uv 坐标&#xff0c;转化为极坐标系&#xff08;θ&#xff0c;r&#xff09; uv - centerUV&#xff1a;将坐标原点平移&#xff0c;使 (0.5, 0.5) 变成原点。 r length(uv)&#xff1a;距离中心点的半径&#xff08;从中…

Spring Boot 敏感信息入库加密全面解决方案

Spring Boot 敏感信息入库加密全面解决方案 在当今数据驱动的时代,保护用户隐私数据已成为系统设计的必备要求。本文将详细介绍 Spring Boot 应用中敏感数据加密存储的完整方案,涵盖从基础实现到生产级落地的全流程。 一、加密方案选型 1.1 常见加密类型对比 加密类型特点…

docker0网卡没有ip一步解决

正常查看ip的时候一直显示没有ip这里先删除docker0网卡ip link delete docker0然后重启服务systemctl restart docker再次查看显示有ip了并且查看配置文件也是正常的cat /etc/docker/daemon.json {"registry-mirrors": ["https://docker.m.daocloud.io",&q…

MYSQL-索引篇

索引结构概述MySQL 的索引是在存储引擎层实现的&#xff0c;不同的存储引擎有不同的索引结构&#xff0c;主要包含以下几种&#xff1a;索引结构描述BTree索引最常见的索引类型&#xff0c;大部分引擎都支持 B 树索引Hash索引底层数据结构是用哈希表实现的&#xff0c;只有精确…

(纯新手教程)HTML零基础教学

&#xff08;下一章&#xff1a;python网络爬虫&#xff09;HTML 简介HTML&#xff08;HyperText Markup Language&#xff0c;超文本标记语言&#xff09;是用于创建网页的标准标记语言。什么是 HTML&#xff1f;HTML 不是编程语言&#xff0c;而是一种标记语言使用标签来描述…

前端面试宝典---项目难点2-智能问答对话框采用虚拟列表动态渲染可视区域元素(10万+条数据)

引言 在我参与智能问答项目中一个智能体回话并不会像豆包一样&#xff0c;每次新建会话都是是从头开始&#xff0c;而项目中你想创建新会话就像chatbox一样&#xff0c;是点击橡皮擦开启新的聊天上下文&#xff0c;但是直接的聊天记录依然存在&#xff0c;针对超过十万&#xf…

Python元组:不可变数据的强大用法

文章目录元组概念1.基本特性2.创建元组3.访问元素4.元组的不可变性5.元组操作6.元组解包7.命名元组8.元组与列表的比较9.元组的优势10.适用场景11.常用方法小结元组 概念 元组是 Python 中一个非常重要的内置数据结构&#xff0c;它与列表(list)相似但具有关键差异。下面我将…

若尔盖湿地的花湖

花湖位于若尔盖县和甘肃的郎木寺之间的213国道旁&#xff0c;属于若尔盖湿地国家级自然保护区内。又名“梅朵湖”&#xff0c;因阳光照射下湖面色彩斑斓如绚丽的花瓣得名。花湖的大门是梯形高大石柱搭成&#xff0c;我们需要过天桥到对面检票坐小交通。通过车窗看到一层一层的云…

50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | DoubleClickHeart(双击爱心)

&#x1f4c5; 我们继续 50 个小项目挑战&#xff01;—— DoubleClickHeart组件 仓库地址&#xff1a;https://github.com/SunACong/50-vue-projects 项目预览地址&#xff1a;https://50-vue-projects.vercel.app/ 使用 Vue 3 的 Composition API&#xff08;<script se…

1-绪论-1-数据结构的基本概念

&#x1f389; 数据结构的魔法世界&#x1f4da;&#x1f468;‍&#x1f393;“数据就像大海中的浪花&#xff0c;结构则是那神秘的洋流。掌握数据结构&#xff0c;就是掌握在信息海洋中自由航行的力量&#xff01;”引言&#xff1a;为什么要学数据结构&#xff1f;&#x1f…

linux网络相关命令简介

目录 一、IP命令 1、Link或L:管理网络接口(网卡) 2、Address或Addr,A:管理Ip地址 3、Route或R:管理路由表

教育培训机构如何为课程视频添加防盗录的强水印?

在知识付费时代&#xff0c;教育培训机构的课程视频是核心资产&#xff0c;但盗录、非法传播等问题却让机构防不胜防。如何在不影响学员观看体验的前提下&#xff0c;为课程视频添加“强效防盗水印”&#xff0c;精准追踪泄露源头&#xff1f;本文将为您揭秘高安全性水印的添加…

python的形成性考核管理系统

前端开发框架:vue.js 数据库 mysql 版本不限 后端语言框架支持&#xff1a; 1 java(SSM/springboot)-idea/eclipse 2.NodejsVue.js -vscode 3.python(flask/django)–pycharm/vscode 4.php(thinkphp/laravel)-hbuilderx 数据库工具&#xff1a;Navicat/SQLyog等都可以 摘要 随着…

A*算法详解

A*算法详解一、A*算法基础概念1.1 算法定位1.2 核心评估函数1.3 关键数据结构二、A*算法的核心步骤三、启发函数设计3.1 网格地图中的启发函数3.2 启发函数的选择原则三、Java代码实现四、启发函数的设计与优化4.1 启发函数的可采纳性4.2 启发函数的效率影响4.3 常见启发函数对…

.net winfrom 获取上传的Excel文件 单元格的背景色

需求&#xff1a;根据Excel某行标注了黄色高亮颜色&#xff0c;说明该行数据已被用户选中(Excel文件中并没有“已选中”这一列&#xff0c;纯粹用颜色表示)&#xff0c;导入数据到数据库时标注此行已选中直接上代码&#xff1a;//选择Excel文件private void btnBrowse_Click(ob…

OpenAI GPT-4o技术详解:全能多模态模型的架构革新与生态影响

本文由「大千AI助手」原创发布&#xff0c;专注用真话讲AI&#xff0c;回归技术本质。拒绝神话或妖魔化。搜索「大千AI助手」关注我&#xff0c;一起撕掉过度包装&#xff0c;学习真实的AI技术&#xff01; ⚙️ 一、核心定义与发布背景 官方定位 GPT-4o&#xff08;“o”代表“…

⚡ 构建真正的高性能即时通讯服务:基于 Netty 集群的架构设计与实现

引子 在前面的文章中&#xff0c;我们基于 Netty 构建了一套单体架构的即时通讯服务。虽然单体架构在开发初期简单高效&#xff0c;但随着用户量的增长和业务规模的扩大&#xff0c;其局限性逐渐显现。当面对高并发场景时&#xff0c;单体 Netty 服务很容易触及性能天花板&…

原来时间序列挖掘这么简单

先搞懂&#xff1a;啥是时间序列&#xff1f;简单说&#xff0c;时间序列就是按时间顺序记下来的数据。比如&#xff1a;你每天早上 8 点测的体重&#xff0c;连起来就是 “体重时间序列”&#xff1b;超市每天的销售额&#xff0c;连起来就是 “销售时间序列”&#xff1b;城市…

基于Python的豆瓣图书数据分析与可视化系统【自动采集、海量数据集、多维度分析、机器学习】

文章目录有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主项目介绍每文一语有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主 项目介绍 豆瓣图书数据智能分析系统是一个集数据采集、清洗、分析与可视化于一体的综合性项…

2.3 数组与字符串

学习目标&#xff1a; 理解数组和字符串的概念&#xff08;存储多个数据的“盒子”&#xff09;。掌握数组的声明、初始化和遍历方法。能用字符串处理简单文本问题&#xff08;如字符计数、回文判断&#xff09;。1 一维数组 基本概念 比喻&#xff1a; 数组就像“储物柜”&…