Я начинающий JNI, почему мой android jni C ++ пытается блокировать исключение - PullRequest
0 голосов
/ 08 мая 2020

Я новичок в JNI. Почему мой android jni C ++ пытается блокировать исключение? Код вылетает, когда и приложение вылетает без перехода к обработке исключений, это мой код

Activity re code Прием данных H264 с очередью на уровне JAVA Запустить поток декодирования и непрерывно взять кадр пакетов данных 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);
}

1 Ответ

0 голосов
/ 08 мая 2020

Вам следует внимательно прочитать документацию of avcodec_receive_frame:

Возвращать декодированные выходные данные из декодера.
Параметры
код avctx c контекст
кадр. Будет установлен видеокадр с подсчетом ссылок (в зависимости от типа декодера), выделенный декодером. Обратите внимание, что функция всегда будет вызывать av_frame_unref (frame), прежде чем делать что-либо еще.

Возвращает 0: успешно, кадр был возвращен
AVERROR (EAGAIN): вывод недоступно в этом состоянии - пользователь должен попытаться отправить новый ввод
AVERROR_EOF: декодер был полностью очищен, и больше не будет выходных кадров AVERROR (EINVAL): код c не открыт, или он - кодировщик другие отрицательные значения: допустимые ошибки декодирования

Я выделил две ключевые части информации:

  • Во-первых, вызов avcodec_receive_frame аннулирует vFrameOne . Если ваш другой поток находится в середине декодирования, ваша программа будет сканировать sh. Вам нужно будет установить sh механизм синхронизации между потоками получения и отображения, чтобы убедиться, что получатель всегда принимает в кадре, к которому он имеет доступ, и что он передает только полные кадры стороне отображения. (см. следующий пункт)
  • Во-вторых, вы должны проверить возвращаемое значение avcodec_receive_frame. Если вы видите AVERROR(EAGAIN), значит, вы получили недостаточно пакетов для создания полного кадра. Только если эта функция выдает 0, вы можете взять полный кадр и передать его отображающему потоку.
...