C++ 和 Java 函數(shù)互調(diào)

分享經(jīng)驗(yàn)總結(jié),歡迎加入

項(xiàng)目如下:


aa.gif

知識(shí)點(diǎn):

  • CMakeLists.txt 的使用

  • c++ 創(chuàng)建子線程,消費(fèi)者和生產(chǎn)者

  • ffmpeg 編譯

  • ffmpeg 高低版本庫(kù)動(dòng)態(tài)切換

  • ffmpeg 解碼音視頻

  • OpenSLES 播放 pcm 音頻

  • soundTouch (變調(diào),變速)導(dǎo)入和使用

  • pcm 數(shù)據(jù)分包處理

  • pcm 數(shù)據(jù)使用 mediacodec 編碼成 aac 文件

  • OpenGLES 渲染圖片

  • OpenGLES 渲染 YUV 數(shù)據(jù)

  • 錄音

  • 剪切音樂(lè)

源碼地址:

https://github.com/taxiao213/ndk_project

build.gradle 配置

android {
     
    defaultConfig {
        ndk {
            abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
        }
        externalNativeBuild {
            cmake {
                // 傳參數(shù)
                arguments "-DFFMPEG_BUILD_VERSION=${Integer.valueOf(FFMPEG_BUILD_VERSION)}"
                cppFlags "-fexceptions", "-frtti"
            }
        }
    }
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
            version "3.10.2"
        }
    }
    
}

CMakeLists.txt 配置

cmake_minimum_required(VERSION 3.4.1)

if (FFMPEG_BUILD_VERSION EQUAL 1)
 include_directories(include/low_version)
 set(version low_version)
 set(avcodec libavcodec-57.so)
 set(avdevice libavdevice-57.so)
 set(avfilter libavfilter-6.so)
 set(avformat libavformat-57.so)
 set(avutil libavutil-55.so)
 set(postproc libpostproc-54.so)
 set(swresample libswresample-2.so)
 set(swscale libswscale-4.so)
elseif (FFMPEG_BUILD_VERSION EQUAL 2)
 include_directories(include/high_version)
 set(version high_version)
 set(avcodec libavcodec.so)
 set(avdevice libavdevice.so)
 set(avfilter libavfilter.so)
 set(avformat libavformat.so)
 set(avutil libavutil.so)
 set(postproc libpostproc.so)
 set(swresample libswresample.so)
 set(swscale libswscale.so)
endif ()
set(rootPath ${CMAKE_SOURCE_DIR}/../../jniLibs/${version}/${CMAKE_ANDROID_ARCH_ABI})
message("rootPath: ${rootPath}")

add_library(${avcodec} SHARED IMPORTED)
set_target_properties(${avcodec} PROPERTIES IMPORTED_LOCATION ${rootPath}/${avcodec})

add_library(${avdevice} SHARED IMPORTED)
set_target_properties(${avdevice} PROPERTIES IMPORTED_LOCATION ${rootPath}/${avdevice})

add_library(${avfilter} SHARED IMPORTED)
set_target_properties(${avfilter} PROPERTIES IMPORTED_LOCATION ${rootPath}/${avfilter})

add_library(${avformat} SHARED IMPORTED)
set_target_properties(${avformat} PROPERTIES IMPORTED_LOCATION ${rootPath}/${avformat})

add_library(${avutil} SHARED IMPORTED)
set_target_properties(${avutil} PROPERTIES IMPORTED_LOCATION ${rootPath}/${avutil})

add_library(${postproc} SHARED IMPORTED)
set_target_properties(${postproc} PROPERTIES IMPORTED_LOCATION ${rootPath}/${postproc})

add_library(${swresample} SHARED IMPORTED)
set_target_properties(${swresample} PROPERTIES IMPORTED_LOCATION ${rootPath}/${swresample})

add_library(${swscale} SHARED IMPORTED)
set_target_properties(${swscale} PROPERTIES IMPORTED_LOCATION ${rootPath}/${swscale})

include_directories(soundtouch/source)
aux_source_directory(soundtouch/source DIR_SRCS)

add_library(
 native-lib
 SHARED
 ${DIR_SRCS}
 native-lib.cpp
 javaListener.cpp
 TXCallJava.cpp
 TXFFmpeg.cpp
 TXAudio.cpp
 TXQueue.cpp
 TXPlayStatus.cpp
 TXCallBack.cpp
 TXBufferQueue.cpp
 TXPcmBean.cpp
 test/thread_test.cpp
 test/Opensles_test.cpp
 TXVideo.cpp
)

target_link_libraries(
 native-lib
 ${avcodec}
 ${avdevice}
 ${avfilter}
 ${avformat}
 ${avutil}
 ${postproc}
 ${swresample}
 ${swscale}
 OpenSLES
 log)

ndk 日志打印

// Created by yin13 on 2021/3/17.
//
#include "android/log.h"

#ifndef APPLE_ANDROID_LOG_H
#define APPLE_ANDROID_LOG_H
#endif //APPLE_ANDROID_LOG_H

#define TAG "TA_XIAO"
#define DEBUG 1
#if DEBUG
#define SDK_LOG_V(FORMAT, ...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, "[%s] line: %d info: " FORMAT, __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#define SDK_LOG_D(FORMAT, ...) __android_log_print(ANDROID_LOG_DEBUG, TAG, "[%s] line: %d info: " FORMAT, __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#define SDK_LOG_W(FORMAT, ...) __android_log_print(ANDROID_LOG_WARN, TAG, "[%s] line: %d info: " FORMAT, __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#define SDK_LOG_E(FORMAT, ...) __android_log_print(ANDROID_LOG_ERROR, TAG, "[%s] line: %d info: " FORMAT, __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#else
#define SDK_LOG_V(FORMAT, ...)
#define SDK_LOG_D(FORMAT, ...)
#define SDK_LOG_W(FORMAT, ...)
#define SDK_LOG_E(FORMAT, ...)
#endif

java 調(diào)用 c++ 方法

// 導(dǎo)入庫(kù),創(chuàng)建 native 方法
static {
 if (BuildConfig.FFMPEG_BUILD_VERSION == 1) {
 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");
 } else if (BuildConfig.FFMPEG_BUILD_VERSION == 2) {
 System.loadLibrary("avcodec");
 System.loadLibrary("avdevice");
 System.loadLibrary("avfilter");
 System.loadLibrary("avformat");
 System.loadLibrary("avutil");
 System.loadLibrary("postproc");
 System.loadLibrary("swresample");
 System.loadLibrary("swscale");
 }
 System.loadLibrary("native-lib");
}

public native void javaMain2C();

native-lib.cpp 實(shí)現(xiàn)相應(yīng)的方法

extern "C"
JNIEXPORT void JNICALL
Java_com_taxiao_ffmpeg_JniSdkImpl_javaMain2C(JNIEnv *env, jobject jobject1) {
 javaListener = new JavaListener(jvm, env, env->NewGlobalRef(jobject1));
 javaListener->onError(1, 111, "main c++");
}

c++ 調(diào)用 java 方法

native-lib.cpp 在 JNI_OnLoad 中獲取 JavaVM

// 獲取JVM
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
 jvm = vm;
 JNIEnv *env;
 if (jvm->GetEnv((void **) (&env), JNI_VERSION_1_4) != JNI_OK) {
 return -1;
 }
 return JNI_VERSION_1_4;
}

TXCallJava.cpp 實(shí)現(xiàn)回調(diào)方法

// 將 JavaVM 傳入回調(diào)文件初始化需要回調(diào)的方法
TXCallJava::TXCallJava(JavaVM *vm, JNIEnv *env, jobject *obj) {
 this->javaVm = vm;
 this->jniEnv = env;

 this->job = jniEnv->NewGlobalRef(*obj);
 jclass aClass = jniEnv->GetObjectClass(job);
 if (aClass) {
 jmethodId = jniEnv->GetMethodID(aClass, JAVA_METHOD_PARPARED, "()V");
 jmethodIdCallLoad = jniEnv->GetMethodID(aClass, JAVA_METHOD_LOAD, "(Z)V");
 jmethodIdTimeInfo = jniEnv->GetMethodID(aClass, JAVA_METHOD_TIME_INFO, "(II)V");
 jmethodIdError = jniEnv->GetMethodID(aClass, JAVA_METHOD_ERROR, "(ILjava/lang/String;)V");
 jmethodIdComplete = jniEnv->GetMethodID(aClass, JAVA_METHOD_COMPLETE, "()V");
 jmethodIdValumeDB = jniEnv->GetMethodID(aClass, JAVA_METHOD_VALUME_DB, "(I)V");
 jmethodIdPcmAAc = jniEnv->GetMethodID(aClass, JAVA_METHOD_PCM_AAC, "(I[B)V");
 jmethodIdRecordTime = jniEnv->GetMethodID(aClass, JAVA_METHOD_RECORD_TIME, "(F)V");
 jmethodIdCutAudio = jniEnv->GetMethodID(aClass, JAVA_METHOD_CUT_AUDIO, "(I[B)V");
 jmethodIdRenderYUV = jniEnv->GetMethodID(aClass, JAVA_METHOD_RENDER_YUV, "(II[B[B[B)V");
 jmethodIdIsSupportMediaCodec = jniEnv->GetMethodID(aClass,
 JAVA_METHOD_IS_SUPPORT_MEDIA_CODEC,
 "(Ljava/lang/String;)Z");
 jmethodIdInitMediaCodecVideo = jniEnv->GetMethodID(aClass,
 JAVA_METHOD_INIT_MEDIA_CODEC_VIDEO,
 "(Ljava/lang/String;II[B[B)V");

 jmethodIdDecodeAvPacket = jniEnv->GetMethodID(aClass, JAVA_METHOD_DECODE_AV_PACKET,
 "(I[B)V");
 }
}

void TXCallJava::onCallOnCutAudio(int type, int sampleRate, int size, void *pcmBuffer) {
 if (type == MAIN_THREAD) {
 jbyteArray pArray = jniEnv->NewByteArray(size);
 jniEnv->SetByteArrayRegion(pArray, 0, size, static_cast<const jbyte *>(pcmBuffer));
 jniEnv->CallVoidMethod(job, jmethodIdCutAudio, sampleRate, pArray);
 jniEnv->DeleteLocalRef(pArray);
 } else if (type == CHILD_THREAD) {
 JNIEnv *env;
 if (javaVm->AttachCurrentThread(&env, 0) != JNI_OK) {
 return;
 }
 jbyteArray pArray = env->NewByteArray(size);
 env->SetByteArrayRegion(pArray, 0, size, static_cast<const jbyte *>(pcmBuffer));
 env->CallVoidMethod(job, jmethodIdCutAudio, sampleRate, pArray);
 env->DeleteLocalRef(pArray);
 javaVm->DetachCurrentThread();
 }
}
(他曉),關(guān)注并轉(zhuǎn)發(fā),謝謝
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容