Ubuntu下为AndroidStudio编译并使用x264(二)AndroidStudio部分
16lz
2021-01-26
Android使用C/C++代码或库需要通过JNI方式,详细的可见相关文章。
x264.h
x264_config.h
到jni目录下
在jni目录下添加
x264encoder.h
x264encoder.cpp
main.cpp
三个源文件,详细源码如下:
/*
* \File
* x264encoder.cpp
* \Author
* Hank
*/
/*
* \File
* main.cpp
* \Author
* Hank
*/
#
# \File
# Android.mk
#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := tutorial01
#LOCAL_SRC_FILES := tutorial01.c
LOCAL_SRC_FILES := x264encoder.cpp main.cpp
LOCAL_LDLIBS := -llog -ljnigraphics -lz
#LOCAL_SHARED_LIBRARIES := libavformat libavcodec libswscale libavutil
LOCAL_SHARED_LIBRARIES := libx264
include $(BUILD_SHARED_LIBRARY)
$(call import-module,x264-snapshot-20151015-2245/android/arm)
2). 修改 jni/Application.mk成如下:
#
# \File
# Android.mk
#
APP_ABI := armeabi
#APP_ABI := armeabi-v7a
APP_PLATFORM := android-10
3). 修改 src/build.gradle成如下
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
applicationId "roman10.tutorial.android_ffmpeg_tutorial01"
minSdkVersion 19
targetSdkVersion 23
sourceSets.main{
jni.srcDirs=[]
jniLibs.srcDir "src/main/libs"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
debug {
debuggable true
jniDebuggable true
renderscriptDebuggable false
}
}
}
dependencies {
compile 'com.android.support:support-v4:18.0.0'
}
4). 编译
在main目录下:
$ cd app/src/main
$ ndk-build
[armeabi] Compile++ thumb: tutorial01 <= x264encoder.cpp
[armeabi] Compile++ thumb: tutorial01 <= main.cpp
[armeabi] Prebuilt : libx264.so <= <NDK>/sources/x264-snapshot-20151015-2245/android/arm/lib/
[armeabi] SharedLibrary : libtutorial01.so
[armeabi] Install : libtutorial01.so => libs/armeabi/libtutorial01.so
[armeabi] Install : libx264.so => libs/armeabi/libx264.so
表示编码成功;
public class MainActivity extends Activity {
// 调用参数的预定义
private static final String FRAME_DUMP_FOLDER_PATH = Environment.getExternalStorageDirectory()
+ File.separator + "android-264-encoder";
private static final String INPUT_YUV_FILENAME = "test_1920x1080.yuv";
private static int pWidth = 1920;
private static int pHeight = 1080;
@override
protected Void doInBackground(Void... params){
// 实际调用
encodeTime = naMain(mlOuterAct,
FRAME_DUMP_FOLDER_PATH + File.separator + INPUT_YUV_FILENAME,
mlNumOfFrames,
pWidth, pHeight );
}
/*
* 接口声明
* pVideoFileName : 表示输入文件名
* pNumOfFrame : 编码帧数
* Width : YUV源文件的图像宽度
* Height : YUV源文件的图像高度
*/
private static native int naMain(MainActivity pObject,
String pVideoFileName, int pNumOfFrame,
int Width, int Height);
// 库加载
static {
System.loadLibrary("x264");
System.loadLibrary("tutorial01");
}
}
再以android工程方式,编译运行;
1. 添加C/C++源文件
复制/opt/android/ndk/android-ndk-r10e/resources/x264下的文件:x264.h
x264_config.h
到jni目录下
在jni目录下添加
x264encoder.h
x264encoder.cpp
main.cpp
三个源文件,详细源码如下:
- /*
- *\File
- *x264encoder.h
- *\Author
- *Hank
- */
- #ifndef x264encoder_h
- #define x264encoder_h
- extern"C"
- {
- #include"stdint.h"
- #include"x264.h"
- enum bitrate_level
- {
- HIGH_LEVEL=0,
- STANDARD_LEVEL=1,
- MEDIUM_LEVEL=2,
- LOW_LEVEL=3,
- };
- classX264Encoder
- {
- public:
- X264Encoder();
- ~X264Encoder();
- bool openX264Encoder();
- //long x264EncoderProcess(uint8_t*pSrcData,intsrcDataSize,x264_nal_t**nals,int&nalsCount);
- long x264EncoderProcess(x264_picture_t*pPicture,x264_nal_t**nals,int&nalsCount);
- bool closeX264Encoder();
- void setSourceFormat(unsignedintsourcformat);
- void setResolution(unsignedintw,unsignedinth);
- void setBitrate(unsignedinti_bitrate);
- void setFps(unsignedintfps);
- void setI_KeyInt_Max(unsignedinti_frame_max);
- void setQp_Max(unsignedintqp_max);
- void setQp_Min(unsignedintqp_min);
- void forceIDRFrame();
- void upgradeBitrateLevel();
- void declineBitrateLevel();
- void setLeastBitrateLevel();
- private:
- x264_param_t*pParameter;
- x264_t*x264EncoderHandle;
- //x264_picture_t*pPicture;
- x264_picture_t*pOutput;
- unsignedintsourceFormat;
- //unsignedinti_bitrate;
- unsignedintbitratelevel;
- unsignedinti_fps;
- unsignedinti_keyint_max;
- unsignedintwidth;
- unsignedintheight;
- unsignedintqp_max;
- unsignedintqp_min;
- unsignedintcurrent_f_rf_constant;
- unsignedintuserSetting_f_rf_constant;
- int64_t frameNo;
- bool isForceIDRFrameEnabled;
- };
- }
- #endif
/*
* \File
* x264encoder.cpp
* \Author
* Hank
*/
- #include<stdlib.h>
- #include<string.h>
- #include"x264encoder.h"
- //new versionforx264 encoder
- X264Encoder::X264Encoder()
- {
- this->bitratelevel=STANDARD_LEVEL;
- qp_max=30;
- qp_min=0;
- i_fps=20;
- i_keyint_max=300;
- width=352;
- height=288;
- frameNo=0;
- isForceIDRFrameEnabled=false;
- pParameter=NULL;
- x264EncoderHandle=NULL;
- //pPicture=NULL;
- pOutput=NULL;
- }
- X264Encoder::~X264Encoder()
- {
- this->closeX264Encoder();
- }
- void X264Encoder::setSourceFormat(unsignedintsourcformat)
- {
- this->sourceFormat=sourcformat;
- }
- void X264Encoder::setResolution(unsignedintw,unsignedinth)
- {
- width=w;
- height=h;
- }
- void X264Encoder::setBitrate(unsignedinti_bitrate)
- {
- if(i_bitrate>0&&i_bitrate<=64){
- this->bitratelevel=LOW_LEVEL;
- }elseif(i_bitrate>64&&i_bitrate<=128){
- this->bitratelevel=MEDIUM_LEVEL;
- }elseif(i_bitrate>128&&i_bitrate<=256){
- this->bitratelevel=STANDARD_LEVEL;
- }elseif(i_bitrate>256&&i_bitrate<=384){
- this->bitratelevel=HIGH_LEVEL;
- }elseif(i_bitrate>384&&i_bitrate<=512){
- this->bitratelevel=HIGH_LEVEL;
- }else{
- this->bitratelevel=STANDARD_LEVEL;
- }
- }
- void X264Encoder::setFps(unsignedintfps)
- {
- i_fps=fps;
- }
- void X264Encoder::setI_KeyInt_Max(unsignedinti_frame_max)
- {
- i_keyint_max=i_frame_max;
- }
- void X264Encoder::setQp_Max(unsignedintqp_max)
- {
- this->qp_max=qp_max;
- }
- void X264Encoder::setQp_Min(unsignedintqp_min)
- {
- this->qp_min=qp_min;
- }
- bool X264Encoder::openX264Encoder(){
- this->closeX264Encoder();
- if(!pParameter)
- {
- pParameter=(x264_param_t*)malloc(sizeof(x264_param_t));
- if(!pParameter){
- this->closeX264Encoder();
- returnfalse;
- }
- memset(pParameter,0,sizeof(x264_param_t));
- }
- intret=x264_param_default_preset(pParameter,"ultrafast","zerolatency");
- if(ret!=0){
- this->closeX264Encoder();
- returnfalse;
- }
- pParameter->i_level_idc=30;
- pParameter->i_width=width;
- pParameter->i_height=height;
- pParameter->b_deterministic=1;
- //pParameter->b_sliced_threads=1;
- pParameter->i_threads=1;
- pParameter->i_csp=X264_CSP_I420;//X264_CSP_NV12;//X264_CSP_I420;
- pParameter->i_fps_num=i_fps;
- pParameter->i_fps_den=1;
- pParameter->i_bframe=0;
- pParameter->i_keyint_max=i_keyint_max;
- //pParameter->b_open_gop=1;
- //pParameter->rc.i_bitrate=i_bitrate;
- pParameter->rc.i_rc_method=X264_RC_CRF;//X264_RC_CQP;
- if(this->bitratelevel==LOW_LEVEL){
- pParameter->rc.f_rf_constant=32;
- }elseif(this->bitratelevel==MEDIUM_LEVEL){
- pParameter->rc.f_rf_constant=29;
- }elseif(this->bitratelevel==STANDARD_LEVEL){
- pParameter->rc.f_rf_constant=26;
- }elseif(this->bitratelevel==HIGH_LEVEL){
- pParameter->rc.f_rf_constant=24;
- }else{
- pParameter->rc.f_rf_constant=24;
- }
- current_f_rf_constant=pParameter->rc.f_rf_constant;
- userSetting_f_rf_constant=pParameter->rc.f_rf_constant;
- //from huxiaopeng
- pParameter->analyse.b_transform_8x8=1;
- pParameter->rc.f_aq_strength=1.5;
- pParameter->rc.i_aq_mode=0;
- pParameter->rc.f_qcompress=0.0;
- pParameter->rc.f_ip_factor=0.5;
- pParameter->rc.f_rate_tolerance=0.1;
- pParameter->analyse.i_direct_mv_pred=X264_DIRECT_PRED_AUTO;
- pParameter->analyse.i_me_method=X264_ME_DIA;
- pParameter->analyse.i_me_range=16;
- pParameter->analyse.i_subpel_refine=2;
- //pParameter->analyse.i_noise_reduction=1;
- pParameter->i_slice_max_size=1200;
- //pParameter->i_nal_hrd=X264_NAL_HRD_NONE;
- pParameter->b_deblocking_filter=1;
- pParameter->i_deblocking_filter_alphac0=4;
- pParameter->i_deblocking_filter_beta=4;
- pParameter->rc.b_mb_tree=0;
- pParameter->i_log_level=X264_LOG_NONE;
- if(x264_param_apply_profile(pParameter,"baseline"))
- //if(x264_param_apply_profile(pParameter,"main"))
- {
- this->closeX264Encoder();
- returnfalse;
- }
- if(!x264EncoderHandle){
- x264EncoderHandle=x264_encoder_open(pParameter);
- if(!x264EncoderHandle){
- this->closeX264Encoder();
- returnfalse;
- }
- }
- if(!pOutput){
- pOutput=(x264_picture_t*)malloc(sizeof(x264_picture_t));
- if(!pOutput){
- this->closeX264Encoder();
- returnfalse;
- }
- memset(pOutput,0,sizeof(x264_picture_t));
- }
- returntrue;
- }
- void X264Encoder::forceIDRFrame()
- {
- isForceIDRFrameEnabled=true;
- }
- void X264Encoder::upgradeBitrateLevel()
- {
- /*
- if(this->bitratelevel==HIGH_LEVEL){
- return;
- }
- this->bitratelevel++;
- if(this->bitratelevel==LOW_LEVEL){
- pParameter->rc.f_rf_constant=30;
- }elseif(this->bitratelevel==MEDIUM_LEVEL){
- pParameter->rc.f_rf_constant=27;
- }elseif(this->bitratelevel==STANDARD_LEVEL){
- pParameter->rc.f_rf_constant=24;
- }elseif(this->bitratelevel==HIGH_LEVEL){
- pParameter->rc.f_rf_constant=22;
- }else{
- pParameter->rc.f_rf_constant=23;
- }
- */
- if(userSetting_f_rf_constant>=current_f_rf_constant){
- return;
- }
- pParameter->rc.f_rf_constant--;
- current_f_rf_constant=pParameter->rc.f_rf_constant;
- x264_encoder_reconfig(x264EncoderHandle,pParameter);
- }
- void X264Encoder::setLeastBitrateLevel()
- {
- pParameter->rc.f_rf_constant=32;
- current_f_rf_constant=pParameter->rc.f_rf_constant;
- x264_encoder_reconfig(x264EncoderHandle,pParameter);
- }
- void X264Encoder::declineBitrateLevel()
- {
- if(32<=current_f_rf_constant){
- return;
- }
- pParameter->rc.f_rf_constant++;
- current_f_rf_constant=pParameter->rc.f_rf_constant;
- x264_encoder_reconfig(x264EncoderHandle,pParameter);
- }
- long X264Encoder::x264EncoderProcess(x264_picture_t*pPicture,x264_nal_t**nals,int&nalsCount)
- {
- pPicture->i_pts=(int64_t)(frameNo*pParameter->i_fps_den);
- pPicture->i_type=X264_TYPE_AUTO;
- pPicture->i_qpplus1=0;//X264_QP_AUTO;
- if(isForceIDRFrameEnabled){
- pPicture->i_type=X264_TYPE_IDR;
- isForceIDRFrameEnabled=false;
- }
- int32_t framesize=-1;
- framesize=x264_encoder_encode(x264EncoderHandle,nals,&nalsCount,pPicture,pOutput);
- if(framesize>0){
- frameNo++;
- }
- return framesize;
- }
- bool X264Encoder::closeX264Encoder()
- {
- if(pOutput){
- free(pOutput);
- pOutput=NULL;
- }
- /*
- if(pPicture){
- free(pPicture);
- pPicture=NULL;
- }
- */
- if(pParameter){
- free(pParameter);
- pParameter=NULL;
- }
- if(x264EncoderHandle){
- x264_encoder_close(x264EncoderHandle);
- x264EncoderHandle=NULL;
- }
- returntrue;
- }
/*
* \File
* main.cpp
* \Author
* Hank
*/
- #include<string.h>
- #include<stdlib.h>
- #include<arpa/inet.h>
- #include<stdio.h>
- #include<wchar.h>
- #include<time.h>
- #include<jni.h>
- /*forandroid logs*/
- #include<android/log.h>
- #include"x264.h"
- #include"x264_config.h"
- #include"x264encoder.h"
- #define LOG_TAG"android-ffmpeg-tutorial01"
- #define LOGI(...)__android_log_print(4,LOG_TAG,__VA_ARGS__);
- #define LOGE(...)__android_log_print(6,LOG_TAG,__VA_ARGS__);
- jint naMain(JNIEnv*pEnv,jobject pObj,jobject pMainAct,
- jstring pFileName,jint pNumOfFrames,
- jint picWidth,jint picHeight){
- /*Preset*/
- intnumOfFrames=pNumOfFrames;
- intpictureWidth=picWidth;
- intpictureHeight=picHeight;
- intpresetBitrate=512;
- intpresetFps=25;
- intpictureSize=pictureWidth*pictureHeight;
- intencodeTime=0;
- X264Encoder x264Encoder;
- x264Encoder.setBitrate(presetBitrate);
- x264Encoder.setResolution(pictureWidth,pictureHeight);
- x264Encoder.setFps(presetFps);
- char*yuvFilename=NULL;
- char*avcFilename=NULL;
- char str[80];
- FILE*inputFile=NULL;
- FILE*outputFile=NULL;
- //GetCstringfrom JNI jstring
- yuvFilename=(char*)pEnv->GetStringUTFChars(pFileName,NULL);
- if((inputFile=fopen(yuvFilename,"rb"))==NULL){
- LOGI("Can not open inputfile %s",yuvFilename);
- return-1;
- }
- strcpy(str,yuvFilename);
- strcat(str,".h264");
- avcFilename=str;
- LOGI("Output file: %s",avcFilename);
- if((outputFile=fopen(avcFilename,"wb"))==NULL){
- LOGI("Can not open outputfile %s",avcFilename);
- return-1;
- }
- x264_picture_t inputPicture;
- x264_picture_alloc(&inputPicture,X264_CSP_I420,pictureWidth,pictureHeight);
- x264_nal_t*p_nals=NULL;
- intnalsCount=0;
- intret=0;
- intj=0;
- if(x264Encoder.openX264Encoder())
- {
- struct timeval start,end;
- struct timeval sum;
- sum.tv_sec=0;
- sum.tv_usec=0;
- /*Including thetimeof read&write file
- gettimeofday(&start,NULL);
- LOGI("Encode start time : %ld.%ld",start.tv_sec,start.tv_usec);
- */
- for(j=0;j<numOfFrames;j++)
- {
- ret=fread(inputPicture.img.plane[0],1,pictureSize,inputFile);
- if(ret<pictureSize)
- {
- break;
- }
- fread(inputPicture.img.plane[1],1,pictureSize/4,inputFile);
- fread(inputPicture.img.plane[2],1,pictureSize/4,inputFile);
- gettimeofday(&start,NULL);
- x264Encoder.x264EncoderProcess(&inputPicture,&p_nals,nalsCount);
- gettimeofday(&end,NULL);
- if(end.tv_sec>start.tv_sec){
- sum.tv_sec+=(end.tv_sec-(start.tv_sec+1));
- sum.tv_usec+=((1000000-start.tv_usec)+end.tv_usec);
- LOGI("A Spend time: %ld.%ld",sum.tv_sec,sum.tv_usec);
- }else{
- sum.tv_sec+=(end.tv_sec-start.tv_sec);
- sum.tv_usec+=(end.tv_usec-start.tv_usec);
- LOGI("B Spend time: %ld.%ld",sum.tv_sec,sum.tv_usec);
- }
- if(p_nals)
- {
- for(inti=0;i<nalsCount;i++)
- {
- ret=fwrite(p_nals[i].p_payload,p_nals[i].i_payload,1,outputFile);
- LOGI("Write NO %d frame",j);
- LOGI("Should write %d bytes, in fact write %d bytes into %s",p_nals[i].i_payload,ret,avcFilename);
- }
- }
- }
- /*Including thetimeof read&write file
- gettimeofday(&end,NULL);
- LOGI("Encode end time : %ld.%ld",end.tv_sec,end.tv_usec);
- if(end.tv_sec>start.tv_sec){
- encodeTime=(end.tv_sec-(start.tv_sec+1))*1000000+((1000000-start.tv_usec)+end.tv_usec);
- LOGI("Spend time: %ld.%ld",(end.tv_sec-(start.tv_sec+1)),((1000000-start.tv_usec)+end.tv_usec));
- }else{
- encodeTime=(end.tv_sec-start.tv_sec)*1000000+(end.tv_usec-start.tv_usec);
- LOGI("Spend time: %ld.%ld",(end.tv_sec-start.tv_sec),end.tv_usec-start.tv_usec);
- }
- */
- encodeTime=(sum.tv_sec+(sum.tv_usec/1000000))*1000000+(sum.tv_usec%1000000);
- LOGI("Spend time: %ld.%ld",sum.tv_sec,sum.tv_usec);
- }
- fclose(inputFile);
- fclose(outputFile);
- LOGI("Closed the files!");
- x264_picture_clean(&inputPicture);
- x264Encoder.closeX264Encoder();
- LOGI("Closed the handler of encoder!");
- return encodeTime;
- //return 0;
- }
- staticconstJNINativeMethod gMethods[]={
- {"naMain",
- "(Lroman10/tutorial/android_ffmpeg_tutorial01/MainActivity;Ljava/lang/String;III)I",
- (void*)naMain
- },
- };
- jint JNI_OnLoad(JavaVM*vm,void*reserved)
- {
- JNIEnv*env=NULL;jint result=-1;
- if((vm->GetEnv((void**)&env,JNI_VERSION_1_6))!=JNI_OK)return-1;
- jclass clazz;staticconstchar*const
- kClassName="roman10/tutorial/android_ffmpeg_tutorial01/MainActivity";
- clazz=env->FindClass(kClassName);if(clazz==NULL){printf("cannot
- get class:%s\n",kClassName);return-1;}
- if(env->RegisterNatives(clazz,gMethods,
- sizeof(gMethods)/sizeof(gMethods[0]))!=JNI_OK){printf("register
- native method failed!\n");return-1;}
- return JNI_VERSION_1_6;
- }
2. 修改相关配置并编译
1). 修改jni/Android.mk成如下:#
# \File
# Android.mk
#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := tutorial01
#LOCAL_SRC_FILES := tutorial01.c
LOCAL_SRC_FILES := x264encoder.cpp main.cpp
LOCAL_LDLIBS := -llog -ljnigraphics -lz
#LOCAL_SHARED_LIBRARIES := libavformat libavcodec libswscale libavutil
LOCAL_SHARED_LIBRARIES := libx264
include $(BUILD_SHARED_LIBRARY)
$(call import-module,x264-snapshot-20151015-2245/android/arm)
2). 修改 jni/Application.mk成如下:
#
# \File
# Android.mk
#
APP_ABI := armeabi
#APP_ABI := armeabi-v7a
APP_PLATFORM := android-10
3). 修改 src/build.gradle成如下
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
applicationId "roman10.tutorial.android_ffmpeg_tutorial01"
minSdkVersion 19
targetSdkVersion 23
sourceSets.main{
jni.srcDirs=[]
jniLibs.srcDir "src/main/libs"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
debug {
debuggable true
jniDebuggable true
renderscriptDebuggable false
}
}
}
dependencies {
compile 'com.android.support:support-v4:18.0.0'
}
4). 编译
在main目录下:
$ cd app/src/main
$ ndk-build
[armeabi] Compile++ thumb: tutorial01 <= x264encoder.cpp
[armeabi] Compile++ thumb: tutorial01 <= main.cpp
[armeabi] Prebuilt : libx264.so <= <NDK>/sources/x264-snapshot-20151015-2245/android/arm/lib/
[armeabi] SharedLibrary : libtutorial01.so
[armeabi] Install : libtutorial01.so => libs/armeabi/libtutorial01.so
[armeabi] Install : libx264.so => libs/armeabi/libx264.so
表示编码成功;
3. 修改java源文件
修改MainActivity.java,添加调用的接口public class MainActivity extends Activity {
// 调用参数的预定义
private static final String FRAME_DUMP_FOLDER_PATH = Environment.getExternalStorageDirectory()
+ File.separator + "android-264-encoder";
private static final String INPUT_YUV_FILENAME = "test_1920x1080.yuv";
private static int pWidth = 1920;
private static int pHeight = 1080;
@override
protected Void doInBackground(Void... params){
// 实际调用
encodeTime = naMain(mlOuterAct,
FRAME_DUMP_FOLDER_PATH + File.separator + INPUT_YUV_FILENAME,
mlNumOfFrames,
pWidth, pHeight );
}
/*
* 接口声明
* pVideoFileName : 表示输入文件名
* pNumOfFrame : 编码帧数
* Width : YUV源文件的图像宽度
* Height : YUV源文件的图像高度
*/
private static native int naMain(MainActivity pObject,
String pVideoFileName, int pNumOfFrame,
int Width, int Height);
// 库加载
static {
System.loadLibrary("x264");
System.loadLibrary("tutorial01");
}
}
再以android工程方式,编译运行;
更多相关文章
- c/c++ android 平台交叉编译 {ERROR: Failed to create toolchai
- ubutun下NDK编译环境配置
- Android(安卓)编译错误总结及收集
- Android(安卓)Studio的各种冷知识,黑科技
- Android(安卓)Studio修改项目编译版本
- android ffmpeg4.0.2编译过程记录
- Android(安卓)2.3 CTS测试修改测试结果和调试方法
- Android(安卓)CPU, Compilers, D8 & R8
- Android多窗口的实现 - 开源