首页 > 其他 > 详细

FFmpeg:初步编译使用

时间:2017-01-05 14:24:37      阅读:469      评论:0      收藏:0      [点我收藏+]

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文件是基本可用。




FFmpeg:初步编译使用

原文:http://www.cnblogs.com/blogs-of-lxl/p/6252130.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!