Open GoogleCodeExporter opened 9 years ago
The documentation from JavaCPP should provide some insights:
http://code.google.com/p/javacpp/#Creating_Callback_Functions
As to what you need to do specifically, do you have some code in C that we
could take a look at?
Original comment by samuel.a...@gmail.com
on 27 May 2013 at 3:32
Hey Samuel,
I have the following code:
Java
-----
import com.googlecode.javacpp.FunctionPointer;
import com.googlecode.javacpp.Loader;
import com.googlecode.javacpp.annotation.Name;
import com.googlecode.javacpp.annotation.Namespace;
import com.googlecode.javacpp.annotation.Platform;
import android.util.Log;
@Platform(include="<algorithm>")
@Namespace("std")
public class FFMpegCallbackManager {
private final static String CLASS_LABEL = "VideoView";
private final static String LOG_TAG = CLASS_LABEL;
static { Loader.load(); }
public static class Callback extends FunctionPointer {
// Loader.load() and allocate() are required only when explicitly creating an instance
static { Loader.load(); }
protected Callback() { allocate(); }
private native void allocate();
public @Name("onRTMPMessage") void call(String messageType, String messageContent) throws Exception {
Log.w(LOG_TAG,"onRTMPMessage: " + messageType + ": " + messageContent);
}
}
}
-----
C
In avformat/rtmpproto.c @ handle_notify
datatowrite = gbc.buffer;
datatowritelength = bytestream2_get_bytes_left(&gbc);
gbc.buffer += 11;
if (ff_amf_read_string(&gbc, statusmsg, sizeof(statusmsg), &stringlen)) {
av_log(s, AV_LOG_ERROR, "onCuePoint Failed\n");
return AVERROR_INVALIDDATA;
} else {
JavaCPP_init(0, NULL);
onRTMPMessage("messageType", "messageContent");
JavaCPP_uninit();
}
---
I looked at the example before writing, and couldn't figure out in the example
what's in jniFoo.h, and where it comes from. It didn't seem to me it was
produced by javah
Moreover, when i take the step of preparing the instructions for android (in
windows) i get the following exceptions:
Warning: Could not load class classes.com.younow.adapters.YouNowChannelAdapter:
java.lang.NoClassDefFoundError: classes/com/younow/adapters/YouNowChannelAdapter
(wrong name: com/younow/adapters/YouNowChannelAdapter)
Warning: Could not load class classes.com.younow.adapters.YouNowEnvAdapter: java
.lang.NoClassDefFoundError: classes/com/younow/adapters/YouNowEnvAdapter (wrong
name: com/younow/adapters/YouNowEnvAdapter)
Warning: Could not load class classes.com.younow.adapters.YouNowSourceAdapter: j
ava.lang.NoClassDefFoundError: classes/com/younow/adapters/YouNowSourceAdapter (
wrong name: com/younow/adapters/YouNowSourceAdapter)
Warning: Could not load class classes.com.younow.BuildConfig: java.lang.NoClassD
efFoundError: classes/com/younow/BuildConfig (wrong name: com/younow/BuildConfig
)
Warning: Could not load class classes.com.younow.jni.FFMpegCallbackManager$Callb
ack: java.lang.NoClassDefFoundError: classes/com/younow/jni/FFMpegCallbackManage
r$Callback (wrong name: com/younow/jni/FFMpegCallbackManager$Callback)
Warning: Could not load class classes.com.younow.jni.FFMpegCallbackManager: java
.lang.NoClassDefFoundError: classes/com/younow/jni/FFMpegCallbackManager (wrong
name: com/younow/jni/FFMpegCallbackManager)
Warning: Could not load class classes.com.younow.MainActivity$1: java.lang.NoCla
ssDefFoundError: classes/com/younow/MainActivity$1 (wrong name: com/younow/MainA
ctivity$1)
Warning: Could not load class classes.com.younow.MainActivity$2: java.lang.NoCla
ssDefFoundError: classes/com/younow/MainActivity$2 (wrong name: com/younow/MainA
ctivity$2)
Warning: Could not load class classes.com.younow.MainActivity$3: java.lang.NoCla
ssDefFoundError: classes/com/younow/MainActivity$3 (wrong name: com/younow/MainA
ctivity$3)
Warning: Could not load class classes.com.younow.MainActivity: java.lang.NoClass
DefFoundError: classes/com/younow/MainActivity (wrong name: com/younow/MainActiv
ity)
Warning: Could not load class classes.com.younow.net.YouNowHttpClient: java.lang
.NoClassDefFoundError: classes/com/younow/net/YouNowHttpClient (wrong name: com/
younow/net/YouNowHttpClient)
Warning: Could not load class classes.com.younow.R$attr: java.lang.NoClassDefFou
ndError: classes/com/younow/R$attr (wrong name: com/younow/R$attr)
Warning: Could not load class classes.com.younow.R$dimen: java.lang.NoClassDefFo
undError: classes/com/younow/R$dimen (wrong name: com/younow/R$dimen)
Warning: Could not load class classes.com.younow.R$drawable: java.lang.NoClassDe
fFoundError: classes/com/younow/R$drawable (wrong name: com/younow/R$drawable)
Warning: Could not load class classes.com.younow.R$id: java.lang.NoClassDefFound
Error: classes/com/younow/R$id (wrong name: com/younow/R$id)
Warning: Could not load class classes.com.younow.R$layout: java.lang.NoClassDefF
oundError: classes/com/younow/R$layout (wrong name: com/younow/R$layout)
Warning: Could not load class classes.com.younow.R$menu: java.lang.NoClassDefFou
ndError: classes/com/younow/R$menu (wrong name: com/younow/R$menu)
Warning: Could not load class classes.com.younow.R$string: java.lang.NoClassDefF
oundError: classes/com/younow/R$string (wrong name: com/younow/R$string)
Warning: Could not load class classes.com.younow.R$style: java.lang.NoClassDefFo
undError: classes/com/younow/R$style (wrong name: com/younow/R$style)
Warning: Could not load class classes.com.younow.R: java.lang.NoClassDefFoundErr
or: classes/com/younow/R (wrong name: com/younow/R)
Warning: Could not load class classes.com.younow.RecordActivity$AudioRecordRunna
ble: java.lang.NoClassDefFoundError: classes/com/younow/RecordActivity$AudioReco
rdRunnable (wrong name: com/younow/RecordActivity$AudioRecordRunnable)
Warning: Could not load class classes.com.younow.RecordActivity$CameraView: java
.lang.NoClassDefFoundError: classes/com/younow/RecordActivity$CameraView (wrong
name: com/younow/RecordActivity$CameraView)
Warning: Could not load class classes.com.younow.RecordActivity: java.lang.NoCla
ssDefFoundError: classes/com/younow/RecordActivity (wrong name: com/younow/Recor
dActivity)
Warning: Could not load class classes.com.younow.server.YouNowChannel: java.lang
.NoClassDefFoundError: classes/com/younow/server/YouNowChannel (wrong name: com/
younow/server/YouNowChannel)
Warning: Could not load class classes.com.younow.server.YouNowEnv: java.lang.NoC
lassDefFoundError: classes/com/younow/server/YouNowEnv (wrong name: com/younow/s
erver/YouNowEnv)
Warning: Could not load class classes.com.younow.server.YouNowSource: java.lang.
NoClassDefFoundError: classes/com/younow/server/YouNowSource (wrong name: com/yo
unow/server/YouNowSource)
Warning: Could not load class classes.com.younow.VersionActivity: java.lang.NoCl
assDefFoundError: classes/com/younow/VersionActivity (wrong name: com/younow/Ver
sionActivity)
Warning: Could not load class classes.com.younow.ViewActivity$1: java.lang.NoCla
ssDefFoundError: classes/com/younow/ViewActivity$1 (wrong name: com/younow/ViewA
ctivity$1)
Warning: Could not load class classes.com.younow.ViewActivity$2: java.lang.NoCla
ssDefFoundError: classes/com/younow/ViewActivity$2 (wrong name: com/younow/ViewA
ctivity$2)
Warning: Could not load class classes.com.younow.ViewActivity$3: java.lang.NoCla
ssDefFoundError: classes/com/younow/ViewActivity$3 (wrong name: com/younow/ViewA
ctivity$3)
Warning: Could not load class classes.com.younow.ViewActivity$4$1: java.lang.NoC
lassDefFoundError: classes/com/younow/ViewActivity$4$1 (wrong name: com/younow/V
iewActivity$4$1)
Warning: Could not load class classes.com.younow.ViewActivity$4: java.lang.NoCla
ssDefFoundError: classes/com/younow/ViewActivity$4 (wrong name: com/younow/ViewA
ctivity$4)
Warning: Could not load class classes.com.younow.ViewActivity$DoorsDataResponse:
java.lang.NoClassDefFoundError: classes/com/younow/ViewActivity$DoorsDataRespon
se (wrong name: com/younow/ViewActivity$DoorsDataResponse)
Warning: Could not load class classes.com.younow.ViewActivity$DoorsDataRetriever
: java.lang.NoClassDefFoundError: classes/com/younow/ViewActivity$DoorsDataRetri
ever (wrong name: com/younow/ViewActivity$DoorsDataRetriever)
Warning: Could not load class classes.com.younow.ViewActivity: java.lang.NoClass
DefFoundError: classes/com/younow/ViewActivity (wrong name: com/younow/ViewActiv
ity)
Warning: Could not load class classes.com.younow.views.VideoView$CanvasThread: j
ava.lang.NoClassDefFoundError: classes/com/younow/views/VideoView$CanvasThread (
wrong name: com/younow/views/VideoView$CanvasThread)
Warning: Could not load class classes.com.younow.views.VideoView: java.lang.NoCl
assDefFoundError: classes/com/younow/views/VideoView (wrong name: com/younow/vie
ws/VideoView)
Warning: Could not load class com.younow.adapters.YouNowChannelAdapter: java.lan
g.NoClassDefFoundError: android/widget/ArrayAdapter
Warning: Could not load class com.younow.adapters.YouNowEnvAdapter: java.lang.No
ClassDefFoundError: android/widget/ArrayAdapter
Warning: Could not load class com.younow.adapters.YouNowSourceAdapter: java.lang
.NoClassDefFoundError: android/widget/ArrayAdapter
Warning: Could not load class com.younow.MainActivity$1: java.lang.NoClassDefFou
ndError: android/view/View$OnClickListener
Warning: Could not load class com.younow.MainActivity$2: java.lang.NoClassDefFou
ndError: android/view/View$OnClickListener
Warning: Could not load class com.younow.MainActivity$3: java.lang.NoClassDefFou
ndError: android/view/View$OnClickListener
Warning: Could not load class com.younow.MainActivity: java.lang.NoClassDefFound
Error: android/app/Activity
Warning: Could not load class com.younow.RecordActivity$CameraView: java.lang.No
ClassDefFoundError: android/view/SurfaceHolder$Callback
Warning: Could not load class com.younow.RecordActivity: java.lang.NoClassDefFou
ndError: android/view/View$OnClickListener
Warning: Could not load class com.younow.VersionActivity: java.lang.NoClassDefFo
undError: android/app/Activity
Warning: Could not load class com.younow.ViewActivity$1: java.lang.NoClassDefFou
ndError: android/widget/AdapterView$OnItemSelectedListener
Warning: Could not load class com.younow.ViewActivity$2: java.lang.NoClassDefFou
ndError: android/widget/AdapterView$OnItemSelectedListener
Warning: Could not load class com.younow.ViewActivity$3: java.lang.NoClassDefFou
ndError: android/widget/AdapterView$OnItemSelectedListener
Warning: Could not load class com.younow.ViewActivity$DoorsDataRetriever: java.l
ang.NoClassDefFoundError: android/os/AsyncTask
Warning: Could not load class com.younow.ViewActivity: java.lang.NoClassDefFound
Error: android/view/View$OnClickListener
Warning: Could not load class com.younow.views.VideoView: java.lang.NoClassDefFo
undError: android/view/SurfaceHolder$Callback
Exception in thread "main" java.lang.NoClassDefFoundError: android/view/View$OnC
lickListener
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.security.SecureClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access$100(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at com.googlecode.javacpp.Builder$UserClassLoader.findClass(Builder.java
:479)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.Class.getDeclaringClass(Native Method)
at com.googlecode.javacpp.Loader.appendProperties(Loader.java:158)
at com.googlecode.javacpp.Builder.build(Builder.java:744)
at com.googlecode.javacpp.Builder.main(Builder.java:861)
Caused by: java.lang.ClassNotFoundException: android.view.View$OnClickListener
at java.net.URLClassLoader$1.run(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at com.googlecode.javacpp.Builder$UserClassLoader.findClass(Builder.java
:479)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 16 more
Thanks a lot,
K
Original comment by klomm...@gmail.com
on 27 May 2013 at 4:08
I forgot to mention one thing - I also have no idea where it comes from. I
searched the projects of JavaCV and JavaCPP searching for it, and found nothing.
p.s.
I truly appreciate the effort you take into answering my ignorant questions.
Thanks again.
Original comment by klomm...@gmail.com
on 27 May 2013 at 4:29
It seems JavaCPP can't find your classes there. Have you made sure to include
everything in the CLASSPATH? Or try to decouple your "FFMpegCallbackManager"
from the rest of the code?
jniFoo.h comes from the "-header" command line option. Try it out as per the
README.txt file!
Original comment by samuel.a...@gmail.com
on 2 Jun 2013 at 5:38
Hey Samuel,
Thank you so much for your guidance. I'll try it again and update on what i
came up with.
Much appreciated,
K
Original comment by klomm...@gmail.com
on 2 Jun 2013 at 12:23
Hey Samuel,
Well, I made a small progress - was able to create the header and the .so lib
file for FFMpegCallbackManager, and added the change to the C code (attached).
Built FFMpeg and JavaCV successfully with the new changes, and tried the
application. Received the following exceptions:
06-03 13:43:09.745: E/AndroidRuntime(1020): FATAL EXCEPTION: main
06-03 13:43:09.745: E/AndroidRuntime(1020):
java.lang.ExceptionInInitializerError
06-03 13:43:09.745: E/AndroidRuntime(1020): at
com.googlecode.javacv.FFmpegFrameGrabber.<init>(FFmpegFrameGrabber.java:105)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
com.younow.views.VideoView.initGrabber(VideoView.java:110)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
com.younow.views.VideoView.start(VideoView.java:96)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
com.younow.ViewActivity.startVideo(ViewActivity.java:426)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
com.younow.ViewActivity.onClick(ViewActivity.java:400)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
android.view.View.performClick(View.java:4232)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
android.view.View$PerformClick.run(View.java:17298)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
android.os.Handler.handleCallback(Handler.java:615)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
android.os.Handler.dispatchMessage(Handler.java:92)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
android.os.Looper.loop(Looper.java:137)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
android.app.ActivityThread.main(ActivityThread.java:4921)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
java.lang.reflect.Method.invokeNative(Native Method)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
java.lang.reflect.Method.invoke(Method.java:511)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1027)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:794)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
dalvik.system.NativeStart.main(Native Method)
06-03 13:43:09.745: E/AndroidRuntime(1020): Caused by:
java.lang.ExceptionInInitializerError
06-03 13:43:09.745: E/AndroidRuntime(1020): at
java.lang.Class.classForName(Native Method)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
java.lang.Class.forName(Class.java:217)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
com.googlecode.javacpp.Loader.load(Loader.java:453)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
com.googlecode.javacv.cpp.avdevice.<clinit>(avdevice.java:62)
06-03 13:43:09.745: E/AndroidRuntime(1020): ... 16 more
06-03 13:43:09.745: E/AndroidRuntime(1020): Caused by:
java.lang.ExceptionInInitializerError
06-03 13:43:09.745: E/AndroidRuntime(1020): at
java.lang.Class.classForName(Native Method)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
java.lang.Class.forName(Class.java:217)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
com.googlecode.javacpp.Loader.load(Loader.java:453)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
com.googlecode.javacv.cpp.avfilter.<clinit>(avfilter.java:79)
06-03 13:43:09.745: E/AndroidRuntime(1020): ... 20 more
06-03 13:43:09.745: E/AndroidRuntime(1020): Caused by:
java.lang.UnsatisfiedLinkError: Cannot load library: link_image[1892]: 1837
could not load needed library 'libavformat.so' for 'libjniavformat.so'
(find_library[1202]: 1837 'libavformat.so' failed to load previously)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
java.lang.Runtime.loadLibrary(Runtime.java:370)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
java.lang.System.loadLibrary(System.java:535)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
com.googlecode.javacpp.Loader.loadLibrary(Loader.java:593)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
com.googlecode.javacpp.Loader.load(Loader.java:489)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
com.googlecode.javacpp.Loader.load(Loader.java:431)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
com.googlecode.javacv.cpp.avformat.<clinit>(avformat.java:76)
06-03 13:43:09.745: E/AndroidRuntime(1020): ... 24 more
06-03 13:43:09.745: E/AndroidRuntime(1020): Caused by:
java.lang.UnsatisfiedLinkError: Cannot load library: reloc_library[1307]: 1837
cannot locate 'JavaCPP_init'...
06-03 13:43:09.745: E/AndroidRuntime(1020): at
java.lang.Runtime.loadLibrary(Runtime.java:370)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
java.lang.System.loadLibrary(System.java:535)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
com.googlecode.javacpp.Loader.loadLibrary(Loader.java:593)
06-03 13:43:09.745: E/AndroidRuntime(1020): at
com.googlecode.javacpp.Loader.load(Loader.java:481)
06-03 13:43:09.745: E/AndroidRuntime(1020): ... 26 more
Needless to say - the ffmpeg and jni libs are in armeabi folder. Have no idea
why it's happening. Any ideas?
K
Original comment by klomm...@gmail.com
on 3 Jun 2013 at 2:37
Attachments:
JavaCPP_init() is basically a simple wrapper to JNI_CreateJavaVM(), but that's
not available on Android, so just remove the calls to JavaCPP_init() and
JavaCPP_uninit().
Original comment by samuel.a...@gmail.com
on 4 Jun 2013 at 1:19
No good. After removing the JavaCPP_(un)init lines, it's throwing the same
exception, this time for onRTMPMessage
06-04 09:03:04.038: E/AndroidRuntime(1501): FATAL EXCEPTION: main
06-04 09:03:04.038: E/AndroidRuntime(1501):
java.lang.ExceptionInInitializerError
06-04 09:03:04.038: E/AndroidRuntime(1501): at
com.googlecode.javacv.FFmpegFrameGrabber.<init>(FFmpegFrameGrabber.java:105)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
com.younow.views.VideoView.initGrabber(VideoView.java:110)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
com.younow.views.VideoView.start(VideoView.java:96)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
com.younow.ViewActivity.startVideo(ViewActivity.java:426)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
com.younow.ViewActivity.onClick(ViewActivity.java:400)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
android.view.View.performClick(View.java:4232)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
android.view.View$PerformClick.run(View.java:17298)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
android.os.Handler.handleCallback(Handler.java:615)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
android.os.Handler.dispatchMessage(Handler.java:92)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
android.os.Looper.loop(Looper.java:137)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
android.app.ActivityThread.main(ActivityThread.java:4921)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
java.lang.reflect.Method.invokeNative(Native Method)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
java.lang.reflect.Method.invoke(Method.java:511)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1027)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:794)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
dalvik.system.NativeStart.main(Native Method)
06-04 09:03:04.038: E/AndroidRuntime(1501): Caused by:
java.lang.ExceptionInInitializerError
06-04 09:03:04.038: E/AndroidRuntime(1501): at
java.lang.Class.classForName(Native Method)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
java.lang.Class.forName(Class.java:217)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
com.googlecode.javacpp.Loader.load(Loader.java:453)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
com.googlecode.javacv.cpp.avdevice.<clinit>(avdevice.java:62)
06-04 09:03:04.038: E/AndroidRuntime(1501): ... 16 more
06-04 09:03:04.038: E/AndroidRuntime(1501): Caused by:
java.lang.ExceptionInInitializerError
06-04 09:03:04.038: E/AndroidRuntime(1501): at
java.lang.Class.classForName(Native Method)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
java.lang.Class.forName(Class.java:217)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
com.googlecode.javacpp.Loader.load(Loader.java:453)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
com.googlecode.javacv.cpp.avfilter.<clinit>(avfilter.java:79)
06-04 09:03:04.038: E/AndroidRuntime(1501): ... 20 more
06-04 09:03:04.038: E/AndroidRuntime(1501): Caused by:
java.lang.UnsatisfiedLinkError: Cannot load library: link_image[1892]: 1837
could not load needed library 'libavformat.so' for 'libjniavformat.so'
(find_library[1202]: 1837 'libavformat.so' failed to load previously)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
java.lang.Runtime.loadLibrary(Runtime.java:370)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
java.lang.System.loadLibrary(System.java:535)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
com.googlecode.javacpp.Loader.loadLibrary(Loader.java:593)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
com.googlecode.javacpp.Loader.load(Loader.java:489)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
com.googlecode.javacpp.Loader.load(Loader.java:431)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
com.googlecode.javacv.cpp.avformat.<clinit>(avformat.java:76)
06-04 09:03:04.038: E/AndroidRuntime(1501): ... 24 more
06-04 09:03:04.038: E/AndroidRuntime(1501): Caused by:
java.lang.UnsatisfiedLinkError: Cannot load library: reloc_library[1307]: 1837
cannot locate 'onRTMPMessage'...
06-04 09:03:04.038: E/AndroidRuntime(1501): at
java.lang.Runtime.loadLibrary(Runtime.java:370)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
java.lang.System.loadLibrary(System.java:535)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
com.googlecode.javacpp.Loader.loadLibrary(Loader.java:593)
06-04 09:03:04.038: E/AndroidRuntime(1501): at
com.googlecode.javacpp.Loader.load(Loader.java:481)
06-04 09:03:04.038: E/AndroidRuntime(1501): ... 26 more
Original comment by klomm...@gmail.com
on 4 Jun 2013 at 6:15
Ah yes, Android doesn't "officially" support circular dependencies like that,
so we're probably best avoiding those. The way to go around this would be to
have an init() function that sets your callback once at start up, something
like:
public class FFMpegCallbackManager {
static { Loader.load(); init(callback); }
public static final Callback callback = new Callback();
public static native void init(Callback callback);
public static class Callback extends FunctionPointer {
static { Loader.load(); }
public Callback() { allocate(); }
private native void allocate();
public void call(String messageType, String messageContent) throws Exception {
System.out.println("onRTMPMessage: " + messageType + ": " + messageContent);
}
}
}
Where on the native side the init() function stores the function pointer it
gets in some global variable.
Original comment by samuel.a...@gmail.com
on 6 Jun 2013 at 10:03
Samuel,
Sorry for the late reply, have relocated to NY, and suffering from a killer jet
lag. I took a look now at what you've written, which makes a lot of sense. I
have made the proper changes to FFMpegCallbackManager, and built the .so and .h
files using JavaCPP.
To my surprise, I have also received a rather exciting .cpp file, which left me
puzzling. I am not sure what I am supposed to do with this file. Clearly, I
can't include it in the FFMpeg project. Is it just an example, or is it a must?
Should I cannibalize it, and take only what I need?
I apologize for my noob questions, but this is getting more complicated for me
by the minute.
Thanks again.
Original comment by klomm...@gmail.com
on 10 Jun 2013 at 10:17
If you're left with a .cpp file it's either because you used the "-nocompile"
flag or you're getting a compilation error, and JavaCPP is leaving the file
behind for your inspection. If you're getting a compiler error, please paste it
here! thanks
Original comment by samuel.a...@gmail.com
on 13 Jun 2013 at 7:02
It was impossible to notice the error inside all the verbose print out. But
this is what i get:
libs\armeabi\jniFFMpegCallbackManager.cpp:215:38: warning: missing terminating "
character [enabled by default]
libs\armeabi\jniFFMpegCallbackManager.cpp: In function 'void Java_com_younow_jni
_FFMpegCallbackManager_init(JNIEnv*, jclass, jobject)':
libs\armeabi\jniFFMpegCallbackManager.cpp:1165:47: error: 'init' was not
declaredd in this scope
I am attaching everything involved.
Thanks
Original comment by klomm...@gmail.com
on 13 Jun 2013 at 1:55
Attachments:
init() is a native function you need to provide in your code somewhere,
including a function declaration in a header file. And I guess we would put it
along your modifications in rtmpproto.c ...
Original comment by samuel.a...@gmail.com
on 16 Jun 2013 at 2:10
That is clear - and i have everything prepared (or so i think)
I have these lines in the header (rtmpproto.h) which i prepared, that is
included in rtmpproto.c :
#include "jniFFMpegCallbackManager.h"
// pointer to the callback function
void (*youNowCallbackPtr)(const char*, const char*);
// init for setting the callback from java
void init(void (*callbackPtr)(const char*, const char*));
question is how do i target javacpp.jar to actually compile the ffmpeg files
for the .so library. Right now the compilation breaks in the middle because it
can't find init(). Do i have to include the entire ffmpeg code in the
compilation of the .so file?
I don't know if anyone else is following our correspondence, but i will try to
summarize the entire process we've been through, because at least in my
opinion, setting up javacpp callbacks to work in android is far from trivial.
Thanks,
K
Original comment by klomm...@gmail.com
on 19 Jun 2013 at 9:26
You can link all that in whatever way works with your platform. With Android,
I'm pretty sure it works the same as normal Linux in that case:
1. Define a function
2. Build a library containing that function definition (the .so file)
3. Link with that library (yes, the "link" value of JavaCPP means that)
I'm not seeing any function definition from your description, so if you forgot
that, define it, and try again.
I agree, we need more documentation. Unfortunately, no volunteers has come
forth. I can give you Wiki access to write up something when you feel up to it.
Original comment by samuel.a...@gmail.com
on 21 Jun 2013 at 2:45
Big progress. This is what the java class looks like:
@Platform(value="android",cinclude="rtmpproto.h", link="avformat",
preload={"avutil","avcodec"})
public class FFMpegCallbackManager {
public static final Callback callback = new Callback();
static {
Loader.load();
init(callback);
}
public static native void init(Callback callback);
public static class Callback extends FunctionPointer {
static { Loader.load(); }
public Callback() { allocate(); }
private native void allocate();
public void call(String messageType, String messageContent) throws Exception {
Log.w("Callback", "onRTMPMessage: " + messageType + ": " + messageContent);
}
}
}
With the function definition of init() as follows:
static void init(void (*callbackPtr)(const char*, const char*)) {
younowCallbackPtr = callbackPtr;
}
The Java side is actually capable of finding the native init(). However, when i
call the actual callback, i get a nasty non descriptive SIGSEGV. I suspected
the callback pointer was NULL, which it was. Unfortunately this is where i get
stuck. This is the call to the callback:
if (younowCallbackPtr != NULL) {
younowCallbackPtr(commandbuffer, statusmsg);
}
Wanted to ask if you might have an idea why it could happen, and whether there
is some kind of built in log interface to pass messages to android because
right now i have no way of knowing what happens on the native side.
Thanks
Original comment by klomm...@gmail.com
on 25 Jun 2013 at 11:15
i forgot to mention - commandbuffer and statusmsg are both char[]. Just to make
things clear
Original comment by klomm...@gmail.com
on 25 Jun 2013 at 11:17
I've been debugging a bit further. The callback pointer i'm receiving ISN'T
null, and when i callback from init() it actually works. The problem begins
when init is finished, and the pointer that i have copied with much blood and
sweat is getting destroyed - leading to a null pointer exception.
I'm not entirely sure the problems comes from the C side. Init is a static
function and saves the pointer in a global variable. Both reside in the same
file, and are obviously visible to each other.
I've tried all kind of funky stuff - setting init to non-static, using extern
and static for the callback pointer, and all other stuff - the simple news is
that it refuses to work.
It may be interesting to mention that when inside init, i am able to log to
android using __android_write(), in all other parts of the code, i can't. I
don't know what to say - i find this all very weird.
Any help would be appreciated.
Code:
The java hasn't changed from the last message
C:
void (*younowCallbackPtr)(const char*, const char*);
static void init(void (*callbackPtr)(const char*, const char*)) {
char buffer [512];
sprintf (buffer, "Trying to call younowCallback: %p", callbackPtr);
__android_log_write(ANDROID_LOG_ERROR, "Tag", buffer);
__android_log_write(ANDROID_LOG_ERROR, "Tag", "init called");
callbackPtr("Name", "Value"); // works
__android_log_write(ANDROID_LOG_ERROR, "Tag", "callback called");
memcpy ( &younowCallbackPtr, &callbackPtr, sizeof(callbackPtr));
__android_log_write(ANDROID_LOG_ERROR, "Tag", buffer);
younowCallbackPtr("Name", "Value"); //works
}
static int handle_notify(URLContext *s, RTMPPacket *pkt) {
RTMPContext *rt = s->priv_data;
const uint8_t *p = NULL;
uint8_t *cp = NULL;
char commandbuffer[64];
uint8_t databuffer[512];
char statusmsg[2048];
int stringlen;
GetByteContext gbc;
PutByteContext pbc;
uint32_t ts;
int old_flv_size;
const uint8_t *datatowrite;
unsigned datatowritelength;
uint8_t *data = NULL;
p = pkt->data;
bytestream2_init(&gbc, p, pkt->data_size);
if (ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer), &stringlen)) {
return AVERROR_INVALIDDATA;
}
if (!strcmp(commandbuffer, "@setDataFrame")) {
datatowrite = gbc.buffer;
datatowritelength = bytestream2_get_bytes_left(&gbc);
if (ff_amf_read_string(&gbc, statusmsg,
sizeof(statusmsg), &stringlen))
return AVERROR_INVALIDDATA;
if (strcmp(statusmsg, "onMetaData")) {
av_log(s, AV_LOG_INFO, "Expecting onMetadata but got %s\n",
statusmsg);
return 0;
}
/* Provide ECMAArray to flv */
ts = pkt->timestamp;
// generate packet header and put data into buffer for FLV demuxer
if (rt->flv_off < rt->flv_size) {
old_flv_size = rt->flv_size;
rt->flv_size += datatowritelength + 15;
} else {
old_flv_size = 0;
rt->flv_size = datatowritelength + 15;
rt->flv_off = 0;
}
cp = av_realloc(rt->flv_data, rt->flv_size);
if (!cp)
return AVERROR(ENOMEM);
rt->flv_data = cp;
bytestream2_init_writer(&pbc, cp, rt->flv_size);
bytestream2_skip_p(&pbc, old_flv_size);
bytestream2_put_byte(&pbc, pkt->type);
bytestream2_put_be24(&pbc, datatowritelength);
bytestream2_put_be24(&pbc, ts);
bytestream2_put_byte(&pbc, ts >> 24);
bytestream2_put_be24(&pbc, 0);
bytestream2_put_buffer(&pbc, datatowrite, datatowritelength);
bytestream2_put_be32(&pbc, 0);
} else if ((!strcmp(commandbuffer, "onCuePoint")) ||
(!strcmp(commandbuffer, "onChannelsData"))) {
datatowrite = gbc.buffer;
datatowritelength = bytestream2_get_bytes_left(&gbc);
gbc.buffer += 11;
if (ff_amf_read_string(&gbc, statusmsg, sizeof(statusmsg), &stringlen)) {
av_log(s, AV_LOG_ERROR, "onCuePoint Failed\n");
return AVERROR_INVALIDDATA;
} else {
younowCallbackPtr(commandbuffer, statusmsg); // doesn't work - SIGSEGV at 0x00000000 (code 1)
}
}
return 0;
}
Original comment by klomm...@gmail.com
on 26 Jun 2013 at 8:11
It sounds like the `Callback` Java object is getting garbage collected. To
avoid that, that's why we keep a reference to it in a static variable in your
FFMpegCallbackManager class there, but for some reason, it is still getting
garbage collected it seems... Are you sure the FFMpegCallbackManager class
itself isn't getting garbage collected by whatever classloader Android happens
to use for it?
Original comment by samuel.a...@gmail.com
on 28 Jun 2013 at 11:36
I think I see what the problem is. The fact that you are using the "static"
keyword indicates you are putting your code in a header file, so the `include`
you do for JavaCPP and the one you do for rtmpproto.c (or whatever) ends up
creating two instances of the global `younowCallbackPtr`: They don't point to
the same are of memory.
You need to define `younowCallbackPtr` and `init()` in the native library, and
*link* with it, not *include* it. Java got rid of this nonsense with the
concept of "import", but C and C++ do not function that way.
Original comment by samuel.a...@gmail.com
on 29 Jun 2013 at 2:47
[deleted comment]
What you're saying makes sense. The problem is that once i remove the include
from the @platform annotation, javacpp doesn't seem to be able to find init().
I've checked the command line, and it does contain
-lavformat and -L<Path/To/libavformat.so>
So i continued to see avformat's symbol table, and indeed, the function is not
there. I tried all different combinations, but i can't seem to convince ffmpeg
to export my function. I get the same results also when running config with
--disable-stripping.
The general structure hasn't changed - a non-static function declaration in
rtmpproto.h, and its definiton in rtmpproto.c.
Original comment by klomm...@gmail.com
on 1 Jul 2013 at 5:48
I'm afraid you will need to learn a bit more about C/C++ on Linux to get this
working. This page seems to have all the info you need:
http://web.cs.swarthmore.edu/~newhall/unixhelp/howto_C_libraries.html If that
doesn't help, please study some other material.
Original comment by samuel.a...@gmail.com
on 2 Jul 2013 at 11:54
Yeah, you're correct about that. The problem is that FFmpeg is such a huge
product with its own build process that every guidance is helpful. Been
experimenting with it yesterday, and still couldnt get it to work. Will make it
happen.
Telling you all, the moment i am getting this callback to work, we make a huge
party in japan, and you sir - you get a huge hug for all the help you've given
me.
Couldn't emphasize enough how much i appreciate that.
K
Original comment by klomm...@gmail.com
on 2 Jul 2013 at 12:42
So, any progress?
You're in Japan? Sure, but I'd prefer contributions to the project :)
Original comment by samuel.a...@gmail.com
on 7 Jul 2013 at 1:33
No. Im in NYC, but I will take a flight to japan just to give u that hug. Didnt
get anywhere near the code the past week. Has been sick as a dog. The moment I
have anything ill update.
K
Original comment by klomm...@gmail.com
on 7 Jul 2013 at 1:37
No good news i'm afraid.
Been attempting to take different approaches, but no matter what i tried i
couldn't get it to work.
My first idea was to create a separate native library that would only have a
non static init, and extern ynCallbackPtr. Both ffmpeg and the jni library
would link to it. Didn't work. ynCallbackPtr kept getting different instances
in different parts of the memory leading to a null pointer exception on the
native side.
Then i tried to provide only one non-static declaration of init(), using a
local ynCallbackPtr that doesn't even appear in the header - hoping that it
would prevent double instances for ynCallbackPtr. I included the header, and
linked to the native library in java cpp, and provided the init() definition in
the avformat lib. the jni lib couldn't locate init().
I am still unable to think of a design that will ensure single instance for the
pointer, and a visible init() declaration both for javacpp and avformat. it
seems that in javacpp a certain include is a must, and so is a link to some
library. Same goes on the AVFormat side. I am not sure how i could (as u said)
link with it, and not include it, when there must be an inclusion on both sides.
I have doubled checked - init() symbol is present on the libavformat.so, but
without the include annotation, building the jniFFMpegCallbackManager.so fails
because it can't find init()'s declaration
I thought that since javacv is loading the ffmpeg libs, then their symbols will
be loaded to the memory, allowing jniFFMpegCallbackManager.so to use these
tables, but it doesn't work.
Bottom line, i have no idea how to go around this problem. If anyone has an
idea how to solve this, i would greatly appreciate it. Alas, I give up.
Thanks all.
Original comment by klomm...@gmail.com
on 11 Jul 2013 at 9:32
The problem isn't with the init() function, it's with the variable you use to
store the function pointer. That variable has to be defined in only one place,
so you can't put it in any header files.
Original comment by samuel.a...@gmail.com
on 12 Jul 2013 at 1:22
It works!
I don't know whether to cry or laugh, but after seven weeks of on and off
attempts, and god knows how many bottles of whisky, i found the problem, which
as expected is rather silly.
My main mistake was to use nm, instead of readelf to check the library symbol
table. I kept seeing that my callback register function was exported, and
couldn't understand why JavaCPP can't locate it when loading the library.
Several minutes of readelf and finally i understood. The function name must
start with the av prefix in order to be global. That's all.
Samuel, really appreciate all your effort on this. Booking my flight to Japan
right now! You get a big hug! ;)
Original comment by klomm...@gmail.com
on 15 Jul 2013 at 7:01
Interesting, maybe it's the build system of FFmpeg that removes from the symbol
table any that doesn't start with "av". Good to know :) Thanks for reporting!
Original comment by samuel.a...@gmail.com
on 16 Jul 2013 at 1:43
Original issue reported on code.google.com by
klomm...@gmail.com
on 26 May 2013 at 6:11