Jni dll 开发教程 vs2019 + idea

Jni dll 开发教程 vs2019 + idea

创建java类 native方法

💡 加载动态库
  • 函数System.loadLibrary()是加载dll(windows)或so(Linux)库
  • System.loadLibrary(“hello”); 需要将此库放到环境变量的路径中
  • 或者 System.load( System.getProperty(“user.dir”) + “/hello.dll”); 用户目录即程序目录下
  • 若此dll或so依赖别的动态库,需要根据依赖性先后添加动态库
  • 检查动态库依赖 windows:dumpbin.exe /dependents D:\py\hell0.dll
创建Native 方法 生成接口c++头文件

在java中编写jni c++ 要实现的方法 native 修饰
private native long createNativeAvTranscodeObj(int id);
idea 项目 src目录下 :格式 javah package.className
javah AVProcess.AVTranscodeJNI
生成 AVProcess_AVTranscodeJNI.h 有文件 接下来c++ 实现头文件生成动态库便可
生成如下c++函数接口

c++ jni 接口 头文件

#include <jni.h>
/* Header for class AVProcess_AVTranscodeJNI */

#ifndef _Included_AVProcess_AVTranscodeJNI
#define _Included_AVProcess_AVTranscodeJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     AVProcess_AVTranscodeJNI
 * Method:    createNativeAvTranscodeObj
 * Signature: (I)J
 */
JNIEXPORT jlong JNICALL Java_AVProcess_AVTranscodeJNI_createNativeAvTranscodeObj
  (JNIEnv *, jobject, jint);

/*
 * Class:     AVProcess_AVTranscodeJNI
 * Method:    ReleaseNativeAvTranscodeObj
 * Signature: (J)V
 */
JNIEXPORT void JNICALL Java_AVProcess_AVTranscodeJNI_ReleaseNativeAvTranscodeObj
  (JNIEnv *, jobject, jlong);
java jni接口
package AVProcess;
public class AVTranscodeJNI {

    static {
        // hello.dll (Windows) or libhello.so (Unixes)
        //System.out.println("当前dll加载路径:"+System.getProperty("java.library.path"));
        //System.setProperty("java.library.path", System.getProperty("user.dir") + "/lib");
        System.out.println(System.getProperty("user.dir"));
        System.load( System.getProperty("user.dir") + "/lib/avutil-57.dll");
        System.load( System.getProperty("user.dir") + "/lib/swscale-6.dll");
        System.load( System.getProperty("user.dir") + "/lib/libx264-164.dll");
        System.load( System.getProperty("user.dir") + "/lib/libx265.dll");
        System.loadLibrary(AVTranscode);

    }
    private long nativeAvTranObj;

    public AVTranscodeJNI(int id) {
        nativeAvTranObj = createNativeAvTranscodeObj(id);
    }

    public void finalize(){
        if(nativeAvTranObj != 0){
            ReleaseNativeAvTranscodeObj(nativeAvTranObj);
            nativeAvTranObj = 0;
        }
    }

    public void SetCallback(Callback callback){
        SetNativeCallback(nativeAvTranObj, callback);
    };

    public  int SetCompressLevel(int compressLevel){
        return SetNativeCompressLevel(nativeAvTranObj, compressLevel);
    };

    public int Pause(){
        return NativePause(nativeAvTranObj);
    };

    public int Running(){
        return NativeRunning(nativeAvTranObj);
    };

    public AVTranscoderState GetState(){
        return GetNativeState(nativeAvTranObj);
    };

    public int StartTranscode(String inAvPath, String outAvPath, int compressLevel){
        return StartNativeTranscode(nativeAvTranObj, inAvPath, outAvPath, compressLevel);
    };


    public int GetAvInfo(String avPath, VideoInfo avInfo){
        return GetNativeAvInfo(nativeAvTranObj, avPath, avInfo);
    };

    //native c++
    private native long createNativeAvTranscodeObj(int id);
    private native void ReleaseNativeAvTranscodeObj(long nativeAvTranObj);
    private native void SetNativeCallback(long nativeAvTranObj, Callback callback);
    private native int SetNativeCompressLevel(long nativeAvTranObj, int compressLevel);
    private native int NativePause(long nativeAvTranObj);
    private native int NativeRunning(long nativeAvTranObj);
    private native AVTranscoderState GetNativeState(long nativeAvTranObj);
    private native int StartNativeTranscode(long nativeAvTranObj, String inAvPath, String outAvPath, int compressLevel);
    private native int GetNativeAvInfo(long nativeAvTranObj, String avPath, VideoInfo avInfo);

    public static void main(String[] args) {
        System.out.println("Hello world!");
        AVTranscodeJNI transcoder = new AVTranscodeJNI(0);
        System.out.println(transcoder.GetState());
        VideoInfo avInfo = new VideoInfo();
        int ret = transcoder.GetAvInfo("00003.mp4", avInfo);
        System.out.println(avInfo);
        ret = transcoder.StartTranscode("000003.mp4", "out.mp4", 0);
        System.out.println(ret);
    }
}

开发 c++ dll

采用vs2019 开发 创建项目->动态库 直接将AVProcess_AVTranscodeJNI.h 复制到项目目录中便可

接口参数

JNIEnv 运行线程环境,jobject java调用对象 这两个是固定参数,其余是函数参数

保存c++ 对象方便调用

保存c++类对象地址存储为 java long nativeAvTranObj
java

private long nativeAvTranObj;

    public AVTranscodeJNI(int id) {
        nativeAvTranObj = createNativeAvTranscodeObj(id);
    }
JNIEXPORT jlong JNICALL Java_AVProcess_AVTranscodeJNI_createNativeAvTranscodeObj(JNIEnv* env, jobject obj, jint id) {
    Transcode* transcoder = NULL;
    transcoder = new Transcode(id);
    if (transcoder)
        return jlong(transcoder);
}
传入修改java对象

java 实现

    public int GetAvInfo(String avPath, VideoInfo avInfo){
        return GetNativeAvInfo(nativeAvTranObj, avPath, avInfo);
    };

c++jni 实现

JNIEXPORT jint JNICALL Java_AVProcess_AVTranscodeJNI_GetNativeAvInfo(JNIEnv* env, jobject obj, jlong tranObjAddr, jstring javPath, jobject javInfo) {
    Transcode* transcoder = (Transcode*)tranObjAddr;
    std::string avPath = JavaStringToString(env, javPath);
    if (avPath.empty()) {
        return -10000;
    }
    AVFileInfo avInfo;
    transcoder->GetVideoinfo(avPath, avInfo);

    jclass jclass_AvInfo = env->GetObjectClass(javInfo);

    jfieldID jformatId = env->GetFieldID(jclass_AvInfo, "format", "Ljava/lang/String;");
    jstring jfmtStr = StringToJavaString(env, avInfo.format);
    env->SetObjectField(javInfo, jformatId, jfmtStr);

    jfieldID jdurationSecsId = env->GetFieldID(jclass_AvInfo, "durationSecs", "I");
    env->SetIntField(javInfo, jdurationSecsId, avInfo.durationSecs);

    env->DeleteLocalRef(jclass_AvInfo);
    return 0;
}
c++ 中获得 java对象字段 方法

jclass jclass_AvInfo = env->GetObjectClass(javInfo); 获得java 类对象引用
jfieldID jformatId = env->GetFieldID(jclass_AvInfo, "format", "Ljava/lang/String;"); 获得类数据字段Id
env->SetObjectField(javInfo, jformatId, jfmtStr);设置数据字段值

JavaNative Interface FieldDescriptors

jni 字段描述符
Ljava/lang/String; string 数据字段
javac VideoInfo.java 生成 VideoInfo.class
javap -s -p VideoInfo.class 查看字段描述命令

java.lang.String format;
    descriptor: Ljava/lang/String;
  int durationSecs;
    descriptor: I
  long bitrate;
    descriptor: J

方法描述:

  private native AVProcess.VideoInfo GetNativeInAVInfo(long);
    descriptor: (J)LAVProcess/VideoInfo;

  private native AVProcess.VideoInfo GetNativeOutAVInfo(long);
    descriptor: (J)LAVProcess/VideoInfo;

  private native AVProcess.VideoInfo GetNativeAvInfo(long, java.lang.String);
    descriptor: (JLjava/lang/String;)LAVProcess/VideoInfo;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V

  static {};

c++ string 与java jstring 互转

windows 下 c++ 17

#include <windows.h>
std::string JavaStringToString(JNIEnv* env, jstring str) {
    if (env == nullptr || str == nullptr) {
        return "";
    }
    const jchar* chars = env->GetStringChars(str, NULL);
    if (chars == nullptr) {
        return "";
    }

    std::wstring wstring = reinterpret_cast<const wchar_t*>(chars);
    std::string u8_string;
    int dstWStrSize = WideCharToMultiByte(CP_ACP, 0, wstring.c_str(), wstring.size(), NULL, 0, NULL, NULL);
    if (dstWStrSize <= 0) {
        return "";
    }
    u8_string.resize(dstWStrSize);
    dstWStrSize = WideCharToMultiByte(CP_ACP, 0, wstring.c_str(), wstring.size(), &u8_string[0], u8_string.size(), NULL, NULL);
    //env->GetStringLength(str));
    env->ReleaseStringChars(str, chars);
    return u8_string;
}

jstring StringToJavaString(JNIEnv* env, const std::string& u8_string) {
    int dstStrSize = MultiByteToWideChar(CP_ACP, 0, u8_string.c_str(), u8_string.size(), NULL, 0);
    if (dstStrSize <= 0) {
        return NULL;
    }
    std::wstring wstring;
    wstring.resize(dstStrSize);
    int writedCharLen = MultiByteToWideChar(CP_UTF8, 0, u8_string.c_str(), u8_string.size(), &wstring[0], wstring.size());
    auto result = env->NewString(reinterpret_cast<const jchar*>(wstring.data()),
        wstring.length());
    return result;
}
设置c++ 回调java 函数

java

package AVProcess;

public interface Callback {
    public default void call(int id, int state, int progressRate){
        System.out.printf("id: %d, state: %d, progressRate: %d", id, state,progressRate);
    }
}
    public void SetCallback(Callback callback){
        SetNativeCallback(nativeAvTranObj, callback);
    };

jni c++

static JavaVM* jvm = NULL;
static jclass jcls = NULL;
static jmethodID methodId = NULL;

JNIEXPORT void JNICALL Java_AVProcess_AVTranscodeJNI_SetNativeCallback(JNIEnv* env, jobject obj, jlong tranObjAddr, jobject callObj) {
    jcls = env->GetObjectClass(callObj);
    methodId = env->GetMethodID(jcls, "call", "(I)V");
    Transcode* transcoder = (Transcode*)tranObjAddr;
    transcoder->SetCallback(ReportProgress);
    //env->CallVoidMethod(callObj, method, 5);
}

全局保存回调接口类引用、字段id、方法
c++ 回调

void CallBacl(int id, int state, int progressRate) {
    JNIEnv* env;
    if (!jvm || !jcls || !methodId)
        return;
    jvm->AttachCurrentThread(reinterpret_cast<void**>(&env), nullptr);
    jobject jobj = env->NewObject(jcls, methodId);
    env->CallVoidMethod(jobj, methodId, id, state, progressRate);
    env->DeleteLocalRef(jobj);
    jvm->DetachCurrentThread();
}

jvm: java 运行虚拟机环境
在 jni c++ 中获取 在java中执行 System.loadLibrary(AVTranscode);时自动执行此函数

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
    jvm = vm;
    JNIEnv* env;
    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_8) != JNI_OK) {
        return JNI_ERR;
    }
    return JNI_VERSION_1_8;
}
返回java 枚举对象

java
getAVTranState 方便 jni c++ 通过互相对应的值调用生成

package AVProcess;

public enum AVTranscoderState{
    READY, RUNNING, PAUSE, ENDING, FINISHED, EXIT, FAILURE;

    public static AVTranscoderState getAVTranState(int ordinal){
        AVTranscoderState states[] = values();
        if(ordinal < states.length && ordinal >= 0)
            return states[ordinal];
        return null;
    }
};

c++

JNIEXPORT jobject JNICALL Java_AVProcess_AVTranscodeJNI_GetNativeState(JNIEnv* env, jobject obj, jlong tranObjAddr) {

    Transcode* transcoder = (Transcode*)tranObjAddr;
    int state = int(transcoder->GetState());

    jclass jState = env->FindClass("AVProcess/AVTranscoderState");
    jmethodID j_method_getAVState = env->GetStaticMethodID(jState, "getAVTranState", "(I)LAVProcess/AVTranscoderState;");
    jobject objState = env->CallStaticObjectMethod(jState, j_method_getAVState, state);

    env->DeleteLocalRef(jState);
    return objState;
}

jmethodID: 获取java 方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值