当前位置: 首页 > news >正文

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
}
#endif

Java 层的调用逻辑:

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 是一款知名的开源音视频处理软件&#xff0c;它提供了丰富而友好的接口支持开发者进行二次开发。FFmpeg 读作 “ef ef em peg” &#xff0c;其中的 “FF” 指的是 “Fast Forward”&#xff0c;“mpeg” 则是 “Moving Picture Experts Group” &#xff08;动态图…...

OOM的俩种情况---主动kill/被动kill

出现OOM, 有两种处理方式&#xff1a;1. 主动Kill; 2. 被动Kill 例&#xff1a;HBase Region Server OOM定位问题复盘 现象 在HBase资源隔离项目中&#xff0c;对测试集群进行压测时&#xff0c;发现region server会出现崩溃的情况&#xff0c;单机请求量从>200到~50每秒都…...

ssh远程连接ECS实例连接失败

尝试通过 SSH 远程连接服务来连接ECS云服务器实例时&#xff0c;收到“连接被拒”或“连接超时”的错误信息&#xff0c;可能的原因分析如下&#xff1a; 错误信息描述 1、错误消息&#xff1a;“ssh: connect to ecs-X-X-X-X.compute-xxxxxxxxx.com port 22: Connection tim…...

[框架设计] MVVM 的介绍,应用及优缺点

介绍 MVVM&#xff08;Model-View-ViewModel&#xff09;是一种架构模式&#xff0c;用于将应用程序分离为三个部分&#xff1a; Model&#xff08;模型&#xff09;&#xff1a;负责处理应用程序的数据和业务逻辑。View&#xff08;视图&#xff09;&#xff1a;负责呈现用户…...

4G模块DTU网关远程抄表方案(二):DL645/698协议国网电表

4G模块DTU网关远程抄表方案(二):DL645/698协议国网电表 1 DL 645协议简介 DL645协议是一种用于智能电能表的远程抄读通讯标准。制定该标准是为统一和规范多功能电能表与数据终端设备进行数据交换时的物理连接和通信链路及应用技术规范。DL645协议可用于远程监测电力传输和使用…...

认识微服务

目录 认识微服务 单体架构 分布式架构 服务架构演变 服务治理 微服务 总结 微服务技术对比 微服务结构 微服务技术对比 企业需求 SpringCloud SpringCloud和SpringBoot的版本兼容 认识微服务 单体架构 单体架构&#xff1a;将业务的所有功能集中在一个项目中开发&a…...

升级Android Studio Electric Eel问题汇总

1.升级以后找不到java可执行程序 问题原因&#xff1a;升级后&#xff0c;Android Studio自带的java目录不再是根目录/jre&#xff0c;调整为一个新目录 Studio根目录/jbr 修改方法&#xff1a;1&#xff09;修改系统环境变量&#xff0c; JAVA_HOME调整为Studio下对应的java…...

令执法机构头疼的“虚拟货币犯罪”,为何链上天眼能“行”

谈到洗钱&#xff0c;你脑海中率先想到的可能是影视剧中利用赌场、收藏品拍卖等来实施犯罪。其实洗钱犯罪的花样不止于此&#xff0c;在近期热播的扫黑剧《狂飙》中&#xff0c;唐小龙为洗白“赌博资金、高利贷业务”&#xff0c;便通过“卖酒网销”的方式达成洗钱目的。 随着科…...

【unity】开发rts 3

一 出生点、阵营类型、阵营 实例栏-GameManage&#xff0c;默认有一个插槽 size 插槽数量 role 权限&#xff0c;host是主人&#xff0c;权限高 type 阵营类型&#xff0c;不选不限制&#xff0c;选的效果没看懂&#xff0c;文档原文&#xff1a; The Type field in Data al…...

突破老旧OA系统局限,打通五大业务管理体系,让效率“狂飙”

目录 用无代码构建上海致远信息化平台 一、支持类(行政人事、财务)体系 二、营销体系 三、供应链体系 四、质量管理体系 五、技术研发体系 下一步规划 我们公司用的第一套系统是 IBM 的系统,部署在本地服务器,这套系统用了十几年,当时 2020 年要全部迁移到LCHub低代…...

【vue2小知识】路由守卫的使用与解决RangeError: Maximum call stack size exceeded问题的报错。

&#x1f973;博 主&#xff1a;初映CY的前说(前端领域) &#x1f31e;个人信条&#xff1a;想要变成得到&#xff0c;中间还有做到&#xff01; &#x1f918;本文核心&#xff1a;当我们在路由跳转前与后我们可实现触发的操作 【前言】当我们在做类似于登录页面的时候&…...

Google Guice 5:AOP

1. AOP 1.1 实际开发中面临的问题 在实际开发中&#xff0c;经常需要打印一个方法的执行时间&#xff0c;以确定是否存在慢操作 最简单的方法&#xff0c;直接修改已有的方法&#xff0c;在finnally语句中打印耗时 Override public Optional<Table> getTable(String da…...

【同步、共享和内容协作软件】上海道宁与​ownCloud让您的团队随时随地在任何设备上轻松处理数据

ownCloud是 一款开源文件同步、共享和 内容协作软件 可让团队随时随地 在任何设备上轻松处理数据 ownCloud开发并提供 用于内容协作的开源软件 使团队能够轻松地无缝 共享和处理文件 而无需考虑设备或位置 开发商介绍 ownCloud成立于2010年&#xff0c;是一个托管和同…...

Linux 文件、目录与磁盘格式

用户与用户组 用户&#xff1a;即某个文件的拥有者&#xff0c;可以管理自己账号下的文件&#xff0c;另有一个超级账号 root&#xff0c;可以统一管理全局&#xff0c;利用 su root 命令登录该账号。用户组&#xff1a;相当于群组&#xff0c;多个用户之间可以组成用户组&…...

锁屏面试题百日百刷-Hive篇(五)

锁屏面试题百日百刷&#xff0c;每个工作日坚持更新面试题。锁屏面试题app、小程序现已上线&#xff0c;官网地址&#xff1a;https://www.demosoftware.cn。已收录了每日更新的面试题的所有内容&#xff0c;还包含特色的解锁屏幕复习面试题、每日编程题目邮件推送等功能。让你…...

java多线程(七)线程等待与唤醒

一、wait()、notify()、notifyAll()等方法介绍 在Object.java中&#xff0c;定义了wait(), notify()和notifyAll()等接口。wait()的作用是让当前线程进入等待状态&#xff0c;同时&#xff0c;wait()也会让当前线程释放它所持有的锁。而notify()和notifyAll()的作用&#xff0…...

第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 的日志级别&#xff0c;产生执行错误相关消息mvn -q - quiet 控制 maven 的日志级别&#xff0c;仅仅显示错误mvn -o - offline 运行 offline 模式&#xff0c;不联网更…...

JavaScript手写题

一、防抖 function debounce(fn, delay200) {let timeout null; // 定时器控制return function(...args) {if (timeout) { // 定时器存在&#xff0c;表示某个动作之前触发过了clearTimeout(timeout); // 清除定时器timeout null;} else {// 对第一次输入立即执行fn.apply…...

为什么图标的宽度总是8的倍数?

对于 Windows 上的所有图标而言&#xff0c;它的宽度总是8的倍数&#xff0c;这可不是因为人们喜欢2的幂&#xff0c;虽然在计算机世界&#xff0c;你会看到很多这样的数字&#xff0c;例如&#xff0c;1024&#xff0c;4096等。 在 Windows 的早期阶段&#xff0c;大多数显卡…...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

day52 ResNet18 CBAM

在深度学习的旅程中&#xff0c;我们不断探索如何提升模型的性能。今天&#xff0c;我将分享我在 ResNet18 模型中插入 CBAM&#xff08;Convolutional Block Attention Module&#xff09;模块&#xff0c;并采用分阶段微调策略的实践过程。通过这个过程&#xff0c;我不仅提升…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

1.3 VSCode安装与环境配置

进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件&#xff0c;然后打开终端&#xff0c;进入下载文件夹&#xff0c;键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

在 Spring Boot 项目里,MYSQL中json类型字段使用

前言&#xff1a; 因为程序特殊需求导致&#xff0c;需要mysql数据库存储json类型数据&#xff0c;因此记录一下使用流程 1.java实体中新增字段 private List<User> users 2.增加mybatis-plus注解 TableField(typeHandler FastjsonTypeHandler.class) private Lis…...

基于鸿蒙(HarmonyOS5)的打车小程序

1. 开发环境准备 安装DevEco Studio (鸿蒙官方IDE)配置HarmonyOS SDK申请开发者账号和必要的API密钥 2. 项目结构设计 ├── entry │ ├── src │ │ ├── main │ │ │ ├── ets │ │ │ │ ├── pages │ │ │ │ │ ├── H…...