Ubuntu编译android版ffmpeg

来源:互联网 发布:零基础学python张志强 编辑:程序博客网 时间:2024/06/07 02:24

准备材料: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_FLAGmake cleanmake -j$THREAD_COUNTmake 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 plaincopy
  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 plaincopy
  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 __cplusplusextern "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 __cplusplusextern "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 {@Overrideprotected 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



0 0
原创粉丝点击