编译Android Ijkplayer以及问题

编译Android Ijkplayer以及问题

一、Linux 环境安装的程序

下载:

  1. git

    yum install git
    
  2. yasm

    yum install yasm
    
  3. ndk

    下载ndk ,推荐ndk 14 以上的

配置环境变量

配置ndk、sdk (交叉编译时需要查找头文件和库文件),打开/etc/profile 文件

vim /etc/profile

在文件末尾加上
export ANDROID_SDK=你的SDF安装路径
export ANDROID_NDK=/root/ndk/android-ndk-r14b  

NDK 的安装路径,使用14版本以上的会出问题,问题分析在后面,虽然能改,但是不太清楚内部有什么限制,所有还是老实的用14版本的

保存,然后执行 source /etc/profile 刷新环境变量

二、下载ijkplayer

git官网上的Build Android

git clone https://github.com/Bilibili/ijkplayer.git ijkplayer-android
cd ijkplayer-android
git checkout -B latest k0.8.8

./init-android.sh

cd android/contrib
./compile-ffmpeg.sh clean
./compile-ffmpeg.sh all

cd ..
./compile-ijk.sh all

github 下载慢,可以在码云上搜ijkplayer,然后下载下来,这里提供一个地址

git clone https://gitee.com/mirrors/ijkplayer.git ijkplayer-android

切换到最新分支:

git checkout -B latest k0.8.8

先不要执行 ./init-android.sh,如果你播放器需要支持rtp、tcp、rtsp等(具体自行谷歌),需要修改配置文件,如果不需要修改,跳过下面的步骤1

1、 config 目录性有四个文件

image-20200911113704739

三个module-...开头的文件就是配置文件,其实里面就是定义一些变量(如下图),用于开启或关闭支持库,默认使用的module-default.sh,如果能看懂就可以自行开启或者关闭,看不懂就老实用module-default.sh

其中module.sh 文件可以理解为指向其他文件的文件,编译时,脚本文件不清楚你使用三个配置文件的哪个文件,所以使用linux 命令

ln -s module-default.sh module.sh

来指定module.sh 链接到module-default.sh文件,当然也可以

ln -s module-lite-hevc.sh module.sh
ln -s module-lite.sh module.sh
来链接到其他文件,反正脚本文件执行时执行的是module.sh脚本文件

2、 如果直接执行 init-android.sh 文件,会从github 上拉取 armv5 、armv7、arm64、x86、x86_64 架构的源码,这里我只需要armv7a 的,所有其他的都关了,如果需要可以自行打开

#IJK_FFMPEG_UPSTREAM=https://github.com/Bilibili/FFmpeg.git
#IJK_FFMPEG_FORK=https://github.com/Bilibili/FFmpeg.git

IJK_FFMPEG_UPSTREAM=https://gitee.com/yuazhen/FFmpeg.git
IJK_FFMPEG_FORK=https://gitee.com/yuazhen/FFmpeg.git

IJK_FFMPEG_COMMIT=ff3.4--ijk0.8.7--20180103--001
IJK_FFMPEG_LOCAL_REPO=extra/ffmpeg

set -e
TOOLS=tools

git --version

echo "== pull ffmpeg base =="
sh $TOOLS/pull-repo-base.sh $IJK_FFMPEG_UPSTREAM $IJK_FFMPEG_LOCAL_REPO

function pull_fork()
{
    echo "== pull ffmpeg fork $1 =="
    sh $TOOLS/pull-repo-ref.sh $IJK_FFMPEG_FORK android/contrib/ffmpeg-$1 ${IJK_FFMPEG_LOCAL_REPO}
    cd android/contrib/ffmpeg-$1
    git checkout ${IJK_FFMPEG_COMMIT} -B ijkplayer
    cd -
}

#pull_fork "armv5"
pull_fork "armv7a"
#pull_fork "arm64"
#pull_fork "x86"
#pull_fork "x86_64"

./init-config.sh
./init-android-libyuv.sh
./init-android-soundtouch.sh

因为拉取代码也是在github 上获取的,这里修改了下载源码路径

#IJK_FFMPEG_UPSTREAM=https://github.com/Bilibili/FFmpeg.git
#IJK_FFMPEG_FORK=https://github.com/Bilibili/FFmpeg.git

IJK_FFMPEG_UPSTREAM=https://gitee.com/yuazhen/FFmpeg.git
IJK_FFMPEG_FORK=https://gitee.com/yuazhen/FFmpeg.git

init-android.sh 里面也会去下载libyuv soundtouch库的代码,这两个库不大,所以可以不用修改下载地址,执行 init-android.sh 文件

./init-android.sh

完成后进入到 android/contrib 目录

cd android/contrib

接下来开始编译下载的ffmpeg 库,首先先清理

./compile-ffmpeg.sh clean

因为只下载了armv7a ,编译ffmpeg 不能编译全部,这里只编译 armv7a的(如果是多架构编译看后文)

./compile-ffmpeg.sh armv7a

(这里可能会因为ndk 版本问题编译出错,具体修改看后面问题)

执行完之后 就会在 ../ijkplayer-android/android/contrib/build/ffmpeg-armv7a/output 目录下生成ffmpeg 的头文件和库文件

image-20200911140429954

以上的都是编译ijkplayer 所需要的东西,接下来才是真正编译ijkplayer

这里只下载了armv7a,所有只编译armv7a的

返回上一层目录

cd ..
./compile-ijk.sh armv7a

成功后会在/ijkplayer/ijkplayer-android/android/ijkplayer 目录下对应的cpu 架构生成ijkplayer的动态库文件,so 文件是放在对应架构的 ../src/main/libs/armeabi-v7a

image-20200911141237983
image-20200911141313915

ijkplayer-example 就是示例项目代码

三、编译遇到的问题

1、You need the NDKr10e or later

在执行 ./compile-ffmpeg.sh armv7a 的时候

如果ndk版本大于 14,会报:

image-20200911141645858

以下是分析原因,如果看结果直接略过

打开 comfile-ffmpeg.sh 文件,省略部分,主要内容:

case "$FF_TARGET" in
    "")
        echo_archs armv7a
        sh tools/do-compile-ffmpeg.sh armv7a
    ;;
    #这里这里
    armv5|armv7a|arm64|x86|x86_64)
        echo_archs $FF_TARGET $FF_TARGET_EXTRA
        sh tools/do-compile-ffmpeg.sh $FF_TARGET $FF_TARGET_EXTRA
        echo_nextstep_help
    ;;
    .
    .
    .
    .
    *)
        echo_usage
        exit 1
    ;;
esac

就是感觉传入进来的armv7a 字符匹配 ,然后执行

sh tools/do-compile-ffmpeg.sh $FF_TARGET $FF_TARGET_EXTRA

FF_TARGET 这里是传进来的armv7a 
FF_TARGET_EXTRA 这里没传进来,为空

就是执行
sh tools/do-compile-ffmpeg.sh armv7a

又去执行当前目录下tools包下的do-compile-ffmpeg.sh 文件,带个armv7a 参数进去;(真正的编译脚本不是comfile-ffmpeg.sh 而是do-compile-ffmpeg.sh ,所有单个文件也可以直接执行./tools/do-compile-ffmpeg.sh armv7a ,执行的目录还是在compile-ffmpeg.sh文件所在的目录)

image-20200911142324453

do-compile-ffmpeg.sh 内容的开头():

FF_ARCH=$1
FF_BUILD_OPT=$2
echo "FF_ARCH=$FF_ARCH"
echo "FF_BUILD_OPT=$FF_BUILD_OPT"
if [ -z "$FF_ARCH" ]; then
    echo "You must specific an architecture 'arm, armv7a, x86, ...'."
    echo ""
    exit 1
fi
.
.
设置各种变量
.
.

#--------------------
echo ""
echo "--------------------"
echo "[*] make NDK standalone toolchain"
echo "--------------------"
. ./tools/do-detect-env.sh
.
.
.

判断 FF_ARCH 参数是否空,如果为空就输出 "You must specific an architecture 'arm, armv7a, x86, ...'. 然后退出,

这里的 FF_ARCH 就是传进来的armv7a(这里讲废话了),有条命令. ./tools/do-detect-env.sh;

上面都是废话,可以不用看,细节而已,下面才是重要内容

在编译脚本之前会执行do-detect-env.sh 文件检查运行环境和NDK 版本

#! /usr/bin/env bash

set -e

UNAME_S=$(uname -s)
UNAME_SM=$(uname -sm)
echo "build on $UNAME_SM"

echo "ANDROID_NDK=$ANDROID_NDK"

if [ -z "$ANDROID_NDK" ]; then
    echo "You must define ANDROID_NDK before starting."
    echo "They must point to your NDK directories."
    echo ""
    exit 1
fi



# try to detect NDK version
export IJK_GCC_VER=4.9
export IJK_GCC_64_VER=4.9
export IJK_MAKE_TOOLCHAIN_FLAGS=
export IJK_MAKE_FLAG=
export IJK_NDK_REL=$(grep -o '^r[0-9]*.*' $ANDROID_NDK/RELEASE.TXT 2>/dev/null | sed 's/[[:space:]]*//g' | cut -b2-)
case "$IJK_NDK_REL" in
    10e*)
        # we don't use 4.4.3 because it doesn't handle threads correctly.
        if test -d ${ANDROID_NDK}/toolchains/arm-linux-androideabi-4.8
        # if gcc 4.8 is present, it's there for all the archs (x86, mips, arm)
        then
            echo "NDKr$IJK_NDK_REL detected"

            case "$UNAME_S" in
                Darwin)
                    export IJK_MAKE_TOOLCHAIN_FLAGS="$IJK_MAKE_TOOLCHAIN_FLAGS --system=darwin-x86_64"
                ;;
                CYGWIN_NT-*)
                    export IJK_MAKE_TOOLCHAIN_FLAGS="$IJK_MAKE_TOOLCHAIN_FLAGS --system=windows-x86_64"
                ;;
            esac
        else
            echo "You need the NDKr10e or later"
            exit 1
        fi
    ;;
    *)
        IJK_NDK_REL=$(grep -o '^Pkg\.Revision.*=[0-9]*.*' $ANDROID_NDK/source.properties 2>/dev/null | sed 's/[[:space:]]*//g' | cut -d "=" -f 2)
        echo "IJK_NDK_REL=$IJK_NDK_REL"
         #这里这里这里
        case "$IJK_NDK_REL" in
            11*|12*|13*|14*)
                if test -d ${ANDROID_NDK}/toolchains/arm-linux-androideabi-4.9
                then
                    echo "NDKr$IJK_NDK_REL detected"
                else
                    echo "You need the NDKr10e or later"
                    exit 1
                fi
            ;;
            *)
                echo "You need the NDKr10e or later"
                exit 1
            ;;
        esac
    ;;
esac


case "$UNAME_S" in
    Darwin)
        export IJK_MAKE_FLAG=-j`sysctl -n machdep.cpu.thread_count`
    ;;
    CYGWIN_NT-*)
        IJK_WIN_TEMP="$(cygpath -am /tmp)"
        export TEMPDIR=$IJK_WIN_TEMP/

        echo "Cygwin temp prefix=$IJK_WIN_TEMP/"
    ;;
esac

export IJK_NDK_REL=$(grep -o '^r[0-9]*.*' $ANDROID_NDK/RELEASE.TXT 2>/dev/null | sed 's/[[:space:]]*//g' | cut -b2-)

使用正则判断NDK的版本

如果NDK 版本是10e的,执行下面的

case "$IJK_NDK_REL" in
    10e*)

如果是其他的,执行

 case "$IJK_NDK_REL" in
            11*|12*|13*|14*) # 这里就是判断NDK 版本是不是11、12、13、14
     if test -d ${ANDROID_NDK}/toolchains/arm-linux-androideabi-4.9  #检查对应版本的是否存在
     这里只检查了 11*|12*|13*|14*四个版本的,不妨加上 17试试
     
      11*|12*|13*|14*|17*)

保存之后执行 ./compile-ffmpeg.sh armv7a ,接着又报:

image-20200911150506225

因为编译ffmpeg 使用的Android平台默认为 9,arm 平台最低为14,所以在do-comfile-ffmpeg.sh 文件中加入

FF_ANDROID_PLATFORM=android-24 #我这里的sdk 版本为24
.
.
.
#----- armv7a begin -----
if [ "$FF_ARCH" = "armv7a" ]; then
    #这里这里
    FF_ANDROID_PLATFORM=android-24

    FF_BUILD_NAME=ffmpeg-armv7a
    FF_BUILD_NAME_OPENSSL=openssl-armv7a
    FF_BUILD_NAME_LIBSOXR=libsoxr-armv7a
    FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME

    FF_CROSS_PREFIX=arm-linux-androideabi
    FF_TOOLCHAIN_NAME=${FF_CROSS_PREFIX}-${FF_GCC_VER}

    FF_CFG_FLAGS="$FF_CFG_FLAGS --arch=arm --cpu=cortex-a8"
    FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-neon"
    FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-thumb"

    FF_EXTRA_CFLAGS="$FF_EXTRA_CFLAGS -march=armv7-a -mcpu=cortex-a8 -mfpu=vfpv3-d16 -mfloat-abi=softfp -mthumb"
    FF_EXTRA_LDFLAGS="$FF_EXTRA_LDFLAGS -Wl,--fix-cortex-a8"

    FF_ASSEMBLER_SUB_DIRS="arm"
 elif [ "$FF_ARCH" = "armv5" ]; then
.
.
.

保存之后执行 ./compile-ffmpeg.sh armv7a

2、ERROR: Failed to create toolchain

在执行./compile-ffmpeg.sh armv7a 的时候有些系统会保存 Failed to create toolchain

这是因为linux 系统有些使用python版本 是python3(python2的我没试过)

可以使用rpm 命令检查python 版本

rpm -qa | grep python
image-20200911151733008

在执行do-compile-ffmpeg.sh 中会执行 NDK的 $ANDROID_NDK/build/tools/make-standalone-toolchain.sh文件

make-standalone-toolchain.sh 文件最后会运行python 脚本 make_standalone_toolchain.py

PLATFORM_NUMBER=${PLATFORM#android-}
if [ -n "$PLATFORM_NUMBER" ]; then
  PLATFORM_ARG="--api $PLATFORM_NUMBER"
else
  PLATFORM_ARG=""
fi
#修改前的
#run python `dirname $0`/make_standalone_toolchain.py \
#    --arch $ARCH $PLATFORM_ARG --stl $STL $INSTALL_ARG $FORCE_ARG
    
#修改后的
python3 `dirname $0`/make_standalone_toolchain.py \
    --arch $ARCH $PLATFORM_ARG --stl $STL $INSTALL_ARG $FORCE_ARG
    
fail_panic "Failed to create toolchain."

if [ -n "$INSTALL_DIR" ]; then
    dump "Toolchain installed to $INSTALL_DIR."
else
    dump "Package installed to $PACKAGE_DIR."
fi

如果是python3 版本就会报错,因为run python 命令运行不了python3的文件(.py),所以把run python改成

python3(python2没试过)

3、./compile-ijk.sh armv7a 报错

image-20200911153625596

在最后关键时刻,使用NDK 14b编译 ijkplayer 竟然不行,就感觉还没拉出来完,中间夹断了那么难受,最后是把NDK 版本改成 17的才可以

四、编译多架构

比如这里需要编译 armv7a 与arm64

首先init-android.sh 必须下载对应架构的源码

function pull_fork()
{
    echo "== pull ffmpeg fork $1 =="
    sh $TOOLS/pull-repo-ref.sh $IJK_FFMPEG_FORK android/contrib/ffmpeg-$1 ${IJK_FFMPEG_LOCAL_REPO}
    cd android/contrib/ffmpeg-$1
    git checkout ${IJK_FFMPEG_COMMIT} -B ijkplayer
    cd -
}

#pull_fork "armv5"
//下载armv7a 与arm64
pull_fork "armv7a"
pull_fork "arm64"
#pull_fork "x86"
#pull_fork "x86_64"

./init-config.sh
./init-android-libyuv.sh
./init-android-soundtouch.sh

接着修改compile-ffmpeg.sh 文件,FF_ACT_ARCHS_64 只保留armv7a 、arm64

.
.
.
#FF_ACT_ARCHS_32="armv5 armv7a x86"
#FF_ACT_ARCHS_64="armv5 armv7a arm64 x86 x86_64"

#这里是32位于64位,现在一般的都是64位
FF_ACT_ARCHS_32="armv7a"
FF_ACT_ARCHS_64="armv7a arm64"
FF_ACT_ARCHS_ALL=$FF_ACT_ARCHS_64
.
.
.

执行脚本时候使用的就是

./compile-ffmpeg.sh all

同样,接着修改compile-ijk.sh 文件 ACT_ABI_64 只保留armv7a 、arm64

.
.
.
REQUEST_TARGET=$1
REQUEST_SUB_CMD=$2
#ACT_ABI_32="armv5 armv7a x86"
#ACT_ABI_64="armv5 armv7a arm64 x86 x86_64"

ACT_ABI_32="armv7a"
ACT_ABI_64="armv7a arm64"
ACT_ABI_ALL=$ACT_ABI_64
UNAME_S=$(uname -s)
.
.
.

执行脚本时候使用的就是

./compile-ijk.sh all

你可能感兴趣的:(编译Android Ijkplayer以及问题)