xref: /third_party/ffmpeg/libavcodec/ffjni.c (revision cabdff1a)
1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * JNI utility functions
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * Copyright (c) 2015-2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
5cabdff1aSopenharmony_ci *
6cabdff1aSopenharmony_ci * This file is part of FFmpeg.
7cabdff1aSopenharmony_ci *
8cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
9cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
10cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
11cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
12cabdff1aSopenharmony_ci *
13cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
14cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
15cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16cabdff1aSopenharmony_ci * Lesser General Public License for more details.
17cabdff1aSopenharmony_ci *
18cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
19cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
20cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21cabdff1aSopenharmony_ci */
22cabdff1aSopenharmony_ci
23cabdff1aSopenharmony_ci#include <jni.h>
24cabdff1aSopenharmony_ci#include <pthread.h>
25cabdff1aSopenharmony_ci#include <stdlib.h>
26cabdff1aSopenharmony_ci
27cabdff1aSopenharmony_ci#include "libavutil/bprint.h"
28cabdff1aSopenharmony_ci#include "libavutil/log.h"
29cabdff1aSopenharmony_ci#include "libavutil/mem.h"
30cabdff1aSopenharmony_ci
31cabdff1aSopenharmony_ci#include "config.h"
32cabdff1aSopenharmony_ci#include "jni.h"
33cabdff1aSopenharmony_ci#include "ffjni.h"
34cabdff1aSopenharmony_ci
35cabdff1aSopenharmony_cistatic JavaVM *java_vm;
36cabdff1aSopenharmony_cistatic pthread_key_t current_env;
37cabdff1aSopenharmony_cistatic pthread_once_t once = PTHREAD_ONCE_INIT;
38cabdff1aSopenharmony_cistatic pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
39cabdff1aSopenharmony_ci
40cabdff1aSopenharmony_cistatic void jni_detach_env(void *data)
41cabdff1aSopenharmony_ci{
42cabdff1aSopenharmony_ci    if (java_vm) {
43cabdff1aSopenharmony_ci        (*java_vm)->DetachCurrentThread(java_vm);
44cabdff1aSopenharmony_ci    }
45cabdff1aSopenharmony_ci}
46cabdff1aSopenharmony_ci
47cabdff1aSopenharmony_cistatic void jni_create_pthread_key(void)
48cabdff1aSopenharmony_ci{
49cabdff1aSopenharmony_ci    pthread_key_create(&current_env, jni_detach_env);
50cabdff1aSopenharmony_ci}
51cabdff1aSopenharmony_ci
52cabdff1aSopenharmony_ciJNIEnv *ff_jni_get_env(void *log_ctx)
53cabdff1aSopenharmony_ci{
54cabdff1aSopenharmony_ci    int ret = 0;
55cabdff1aSopenharmony_ci    JNIEnv *env = NULL;
56cabdff1aSopenharmony_ci
57cabdff1aSopenharmony_ci    pthread_mutex_lock(&lock);
58cabdff1aSopenharmony_ci    if (java_vm == NULL) {
59cabdff1aSopenharmony_ci        java_vm = av_jni_get_java_vm(log_ctx);
60cabdff1aSopenharmony_ci    }
61cabdff1aSopenharmony_ci
62cabdff1aSopenharmony_ci    if (!java_vm) {
63cabdff1aSopenharmony_ci        av_log(log_ctx, AV_LOG_ERROR, "No Java virtual machine has been registered\n");
64cabdff1aSopenharmony_ci        goto done;
65cabdff1aSopenharmony_ci    }
66cabdff1aSopenharmony_ci
67cabdff1aSopenharmony_ci    pthread_once(&once, jni_create_pthread_key);
68cabdff1aSopenharmony_ci
69cabdff1aSopenharmony_ci    if ((env = pthread_getspecific(current_env)) != NULL) {
70cabdff1aSopenharmony_ci        goto done;
71cabdff1aSopenharmony_ci    }
72cabdff1aSopenharmony_ci
73cabdff1aSopenharmony_ci    ret = (*java_vm)->GetEnv(java_vm, (void **)&env, JNI_VERSION_1_6);
74cabdff1aSopenharmony_ci    switch(ret) {
75cabdff1aSopenharmony_ci    case JNI_EDETACHED:
76cabdff1aSopenharmony_ci        if ((*java_vm)->AttachCurrentThread(java_vm, &env, NULL) != 0) {
77cabdff1aSopenharmony_ci            av_log(log_ctx, AV_LOG_ERROR, "Failed to attach the JNI environment to the current thread\n");
78cabdff1aSopenharmony_ci            env = NULL;
79cabdff1aSopenharmony_ci        } else {
80cabdff1aSopenharmony_ci            pthread_setspecific(current_env, env);
81cabdff1aSopenharmony_ci        }
82cabdff1aSopenharmony_ci        break;
83cabdff1aSopenharmony_ci    case JNI_OK:
84cabdff1aSopenharmony_ci        break;
85cabdff1aSopenharmony_ci    case JNI_EVERSION:
86cabdff1aSopenharmony_ci        av_log(log_ctx, AV_LOG_ERROR, "The specified JNI version is not supported\n");
87cabdff1aSopenharmony_ci        break;
88cabdff1aSopenharmony_ci    default:
89cabdff1aSopenharmony_ci        av_log(log_ctx, AV_LOG_ERROR, "Failed to get the JNI environment attached to this thread\n");
90cabdff1aSopenharmony_ci        break;
91cabdff1aSopenharmony_ci    }
92cabdff1aSopenharmony_ci
93cabdff1aSopenharmony_cidone:
94cabdff1aSopenharmony_ci    pthread_mutex_unlock(&lock);
95cabdff1aSopenharmony_ci    return env;
96cabdff1aSopenharmony_ci}
97cabdff1aSopenharmony_ci
98cabdff1aSopenharmony_cichar *ff_jni_jstring_to_utf_chars(JNIEnv *env, jstring string, void *log_ctx)
99cabdff1aSopenharmony_ci{
100cabdff1aSopenharmony_ci    char *ret = NULL;
101cabdff1aSopenharmony_ci    const char *utf_chars = NULL;
102cabdff1aSopenharmony_ci
103cabdff1aSopenharmony_ci    jboolean copy = 0;
104cabdff1aSopenharmony_ci
105cabdff1aSopenharmony_ci    if (!string) {
106cabdff1aSopenharmony_ci        return NULL;
107cabdff1aSopenharmony_ci    }
108cabdff1aSopenharmony_ci
109cabdff1aSopenharmony_ci    utf_chars = (*env)->GetStringUTFChars(env, string, &copy);
110cabdff1aSopenharmony_ci    if ((*env)->ExceptionCheck(env)) {
111cabdff1aSopenharmony_ci        (*env)->ExceptionClear(env);
112cabdff1aSopenharmony_ci        av_log(log_ctx, AV_LOG_ERROR, "String.getStringUTFChars() threw an exception\n");
113cabdff1aSopenharmony_ci        return NULL;
114cabdff1aSopenharmony_ci    }
115cabdff1aSopenharmony_ci
116cabdff1aSopenharmony_ci    ret = av_strdup(utf_chars);
117cabdff1aSopenharmony_ci
118cabdff1aSopenharmony_ci    (*env)->ReleaseStringUTFChars(env, string, utf_chars);
119cabdff1aSopenharmony_ci    if ((*env)->ExceptionCheck(env)) {
120cabdff1aSopenharmony_ci        (*env)->ExceptionClear(env);
121cabdff1aSopenharmony_ci        av_log(log_ctx, AV_LOG_ERROR, "String.releaseStringUTFChars() threw an exception\n");
122cabdff1aSopenharmony_ci        return NULL;
123cabdff1aSopenharmony_ci    }
124cabdff1aSopenharmony_ci
125cabdff1aSopenharmony_ci    return ret;
126cabdff1aSopenharmony_ci}
127cabdff1aSopenharmony_ci
128cabdff1aSopenharmony_cijstring ff_jni_utf_chars_to_jstring(JNIEnv *env, const char *utf_chars, void *log_ctx)
129cabdff1aSopenharmony_ci{
130cabdff1aSopenharmony_ci    jstring ret;
131cabdff1aSopenharmony_ci
132cabdff1aSopenharmony_ci    ret = (*env)->NewStringUTF(env, utf_chars);
133cabdff1aSopenharmony_ci    if ((*env)->ExceptionCheck(env)) {
134cabdff1aSopenharmony_ci        (*env)->ExceptionClear(env);
135cabdff1aSopenharmony_ci        av_log(log_ctx, AV_LOG_ERROR, "NewStringUTF() threw an exception\n");
136cabdff1aSopenharmony_ci        return NULL;
137cabdff1aSopenharmony_ci    }
138cabdff1aSopenharmony_ci
139cabdff1aSopenharmony_ci    return ret;
140cabdff1aSopenharmony_ci}
141cabdff1aSopenharmony_ci
142cabdff1aSopenharmony_ciint ff_jni_exception_get_summary(JNIEnv *env, jthrowable exception, char **error, void *log_ctx)
143cabdff1aSopenharmony_ci{
144cabdff1aSopenharmony_ci    int ret = 0;
145cabdff1aSopenharmony_ci
146cabdff1aSopenharmony_ci    AVBPrint bp;
147cabdff1aSopenharmony_ci
148cabdff1aSopenharmony_ci    char *name = NULL;
149cabdff1aSopenharmony_ci    char *message = NULL;
150cabdff1aSopenharmony_ci
151cabdff1aSopenharmony_ci    jclass class_class = NULL;
152cabdff1aSopenharmony_ci    jmethodID get_name_id = NULL;
153cabdff1aSopenharmony_ci
154cabdff1aSopenharmony_ci    jclass exception_class = NULL;
155cabdff1aSopenharmony_ci    jmethodID get_message_id = NULL;
156cabdff1aSopenharmony_ci
157cabdff1aSopenharmony_ci    jstring string = NULL;
158cabdff1aSopenharmony_ci
159cabdff1aSopenharmony_ci    av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
160cabdff1aSopenharmony_ci
161cabdff1aSopenharmony_ci    exception_class = (*env)->GetObjectClass(env, exception);
162cabdff1aSopenharmony_ci    if ((*env)->ExceptionCheck(env)) {
163cabdff1aSopenharmony_ci        (*env)->ExceptionClear(env);
164cabdff1aSopenharmony_ci        av_log(log_ctx, AV_LOG_ERROR, "Could not find Throwable class\n");
165cabdff1aSopenharmony_ci        ret = AVERROR_EXTERNAL;
166cabdff1aSopenharmony_ci        goto done;
167cabdff1aSopenharmony_ci    }
168cabdff1aSopenharmony_ci
169cabdff1aSopenharmony_ci    class_class = (*env)->GetObjectClass(env, exception_class);
170cabdff1aSopenharmony_ci    if ((*env)->ExceptionCheck(env)) {
171cabdff1aSopenharmony_ci        (*env)->ExceptionClear(env);
172cabdff1aSopenharmony_ci        av_log(log_ctx, AV_LOG_ERROR, "Could not find Throwable class's class\n");
173cabdff1aSopenharmony_ci        ret = AVERROR_EXTERNAL;
174cabdff1aSopenharmony_ci        goto done;
175cabdff1aSopenharmony_ci    }
176cabdff1aSopenharmony_ci
177cabdff1aSopenharmony_ci    get_name_id = (*env)->GetMethodID(env, class_class, "getName", "()Ljava/lang/String;");
178cabdff1aSopenharmony_ci    if ((*env)->ExceptionCheck(env)) {
179cabdff1aSopenharmony_ci        (*env)->ExceptionClear(env);
180cabdff1aSopenharmony_ci        av_log(log_ctx, AV_LOG_ERROR, "Could not find method Class.getName()\n");
181cabdff1aSopenharmony_ci        ret = AVERROR_EXTERNAL;
182cabdff1aSopenharmony_ci        goto done;
183cabdff1aSopenharmony_ci    }
184cabdff1aSopenharmony_ci
185cabdff1aSopenharmony_ci    string = (*env)->CallObjectMethod(env, exception_class, get_name_id);
186cabdff1aSopenharmony_ci    if ((*env)->ExceptionCheck(env)) {
187cabdff1aSopenharmony_ci        (*env)->ExceptionClear(env);
188cabdff1aSopenharmony_ci        av_log(log_ctx, AV_LOG_ERROR, "Class.getName() threw an exception\n");
189cabdff1aSopenharmony_ci        ret = AVERROR_EXTERNAL;
190cabdff1aSopenharmony_ci        goto done;
191cabdff1aSopenharmony_ci    }
192cabdff1aSopenharmony_ci
193cabdff1aSopenharmony_ci    if (string) {
194cabdff1aSopenharmony_ci        name = ff_jni_jstring_to_utf_chars(env, string, log_ctx);
195cabdff1aSopenharmony_ci        (*env)->DeleteLocalRef(env, string);
196cabdff1aSopenharmony_ci        string = NULL;
197cabdff1aSopenharmony_ci    }
198cabdff1aSopenharmony_ci
199cabdff1aSopenharmony_ci    get_message_id = (*env)->GetMethodID(env, exception_class, "getMessage", "()Ljava/lang/String;");
200cabdff1aSopenharmony_ci    if ((*env)->ExceptionCheck(env)) {
201cabdff1aSopenharmony_ci        (*env)->ExceptionClear(env);
202cabdff1aSopenharmony_ci        av_log(log_ctx, AV_LOG_ERROR, "Could not find method java/lang/Throwable.getMessage()\n");
203cabdff1aSopenharmony_ci        ret = AVERROR_EXTERNAL;
204cabdff1aSopenharmony_ci        goto done;
205cabdff1aSopenharmony_ci    }
206cabdff1aSopenharmony_ci
207cabdff1aSopenharmony_ci    string = (*env)->CallObjectMethod(env, exception, get_message_id);
208cabdff1aSopenharmony_ci    if ((*env)->ExceptionCheck(env)) {
209cabdff1aSopenharmony_ci        (*env)->ExceptionClear(env);
210cabdff1aSopenharmony_ci        av_log(log_ctx, AV_LOG_ERROR, "Throwable.getMessage() threw an exception\n");
211cabdff1aSopenharmony_ci        ret = AVERROR_EXTERNAL;
212cabdff1aSopenharmony_ci        goto done;
213cabdff1aSopenharmony_ci    }
214cabdff1aSopenharmony_ci
215cabdff1aSopenharmony_ci    if (string) {
216cabdff1aSopenharmony_ci        message = ff_jni_jstring_to_utf_chars(env, string, log_ctx);
217cabdff1aSopenharmony_ci        (*env)->DeleteLocalRef(env, string);
218cabdff1aSopenharmony_ci        string = NULL;
219cabdff1aSopenharmony_ci    }
220cabdff1aSopenharmony_ci
221cabdff1aSopenharmony_ci    if (name && message) {
222cabdff1aSopenharmony_ci        av_bprintf(&bp, "%s: %s", name, message);
223cabdff1aSopenharmony_ci    } else if (name && !message) {
224cabdff1aSopenharmony_ci        av_bprintf(&bp, "%s occurred", name);
225cabdff1aSopenharmony_ci    } else if (!name && message) {
226cabdff1aSopenharmony_ci        av_bprintf(&bp, "Exception: %s", message);
227cabdff1aSopenharmony_ci    } else {
228cabdff1aSopenharmony_ci        av_log(log_ctx, AV_LOG_WARNING, "Could not retrieve exception name and message\n");
229cabdff1aSopenharmony_ci        av_bprintf(&bp, "Exception occurred");
230cabdff1aSopenharmony_ci    }
231cabdff1aSopenharmony_ci
232cabdff1aSopenharmony_ci    ret = av_bprint_finalize(&bp, error);
233cabdff1aSopenharmony_cidone:
234cabdff1aSopenharmony_ci
235cabdff1aSopenharmony_ci    av_free(name);
236cabdff1aSopenharmony_ci    av_free(message);
237cabdff1aSopenharmony_ci
238cabdff1aSopenharmony_ci    if (class_class) {
239cabdff1aSopenharmony_ci        (*env)->DeleteLocalRef(env, class_class);
240cabdff1aSopenharmony_ci    }
241cabdff1aSopenharmony_ci
242cabdff1aSopenharmony_ci    if (exception_class) {
243cabdff1aSopenharmony_ci        (*env)->DeleteLocalRef(env, exception_class);
244cabdff1aSopenharmony_ci    }
245cabdff1aSopenharmony_ci
246cabdff1aSopenharmony_ci    if (string) {
247cabdff1aSopenharmony_ci        (*env)->DeleteLocalRef(env, string);
248cabdff1aSopenharmony_ci    }
249cabdff1aSopenharmony_ci
250cabdff1aSopenharmony_ci    return ret;
251cabdff1aSopenharmony_ci}
252cabdff1aSopenharmony_ci
253cabdff1aSopenharmony_ciint ff_jni_exception_check(JNIEnv *env, int log, void *log_ctx)
254cabdff1aSopenharmony_ci{
255cabdff1aSopenharmony_ci    int ret;
256cabdff1aSopenharmony_ci
257cabdff1aSopenharmony_ci    jthrowable exception;
258cabdff1aSopenharmony_ci
259cabdff1aSopenharmony_ci    char *message = NULL;
260cabdff1aSopenharmony_ci
261cabdff1aSopenharmony_ci    if (!(*(env))->ExceptionCheck((env))) {
262cabdff1aSopenharmony_ci        return 0;
263cabdff1aSopenharmony_ci    }
264cabdff1aSopenharmony_ci
265cabdff1aSopenharmony_ci    if (!log) {
266cabdff1aSopenharmony_ci        (*(env))->ExceptionClear((env));
267cabdff1aSopenharmony_ci        return -1;
268cabdff1aSopenharmony_ci    }
269cabdff1aSopenharmony_ci
270cabdff1aSopenharmony_ci    exception = (*env)->ExceptionOccurred(env);
271cabdff1aSopenharmony_ci    (*(env))->ExceptionClear((env));
272cabdff1aSopenharmony_ci
273cabdff1aSopenharmony_ci    if ((ret = ff_jni_exception_get_summary(env, exception, &message, log_ctx)) < 0) {
274cabdff1aSopenharmony_ci        (*env)->DeleteLocalRef(env, exception);
275cabdff1aSopenharmony_ci        return ret;
276cabdff1aSopenharmony_ci    }
277cabdff1aSopenharmony_ci
278cabdff1aSopenharmony_ci    (*env)->DeleteLocalRef(env, exception);
279cabdff1aSopenharmony_ci
280cabdff1aSopenharmony_ci    av_log(log_ctx, AV_LOG_ERROR, "%s\n", message);
281cabdff1aSopenharmony_ci    av_free(message);
282cabdff1aSopenharmony_ci
283cabdff1aSopenharmony_ci    return -1;
284cabdff1aSopenharmony_ci}
285cabdff1aSopenharmony_ci
286cabdff1aSopenharmony_ciint ff_jni_init_jfields(JNIEnv *env, void *jfields, const struct FFJniField *jfields_mapping, int global, void *log_ctx)
287cabdff1aSopenharmony_ci{
288cabdff1aSopenharmony_ci    int i, ret = 0;
289cabdff1aSopenharmony_ci    jclass last_clazz = NULL;
290cabdff1aSopenharmony_ci
291cabdff1aSopenharmony_ci    for (i = 0; jfields_mapping[i].name; i++) {
292cabdff1aSopenharmony_ci        int mandatory = jfields_mapping[i].mandatory;
293cabdff1aSopenharmony_ci        enum FFJniFieldType type = jfields_mapping[i].type;
294cabdff1aSopenharmony_ci
295cabdff1aSopenharmony_ci        if (type == FF_JNI_CLASS) {
296cabdff1aSopenharmony_ci            jclass clazz;
297cabdff1aSopenharmony_ci
298cabdff1aSopenharmony_ci            last_clazz = NULL;
299cabdff1aSopenharmony_ci
300cabdff1aSopenharmony_ci            clazz = (*env)->FindClass(env, jfields_mapping[i].name);
301cabdff1aSopenharmony_ci            if ((ret = ff_jni_exception_check(env, mandatory, log_ctx)) < 0 && mandatory) {
302cabdff1aSopenharmony_ci                goto done;
303cabdff1aSopenharmony_ci            }
304cabdff1aSopenharmony_ci
305cabdff1aSopenharmony_ci            last_clazz = *(jclass*)((uint8_t*)jfields + jfields_mapping[i].offset) =
306cabdff1aSopenharmony_ci                    global ? (*env)->NewGlobalRef(env, clazz) : clazz;
307cabdff1aSopenharmony_ci
308cabdff1aSopenharmony_ci            if (global) {
309cabdff1aSopenharmony_ci                (*env)->DeleteLocalRef(env, clazz);
310cabdff1aSopenharmony_ci            }
311cabdff1aSopenharmony_ci
312cabdff1aSopenharmony_ci        } else {
313cabdff1aSopenharmony_ci
314cabdff1aSopenharmony_ci            if (!last_clazz) {
315cabdff1aSopenharmony_ci                ret = AVERROR_EXTERNAL;
316cabdff1aSopenharmony_ci                break;
317cabdff1aSopenharmony_ci            }
318cabdff1aSopenharmony_ci
319cabdff1aSopenharmony_ci            switch(type) {
320cabdff1aSopenharmony_ci            case FF_JNI_FIELD: {
321cabdff1aSopenharmony_ci                jfieldID field_id = (*env)->GetFieldID(env, last_clazz, jfields_mapping[i].method, jfields_mapping[i].signature);
322cabdff1aSopenharmony_ci                if ((ret = ff_jni_exception_check(env, mandatory, log_ctx)) < 0 && mandatory) {
323cabdff1aSopenharmony_ci                    goto done;
324cabdff1aSopenharmony_ci                }
325cabdff1aSopenharmony_ci
326cabdff1aSopenharmony_ci                *(jfieldID*)((uint8_t*)jfields + jfields_mapping[i].offset) = field_id;
327cabdff1aSopenharmony_ci                break;
328cabdff1aSopenharmony_ci            }
329cabdff1aSopenharmony_ci            case FF_JNI_STATIC_FIELD: {
330cabdff1aSopenharmony_ci                jfieldID field_id = (*env)->GetStaticFieldID(env, last_clazz, jfields_mapping[i].method, jfields_mapping[i].signature);
331cabdff1aSopenharmony_ci                if ((ret = ff_jni_exception_check(env, mandatory, log_ctx)) < 0 && mandatory) {
332cabdff1aSopenharmony_ci                    goto done;
333cabdff1aSopenharmony_ci                }
334cabdff1aSopenharmony_ci
335cabdff1aSopenharmony_ci                *(jfieldID*)((uint8_t*)jfields + jfields_mapping[i].offset) = field_id;
336cabdff1aSopenharmony_ci                break;
337cabdff1aSopenharmony_ci            }
338cabdff1aSopenharmony_ci            case FF_JNI_METHOD: {
339cabdff1aSopenharmony_ci                jmethodID method_id = (*env)->GetMethodID(env, last_clazz, jfields_mapping[i].method, jfields_mapping[i].signature);
340cabdff1aSopenharmony_ci                if ((ret = ff_jni_exception_check(env, mandatory, log_ctx)) < 0 && mandatory) {
341cabdff1aSopenharmony_ci                    goto done;
342cabdff1aSopenharmony_ci                }
343cabdff1aSopenharmony_ci
344cabdff1aSopenharmony_ci                *(jmethodID*)((uint8_t*)jfields + jfields_mapping[i].offset) = method_id;
345cabdff1aSopenharmony_ci                break;
346cabdff1aSopenharmony_ci            }
347cabdff1aSopenharmony_ci            case FF_JNI_STATIC_METHOD: {
348cabdff1aSopenharmony_ci                jmethodID method_id = (*env)->GetStaticMethodID(env, last_clazz, jfields_mapping[i].method, jfields_mapping[i].signature);
349cabdff1aSopenharmony_ci                if ((ret = ff_jni_exception_check(env, mandatory, log_ctx)) < 0 && mandatory) {
350cabdff1aSopenharmony_ci                    goto done;
351cabdff1aSopenharmony_ci                }
352cabdff1aSopenharmony_ci
353cabdff1aSopenharmony_ci                *(jmethodID*)((uint8_t*)jfields + jfields_mapping[i].offset) = method_id;
354cabdff1aSopenharmony_ci                break;
355cabdff1aSopenharmony_ci            }
356cabdff1aSopenharmony_ci            default:
357cabdff1aSopenharmony_ci                av_log(log_ctx, AV_LOG_ERROR, "Unknown JNI field type\n");
358cabdff1aSopenharmony_ci                ret = AVERROR(EINVAL);
359cabdff1aSopenharmony_ci                goto done;
360cabdff1aSopenharmony_ci            }
361cabdff1aSopenharmony_ci
362cabdff1aSopenharmony_ci            ret = 0;
363cabdff1aSopenharmony_ci        }
364cabdff1aSopenharmony_ci    }
365cabdff1aSopenharmony_ci
366cabdff1aSopenharmony_cidone:
367cabdff1aSopenharmony_ci    if (ret < 0) {
368cabdff1aSopenharmony_ci        /* reset jfields in case of failure so it does not leak references */
369cabdff1aSopenharmony_ci        ff_jni_reset_jfields(env, jfields, jfields_mapping, global, log_ctx);
370cabdff1aSopenharmony_ci    }
371cabdff1aSopenharmony_ci
372cabdff1aSopenharmony_ci    return ret;
373cabdff1aSopenharmony_ci}
374cabdff1aSopenharmony_ci
375cabdff1aSopenharmony_ciint ff_jni_reset_jfields(JNIEnv *env, void *jfields, const struct FFJniField *jfields_mapping, int global, void *log_ctx)
376cabdff1aSopenharmony_ci{
377cabdff1aSopenharmony_ci    int i;
378cabdff1aSopenharmony_ci
379cabdff1aSopenharmony_ci    for (i = 0; jfields_mapping[i].name; i++) {
380cabdff1aSopenharmony_ci        enum FFJniFieldType type = jfields_mapping[i].type;
381cabdff1aSopenharmony_ci
382cabdff1aSopenharmony_ci        switch(type) {
383cabdff1aSopenharmony_ci        case FF_JNI_CLASS: {
384cabdff1aSopenharmony_ci            jclass clazz = *(jclass*)((uint8_t*)jfields + jfields_mapping[i].offset);
385cabdff1aSopenharmony_ci            if (!clazz)
386cabdff1aSopenharmony_ci                continue;
387cabdff1aSopenharmony_ci
388cabdff1aSopenharmony_ci            if (global) {
389cabdff1aSopenharmony_ci                (*env)->DeleteGlobalRef(env, clazz);
390cabdff1aSopenharmony_ci            } else {
391cabdff1aSopenharmony_ci                (*env)->DeleteLocalRef(env, clazz);
392cabdff1aSopenharmony_ci            }
393cabdff1aSopenharmony_ci
394cabdff1aSopenharmony_ci            *(jclass*)((uint8_t*)jfields + jfields_mapping[i].offset) = NULL;
395cabdff1aSopenharmony_ci            break;
396cabdff1aSopenharmony_ci        }
397cabdff1aSopenharmony_ci        case FF_JNI_FIELD: {
398cabdff1aSopenharmony_ci            *(jfieldID*)((uint8_t*)jfields + jfields_mapping[i].offset) = NULL;
399cabdff1aSopenharmony_ci            break;
400cabdff1aSopenharmony_ci        }
401cabdff1aSopenharmony_ci        case FF_JNI_STATIC_FIELD: {
402cabdff1aSopenharmony_ci            *(jfieldID*)((uint8_t*)jfields + jfields_mapping[i].offset) = NULL;
403cabdff1aSopenharmony_ci            break;
404cabdff1aSopenharmony_ci        }
405cabdff1aSopenharmony_ci        case FF_JNI_METHOD: {
406cabdff1aSopenharmony_ci            *(jmethodID*)((uint8_t*)jfields + jfields_mapping[i].offset) = NULL;
407cabdff1aSopenharmony_ci            break;
408cabdff1aSopenharmony_ci        }
409cabdff1aSopenharmony_ci        case FF_JNI_STATIC_METHOD: {
410cabdff1aSopenharmony_ci            *(jmethodID*)((uint8_t*)jfields + jfields_mapping[i].offset) = NULL;
411cabdff1aSopenharmony_ci            break;
412cabdff1aSopenharmony_ci        }
413cabdff1aSopenharmony_ci        default:
414cabdff1aSopenharmony_ci            av_log(log_ctx, AV_LOG_ERROR, "Unknown JNI field type\n");
415cabdff1aSopenharmony_ci        }
416cabdff1aSopenharmony_ci    }
417cabdff1aSopenharmony_ci
418cabdff1aSopenharmony_ci    return 0;
419cabdff1aSopenharmony_ci}
420