• FFmpeg:初步编译使用[Android]


    1.安装NDK:http://dl.google.com/android/ndk/android-ndk-r9-linux-x86.tar.bz2

     sudo gedit ~/.bashrc
     末尾添加:
     #add NDK
     PATH=$PATH:/home/sheldon/Android/android-ndk-r9/

     source ~/.bashrc  : 立即生效配置,可以使用"ndk-build"指令

    2.FFmpeg官方网站 http://www.ffmpeg.org/  下载源代码.

    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/android-ndk-r9/
    SYSROOT=$NDK/platforms/android-9/arch-arm/
    TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86

    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  

    生成:[头文件]android/arm/include/*.h 和  [动态库文件]android/arm/lib/*.so

    6.创建Android工程使用lib:
    (1)创建一个新的Android工程FFmpeg4android。
    (2)在工程目录下创建jni文件夹,与java目录同级。
    (3)在jni下创建prebuilt/armeabi目录,然后:
       将上面FFmpeg source code编译生成的so文件(带版号的真实库而不是链接文件)放入到该目录下的armeabi目录;
       将android/arm/include/下的所有头文件夹拷贝到该jni目录下.
    (4)创建包含native方法的类(java层直接调用的接口),先在src/main/java/下创建FFmpegNative.java类文件。主要包括加载so库文件和一个native测试方法两部分,其内容如下:

    package com.li.sheldon.ffmpeg4android;

    /**
    * Created by sheldon on 17-1-4.
    */
    public class FFmpegNative {
    static{
     System.loadLibrary("avcodec-57");
     System.loadLibrary("avdevice-57");
      System.loadLibrary("avfilter-6");
     System.loadLibrary("avformat-57");
     System.loadLibrary("avutil-55");
    System.loadLibrary("swresample-2");
    System.loadLibrary("swscale-4");
    System.loadLibrary("ffmpegjni");
    }
    private native int ffmpeg_h264(int codecID);

    public int test_h246(int id){
    return ffmpeg_h264(id);
    }
    }

    (5)用javah创建.头文件:

      -classpath <路径> 用于装入类的路径
      -d <目录> 输出目录
      -jni 生成 JNI样式的头文件(默认)

         javah -classpath /FFmpeg4android/app/src/main/java/ -d ./ -jni com.li.sheldon.ffmpeg4android.FFmpegNative
         -classpath 后面的路径是指包”com.li.sheldon.ffmpeg4android”所在的根路径
        会在当前目录产生com_li_sheldon_ffmpeg4android_FFmpegNative.h的C头文件;

    (6)根据头文件名,建立相同名字才C源文件com_li_sheldon_ffmpeg4android_FFmpegNative.c
        在这个源文件中实现头文件中定义的方法,核心部分代码如下:

    #include "com_li_sheldon_ffmpeg4android_FFmpegNative.h"
    JNIEXPORT jint JNICALL Java_com_li_sheldon_ffmpeg4android_FFmpegNative_ffmpeg_1h264
    (JNIEnv* env, jobject thiz, jint codecID)
    {
    AVCodec* codec = NULL;
    av_register_all();//该函数在所有基于ffmpeg的应用程序中几乎都是第一个被调用的。只有调用了该函数,才能使用复用器,编码器等
     codec = avcodec_find_decoder(codecID);//通过code ID查找一个已经注册的音视频编码器。H264codecID28,所以我们java那边传28下来如果检测到H264注册过了这边codec就不为空,返回0
      if(codec != NULL){
     return 0;
    }else{
    return -1;
    }
    }
    
    


    (7)编写Android.mk,内容如下:
    #APP_ABI := armeabi armeabi-v7a x86
    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)
    ifeq ($(APP_ABI), x86)
    TARGET_ARCH:=x86
    TARGET_ARCH_ABI:=x86
    else
    LOCAL_ARM_MODE := arm
    endif

    LOCAL_MODULE := libffmpegjni
    LOCAL_SRC_FILES := com_li_sheldon_ffmpeg4android_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, 指定编译平台[可省略]
        APP_PROJECT_PATH := $(call my-dir)/..
        APP_MODULES := libffmpegjni
    -------------------
        编译so文件:
        打开cmd命令行,进入FFmpeg4Androidjni目录下,执行如下命令:
        ndk-build  
        截止本步骤完成,将在FFmpeg4android/app/src/main/libs/armeabi/下另外生成了libffmpegjni.so文件, cp到FFmpeg4android/app/libs/armeabi/下由java类加载。
        ps:共享库将被拷贝到 $PROJECT/obj/local 和 $PROJECT/libs/<abi> (stripped)  主要是用在将已经编译好的第三方库.

    -------------------------如果ndk编译报错,加下面一段

    build.greadle(app):

    sourceSets.main{
      jniLibs.srcDir 'libs'
      jni.srcDirs = [] //disable automatic ndk-build call
    }


    (9)修改layout/main.xml,给TextView增加id,以便在代码中操作它:

    
    
    <?xml version="1.0" encoding="utf-8"?>
    <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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.li.sheldon.ffmpeg4android.MainActivity">

    <TextView
    android:id="@+id/hello_ffmpeg"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Hello World!" />
    </RelativeLayout>
    (10)增加一个Activity实现类FFmpeg4AndroidActivity,在OnCreate方法中调用native函数将值传给TextView控件,打包运行即可。FFmpeg4AndroidActivity代码如下:
    
    
    package com.li.sheldon.ffmpeg4android;

    import android.app.Activity;
    import android.os.Bundle;
    import android.widget.TextView;

    public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    int codec_id=28;
    FFmpegNative ffmpeg = new FFmpegNative();
    int tmp = ffmpeg.test_h246(codec_id); //28 is the H264 Codec ID
    TextView tv = (TextView)this.findViewById(R.id.hello_ffmpeg);
    tv.setText(tmp==0?"Support Codec ID:"+codec_id:"Not support Codec ID:"+codec_id);
    }
    }

    代码中的28是H264的编解码枚举类型定义的ID,如果能找到H264编解码,表明可以成功使用FFmpeg库文件。

    android 代码和动态库已传至github : https://github.com/dragonforgithub/FFmpeg4Android.git

    记录FFmpeg 雷神博客:http://blog.csdn.net/leixiaohua1020/article/details/44226355  (致敬永远的雷神)

  • 相关阅读:
    青蛙的约会
    租用游艇问题
    宾馆房间
    [USACO10FEB]购买巧克力Chocolate Buying
    骑士的工作
    Power Strings
    [HAOI2006]聪明的猴子
    骑马修栅栏 Riding the Fences
    [USACO06JAN]牛的舞会The Cow Prom
    UVA 11294 wedding 2-sat
  • 原文地址:https://www.cnblogs.com/blogs-of-lxl/p/6252130.html
Copyright © 2020-2023  润新知