I am a novice JNI,Why doesn't my android jni C ++ try block catch an exception,The code crashes when and the app crashes without jumping to exception handling this is my code
Activity re code Receive H264 data with queue at JAVA layer Start a decoding thread and continuously take a frame of H264 data packets from the queue into the C ++ layer to decode with 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 File code
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);
}
}
At this time, a display thread is started in the C layer for screen rendering
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);
}
You should carefully read the documentation of avcodec_receive_frame
:
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
I have highlighted two key pieces of information:
avcodec_receive_frame
will invalidate vFrameOne
. If your other thread is in the middle of decoding, your program will crash. You will need to establish a synchronization mechanism between receiving and displaying threads to make sure the receiver is always receiving into a frame only it has access to, and that it only passes full frames to the displaying side. (see next point)avcodec_receive_frame
. If you see an AVERROR(EAGAIN)
you have not received enough packets to produce a full frame. Only if this function produces 0 can you take the full frame and hand it over to the displaying thread.