diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index acfbbda..84591ec 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -38,6 +38,7 @@ add_library( # Sets the name of the library. src/main/cpp/visualizer/fixed_fft.cpp src/main/cpp/visualizer/block_queue.c src/main/cpp/visualizer/frank_visualizer.cpp + src/main/cpp/visualizer/frank_visualizer_jni.cpp src/main/cpp/visualizer/window.cpp ) diff --git a/app/src/main/cpp/visualizer/frank_visualizer.h b/app/src/main/cpp/visualizer/frank_visualizer.h index f55e51b..12a418f 100644 --- a/app/src/main/cpp/visualizer/frank_visualizer.h +++ b/app/src/main/cpp/visualizer/frank_visualizer.h @@ -36,12 +36,13 @@ typedef struct class FrankVisualizer { +private: + std::mutex mFftLock; + public: FrankVisualizer(); ~FrankVisualizer(); - std::mutex mFftLock; - filter_sys_t *fft_context = nullptr; void fft_run(); diff --git a/app/src/main/cpp/visualizer/frank_visualizer_jni.cpp b/app/src/main/cpp/visualizer/frank_visualizer_jni.cpp new file mode 100644 index 0000000..ca90716 --- /dev/null +++ b/app/src/main/cpp/visualizer/frank_visualizer_jni.cpp @@ -0,0 +1,80 @@ +// +// Created by frank on 2021/8/28. +// + +#include +#include "frank_visualizer.h" + +#define VISUALIZER_FUNC(RETURN_TYPE, NAME, ...) \ + extern "C" { \ + JNIEXPORT RETURN_TYPE \ + Java_com_frank_ffmpeg_effect_FrankVisualizer_ ## NAME \ + (JNIEnv* env, jobject thiz, ##__VA_ARGS__);\ + } \ + JNIEXPORT RETURN_TYPE \ + Java_com_frank_ffmpeg_effect_FrankVisualizer_ ## NAME \ + (JNIEnv* env, jobject thiz, ##__VA_ARGS__)\ + +struct fields_t { + jfieldID context; +}; + +static fields_t fields; +static const char *className = "com/frank/ffmpeg/effect/FrankVisualizer"; + +void setCustomVisualizer(JNIEnv *env, jobject thiz) { + auto *customVisualizer = new FrankVisualizer(); + jclass clazz = env->FindClass(className); + if (!clazz) { + return; + } + fields.context = env->GetFieldID(clazz, "mNativeVisualizer", "J"); + if (!fields.context) { + return; + } + env->SetLongField(thiz, fields.context, (jlong) customVisualizer); +} + +FrankVisualizer *getCustomVisualizer(JNIEnv *env, jobject thiz) { + if (!fields.context) return nullptr; + return (FrankVisualizer *) env->GetLongField(thiz, fields.context); +} + +void fft_callback(JNIEnv *jniEnv, int8_t * arg, int samples) { + jclass visual_class = jniEnv->FindClass(className); + jmethodID fft_method = jniEnv->GetStaticMethodID(visual_class, "onFftCallback", "([B)V"); + jbyteArray dataArray = jniEnv->NewByteArray(samples); + jniEnv->SetByteArrayRegion(dataArray, 0, samples, arg); + jniEnv->CallStaticVoidMethod(visual_class, fft_method, dataArray); + jniEnv->DeleteLocalRef(dataArray); +} + +VISUALIZER_FUNC(int, nativeInitVisualizer) { + setCustomVisualizer(env, thiz); + FrankVisualizer *mVisualizer = getCustomVisualizer(env, thiz); + if (!mVisualizer) return -2; + return mVisualizer->init_visualizer(); +} + +VISUALIZER_FUNC(int, nativeCaptureData, jobject buffer, jint size) { + if (!buffer) return -1; + FrankVisualizer *mVisualizer = getCustomVisualizer(env, thiz); + if (!mVisualizer || !mVisualizer->fft_context) return -2; + int nb_samples = size < MAX_FFT_SIZE ? size : MAX_FFT_SIZE; + if (nb_samples >= MIN_FFT_SIZE) { + mVisualizer->fft_context->nb_samples = nb_samples; + auto *direct_buffer = static_cast(env->GetDirectBufferAddress(buffer)); + memcpy(mVisualizer->fft_context->data, direct_buffer, static_cast(nb_samples)); + mVisualizer->fft_run(); + fft_callback(env, mVisualizer->fft_context->output, mVisualizer->fft_context->out_samples); + } + return 0; +} + +VISUALIZER_FUNC(void, nativeReleaseVisualizer) { + FrankVisualizer *mVisualizer = getCustomVisualizer(env, thiz); + if (!mVisualizer) return; + mVisualizer->release_visualizer(); + delete mVisualizer; + env->SetLongField(thiz, fields.context, 0); +} \ No newline at end of file diff --git a/app/src/main/java/com/frank/ffmpeg/effect/FrankVisualizer.java b/app/src/main/java/com/frank/ffmpeg/effect/FrankVisualizer.java new file mode 100644 index 0000000..68e215e --- /dev/null +++ b/app/src/main/java/com/frank/ffmpeg/effect/FrankVisualizer.java @@ -0,0 +1,53 @@ +package com.frank.ffmpeg.effect; + +import java.nio.ByteBuffer; + +/** + * @author frank + * @date 2021/10/1 11:25 + * @desc custom audio visualizer + */ +public class FrankVisualizer { + + private long mNativeVisualizer; + + private static OnFftDataListener mOnFftDataListener; + + public FrankVisualizer() {} + + public void setOnFftDataListener(OnFftDataListener onFftDataListener) { + mOnFftDataListener = onFftDataListener; + } + + public int initVisualizer() { + return nativeInitVisualizer(); + } + + public void captureData(ByteBuffer data, int size) { + if (data == null || size <= 0) { + nativeCaptureData(data, size); + } + } + + public void releaseVisualizer() { + mOnFftDataListener = null; + nativeReleaseVisualizer(); + } + + public interface OnFftDataListener { + void onFftData(byte[] data); + } + + public static void onFftCallback(byte[] data) { + if (mOnFftDataListener != null) { + mOnFftDataListener.onFftData(data); + } + } + + private native int nativeInitVisualizer(); + + private native int nativeCaptureData(ByteBuffer buffer, int size); + + private native void nativeReleaseVisualizer(); + +}