• FFmpeg 移植 Android


    近期项目需要解析苹果的HLS流媒体协议,而FFmpeg从0.11.1“Happiness”版本开始,才增加了对HLS协议的支持。目前网上关于FFmpeg编译移植的文章有很多,但大多都是对旧版本的说明。新版本的源码对很多地方做了改动,包括一些变量名、常量名、函数名、函数参数、结构体等,所以在用旧版本的JNI接口时,需要相应地做出改动。这个编译移植工作确实花了本人不少时间,现在总结一下,希望能给到大家一些帮助。说明一点,本文阐述的不一定都正确,大家在编译过程中,难免会遇到各种各样的错误,可以提出来,一起讨论。

    编译环境:Ubuntu 12.04、Android NDK r8

    一、下载源码、新建工程

    下载地址:http://ffmpeg.org/download.html ,下载最新ffmpeg-0.11.1压缩包。

    在$NDK_HOME/samples/目录下(我的是/root/Develop/android-ndk-r8/samples/)创建一个FFMPEG-0.11目录,在里面新建一个jni目录,然后把ffmpeg源码解压放在jni里面,源码的文件夹重命名为libffmpeg,所以最后源码的路径是:

    /root/Develop/android-ndk-r8/samples/FFMPEG-0.11/jni/libffmpeg

      

    二、配置源代码

    1. 创建config_common.sh脚本

    在jni目录下创建一个config_common.sh,内容如下:

    Shellscript代码  收藏代码
    1. #!/bin/bash  
    2.   
    3. FFCONFIG_COMMON='  
    4.     --enable-version3  
    5.     --disable-gpl  
    6.     --disable-nonfree  
    7.     --disable-debug  
    8.     --disable-ffmpeg  
    9.     --disable-ffplay  
    10.     --disable-ffserver  
    11.     --disable-ffprobe  
    12.     --disable-encoders  
    13.     --disable-muxers  
    14.     --disable-devices  
    15.     --disable-protocols  
    16.     --enable-protocol=file  
    17.     --disable-swscale  
    18.     --disable-avfilter  
    19.     --enable-network  
    20.     --disable-avdevice  
    21.     --enable-parsers  
    22.     --disable-decoders  
    23.     --disable-demuxers  
    24.     --enable-demuxer=matroska  
    25.     --disable-demuxer=rm  
    26.     --disable-demuxer=avi  
    27.     --disable-demuxer=flv  
    28.     --disable-demuxer=mov  
    29.     --enable-demuxer=mp3  
    30.     --enable-demuxer=mpegps  
    31.     --enable-demuxer=mpegvideo  
    32.     --enable-demuxer=asf  
    33.     --enable-decoder=aac  
    34.     --enable-decoder=ac3  
    35.     --enable-decoder=dca  
    36.     --enable-decoder=flv  
    37.     --disable-decoder=h263  
    38.     --disable-decoder=h264  
    39.     --enable-decoder=svq3  
    40.     --enable-decoder=amrnb  
    41.     --enable-decoder=nellymoser  
    42.     --enable-decoder=pcm_alaw  
    43.     --enable-decoder=pcm_dvd  
    44.     --enable-decoder=pcm_mulaw  
    45.     --enable-decoder=pcm_s16be  
    46.     --enable-decoder=pcm_s16le  
    47.     --enable-decoder=pcm_s16le_planar  
    48.     --enable-decoder=pcm_s24be  
    49.     --enable-decoder=pcm_s24daud  
    50.     --enable-decoder=pcm_s24le  
    51.     --enable-decoder=pcm_s32be  
    52.     --enable-decoder=pcm_s32le  
    53.     --enable-decoder=pcm_s8  
    54.     --enable-decoder=pcm_u16be  
    55.     --enable-decoder=pcm_u16le  
    56.     --enable-decoder=pcm_u24be  
    57.     --enable-decoder=pcm_u24le  
    58.     --enable-decoder=pcm_u32be  
    59.     --enable-decoder=pcm_u32le  
    60.     --enable-decoder=atrac3  
    61.     --enable-decoder=pcm_u8  
    62.     --enable-decoder=sipr  
    63.     --enable-decoder=mjpeg  
    64.     --enable-decoder=mp1  
    65.     --enable-decoder=mp2  
    66.     --enable-decoder=mp3  
    67.     --enable-decoder=tscc  
    68.     --enable-decoder=mpeg1video  
    69.     --enable-decoder=mpeg2video  
    70.     --enable-decoder=mpeg4  
    71.     --enable-decoder=ra_144  
    72.     --enable-decoder=ra_288  
    73.     --enable-decoder=cook  
    74.     --enable-decoder=rv10  
    75.     --enable-decoder=rv20  
    76.     --enable-decoder=rv30  
    77.     --enable-decoder=rv40  
    78.     --enable-decoder=wmav1  
    79.     --enable-decoder=wmav2  
    80.     --enable-decoder=wmapro  
    81.     --disable-decoder=wmv1  
    82.     --disable-decoder=wmv2  
    83.     --disable-decoder=wmv3  
    84.     --enable-decoder=vc1  
    85.     --enable-decoder=msmpeg4v1  
    86.     --enable-decoder=msmpeg4v2  
    87.     --enable-decoder=msmpeg4v3  
    88. '  

      

    可以根据需要自行配置以上参数。

    2. 创建config.sh脚本

    在jni目录下创建一个config.sh,内容如下:

    Shellscript代码  收藏代码
    1. #!/bin/bash  
    2.   
    3. source config_common.sh            /*这里执行上面的config_common.sh脚本*/  
    4.   
    5. cd libffmpeg               /*进入libffmpeg目录*/  
    6.   
    7. PREBUILT=/root/Develop/android-ndk-r8/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86  
    8. PLATFORM=/root/Develop/android-ndk-r8/platforms/android-14/arch-arm  
    9.   
    10. ./configure --target-os=linux   
    11.     --arch=arm   
    12.     --enable-shared   
    13.     --enable-cross-compile   
    14.     --cc=$PREBUILT/bin/arm-linux-androideabi-gcc   
    15.     --cross-prefix=$PREBUILT/bin/arm-linux-androideabi-   
    16.     --strip=$PREBUILT/bin/arm-linux-androideabi-strip   
    17.     --extra-cflags="-fPIC -DANDROID"   
    18.     --extra-ldflags="-Wl,-T,$PREBUILT/arm-linux-androideabi/lib/ldscripts/armelf_linux_eabi.x -Wl,-rpath-link=$PLATFORM/usr/lib -L$PLATFORM/usr/lib -nostdlib $PREBUILT/lib/gcc/arm-linux-androideabi/4.4.3/crtbegin.o $PREBUILT/lib/gcc/arm-linux-androideabi/4.4.3/crtend.o -lc -lm -ldl"   
    19.     $FFCONFIG_COMMON  
    20.   
    21.   
    22. cd ..                       /*返回jni目录*/  
    23. ndk-build clean  

      

    3.  执行config.sh脚本

    然后打开终端,执行以下命令:

    $chmod +x config.sh /*赋予config.sh执行权限*/
    $./config.sh

      

    如果配置正确的话,显示出来的最后两行是这样的:

    License:LGPL version 3 or later
    Creating config.mak and config.h...

    若出现WARNING:/root/Develop/android-ndk-8/.............../arm-linux-androideabi-pkg-config not found, library detection may fail. 可忽略。

    4. 修改config.h

    进入jni/libffmpeg/目录,在刚刚生成的config.h中找到这句:

    #define restrict restrict

    因为Android的gcc并不认得restrict这个关键字,所以把它改写成:

    #define restrict

    如果需要联网的话,还需要将config.h中的以下定义置为1:

    #define CONFIG_NETWORK 1
    #define CONFIG_HTTP_PROTOCOL 1
    #define CONFIG_HTTPPROXY_PROTOCOL 1
    #define CONFIG_HTTPS_PROTOCOL 1
    #define CONFIG_TCP_PROTOCOL 1
    #define CONFIG_UDP_PROTOCOL 1
    #define HAVE_STRUCT_SOCKADDR_STORAGE 1
    #define HAVE_STRUCT_ADDRINFO 1
    #define HAVE_SOCKLEN_T 1

    #define HAVE_INET_ATON 0

    相应的,config.mak中也需要修改为:

    CONFIG_NETWORK=yes
    CONFIG_HTTP_PROTOCOL=yes
    CONFIG_HTTPPROXY_PROTOCOL=yes
    CONFIG_HTTPS_PROTOCOL=yes 
    CONFIG_TCP_PROTOCOL=yes
    CONFIG_UDP_PROTOCOL=yes
    HAVE_STRUCT_SOCKADDR_STORAGE=yes
    HAVE_STRUCT_ADDRINFO=yes
    HAVE_SOCKLEN_T=yes

    !HAVE_INET_ATON=yes

      

    5. 修改libm.h文件

    将/libavutil/libm.h中所有的static函数全部注释掉。

    6. 修改Makefile文件

    分別修改libavcodec、libavfilter、libavformat、libavutil、libpostproc和libswscale目录下的Makefile文件,将下面一句注释掉:

    include $(SUBDIR)../config.mak

      

    7. 新建av.mk脚本

    在/jni/libffmpeg下建立一个脚本文件av.mk,內容如下:

    # LOCAL_PATH is one of libavutil, libavcodec, libavformat, or libswscale

    #include $(LOCAL_PATH)/../config-$(TARGET_ARCH).mak
    include $(LOCAL_PATH)/../config.mak

    OBJS :=
    OBJS-yes :=
    MMX-OBJS-yes :=
    include $(LOCAL_PATH)/Makefile
    ifdef ADDITION_INC
    include $(ADDITION_INC)
    endif

    # collect objects
    OBJS-$(HAVE_MMX) += $(MMX-OBJS-yes)
    OBJS += $(OBJS-yes)

    FFNAME := lib$(NAME)
    FFLIBS := $(foreach,NAME,$(FFLIBS),lib$(NAME))
    FFCFLAGS = -DHAVE_AV_CONFIG_H $(CFLAGS)
    FFCFLAGS += -DTARGET_CONFIG="config-$(TARGET_ARCH).h"

    ALL_S_FILES := $(wildcard $(LOCAL_PATH)/$(TARGET_ARCH)/*.S)
    ALL_S_FILES := $(addprefix $(TARGET_ARCH)/, $(notdir $(ALL_S_FILES)))

    ifneq ($(ALL_S_FILES),)
    ALL_S_OBJS := $(patsubst %.S,%.o,$(ALL_S_FILES))
    C_OBJS := $(filter-out $(ALL_S_OBJS),$(OBJS))
    S_OBJS := $(filter $(ALL_S_OBJS),$(OBJS))
    else
    C_OBJS := $(OBJS)
    S_OBJS :=
    endif

    C_FILES := $(patsubst %.o,%.c,$(C_OBJS))
    S_FILES := $(patsubst %.o,%.S,$(S_OBJS))

    FFFILES := $(sort $(S_FILES)) $(sort $(C_FILES))

      

    8. 新建Android.mk脚本

    在jni目录下新建Android.mk,內容如下:

    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_SRC_FILES := ExportJNI.cpp ExportPlayer.cpp PacketQueue.cpp /*其中ExportJNI.cpp是我编写的JNI接口*/
    LOCAL_STATIC_LIBRARIES := libavformat libavcodec libswscale libavutil libpostproc ffmpeg libsubtitle /*注意Libraries的顺序*/
    LOCAL_MODULE := export /*最终生成libexport.so*/ 
    LOCAL_ARM_MODE := arm
    LOCAL_CFLAGS := -D__STDC_CONSTANT_MACROS -I$(LOCAL_PATH)/libffmpeg/ -I$(LOCAL_PATH)/libsubtitle/
    LOCAL_LDLIBS := -llog
    include $(BUILD_SHARED_LIBRARY)
    include $(call all-makefiles-under,$(LOCAL_PATH))

    在jni/libffmpeg目录下新建Android.mk:

    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_SRC_FILES := settings.c MyLog.cpp       /*如果不需要打印输出等辅助功能,这行可删去*/
    LOCAL_MODULE := ffmpeg
    LOCAL_ARM_MODE := arm
    include $(BUILD_STATIC_LIBRARY)
    include $(call all-makefiles-under,$(LOCAL_PATH))

      
    在jni/libffmpeg/libavformat目录下新建Android.mk:

    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    include $(LOCAL_PATH)/../av.mk
    LOCAL_SRC_FILES := $(FFFILES)
    LOCAL_C_INCLUDES :=
    $(LOCAL_PATH)
    $(LOCAL_PATH)/..
    LOCAL_CFLAGS += $(FFCFLAGS)
    LOCAL_CFLAGS += -include "string.h" -Dipv6mr_interface=ipv6mr_ifindex
    LOCAL_LDLIBS := -lz
    LOCAL_STATIC_LIBRARIES := $(FFLIBS)
    LOCAL_MODULE := $(FFNAME)
    LOCAL_ARM_MODE := arm
    include $(BUILD_STATIC_LIBRARY)

       

    在jni/libffmpeg/libavcodec目录下新建Android.mk:

    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    ADDITION_INC := $(LOCAL_PATH)/arm/Makefile
    include $(LOCAL_PATH)/../av.mk
    ADDITION_INC := 

    LOCAL_SRC_FILES := $(FFFILES)

    LOCAL_C_INCLUDES :=
    $(LOCAL_PATH)
    $(LOCAL_PATH)/..
    LOCAL_CFLAGS += $(FFCFLAGS)
    ifeq ($(TARGET_ARCH_ABI),armeabi)
    LOCAL_CFLAGS += -DUSE_INT
    endif

    LOCAL_LDLIBS := -lz
    LOCAL_STATIC_LIBRARIES := $(FFLIBS)
    LOCAL_MODULE := $(FFNAME)
    LOCAL_ARM_MODE := arm
    include $(BUILD_STATIC_LIBRARY)

      

    在libavfilter、libavutil、libpostproc和libswscale目录下都分別新建Android.mk:

    LOCAL_PATH:= $(call my-dir)
    include $(CLEAR_VARS)
    include$(LOCAL_PATH)/../av.mk
    LOCAL_SRC_FILES:= $(FFFILES)
    LOCAL_C_INCLUDES:=
    $(LOCAL_PATH)
    $(LOCAL_PATH)/..
    LOCAL_CFLAGS+= $(FFCFLAGS)
    LOCAL_STATIC_LIBRARIES:= $(FFLIBS)
    LOCAL_MODULE:= $(FFNAME)
    include$(BUILD_STATIC_LIBRARY)

      

    9. 新建Application.mk脚本

    在jni目录下创建一个Application.mk,内容如下:

    APP_STL := stlport_static
    APP_ABI := armeabi

    三、 NDK编译

    在FFMPEG-0.11/下执行ndk-build:

    $/ FFMPEG-0.11# ndk-build

      

    编译过程需要十分钟左右,最后会在FFMPEG-0.11/obj/local/armeabi/目录下生成libavcodec.a、libavformat.a、libavutil.a、libffmpeg.a、libswscale.a和libpostproc.a以及libexport.so,在FFMPEG-0.11/libs/armeabi/目录下生成libexport.so。

    转载:http://superonion.iteye.com/blog/1609777

  • 相关阅读:
    Python调用ansible API系列(三)带有callback的执行adhoc和playbook
    Python调用ansible API系列(二)执行adhoc和playbook
    Python调用ansible API系列(一)获取资产信息
    kube-proxy的功能
    Kubernetes集群部署史上最详细(二)Prometheus监控Kubernetes集群
    Kubernetes集群部署史上最详细(一)Kubernetes集群安装
    Celery异步调度框架(二)与Django结合使用
    【WPF on .NET Core 3.0】 Stylet演示项目
    [译]基于ASP.NET Core 3.0的ABP v0.21已发布
    .NET Conf 2019日程(北京时间)
  • 原文地址:https://www.cnblogs.com/canphp/p/4475515.html
Copyright © 2020-2023  润新知