原理我就不多说了,自行解决,我提供一个最新的实现方式。
1、编译h264
下载地址 http://www.videolan.org/developers/x264.html
解压后出现x264文件夹,然后写一个sh,我是放到了x264同级目录下,这个随意注意地址就行。如下build_x264.sh。
cd x264
# NDK的路径,根据自己的安装位置进行设置
exportNDK=~/Library/Android/sdk/ndk-bundle
#编译针对的平台,可以根据自己的需求进行设置
#这里选择最低支持android-14, arm架构,生成的so库是放在
# libs/armeabi文件夹下的,若针对x86架构,要选择arch-x86
exportPLATFORM=$NDK/platforms/android-14/arch-arm
#工具链的路径,根据编译的平台不同而不同
# arm-linux-androideabi-4.9与上面设置的PLATFORM对应,4.9为工具的版本号,
#根据自己安装的NDK版本来确定,一般使用最新的版本
exportTOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
exportPREFIX=~/libx264
./configure \
--prefix=$PREFIX \
--enable-static \
--enable-shared \
--enable-pic \
--disable-asm \
--disable-cli \
--host=arm-linux \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--sysroot=$PLATFORM
make
make install
编译完成生成文件夹libx264,里面有后续用到的include&lib。
2、编译ffmpeg
下载地址 http://ffmpeg.org/
解压生成FFmpeg-master文件夹,然后要编写一个sh,如下build_with_x264.sh,脚本放入master文件夹。
#!/bin/bash
TMPDIR=/Users/liuxiaoyu/Downloads/ffmpegtemp
#这句很重要,不然会报错unable to create temporary file in,目录可以换,要提前建好!
# NDK的路径,根据自己的安装位置进行设置
NDK=~/Library/Android/sdk/ndk-bundle
#编译针对的平台,可以根据自己的需求进行设置
#这里选择最低支持android-14, arm架构,生成的so库是放在
# libs/armeabi文件夹下的,若针对x86架构,要选择arch-x86
PLATFORM=$NDK/platforms/android-14/arch-arm
#工具链的路径,根据编译的平台不同而不同
# arm-linux-androideabi-4.9与上面设置的PLATFORM对应,4.9为工具的版本号,
#根据自己安装的NDK版本来确定,一般使用最新的版本
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
#加入x264编译库上文中提到的
EXTRA_CFLAGS="-I/Users/liuxiaoyu/libx264/include"
EXTRA_LDFLAGS="-L/Users/liuxiaoyu/libx264/lib"
PREFIX=./android/
./configure \
--prefix=$PREFIX \
--target-os=linux \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--arch=arm \
--sysroot=$PLATFORM \
--extra-cflags=$EXTRA_CFLAGS \
--extra-ldflags=$EXTRA_LDFLAGS \
--cc=$TOOLCHAIN/bin/arm-linux-androideabi-gcc \
--nm=$TOOLCHAIN/bin/arm-linux-androideabi-nm \
--enable-static \
--enable-shared \
--enable-runtime-cpudetect \
--enable-gpl \
--enable-small \
--enable-cross-compile \
--enable-libx264 \
--enable-encoder=libx264 \
--enable-decoder=h264 \
--disable-debug \
--disable-doc \
--disable-asm \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--disable-postproc \
--disable-avdevice \
--disable-symver \
--disable-stripping
make clean
make -j8
make install
编译完成后在master目录中生成android文件夹,其中包含include&lib。
3、建立android项目
1、copy so库
�app目录下新建libs文件夹,libs下建立3个文件夹,armeabi,armeabi-v7a,include。
将ffmpeg编译出来的so库拷入armeabi,armeabi-v7a中,同时还要copy早前libx264中的so库。
将ffmpeg编译出来的include拷入include文件夹,如下图。
2、编写cmake文件
有人说我用的ndk-build,需要android.mk,怎么办。我建议还是尝试新东西吧,效率会高很多。
新建项目的时候勾选c++支持或者在项目上点右键增加c++支持。在main/cpp/目录中,编辑CMakeLists.txt。内容如下。
# Sets the minimum version of CMake required to build the native
# library. You should either keep the default value or only pass a
# value of 3.4.0 or lower.
cmake_minimum_required(VERSION 3.4.1)
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
set(distribution_DIR ${CMAKE_SOURCE_DIR}/../../../libs)
add_library( x264-148
SHARED
IMPORTED )
set_target_properties( x264-148
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/${ANDROID_ABI}/libx264-148.so )
add_library( avutil-55
SHARED
IMPORTED )
set_target_properties( avutil-55
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/${ANDROID_ABI}/libavutil-55.so )
add_library( swresample-2
SHARED
IMPORTED )
set_target_properties( swresample-2
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/${ANDROID_ABI}/libswresample-2.so )
add_library( avcodec-57
SHARED
IMPORTED )
set_target_properties( avcodec-57
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/${ANDROID_ABI}/libavcodec-57.so )
add_library( avfilter-6
SHARED
IMPORTED)
set_target_properties( avfilter-6
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/${ANDROID_ABI}/libavfilter-6.so )
add_library( swscale-4
SHARED
IMPORTED)
set_target_properties( swscale-4
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/${ANDROID_ABI}/libswscale-4.so )
add_library( avformat-57
SHARED
IMPORTED)
set_target_properties( avformat-57
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/${ANDROID_ABI}/libavformat-57.so )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
add_library( pretty SHARED ffmpeg-flv.c)
include_directories(${distribution_DIR}/include)
target_include_directories(pretty PRIVATE ${distribution_DIR}/include)
target_link_libraries( pretty x264-148 avutil-55 swresample-2 avcodec-57 avfilter-6 swscale-4 avformat-57
${log-lib} )
规则请参考官网在android studio使用与ndk使用,皆有篇幅介绍。
或者参考GoogleSamples
3、编写Activity,好像顺序有点乱。。。
packagecsupport.lyjq.com.csupport;
/**
* Created by liuxiaoyu on 2017/5/1.
*/
public classFlvActivityextendsAppCompatActivity {
private static finalStringTAG="MainActivity";
privateButtonmTakeButton;
privateCameramCamera;
privateSurfaceViewmSurfaceView;
privateSurfaceHoldermSurfaceHolder;
private booleanisRecording=false;
private classStreamTaskextendsAsyncTask {
private byte[]mData;
//构造函数
StreamTask(byte[] data){
this.mData= data;
}
@Override
protectedVoid doInBackground(Void... params) {
//TODO Auto-generated method stub
if(mData!=null){
Log.i(TAG,"fps: "+mCamera.getParameters().getPreviewFrameRate());
encode(mData);
}
return null;
}
}
privateStreamTaskmStreamTask;
@Override
protected voidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_flv);
finalCamera.PreviewCallback mPreviewCallbacx=newCamera.PreviewCallback() {
@Override
public voidonPreviewFrame(byte[] arg0, Camera arg1) {
//TODO Auto-generated method stub
if(null!=mStreamTask){
switch(mStreamTask.getStatus()){
caseRUNNING:
return;
casePENDING:
mStreamTask.cancel(false);
break;
}
}
mStreamTask=newStreamTask(arg0);
mStreamTask.execute((Void)null);
}
};
mTakeButton=(Button)findViewById(R.id.take_button);
PackageManager pm=this.getPackageManager();
booleanhasCamera=pm.hasSystemFeature(PackageManager.FEATURE_CAMERA) ||
pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT) ||
Build.VERSION.SDK_INT
if(!hasCamera)
mTakeButton.setEnabled(false);
mTakeButton.setOnClickListener(newView.OnClickListener() {
@Override
public voidonClick(View arg0) {
//TODO Auto-generated method stub
if(mCamera!=null)
{
if(isRecording) {
mTakeButton.setText("Start");
mCamera.setPreviewCallback(null);
Toast.makeText(FlvActivity.this,"encode done", Toast.LENGTH_SHORT).show();
isRecording=false;
}else{
mTakeButton.setText("Stop");
initial(mCamera.getParameters().getPreviewSize().width,mCamera.getParameters().getPreviewSize().height);
mCamera.setPreviewCallback(mPreviewCallbacx);
isRecording=true;
}
}
}
});
mSurfaceView=(SurfaceView)findViewById(R.id.surfaceView1);
SurfaceHolder holder=mSurfaceView.getHolder();
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
holder.addCallback(newSurfaceHolder.Callback() {
@Override
public voidsurfaceDestroyed(SurfaceHolder arg0) {
//TODO Auto-generated method stub
if(mCamera!=null)
{
mCamera.stopPreview();
mSurfaceView=null;
mSurfaceHolder=null;
}
}
@Override
public voidsurfaceCreated(SurfaceHolder arg0) {
//TODO Auto-generated method stub
try{
if(mCamera!=null){
mCamera.setPreviewDisplay(arg0);
mSurfaceHolder=arg0;
}
}catch(IOException exception){
Log.e(TAG,"Error setting up preview display", exception);
}
}
@Override
public voidsurfaceChanged(SurfaceHolder arg0,intarg1,intarg2,intarg3) {
//TODO Auto-generated method stub
if(mCamera==null)return;
Camera.Parameters parameters=mCamera.getParameters();
parameters.setPreviewSize(640,480);
parameters.setPictureSize(640,480);
mCamera.setParameters(parameters);
try{
mCamera.startPreview();
mSurfaceHolder=arg0;
}catch(Exception e){
Log.e(TAG,"could not start preview", e);
mCamera.release();
mCamera=null;
}
}
});
}
@TargetApi(9)
@Override
protected voidonResume(){
super.onResume();
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.GINGERBREAD){
mCamera=Camera.open(0);
}else
{
mCamera=Camera.open();
}
}
@Override
protected voidonPause(){
super.onPause();
flush();
close();
if(mCamera!=null){
mCamera.release();
mCamera=null;
}
}
//JNI
public native intinitial(intwidth,intheight);
public native intencode(byte[] yuvimage);
public native intflush();
public native intclose();
static{
System.loadLibrary("pretty");
}
}
好像写不下了,那么请接下篇吧
http://www.jianshu.com/p/893dc7ec1f20