Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Mac OS下為Android Studio編譯FFmpeg解碼庫的詳細教程

Mac OS下為Android Studio編譯FFmpeg解碼庫的詳細教程

編輯:關於Android編程

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 +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.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:= 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下,我們要修改的是後者。
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 := ovsplayer
LOCAL_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/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_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。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved