1.FFmpeg官方网站http://www.ffmpeg.org/ 下载源代码.
2.安装NDK,网上有方法,我直接用AndroidStudio下载的:/home/sheldon/Android/Sdk/ndk-bundle/
3.修改configure,将生成lib的版本号置于.so之前,以防Android无法加载:
#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)‘
VERSION_SCRIPT_POSTPROCESS_CMD="cat"
4.编写build_android.sh脚本文件,如果从网上直接copy过去可能会是dos格式,使用dos2unix build_android.sh 转换一下,删掉多余空格:
#!/bin/bash
NDK=/home/sheldon/Android/Sdk/ndk-bundle/
SYSROOT=$NDK/platforms/android-24/arch-arm/
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
function build_one
{
./configure \
--prefix=$PREFIX \
--enable-shared \
--disable-static \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--disable-doc \
--disable-symver \
--enable-small \
--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
5.增加执行权限,执行:
$chmod a+x build_android.sh
$./build_android.sh
-----------
6.创建Android工程使用lib:
(1)创建一个新的Android工程FFmpeg4android。
(2)在工程目录下创建jni文件夹,与java目录同级。
(3)在jni下创建prebuilt/armeabi目录,然后:
将上面编译生成的so文件放入到该目录下的armeabi目录;
将android/arm/include/下的所有头文件夹拷贝到该jni目录下.
(4)创建包含native方法的类,先在src/main/java/下创建 cn.ffmpegnative包,然后创建FFmpegNative.java类文件。主要包括加载so库文件和一个native测试方法两部分,其内容如下:
package cn.ffmpegnative;
public class FFmpegNative {
static{
System.loadLibrary("avcodec-57");
System.loadLibrary("libavdevice-57");
System.loadLibrary("avfilter-6");
System.loadLibrary("avformat-57");
System.loadLibrary("avutil-55");
System.loadLibrary("swresample-2");
System.loadLibrary("swscale-4");
System.loadLibrary("ffmpeg_codec");
}
public native int avcodec_find_decoder(int codecID);
}
(5)
用javah创建.头文件:
进入/FFmpeg4android/app/src/main/目录,执行:javah -jni cn.ffmpegnative.FFmpegNative
会在当前目录产生cn_ffmpegnative_FFmpegNative.h的C头文件;
(6)
根据头文件名,建立相同名字才C源文件cn_ffmpegnative_FFmpegNative.c
在这个源文件中实现头文件中定义的方法,核心部分代码如下:
/*
(1)JNIEXPORT :在Jni编程中所有本地语言实现Jni接口的方法前面都有一个"JNIEXPORT",这个可以看做是Jni的一个标志,至今为止没发现它有什么特殊的用处。
(2)void :这个学过编程的人都知道,当然是方法的返回值了。
(3)JNICALL :这个可以理解为Jni 和Call两个部分,和起来的意思就是 Jni调用XXX(后面的XXX就是JAVA的方法名)。
(4)Java_com_test01_Test_firstTest:这个就是被上一步中被调用的部分,也就是Java中的native 方法名,这里起名字的方式比较特别,是:包名+类名+方法名。
(5)JNIEnv * env:这个env可以看做是Jni接口本身的一个对象,在上一篇中提到的jni.h头文件中存在着大量被封装好的函数,这些函数也是Jni编程中经常被使用到的,要想调用这些函数就需要使用JNIEnv这个对象。例如:env->GetObjectClass()。(详情请查看jni.h)
(6)jobject obj:刚才在Test类的main方法中有这样一段代码:
*/
#include <string.h>
#include <stdio.h>
#include <android/log.h>
#include <stdlib.h>
#include <jni.h>
#include <libavcodec/avcodec.h>
#include <cn_ffmpegnative_FFmpegNative.h>
JNIEXPORT jint JNICALL Java_cn_ffmpegnative_FFmpegNative_test_1h264
(JNIEnv* env, jobject thiz,jint codecID)
{
AVCodec* codec = NULL;
av_register_all();//该函数在所有基于ffmpeg的应用程序中几乎都是第一个被调用的。只有调用了该函数,才能使用复用器,编码器等
codec = avcodec_find_decoder(codecID);//通过code ID查找一个已经注册的音视频编码器。H264的codecID是28,所以我们java那边传28下来如果检测到H264注册过了这边codec就不为空,返回0
if(codec != NULL)
{
return 0;
}else{
return -1;
}
}
(7)编写Android.mk,内容如下:
ifeq ($(APP_ABI), x86)
LIB_NAME_PLUS := x86
else
LIB_NAME_PLUS := armeabi
endif
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE:= avcodec-prebuilt-$(LIB_NAME_PLUS)
LOCAL_SRC_FILES:= prebuilt/$(LIB_NAME_PLUS)/libavcodec-57.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE:= avdevice-prebuilt-$(LIB_NAME_PLUS)
LOCAL_SRC_FILES:= prebuilt/$(LIB_NAME_PLUS)/libavdevice-57.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE:= avfilter-prebuilt-$(LIB_NAME_PLUS)
LOCAL_SRC_FILES:= prebuilt/$(LIB_NAME_PLUS)/libavfilter-6.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE:= avformat-prebuilt-$(LIB_NAME_PLUS)
LOCAL_SRC_FILES:= prebuilt/$(LIB_NAME_PLUS)/libavformat-57.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := avutil-prebuilt-$(LIB_NAME_PLUS)
LOCAL_SRC_FILES := prebuilt/$(LIB_NAME_PLUS)/libavutil-55.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := swresample-prebuilt-$(LIB_NAME_PLUS)
LOCAL_SRC_FILES := prebuilt/$(LIB_NAME_PLUS)/libswresample-2.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := swscale-prebuilt-$(LIB_NAME_PLUS)
LOCAL_SRC_FILES := prebuilt/$(LIB_NAME_PLUS)/libswscale-4.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libffmpegjni
ifeq ($(APP_ABI), x86)
TARGET_ARCH:=x86
TARGET_ARCH_ABI:=x86
else
LOCAL_ARM_MODE := arm
endif
LOCAL_SRC_FILES := cn_ffmpegnative_FFmpegNative.c
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog -lz
LOCAL_SHARED_LIBRARIES:= avcodec-prebuilt-$(LIB_NAME_PLUS) \
avdevice-prebuilt-$(LIB_NAME_PLUS) \
avfilter-prebuilt-$(LIB_NAME_PLUS) \
avformat-prebuilt-$(LIB_NAME_PLUS) \
avutil-prebuilt-$(LIB_NAME_PLUS) \
swresample-prebuilt-$(LIB_NAME_PLUS) \
swscale-prebuilt-$(LIB_NAME_PLUS)
LOCAL_C_INCLUDES += -L$(SYSROOT)/usr/include
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
ifeq ($(APP_ABI), x86)
LOCAL_CFLAGS := -DUSE_X86_CONFIG
else
LOCAL_CFLAGS := -DUSE_ARM_CONFIG
endif
include $(BUILD_SHARED_LIBRARY)
(8) 编写Application.mk[可省略]
编译so文件:
打开cmd命令行,进入FFmpeg4Android\jni目录下,执行如下命令:
ndk-build
截止本步骤完成,将在FFmpeg4Android根目录下生成libs\armeabi目录,该目录除了包含上面的7个so之外,另外还生成了libffmpeg_codec.so文件。
(9)修改layout/main.xml,给TextView增加id,以便在代码中操作它:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:id="@+id/textview_hello"
android:text="@string/hello"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
/>
</LinearLayout>
(10)增加一个Activity实现类FFmpeg4AndroidActivity,在OnCreate方法中调用native函数将值传给TextView控件,打包运行即可。FFmpeg4AndroidActivity代码如下:
package cn.ffmpegnative;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class FFmpeg4AndroidActivity extends Activity {
@Override
protectedvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextViewtv = (TextView)this.findViewById(R.id.textview_hello);
FFmpegNativeffmpeg = new FFmpegNative();
intcodecID = 28; //28 is the H264 Codec ID
intres = ffmpeg.avcodec_find_decoder(codecID);
if(res ==0) {
tv.setText("Success!");
}
else{
tv.setText("Failed!");
}
}
}
代码中的28是H264的编解码ID,可以在ffmpeg的源代码中找到,它是枚举类型定义的。在C语言中,可以换算为整型值。这里测试能否找到H264编解码,如果能找到,说明调用ffmpeg的库函数是成功的,这也表明我们编译的so文件是基本可用。
原文:http://www.cnblogs.com/blogs-of-lxl/p/6252130.html