jmgomezpoveda / JGaze

Gaze library in Java
1 stars 1 forks source link

JavaCV FFmpegFrameGrabber: Unable to destroy and re-create grabber #12

Open jmgomezpoveda opened 11 years ago

jmgomezpoveda commented 11 years ago

Detail in https://groups.google.com/forum/#!topic/javacv/LKq5uewdjCw

I want to use a FFmpegFrameGrabber when possible, but if something fails (the user doesn't have the ffmpeg libraries, or any other initialization problem, I would like to release the reserved resources, and create an OpenCVFrameGrabber:

FrameGrabber grabber = new FFmpegFrameGrabber(new java.io.File("/dev/video0"));
grabber.setFormat("video4linux2");

try {
    grabber.start();
}
catch (Exception e)
{
    grabber.stop();
    grabber.release();
    grabber = null;

    grabber = FrameGrabber.createDefault(0);    // Lowest common denominator
    grabber.start();
}

However, on the second grabber.start(), I get the following error:

libv4l2: error setting pixformat: Device or resource busy
HIGHGUI ERROR: libv4l unable to ioctl S_FMT
libv4l2: error setting pixformat: Device or resource busy
libv4l1: error setting pixformat: Device or resource busy
HIGHGUI ERROR: libv4l unable to ioctl VIDIOCSPICT

*** glibc detected *** /usr/lib/jvm/java-7-oracle/bin/java: double free or corruption (fasttop): 0x00007f68c4199dd0 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x7eb96)[0x7f68cb6d8b96]
/tmp/javacpp42478226030754/libopencv_highgui.so.2.4(_ZN20CvCaptureCAM_V4L_CPP4openEi+0x6ca)[0x7f688e52312a]
/tmp/javacpp42478226030754/libopencv_highgui.so.2.4(_Z25cvCreateCameraCapture_V4Li+0x3d)[0x7f688e52459d]
/tmp/javacpp42478226030754/libopencv_highgui.so.2.4(cvCreateCameraCapture+0x7a)[0x7f688e5125ca]
/tmp/javacpp42478226030754/libjniopencv_highgui.so(Java_com_googlecode_javacv_cpp_opencv_1highgui_cvCreateCameraCapture+0x1d)[0x7f688901ce0d]
[0x7f68c1011f90]
======= Memory map: ========

I have tried using/commenting out several combinations of grabber.stop/release, but so far I haven't been able to create an OpenCVFrameGrabber after a failed attempt to build a FFmpegFrameGrabber.

However, if I create an OpenCVFrameGrabber, destroy it, and create a new one, that is fine. The problem is only trying to create first a FFmpegFrameGrabber and afterwards a OpenCVFrameGrabber.

jmgomezpoveda commented 11 years ago

According to FFmpeg's documentation, there's nothing to do done when avformat_open_input() fails, but to abort, give up. So I guess there is a bug in FFmpeg and it fails to release some resources before deallocating its memory. You should report that to them so they can fix it :)

Samuel

jmgomezpoveda commented 11 years ago

In FFmpegFrameGrabber.java, I have tried to add a call to avformat_close_input in the exception after avformat_open_input, but I get an error like:

# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007f1db5e398a2, pid=25944, tid=139766481565440
#
# JRE version: 7.0_17-b02
# Java VM: Java HotSpot(TM) 64-Bit Server VM (23.7-b01 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C  [libavformat.so.54.59.106+0xff8a2]  avformat_close_input+0x12

So, it is probably not a good solution... :)

I have also tried adding the following before throwing the exception:

release();
av_dict_free(options);
oc = null;

No improvement so far...

noncom commented 11 years ago

JavaCV is very cool and I highly prefer it over Java port of OpenCV for its video streaming capabilities, but I'm getting the same error. In my application I grab many files one after another, and on one of them this error happens. It totally ruins everything.. :( I do not know how to report to the FFmpeg team because I know very little C or C++ and cannot even properly describe what is happening (I guess "error releasing resources" is not very descriptive).

I find some details interesting, though: look at where the error occures:

Stack: [0x06e50000,0x06ea0000],  sp=0x06e9e818,  free space=314k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C  [swscale-2.dll+0x36df7]  sws_getCachedContext+0x177e7

Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j  com.googlecode.javacv.cpp.swscale.sws_scale(Lcom/googlecode/javacv/cpp/swscale$SwsContext;Lcom/googlecode/javacpp/PointerPointer;Lcom/googlecode/javacpp/IntPointer;IILcom/googlecode/javacpp/PointerPointer;Lcom/googlecode/javacpp/IntPointer;)I+0
j  com.googlecode.javacv.FFmpegFrameGrabber.processImage()V+189
j  com.googlecode.javacv.FFmpegFrameGrabber.grabFrame(ZZ)Lcom/googlecode/javacv/Frame;+228
j  com.googlecode.javacv.FFmpegFrameGrabber.grab()Lcom/googlecode/javacv/cpp/opencv_core$IplImage;+3
j  sun.reflect.GeneratedMethodAccessor9.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+36
J  sun.reflect.DelegatingMethodAccessorImpl.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;
J  java.lang.reflect.Method.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;
J  clojure.lang.Reflector.invokeMatchingMethod(Ljava/lang/String;Ljava/util/List;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;
J  clojure.lang.Reflector.invokeNoArgInstanceMember(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;
j  nest.system.wrappers.cores.video.javacv$grab.invoke(Ljava/lang/Object;)Ljava/lang/Object;+5
j  nest.system.wrappers.extensions.video.javacv.player$play$fn__13782.invoke(Ljava/lang/Object;)Ljava/lang/Object;+27
j  clojure.core$binding_conveyor_fn$fn__4107.invoke(Ljava/lang/Object;)Ljava/lang/Object;+17
J  clojure.lang.AFn.applyToHelper(Lclojure/lang/IFn;Lclojure/lang/ISeq;)Ljava/lang/Object;
j  clojure.lang.RestFn.applyTo(Lclojure/lang/ISeq;)Ljava/lang/Object;+23
j  clojure.lang.Agent$Action.doRun(Lclojure/lang/Agent$Action;)V+37
j  clojure.lang.Agent$Action.run()V+1
j  java.util.concurrent.ThreadPoolExecutor.runWorker(Ljava/util/concurrent/ThreadPoolExecutor$Worker;)V+95
j  java.util.concurrent.ThreadPoolExecutor$Worker.run()V+5
j  java.lang.Thread.run()V+11
v  ~StubRoutines::call_stub