您的位置:首页 > 移动开发 > Android开发

Android:WIN10+MinGW+NDK编译FFmpeg

2017-07-31 21:46 591 查看
前言:

Android音视频开发的话,FFmpeg总是必须的,出于学习目的,花时间起了个开头。

FFmpeg源码是很多的c文件,首先要借助工具编译出so库,仅有这个Android是无法调用的,必须再用JNI写一层Android能用的接口。网上资料非常多,但是看了几天下来,编译平台和工具版本的差异总是存在,编译过程中也有各种各样的问题。这里给出自己的编译过程,希望给刚好需要的同学。

到写文章为止,所有源码和工具都是用的最新版。

一.MinGW编译出so库
http://ffmpeg.org/下载源码,解压到一个文件夹里


https://sourceforge.net/projects/mingw/files/下载MinGW,把相应的选项都勾上,环境变量配置好。

找到ffmpeg目录下的configure

打开并找到以下几行

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

在ffmpeg下新建一个build_android.sh,将以下代码复制进去

1)前三行按实际情况替换

2)这里我用notepad++编辑将文件格式改为Unix格式,否则会有一些换行符等Windows与Linux平台差异问题编译出问题

#!/bin/sh
NDK=D:/Program/android-ndk-r14b
SYSROOT=$NDK/platforms/Android-21/arch-arm
TOOLCHAIN=$NDK/toolchains/arm-Linux-androideabi-4.9/prebuilt/windows-x86_64
function build_one
{
./configure \
--prefix=$PREFIX \
--enable-shared \
--enable-gpl \
--disable-static \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--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
make install
}
CPU=arm
PREFIX=$(pwd)/libs/$CPU
ADDI_CFLAGS="-marm"
build_one

之后打开下载好的MinGW的  MinGW\msys\1.0\msys.bat,执行以下命令



耐心等待后,ffmpeg下多出一个libs文件夹,里面就是我们想要的东西了



二.NDK编译JNI

还是在ffmpeg目录下,新建一个jni目录,里面是这些东西



其中Android.mk

APP_ALLOW_MISSING_DEPS=true

LOCAL_PATH := $(call my-dir)

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

include $(CLEAR_VARS)
LOCAL_MODULE := avfilter
LOCAL_SRC_FILES := libavfilter-6.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := avformat
LOCAL_SRC_FILES := libavformat-57.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := avutil
LOCAL_SRC_FILES := libavutil-55.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := swscale
LOCAL_SRC_FILES := libswscale-4.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := swresample
LOCAL_SRC_FILES := libswresample-2.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := avdevice
LOCAL_SRC_FILES := libavdevice-57.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := postproc
LOCAL_SRC_FILES := libpostproc-54.so
include $(PREBUILT_SHARED_LIBRARY)

# Program
include $(CLEAR_VARS)
LOCAL_MODULE := jniloader
LOCAL_SRC_FILES := jniloader.c
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
LOCAL_LDLIBS := -llog -lz
LOCAL_SHARED_LIBRARIES := avcodec avdevice avfilter avformat avutil postproc swresample swscale
include $(BUILD_SHARED_LIBRARY)

Application.mk

APP_ABI :=armeabi

jniloader.c

#include <stdio.h>
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavfilter/avfilter.h"  

#ifdef ANDROID
#include <jni.h>
#include <android/log.h>
#endif

struct URLProtocol;  

JNIEXPORT jstring Java_com_example_ffmpeg_JNILoader_urlprotocolinfo(JNIEnv *env, jobject obj){  
      
    char info[40000]={0};  
    av_register_all();  
  
    struct URLProtocol *pup = NULL;  
    //Input  
    struct URLProtocol **p_temp = &pup;  
    avio_enum_protocols((void **)p_temp, 0);  
    while ((*p_temp) != NULL){  
        sprintf(info, "%s[In ][%10s]\n", info, avio_enum_protocols((void **)p_temp, 0));  
    }  
    pup = NULL;  
    //Output  
    avio_enum_protocols((void **)p_temp, 1);  
    while ((*p_temp) != NULL){  
        sprintf(info, "%s[Out][%10s]\n", info, avio_enum_protocols((void **)p_temp, 1));  
    }  
  
    //LOGE("%s", info);  
    return (*env)->NewStringUTF(env, info);  
}

JNIEXPORT jstring Java_com_example_ffmpeg_JNILoader_avformatinfo(JNIEnv *env, jobject obj){  
  
    char info[40000] = { 0 };  
  
    av_register_all();  
  
    AVInputFormat *if_temp = av_iformat_next(NULL);  
    AVOutputFormat *of_temp = av_oformat_next(NULL);  
    //Input  
    while(if_temp!=NULL){  
        sprintf(info, "%s[In ][%10s]\n", info, if_temp->name);  
        if_temp=if_temp->next;  
    }  
    //Output  
    while (of_temp != NULL){  
        sprintf(info, "%s[Out][%10s]\n", info, of_temp->name);  
        of_temp = of_temp->next;  
    }  
    //LOGE("%s", info);  
    return (*env)->NewStringUTF(env, info);  
} 

JNIEXPORT jstring Java_com_example_ffmpeg_JNILoader_avcodecinfo(JNIEnv *env, jobject obj)  
{  
    char info[40000] = { 0 };  
  
    av_register_all();  
  
    AVCodec *c_temp = av_codec_next(NULL);  
  
    while(c_temp!=NULL){  
        if (c_temp->decode!=NULL){  
            sprintf(info, "%s[Dec]", info);  
        }  
        else{  
            sprintf(info, "%s[Enc]", info);  
        }  
        switch (c_temp->type){  
        case AVMEDIA_TYPE_VIDEO:  
            sprintf(info, "%s[Video]", info);  
            break;  
        case AVMEDIA_TYPE_AUDIO:  
            sprintf(info, "%s[Audio]", info);  
            break;  
        default:  
            sprintf(info, "%s[Other]", info);  
            break;  
        }  
        sprintf(info, "%s[%10s]\n", info, c_temp->name);  
  
          
        c_temp=c_temp->next;  
    }  
    //LOGE("%s", info);  
  
    return (*env)->NewStringUTF(env, info);  
}     

JNIEXPORT jstring Java_com_example_ffmpeg_JNILoader_avfilterinfo(JNIEnv *env, jobject obj)  
{  
    char info[40000] = { 0 };  
    avfilter_register_all();  
    AVFilter *f_temp = (AVFilter *)avfilter_next(NULL);  
    while (f_temp != NULL){  
        sprintf(info, "%s[%10s]\n", info, f_temp->name);  
f_temp = f_temp->next; 
    }  
    //LOGE("%s", info);  
  
    return (*env)->NewStringUTF(env, info);  
} 

JNIEXPORT jstring Java_com_example_ffmpeg_JNILoader_configurationinfo(JNIEnv *env, jobject obj)  
{  
    char info[10000] = { 0 };  
    av_register_all();  
  
    sprintf(info, "%s\n", avcodec_configuration());  
  
    //LOGE("%s", info);  
    return (*env)->NewStringUTF(env, info);  
}   

然后就用NDK编译即可,这就是我们最终要的了。



三.Java层调用接口

把JNI编译出来的SO库放在jniLibs下



声明相关的c层函数并加载so库



最后调用即可,这些都只是简单的用ffmpeg提供的函数输出相关的配置信息,还有很多强大的音视频相关的功能要慢慢探索了。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: