FFmpeg is an open source computer program that can record, convert, and stream digital audio and video. It provides a complete solution for recording, converting and streaming audio and video.

1. Write at the front

In the last article “Android NDK development (3) in the Linux environment to compile FFmpeg”, we learned how to compile FFmpeg source into so files, but these so files can not be directly referenced to the Android project, but also need to compile again to use. Today let’s learn how to port FFmpeg to Android and how to use FFmpeg from the command line in Android projects.

2. Environment construction

OS: Windows 10 64bit

NDK version: Android-NdK-R14B-Windows-x86_64

FFmpeg version: 3.4.2

Compiler: Android Studio 3.0

NDK build tool: CMake

Create an FFmpeg project

When creating a project, check the Include C++ support option and go all the way to the Customize C++ support Settings page:

You can see three options:

  • C++ Standard: C++ Standard. Selecting Toolchain Default will use the Default CMake configuration.

  • Exceptions Support: C++ exception handling is supported. The flag is -fexceptions.

  • Runtime Type Information Support: Runtime Type recognition, marked -FRTTI, enables programs to use Pointers or references to base classes to check the actual derived Type of the object to which these Pointers or references refer.

Here we use the default C++ standard, uncheck the following two options, and click Finish to proceed to the next step to see the structure of the project:

3. The FFmpeg transplantation

The preparatory work

  • Copy the compiled include folder to the SRC \main\ CPP directory.

  • Copy the cmDutils. c, cmDutils. h, FFmpeg. c, ffmpeg.h, ffmpeg_filter.c, and ffmpeg_opt.c classes in the FFTools directory of the FFmpeg source code to the SRC \main\ CPP directory.

  • Copy the compiled so file to SRC \main\jniLibs\armeabi, or create a new one if you don’t have one.

  • Rename native lib. CPP in SRC \main\jniLibs\armeabi to ffmpeg_cmd.c.

  • This article only compiles armeabi so files, so you need to set this up in build.gradle:

android {
    ...
	
    defaultConfig {
        ...
		
        ndk {
            abiFilters "armeabi"}}}Copy the code

Take a look at the project structure at this point:

Compile the script

Cmakelists.txt: cmakelists.txt: cmakelists.txt: cmakelists.txt

Set the Cmake versionCmake_minimum_required (VERSION 3.4.1 track)Set the CPP directory path
set(CPP_DIR ${CMAKE_SOURCE_DIR}/src/main/cpp)

# set jniLibs directory path
set(LIBS_DIR ${CMAKE_SOURCE_DIR}/src/main/jniLibs)

# add library
add_library( # library name
             ffmpeg

             # Dynamic library, generate so file
		     SHARED

		     # source
		     ${CPP_DIR}/cmdutils.c
		     ${CPP_DIR}/ffmpeg.c
		     ${CPP_DIR}/ffmpeg_filter.c
		     ${CPP_DIR}/ffmpeg_opt.c
		     ${CPP_DIR}/ffmpeg_cmd.c )

Used for various types of sound, image coding and decoding
add_library( # library name
             avcodec

             # Dynamic library, generate so file
             SHARED

             # indicates that the library is referenced, not generated
             IMPORTED )

# reference library file
set_target_properties( # library name
                       avcodec

                       # library path
                       PROPERTIES IMPORTED_LOCATION
                       ${LIBS_DIR}/armeabi/libavcodec.so )

For all kinds of audio and video packaging format generation and analysis, read audio and video frames and other functions
add_library( avformat
             SHARED
             IMPORTED )

set_target_properties( avformat
                       PROPERTIES IMPORTED_LOCATION
                       ${LIBS_DIR}/armeabi/libavformat.so )

Contains some common utility functions
add_library( avutil
             SHARED
             IMPORTED )

set_target_properties( avutil
                       PROPERTIES IMPORTED_LOCATION
                       ${LIBS_DIR}/armeabi/libavutil.so )

A variety of audio and video filters are provided
add_library( avfilter
             SHARED
             IMPORTED )

set_target_properties( avfilter
                       PROPERTIES IMPORTED_LOCATION
                       ${LIBS_DIR}/armeabi/libavfilter.so )

Used for audio resampling, sampling format conversion and mixing
add_library( swresample
             SHARED
             IMPORTED )

set_target_properties( swresample
                       PROPERTIES IMPORTED_LOCATION
                       ${LIBS_DIR}/armeabi/libswresample.so )

# Used for video scene scaling, color mapping conversion
add_library( swscale
             SHARED
             IMPORTED )

set_target_properties( swscale
                       PROPERTIES IMPORTED_LOCATION
                       ${LIBS_DIR}/armeabi/libswscale.so )

# quote source.. / indicates the upper-level directoryinclude_directories( .. /.. / ffmpeg 3.4.2 /${CPP_DIR}/include/ )

# associated library
target_link_libraries( ffmpeg
                       avcodec
                       avformat
                       avutil
                       avfilter
                       swresample
                       swscale )
Copy the code

Include_directories = FFmpeg = FFmpeg = FFmpeg = FFmpeg = FFmpeg = FFmpeg = FFmpeg = FFmpeg = FFmpeg But I tried to find a few files, so I referenced both.

Modify FFmpeg source code

  • src\main\cpp\ffmpeg.c

Modify main method:

// Modify: int main(int argc, char **argv)Copy the code

Reinitialize after executing the command:

// returnPreviously added: 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;Copy the code

Comment out the following code, otherwise it will crash after executing the command:

exit_program(received_nb_signals ? 255 : main_return_code);
Copy the code
  • src\main\cpp\ffmpeg.h
Int run(int argc, char **argv);Copy the code
  • src\main\cpp\cmdutils.c

Modify the exit method, the original code will directly exit APP, so need to modify:

Void exit_program(int ret) {if (program_exit)
        program_exit(ret);

    exit(ret); } int exit_program(int ret) {return ret;
}
Copy the code
  • src\main\cpp\cmdutils.h
Void exit_program(int ret) av_noreturn; Int exit_program(int ret);Copy the code

Modify ffmpeg_cmd. C

#include <jni.h>
#include "ffmpeg.h"

JNIEXPORT jint

JNICALL
Java_com_yl_ffmpeg4android_MainActivity_run(
        JNIEnv *env, jclass obj, jobjectArray commands) {
    int argc = (*env)->GetArrayLength(env, commands);
    char *argv[argc];

    int i;
    for (i = 0; i < argc; i++) {
        jstring js = (jstring) (*env)->GetObjectArrayElement(env, commands, i);
        argv[i] = (char *) (*env)->GetStringUTFChars(env, js, 0);
    }
    return run(argc, argv);
}
Copy the code

The method is simple: pass in instructions (type String[]), then call the run method in ffmpeg.h to execute these instructions, and click the compile button. If nothing else, an error will be reported.

Setting the compile mode

First look at the error:

After checking Baidu and Google, I did not find a solution. Later, I looked at CMake document again and again, and tried one parameter after another. Finally, I was in a good mood and looked at how to solve it:

android {
    ...
	
    defaultConfig {
        ...
		
        externalNativeBuild {
            cmake {
                arguments '-DANDROID_ARM_MODE=arm'}}}Copy the code

Set ANDROID_ARM_MOD to arm, default is thumb, OK, continue compiling, what? Error:

There are some undefined methods. Fortunately, we add a few empty methods to ffmpeg.c:

HWDevice *hw_device_get_by_name(const char *name) {
}

int hw_device_init_from_string(const char *arg, HWDevice **dev) {
}

void hw_device_free_all(void) {
}

int hw_device_setup_for_decode(InputStream *ist) {
}

int hw_device_setup_for_encode(OutputStream *ost) {
}
Copy the code

Recompile:

A long time ago the message appears, look at the compiled so file where:

4. Test

Write a simple Demo to test the successful compilation of FFmpeg, a video of the first 100 frames into a GIF, the code above:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    static {
        System.loadLibrary("ffmpeg");
    }

    private ImageView ivGif; private Button btnConvert; private ProgressDialog progressDialog; / / equipment private root directory path String path = Environment. External.getexternalstoragedirectory () getAbsolutePath (); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);

        ivGif= findViewById(R.id.iv_gif); btnConvert = findViewById(R.id.btn_convert); btnConvert.setOnClickListener(this); } @override public void onClick(View v) {// Capture the first 100 frames of the video final String CMD ="ffmpeg -i " + path + "/ video.mp4-vframes 100 -y -f gif-s 480x497" + path + "/video_100.gif"; Loading progressDialog = new progressDialog (this); progressDialog.setTitle("Intercepting...");
        progressDialog.show();

        new Thread() {
            @Override
            public void run() { super.run(); CmdRun (CMD); // Hide loading runOnUiThread(new)Runnable() {
                    @Override
                    public void run() { progressDialog.dismiss(); progressDialog = null; GIF Glide. With (mainactivity.this).load(new File(path +)"/video_500.gif"))
                                .into(ivGif); }}); } }.start(); } /** * split directives with Spaces to generate an array of type String ** @param CMD directives * @returnRun code */ private int cmdRun(String CMD) {String regulation ="[ \\t]+";
        final String[] split = cmd.split(regulation);
        returnrun(split); } /** * the run method defined in ffmpeg_cmd ** @param CMD * @returnExecute code */ public native int run(String[] CMD); }Copy the code

Take a look at the GIF:

5. Write at the end

If there are mistakes in the article, you can give me a message to correct, thank you!

The source code of FFmpeg used in the article, the compilation script and the generated so file have been uploaded to GitHub, and will be updated in the future. Welcome Start, Fork!

Making portal

Click me to download the Apk for this Demo