编译ffmpeg库

目录

环境

下载配置ndk工具

下载

配置ndk环境变量

下载ffmpeg库并解压

编写编译脚本

执行脚本编译ffmpeg

1. 编译x86-64时提示安装yasm

2. Linux中执行bash脚本报错/bin/bash^M: bad interpreter: No such file or directory

3. so链接错误

把编译好的库加入项目中

编写cmakelist.txt文件

目录结构

在工程build.gradle文件中,配置so库的目录


编译环境:ubantu 21

ndk版本:r25b

ffmepg版本:4.2.1

环境

下载配置ndk工具

下载

NDK 下载  |  Android NDK  |  Android Developers (google.cn)

解压   

unzip android-ndk-r25b-linux-x86_64.zip

配置ndk环境变量

# 打开配置文件
vim /etc/profile  
# 保存退出,更新一下环境变量
source /etc/profile
# 测试ndk环境是否配置成功
ndk-build

如果不 是显示“ndk-build not found”, 则说明你的ndk安装成功

下载ffmpeg库并解压

下载地址: http://ffmpeg.org/releases/ffmpeg-4.2.1.tar.bz2

#解压
tar -jxvf ffmpeg-4.2.1.tar.bz2

解压完成后,进入ffmpeg目录,修改configure文件。 在此文件,你可以选择要编译的模块。

由于编译出来的动态库文件名的版本号在.so之后(例如 “libavcodec.so.5.100.1”),而Android平台不能识别这样的文件名,所以需要修改这种文件名

# 跳到3717行,原来的变量为
#SLIBNAME_WITH_MAJOR='$(SLIBNAME).$(LIBMAJOR)'
#LIB_INSTALL_EXTRA_CMD='$$(RANLIB) "$(LIBDIR)/$(LIBNAME)"'
#SLIB_INSTALL_NAME='$(SLIBNAME_WITH_VERSION)'
#SLIB_INSTALL_LINKS='$(SLIBNAME_WITH_MAJOR) $(SLIBNAME)'


#将其修改成

SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB) "$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'
SLIB_INSTALL_LINKS='$(SLIBNAME)'

编写编译脚本

#!/bin/bash

NDK=/root/android/android-ndk-r25b
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64/
API=29

function build_android
{
echo "Compiling FFmpeg for $CPU"
./configure \
--prefix=$PREFIX \
--enable-neon \
--enable-hwaccels \
--enable-gpl \
--enable-postproc \
--enable-shared \
--enable-jni \
--disable-mediacodec \
--disable-decoder=h264_mediacodec \
--disable-static \
--disable-doc \
--disable-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" \
$ADDITIONAL_CONFIGURE_FLAG
make clean
make
make install
echo "The Compilation of FFmpeg for $CPU is completed"
}


#armv8-a
ARCH=arm64
CPU=armv8-a
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/llvm-
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-march=$CPU"
build_android



#armv7-a
ARCH=arm
CPU=armv7-a
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/llvm-
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-mfloat-abi=softfp -mfpu=vfp -marm -march=$CPU "
build_android



#x86
ARCH=x86
CPU=x86
CC=$TOOLCHAIN/bin/i686-linux-android$API-clang
CXX=$TOOLCHAIN/bin/i686-linux-android$API-clang++
SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/llvm-
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32"
build_android


#x86_64
ARCH=x86_64
CPU=x86-64
CC=$TOOLCHAIN/bin/x86_64-linux-android$API-clang
CXX=$TOOLCHAIN/bin/x86_64-linux-android$API-clang++
SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/llvm-
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-march=$CPU -msse4.2 -mpopcnt -m64 -mtune=intel"
build_android

执行脚本编译ffmpeg

# 进行脚本文件所在目录,执行脚本命令
./build.sh

错误解决方法

1. 编译x86-64时提示安装yasm

FFmpeg yasm/nasm not found or too old. Use --disable-yasm for a crippledbuild

yasm是汇编编译器,ffmpeg为了提高效率使用了汇编指令,如MMX和SSE等。

所以系统中未安装yasm时,就会报上面错误

解决:

# 安装最新的yasm
sudo apt-get install yasm


#或者不启用yasm,脚本里加上配置
./configure --disable-x86asm

2. Linux中执行bash脚本报错/bin/bash^M: bad interpreter: No such file or directory

原因:在windows上编译脚本文件,由于dos格式的文件行尾为^M$,unix格式的文件行尾为$,产生错误

解决:

#查看
cat -A xxx.sh
#替换
sed -i "s/\r//" build.sh

3. so链接错误

UnsatisfiedLinkError: dlopen failed: cannot locate symbol "ff_vp9_copy128_aarch64" 

解决:编译时打开neon

--enable-neon \

把编译好的库加入项目中

编写cmakelist.txt文件

cmake_minimum_required(VERSION 3.22.1)

project("myplayer")


# 引入ffmpeg文件
include_directories(include)


# 引入avcodec 
add_library(avcodec SHARED IMPORTED)
set_target_properties(avcodec PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/libs/${CMAKE_ANDROID_ARCH_ABI}/libavcodec.so)

# 引入avfilter 
add_library(avfilter SHARED IMPORTED)
set_target_properties(avfilter PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/libs/${CMAKE_ANDROID_ARCH_ABI}/libavfilter.so)

# 引入avformat 
add_library(avformat SHARED IMPORTED)
set_target_properties(avformat PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/libs/${CMAKE_ANDROID_ARCH_ABI}/libavformat.so)

# 引入avutil 
add_library(avutil SHARED IMPORTED)
set_target_properties(avutil PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/libs/${CMAKE_ANDROID_ARCH_ABI}/libavutil.so)

# 引入postproc 
add_library(postproc SHARED IMPORTED)
set_target_properties(postproc PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/libs/${CMAKE_ANDROID_ARCH_ABI}/libpostproc.so)

# 引入swresample 
add_library(swresample SHARED IMPORTED)
set_target_properties(swresample PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/libs/${CMAKE_ANDROID_ARCH_ABI}/libswresample.so)


# 引入swscale 
add_library(swscale SHARED IMPORTED)
set_target_properties(swscale PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/libs/${CMAKE_ANDROID_ARCH_ABI}/libswscale.so)


add_library(${CMAKE_PROJECT_NAME} SHARED
        native-lib.cpp)

target_link_libraries(
        ${CMAKE_PROJECT_NAME}

        avcodec
        avfilter
        avformat
        avutil
        postproc
        swresample
        swscale

        android
        log)

目录结构

在工程build.gradle文件中,配置so库的目录

    sourceSets {
        main {
            jni {
                srcDirs 'src\\main\\cpp\\libs'
            }
        }
    }

测试ffmpeg是否加入成功

#include <jni.h>
#include <string>
#include "Log.h"

extern "C" {
#include <libavutil/avutil.h>
}

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_myplayer_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++";


    int v = avutil_version();
    LOGE("avutil_version()=%d", v);

    return env->NewStringUTF(hello.c_str());
}

  • 23
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值