Reputation: 33
I am running a play framework application using opencv with scala. When I run the application I am receiving an UnsatisfiedLinkError from VideoCapture, so how can I load the opencv library correctly?
When i run a test using classes from opencv everything works correctly. I always set the System.loadLibrary(Core.NATIVE_LIBRARY_NAME) and define the java.path.library param correctly. But when I run the play application this doesn't work as with the tests.
From other posts, people have been resolving this issue using the abstract GlobalSetting class from play and loading the library in the beforeStart() method. But this has been deprecated and now Play recommends to do an eager binding. I have already tried to create an Eager loader to run first when I start the server where I load the library in the same way I run the tests. The code in this class run first as it's supposed to be but it doesn't save my problem.
I have also tried to load the library in the different controllers i have and the class where I use the VideoCapture() but nothing works. Moreover, i tried to create a sbt task where i loaded the library but didn't work.
class EagerLoaderModule extends AbstractModule {
override def configure(): Unit = bind(classOf[StartUpService]).asEagerSingleton()
}
final class StartUpService {
def loadedLibs: Seq[String] = {
val libs = classOf[ClassLoader].getDeclaredField("loadedLibraryNames")
libs.setAccessible(true)
import scala.collection.JavaConverters._
libs.get(ClassLoader.getSystemClassLoader)
.asInstanceOf[java.util.Vector[String]]
.asScala
}
def loadOpenCVOnDemand(): Unit = {
val isLoaded = loadedLibs.map(str => str contains "opencv").reduce((x, y) => x || y)
if(!isLoaded) {
try {
println("hey there dude")
System.loadLibrary(Core.NATIVE_LIBRARY_NAME)
println("ksdfjsdkfh")
} catch {
case e: UnsatisfiedLinkError =>
println("Loading Library OPENCV")
System.loadLibrary("opencv_java345")
// e.printStackTrace()
}
}
}
loadOpenCVOnDemand()
}
The error I am receiving is: java.lang.UnsatisfiedLinkError: org.opencv.videoio.VideoCapture.VideoCapture_1(Ljava/lang/String;)J and I know that it is because the System.loadLibrary(Core.NATIVE_LIBRARY_NAME) isn't working correctly but how can I make it to work or where should I set it so the application loads the library correctly?
Upvotes: 3
Views: 649
Reputation: 48400
Native library support in development mode(play run) #2212 identifies the issue as:
When libopencv_java is loaded from the play-sbt-plugin managed code, it is loaded into the ReloadableClassLoader, but opencv-*.jar is already in the PlayDependencyClassLoader. It seems JDK does not like that kind of split. So, native library and it's java counterpart should (must?) be in the same class loader. One solution is to move out load / loadLibrary calls from the Play based project into a separate jar and then add that jar as a project dependency.
To workaround try importing play-native-loader
libraryDependencies += "com.typesafe.play" %% "play-native-loader" % "1.0.0"
and load the library with NativeLoader.load
instead of System.loadLibrary
like so
NativeLoader.load(Core.NATIVE_LIBRARY_NAME)
play-opencv-native-example is a working example.
Upvotes: 2