android mp4v2的编译和使用

    • 一下载mp4v2源码
    • 二源码放入Android studio工程目录
      • 以下是我的目录结构
    • 三编写cmake脚本或者Makefile脚本
      • 以下为mp4v2模块的CMakeListstxt
      • 以下为外层我们JNI接口的CMakeListstxt
    • 三在buildgradle里配置cmake CMakeListstxt
      • buildgradle里的脚本配置
    • 四mp4v2使用需要注意的知识点

一、下载mp4v2源码

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

android mp4v2的编译和使用_第1张图片

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

1.以下是我的目录结构

android mp4v2的编译和使用_第2张图片

android mp4v2的编译和使用_第3张图片

android mp4v2的编译和使用_第4张图片

注意: 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,NDK)