Mac OS下为Android Studio编译FFmpeg解码库的详细教程

这篇文章主要介绍了Mac OS下为Android Studio编译FFmpeg解码库的详细教程,包括NDK的配置和Android Studio的配置两个部分的内容,需要的朋友可以参考下

本文转载自 Mac OS下为Android Studio编译FFmpeg解码库的详细教程 陈钢。修正了部分小错误,实测可行。

NDK部分

1、 下载ndk

这里就一笔带过了。

2、 解压ndk

不要解压,文件权限会出错。执行之,会自动解压,然后mv到想放的地方。我放到了/usr/local/bin/android-ndk-r10d(此目录之后用$NDK_DIR指代)。

3、 下载Ffmpeg

我下的是2.5.3版本。

4、 解压Ffmpeg

解压Ffmpeg到$NDK_DIR/sources/ffmpeg-2.5.3

5、 修改Ffmpeg编译配置

ffmpeg-2.5.3目录下把configure文件中的这几行,目的是去掉默认生成的库名字libavcodec.so.55最后那个55的版本号。

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)’

6、 编译Ffmpeg

ffmpeg-2.5.3目录下创建文件build_android.sh
注意前三行要按照自己的路径正确配置。

#!/bin/bash
NDK=/usr/local/android-ndk-r10d
SYSROOT=$NDK/platforms/android-15/arch-arm/
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
function build_one
{
./configure \
–prefix=$PREFIX \
–enable-shared \
–disable-static \
–disable-doc \
–disable-ffmpeg \
–disable-ffplay \
–disable-ffprobe \
–disable-ffserver \
–disable-avdevice \
–disable-doc \
–disable-symver \
–cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
–target-os=linux \
–arch=arm \
–enable-cross-compile \
–sysroot=$SYSROOT \
–extra-cflags=”-Os -fpic $ADDI_CFLAGS” \
–extra-ldflags=”$ADDI_LDFLAGS” \
$ADDITIONAL_CONFIGURE_FLAG
make clean
make
make install
}
CPU=arm
PREFIX=$(pwd)/android/$CPU
ADDI_CFLAGS=”-marm”
build_one

保存后执行
sudo chmod a+x build_android.sh
./build_android.sh
编译会花上一段时间。

7、 查看编译结果

编译完成后$NDK_DIR/sources/ffmpeg-2.5.3下面会多出一个android目录,里面就是我们想要的编译好的库。

[cg@local]# ls -R android/

arm

android//arm:
Android.mk include lib

android//arm/include:
libavcodec libavfilter libavformat libavutil libswresample libswscale

android//arm/include/libavcodec:
avcodec.h avfft.h dv_profile.h dxva2.h old_codec_ids.h vaapi.h vda.h vdpau.h version.h vorbis_parser.h xvmc.h

android//arm/include/libavfilter:
asrc_abuffer.h avcodec.h avfilter.h avfiltergraph.h buffersink.h buffersrc.h version.h

android//arm/include/libavformat:
avformat.h avio.h version.h

android//arm/include/libavutil:
adler32.h avstring.h cast5.h downmix_info.h hash.h macros.h opt.h replaygain.h time.h
aes.h avutil.h channel_layout.h error.h hmac.h mathematics.h parseutils.h ripemd.h timecode.h
attributes.h base64.h common.h eval.h imgutils.h md5.h pixdesc.h samplefmt.h timestamp.h
audio_fifo.h blowfish.h cpu.h ffversion.h intfloat.h mem.h pixelutils.h sha.h version.h
audioconvert.h bprint.h crc.h fifo.h intreadwrite.h motion_vector.h pixfmt.h sha512.h xtea.h
avassert.h bswap.h dict.h file.h lfg.h murmur3.h random_seed.h stereo3d.h
avconfig.h buffer.h display.h frame.h log.h old_pix_fmts.h rational.h threadmessage.h

android//arm/include/libswresample:
swresample.h version.h

android//arm/include/libswscale:
swscale.h version.h

android//arm/lib:
libavcodec-56.so libavfilter-5.so libavformat-56.so libavutil-54.so libswresample-1.so libswscale-3.so pkgconfig
libavcodec.so libavfilter.so libavformat.so libavutil.so libswresample.so libswscale.so

android//arm/lib/pkgconfig:
libavcodec.pc libavfilter.pc libavformat.pc libavutil.pc libswresample.pc libswscale.pc

其中libavcodec.solibavfilter.solibavformat.solibavutil.solibswresample.solibswscale.so都是软链,没有用,可以删掉。
8、给Ffmpeg库写Android.mk使其可用
创建\$NDK_DIR/sources/ffmpeg-2.5.3/android/arm/Android.mk文件,内容如下:
要注意其中.so前面的数字应该改成你的ffmpeg版本编译出来的数字。

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE:= libavcodec
LOCAL_SRC_FILES:= lib/libavcodec-56.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE:= libavformat
LOCAL_SRC_FILES:= lib/libavformat-56.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE:= libswscale
LOCAL_SRC_FILES:= lib/libswscale-3.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE:= libavutil
LOCAL_SRC_FILES:= lib/libavutil-54.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE:= libavfilter
LOCAL_SRC_FILES:= lib/libavfilter-5.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE:= libswresample
LOCAL_SRC_FILES:= lib/libswresample-1.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)

至此ndk配置完毕,后面是配置Android Studio的部分。

Android Studio部分

Android Studio和Eclipse不太一样,它有一定的自动生成Android.mk并自动搞定JNI的能力。
但目前还并不足以让我们使用起来Ffmpeg库。
因此我们的思路是禁用掉Android Studio自动ndk-build的功能,手动编译我们的C代码达到目的。
首先当然要新建一个Android Studio项目。
我们使用$ROOT_DIR指代项目根目录。

1、 Android Studio配置ndk路径

$ROOT_DIR/local.properties原先只配置了sdk。

sdk.dir=/usr/local/bin/android-sdk-macosx

给它增加一行ndk的配置

sdk.dir=/usr/local/bin/android-sdk-macosx
ndk.dir=/usr/local/bin/android-ndk-r10d

2、 配置build.gradle

项目里面有两个build.gradle,一个在根目录下,一个在$ROOT_DIR/app/src下,我们要修改的是后者(module的build.gradle)。
A>添加这一段以禁用自动ndk-build。

sourceSets.main.jni.srcDirs = []

B>添加这一段让它知道用库

ndk {
abiFilter “armeabi”
moduleName “ovsplayer”
ldLibs “log”, “z”, “m”, “jnigraphics”, “android”
}

修改后的build.gradle是这样的。

android {
 compileSdkVersion 21
 buildToolsVersion "21.1.1"

 sourceSets.main.jni.srcDirs = [] // 禁用自动执行ndk-build
 defaultConfig {
  applicationId "com.example.chengang.myapplication"
  minSdkVersion 15
  targetSdkVersion 21
  versionCode 1
  versionName "1.0"
  ndk {
   abiFilter "armeabi"
   moduleName "ovsplayer" // 这个是C文件的名字
   ldLibs "log", "z", "m", "jnigraphics", "android"
  }
 }
 buildTypes {
  release {
   minifyEnabled false
   proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
  }
 }
}

3、 编写Java文件

$ROOT_DIR/app/src/main/java/com/example/chengang/myapplication/MainActivity.java内容如下。
其中getStringFromNative()方法是我们实现的,打印了Ffmpeg库的版本号(我编译的这个是3673444)和视频文件的信息出来。

package com.example.chengang.myapplication;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;


public class MainActivity extends ActionBarActivity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  TextView view = (TextView) findViewById(R.id.mytext);
  view.setText(this.getStringFromNative());
 }


 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.menu_main, menu);
  return true;
 }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  // Handle action bar item clicks here. The action bar will
  // automatically handle clicks on the Home/Up button, so long
  // as you specify a parent activity in AndroidManifest.xml.
  int id = item.getItemId();

  //noinspection SimplifiableIfStatement
  if (id == R.id.action_settings) {
   return true;
  }

  return super.onOptionsItemSelected(item);
 }

 public native String getStringFromNative();
 static {
  System.loadLibrary("swresample-1");
  System.loadLibrary("avutil-54");
  System.loadLibrary("avformat-56");
  System.loadLibrary("avcodec-56");
  System.loadLibrary("swscale-3");
  System.loadLibrary("ovsplayer");
 }
}


附上布局文件是这样的。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
 android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
 android:paddingRight="@dimen/activity_horizontal_margin"
 android:paddingTop="@dimen/activity_vertical_margin"
 android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

 <TextView
  android:id="@+id/mytext"
  android:text="@string/hello_world" android:layout_width="wrap_content"
  android:layout_height="wrap_content" />

</RelativeLayout>

4、 生成头文件

执行命令,注意路径要根据自己的情况更改。
复制代码 代码如下:

javah -d jni -classpath ….\build\intermediates\classes\debug com.example.nativeapp.app.MainActivity

会生成这个文件$ROOT_DIR/app/src/main/jni/com_example_chengang_myapplication_MainActivity.h

5、 编写C文件

$ROOT_DIR/app/src/main/jni/ovsplayer.c内容如下:

#include <stdio.h>
#include <stdlib.h>
#include <android/log.h>

#include "com_example_chengang_myapplication_MainActivity.h"
#include "libavutil/avutil.h"
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"


JNIEXPORT jstring JNICALL Java_com_example_chengang_myapplication_MainActivity_getStringFromNative
 (JNIEnv * env , jobject obj)
 {
  __android_log_print(ANDROID_LOG_ERROR,"!!!","this is in C!");
  const char *url = "/mnt/sdcard/1.mp4";
  av_register_all();

  AVFormatContext *pFormatCtx = NULL;
  int ret = avformat_open_input(&pFormatCtx, url, NULL, NULL);

  ret = avformat_find_stream_info(pFormatCtx, NULL);
  int streamNum = pFormatCtx->nb_streams;

  char wd[512];
  sprintf(wd, "AVCODEC VERSION %u\n, streamNum[%d]"
    , avcodec_version()
    , streamNum
    );
  return (*env)->NewStringUTF(env, wd);
 }

6、 编写项目Android.mk

Android.mk放到$ROOT_DIR/app/build/intermediates/ndk/debug/下。
注意其中的绝对路径/Users/chengang/Code/Android/MyApplication4是咱们的$ROOT_DIR

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE := ovsplayer
LOCAL_LDLIBS := \
-lm \
-ljnigraphics \
-landroid \
-llog \
-lz \

LOCAL_SHARED_LIBRARIES := libavformat libavcodec libswscale libavutil libswresample

LOCAL_SRC_FILES := \
/Users/chengang/Code/Android/MyApplication4/app/src/main/jni/ovsplayer.c \

LOCAL_C_INCLUDES += /Users/chengang/Code/Android/MyApplication4/app/src/main/jni
LOCAL_C_INCLUDES += /Users/chengang/Code/Android/MyApplication4/app/src/debug/jni

include $(BUILD_SHARED_LIBRARY)
$(call import-module,ffmpeg-2.5.3/android/arm)

简单说下LOCAL_LDLIBSLOCAL_SHARED_LIBRARIES的区别,前者链接系统库,后者链接第三方库。
并不能换着用。

7、 编译C代码

在终端下执行这个命令编译C代码。
复制代码 代码如下:

/usr/local/bin/android-ndk-r10d/ndk-build NDK_PROJECT_PATH=null APP_BUILD_SCRIPT=/Users/chengang/Code/Android/MyApplication4/app/build/intermediates/ndk/debug/Android.mk APP_PLATFORM=android-21 NDK_OUT=/Users/chengang/Code/Android/MyApplication4/app/build/intermediates/ndk/debug/obj NDK_LIBS_OUT=/Users/chengang/Code/Android/MyApplication4/app/build/intermediates/ndk/debug/lib APP_ABI=armeabi

8、 运行项目

回到Android Studio中Ctrl+R运行项目。
会看到手机上打印出Ffmpeg库的版本号(我编译的这个是3673444)和视频文件的信息出来。
Ffmpeg库已经可以调用了,然后继续写自己的逻辑就好了。

9、 另外

另外说两个C代码中可能遇见的错误:
A>如果你通过标准库想得到文件大小,又写错了文件名。安卓上,在不存在的文件的句柄上执行fseek会报如下错误:”could not disable core file generation.”
B>如果avformat_open_input()返回-1330794744了。那有两种可能,一是你忘记调用av_register_all()了,二是编译Ffmpeg的时候没有编译进对应的DEMUXER或者指定了disable-everything

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在 Android Studio 中使用 FFmpeg 的 so ,可以按照以下步骤进行操作: 1. 将 FFmpeg 的 so 添加到项目中: 将 FFmpeg 的 so 文件拷贝到项目的 `src/main/jniLibs` 目录下,其中 `src/main` 是项目的主目录,`jniLibs` 是自己创建的目录,用于存放 JNI 动态文件。 2. 在 build.gradle 中配置 ndk 和 sourceSets: 在 `build.gradle` 文件中添加以下配置: ``` android { ... defaultConfig { ... ndk { // 指定支持的 CPU 架构 abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' } } sourceSets { main { jniLibs.srcDirs = ['src/main/jniLibs'] } } } ``` 3. 创建 JNI 接口: 在项目的 `src/main/java` 目录下创建一个 Java 类,用于实现 JNI 接口。例如,可以创建一个名为 `FFmpegJNI` 的类,其中包含以下代码: ``` public class FFmpegJNI { static { System.loadLibrary("ffmpeg"); } public static native String avcodecConfiguration(); } ``` 其中,`System.loadLibrary("ffmpeg")` 用于加载 FFmpeg 的 so ,`avcodecConfiguration()` 方法是 JNI 接口中的一个方法,用于获取 FFmpeg 的配置信息。 4. 生成 JNI 头文件: 在终端中进入项目的 `src/main/java` 目录下,执行以下命令: ``` javac FFmpegJNI.java javah -jni FFmpegJNI ``` 这些命令将生成一个名为 `FFmpegJNI.h` 的文件,其中包含 JNI 接口的声明。 5. 编写 JNI 实现: 在项目的 `src/main/jni` 目录下创建一个名为 `FFmpegJNI.cpp` 的文件,用于实现 JNI 接口。例如,可以创建以下代码: ``` #include <jni.h> #include <string> #include "FFmpegJNI.h" #include "libavcodec/avcodec.h" extern "C" JNIEXPORT jstring JNICALL Java_com_example_ffmpegtest_FFmpegJNI_avcodecConfiguration(JNIEnv *env, jclass clazz) { std::string result; result += "AVCodec configuration: "; result += avcodec_configuration(); return env->NewStringUTF(result.c_str()); } ``` 其中,`avcodec_configuration()` 方法是 FFmpeg 中的一个方法,用于获取编解码器的配置信息。 6. 编译项目: 在终端中进入项目的根目录,执行以下命令: ``` ./gradlew assembleDebug ``` 这个命令将编译项目,并在 `build/outputs/apk` 目录下生成一个名为 `app-debug.apk` 的文件。 7. 运行项目: 将生成的 apk 文件安装到 Android 设备上,并运行项目。在项目中调用 `FFmpegJNI.avcodecConfiguration()` 方法,即可获取 FFmpeg 的编解码器配置信息。 注意:在 Android 6.0 及以上的版本中,需要动态获取权限才能使用 JNI 动态文件。可以使用 ActivityCompat.requestPermissions() 方法或者在 AndroidManifest.xml 文件中声明权限。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值