android mp4v2的编译和使用

作者: 一林花色 | 来源:发表于2017-07-14 23:40 被阅读725次

    一、下载mp4v2源码

    下载地址:https://code.google.com/archive/p/mp4v2/downloads下载后解压,我们要在Android平台上使用,所以需要使用NDK编译,我们需要以下源码

    mp4v2编译需要源码

    二、源码放入Android studio工程目录

    1.以下是我的目录结构

    jni目录结构 mp4v2作为一个单独的共享模块 libyuv使用已经编译好的库

    注意: 1
       mp4v2源码里有一些文件已“.in”作为后缀,要把“.in”去掉保留应有的后缀名,不然有些文件会找不到,比如mp4v2-2.0.0\libplatform\config.h.in 要改成 config.h
    注意: 2
       头文件的导入,源码里 mp4v2-2.0.0\include\mp4v2\mp4v2.h ,我把mp4v2.h放到上一级的目录了,注意修改mp4v2.h里头文件的引用,还有一下其它文件对mp4v2.h的include,比如src.h的头文件里对mp4v2.h的include,因为目录有变,记得修改

    三、编写cmake脚本或者Makefile脚本

    如果要和工程一起build可以使用cmake脚本,编写CMakeLists.txt文件,也可以使用makefile.我的目录结构是把mp4v2作为一个单独的共享模块编译的,所以这里的脚本编写分为两级,第一级jni目录下,编写我们自己的jni接口源码的CMakeLists.txtmp4v2作为单独模块编译的CMakeLists.txt。而且我把mp4v2也放在它自己的jni目录下,在它自己的模块下编写脚本

    1.以下为mp4v2模块的CMakeLists.txt

    cmake_minimum_required(VERSION 3.4.1)
    
    SET ( ly_cmake_dir ${CMAKE_CURRENT_SOURCE_DIR} )  #cmake所在的目录
    
    SET ( ly_base_dir   ${PROJECT_SOURCE_DIR}/libs/mp4v2/jni )
    SET ( ly_src_dir    ${ly_base_dir}/src)
    SET ( ly_inc_dir    ${ly_base_dir}/include )
    SET ( ly_lib_name   mp4v2 )
    SET ( ly_lib_static ${ly_lib_name} )
    SET ( ly_lib_shared ${ly_lib_name}_shared )
    
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -fexceptions -Wno-write-strings -O2 -DHAVE_SOCKLEN_T -DHAVE_STRUCT_IOVEC")
    
    message("------------------------------Cmake build ${ly_lib_name}-----------------------------")
    message("project source dir==>${PROJECT_SOURCE_DIR}")
    message("Cmake file dir==>${CMAKE_CURRENT_SOURCE_DIR}")
    
    #查找目录下所有的源文件,并保存在指定变量ly_source_files中,遗憾的是它不能像File递归查找
    aux_source_directory( src ly_source_files)
    aux_source_directory( src/bmff ly_source_files)
    aux_source_directory( src/itmf ly_source_files)
    aux_source_directory( src/qtff ly_source_files)
    aux_source_directory( libplatform ly_source_files)
    aux_source_directory( libplatform/io ly_source_files)
    aux_source_directory( libplatform/number ly_source_files)
    aux_source_directory( libplatform/process ly_source_files)
    aux_source_directory( libplatform/prog ly_source_files)
    aux_source_directory( libplatform/sys ly_source_files)
    aux_source_directory( libplatform/time ly_source_files)
    aux_source_directory( libutil ly_source_files)
    # FILE ( GLOB_RECURSE   ly_source_files ./src/*.cpp )
    #LIST ( SORT    ly_source_files )
    
    #排序之后的文件
    message("-----------------The following is the sorted source file--------------------")
    foreach(_var ${ly_source_files})
       message("${_var}")
       if(_var MATCHES "_win32.cpp")
             list(APPEND  filter_source_cpp ${_var})
       endif()
    endforeach()
    
    foreach(_var ${filter_source_cpp})
        message("remove win32==>${_var}")
        # 切记此处remove_item 的list不能  ${}  求值
        list(REMOVE_ITEM ly_source_files ${_var})
    endforeach()
    
    message("---------------------------------------------------------------------------")
    
    if (${ANDROID_ABI} STREQUAL "armeabi-v7a")
        message("------------------------${ly_lib_name}::armeabi-v7a-----------------------------")
    set_property(SOURCE ${ly_source_files} APPEND_STRING PROPERTY COMPILE_FLAGS " -mfpu=neon")
    endif ()
    
    # include目录  AFTER OR BEFORE 表示添加在之前还是之后,SYSTEM表示系统包含目录
    # https://cmake.org/cmake/help/latest/command/include_directories.html
    include_directories( BEFORE ${ly_inc_dir} ${ly_base_dir}
    ${ly_cmake_dir}/src ${ly_cmake_dir}/libutil ${ly_cmake_dir}/libplatform)
    # this creates the static library (.a)
    
    ADD_LIBRARY ( ${ly_lib_static} STATIC ${ly_source_files} )
    
    #-------------------------------------------------------------------------------------------
    # this creates the shared library (.so)
    #ADD_LIBRARY    ( ${ly_lib_shared} SHARED ${ly_source_files} )
    
    #可以输出同名的  动、静态库
    #SET_TARGET_PROPERTIES  ( ${ly_lib_shared} PROPERTIES OUTPUT_NAME "${ly_lib_name}" )
    ## SET_TARGET_PROPERTIES    ( ${ly_lib_shared} PROPERTIES PREFIX "lib" )
    
    #cmake在构建完一个target构建下一个target时会clean掉上一个使用此target名字的库
    #set_target_properties ( ${ly_lib_static} PROPERTIES CLEAN_DIRECT_OUTPUT 1)
    #set_target_properties ( ${ly_lib_shared} PROPERTIES CLEAN_DIRECT_OUTPUT 1)
    
    #动态库版本号
    ##set_target_properties ( ${ly_lib_shared} properties VERSION 1.0 SOVERSION 1)
    

    2.以下为外层我们JNI接口的CMakeLists.txt

    cmake_minimum_required(VERSION 3.4.1)
    
    #输出更详细的构建信息
    # SET( CMAKE_VERBOSE_MAKEFILE on )
    
    SET ( ly_cmake_dir ${CMAKE_CURRENT_SOURCE_DIR} )   #cmake所在的目录
    SET ( ly_base_dir   ${PROJECT_SOURCE_DIR} )
    SET ( ly_src_dir    ${ly_base_dir}/src )
    SET ( ly_inc_dir    ${ly_base_dir}/include )
    SET ( ly_lib_name   mp4 )
    SET ( ly_lib_static ${ly_lib_name} )
    SET ( ly_lib_shared ${ly_lib_name}_shared )
    SET ( MY_LOG_TAG yuv-tag)
    
    message(STATUS "Source_Dir==>${PROJECT_SOURCE_DIR}")
    message(STATUS "Cmake_file_Dir==>${CMAKE_CURRENT_SOURCE_DIR}")
    message(STATUS "CMAKE_CURRENT_LIST_FILE==>${CMAKE_CURRENT_LIST_FILE}")
    message(STATUS "Android NDK::${ANDROID_NDK}")
    message(STATUS "ENV Android NDK::$ENV{NDK_ROOT}")
    message(STATUS "ANDROID_ABI==>${ANDROID_ABI}")
    message(STATUS "ANDROID_PLATFORM==>${ANDROID_PLATFORM}")
    message(STATUS "CMAKE_ANDROID_ARCH_ABI==>${CMAKE_ANDROID_ARCH_ABI}")
    
    #-std=c++11
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pipe -fPIC -Wall -frtti -fexceptions")
    # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
    
    #------------------------------------------------------------------------------------------
    #add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
    
    message("-------------------------compile subdirectory ${ly_lib_name}------------------------------")
    add_subdirectory(${ly_cmake_dir}/libs/mp4v2/jni ${ly_cmake_dir}/libs/mp4v2)
    message("---------------------------compile ${ly_lib_name} finished--------------------------------")
    
    set(sub_lib_name mp4v2)
    #------------------------------------------------------------------------------------------
    
    message("--------------------------Cmake build ${ly_lib_name}----------------------------")
    
    FILE ( GLOB_RECURSE yuv_source_files ${ly_src_dir}/*.cpp )        #递归搜索目录下所有的c文件
    LIST ( SORT         yuv_source_files )
    
    message("---------------------The following is the sorted source file---------------------")
    foreach(_var ${yuv_source_files})
        message("${_var}")
    endforeach()
    
    message("---------------------------------------------------------------------------------")
    #------------------------------------------------------------------------------------------
    #追加编译参数  add_definitions("-DMY_LOG_TAG=${MY_LOG_TAG}")
    #add_compile_options(-DMY_LOG_TAG=${MY_LOG_TAG})
    
    if(NOT ${CMAKE_BUILD_TYPE} MATCHES "Debug")
        message("---------------------${ly_lib_name}::Compile the release version---------------------")
    #    add_compile_options( -DMY_LOG_LEVEL=MY_LOG_LEVEL_ERROR )
    else()
        message("---------------------${ly_lib_name}::Compile the Debug version-----------------------")
    #    add_compile_options( -DMY_LOG_LEVEL=MY_LOG_LEVEL_VERBOSE )
    endif()
    #------------------------------------------------------------------------------------------
    
    include_directories( AFTER ${ly_inc_dir} ${ly_base_dir}/libs/libyuv/include ${ly_base_dir}/libs/mp4v2/jni/include)
    
    #查找一系列平台已提供的原始库,find_library(变量名 库名称)
    find_library(log-lib log)
    #find_library(graphics-lib jnigraphics)
    find_library(android-lib android)
    
    # 导入其它预构建库,使用  IMPORTED
    # add_library( imported-lib SHARED IMPORTED )
    # set_target_properties( imported-lib PROPERTIES IMPORTED_LOCATION imported-lib/src/${ANDROID_ABI}/libimported-lib.so)
    # include_directories( imported-lib/include/ )
    
    add_library( yuv-static STATIC IMPORTED )
    set_target_properties( yuv-static PROPERTIES IMPORTED_LOCATION ${ly_base_dir}/libs/libyuv/libs/${ANDROID_ABI}/libyuv.a)
    
    # 链接库使用的language
    #set_target_properties(${ly_lib_shared} PROPERTIES LINKER_LANGUAGE CXX)
    
    add_library( ${ly_lib_name} SHARED ${yuv_source_files} )
    
    target_link_libraries(${ly_lib_name} yuv-static mp4v2 ${log-lib} ${android-lib})
    
    #设置本次target的构建依赖其它target,确保本target构建前,其它target先被构建好
    add_dependencies(${ly_lib_name} ${sub_lib_name})
    

    三、在build.gradle里配置cmake CMakeLists.txt

    1.build.gradle里的脚本配置

        defaultConfig {
            minSdkVersion 16
            targetSdkVersion 25
            versionCode sdk_version_code
            versionName sdk_version_name
    
            ndk {
    //            abiFilters('x86', 'armeabi', 'armeabi-v7a', 'arm64-v8a')
                abiFilters('armeabi-v7a')
            }
    
            externalNativeBuild {
                cmake {
                    arguments "-DANDROID_ARM_NEON=TRUE", "-DANDROID_TOOLCHAIN=clang","-DANDROID_STL=gnustl_static"
                }
            }
        }
    
        externalNativeBuild {
            cmake {
                path 'src/main/jni/CMakeLists.txt'
            }
    
    //        ndkBuild {
    //            path 'src/main/jni/Android.mk'
    //        }
        }
    

    至此我们就可以跟随工程编译,编译出我们需要的库,最终编译的release版本已经strip去掉符号表的库在build\intermediates\transforms\stripDebugSymbol\release\folders\2000\3\main\lib\\
      未去除符号表的库在目录下build\intermediates\transforms\mergeJniLibs\release\folders\2000\3\main\lib\\目录下

    四、mp4v2使用需要注意的知识点

    至于mp4v2的接口调用网上已经太多了,就不介绍接口的使用,按照网上的基本没错,然后最终的就是要知道一下几点知识

    1. audioTrack和videoTrack都创建添加到MP4之后才可以写流数据
    2. 必须线程安全的通过MP4WriteSample写数据,就是不能多线程同时写数据,否则写出了的MP4文件播放中间自动停止播放错误的情况,elecard都无法解析MP4 中的h264
    3. h264的start code “0x00 00 00 01”,需要改写成h264除去0x00000001四个字节外的有效数据附载长度的大端字节形式
    4. AAC音频数据不能加ADTS header
    5. Android使用MediaCodec编码的第一帧音频或者视频数据都是codec config,通过判断编码数据的(bufferinfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0知道是配置数据,视频可以取出SPS、PPSMP4AddH264VideoTrack使用,音频2个字节的数据给MP4SetTrackESConfiguration使用
    6. 编码数据的bufferinfo.flags == MediaCodec.BUFFER_FLAG_KEY_FRAME 说明是关键帧,写视频数据MP4WriteSample(...,isSyncSample)最后一个参数通过上面的判断,关键帧isSyncSample就等于1,非关键帧就等于0.

    以下为一些参考

    https://code.google.com/archive/p/mp4v2/downloads
    http://blog.csdn.net/baiseled/article/details/52622269
    http://blog.csdn.net/baiseled/article/details/52643223
    markdown语法
    markdown使用语法

    相关文章

      网友评论

        本文标题:android mp4v2的编译和使用

        本文链接:https://www.haomeiwen.com/subject/ezoohxtx.html