白嫖ijkplayer

2020-11-11 17:38:49 浏览数 (1)

我们要引入ijkplayer播放器的时候,发现一个小小的缺陷就是so库太大了,一般有3个so库:

代码语言:javascript复制
jeffmony@JeffMonydeMacBook-Pro arm64-v8a % ls -hl
total 21240
-rwxr-xr-x  1 jeffmony  staff   9.6M  4 30 00:25 libijkffmpeg.so
-rwxr-xr-x  1 jeffmony  staff   348K  4 30 00:25 libijkplayer.so
-rwxr-xr-x  1 jeffmony  staff   474K  4 30 00:25 libijksdl.so

其中一个libijkffmpeg.so库非常大,有近9.6M,这个非常吓人了,当然你可以裁剪一些不用的库。

但是ijkplayer毕竟只是播放视频才用到的。但是ijkplayer底层是基于ffmpeg的ffplay播放框架,也就是说ffmpeg也集成到了libijkffmpeg.so中了。

这就有点意思了,那我们需要引用ffmpeg中的一些方法就不用额外的编译库了,直接使用libijkffmpeg.so中的文件就可以的。

  • 1.节省了空间大小,防止重复编译ffmpeg导致的包体积增大。
  • 2.native接口不用和ijkplayer的上层写在一起,可以单独写,完全不影响。

看一下这个提交: https://github.com/JeffMony/PlayerSDK/commit/af1482d1842583772702a953d4612ae50d9a5631

  • 1.复用libijkffmpeg.so
  • 2.引入ffmpeg头文件
  • 3.编译生成新的so
1.FFmpeg头文件如何生成

具体的build_ffmpeg.sh如下:

代码语言:javascript复制
#!/bin/bash
export NDK_ROOT=/Users/jeffmony/tools/android-ndk-r14b # 修改自己本地的ndk路径

build() {
API=24
ARCH=$1
PLATFORM=$2
SYSROOT=$NDK_ROOT/platforms/android-$API/arch-$ARCH/
CROSS_PREFIX=$NDK_ROOT/toolchains/$PLATFORM-4.9/prebuilt/darwin-x86_64/bin/$PLATFORM-
PREFIX=$(pwd)/android/$ARCH #自己指定一个输出目录
rm -rf $(pwd)/android/$ARCH

echo "开始编译ffmpeg $ARCH so"
./configure 
--prefix=$PREFIX 
--disable-doc 
--enable-shared 
--disable-static 
--disable-x86asm 
--disable-asm 
--disable-symver 
--disable-devices 
--disable-avdevice 
--enable-gpl 
--disable-ffmpeg 
--disable-ffplay 
--disable-ffprobe 
--enable-small 
--enable-cross-compile 
--cross-prefix=$CROSS_PREFIX 
--target-os=android 
--arch=$ARCH 
--sysroot=$SYSROOT
}

# build armv7a
build arm arm-linux-androideabi
make clean
make -j4
make install

echo "完成ffmpeg $ARCH 编译..."


# build armv8a
build arm64 aarch64-linux-android
make clean
make -j4
make install

echo "完成ffmpeg $ARCH 编译..."

生成的目录中./android/arm/include 就是头文件

2.如何复用libijkffmpeg.so

主要的操作步骤如下:

  • 新建一个cpp文件夹,将include文件夹拷贝到cpp下面
  • 新建CMakeLists.txt和jeffmony.cpp,jeffmony.cpp就是自定义的native方法
  • 修改build.gradle编译

build.gradle修改如下:

CMakeLists.txt修改如下:

代码语言:javascript复制
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

## libijkffmpeg.so
add_library(ffmpeg SHARED IMPORTED)
set_target_properties(ffmpeg PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libijkffmpeg.so)

include_directories(./include)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
        jeffmony

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        jeffmony.cpp)

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
        log-lib

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log)

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
        jeffmony
        ffmpeg
        # Links the target library to the log library
        # included in the NDK.
        ${log-lib})

编译运行,生成了一个libjeffmony.so库。

具体的项目代码见:https://github.com/JeffMony/PlayerSDK

3.修改ffmpeg库链接顺序

使用libijkffmpeg.so运行的时候总是发现有一些库函数找不到, 例如:

代码语言:javascript复制
/home/jeffmony/github/PlayerSDK/ijkplayer/src/main/cpp/jeffmony.cpp:58: error: undefined reference to 'av_mallocz_array'

出现以上错误,基本上是链接库文件时出了问题,而且链接库文件时需要按照一定的顺序来链接,上层库需要放在底层库的左边,比如 libavcodec 库调用了 libavutil 库中的 av_log() 函数, 那么链接时 libavcodec 库需要放在 libavutil 库的左边,这样链接时才能正常,可以参考如下链接顺序:

代码语言:javascript复制
-lavdevice -lavfilter -lavformat -lavcodec -lavutil

ijkplayer中的对ffmpeg库链接的地方在android/contrib/tools/do-compile-ffmpeg.sh

代码语言:javascript复制
ln -s $FF_PREFIX/include $FF_PREFIX/shared/include
ln -s $FF_PREFIX/libijkffmpeg.so $FF_PREFIX/shared/lib/libijkffmpeg.so
cp $FF_PREFIX/lib/pkgconfig/*.pc $FF_PREFIX/shared/lib/pkgconfig
for f in $FF_PREFIX/lib/pkgconfig/*.pc; do
    # in case empty dir
    if [ ! -f $f ]; then
        continue
    fi
    cp $f $FF_PREFIX/shared/lib/pkgconfig
    f=$FF_PREFIX/shared/lib/pkgconfig/`basename $f`
    # OSX sed doesn't have in-place(-i)
    mysedi $f 's//output//output/shared/g'
    mysedi $f 's/-lavcodec/-lijkffmpeg/g'
    mysedi $f 's/-lavfilter/-lijkffmpeg/g'
    mysedi $f 's/-lavformat/-lijkffmpeg/g'
    mysedi $f 's/-lavutil/-lijkffmpeg/g'
    mysedi $f 's/-lswresample/-lijkffmpeg/g'
    mysedi $f 's/-lswscale/-lijkffmpeg/g'
done

调整一下链接顺序, 将libavformat libavcodec libavutil依次放在最后, 这样得到的libijkffmpeg.so就是链接正确的库, 可以正常使用了

  • 音视频开发中使用ffmpeg的地方非常多, 播放场景/音视频编辑场景, 其中都会使用到ffmpeg核心模块, 本文的介绍就是告诉大家, 我们可以将不同的功能模块封在同一个ffmpeg库中, 帮我们节省空间

0 人点赞