天天看点

FFMPEG之路——初探类‘HelloWord’

        最近开始在学习FFMPEG,准确点来讲是FFMPEG for Android!也开始尝试着写博客,主要是为了记录自己的学习过程,和大家一起分享和探讨,共同进步。

      在这里,我会把自己遇到的一些坑提醒给大家,提高大家的学习效率。上文中我们已经在Linux环境下搭建好了FFMPEG开源库的编译环境,并且拿到了可以在Android上运行的动态库,下面我们一起学习一个FFMPEG的简单Demo,我把它叫做类'HelloWord'。程序猿癖好,喜欢把第一个程序叫做HelloWord!

创建一个Android工程

        我觉得Android Studio运行起来比Eclipse慢,用起来也相对更熟悉,对于这种简单的程序,还是喜欢用Eclipse+SDK环境编写。如下图,先创建了一个名为FFmpeg4Android的工程,这里主要把它分为三块,界面显示及逻辑控制(MainActivity和activity_main.xml) 、 Native接口(FFmpegNative)和jni动态库部分。工程目录结构如下图所示:

FFMPEG之路——初探类‘HelloWord’

图1-1    工程结构图         代码比较简单,就不赘述了,相信有学习或开发过Android的都比较清楚,源码后面也会给出,可以完整编译运行。下面主要讲下我们自己编写的依赖FFMPEG开源库的jni动态库的编译方法。

生成jni头文件

        jni的函数声明和定义是有一定规则的,函数名字都是以"JNIEXPORT 返回类型 JNICALL Java_完整包名_类名_对应函数名"为规范的,不过Android Framework源码里面有另一套方法可以自定义函数名,有兴趣的可以去看看,在开发应用的时候没必要这么去做,按照这种规则自动生成就好。         cmd进入到工程的bin/classes目录下,执行javah -jni com.jacky.ffmpeg.jni.FFmpegNative就可以在当前目录生成com_jacky_ffmpeg_jni_FFmpegNative.h头文件了,自动生成的头文件不需要做任何改动。

根据生成的jni头文件编写.c或者.cpp文件

        可以先根据 .h文件的结构快速的完成.c文件结构的编写,具体的实现代码暂时忽略。简单归纳了下:         创建与.h文件前缀同名的.c文件;         .c文件include.h头文件;         复制.h文件中的所有函数到.c文件,并给函数参数加上变量名;         去掉函数后面分号,加花括号对,对于有返回值得函数返回默认值。         经过如上几步,c文件的结构就编写完成了,然后可以逐步完成各个接口函数的代码编写了。

编写Android.mk文件

        编 译独立的jni库相对要简单些,下面几行就可以了。

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := ffmpeg
LOCAL_SRC_FILES := com_jacky_ffmpeg_jni_FFmpegNative.c
include $(BUILD_SHARED_LIBRARY)
           

         但是libffmpeg jni库对FFMPEG的动态库有依赖,这就要麻烦一些了,需要先PREBUILT所依赖的动态库,如下

include $(CLEAR_VARS)
LOCAL_MODULE := avcodec
LOCAL_SRC_FILES := libavcodec-57.so
include $(PREBUILT_SHARED_LIBRARY)
           

        然后在前面的基础上加上LOCAL_SHARED_LIBRARIES,变成如下

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SHARED_LIBRARIES := avcodec
LOCAL_MODULE := ffmpeg
LOCAL_SRC_FILES := com_jacky_ffmpeg_jni_FFmpegNative.c
include $(BUILD_SHARED_LIBRARY)
           

        这里简单说明了有依赖第三方动态库和无依赖的区别,以及mk文件分别需要怎么去编写。完整代码可以下载,理解了这个应该就不会有什么疑问了。

编写Application.mk文件(可选)

        Application.mk中的APP_ABI设定了编译后库文件支持的指令集,默认使用“armeabi”,APP_ABI取值为“all”则会编译所有的,x86、arm的各种都会生成。也可以自行指定需要的某一种或者某几种。

运行ndk-build编译

        注意两点,一个是ndk-build以及jni的路径,需要在jni目录下执行ndk-build命令,要求已经配置好ndk-build系统环境或者使用完整路径;另一个则是必须要有所依赖FFMPEG动态库对应的头文件。我是在Linux环境下面先安装了ffmpeg库,所以local有了头文件可以直接编译。你可以把用到的头文件拷贝到jni目录能够访问到地方,然后在mk文件中用LOCAL_C_INCLUDES引用该头文件,或者像我一样先安装到系统环境里。得让编译器能够找的到头文件。         然后在jni的上一级目录下,会生成libs和obj两个目录,直接libs里面对应指令集的库放到工程libs下面就可以编译运行了,也可以全部指令集的都放过去,没影响,只是生成的安装包会大一些。

源码下载地址 点击打开链接

在路上!