JNI和【NDK】音视频android视频相关

Android 音视频开发入门(一)

2019-05-28  本文已影响250人  吾乃韩小呆

作为资深失业用户,怀念一句话“裸辞一时爽,一直裸辞一直爽”,然后,笔者快要爽死了。好了言归正传,笔者开始带领大家一起学习很多人比较头痛的一个地方,音视频处理。马上 5g 要来了,虽然美国佬和中国闹得很凶,但是肯定不能阻挡科技的进程,所以,大家可以想一想5g到来了,什么东西会火起来呢?想来想去,移动端 音视频肯定会火,你想想,你坐着高铁开着用不完的流量看着 4k 甚至是清晰度更高的视频,什么感觉。所以不用多说,音视频很重要。
万事开头难,音视频处理可能会涉及大量的笔者从没接触的东西,或者读者也从未接触的,但是只要努力肯定没问题的哈。下面我们言归正传哈

一、创建项目

1、外表直观的东西

说到音视频开发,我们肯定要创建一个 c++ 的 Android 项目,不要头大,我们还要撰写 c++ 相关代码哈,各位看官 需要准备 带有 ndk 的 AS。创建工程各位应该都没有问题,然后,我们需要为 这个项目做一些特殊处理,如下:


特殊处理

我们需要为项目添加这两个工具,这样我们的项目就可以顺利运行了。
CMake:项目需要 CMake 进行编译
LLDB: 动态调试C++ 的库

简单说一下 c++ 项目 与普通 Android 项目的不同之处: 项目结构
这里比普通的 Android 项目多了 一个 cpp 文件夹里面包含“CMakeLists.txt”和“native-lib.cpp”两个文件这两个文件的作用分别是“引入外部动态库”和“撰写c++”代码

2、深入代码表层的东西

CMakeLists.txt 内生成代码含义

#CMakeLists 的版本
cmake_minimum_required(VERSION 3.4.1)
# 添加动态库的名属性
add_library(
        # 添加的动态库名字
        native-lib
        # 动态库的类型
        SHARED
        # 指定 cpp 文件所在位置
        native-lib.cpp)
# 表示使用系统自带的动态库
target_link_libraries(
        native-lib
        # 需要系统 log 日志的动态库
        log)

native-lib.cpp 文件内的代码含义 : 一个c++ 撰写的方法

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

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

在项目的module 下 build.gradle 内也增加一些东西分别是:

//添加的一些动态库
 externalNativeBuild {
            cmake {
                cppFlags ""
            }
        }

// CMakeList 的编译路径
 externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
            version "3.10.2"
        }
    }

项目的 MainActivity 内也存在差别

public class MainActivity extends AppCompatActivity {

//加载到系统 使用的动态库
    static {
        System.loadLibrary("native-lib");
    }

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

        TextView tv = findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
    }
  //调用 c++ 方法
    public native String stringFromJNI();
}

该介绍的都介绍完了,我们来运行一些我们的项目

运行一下项目

二、创建新的 library 进行 分包管理

创建一个 library 并将 视频处理相关文件 转移到 library 内 ,类似于组件化开发,文件迁移完成之后 ,library 的 结构如下


文件

library内的 build.gradle 的结构为

android {
    compileSdkVersion 28
    defaultConfig {
        minSdkVersion 21
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags ""
            }
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
            version "3.10.2"
        }
    }
}

三、项目内导入动态库

将我使用的 .so 文件上传到 csdn,连接为:自用 FFmpeg 动态库

1、导入 so 库

在 library 内的 main 文件夹下 建立 jniLibs 文件夹 将 “armeabi” 和 “X86” 的文件加入其中,如图


导入 so 文件

2、导入头文件

在 cpp 文件夹内 导入 “include”文件夹 :自用头文件

导入头文件

3、library 内的 build.gradle 内添加 abi 过滤

  externalNativeBuild {
            cmake {
                cppFlags ""
                abiFilters'armeabi','x86'
            }
        }

4、在 android 的大括号内 添加 sourceSets 配置

  sourceSets {
        main{
            jniLibs.srcDirs("src/main/jniLibs")
        }
    }

5、在 CMakeLists 内关联头文件路径

#关联 头文件路径
include_directories(src/main/cpp/include)

括号内表示 include 文件夹所在位置

6、设置动态库路径

在 CMakeLists.txt 内配置动态库的路径如下

#CMakeLists 的版本
cmake_minimum_required(VERSION 3.4.1)
#关联 头文件路径
include_directories(src/main/cpp/include)
# 引入自己需的动态库
add_library( avcodec-57 SHARED IMPORTED)
set_target_properties( avcodec-57
        PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libavcodec-57.so)


add_library( avdevice-57 SHARED IMPORTED)
set_target_properties( avdevice-57
        PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libavdevice-57.so)


add_library( avfilter-6 SHARED IMPORTED)
set_target_properties( avfilter-6
        PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libavfilter-6.so)


add_library( avformat-57 SHARED IMPORTED)
set_target_properties( avformat-57
        PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libavformat-57.so)


add_library( avutil-55 SHARED IMPORTED)
set_target_properties( avutil-55
        PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libavutil-55.so)

add_library( postproc-54 SHARED IMPORTED)
set_target_properties( postproc-54
        PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libpostproc-54.so)

add_library( swresample-2 SHARED IMPORTED)
set_target_properties( swresample-2
        PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libswresample-2.so)


add_library( swscale-4 SHARED IMPORTED)
set_target_properties( swscale-4
        PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libswscale-4.so)

# 添加动态库的名属性
add_library(
        # 添加的动态库名字
        native-lib
        # 动态库的类型
        SHARED
        # 指定 cpp 文件所在位置
        native-lib.cpp)
# 表示使用系统自带的动态库
target_link_libraries(
        native-lib
        avcodec-57
        avdevice-57
        avfilter-6
        avformat-57
        avutil-55
        postproc-54
        swresample-2
        swscale-4
        # 需要系统 log 日志的动态库
        log)
//上面表示项目内添加 该动态库
add_library( swscale-4 SHARED IMPORTED)
//下面表示该动态库路径
set_target_properties( swscale-4
        PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libswscale-4.so)

7、Java项目内引入动态库

package com.hxd.player;

public class Test {
    static {
        System.loadLibrary("native-lib");

        System.loadLibrary("avcodec-57");
        System.loadLibrary("avdevice-57");
        System.loadLibrary("avfilter-6");
        System.loadLibrary("avformat-57");
        System.loadLibrary("avutil-55");
        System.loadLibrary("postproc-54");
        System.loadLibrary("swresample-2");
        System.loadLibrary("swscale-4");
    }

    public native String stringFromJNI();
}

8、在撰写相关方法 测试动态库是否导入成功

Test.java 文件内撰写

  public native void TestFFmpeg ();

native-lib.cpp 内撰写

#include <android/log.h>
extern "C"{
#include "include/libavformat/avformat.h"
#include "include/libavutil/avutil.h"
#include "include/libavcodec/avcodec.h"
}


extern "C"
JNIEXPORT void JNICALL
Java_com_hxd_player_Test_TestFFmpeg(JNIEnv *env, jobject instance) {
    //导入头文件
    av_register_all();
    AVCodec *c_temp = av_codec_next(NULL);
    while (c_temp != NULL)
    {
        switch (c_temp->type)
        {
            case AVMEDIA_TYPE_VIDEO:
                LOGI("[Video]:%s", c_temp->name);
                break;
            case AVMEDIA_TYPE_AUDIO:
                LOGI("[Audio]:%s", c_temp->name);
                break;
            default:
                LOGI("[Other]:%s", c_temp->name);
                break;
        }
        c_temp = c_temp->next;
    }
}

9、在library 内和项目的 build.gradle 内进行配置

library 内

   defaultConfig {
        minSdkVersion 21
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags ""
                abiFilters"armeabi","x86"
            }
        }
        ndk {
            abiFilters"armeabi","x86"
        }
    }

项目内

   defaultConfig {
        applicationId "com.hxd.music"
        minSdkVersion 21
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        ndk {
            abiFilters"armeabi","x86"
        }
    }

最后 运行项目打印如下日志则表示 引入成功


项目运行成功

项目地址

上一篇下一篇

猜你喜欢

热点阅读