美文网首页
C++ 和 Java 函数互调

C++ 和 Java 函数互调

作者: 他晓 | 来源:发表于2021-06-28 20:30 被阅读0次

分享经验总结,欢迎加入

项目如下:


aa.gif

知识点:

  • CMakeLists.txt 的使用

  • c++ 创建子线程,消费者和生产者

  • ffmpeg 编译

  • ffmpeg 高低版本库动态切换

  • ffmpeg 解码音视频

  • OpenSLES 播放 pcm 音频

  • soundTouch (变调,变速)导入和使用

  • pcm 数据分包处理

  • pcm 数据使用 mediacodec 编码成 aac 文件

  • OpenGLES 渲染图片

  • OpenGLES 渲染 YUV 数据

  • 录音

  • 剪切音乐

源码地址:

https://github.com/taxiao213/ndk_project

build.gradle 配置

android {
     
    defaultConfig {
        ndk {
            abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
        }
        externalNativeBuild {
            cmake {
                // 传参数
                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 调用 c++ 方法

// 导入库,创建 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 实现相应的方法

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++ 调用 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 实现回调方法

// 将 JavaVM 传入回调文件初始化需要回调的方法
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();
 }
}
(他晓),关注并转发,谢谢

相关文章

  • C函数和C++函数相互调用的问题

    C函数和C++函数相互调用的问题

  • C++ 和 Java 函数互调

    分享经验总结,欢迎加入 项目如下: 知识点: CMakeLists.txt 的使用 c++ 创建子线程,消费者和生...

  • C&C++——C函数与C++函数相互调用问题

    【转载】C&C++——C函数与C++函数相互调用问题 C C++相互调用 在项目中融合C和C++有时是不可避免的,...

  • 关于c/c++互调的事情

    c/c++互调其实是老生常谈的事情了,不过还是说说自己的理解~。 c/c++互调无外乎c++文件里调用c的函数或者...

  • Java 和 Kotlin 互调

    Java 和 Kotlin 互调 1. 如何在 Java 中调用 Kotlin 参数类型为「函数」的函数? 来一个...

  • C/C++与Java之间的互相调用

    利用JNI技术,可以做到C/C++与Java之间的相互调用。 1、Java调用C/C++接口 一般把C/C++写成...

  • C++ 类虚函数原理

    学习过C++的童鞋都知道C++类成员函数可以分为虚函数和非虚函数,(java程序员就请绕过这个问题,因为java类...

  • JNI介绍和文档

    JNI 简介 JNI是JAVA和C/C++相互调用的桥梁 文档 官方文档 类型映射 Jni中定义了原始类型和jav...

  • 快速上⼿ Kotlin

    快速上⼿ Kotlin 基础语法 函数基础语法 与 Java 代码互调 Java 与 Kotlin 交互的语法变化...

  • kotlin-第一章

    02:最基础语法 变量声明 函数声明 03:Kotlin与java互调 java调kotlin Test.kt文件...

网友评论

      本文标题:C++ 和 Java 函数互调

      本文链接:https://www.haomeiwen.com/subject/prrcultx.html