android studio new project, check it
Throw the compiled libffmpeg.so library to src/main/jniLibs/armeabi (mainly here I only compiled arm's ffmpeg library)
New file com.jni.FFmpegCmd
package com.jni; public class FFmpegCmd { static { System.loadLibrary("ffmpeg"); System.loadLibrary("ffmpeg-cmd"); } public static native int run(String[] commands); }
Create a ffmpeg-cmd.cpp file under cpp (that is, the directory with native-lib.cpp)
#include <jni.h> #include "ffmpeg.h" #include "android_log.h" extern "C" JNIEXPORT jint JNICALL Java_com_jni_FFmpegCmd_run(JNIEnv *env, jobject, jobjectArray commands) { int argc = env->GetArrayLength(commands); char *argv[argc]; for (int i = 0; i < argc; i++) { jstring js = (jstring) env->GetObjectArrayElement(commands, i); argv[i] = (char *) env->GetStringUTFChars(js, 0); } LOGD( " ===========Start command line execution =========== " ); return main(argc, argv); }
android_log.h
#ifdef ANDROID #include <android/log.h> #ifndef LOG_TAG #define MY_TAG "MYTAG" #define AV_TAG "AVLOG" #endif #define LOGE(format, ...) __android_log_print(ANDROID_LOG_ERROR, MY_TAG, format, ##__VA_ARGS__) #define LOGD(format, ...) __android_log_print(ANDROID_LOG_DEBUG, MY_TAG, format, ##__VA_ARGS__) #define XLOGD(...) __android_log_print(ANDROID_LOG_INFO,AV_TAG,__VA_ARGS__) #define XLOGE(...) __android_log_print(ANDROID_LOG_ERROR,AV_TAG,__VA_ARGS__) #else #define LOGE(format, ...) printf(MY_TAG format "\n", ##__VA_ARGS__) #define LOGD(format, ...) printf(MY_TAG format "\n", ##__VA_ARGS__) #define XLOGE(format, ...) fprintf(stdout, AV_TAG ": " format "\n", ##__VA_ARGS__) #define XLOGI(format, ...) fprintf(stderr, AV_TAG ": " format "\n", ##__VA_ARGS__) #endif
Copy the ffmpeg source files cmdutils.c cmdutils.h ffmpeg.cffmpeg_filter.cffmpeg_opt.c ffmpeg_hw.c to the cpp directory
The folder include lib compiled by ffmpeg is also copied to this directory
Modify ffmpeg.h to add int main(int argc, char **argv) at the end;
Modify ffmpeg.c
Add it at the end of the main method (I heard that it is to prevent the flashback problem in order to repeatedly execute the ffmpeg command)
nb_filtergraphs = 0; progress_avio = NULL; input_streams = NULL; nb_input_streams = 0; input_files = NULL; nb_input_files = 0; output_streams = NULL; nb_output_streams = 0; output_files = NULL; nb_output_files = 0;
Modify cmdutils.h
Before modification void exit_program( int ret) av_noreturn; After modification int exit_program( int ret); Before modification void show_help_children( const AVClass * class , int flags); // If you don't modify it, there will always be an error in the compilation. After modification void show_help_children( const AVClass *avClass, int flags);
Modify cmdutils.c
void exit_program( int ret) before modification { if (program_exit) program_exit(ret); exit(ret); } after modification int exit_program(int ret) { if (program_exit) program_exit(ret); return ret; }
CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1) add_library(ffmpeg-cmd SHARED src/main/cpp/cmdutils.c src/main/cpp/ffmpeg.c src/main/cpp/ffmpeg_filter.c src/main/cpp/ffmpeg_opt.c src/main/cpp/ffmpeg_hw.c src/main/cpp/ffmpeg-cmd.cpp) find_library(log-lib log android) include_directories(src/main/cpp/include src/main/cpp/lib E:/ffmpeg/4.0/build/ffmpeg-4.0) add_library(ffmpeg SHARED IMPORTED) set_target_properties(ffmpeg PROPERTIES IMPORTED_LOCATION E:/ffmpeg/4.0/build/android/arm/libffmpeg.so) target_link_libraries( ffmpeg-cmd ffmpeg android ${log-lib} )
build.gradle(Module:app)
This mainly needs to deal with the red part, other parts are automatically generated
Finally test it in MainActivity.java
public class MainActivity extends AppCompatActivity { private ExecutorService es = Executors.newSingleThreadExecutor(); String path = Environment.getExternalStorageDirectory().getPath(); private ProgressDialog progressDialog; private TextView tv; @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate (savedInstanceState); setContentView(R.layout.activity_main); tv = findViewById(R.id.sample_text); tv.setText( "Test" ); tv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { progressDialog = ProgressDialog.show(MainActivity.this,"","处理中"); new Thread(new Runnable() { @Override public void run() { String str = "ffmpeg -i %s -vcodec copy -f mpegts -y %s" ;//mp4 to ts -y will overwrite the file if it has the same name. If you don't add -y, you will be prompted whether there is a file with the same name overwritten. If you execute it again, it will flash back. String commandStr = String.format(str,path+"/data/qq.mp4",path+"/data/qq.ts"); String[] commands = commandStr.split("\\s+"); for(String command:commands){ Log.d(MainActivity.class.getName(),"command="+command); } final int sum = FFmpegCmd.run(commands); new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { if(sum == 0){ if(progressDialog != null){ progressDialog.dismiss(); } tv.setText( "Processed successfully" ); }else{ tv.setText( "Processing failed" ); } } }); } }).start(); } }); } }