android mp4v2的编译和使用

一、下载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使用语法

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,864评论 6 494
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,175评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,401评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,170评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,276评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,364评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,401评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,179评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,604评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,902评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,070评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,751评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,380评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,077评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,312评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,924评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,957评论 2 351

推荐阅读更多精彩内容

  • 本篇文章旨在简介 Android 中 NDK 是什么以及重点讲解最新 Android Studio 编译工具 CM...
    Tsy远阅读 63,330评论 20 213
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,918评论 25 707
  • 前段时间由于做比赛的事,一直都没时间写博客,现在终于可以补上一篇了,一直想学习一点NDK开发的知识,但是迟迟没有动...
    冰鉴IT阅读 1,754评论 7 18
  • 我们一起玩的还有一个同学叫刘洋,坐在张伟的后面,他的智商可以这么形容,就是加减法他也能算错,但是他真的很可爱,用傻...
    汤毛毛阅读 516评论 1 2
  • 伤口不会在出现的一刻感到疼痛,更多的是心惊。 血忽然涌出,带着快感。 这感觉,比疼痛来的快。 要过很长时间,才会感...
    尚巾木卯阅读 224评论 0 0