Closed MachineIntelligence6 closed 7 years ago
Thank you i have tried the fix, but still getting the same problem. before stopping the grabber, i get an exception in the catch block.
java.lang.IllegalArgumentException at java.nio.Buffer.limit(Buffer.java:275) at org.bytedeco.javacv.FFmpegFrameGrabber.processImage(FFmpegFrameGrabber.java:776) at org.bytedeco.javacv.FFmpegFrameGrabber.grabFrame(FFmpegFrameGrabber.java:945) at com.msv.util.FrameCreator.run(FrameCreator.java:90) at java.lang.Thread.run(Thread.java:745)
after that in the final block in my code , i stop the grabber, and app crashes. if i didn't get the above exception, then it works fine, with multi threaded code also.
Sounds like there is a race condition somewhere in your code then.
I'm copying the sample of my code. Our goal is the app should not crash for any reason, it should catch the exception. Thank you for your support. 🥇
package com.video.util;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.WritableRaster;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.bytedeco.javacpp.avutil;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import com.video.MainWindow;
import com.video.controls.CheckVideoIntegrete;
import com.video.model.Video;
import com.video.util.VideoThumbnailsCreator.ThumbnailListener;
public class FrameCreator implements Runnable {
private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(FrameCreator.class);
private final Video input;
private final ThumbnailListener listener;
private final AtomicBoolean interrupted;
private boolean grabSecondOnly=true;
private long predefinedLen=0;
boolean bySeconds;
private FFmpegFrameGrabber grabber=null;
private long gap;
public FrameCreator(Video input, ThumbnailListener listener, MainWindow vcjMain, AtomicBoolean interrupted,boolean bySeconds) {
this.input = input;
this.listener = listener;
this.interrupted = interrupted;
this.bySeconds=bySeconds;
}
public void setLength(long length){
predefinedLen = length;
}
@Override
public void run() {
avutil.av_log_set_level(avutil.AV_LOG_QUIET);
grabber = new FFmpegFrameGrabber(input.getFile());
grabber.setOption("max_nal_size", "1024");
try {
grabber.start();
//if(!CheckVideoIntegrete.check(input))
//throw new Exception("Video is Corrpt");
long totalTime = grabber.getLengthInTime();
listener.obtainVideoLength(this,formatFrameTime(totalTime / 1000));
if(predefinedLen>0) totalTime=predefinedLen*1000;
long totalSecond = totalTime / 1000000;
long totalFrame;
if(!bySeconds){
totalFrame = (MainWindow.getSettings().getFrameNumber()+1);
if (grabSecondOnly && totalFrame > totalSecond) {
totalFrame = (int) totalSecond;
}
gap = (totalTime / totalFrame);
if (gap == 0) {
gap++;
}
} else {
gap = (MainWindow.getSettings().getFrameNumber())*1000000;
if(gap<=0) gap=1000000;
totalFrame = totalTime / gap;
}
Java2DFrameConverter converter = new Java2DFrameConverter();
long timestamp;
long realtime;
Frame frame=null;
int countErrors=bySeconds?0:10;
for (int i = 0; i < totalFrame || countErrors<10; i++) {
if(interrupted.get()) {break;}
timestamp=1+i*gap;
if (!bySeconds && timestamp > totalTime) break;
try {
grabber.setTimestamp(timestamp);
realtime = timestamp;
while(realtime<timestamp+gap){
frame = grabber.grabFrame(false,true,false,false);
frame = grabber.grabFrame(false,true,true,false);
realtime = grabber.getTimestamp();
if(frame==null || frame.image!=null) break;
}
if (frame != null && frame.image!=null && realtime!=0) {
listener.thumbnailCreated(this,null, realtime / 1000, i+1,
deepCopy(converter.convert(frame)),(int)totalFrame);
listener.updateProgress(this,i+1, totalSecond,(int)totalFrame);
} else {
log.error("grab error at "+timestamp);
if(bySeconds && timestamp>totalTime) countErrors++;
}
} catch (java.lang.Exception e) {
log.error("grab error at "+timestamp+ " "+e.getMessage());
log.trace("",e);
e.printStackTrace();
}
}
} catch (Exception e) {
listener.onUnsupportedVideo(this);
log.error("Error load video grabber "+e.getMessage());
log.trace("",e);
} finally {
if(grabber!=null) try {grabber.stop();} catch (Exception e) {e.printStackTrace();}
grabber = null;
listener.onFinish(this);
}
}
private static String formatFrameTime(long totalTime) {
return String.format(
"%02d:%02d:%02d",
TimeUnit.MILLISECONDS.toHours(totalTime),
TimeUnit.MILLISECONDS.toMinutes(totalTime)
- TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(totalTime)),
TimeUnit.MILLISECONDS.toSeconds(totalTime)
- TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(totalTime)));
}
public static BufferedImage deepCopy(BufferedImage o) {
ColorModel cm = o.getColorModel();
boolean isAlpha = o.isAlphaPremultiplied();
WritableRaster r = o.copyData(null);
return new BufferedImage(cm, r, isAlpha, null);
}
public boolean isGrabSecondOnly() {
return grabSecondOnly;
}
public void setGrabSecondOnly(boolean grabSecondOnly) {
this.grabSecondOnly = grabSecondOnly;
}
}
`
So, the same grabber never gets used by more than one thread?
Yes, that's why we have to stop the grabber, when the thread is finish. in the final block.
Does it also happen with only one thread?
yes currently the video crash with only one thread. We know the video is corrupt. Im testing the code with only one video. and it crash.
Oh, then it's a bug in FFmpeg probably. Try FFmpeg 3.3.2 see if it's fixed.
let me check it, i will get back shortly, after testing it with 3.3.2
I have downloaded the javacpp-presets-platform-1.3-bin.zip (516 MB) ans use the ffmpeg from it, here is the link from which i download https://github.com/bytedeco/javacpp-presets. or i have to build the src from this link https://github.com/bytedeco/javacpp-presets/tree/master/ffmpeg? I use the javacpp-presets and replace the jars with them, but still getting the same crash. I really appreciated your support. Thanks once again.
Try the SNAPSHOT version: https://github.com/bytedeco/javacpp-presets/tree/master/ffmpeg#the-pomxml-build-file
If you prefer to replace the JAR files manually, we can download them from the browser here: https://oss.sonatype.org/content/repositories/snapshots/org/bytedeco/javacpp-presets/ffmpeg/3.3.2-1.3.3-SNAPSHOT/
In the end, were you able to reproduce this issue with FFmpeg 3.3.2?
Yes, In my testing I found out the problem in grabber.setTimestamp(timestamp);
setTimestamp() method in your code has two while loops inside it, I was seeking frame by mouse movements, I check when I move forward and then seek frame backward, it remain in the while and never get out for some corrupt videos and hangs my app.
I remove the code for while loop in setTimestamp() method, and it start working, but then I found out that for some videos the frame I was grabbing was for wrong timestamp.
so again I uncomment the code for while loop and but put a fix for it that it remain in the loop for not more then 10 times.
Sounds good, could you send a pull request? And maybe we can even make the limit 100 or 1000? Thanks for the feedback!
Hi Im using JavaCV to GrabFrames from Videos, The process is multiThreaded and work fine, but one the video is crash the app when i stop the grabber. Im using JavaCV 1.3.2 Here is sample of my code and the exception.
****Exception ***