我是JNI新手,为什么我的android jni C++ try块没有捕获到异常

I am a novice JNI,Why doesn't my android jni C ++ try block catch an exception

我是JNI新手,为什么我的androidjni C++ try块没有捕获到异常,代码崩溃时应用程序崩溃没有跳转到异常处理 这是我的代码

Activity重新编码 在 JAVA 层接收带队列的 H264 数据 启动一个解码线程,不断从队列中取出一帧H264数据包进入C++层用FFmpeg解码

    class decode extends Thread {
        @Override
        public void run() {
//            super.run();
            while (isDecode) {
                byte[] data = one.poll();
                if (data != null)
                    if (ffmpegUtilsInSignalOne != null)
                        ffmpegUtilsInSignalOne.decodeH264One(data);
            }
        }
    }

cpp 文件代码

extern "C"
JNIEXPORT void JNICALL
Java_cn_zhihuiyun_control_utils_FFMPEGUtils_decodeH264One(JNIEnv *env, jobject thiz,
                                                          jbyteArray data) {
    if (packetOne != nullptr && pCodecCtxOne != nullptr && vFrameOne != nullptr) {
        if (data == nullptr)
            return;;
        if (isPlay == 0)
            return;
        jbyte *arr = env->GetByteArrayElements(data, JNI_FALSE);
        packetOne->data = (uint8_t *) arr;
        packetOne->size = env->GetArrayLength(data);
        avcodec_send_packet(pCodecCtxOne, packetOne);
        avcodec_receive_frame(pCodecCtxOne, vFrameOne);
        av_packet_unref(packetOne);
        env->ReleaseByteArrayElements(data, arr, 0);
    }
}

此时在C层启动一个显示线程进行屏幕渲染

extern "C"
JNIEXPORT void JNICALL
Java_cn_zhihuiyun_control_utils_FFMPEGUtils_initVisThread(JNIEnv *env, jobject thiz) {
    isPlay = 1;
    threadVister = pthread_create(&threadVister, nullptr,
                                  reinterpret_cast<void *(*)(void *)>(&showVideo),
                                  (void *) env);
    pthread_detach(threadVister);
}

void *showVideo(JNIEnv *env) {
    try {
        while (isPlay == 1) {
            if (vFrameOne != nullptr && pFrameRGBAOne != nullptr && pCodecCtxOne != nullptr &&
                nativeWindowOne != nullptr) {
                ANativeWindow_lock(nativeWindowOne, &windowBufferOne, nullptr);
                av_image_fill_arrays(pFrameRGBAOne->data, pFrameRGBAOne->linesize,
                                     (const uint8_t *) windowBufferOne.bits, AV_PIX_FMT_RGBA,
                                     detWidth, detHeight, 1);
                int re = -1;
                try {
                    re = libyuv::I420ToARGB(vFrameOne->data[0], vFrameOne->linesize[0],
                                            vFrameOne->data[2], vFrameOne->linesize[2],
                                            vFrameOne->data[1], vFrameOne->linesize[1],
                                            pFrameRGBAOne->data[0], pFrameRGBAOne->linesize[0],
                                            pCodecCtxOne->width, pCodecCtxOne->height);
                    if (env->ExceptionCheck()) {
                        env->ExceptionDescribe();
                        env->ExceptionClear();
                    }
                } catch (...) {

                }
                if (re == -1) {

                } else {
                    ANativeWindow_unlockAndPost(nativeWindowOne);

                }
            }
            }
        }
    } catch (...) {
        printf("error");

    }
    if (vFrameOne != nullptr) {
        av_frame_free(&vFrameOne);
        vFrameOne = nullptr;
    }
    if (packetOne != nullptr) {
        av_free(packetOne);
        packetOne = nullptr;
    }
    if (pFrameRGBAOne != nullptr) {
        av_free(pFrameRGBAOne);
        pFrameRGBAOne = nullptr;
    }
    if (pCodecCtxOne != nullptr) {
        avcodec_free_context(&pCodecCtxOne);
        pCodecCtxOne = nullptr;
    }
    if (nativeWindowOne != nullptr) {
        ANativeWindow_release(nativeWindowOne);
        nativeWindowOne = nullptr;
    }

    pthread_exit(&threadVister);
}

你应该仔细阅读 avcodec_receive_framedocumentation:

Return decoded output data from a decoder.
Parameters
avctx codec context
frame This will be set to a reference-counted video or audio frame (depending on the decoder type) allocated by the decoder. Note that the function will always call av_frame_unref(frame) before doing anything else.

Returns 0: success, a frame was returned
AVERROR(EAGAIN): output is not available in this state - user must try to send new input
AVERROR_EOF: the decoder has been fully flushed, and there will be no more output frames AVERROR(EINVAL): codec not opened, or it is an encoder other negative values: legitimate decoding errors

我强调了两个关键信息:

  • 首先,对 avcodec_receive_frame 的调用将使 vFrameOne 无效。如果你的另一个线程正在解码,你的程序就会崩溃。您需要在接收线程和显示线程之间建立同步机制,以确保接收器始终接收到只有它有权访问的帧,并且它只将完整的帧传递给显示端。 (见下一点)
  • 其次,您应该检查 avcodec_receive_frame 的 return 值。如果您看到 AVERROR(EAGAIN),则表示您没有收到足够的数据包来生成完整的帧。只有当这个函数产生0时,你才能把完整的帧交给显示线程。