C++ and Java functions intertune

Share experience summary, welcome to join

QQ group: 686809487

The projects are as follows:

Knowledge:

  • The use of CMakeLists. TXT
  • C++ creates child threads, consumers, and producers
  • Ffmpeg compilation
  • Ffmpeg high and low version library dynamic switching
  • Ffmpeg decodes audio and video
  • OpenSLES plays PCM audio
  • SoundTouch import and use
  • PCM data subcontracting processing
  • PCM data is encoded into AAC files using Mediacodec
  • OpenGLES renders images
  • OpenGLES renders YUV data
  • The recording
  • Shear music

Source code address:

Github.com/taxiao213/n…

Build. Gradle configuration

android {
    ```
    defaultConfig {
        ndk {
            abiFilters "armeabi-v7a"."arm64-v8a"."x86"."x86_64"
        }
        externalNativeBuild {
            cmake {
                / / parameters
                arguments "-DFFMPEG_BUILD_VERSION=${Integer.valueOf(FFMPEG_BUILD_VERSION)}"
                cppFlags "-fexceptions"."-frtti"
            }
        }
    }
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
            version "3.10.2"
        }
    }
    ```
}
Copy the code

CMakeLists. TXT configuration

cmake_minimum_required(VERSION 3.41.)

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)
Copy the code

NDK logs are printed

//
// 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

Copy the code

Java calls c++ methods

// Import the library to create native methods
    
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(a);
Copy the code

Native -lib. CPP implements the corresponding method

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++");
}
Copy the code

C++ calls Java methods

Native-lib. CPP gets JavaVM in JNI_OnLoad

/ / get the 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;
}
Copy the code

Txcalljava.cpp implements callback methods

// Pass JavaVM to the callback file to initialize the method that needs to be called back
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();
    }
}
Copy the code

Wechat official account (Taxiao), follow and forward, thank you