美文网首页
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++ 和 Java 函数互调

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