Ubuntu编译android版ffmpeg

准备材料:ffmpeg源码,NDK环境

去ffmpeg官网下载ffmpeg源码。我的为ffmpeg-2.6.2。进入ffmpeg的目录。编写编译脚本文件android_ffmpeg.sh.内容如下

NDK=/home/hxl/bin/android-ndk-r10d 
SYSROOT=$NDK/platforms/android-9/arch-arm/  
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64  
  
function build_one  
{  
./configure \
    --prefix=$PREFIX \
	--enable-nonfree \
	--enable-shared \
    --enable-gpl \
    --enable-static \
    --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 -j$THREAD_COUNT
make install
}  
CPU=arm  
PREFIX=$(pwd)/android/$CPU  
ADDI_CFLAGS="-marm"  
build_one 

注意将NDK_ROOT换为你自己的路径。

然后chmod 777 android_ffmpeg.sh 给该文件添加权限。最后执行./android_ffmpeg.sh 就进行编译了。编译完成后进入ffmpeg目录你会发现多出来一个android文件夹,在android/arm/lib下面就是编译出来的.a的静态库和.so的分享库。我的编译过程也是参考网上的给出的编译脚本代码完成的。需要注意的一点是如果直接copy脚本代码有可能会有一些格式上面的问题而导致编译失败。最后我会将脚本文件直接上传,有需要的可以下载。

参考网址:http://blog.csdn.net/gobitan/article/details/22750719

这样编出来的so包的名字存在像这样avcodec.so.54这样的文件,也存在不带数字的.so文件,android识别不出来。解决办法如下:

将ffmpeg的config文件的以下四行:

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

编译出来的就以.so结尾了,原来的avcodec.so.54这样的文件变为了avcodec.54.so这样的文件,但有点疑问的是在mk文件中引用的都是带数字的so包,使用不带数字的so包编译出来的会提示dlopen failed: could not load library "libavutil-54.so" needed by "libswresample.so"; caused by library "libavutil-54.so" not found 的error,都换为带数字的so文件时就可以正正确使用啦。不明白原因,有知道的希望能给留言赐教。


     现在写一个android项目测试下是否编译成功。

具体步骤仿照文章:

我贴下我的代码Android.mk文件

LOCAL_PATH := $(call my-dir)  
   
include $(CLEAR_VARS)  
LOCAL_MODULE :=avcodec-prebuilt  
LOCAL_SRC_FILES :=prebuilt/libavcodec-56.so  


include $(PREBUILT_SHARED_LIBRARY)  
   
include $(CLEAR_VARS)  
LOCAL_MODULE :=avdevice-prebuilt  
LOCAL_SRC_FILES :=prebuilt/libavdevice-56.so  


include $(PREBUILT_SHARED_LIBRARY)  
   
include $(CLEAR_VARS)  
LOCAL_MODULE :=avfilter-prebuilt  
LOCAL_SRC_FILES :=prebuilt/libavfilter-5.so  


include $(PREBUILT_SHARED_LIBRARY)  
   
include $(CLEAR_VARS)  
LOCAL_MODULE :=avformat-prebuilt  
LOCAL_SRC_FILES :=prebuilt/libavformat-56.so  


include $(PREBUILT_SHARED_LIBRARY)  


include $(CLEAR_VARS)  
LOCAL_MODULE :=swresample-prebuilt  
LOCAL_SRC_FILES :=prebuilt/libswresample-1.so  


include $(PREBUILT_SHARED_LIBRARY)  
   
include $(CLEAR_VARS)  
LOCAL_MODULE :=  avutil-prebuilt  
LOCAL_SRC_FILES :=prebuilt/libavutil-54.so  


include $(PREBUILT_SHARED_LIBRARY)  
   
include $(CLEAR_VARS)  
LOCAL_MODULE :=  postproc-prebuilt  
LOCAL_SRC_FILES :=prebuilt/libpostproc-53.so  


include $(PREBUILT_SHARED_LIBRARY)  
   
include $(CLEAR_VARS)  
LOCAL_MODULE :=  swscale-prebuilt  
LOCAL_SRC_FILES :=prebuilt/libswscale-3.so  


include $(PREBUILT_SHARED_LIBRARY)  
   
include $(CLEAR_VARS)  
   
LOCAL_MODULE :=ffmpeg_lily_codec  
LOCAL_SRC_FILES :=com_lily_testffmpeg_FFmpegExample.c \
	 


   
LOCAL_LDLIBS :=-llog -ljnigraphics -lz -landroid  
LOCAL_SHARED_LIBRARIES:= avcodec-prebuilt avdevice-prebuilt avfilter-prebuilt avformat-prebuilt avutil-prebuilt swscale-prebuilt swresample-prebuilt 
   
include $(BUILD_SHARED_LIBRARY)  

对于这段mk文件的解释,感谢:http://blog.csdn.net/smfwuxiao/article/details/8523479

I. 声明一个预编译库的模块

对于Android编译工具而言,每个预编译库必须声明为一个独立的模块。这里举一个例子,假设 libfoo.so 文件与 Android.mk 位于同一个目录:
[plain]  view plain copy
  1. LOCAL_PATH := $(call my-dir)  
  2. include $(CLEAR_VARS)  
  3. LOCAL_MODULE := foo-prebuilt  
  4. LOCAL_SRC_FILES := libfoo.so  
  5. include $(PREBUILT_SHARED_LIBRARY)  
按以下步骤声明这样一个模块:
1. 给该模块取一个名字(这里是 foo-prebuilt)。这个名字不需要与预编译库自身的名字相同。
2. 将 LOCAL_SRC_FILES 指定为你要提供的共享库的路径。通常,该路径是相对于 LOCAL_PATH 的路径。注意:必须保证共享库ABI的兼容性。
3. 如果你的库是共享库,则包含 PREBUILT_SHARED_LIBRARY 而不是 BUILD_SHARED_LIBRARY;如果是静态库,则包含 PREBUILT_STATIC_LIBRARY。

预编译模块不需要编译。该预编译模块会被拷贝到 $PROJECT/obj/local 下面,还会被拷贝到 $PROJECT/libs/<abi> 下面(这里的库被strip过)。

II. 在其他模块中引用这个预编译库

在依赖该预编译库的模块对应的Android.mk中,将预编译库的名字(前面取的)加入到 LOCAL_STATIC_LIBRARIES 或 LOCAL_SHARED_LIBRARIES 声明中。例如,一个使用上面libfoo.so的简单例子如下:

[plain]  view plain copy
  1. include $(CLEAR_VARS)  
  2. LOCAL_MODULE := foo-user  
  3. LOCAL_SRC_FILES := foo-user.c  
  4. LOCAL_SHARED_LIBRARIES := foo-prebuilt  
  5. include $(BUILD_SHARED_LIBRARY)  

FFmpegExample.java

package com.lily.testffmpeg;
public class FFmpegExample {
static{  
System.loadLibrary("swresample-1");
System.loadLibrary("avcodec-56");  
         
         System.loadLibrary("avdevice-56");  
         System.loadLibrary("avfilter-5"); 
         System.loadLibrary("avformat-56");  
         System.loadLibrary("avutil-54"); 
         System.loadLibrary("postproc-53");  
         
         System.loadLibrary("swscale-3"); 
         System.loadLibrary("ffmpeg_lily_codec");
}  
public native int lilyavcodec_findcodec(int id); 
}

com_lily_testffmpeg_FFmpegExample.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_lily_testffmpeg_FFmpegExample */


#ifndef _Included_com_lily_testffmpeg_FFmpegExample
#define _Included_com_lily_testffmpeg_FFmpegExample
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_lily_testffmpeg_FFmpegExample
 * Method:    lilyavcodec_findcodec
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_com_lily_testffmpeg_FFmpegExample_lilyavcodec_1findcodec
  (JNIEnv * env, jobject obj, jint id);


#ifdef __cplusplus
}
#endif
#endif

com_lily_testffmpeg_FFmpegExample.c

#include "com_lily_testffmpeg_FFmpegExample.h"
#include <math.h>
#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavutil/imgutils.h>
#include <libavutil/mathematics.h>


#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     cn_dennishucd_FFmpegNative
 * Method:    avcodec_find_decoder
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_com_lily_testffmpeg_FFmpegExample_lilyavcodec_1findcodec
  (JNIEnv * env, jobject obj, jint id)
{
AVCodec *codec = NULL;
/* register all formats and codecs */
av_register_all();
codec = avcodec_find_decoder(id);
if (codec != NULL)
{
return 0;
}
else
{
return -1;
}
}

#ifdef __cplusplus
}
#endif

MainActivity.java

package com.lily.testffmpeg;
import com.example.testandroidsp.R;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.TextureView;
import android.widget.TextView;


public class MainActivity extends ActionBarActivity {


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv=(TextView) findViewById(R.id.tv);

FFmpegExample fFmpegExample = new FFmpegExample();  
         int codecID = 28; //28 is the H264 Codec ID  
          
         int res = fFmpegExample.lilyavcodec_findcodec(codecID);  
          
         if(res ==0) {  
                         tv.setText("Success!");  
         }  
         else{  
                         tv.setText("Failed!");  
         }  
}
}

特别鸣谢:http://blog.csdn.net/gobitan/article/details/22750719

编译脚本文件http://download.csdn.net/detail/u010095768/8703265

例子源码:http://download.csdn.net/detail/u010095768/8703311



你可能感兴趣的:(Ubuntu编译android版ffmpeg)