native-lib.cpp 7.2 KB
Newer Older
xiongziliang committed
1
#include <jni.h>
2 3 4 5
#include <string>
#include "test_server.cpp"

#define JNI_API(retType,funName,...) extern "C"  JNIEXPORT retType Java_com_zlmediakit_jni_ZLMediaKit_##funName(JNIEnv* env, jclass cls,##__VA_ARGS__)
6 7
#define MediaPlayerCallBackSign "com/zlmediakit/jni/ZLMediaKit$MediaPlayerCallBack"
#define MediaFrameSign "com/zlmediakit/jni/ZLMediaKit$MediaFrame"
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64


string stringFromJstring(JNIEnv *env,jstring jstr){
    if(!env || !jstr){
        WarnL << "invalid args";
        return "";
    }
    const char *field_char = env->GetStringUTFChars(jstr, 0);
    string ret(field_char,env->GetStringUTFLength(jstr));
    env->ReleaseStringUTFChars(jstr, field_char);
    return ret;
}
string stringFromJbytes(JNIEnv *env,jbyteArray jbytes){
    if(!env || !jbytes){
        WarnL << "invalid args";
        return "";
    }
    jbyte *bytes = env->GetByteArrayElements(jbytes, 0);
    string ret((char *)bytes,env->GetArrayLength(jbytes));
    env->ReleaseByteArrayElements(jbytes,bytes,0);
    return ret;
}
string stringFieldFromJava(JNIEnv *env,  jobject jdata,jfieldID jid){
    if(!env || !jdata || !jid){
        WarnL << "invalid args";
        return "";
    }
    jstring field_str = (jstring)env->GetObjectField(jdata,jid);
    auto ret = stringFromJstring(env,field_str);
    env->DeleteLocalRef(field_str);
    return ret;
}

string bytesFieldFromJava(JNIEnv *env,  jobject jdata,jfieldID jid){
    if(!env || !jdata || !jid){
        WarnL << "invalid args";
        return "";
    }
    jbyteArray jbufArray = (jbyteArray)env->GetObjectField(jdata, jid);
    string ret = stringFromJbytes(env,jbufArray);
    env->DeleteLocalRef(jbufArray);
    return ret;
}

jstring jstringFromString(JNIEnv* env, const char* pat) {
    return (jstring)env->NewStringUTF(pat);
}

jbyteArray jbyteArrayFromString(JNIEnv* env, const char* pat,int len = 0){
    if(len <= 0){
        len = strlen(pat);
    }
    jbyteArray jarray = env->NewByteArray(len);
    env->SetByteArrayRegion(jarray, 0, len, (jbyte *)(pat));
    return jarray;
}

65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
jobject makeJavaFrame(JNIEnv* env,const Frame::Ptr &frame){
    static jclass jclass_obj = (jclass)env->NewGlobalRef(env->FindClass(MediaFrameSign));
    static jmethodID jmethodID_init = env->GetMethodID(jclass_obj, "<init>", "()V");
    static jfieldID jfieldID_dts = env->GetFieldID(jclass_obj,"dts","I");
    static jfieldID jfieldID_pts = env->GetFieldID(jclass_obj,"pts","I");
    static jfieldID jfieldID_prefixSize = env->GetFieldID(jclass_obj,"prefixSize","I");
    static jfieldID jfieldID_keyFrame = env->GetFieldID(jclass_obj,"keyFrame","Z");
    static jfieldID jfieldID_data = env->GetFieldID(jclass_obj,"data","[B");
    static jfieldID jfieldID_trackType = env->GetFieldID(jclass_obj,"trackType","I");
    static jfieldID jfieldID_codecId = env->GetFieldID(jclass_obj,"codecId","I");

    if(!frame){
        return nullptr;
    }
    jobject ret = env->NewObject(jclass_obj, jmethodID_init);
    env->SetIntField(ret,jfieldID_dts,frame->dts());
    env->SetIntField(ret,jfieldID_pts,frame->pts());
    env->SetIntField(ret,jfieldID_prefixSize,frame->prefixSize());
    env->SetBooleanField(ret,jfieldID_keyFrame,frame->keyFrame());
    env->SetObjectField(ret,jfieldID_data,jbyteArrayFromString(env,frame->data(),frame->size()));
    env->SetIntField(ret,jfieldID_trackType,frame->getTrackType());
    env->SetIntField(ret,jfieldID_codecId,frame->getCodecId());
    return ret;
}

static JavaVM *s_jvm = nullptr;

template <typename FUN>
void doInJavaThread(FUN &&fun){
    JNIEnv *env;
    int status = s_jvm->GetEnv((void **) &env, JNI_VERSION_1_6);
    if (status != JNI_OK) {
        if (s_jvm->AttachCurrentThread(&env, NULL) != JNI_OK) {
            return;
        }
    }
    fun(env);
    if (status != JNI_OK) {
        //Detach线程
        s_jvm->DetachCurrentThread();
    }
}

#define emitEvent(delegate,method,argFmt,...) \
{ \
    doInJavaThread([&](JNIEnv* env) { \
        static jclass cls = env->GetObjectClass(delegate); \
        static jmethodID jmid = env->GetMethodID(cls, method, argFmt); \
        jobject localRef = env->NewLocalRef(delegate); \
        if(localRef){ \
            env->CallVoidMethod(localRef, jmid, ##__VA_ARGS__); \
        }else{ \
            WarnL << "弱引用已经释放:" << method << " " << argFmt; \
        }\
    }); \
}

122 123 124 125 126
/*
 * 加载动态库
 */
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
    //设置日志
127
    s_jvm = vm;
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
    Logger::Instance().add(std::make_shared<ConsoleChannel>());
    Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
    InfoL;
    return JNI_VERSION_1_6;
}
/*
 * 卸载动态库
 */
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved){
    InfoL;
    s_sem.post();
}


JNI_API(jboolean,startDemo,jstring path_to_jni_file){
    string sd_path = stringFromJstring(env,path_to_jni_file);
    string jni_file = sd_path +  "/zlmediakit.jni";

    DebugL << "sd_path:" << sd_path;
xiongziliang committed
147
    DebugL << "jni file:" << jni_file;
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162

    static thread s_th([sd_path,jni_file](){
        try {
            mINI::Instance()[Http::kRootPath] = mINI::Instance()[Hls::kFilePath] = sd_path + "/httpRoot";
            do_main(jni_file);
        }catch (std::exception &ex){
            WarnL << ex.what();
        }
    });

    static onceToken s_token([]{
        s_th.detach();
    });
    return true;
};
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205

JNI_API(jlong,createMediaPlayer,jstring url,jobject callback){
    static auto loadFrameClass = makeJavaFrame(env,nullptr);
    MediaPlayer::Ptr *ret = new MediaPlayer::Ptr(new MediaPlayer());
    MediaPlayer::Ptr &player = *ret;

    weak_ptr<MediaPlayer> weakPlayer = player;
    jobject globalWeakRef = env->NewWeakGlobalRef(callback);
    player->setOnPlayResult([weakPlayer,globalWeakRef](const SockException &ex) {
        auto strongPlayer = weakPlayer.lock();
        if (!strongPlayer) {
            return;
        }
        emitEvent((jobject)globalWeakRef,"onPlayResult","(ILjava/lang/String;)V",(jint)ex.getErrCode(),env->NewStringUTF(ex.what()));

        if(ex){
            return;
        }

        auto viedoTrack = strongPlayer->getTrack(TrackVideo);
        if (viedoTrack) {
            viedoTrack->addDelegate(std::make_shared<FrameWriterInterfaceHelper>([globalWeakRef](const Frame::Ptr &frame) {
                emitEvent((jobject)globalWeakRef,"onData","(L" MediaFrameSign ";)V",makeJavaFrame(env,frame));
            }));
        }

        auto audioTrack = strongPlayer->getTrack(TrackAudio);
        if (audioTrack) {
            audioTrack->addDelegate(std::make_shared<FrameWriterInterfaceHelper>([globalWeakRef](const Frame::Ptr &frame) {
                emitEvent((jobject)globalWeakRef,"onData","(L" MediaFrameSign ";)V",makeJavaFrame(env,frame));
            }));
        }

    });

    player->setOnShutdown([globalWeakRef,weakPlayer](const SockException &ex) {
        auto strongPlayer = weakPlayer.lock();
        if (!strongPlayer) {
            return;
        }
        emitEvent((jobject)globalWeakRef,"onShutdown","(ILjava/lang/String;)V",(jint)ex.getErrCode(),env->NewStringUTF(ex.what()));
    });

xiongziliang committed
206
    (*player)[Client::kRtpType] = Rtsp::RTP_TCP;
207 208 209 210 211 212 213 214 215 216 217
    player->play(stringFromJstring(env,url));

    return (jlong)(ret);
}



JNI_API(void,releaseMediaPlayer,jlong ptr){
    MediaPlayer::Ptr *player = (MediaPlayer::Ptr *)ptr;
    delete player;
}