Android中使用FFMPEG

一、JNI

先创建一个支持C++的Android的工程:

File->New->New Project->Phone and Tablet->Native C++ ->然后选择C++的版本,不清楚C++各个版本的,可以选择Toolchain Default。点击Finished。完成创建。

在创建完成后,我们将视图从Android切换到project。相比普通Android项目,这里多了两个文件夹。一个是app目录下的.cxx目录。一个是src/main/cpp目录。.cxx文件夹就是我们c编译过程中的临时文件。再看cpp目录,这里有两个文件,一个是CMakeLists.txt。这个文件就是需要我们在这里写入要放入工程中所依赖的所有的C++库文件。而native-lib.cpp文件则是C++与JAVA互相调用的中转方法。颇有跨平台Android中JS Bridge的感觉。我们可以查看系统中帮我们创建的示例方法:

#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_wfffmpeg_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

这里是系统自动创建的示范。我们写自己的文件只需按照这个来就行。注意这里方法名的格式:

Java_com_example_wfffmpeg_MainActivity_stringFromJNI

即是java.com.example.wfffmpeg package下的MainActivity的stringFromJNI。简单来说就是通过命名的规则,来定位一个文件。因为方法名不能出现点号.,所以,方法名用下划线_来代替包名中的.

接着我们来看看MainActivity.java中怎么去和这个方法通信:

package com.example.wfffmpeg;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Example of a call to a native method
        TextView tv = findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
}

看这个文件,这是一个普通Activity。在static的静态区域,使用System.loadLibrary("native-lib")引入nativie-lib库文件,就是我们上面写的桥接文件。也就是说在这个Activity刚启动的时候就引入。接着是方法的声明。注意这里的声明有个前缀native.完整的声明就是 public native String stringFromJNI();而在这个Activity中我们使用这个方法就可以直接调用stringFromJNI();

现在。我们已经了解了JNI的使用方法。那么下面看下作为C++库的FFMPEG,我们在Android中怎么使用吧:

1.在上一篇文章中,我们所编译了FFMPEG,产生了一些库文件,现在我们要把这些库文件,拷贝到工程中去。首先,我们把include文件夹全部拷入libs文件夹下面。

include文件夹下面有这么几个文件夹:

1.libavcodec 编码/解码

2.libavdevice 复用/解复用库专用设备(读设备)

3.libavfilter 基于帧的编辑库图(加特效)

4.libavformat I/O多路复用/解复用库

5.libavutil 常见的实用工具库

6.libpostproc 后处理库

7.libswresample 音频重采样、格式转换和混合

8.libswscale 颜色转换和缩放的图书馆(图像拉伸,像素格式转换)

接着,在libs文件夹下,新建armeabi文件夹。然后把

libavcodec-57.so、libavdevice-57.so、libavfilter-6.so、libavformat-57.so、libavutil-55.so、libpostproc-54.so、libswresample-2.so libswscale-4.so

这8个文件拷入armeabi文件夹下,拷贝后的工程文件结构目录为:

2.在上面一段中,我们说过CMakeLists.txt文件。就是要写入我们工程中所依赖的C++库文件的。因此我们需要在这个文件中写入相关信息:

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)
include_directories(libs/include)
set(DIR ../../../../libs)

project("wfffmpeg")


add_library(avcodec-57
        SHARED
        IMPORTED)
set_target_properties(avcodec-57
        PROPERTIES IMPORTED_LOCATION
        ${DIR}/armeabi/libavcodec-57.so)

add_library(avdevice-57
        SHARED
        IMPORTED)
set_target_properties(avdevice-57
        PROPERTIES IMPORTED_LOCATION
        ${DIR}/armeabi/libavdevice-57.so)

add_library(avformat-57
        SHARED
        IMPORTED)
set_target_properties(avformat-57
        PROPERTIES IMPORTED_LOCATION
        ${DIR}/armeabi/libavformat-57.so)

add_library(avutil-55
        SHARED
        IMPORTED)
set_target_properties(avutil-55
        PROPERTIES IMPORTED_LOCATION
        ${DIR}/armeabi/libavutil-55.so)

add_library(postproc-54
        SHARED
        IMPORTED)
set_target_properties(postproc-54
        PROPERTIES IMPORTED_LOCATION
        ${DIR}/armeabi/libpostproc-54.so)

add_library(swresample-2
        SHARED
        IMPORTED)
set_target_properties(swresample-2
        PROPERTIES IMPORTED_LOCATION
        ${DIR}/armeabi/libswresample-2.so)

add_library(swscale-4
        SHARED
        IMPORTED)
set_target_properties(swscale-4
        PROPERTIES IMPORTED_LOCATION
        ${DIR}/armeabi/libswscale-4.so)

add_library(avfilter-6
        SHARED
        IMPORTED)
set_target_properties(avfilter-6
        PROPERTIES IMPORTED_LOCATION
        ${DIR}/armeabi/libavfilter-6.so)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
             native-lib

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             native-lib.cpp )

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

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 )

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
        native-lib
        avfilter-6
        avcodec-57
        avdevice-57
        avformat-57
        avutil-55
        postproc-54
        swresample-2
        swscale-4
        # Links the target library to the log library
        # included in the NDK.
        ${log-lib})

3.修改app build.gradle文件

在defaultConfig文件中加入:

defaultConfig{
      /...
  externalNativeBuild {
              cmake {
                  cppFlags "-frtti -fexceptions"
              }
        }
   ndk {
              //选择要添加的对应cpu类型的.so库。
              abiFilters 'armeabi-v7a'
              // 还可以添加 'x86', 'x86_64', 'mips', 'mips64'
        }
}

4.编译

Build -> clean project -> Refresh Linked C++ Projects

然后连接手机,跑一跑,试试这个函数能否调用。如果出现问题,可以在这几个方面排查下:

1.检查CMakeLists.txt中代码配置是否正确。

2.检查CMakeLists.txt中so库是否一致。

3.检查CMakeLists.txt中target_link_libraries()是否遗漏

4.检查build.gradle文件中配置是否正确。

5.尝试在Project Structure中更换SDK版本。

后续我们将学习FFMPEG的具体功能。

祝各位同僚顺利!

 

猜你喜欢

转载自blog.csdn.net/howlaa/article/details/112824965#comments_23883841
今日推荐