Javacv: java.lang.UnsatisfiedLinkError with Alpine Linux

Created on 16 Dec 2019  路  19Comments  路  Source: bytedeco/javacv

I'm deploying my spring boot gradle web app that uses ffprobe/ffmpeg in javacp-platform to docker with image openjdk:8u121-alpine.

I set the dependency in the build.gradle like this:

dependencies {
    compile 'org.bytedeco:javacv-platform:1.5.2'
    ...
}

When the web app tried to load the ffprobe (Loader.load(org.bytedeco.ffmpeg.ffprobe.class)), it throwed this error:

```20:34:34.786 [http-nio-8080-exec-1] ERROR org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/].[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler processing failed; nested exception is java.lang.UnsatisfiedLinkError: no jniavutil in java.library.path] with root cause
java.lang.UnsatisfiedLinkError: /root/.javacpp/cache/ffmpeg-4.2.1-1.5.2-linux-x86_64.jar/org/bytedeco/ffmpeg/linux-x86_64/libjniavutil.so: Error relocating /root/.javacpp/cache/ffmpeg-4.2.1-1.5.2-linux-x86_64.jar/org/bytedeco/ffmpeg/linux-x86_64/libjniavutil.so: malloc_trim: symbol not found
at java.lang.ClassLoader$NativeLibrary.load(Native Method) ~[?:1.8.0_121]
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1941) ~[?:1.8.0_121]
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1824) ~[?:1.8.0_121]
at java.lang.Runtime.load0(Runtime.java:809) ~[?:1.8.0_121]
at java.lang.System.load(System.java:1086) ~[?:1.8.0_121]
at org.bytedeco.javacpp.Loader.loadLibrary(Loader.java:1493) ~[javacpp-1.5.2.jar!/:1.5.2]
at org.bytedeco.javacpp.Loader.load(Loader.java:1192) ~[javacpp-1.5.2.jar!/:1.5.2]
at org.bytedeco.javacpp.Loader.load(Loader.java:1042) ~[javacpp-1.5.2.jar!/:1.5.2]
at org.bytedeco.ffmpeg.global.avutil.(avutil.java:12) ~[ffmpeg-4.2.1-1.5.2.jar!/:4.2.1-1.5.2]
at java.lang.Class.forName0(Native Method) ~[?:1.8.0_121]
at java.lang.Class.forName(Class.java:348) ~[?:1.8.0_121]
at org.bytedeco.javacpp.Loader.load(Loader.java:1109) ~[javacpp-1.5.2.jar!/:1.5.2]
at org.bytedeco.javacpp.Loader.load(Loader.java:1058) ~[javacpp-1.5.2.jar!/:1.5.2]
...


There is no error if I run the web app without docker.

Am I missing certain required native library in the docker image ?

I had tried adding ffmpeg in the `Dockerfile`:

FROM openjdk:8u121-alpine

RUN apk update && \
apk add ffmpeg

...
```

but still got same error.

help wanted question

Most helpful comment

Alright, it seems I have to switch to other linux image. I have managed to run the web app with the ubuntu docker image (xqdocker/ubuntu-openjdk:8), I just need to install these two packages:

RUN apt-get update -y && apt-get install -y \
 libxcb-shape0 \
 libxcb-xfixes0

All 19 comments

Alpine Linux doesn't install glibc by default. We need to install it.

Ok, I have installed the glibc using this package: https://github.com/sgerrand/alpine-pkg-glibc

When I run it again, I got different error:

00:42:36.269 [http-nio-8080-exec-2] ERROR org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/].[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler processing failed; nested exception is java.lang.NoClassDefFoundError: Could not initialize class org.bytedeco.ffmpeg.global.avutil] with root cause
java.lang.NoClassDefFoundError: Could not initialize class org.bytedeco.ffmpeg.global.avutil
    at java.lang.Class.forName0(Native Method) ~[?:1.8.0_121]
    at java.lang.Class.forName(Class.java:348) ~[?:1.8.0_121]
    at org.bytedeco.javacpp.Loader.load(Loader.java:1006) ~[javacpp-1.5.jar!/:1.5]
    at org.bytedeco.javacpp.Loader.load(Loader.java:963) ~[javacpp-1.5.jar!/:1.5]
        ...

What caused this error?

Check the full stack trace, it will give more info.

That's already the full stack trace and it's the only the error stack trace that's shown. It's produced from this line of code: String ffprobe = Loader.load(org.bytedeco.ffmpeg.ffprobe.class);

Then there's some exception that is getting masked. Set the log level to
debug or more to try to see it. Also set the
"org.bytedeco.javacpp.logger.debug" system property to "true" and/or
"org.bytedeco.javacpp.logger" to "slf4j".

Setting logging level to debug doesn't show anything new. Also, I saw the libjniavutil.so: malloc_trim: symbol not found error shows up again, so the installing glibc doesn't really solve it.

And what interesting is the error malloc_trim always happens only at the first time of Loader.load code run. The next code run will not throw that error anymore and instead it will always throw the java.lang.NoClassDefFoundError: Could not initialize class org.bytedeco.ffmpeg.global.avutil.

Right, ok, so that's your first exception. malloc_trim() comes with glibc, so it's not actually using it for some reason.

I also tried it with docker image xqdocker/ubuntu-openjdk:8. It requires installing libxcb-shape0 package.

No maloc_trim error, but got java.lang.NoClassDefFoundError: Could not initialize class org.bytedeco.ffmpeg.global.avdevice error, same like the second error in alpine above, only differ in the class name (avdevice instead of avutil).

Is the javacv's ffprobe/ffmpeg.class loading not supported in docker environment at all?

libavdevice depends on a few things normally installed on Linux, such as libxcb, yes, so you'll need to install whatever it needs to load. We can of course build lighter binaries, see issue https://github.com/bytedeco/javacpp-presets/issues/593.

This sounds very troublesome to hunt those libraries that are required to run the ffmpeg class. Why couldn't just installing ffmpeg package solve the issue ? Aren't the dependencies requirement of ffprobe/ffmpeg.class inside javacv and the real ffmpeg binary same ?

Yes, we can do that as well. Set the "org.bytedeco.javacpp.pathsfirst" system property to "true", and it will search for binaries of FFmpeg on the system first in priority. But those binaries need to be compatible with the JNI bindings, which is less likely to succeed than simply installing standard libraries available for Linux and using the version of FFmpeg that is bundled.

If I can use ffmpeg binary then I don't really need to use the javacv library anymore. The main reason to use the javacv's ffmpeg.class is because my client doesn't want the java web app to run external binary app.

About the error in alpine docker image again: "java.lang.NoClassDefFoundError: Could not initialize class org.bytedeco.ffmpeg.global.avutil". I think this has nothing to do with linux dependencies at all. The error message shows it can't find the org.bytedeco.ffmpeg.global.avutil class, and the avutil class is part of the javacv, so it looks more like an issue in javacv itself. If the error is about missing external dependencies, the error message should be something like "libxcb-shape0.so.0: cannot open shared object file" instead.

java.lang.NoClassDefFoundError means that some other exception happened before that point. You need to look at that exception to know what the error was.

That's the only error message / stacktrace shown, nothing else before it.

That's the only error message / stacktrace shown, nothing else before it.

I already answered that above: https://github.com/bytedeco/javacv/issues/1357#issuecomment-566352938

I won't be able to help you more if you're unwilling to provide more information.

As I said before, I have enabled debug mode in the logging and I even set the root logging level to debug. The error stack trace result is still same, nothing changes.

Maybe I will try if I can create simple demo gradle app that uses the javacv and the dockerfile script that can reproduce the issue.

Here is the demo app: https://github.com/s101d1/javacv-docker/

When I run it, I got this error:

Exception in thread "main" java.lang.UnsatisfiedLinkError: no jniavutil in java.library.path
        at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867)
        at java.lang.Runtime.loadLibrary0(Runtime.java:870)
        at java.lang.System.loadLibrary(System.java:1122)
        at org.bytedeco.javacpp.Loader.loadLibrary(Loader.java:1543)
        at org.bytedeco.javacpp.Loader.load(Loader.java:1192)
        at org.bytedeco.javacpp.Loader.load(Loader.java:1042)
        at org.bytedeco.ffmpeg.global.avutil.<clinit>(avutil.java:12)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:348)
        at org.bytedeco.javacpp.Loader.load(Loader.java:1109)
        at org.bytedeco.javacpp.Loader.load(Loader.java:1058)
        at com.example.Application.main(Application.java:9)
Caused by: java.lang.UnsatisfiedLinkError: /root/.javacpp/cache/javacv-docker.jar/org/bytedeco/ffmpeg/linux-x86_64/libjniavutil.so: Error relocating /root/.javacpp/cache/javacv-docker.jar/org/bytedeco/ffmpeg/linux-x86_64/libjniavutil.so: malloc_trim: symbol not found
        at java.lang.ClassLoader$NativeLibrary.load(Native Method)
        at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1941)
        at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1824)
        at java.lang.Runtime.load0(Runtime.java:809)
        at java.lang.System.load(System.java:1086)
        at org.bytedeco.javacpp.Loader.loadLibrary(Loader.java:1493)
        ... 8 more

When I coded the demo app, I realized that the JAR must be created as fat JAR or the org.bytedeco.ffmpeg.ffprobe.class won't be found. Maybe this is what caused the java.lang.NoClassDefFoundError: Could not initialize class org.bytedeco.ffmpeg.global.avutil error? But spring boot should create fat jar by default when building the code.

Like I said, it's not using glibc. You'll need to figure out how to install glibc properly.

Alright, it seems I have to switch to other linux image. I have managed to run the web app with the ubuntu docker image (xqdocker/ubuntu-openjdk:8), I just need to install these two packages:

RUN apt-get update -y && apt-get install -y \
 libxcb-shape0 \
 libxcb-xfixes0
Was this page helpful?
0 / 5 - 0 ratings

Related issues

newstarbka picture newstarbka  路  5Comments

The-Crocop picture The-Crocop  路  5Comments

SenudaJayalath picture SenudaJayalath  路  3Comments

chrisliu12345 picture chrisliu12345  路  4Comments

Bahramudin picture Bahramudin  路  3Comments