Open jinl2011 opened 2 years ago
It looks like your calling the ffmpeg program? That's not under the control of JavaCV. It's something wrong with FFmpeg itself.
yes i calling the ffmpeg for thumbnail
tell me what can i do
It depends, for example, it looks like that can happen with the "split" filter: https://stackoverflow.com/questions/66724106/how-can-i-avoid-an-ffmpeg-out-of-memory-error Are you using the split filter? If not, look for other more similar issues: https://www.google.com/search?client=firefox-b-d&q=ffmpeg+%22killed+process%22
ok i know, but i want my application is stable. so i think, before my code use javacv, my code find the linux os remain memory, if enough code continue, if not enough code throw exception. to protect my application. do you think?
Since the ffmpeg program runs in another process, it cannot crash your Java application. It's already doing what you need it to do.
i use java, pom.xml dependency javacv1.5.7 the same process.
Then you should use the ffmpeg program, that's fine. What's the question? If you expect an answer, you'll need to ask a question.
how-can-i-avoid-an-ffmpeg-out-of-memory-error in my jvm process ??
Like I keep telling you, you'll either need to fix whatever is wrong with the code of ffmpeg, or you'll need to run the bad code as part of another process, for example, using the ffmpeg program. There is no other option! Please explain what you do not understand.
in my jvm process, when i use javacv( javacv use ffmpeg), jvm direct memory is bigger and bigger, in the end, jvm was killed by linux os.
Like I keep telling you, if you want someone to look at your code for bugs, you'll need to at least provide the code. I cannot tell you what is wrong with your code if I cannot see your code. Do you understand?
yes, i know you tell, but i hava to use same process.
can you speak chiness??
我明白你说的意思,但是,我目前必须要在一个进程内去使用javacv
import it.sauronsoftware.jave.Encoder; import it.sauronsoftware.jave.MultimediaInfo; import it.sauronsoftware.jave.Encoder; import it.sauronsoftware.jave.MultimediaInfo; import lombok.Cleanup; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.bytedeco.javacv.FFmpegFrameGrabber; import org.bytedeco.javacv.Frame; import org.bytedeco.javacv.Java2DFrameConverter; import org.bytedeco.javacv.OpenCVFrameConverter; import org.bytedeco.opencv.global.opencv_core; import org.bytedeco.opencv.opencv_core.IplImage; import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO; import javax.imageio.stream.ImageOutputStream; import java.awt.image.BufferedImage; import java.io.*; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List;
@Component @Slf4j @RequiredArgsConstructor public class VideoImageUtils {
/**
* 获取指定视频的帧并保存为图片至指定目录
* @param inputStream 源视频文件输入流
* @throws Exception
* @throws IOException
*/
public static byte[] fetchFrame(InputStream inputStream) throws Exception, IOException {
if (!(inputStream instanceof FileInputStream)) {
log.info("不支持的流类型");
return null;
}
Field pathField = inputStream.getClass().getDeclaredField("path");
if (!pathField.isAccessible()) {
pathField.setAccessible(true);
}
String tmpFilePath = pathField.get(inputStream).toString();
//重新构建一个File对象,FFmpegFrameGrabber的构造函数使用FileInputStream作为参数会报错
File tmpFile = new File(tmpFilePath);
@Cleanup
FFmpegFrameGrabber ff = new FFmpegFrameGrabber(tmpFile);
ff.start();
ff.getAudioChannels();
//视频的旋转角度
String rotate = ff.getVideoMetadata("rotate");
int length = ff.getLengthInFrames();
int i = 0;
Frame f;
while (i < length) {
f = ff.grabFrame();
if (i > 500) {
break;
}
if (f.image != null) {
IplImage src = null;
if(null != rotate && rotate.length() > 1) {
@Cleanup
OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
src = converter.convert(f);
f = converter.convert(rotate(src, Integer.parseInt(rotate)));
}
if (src != null) {
src.close();
src = null;
}
return doExecuteFrame(f);
}
i++;
}
ff.stop();
ff = null;
return null;
}
public static byte[] fetchFrame(String filePath) throws Exception, IOException {
File tmpFile = new File(filePath);
@Cleanup
FFmpegFrameGrabber ff = new FFmpegFrameGrabber(tmpFile);
ff.start();
ff.getAudioChannels();
//视频的旋转角度
String rotate = ff.getVideoMetadata("rotate");
int length = ff.getLengthInFrames();
int i = 0;
Frame f;
while (i < length) {
f = ff.grabFrame();
if (i > 500) {
break;
}
if (f.image != null) {
IplImage src = null;
if(null != rotate && rotate.length() > 1) {
@Cleanup
OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
src = converter.convert(f);
f = converter.convert(rotate(src, Integer.parseInt(rotate)));
}
if (src != null) {
src.close();
src = null;
}
return doExecuteFrame(f);
}
i++;
}
ff.stop();
ff = null;
return null;
}
public static void main(String[] args) throws Exception{
for (int i =0; i<10000;i++){
String filePath = "D:\\迅雷下载\\";
// test - 副本 (15) filePath += "test - 副本 ("+(i%19)+").mp4"; byte[] bytes = fetchFrame(filePath); byteToFile(bytes, "D:\迅雷下载\image\test"+i+".png"); System.out.println("==============================================="+i); // Thread.sleep(5000); // if (i%20==0){ // System.gc(); // } } }
public static void byteToFile(byte[] contents, String filePath) throws Exception{
BufferedInputStream bis = null;
FileOutputStream fos = null;
BufferedOutputStream output = null;
ByteArrayInputStream byteInputStream = null;
try {
byteInputStream = new ByteArrayInputStream(contents);
bis = new BufferedInputStream(byteInputStream);
File file = new File(filePath);
// 获取文件的父路径字符串
File path = file.getParentFile();
if (!path.exists()) {
boolean isCreated = path.mkdirs();
if (!isCreated) {
System.out.println("==========> create Fail");
}
}
fos = new FileOutputStream(file);
// 实例化OutputString 对象
output = new BufferedOutputStream(fos);
byte[] buffer = new byte[1024];
int length = bis.read(buffer);
while (length != -1) {
output.write(buffer, 0, length);
length = bis.read(buffer);
}
output.flush();
} catch (Exception e) {
System.out.println("==========> create Fail");
throw e;
} finally {
try {
byteInputStream.close();
bis.close();
fos.close();
output.close();
} catch (IOException e) {
System.out.println("==========> create Fail");
throw e;
}
}
}
public static IplImage rotate(IplImage src, int angle) {
IplImage img = IplImage.create(src.height(),src.width(),src.depth(),src.nChannels());
opencv_core.cvTranspose(src,img);
opencv_core.cvFlip(img,img,angle);
return img;
}
public static byte [] doExecuteFrame(Frame f) {
if (null == f || null == f.image) {
return null;
}
@Cleanup
Java2DFrameConverter converter = new Java2DFrameConverter();
BufferedImage bufferedImage = converter.getBufferedImage(f);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
ImageIO.write(bufferedImage,"png", byteArrayOutputStream);
} catch (IOException e) {
log.error("视频缩略图生成失败", e);
byteArrayOutputStream = null;
} finally {
if (bufferedImage != null) {
bufferedImage.flush();
bufferedImage.getGraphics().dispose();
}
f.close();
f = null;
converter = null;
}
if (byteArrayOutputStream == null) {
return null;
}
return byteArrayOutputStream.toByteArray();
}
}
You're not calling converter.close()
anywhere, that can leak memory.
My fundamental desire is to control how the JVM processes use out-of-heap memory.
If you're talking about a tool like JavaCPP, that's explained here: http://bytedeco.org/news/2018/07/17/bytedeco-as-distribution/
when i use javacv, direct memory overflow, linux os kill my process. so i want to know , i can ensure direct memory not overflow??