首页 > 系统 > Android > 正文

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

2020-04-11 11:02:45
字体:
来源:转载
供稿:网友

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/bashNDK=/usr/local/android-ndk-r10dSYSROOT=$NDK/platforms/android-15/arch-arm/TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64function 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_FLAGmake cleanmakemake install}CPU=armPREFIX=$(pwd)/android/$CPU ADDI_CFLAGS="-marm"build_one

保存后执行

sudo chmod +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.haes.h   avutil.h   channel_layout.h error.h   hmac.h   mathematics.h parseutils.h  ripemd.h   timecode.hattributes.h  base64.h   common.h   eval.h   imgutils.h  md5.h   pixdesc.h  samplefmt.h  timestamp.haudio_fifo.h  blowfish.h  cpu.h   ffversion.h  intfloat.h  mem.h   pixelutils.h  sha.h   version.haudioconvert.h bprint.h   crc.h   fifo.h   intreadwrite.h motion_vector.h pixfmt.h   sha512.h   xtea.havassert.h  bswap.h   dict.h   file.h   lfg.h   murmur3.h  random_seed.h stereo3d.havconfig.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 pkgconfiglibavcodec.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.so、libavfilter.so、libavformat.so、libavutil.so、libswresample.so、libswscale.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:= libavcodecLOCAL_SRC_FILES:= lib/libavcodec-56.soLOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/includeinclude $(PREBUILT_SHARED_LIBRARY)  include $(CLEAR_VARS)LOCAL_MODULE:= libavformatLOCAL_SRC_FILES:= lib/libavformat-56.soLOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/includeinclude $(PREBUILT_SHARED_LIBRARY)  include $(CLEAR_VARS)LOCAL_MODULE:= libswscaleLOCAL_SRC_FILES:= lib/libswscale-3.soLOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/includeinclude $(PREBUILT_SHARED_LIBRARY)  include $(CLEAR_VARS)LOCAL_MODULE:= libavutilLOCAL_SRC_FILES:= lib/libavutil-54.soLOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/includeinclude $(PREBUILT_SHARED_LIBRARY)  include $(CLEAR_VARS)LOCAL_MODULE:= libavfilterLOCAL_SRC_FILES:= lib/libavfilter-5.soLOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/includeinclude $(PREBUILT_SHARED_LIBRARY)  include $(CLEAR_VARS)LOCAL_MODULE:= libswresampleLOCAL_SRC_FILES:= lib/libswresample-1.soLOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/includeinclude $(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-macosxndk.dir=/usr/local/bin/android-ndk-r10d

2、配置build.gradle
项目里面有两个build.gradle,一个在根目录下,一个在$ROOT_DIR/app/src下,我们要修改的是后者。
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、生成头文件
执行命令,注意路径要根据自己的情况更改。

复制代码 代码如下:

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

4、编写C文件
$ROOT_DIR/app/src/main/jni/ovsplayer.c内容如下:


 

#include <stdio.h>#include <stdlib.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) {  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(input_context, NULL);  int streamNum = input_context->nb_streams;   char wd[512];  sprintf(wd, "AVCODEC VERSION %u/n, streamNum[%d]"    , avcodec_version()    , streamNum    );  return (*env)->NewStringUTF(env, wd); }

5、编写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>

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 := ovsplayerLOCAL_LDLIBS := / -lm / -ljnigraphics / -landroid / -llog / -lz / LOCAL_SHARED_LIBRARIES := libavformat libavcodec libswscale libavutil 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/jniLOCAL_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_LDLIBS和LOCAL_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。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表