Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
F
ffmpeg
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
ffmpeg
Commits
3ab17851
Commit
3ab17851
authored
Sep 28, 2015
by
Matthieu Bouron
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
lavc: add JNI support
parent
6f5048f4
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
771 additions
and
0 deletions
+771
-0
MAINTAINERS
MAINTAINERS
+1
-0
configure
configure
+5
-0
Makefile
libavcodec/Makefile
+4
-0
ffjni.c
libavcodec/ffjni.c
+485
-0
ffjni.h
libavcodec/ffjni.h
+150
-0
jni.c
libavcodec/jni.c
+80
-0
jni.h
libavcodec/jni.h
+46
-0
No files found.
MAINTAINERS
View file @
3ab17851
...
@@ -196,6 +196,7 @@ Codecs:
...
@@ -196,6 +196,7 @@ Codecs:
interplayvideo.c Mike Melanson
interplayvideo.c Mike Melanson
ivi* Kostya Shishkov
ivi* Kostya Shishkov
jacosub* Clément Bœsch
jacosub* Clément Bœsch
jni*, ffjni* Matthieu Bouron
jpeg2000* Nicolas Bertrand
jpeg2000* Nicolas Bertrand
jpeg_ls.c Kostya Shishkov
jpeg_ls.c Kostya Shishkov
jvdec.c Peter Ross
jvdec.c Peter Ross
...
...
configure
View file @
3ab17851
...
@@ -207,6 +207,7 @@ External library support:
...
@@ -207,6 +207,7 @@ External library support:
--enable-gnutls enable gnutls, needed for https support
--enable-gnutls enable gnutls, needed for https support
if openssl is not used [no]
if openssl is not used [no]
--disable-iconv disable iconv [autodetect]
--disable-iconv disable iconv [autodetect]
--enable-jni enable JNI support [no]
--enable-ladspa enable LADSPA audio filtering [no]
--enable-ladspa enable LADSPA audio filtering [no]
--enable-libass enable libass subtitles rendering,
--enable-libass enable libass subtitles rendering,
needed for subtitles and ass filter [no]
needed for subtitles and ass filter [no]
...
@@ -1436,6 +1437,7 @@ EXTERNAL_LIBRARY_LIST="
...
@@ -1436,6 +1437,7 @@ EXTERNAL_LIBRARY_LIST="
gmp
gmp
gnutls
gnutls
iconv
iconv
jni
ladspa
ladspa
libass
libass
libbluray
libbluray
...
@@ -5556,6 +5558,8 @@ enabled decklink && { check_header DeckLinkAPI.h || die "ERROR: DeckLin
...
@@ -5556,6 +5558,8 @@ enabled decklink && { check_header DeckLinkAPI.h || die "ERROR: DeckLin
enabled frei0r
&&
{
check_header frei0r.h
||
die
"ERROR: frei0r.h header not found"
;
}
enabled frei0r
&&
{
check_header frei0r.h
||
die
"ERROR: frei0r.h header not found"
;
}
enabled gmp
&&
require2 gmp gmp.h mpz_export
-lgmp
enabled gmp
&&
require2 gmp gmp.h mpz_export
-lgmp
enabled gnutls
&&
require_pkg_config gnutls gnutls/gnutls.h gnutls_global_init
enabled gnutls
&&
require_pkg_config gnutls gnutls/gnutls.h gnutls_global_init
enabled jni
&&
{
[
$target_os
=
"android"
]
&&
check_header jni.h
&&
enabled pthreads
&&
check_lib2
"dlfcn.h"
dlopen
-ldl
;
}
enabled ladspa
&&
{
check_header ladspa.h
||
die
"ERROR: ladspa.h header not found"
;
}
enabled ladspa
&&
{
check_header ladspa.h
||
die
"ERROR: ladspa.h header not found"
;
}
enabled libiec61883
&&
require libiec61883 libiec61883/iec61883.h iec61883_cmp_connect
-lraw1394
-lavc1394
-lrom1394
-liec61883
enabled libiec61883
&&
require libiec61883 libiec61883/iec61883.h iec61883_cmp_connect
-lraw1394
-lavc1394
-lrom1394
-liec61883
enabled libass
&&
require_pkg_config libass ass/ass.h ass_library_init
enabled libass
&&
require_pkg_config libass ass/ass.h ass_library_init
...
@@ -6324,6 +6328,7 @@ echo "threading support ${thread_type-no}"
...
@@ -6324,6 +6328,7 @@ echo "threading support ${thread_type-no}"
echo
"safe bitstream reader
${
safe_bitstream_reader
-no
}
"
echo
"safe bitstream reader
${
safe_bitstream_reader
-no
}
"
echo
"SDL support
${
sdl
-no
}
"
echo
"SDL support
${
sdl
-no
}
"
echo
"opencl enabled
${
opencl
-no
}
"
echo
"opencl enabled
${
opencl
-no
}
"
echo
"JNI support
${
jni
-no
}
"
echo
"texi2html enabled
${
texi2html
-no
}
"
echo
"texi2html enabled
${
texi2html
-no
}
"
echo
"perl enabled
${
perl
-no
}
"
echo
"perl enabled
${
perl
-no
}
"
echo
"pod2man enabled
${
pod2man
-no
}
"
echo
"pod2man enabled
${
pod2man
-no
}
"
...
...
libavcodec/Makefile
View file @
3ab17851
...
@@ -9,6 +9,7 @@ HEADERS = avcodec.h \
...
@@ -9,6 +9,7 @@ HEADERS = avcodec.h \
d3d11va.h
\
d3d11va.h
\
dirac.h
\
dirac.h
\
dxva2.h
\
dxva2.h
\
jni.h
\
qsv.h
\
qsv.h
\
vaapi.h
\
vaapi.h
\
vda.h
\
vda.h
\
...
@@ -30,6 +31,7 @@ OBJS = allcodecs.o \
...
@@ -30,6 +31,7 @@ OBJS = allcodecs.o \
dirac.o
\
dirac.o
\
dv_profile.o
\
dv_profile.o
\
imgconvert.o
\
imgconvert.o
\
jni.o
\
mathtables.o
\
mathtables.o
\
options.o
\
options.o
\
parser.o
\
parser.o
\
...
@@ -79,6 +81,7 @@ OBJS-$(CONFIG_IIRFILTER) += iirfilter.o
...
@@ -79,6 +81,7 @@ OBJS-$(CONFIG_IIRFILTER) += iirfilter.o
OBJS-$(CONFIG_IMDCT15)
+=
imdct15.o
OBJS-$(CONFIG_IMDCT15)
+=
imdct15.o
OBJS-$(CONFIG_INTRAX8)
+=
intrax8.o
intrax8dsp.o
OBJS-$(CONFIG_INTRAX8)
+=
intrax8.o
intrax8dsp.o
OBJS-$(CONFIG_IVIDSP)
+=
ivi_dsp.o
OBJS-$(CONFIG_IVIDSP)
+=
ivi_dsp.o
OBJS-$(CONFIG_JNI)
+=
ffjni.o
jni.o
OBJS-$(CONFIG_JPEGTABLES)
+=
jpegtables.o
OBJS-$(CONFIG_JPEGTABLES)
+=
jpegtables.o
OBJS-$(CONFIG_LIBXVID)
+=
libxvid_rc.o
OBJS-$(CONFIG_LIBXVID)
+=
libxvid_rc.o
OBJS-$(CONFIG_LLAUDDSP)
+=
lossless_audiodsp.o
OBJS-$(CONFIG_LLAUDDSP)
+=
lossless_audiodsp.o
...
@@ -936,6 +939,7 @@ SKIPHEADERS += %_tablegen.h \
...
@@ -936,6 +939,7 @@ SKIPHEADERS += %_tablegen.h \
SKIPHEADERS-$(CONFIG_D3D11VA)
+=
d3d11va.h
dxva2_internal.h
SKIPHEADERS-$(CONFIG_D3D11VA)
+=
d3d11va.h
dxva2_internal.h
SKIPHEADERS-$(CONFIG_DXVA2)
+=
dxva2.h
dxva2_internal.h
SKIPHEADERS-$(CONFIG_DXVA2)
+=
dxva2.h
dxva2_internal.h
SKIPHEADERS-$(CONFIG_JNI)
+=
ffjni.h
SKIPHEADERS-$(CONFIG_LIBSCHROEDINGER)
+=
libschroedinger.h
SKIPHEADERS-$(CONFIG_LIBSCHROEDINGER)
+=
libschroedinger.h
SKIPHEADERS-$(CONFIG_LIBUTVIDEO)
+=
libutvideo.h
SKIPHEADERS-$(CONFIG_LIBUTVIDEO)
+=
libutvideo.h
SKIPHEADERS-$(CONFIG_LIBVPX)
+=
libvpx.h
SKIPHEADERS-$(CONFIG_LIBVPX)
+=
libvpx.h
...
...
libavcodec/ffjni.c
0 → 100644
View file @
3ab17851
/*
* JNI utility functions
*
* Copyright (c) 2015-2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <dlfcn.h>
#include <jni.h>
#include <pthread.h>
#include <stdlib.h>
#include "libavutil/bprint.h"
#include "libavutil/log.h"
#include "config.h"
#include "jni.h"
#include "ffjni.h"
static
JavaVM
*
java_vm
=
NULL
;
static
pthread_mutex_t
lock
=
PTHREAD_MUTEX_INITIALIZER
;
/**
* Check if JniInvocation has been initialized. Only available on
* Android >= 4.4.
*
* @param log_ctx context used for logging, can be NULL
* @return 0 on success, < 0 otherwise
*/
static
int
check_jni_invocation
(
void
*
log_ctx
)
{
int
ret
=
AVERROR_EXTERNAL
;
void
*
handle
=
NULL
;
void
**
jni_invocation
=
NULL
;
handle
=
dlopen
(
NULL
,
RTLD_LOCAL
);
if
(
!
handle
)
{
goto
done
;
}
jni_invocation
=
(
void
**
)
dlsym
(
handle
,
"_ZN13JniInvocation15jni_invocation_E"
);
if
(
!
jni_invocation
)
{
av_log
(
log_ctx
,
AV_LOG_ERROR
,
"Could not find JniInvocation::jni_invocation_ symbol
\n
"
);
goto
done
;
}
ret
=
!
(
jni_invocation
!=
NULL
&&
*
jni_invocation
!=
NULL
);
done:
if
(
handle
)
{
dlclose
(
handle
);
}
return
ret
;
}
/**
* Return created Java virtual machine using private JNI_GetCreatedJavaVMs
* function from the specified library name.
*
* @param name library name used for symbol lookups, can be NULL
* @param log_ctx context used for logging, can be NULL
* @return the current Java virtual machine in use
*/
static
JavaVM
*
get_java_vm
(
const
char
*
name
,
void
*
log_ctx
)
{
JavaVM
*
vm
=
NULL
;
jsize
nb_vm
=
0
;
void
*
handle
=
NULL
;
jint
(
*
get_created_java_vms
)
(
JavaVM
**
vmBuf
,
jsize
bufLen
,
jsize
*
nVMs
)
=
NULL
;
handle
=
dlopen
(
name
,
RTLD_LOCAL
);
if
(
!
handle
)
{
return
NULL
;
}
get_created_java_vms
=
(
jint
(
*
)(
JavaVM
**
,
jsize
,
jsize
*
))
dlsym
(
handle
,
"JNI_GetCreatedJavaVMs"
);
if
(
!
get_created_java_vms
)
{
av_log
(
log_ctx
,
AV_LOG_ERROR
,
"Could not find JNI_GetCreatedJavaVMs symbol in library '%s'
\n
"
,
name
);
goto
done
;
}
if
(
get_created_java_vms
(
&
vm
,
1
,
&
nb_vm
)
!=
JNI_OK
)
{
av_log
(
log_ctx
,
AV_LOG_ERROR
,
"Could not get created Java virtual machines
\n
"
);
goto
done
;
}
done:
if
(
handle
)
{
dlclose
(
handle
);
}
return
vm
;
}
JNIEnv
*
ff_jni_attach_env
(
int
*
attached
,
void
*
log_ctx
)
{
int
ret
=
0
;
JNIEnv
*
env
=
NULL
;
*
attached
=
0
;
pthread_mutex_lock
(
&
lock
);
if
(
java_vm
==
NULL
&&
(
java_vm
=
av_jni_get_java_vm
(
log_ctx
))
==
NULL
)
{
av_log
(
log_ctx
,
AV_LOG_INFO
,
"Retrieving current Java virtual machine using Android JniInvocation wrapper
\n
"
);
if
(
check_jni_invocation
(
log_ctx
)
==
0
)
{
if
((
java_vm
=
get_java_vm
(
NULL
,
log_ctx
))
!=
NULL
||
(
java_vm
=
get_java_vm
(
"libdvm.so"
,
log_ctx
))
!=
NULL
||
(
java_vm
=
get_java_vm
(
"libart.so"
,
log_ctx
))
!=
NULL
)
{
av_log
(
log_ctx
,
AV_LOG_INFO
,
"Found Java virtual machine using Android JniInvocation wrapper
\n
"
);
}
}
}
pthread_mutex_unlock
(
&
lock
);
if
(
!
java_vm
)
{
av_log
(
log_ctx
,
AV_LOG_ERROR
,
"Could not retrieve a Java virtual machine
\n
"
);
return
NULL
;
}
ret
=
(
*
java_vm
)
->
GetEnv
(
java_vm
,
(
void
**
)
&
env
,
JNI_VERSION_1_6
);
switch
(
ret
)
{
case
JNI_EDETACHED
:
if
((
*
java_vm
)
->
AttachCurrentThread
(
java_vm
,
&
env
,
NULL
)
!=
0
)
{
av_log
(
log_ctx
,
AV_LOG_ERROR
,
"Failed to attach the JNI environment to the current thread
\n
"
);
env
=
NULL
;
}
else
{
*
attached
=
1
;
}
break
;
case
JNI_OK
:
break
;
case
JNI_EVERSION
:
av_log
(
log_ctx
,
AV_LOG_ERROR
,
"The specified JNI version is not supported
\n
"
);
break
;
default:
av_log
(
log_ctx
,
AV_LOG_ERROR
,
"Failed to get the JNI environment attached to this thread"
);
break
;
}
return
env
;
}
int
ff_jni_detach_env
(
void
*
log_ctx
)
{
if
(
java_vm
==
NULL
)
{
av_log
(
log_ctx
,
AV_LOG_ERROR
,
"No Java virtual machine has been registered
\n
"
);
return
AVERROR
(
EINVAL
);
}
return
(
*
java_vm
)
->
DetachCurrentThread
(
java_vm
);
}
char
*
ff_jni_jstring_to_utf_chars
(
JNIEnv
*
env
,
jstring
string
,
void
*
log_ctx
)
{
char
*
ret
=
NULL
;
const
char
*
utf_chars
=
NULL
;
jboolean
copy
=
0
;
if
(
!
string
)
{
return
NULL
;
}
utf_chars
=
(
*
env
)
->
GetStringUTFChars
(
env
,
string
,
&
copy
);
if
((
*
env
)
->
ExceptionCheck
(
env
))
{
(
*
env
)
->
ExceptionClear
(
env
);
av_log
(
log_ctx
,
AV_LOG_ERROR
,
"String.getStringUTFChars() threw an exception
\n
"
);
return
NULL
;
}
ret
=
av_strdup
(
utf_chars
);
(
*
env
)
->
ReleaseStringUTFChars
(
env
,
string
,
utf_chars
);
if
((
*
env
)
->
ExceptionCheck
(
env
))
{
(
*
env
)
->
ExceptionClear
(
env
);
av_log
(
log_ctx
,
AV_LOG_ERROR
,
"String.releaseStringUTFChars() threw an exception
\n
"
);
return
NULL
;;
}
return
ret
;
}
jstring
ff_jni_utf_chars_to_jstring
(
JNIEnv
*
env
,
const
char
*
utf_chars
,
void
*
log_ctx
)
{
jstring
ret
;
ret
=
(
*
env
)
->
NewStringUTF
(
env
,
utf_chars
);
if
((
*
env
)
->
ExceptionCheck
(
env
))
{
(
*
env
)
->
ExceptionClear
(
env
);
av_log
(
log_ctx
,
AV_LOG_ERROR
,
"NewStringUTF() threw an exception
\n
"
);
return
NULL
;
}
return
ret
;
}
int
ff_jni_exception_get_summary
(
JNIEnv
*
env
,
jthrowable
exception
,
char
**
error
,
void
*
log_ctx
)
{
int
ret
=
0
;
AVBPrint
bp
;
char
*
name
=
NULL
;
char
*
message
=
NULL
;
jclass
class_class
=
NULL
;
jmethodID
get_name_id
=
NULL
;
jclass
exception_class
=
NULL
;
jmethodID
get_message_id
=
NULL
;
jstring
string
;
av_bprint_init
(
&
bp
,
0
,
AV_BPRINT_SIZE_AUTOMATIC
);
exception_class
=
(
*
env
)
->
GetObjectClass
(
env
,
exception
);
if
((
*
env
)
->
ExceptionCheck
(
env
))
{
(
*
env
)
->
ExceptionClear
(
env
);
av_log
(
log_ctx
,
AV_LOG_ERROR
,
"Could not find Throwable class
\n
"
);
ret
=
AVERROR_EXTERNAL
;
goto
done
;
}
class_class
=
(
*
env
)
->
GetObjectClass
(
env
,
exception_class
);
if
((
*
env
)
->
ExceptionCheck
(
env
))
{
(
*
env
)
->
ExceptionClear
(
env
);
av_log
(
log_ctx
,
AV_LOG_ERROR
,
"Could not find Throwable class's class
\n
"
);
ret
=
AVERROR_EXTERNAL
;
goto
done
;
}
get_name_id
=
(
*
env
)
->
GetMethodID
(
env
,
class_class
,
"getName"
,
"()Ljava/lang/String;"
);
if
((
*
env
)
->
ExceptionCheck
(
env
))
{
(
*
env
)
->
ExceptionClear
(
env
);
av_log
(
log_ctx
,
AV_LOG_ERROR
,
"Could not find method Class.getName()
\n
"
);
ret
=
AVERROR_EXTERNAL
;
goto
done
;
}
string
=
(
*
env
)
->
CallObjectMethod
(
env
,
exception_class
,
get_name_id
);
if
((
*
env
)
->
ExceptionCheck
(
env
))
{
(
*
env
)
->
ExceptionClear
(
env
);
av_log
(
log_ctx
,
AV_LOG_ERROR
,
"Class.getName() threw an exception
\n
"
);
ret
=
AVERROR_EXTERNAL
;
goto
done
;
}
if
(
string
)
{
name
=
ff_jni_jstring_to_utf_chars
(
env
,
string
,
log_ctx
);
(
*
env
)
->
DeleteLocalRef
(
env
,
string
);
string
=
NULL
;
}
get_message_id
=
(
*
env
)
->
GetMethodID
(
env
,
exception_class
,
"getMessage"
,
"()Ljava/lang/String;"
);
if
((
*
env
)
->
ExceptionCheck
(
env
))
{
(
*
env
)
->
ExceptionClear
(
env
);
av_log
(
log_ctx
,
AV_LOG_ERROR
,
"Could not find method java/lang/Throwable.getMessage()
\n
"
);
ret
=
AVERROR_EXTERNAL
;
goto
done
;
}
string
=
(
*
env
)
->
CallObjectMethod
(
env
,
exception
,
get_message_id
);
if
((
*
env
)
->
ExceptionCheck
(
env
))
{
(
*
env
)
->
ExceptionClear
(
env
);
av_log
(
log_ctx
,
AV_LOG_ERROR
,
"Throwable.getMessage() threw an exception
\n
"
);
ret
=
AVERROR_EXTERNAL
;
goto
done
;
}
if
(
string
)
{
message
=
ff_jni_jstring_to_utf_chars
(
env
,
string
,
log_ctx
);
(
*
env
)
->
DeleteLocalRef
(
env
,
string
);
string
=
NULL
;
}
if
(
name
&&
message
)
{
av_bprintf
(
&
bp
,
"%s: %s"
,
name
,
message
);
}
else
if
(
name
&&
!
message
)
{
av_bprintf
(
&
bp
,
"%s occured"
,
name
);
}
else
if
(
!
name
&&
message
)
{
av_bprintf
(
&
bp
,
"Exception: %s"
,
message
);
}
else
{
av_log
(
log_ctx
,
AV_LOG_WARNING
,
"Could not retreive exception name and message
\n
"
);
av_bprintf
(
&
bp
,
"Exception occured"
);
}
ret
=
av_bprint_finalize
(
&
bp
,
error
);
done:
av_free
(
name
);
av_free
(
message
);
if
(
class_class
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
class_class
);
}
if
(
exception_class
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
exception_class
);
}
if
(
string
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
string
);
}
return
ret
;
}
int
ff_jni_exception_check
(
JNIEnv
*
env
,
int
log
,
void
*
log_ctx
)
{
int
ret
;
jthrowable
exception
;
char
*
message
=
NULL
;
if
(
!
(
*
(
env
))
->
ExceptionCheck
((
env
)))
{
return
0
;
}
if
(
!
log
)
{
(
*
(
env
))
->
ExceptionClear
((
env
));
return
-
1
;
}
exception
=
(
*
env
)
->
ExceptionOccurred
(
env
);
(
*
(
env
))
->
ExceptionClear
((
env
));
if
((
ret
=
ff_jni_exception_get_summary
(
env
,
exception
,
&
message
,
log_ctx
))
<
0
)
{
(
*
env
)
->
DeleteLocalRef
(
env
,
exception
);
return
ret
;
}
(
*
env
)
->
DeleteLocalRef
(
env
,
exception
);
av_log
(
log_ctx
,
AV_LOG_ERROR
,
"%s
\n
"
,
message
);
av_free
(
message
);
return
-
1
;
}
int
ff_jni_init_jfields
(
JNIEnv
*
env
,
void
*
jfields
,
const
struct
FFJniField
*
jfields_mapping
,
int
global
,
void
*
log_ctx
)
{
int
i
,
ret
=
0
;
jclass
last_clazz
=
NULL
;
for
(
i
=
0
;
jfields_mapping
[
i
].
name
;
i
++
)
{
int
mandatory
=
jfields_mapping
[
i
].
mandatory
;
enum
FFJniFieldType
type
=
jfields_mapping
[
i
].
type
;
if
(
type
==
FF_JNI_CLASS
)
{
jclass
clazz
;
last_clazz
=
NULL
;
clazz
=
(
*
env
)
->
FindClass
(
env
,
jfields_mapping
[
i
].
name
);
if
((
ret
=
ff_jni_exception_check
(
env
,
mandatory
,
log_ctx
))
<
0
&&
mandatory
)
{
goto
done
;
}
last_clazz
=
*
(
jclass
*
)((
uint8_t
*
)
jfields
+
jfields_mapping
[
i
].
offset
)
=
global
?
(
*
env
)
->
NewGlobalRef
(
env
,
clazz
)
:
clazz
;
}
else
{
if
(
!
last_clazz
)
{
ret
=
AVERROR_EXTERNAL
;
break
;
}
switch
(
type
)
{
case
FF_JNI_FIELD
:
{
jfieldID
field_id
=
(
*
env
)
->
GetFieldID
(
env
,
last_clazz
,
jfields_mapping
[
i
].
method
,
jfields_mapping
[
i
].
signature
);
if
((
ret
=
ff_jni_exception_check
(
env
,
mandatory
,
log_ctx
))
<
0
&&
mandatory
)
{
goto
done
;
}
*
(
jfieldID
*
)((
uint8_t
*
)
jfields
+
jfields_mapping
[
i
].
offset
)
=
field_id
;
break
;
}
case
FF_JNI_STATIC_FIELD
:
{
jfieldID
field_id
=
(
*
env
)
->
GetStaticFieldID
(
env
,
last_clazz
,
jfields_mapping
[
i
].
method
,
jfields_mapping
[
i
].
signature
);
if
((
ret
=
ff_jni_exception_check
(
env
,
mandatory
,
log_ctx
))
<
0
&&
mandatory
)
{
goto
done
;
}
*
(
jfieldID
*
)((
uint8_t
*
)
jfields
+
jfields_mapping
[
i
].
offset
)
=
field_id
;
break
;
}
case
FF_JNI_METHOD
:
{
jmethodID
method_id
=
(
*
env
)
->
GetMethodID
(
env
,
last_clazz
,
jfields_mapping
[
i
].
method
,
jfields_mapping
[
i
].
signature
);
if
((
ret
=
ff_jni_exception_check
(
env
,
mandatory
,
log_ctx
))
<
0
&&
mandatory
)
{
goto
done
;
}
*
(
jmethodID
*
)((
uint8_t
*
)
jfields
+
jfields_mapping
[
i
].
offset
)
=
method_id
;
break
;
}
case
FF_JNI_STATIC_METHOD
:
{
jmethodID
method_id
=
(
*
env
)
->
GetStaticMethodID
(
env
,
last_clazz
,
jfields_mapping
[
i
].
method
,
jfields_mapping
[
i
].
signature
);
if
((
ret
=
ff_jni_exception_check
(
env
,
mandatory
,
log_ctx
))
<
0
&&
mandatory
)
{
goto
done
;
}
*
(
jmethodID
*
)((
uint8_t
*
)
jfields
+
jfields_mapping
[
i
].
offset
)
=
method_id
;
break
;
}
default:
av_log
(
log_ctx
,
AV_LOG_ERROR
,
"Unknown JNI field type
\n
"
);
ret
=
AVERROR
(
EINVAL
);
goto
done
;
}
}
}
done:
if
(
ret
<
0
)
{
/* reset jfields in case of failure so it does not leak references */
ff_jni_reset_jfields
(
env
,
jfields
,
jfields_mapping
,
global
,
log_ctx
);
}
return
ret
;
}
int
ff_jni_reset_jfields
(
JNIEnv
*
env
,
void
*
jfields
,
const
struct
FFJniField
*
jfields_mapping
,
int
global
,
void
*
log_ctx
)
{
int
i
;
for
(
i
=
0
;
jfields_mapping
[
i
].
name
;
i
++
)
{
enum
FFJniFieldType
type
=
jfields_mapping
[
i
].
type
;
switch
(
type
)
{
case
FF_JNI_CLASS
:
{
jclass
clazz
=
*
(
jclass
*
)((
uint8_t
*
)
jfields
+
jfields_mapping
[
i
].
offset
);
if
(
!
clazz
)
continue
;
if
(
global
)
{
(
*
env
)
->
DeleteGlobalRef
(
env
,
clazz
);
}
else
{
(
*
env
)
->
DeleteLocalRef
(
env
,
clazz
);
}
*
(
jclass
*
)((
uint8_t
*
)
jfields
+
jfields_mapping
[
i
].
offset
)
=
NULL
;
break
;
}
case
FF_JNI_FIELD
:
{
*
(
jfieldID
*
)((
uint8_t
*
)
jfields
+
jfields_mapping
[
i
].
offset
)
=
NULL
;
break
;
}
case
FF_JNI_STATIC_FIELD
:
{
*
(
jfieldID
*
)((
uint8_t
*
)
jfields
+
jfields_mapping
[
i
].
offset
)
=
NULL
;
break
;
}
case
FF_JNI_METHOD
:
{
*
(
jmethodID
*
)((
uint8_t
*
)
jfields
+
jfields_mapping
[
i
].
offset
)
=
NULL
;
break
;
}
case
FF_JNI_STATIC_METHOD
:
{
*
(
jmethodID
*
)((
uint8_t
*
)
jfields
+
jfields_mapping
[
i
].
offset
)
=
NULL
;
break
;
}
default:
av_log
(
log_ctx
,
AV_LOG_ERROR
,
"Unknown JNI field type
\n
"
);
}
}
return
0
;
}
libavcodec/ffjni.h
0 → 100644
View file @
3ab17851
/*
* JNI utility functions
*
* Copyright (c) 2015-2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVCODEC_FFJNI_H
#define AVCODEC_FFJNI_H
#include <jni.h>
/*
* Attach a JNI environment to the current thread.
*
* @param attached pointer to an integer that will be set to 1 if the
* environment has been attached to the current thread or 0 if it is
* already attached.
* @param log_ctx context used for logging, can be NULL
* @return the JNI environment on success, NULL otherwise
*/
JNIEnv
*
ff_jni_attach_env
(
int
*
attached
,
void
*
log_ctx
);
/*
* Detach the JNI environment from the current thread.
*
* @param log_ctx context used for logging, can be NULL
* @return 0 on success, < 0 otherwise
*/
int
ff_jni_detach_env
(
void
*
log_ctx
);
/*
* Convert a jstring to its utf characters equivalent.
*
* @param env JNI environment
* @param string Java string to convert
* @param log_ctx context used for logging, can be NULL
* @return a pointer to an array of unicode characters on success, NULL
* otherwise
*/
char
*
ff_jni_jstring_to_utf_chars
(
JNIEnv
*
env
,
jstring
string
,
void
*
log_ctx
);
/*
* Convert utf chars to its jstring equivalent.
*
* @param env JNI environment
* @param utf_chars a pointer to an array of unicode characters
* @param log_ctx context used for logging, can be NULL
* @return a Java string object on success, NULL otherwise
*/
jstring
ff_jni_utf_chars_to_jstring
(
JNIEnv
*
env
,
const
char
*
utf_chars
,
void
*
log_ctx
);
/*
* Extract the error summary from a jthrowable in the form of "className: errorMessage"
*
* @param env JNI environment
* @param exception exception to get the summary from
* @param error address pointing to the error, the value is updated if a
* summary can be extracted
* @param log_ctx context used for logging, can be NULL
* @return 0 on success, < 0 otherwise
*/
int
ff_jni_exception_get_summary
(
JNIEnv
*
env
,
jthrowable
exception
,
char
**
error
,
void
*
log_ctx
);
/*
* Check if an exception has occurred,log it using av_log and clear it.
*
* @param env JNI environment
* @param log value used to enable logging if an exception has occurred,
* 0 disables logging, != 0 enables logging
* @param log_ctx context used for logging, can be NULL
*/
int
ff_jni_exception_check
(
JNIEnv
*
env
,
int
log
,
void
*
log_ctx
);
/*
* Jni field type.
*/
enum
FFJniFieldType
{
FF_JNI_CLASS
,
FF_JNI_FIELD
,
FF_JNI_STATIC_FIELD
,
FF_JNI_METHOD
,
FF_JNI_STATIC_METHOD
};
/*
* Jni field describing a class, a field or a method to be retrieved using
* the ff_jni_init_jfields method.
*/
struct
FFJniField
{
const
char
*
name
;
const
char
*
method
;
const
char
*
signature
;
enum
FFJniFieldType
type
;
int
offset
;
int
mandatory
;
};
/*
* Retrieve class references, field ids and method ids to an arbitrary structure.
*
* @param env JNI environment
* @param jfields a pointer to an arbitrary structure where the different
* fields are declared and where the FFJNIField mapping table offsets are
* pointing to
* @param jfields_mapping null terminated array of FFJNIFields describing
* the class/field/method to be retrieved
* @param global make the classes references global. It is the caller
* responsibility to properly release global references.
* @param log_ctx context used for logging, can be NULL
* @return 0 on success, < 0 otherwise
*/
int
ff_jni_init_jfields
(
JNIEnv
*
env
,
void
*
jfields
,
const
struct
FFJniField
*
jfields_mapping
,
int
global
,
void
*
log_ctx
);
/*
* Delete class references, field ids and method ids of an arbitrary structure.
*
* @param env JNI environment
* @param jfields a pointer to an arbitrary structure where the different
* fields are declared and where the FFJNIField mapping table offsets are
* pointing to
* @param jfields_mapping null terminated array of FFJNIFields describing
* the class/field/method to be deleted
* @param global threat the classes references as global and delete them
* accordingly
* @param log_ctx context used for logging, can be NULL
* @return 0 on success, < 0 otherwise
*/
int
ff_jni_reset_jfields
(
JNIEnv
*
env
,
void
*
jfields
,
const
struct
FFJniField
*
jfields_mapping
,
int
global
,
void
*
log_ctx
);
#endif
/* AVCODEC_FFJNI_H */
libavcodec/jni.c
0 → 100644
View file @
3ab17851
/*
* JNI public API functions
*
* Copyright (c) 2015-2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include "config.h"
#include "jni.h"
#if CONFIG_JNI
#include <errno.h>
#include <jni.h>
#include <pthread.h>
#include "libavutil/log.h"
#include "libavutil/error.h"
#include "ffjni.h"
void
*
java_vm
;
pthread_mutex_t
lock
=
PTHREAD_MUTEX_INITIALIZER
;
int
av_jni_set_java_vm
(
void
*
vm
,
void
*
log_ctx
)
{
int
ret
=
0
;
pthread_mutex_lock
(
&
lock
);
if
(
java_vm
==
NULL
)
{
java_vm
=
vm
;
}
else
if
(
java_vm
!=
vm
)
{
ret
=
AVERROR
(
EINVAL
);
av_log
(
log_ctx
,
AV_LOG_ERROR
,
"A Java virtual machine has already been set"
);
}
pthread_mutex_unlock
(
&
lock
);
return
ret
;
}
void
*
av_jni_get_java_vm
(
void
*
log_ctx
)
{
void
*
vm
;
pthread_mutex_lock
(
&
lock
);
vm
=
java_vm
;
pthread_mutex_unlock
(
&
lock
);
return
vm
;
}
#else
int
av_jni_set_java_vm
(
void
*
vm
,
void
*
log_ctx
)
{
return
0
;
}
void
*
av_jni_get_java_vm
(
void
*
log_ctx
)
{
return
NULL
;
}
#endif
libavcodec/jni.h
0 → 100644
View file @
3ab17851
/*
* JNI public API functions
*
* Copyright (c) 2015-2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVCODEC_JNI_H
#define AVCODEC_JNI_H
/*
* Manually set a Java virtual machine which will be used to retrieve the JNI
* environment. Once a Java VM is set it cannot be changed afterwards, meaning
* you can call multiple times av_jni_set_java_vm with the same Java VM pointer
* however it will error out if you try to set a different Java VM.
*
* @param vm Java virtual machine
* @param log_ctx context used for logging, can be NULL
* @return 0 on success, < 0 otherwise
*/
int
av_jni_set_java_vm
(
void
*
vm
,
void
*
log_ctx
);
/*
* Get the Java virtual machine which has been set with av_jni_set_java_vm.
*
* @param vm Java virtual machine
* @return a pointer to the Java virtual machine
*/
void
*
av_jni_get_java_vm
(
void
*
log_ctx
);
#endif
/* AVCODEC_JNI_H */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment