音視頻學習:使用NDK編譯FFmpeg動態庫

1. 環境

1.1 基礎配置

  • NDK 22b (r22b)
  • FFmpeg 4.4
  • Ubuntu 22.04

1.2 下載ffmpeg

官網提供了 .tar.xz 包,可以直接下載解壓:

wget https://ffmpeg.org/releases/ffmpeg-4.4.tar.xz
tar -xvf ffmpeg-4.4.tar.xz
cd ffmpeg-4.4

1.3 安裝基礎工具鏈

sudo apt-get update && sudo apt-get install \
build-essential autoconf automake libtool \
pkg-config cmake git wget unzip yasm

可能不包含全部,遇到報錯缺少的工具鏈的,把報錯拋給AI,按提示下載即可:)


2. 編譯腳本配置

注意將腳本中的 export NDK 換成自己的路徑

 #!/bin/bashecho ">>>>>>>>> 編譯硬件解碼版本 <<<<<<<<"#替換為你自己的NDK路徑.export NDK=/home/xaye/Android/Sdk/ndk/android-ndk-r22TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64function build_android{echo "開始編譯 $CPU"./configure \--prefix=$PREFIX \--enable-neon  \--enable-hwaccels  \--enable-gpl   \--enable-postproc \--enable-shared \--disable-debug \--enable-small \--enable-jni \--enable-mediacodec \--enable-decoder=h264_mediacodec \--disable-static \--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 cleanmakemake installecho "編譯成功 $CPU"}#armv8-aARCH=arm64CPU=armv8-aAPI=21CC=$TOOLCHAIN/bin/aarch64-linux-android$API-clangCXX=$TOOLCHAIN/bin/aarch64-linux-android$API-clang++SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysrootCROSS_PREFIX=$TOOLCHAIN/bin/aarch64-linux-android-PREFIX=$(pwd)/android/$CPUOPTIMIZE_CFLAGS="-march=$CPU"build_android#armv7-aARCH=armCPU=armv7-aAPI=16CC=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clangCXX=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang++SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysrootCROSS_PREFIX=$TOOLCHAIN/bin/arm-linux-androideabi-PREFIX=$(pwd)/android/$CPUOPTIMIZE_CFLAGS="-mfloat-abi=softfp -mfpu=vfp -marm -march=$CPU "build_android

3. 執行編譯

# 賦予執行權限
chmod +x build_android.sh# 開始編譯(約10-30分鐘)
./build_android.sh

編譯完成后,會生成 android/armv7-aandroid/armv8-a 目錄,結構如下

android/├── armv7-a/│   ├── lib/*.so│   └── include/   <-- FFmpeg 頭文件└── armv8-a/├── lib/*.so└── include/

這些 .so 文件,分別對應:

  • armv7-a/ → 用于 Android 項目的 armeabi-v7a
  • armv8-a/ → 用于 Android 項目的 arm64-v8a

4. Android 項目配置

修改 build.gradle,啟用 NDK 支持

 android {defaultConfig {externalNativeBuild {cmake {cppFlags "-std=c++11"abiFilters 'armeabi-v7a', 'arm64-v8a'}}}externalNativeBuild {cmake {path "CMakeLists.txt"}}ndkVersion '22.0.7026061'}

放入頭文件

將 FFmpeg 頭文件復制到 app/src/main/cpp/ 下,就是把上面編譯生成的整個 include 文件夾復制進去,不用在意v7a還是v8a,頭文件接口都是一樣的。

創建 CMakeLists.txt

app/ 目錄下創建:

# 最低 CMake 版本要求
cmake_minimum_required(VERSION 3.4.1)# 項目設置
project("ffmpeg_jni")# 設置 C 標準(FFmpeg 需要 C11)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 11)# 打印當前 ABI 用于調試
message("Current ABI: ${ANDROID_ABI}")# 設置 FFmpeg 庫路徑(根據實際路徑調整)
set(FFMPEG_LIBS_DIR ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI})# 定義 FFmpeg 核心庫(按依賴順序)
set(FFMPEG_LIBSavutilswresampleavcodecavformatswscale# 可選添加其他庫:postproc, avfilter 等
)# 導入預編譯的 FFmpeg 共享庫
foreach(LIB ${FFMPEG_LIBS})add_library(${LIB} SHARED IMPORTED)set_target_properties(${LIB} PROPERTIESIMPORTED_LOCATION "${FFMPEG_LIBS_DIR}/lib${LIB}.so"# 對于 Android 8.0+ 需要設置 SONAMEIMPORTED_SONAME "lib${LIB}.so")message("Imported lib: ${FFMPEG_LIBS_DIR}/lib${LIB}.so")
endforeach()# 添加 Android 日志庫
find_library(log-lib log)# 設置 JNI 源文件
file(GLOB JNI_SOURCES src/main/cpp/*.cpp)# 創建 JNI 庫
add_library(ffmpeg_jni SHARED ${JNI_SOURCES})# 頭文件包含路徑(根據 FFmpeg 頭文件位置調整)
target_include_directories(ffmpeg_jni PRIVATE${CMAKE_SOURCE_DIR}/src/main/cpp/include  # 頭文件放在這里${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/include  # 如果 FFmpeg 頭文件隨庫提供
)# 鏈接庫
target_link_libraries(ffmpeg_jniandroid${log-lib}${FFMPEG_LIBS}  # 按依賴順序自動鏈接
)# 編譯選項優化
target_compile_options(ffmpeg_jni PRIVATE-Wall-Werror-fno-exceptions-fno-rtti-fvisibility=hidden
)

5. JNI 代碼實現

Java 層聲明

創建 FFmpegHelper.java

public class FFmpegHelper {static {// 按依賴順序加載FFmpeg庫System.loadLibrary("avutil");System.loadLibrary("swresample");System.loadLibrary("avcodec");System.loadLibrary("avformat");System.loadLibrary("swscale");System.loadLibrary("ffmpeg_jni"); // 我們的JNI庫}public static native String getFFmpegVersion();
}

Native 層實現

創建 ffmpeg_jni.cpp

#include <jni.h>
#include <android/log.h>
//#include <libavutil/avutil.h>
#include <stdio.h>extern "C" {
#include <libavutil/avutil.h>
}#define LOG_TAG "FFmpegJNI"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)extern "C" {
JNIEXPORT jstring JNICALL
Java_com_xaye_compiler_FFmpegHelper_getFFmpegVersion(JNIEnv *env, jclass clazz) {// 調用FFmpeg API獲取版本信息const char* version = av_version_info();LOGD("Native FFmpeg version: %s", version);return env->NewStringUTF(version ? version : "Unknown");
}
}

注意:在#include ffmpeg 庫的頭文件時,要使用 extern "C" 包起來,不然會報錯!


6. 驗證

在主界面 打印版本號

  Log.i("MainActivity", " FFmpeg version : "+FFmpegHelper.getFFmpegVersion());

輸出:

在這里插入圖片描述


代碼已上傳 ffmpeg-compiler

參考:音視頻學習 (六) 一鍵編譯 32/64 位 FFmpeg 4.2.2

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/80820.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/80820.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/80820.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

前端開發避坑指南:React 代理配置常見問題與解決方案

前端開發避坑指南:React 代理配置常見問題與解決方案 一、為什么需要配置代理?二、使用 create-react-app 默認配置代理三、使用 http-proxy-middleware 配置復雜代理四、高級代理配置五、生產環境中的代理配置一、為什么需要配置代理? React 應用在開發過程中經常需要與后端…

用影刀RPA打通內容創作“最后一公里”:CSDN草稿一鍵同步多平臺發布

文章目錄 引言 一、需求場景&#xff1a;多平臺分發的效率困境1. 痛點分析2. 影刀RPA的破局價值 二、影刀RPA是啥&#xff1f;打工人逆襲神器&#xff01;三、手把手教你造"搬運工"——技術宅的土味開發日記第一步&#xff1a;當個"偷窺狂"——觀察手動操作…

進程與線程:09 進程同步與信號量

課程引入&#xff1a;進程同步與信號量 接下來這節課開始&#xff0c;我們再開始講多進程圖像。講多進程圖像的下一個點&#xff0c;前面我們講清楚了多進程圖像要想實現切換&#xff0c;調度是如何做的。同時&#xff0c;多個進程放在內存中&#xff0c;就會存在多進程合作的…

【愚公系列】《Manus極簡入門》036-物聯網系統架構師:“萬物互聯師”

&#x1f31f;【技術大咖愚公搬代碼&#xff1a;全棧專家的成長之路&#xff0c;你關注的寶藏博主在這里&#xff01;】&#x1f31f; &#x1f4e3;開發者圈持續輸出高質量干貨的"愚公精神"踐行者——全網百萬開發者都在追更的頂級技術博主&#xff01; &#x1f…

MySQL 8.0 OCP 英文題庫解析(四)

Oracle 為慶祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免費考取原價245美元的MySQL OCP 認證。 從今天開始&#xff0c;將英文題庫免費公布出來&#xff0c;并進行解析&#xff0c;幫助大家在一個月之內輕松通過OCP認證。 本期公布試題26~30 試題26:…

什么是原碼和補碼

補碼的本質確實是模運算&#xff08;Modular Arithmetic&#xff09;&#xff0c;這是理解補碼為何能統一加減法的核心數學原理。下面用最通俗的語言和例子解釋清楚&#xff1a; —### 1. 先理解什么是“模運算”- 模運算就是“周期性計數”&#xff0c;比如鐘表&#xff1a; -…

筆記項目 day02

一、用戶登錄接口 請求參數&#xff1a; 用loginDTO來封裝請求參數&#xff0c;要加上RequestBody注解 響應參數&#xff1a; 由于data里內容較多&#xff0c;考慮將其封裝到一個LoginUser的實體中&#xff0c;用戶登陸后&#xff0c;需要生成jwtToken并返回給前端。 登錄功…

2025年土木建筑與水利工程國際會議(ICCHE 2025)

2025 International Conference on Civil and Hydraulic Engineering (ICCHE 2025) &#xff08;一&#xff09;會議信息 會議簡稱&#xff1a;ICCHE 2025 大會地點&#xff1a;中國銀川 投稿郵箱&#xff1a;icchesub-paper.com 收錄檢索&#xff1a;提交Ei Compendex,CPCI,C…

運行Spark程序-在shell中運行1

&#xff08;一&#xff09;分布式計算要處理的問題 【老師提問&#xff1a;分布式計算要面臨什么問題&#xff1f;】 【老師總結】 分布式計算需要做到&#xff1a; 1.分區控制。把大的數據拆成一小份一小份的&#xff08;分區&#xff0c;分片&#xff09;讓多臺設備同時計算…

一文理清人工智能,機器學習,深度學習的概念

目錄 一、人工智能的起源與核心范疇&#xff08;1950-1980&#xff09; 1.1 智能機器的最初構想 1.2 核心范疇的初步分化 二、機器學習的興起與技術分化&#xff08;1980-2010&#xff09; 2.1 統計學習的黃金時代 2.2 神經網絡的復興與子集定位 2.3 技術生態的形成與AI…

《Effective Python》第1章 Pythonic 思維總結——編寫優雅、高效的 Python 代碼

《Effective Python》第1章 Pythonic 思維總結——編寫優雅、高效的 Python 代碼 在編程的世界里&#xff0c;每個語言都有其獨特的風格和最佳實踐。對于 Python 而言&#xff0c;“Pythonic”已經成為描述遵循 Python 特定風格的代碼的代名詞。這種風格不僅讓代碼更易讀、更簡…

MySQL 事務(二)

文章目錄 事務隔離性理論理解隔離性隔離級別 事務隔離級別的設置和查看事務隔離級別讀未提交讀提交&#xff08;不可重復讀&#xff09; 事務隔離性理論 理解隔離性 MySQL服務可能會同時被多個客戶端進程(線程)訪問&#xff0c;訪問的方式以事務方式進行一個事務可能由多條SQL…

代碼倉提交分支規范

以下是我部門開發時用的分支規范&#xff0c;參考于Linux社區 Tips 分支命名通常遵循一些最佳實踐和規則&#xff0c;以便使分支的用途和內容清晰易懂&#xff0c;就在寫一個文檔的主題一樣。 功能分支 (Feature Branches) 用于開發新功能。 命名格式&#xff1a;feature/功能名…

Google Earth Engine(GEE) 代碼詳解:批量計算_年 NDVI 并導出(附 Landsat 8 數據處理全流程)

一、代碼整體目標 基于 Landsat 8 衛星數據,批量計算 2013-2020 年研究區的 NDVI(歸一化植被指數),實現去云處理、數據合成、可視化及批量導出為 GeoTIFF 格式,適用于植被動態監測、生態環境評估等場景。 二、代碼分步解析(含核心原理與易錯點) 1. 加載并顯示研究區邊…

Maven 處理依賴沖突

Maven處理依賴沖突 什么是依賴沖突&#xff1f;如何解決&#xff1f;Maven自動處理依賴沖突的規則路徑優先原則第一聲明優先原則注意 子模塊覆蓋父模塊父模塊聲明dependency子模塊覆蓋dependency父模塊聲明dependencyManagement 子模塊覆蓋dependency父模塊聲明dependencyManag…

docker 安裝 sqlserver2022 和注意點

一、前言 1、可以直接參考微軟官方文檔 快速入門&#xff1a;使用 Docker 運行 SQL Server Linux 容器映像&#xff0c;這里主要是說一些注意點和坑 二、安裝 1、拉取鏡像 docker pull mcr.microsoft.com/mssql/server:2022-latest2、創建掛載目錄&#xff0c;這里只是比官方…

Dagster Pipes系列-1:調用外部Python腳本

本文是"Dagster Pipes教程"的第一部分&#xff0c;介紹如何通過Dagster資產調用外部Python腳本并集成到數據管道中。首先&#xff0c;創建Dagster資產subprocess_asset&#xff0c;利用PipesSubprocessClient資源執行外部腳本external_code.py&#xff0c;實現跨進程…

【SQL系列】多表關聯更新

&#x1f49d;&#x1f49d;&#x1f49d;歡迎來到我的博客&#xff0c;很高興能夠在這里和您見面&#xff01;希望您在這里可以感受到一份輕松愉快的氛圍&#xff0c;不僅可以獲得有趣的內容和知識&#xff0c;也可以暢所欲言、分享您的想法和見解。 推薦:kwan 的首頁,持續學…

C++進階學習:STL常用容器--map/multimap容器

1. map 容器基本概念 map 中所有元素都是 pair pair 中第一個元素為 key &#xff08;鍵值&#xff09; 起到索引運用 第二個元素為 value&#xff08;實值&#xff09; 所有元素都會根據元素的鍵值自動排序 本質&#xff1a; map/multimap 屬于關聯式容器 底層結構是用二…

let,const,var關鍵字的區別

let,const,var關鍵字 let&#xff0c;const&#xff0c;var都存在變量提升 它們都存在變量提升但是稍微有點不同 var變量聲明會被提升到作用域的頂部&#xff0c;并且會被初始化為 undefinedlet 和 const&#xff1a;變量聲明也會被提升到作用域的頂部&#xff0c;但不會被初…