FFmpeg 编译和集成
背景
FFmpeg 是一款知名的开源音视频处理软件,它提供了丰富而友好的接口支持开发者进行二次开发。
FFmpeg 读作 “ef ef em peg” ,其中的 “FF” 指的是 “Fast Forward”,“mpeg” 则是 “Moving Picture Experts Group” (动态图像专家组)。
FFmpeg 项目功能复杂而庞大,基本上支持所有常见的音视频处理操作,如封装格式转换、音视频转码、音视频播放和剪辑、视频添加水印滤镜等。
尽管 FFmpeg 功能强大,但是由于其采用的是带有传染性的 LGPL/GPL 开源协议,所以一些大厂基本上都是自己独立开发类似的音视频处理库,甚至在接口和组织模块上模仿 FFmpeg 。
因此,学习 FFmpeg 不仅能够帮助你掌握音视频开发的相关知识脉络,还能让你快速适应不同的音视频处理框架。
FFmpeg 编译
FFmpeg 有六个常用的功能模块:
libavformat:多媒体文件或协议的封装和解封装库;
libavcodec:音视频编解码库;
libavfilter:音视频、字幕滤镜库;
libswscale:图像格式转换库;
libswresample:音频重采样库;
libavutil:工具库。
本文主要是帮助初学者快速上手 FFmpeg 的编译和集成,对 FFmpeg 项目的编译配置细节就不做过多阐述,这不是本篇内容所能容纳的。
这里主要选择编译 ffmpeg v4.2.2 版本,因为这个版本网上的解决方案比较多,而且大部分可行。
编译环境:
CentOS Linux release 7.6.1810 (Core)
android-ndk-r20b-linux-x86_64
ffmpeg-4.2.2
编译前准备:
#1. 下载 ffmpeg-4.2.2
wget https://ffmpeg.org/releases/ffmpeg-4.2.2.tar.bz2
#2. 解压 FFmpeg
tar -jxvf ffmpeg-4.2.2.tar.bz2
#3. 运行 configure 脚本配置项目
./configure --disable-x86asm解压目录下创建编译脚本

在 FFmpeg 4.2.2 解压目录下创建编译脚本 build_android_arm64-v8a_clang.sh:
#!/bin/bashexport NDK=/root/workspace/android-ndk-r20b #这里配置先你的 NDK 路径
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64function build_android
{./configure \
--prefix=$PREFIX \
--enable-neon \
--enable-hwaccels \
--enable-gpl \
--disable-postproc \
--disable-debug \
--enable-small \
--enable-jni \
--enable-mediacodec \
--enable-decoder=h264_mediacodec \
--enable-static \
--enable-shared \
--disable-doc \
--enable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-avdevice \
--disable-doc \
--disable-symver \
--cross-prefix=$CROSS_PREFIX \
--target-os=android \
--arch=$ARCH \
--cpu=$CPU \
--cc=$CC \
--cxx=$CXX \
--enable-cross-compile \
--sysroot=$SYSROOT \
--extra-cflags="-Os -fpic $OPTIMIZE_CFLAGS" \
--extra-ldflags="$ADDI_LDFLAGS"make clean
make -j16
make installecho "============================ build android arm64-v8a success =========================="}#arm64-v8a
ARCH=arm64
CPU=armv8-a
API=21
CC=$TOOLCHAIN/bin/aarch64-linux-android$API-clang
CXX=$TOOLCHAIN/bin/aarch64-linux-android$API-clang++
SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/aarch64-linux-android-
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-march=$CPU"build_android编译 FFmpeg Android 平台的 64 位动态库和静态库:
# 修改 build_android_arm64-v8a_clang.sh 可执行权限
chmod +x build_android_arm64-v8a_clang.sh
# 运行编译脚本
./build_android_arm64-v8a_clang.sh编译成功

编译成功后会在 android 目录下生成对应六个模块的静态库和动态库。
另外,若要编译成 32 位的库,则需修改对应的编译脚本:
#armv7-a
ARCH=arm
CPU=armv7-a
API=21
CC=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang
CXX=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang++
SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/arm-linux-androideabi-
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-mfloat-abi=softfp -mfpu=vfp -marm -march=$CPU "FFmpeg 集成
基于上节编译好的 FFmpeg 静态库,我们在 Android Studio 上进行简单的集成测试。
将 FFmpeg 各个模块的静态库和头文件放置到指定目录下

我们可以按照上图所示,将 FFmpeg 各个模块的静态库和头文件放置到指定目录下,实现一个获取各个模块版本信息的 jni 。
#include <cstdio>
#include <cstring>
#include "util/LogUtil.h"
#include "jni.h"//由于 FFmpeg 库是 C 语言实现的,告诉编译器按照 C 的规则进行编译
extern "C" {
#include <libavcodec/version.h>
#include <libavcodec/avcodec.h>
#include <libavformat/version.h>
#include <libavutil/version.h>
#include <libavfilter/version.h>
#include <libswresample/version.h>
#include <libswscale/version.h>
};#ifdef __cplusplus
extern "C" {
#endif
/** Class: com_byteflow_learnffmpeg_media_FFMediaPlayer* Method: native_GetFFmpegVersion* Signature: ()Ljava/lang/String;*/
JNIEXPORT jstring JNICALL Java_com_byteflow_learnffmpeg_media_FFMediaPlayer_native_1GetFFmpegVersion(JNIEnv *env, jclass cls)
{char strBuffer[1024 * 4] = {0};strcat(strBuffer, "libavcodec : ");strcat(strBuffer, AV_STRINGIFY(LIBAVCODEC_VERSION));strcat(strBuffer, "\nlibavformat : ");strcat(strBuffer, AV_STRINGIFY(LIBAVFORMAT_VERSION));strcat(strBuffer, "\nlibavutil : ");strcat(strBuffer, AV_STRINGIFY(LIBAVUTIL_VERSION));strcat(strBuffer, "\nlibavfilter : ");strcat(strBuffer, AV_STRINGIFY(LIBAVFILTER_VERSION));strcat(strBuffer, "\nlibswresample : ");strcat(strBuffer, AV_STRINGIFY(LIBSWRESAMPLE_VERSION));strcat(strBuffer, "\nlibswscale : ");strcat(strBuffer, AV_STRINGIFY(LIBSWSCALE_VERSION));strcat(strBuffer, "\navcodec_configure : \n");strcat(strBuffer, avcodec_configuration());strcat(strBuffer, "\navcodec_license : ");strcat(strBuffer, avcodec_license());LOGCATE("GetFFmpegVersion\n%s", strBuffer);return env->NewStringUTF(strBuffer);
}#ifdef __cplusplus
}
#endifJava 层的调用逻辑:
package com.byteflow.learnffmpeg.media;public class FFMediaPlayer {static {System.loadLibrary("learn-ffmpeg");}public static String GetFFmpegVersion() {return native_GetFFmpegVersion();}private static native String native_GetFFmpegVersion();
}
//=================== main activity ===========================
public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);((TextView)findViewById(R.id.text_view)).setText(FFMediaPlayer.GetFFmpegVersion());}
}CMakeLists.txt 构建脚本:
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")set(jnilibs ${CMAKE_SOURCE_DIR}/../jniLibs)
set(libname learn-ffmpeg)include_directories(include${CMAKE_SOURCE_DIR}/util
)link_directories(${jnilibs}/${ANDROID_ABI})file(GLOB src-files${CMAKE_SOURCE_DIR}/*.cpp)add_library( # Sets the name of the library.${libname}# Sets the library as a shared library.SHARED# Provides a relative path to your source file(s).${src-files})set(third-party-libsavformatavcodecavfilterswresampleswscaleavutil)set(native-libsandroidEGLGLESv3OpenSLESlogmz)target_link_libraries( # Specifies the target library.${libname}# Links the target library to the log library# included in the NDK.${log-lib}${third-party-libs}${native-libs})编译完成后,运行 App 获取 FFmpeg 各个模块版本和编译配置信息。

编译好的FFmpeg下载地址
FFmpeg_4.3.2支持Android的音视频处理库-Android文档类资源-CSDN文库
相关文章:
FFmpeg 编译和集成
背景FFmpeg 是一款知名的开源音视频处理软件,它提供了丰富而友好的接口支持开发者进行二次开发。FFmpeg 读作 “ef ef em peg” ,其中的 “FF” 指的是 “Fast Forward”,“mpeg” 则是 “Moving Picture Experts Group” (动态图…...
OOM的俩种情况---主动kill/被动kill
出现OOM, 有两种处理方式:1. 主动Kill; 2. 被动Kill 例:HBase Region Server OOM定位问题复盘 现象 在HBase资源隔离项目中,对测试集群进行压测时,发现region server会出现崩溃的情况,单机请求量从>200到~50每秒都…...
ssh远程连接ECS实例连接失败
尝试通过 SSH 远程连接服务来连接ECS云服务器实例时,收到“连接被拒”或“连接超时”的错误信息,可能的原因分析如下: 错误信息描述 1、错误消息:“ssh: connect to ecs-X-X-X-X.compute-xxxxxxxxx.com port 22: Connection tim…...
[框架设计] MVVM 的介绍,应用及优缺点
介绍 MVVM(Model-View-ViewModel)是一种架构模式,用于将应用程序分离为三个部分: Model(模型):负责处理应用程序的数据和业务逻辑。View(视图):负责呈现用户…...
4G模块DTU网关远程抄表方案(二):DL645/698协议国网电表
4G模块DTU网关远程抄表方案(二):DL645/698协议国网电表 1 DL 645协议简介 DL645协议是一种用于智能电能表的远程抄读通讯标准。制定该标准是为统一和规范多功能电能表与数据终端设备进行数据交换时的物理连接和通信链路及应用技术规范。DL645协议可用于远程监测电力传输和使用…...
认识微服务
目录 认识微服务 单体架构 分布式架构 服务架构演变 服务治理 微服务 总结 微服务技术对比 微服务结构 微服务技术对比 企业需求 SpringCloud SpringCloud和SpringBoot的版本兼容 认识微服务 单体架构 单体架构:将业务的所有功能集中在一个项目中开发&a…...
升级Android Studio Electric Eel问题汇总
1.升级以后找不到java可执行程序 问题原因:升级后,Android Studio自带的java目录不再是根目录/jre,调整为一个新目录 Studio根目录/jbr 修改方法:1)修改系统环境变量, JAVA_HOME调整为Studio下对应的java…...
令执法机构头疼的“虚拟货币犯罪”,为何链上天眼能“行”
谈到洗钱,你脑海中率先想到的可能是影视剧中利用赌场、收藏品拍卖等来实施犯罪。其实洗钱犯罪的花样不止于此,在近期热播的扫黑剧《狂飙》中,唐小龙为洗白“赌博资金、高利贷业务”,便通过“卖酒网销”的方式达成洗钱目的。 随着科…...
【unity】开发rts 3
一 出生点、阵营类型、阵营 实例栏-GameManage,默认有一个插槽 size 插槽数量 role 权限,host是主人,权限高 type 阵营类型,不选不限制,选的效果没看懂,文档原文: The Type field in Data al…...
突破老旧OA系统局限,打通五大业务管理体系,让效率“狂飙”
目录 用无代码构建上海致远信息化平台 一、支持类(行政人事、财务)体系 二、营销体系 三、供应链体系 四、质量管理体系 五、技术研发体系 下一步规划 我们公司用的第一套系统是 IBM 的系统,部署在本地服务器,这套系统用了十几年,当时 2020 年要全部迁移到LCHub低代…...
【vue2小知识】路由守卫的使用与解决RangeError: Maximum call stack size exceeded问题的报错。
🥳博 主:初映CY的前说(前端领域) 🌞个人信条:想要变成得到,中间还有做到! 🤘本文核心:当我们在路由跳转前与后我们可实现触发的操作 【前言】当我们在做类似于登录页面的时候&…...
Google Guice 5:AOP
1. AOP 1.1 实际开发中面临的问题 在实际开发中,经常需要打印一个方法的执行时间,以确定是否存在慢操作 最简单的方法,直接修改已有的方法,在finnally语句中打印耗时 Override public Optional<Table> getTable(String da…...
【同步、共享和内容协作软件】上海道宁与ownCloud让您的团队随时随地在任何设备上轻松处理数据
ownCloud是 一款开源文件同步、共享和 内容协作软件 可让团队随时随地 在任何设备上轻松处理数据 ownCloud开发并提供 用于内容协作的开源软件 使团队能够轻松地无缝 共享和处理文件 而无需考虑设备或位置 开发商介绍 ownCloud成立于2010年,是一个托管和同…...
Linux 文件、目录与磁盘格式
用户与用户组 用户:即某个文件的拥有者,可以管理自己账号下的文件,另有一个超级账号 root,可以统一管理全局,利用 su root 命令登录该账号。用户组:相当于群组,多个用户之间可以组成用户组&…...
锁屏面试题百日百刷-Hive篇(五)
锁屏面试题百日百刷,每个工作日坚持更新面试题。锁屏面试题app、小程序现已上线,官网地址:https://www.demosoftware.cn。已收录了每日更新的面试题的所有内容,还包含特色的解锁屏幕复习面试题、每日编程题目邮件推送等功能。让你…...
java多线程(七)线程等待与唤醒
一、wait()、notify()、notifyAll()等方法介绍 在Object.java中,定义了wait(), notify()和notifyAll()等接口。wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。而notify()和notifyAll()的作用࿰…...
第13天-仓储服务(仓库管理,采购管理 ,SPU规格维护)
1.仓储服务开发配置 1.1.加入到Nacos注册中心 spring:application:name: gmall-warecloud:nacos:discovery:server-addr: 192.168.139.10:8848namespace: 36854647-e68c-409b-9233-708a2d41702c1.2.配置网关路由 spring:cloud:gateway:routes:- id: ware_routeuri: lb://gmal…...
Maven 命令行及例子
基本 mvn -v - show-version -version 显示版本信息mvn -h - help 显示帮助信息mvn -e -errors控制 maven 的日志级别,产生执行错误相关消息mvn -q - quiet 控制 maven 的日志级别,仅仅显示错误mvn -o - offline 运行 offline 模式,不联网更…...
JavaScript手写题
一、防抖 function debounce(fn, delay200) {let timeout null; // 定时器控制return function(...args) {if (timeout) { // 定时器存在,表示某个动作之前触发过了clearTimeout(timeout); // 清除定时器timeout null;} else {// 对第一次输入立即执行fn.apply…...
为什么图标的宽度总是8的倍数?
对于 Windows 上的所有图标而言,它的宽度总是8的倍数,这可不是因为人们喜欢2的幂,虽然在计算机世界,你会看到很多这样的数字,例如,1024,4096等。 在 Windows 的早期阶段,大多数显卡…...
5分钟快速上手:用FanControl打造你的Windows电脑静音散热系统
5分钟快速上手:用FanControl打造你的Windows电脑静音散热系统 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode.com/GitHub_Tren…...
Arm CoreLink GFC-200 Flash控制器架构与优化实践
1. Arm CoreLink GFC-200 Flash控制器架构解析在嵌入式系统设计中,非易失性存储管理是核心挑战之一。作为Arm CoreLink系列的重要成员,GFC-200通用Flash控制器通过创新的总线架构和分区管理机制,为SoC设计提供了高效的Flash存储解决方案。这款…...
量化研究实战:从数据到策略的Python框架与机器学习应用
1. 从零到一:量化研究实战框架搭建心路如果你和我一样,对金融市场既着迷又敬畏,总想用理性和数据去解读那些看似随机的价格波动,那么“量化研究”这个词对你来说一定不陌生。它听起来高大上,仿佛是高学历精英们在华尔街…...
文献阅读 260511-Wildfire damages and the cost-effective role of forest fuel treatments
Wildfire damages and the cost-effective role of forest fuel treatments 来自 <https://www.science.org/doi/10.1126/science.aea6463> ## Abstract: Gave the core question: Wildfires are among the most pressing environmental challenges of the 21st century,…...
Prometheus 自定义指标监控:Python Exporter 编写与业务指标告警配置
前言 Prometheus 监控系统指标(CPU、内存、磁盘)这件事很多人熟悉,但不少开发者有个共同疑问:业务特有的指标——比如队列积压数、订单待处理量、API 调用成功率——Prometheus 能监控吗? 答案是:完全可以…...
STM32H750调试KSZ8863翻车实录:从F4经验到H7的坑,硬件配置避雷指南
STM32H7与KSZ8863实战避坑指南:从F4经验到H7的硬件设计差异 调试以太网PHY芯片KSZ8863时,许多工程师会带着STM32F4的成功经验直接迁移到STM32H7平台,结果往往遭遇意想不到的硬件兼容性问题。本文将深入剖析两个平台在RMII接口设计上的关键差…...
从“抄答案”到“会解题”:我是如何利用头歌实训平台,真正掌握Python数据分析的?
从“抄答案”到“会解题”:我的Python数据分析思维进阶之路 记得第一次打开头歌实训平台的Python数据分析题目时,我像大多数初学者一样,迫不及待地寻找"正确答案"。复制、粘贴、运行——看到绿色通过提示的瞬间,以为自己…...
基于SpringBoot的B2C生鲜电商平台毕设源码
博主介绍:✌ 专注于Java,python,✌关注✌私信我✌具体的问题,我会尽力帮助你。一、研究目的本研究旨在构建一个基于Spring Boot与Vue框架的B2C生鲜电商平台以解决当前生鲜电商领域存在的核心问题包括供应链管理效率低下导致的商品损耗率居高不下用户端体…...
2026 年 Redis 面试题全解析:原理 + 实战 + 高频考点
Redis 高频面试题全解析(2026 最新版) Redis 作为后端开发高并发、高可用架构的核心组件,是面试中必问的核心考点。本文从基础入门、核心原理、高并发实战、高可用架构、进阶运维五大模块,整理大厂高频面试题与标准答案ÿ…...
Verilog分频器进阶:从6分频到1.5分频的实战设计与波形分析
1. 分频器基础与设计思路 在数字电路设计中,时钟信号就像人的心跳一样重要。分频器的作用,就是把这个"心跳"调整到我们需要的节奏。简单来说,分频器就是把输入时钟的频率降低N倍,得到一个新的时钟信号。比如6分频&#…...
