Closed zoooooway closed 1 month ago
These are dependent information:
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacpp</artifactId>
<version>1.4.3</version>
</dependency>
<dependency>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>ffmpeg-platform</artifactId>
<version>4.0.2-1.4.3</version>
</dependency>
You'll need to pass something else than null to avformat_find_stream_info()...
avformat_find_stream_info
second parameter can be null. it is okay. (See link)
I think problem is AVFormatContext pFormatCtx = new AVFormatContext(null);
under getFormatContext
method.
use instead AVFormatContext pFormatCtx = avformat_alloc_context();
(new AVFormatContext(null)
mean is "Casting null to AVFormatContext". See link)
You'll need to pass something else than null to avformat_find_stream_info()...
Hello, thank you for your reply. According to your prompt, I guess that there may be problems with some urls that cause problems with the AVFormatContext
obtained after executing avformat_open_input(pFormatCtx, url, null, options)
, because not every url will let The jvm crashes, it can work normally when some URLs execute this program and return screenshots. So I tried to perform some non-null judgments on the internal data of pFormatCtx
before executing avformat_find_stream_info(pFormatCtx, (PointerPointer<Pointer>) null)
, but it didn't seem to work. So I would like to ask if there is any way for me to safely execute avformat_find_stream_info(pFormatCtx, (PointerPointer<Pointer>) null)
, or terminate it when an error is foreseen, to prevent jvm from crashing. Thank you again for your help.
avformat_find_stream_info
second parameter can be null. it is okay. (See link)I think problem is
AVFormatContext pFormatCtx = new AVFormatContext(null);
undergetFormatContext
method.use instead
AVFormatContext pFormatCtx = avformat_alloc_context();
(new AVFormatContext(null)
mean is "Casting null to AVFormatContext". See link)
Hello, thank you for your reply, I replaced the constructor with the constructor as you said. But now av_dict_set(options, "rtsp_transport", "tcp", 0)
does not work properly and crashes the virtual machine.
AVFormatContext pFormatCtx = avformat_alloc_context();
AVDictionary options = new AVDictionary(pFormatCtx);
av_dict_set(options, "rtsp_transport", "tcp", 0);
if (avformat_open_input(pFormatCtx, url, null, options) != 0) {
return null;
}
I need this function to set options, so can you please tell me how to do it? Thank you again for your help.
Use like this
AVFormatContext pFormatCtx = avformat_alloc_context();
AVDictionary options = new AVDictionary();
av_dict_set(options, "rtsp_transport", "tcp", 0);
if (avformat_open_input(pFormatCtx, url, null, options) != 0) {
return null;
}
Please test it and let me know the result
Your first code is strange, but it is no problem in working. (When AVFormatContext points to NULL, ffmpeg allocates it.)
AVFormatContext pFormatCtx = new AVFormatContext(null);
AVDictionary options = new AVDictionary(pFormatCtx);
But this code is more standard code.
AVFormatContext pFormatCtx = avformat_alloc_context();
AVDictionary options = new AVDictionary();
I'm tested using your code snippet. like this
public static void main(String[] args) throws IOException, InterruptedException {
Stream2Image stream2Image = new Stream2Image();
for (int i = 0; i < 100000; i++) {
stream2Image.safeOpenMediaAndSaveImage("test" + (i % 10) + ".mp4", "test/snap_" + i + ".png");
}
}
JVM doesn't crash. It looks like we need more information about error URL or video binary.
Your first code is strange, but it is no problem in working. (When AVFormatContext points to NULL, ffmpeg allocates it.)
AVFormatContext pFormatCtx = new AVFormatContext(null); AVDictionary options = new AVDictionary(pFormatCtx);
But this code is more standard code.
AVFormatContext pFormatCtx = avformat_alloc_context(); AVDictionary options = new AVDictionary();
I'm tested using your code snippet. like this
public static void main(String[] args) throws IOException, InterruptedException { Stream2Image stream2Image = new Stream2Image(); for (int i = 0; i < 100000; i++) { stream2Image.safeOpenMediaAndSaveImage("test" + (i % 10) + ".mp4", "test/snap_" + i + ".png"); } }
JVM doesn't crash. It looks like we need more information about error URL or video binary.
Hello, sorry for the late reply, thank you very much for everything. As you said, I use
AVFormatContext pFormatCtx = avformat_alloc_context();
AVDictionary options = new AVDictionary();
av_dict_set(options, "rtsp_transport", "tcp", 0);
if (avformat_open_input(pFormatCtx, url, null, options) != 0) {
return null;
}
It can work normally. However, during the running of the program, there will still be the previous situation: jvm crashes when executing avformat_find_stream_info()
.
Since the program is deployed on a special server, and only this server can access the URLs from another streaming media server and fetch frames and convert them into pictures, I cannot debug locally to find out which URL is causing the crash.
This troubles me a lot. Due to these limitations, I wonder if there is a way to execute avformat_find_stream_info()
safely, such as a comprehensive parameter check before execution, and if the necessary conditions are missing, the program will not be executed to prevent jvm collapse. If you have any suggestions, please let me know and I will continue to try to change the program.
Thank you again for your help.
I can't say that the avformat_find_stream_info
function is the problem. because the avformat_find_stream_info
function is implemented to return an error code in case of an error.
In general, it is possible that the JVM crashed is a memory corruption. So, "parameter check for execute safely" is meaningless because maybe the FFmpeg memory is already corrupted.
RTSP/LocalFile stream can be received without calling the avformat_find_stream_info
function. Comment out the avformat_find_stream_info
call and test it.
@hzw133 Do you get any crashes with FFmpegFrameGrabber?
I can't say that the
avformat_find_stream_info
function is the problem. because theavformat_find_stream_info
function is implemented to return an error code in case of an error.In general, it is possible that the JVM crashed is a memory corruption. So, "parameter check for execute safely" is meaningless because maybe the FFmpeg memory is already corrupted.
RTSP/LocalFile stream can be received without calling the
avformat_find_stream_info
function. Comment out theavformat_find_stream_info
call and test it.
It succeeded. After skipping the avformat_find_stream_info()
function, I waited for the program to execute for a while, and the jvm didn't crash anymore (usually it would crash after five to twenty minutes of program execution). Fortunately, the streams I need to process are all RTSP protocols, so I think this solution is effective. thank you for your help.
For me, this problem may not be over. I need to handle streams of other protocols in this way in other programs, but it may not be possible to skip the avformat_find_stream_info()
function at that time. But now this problem has come to an end, and I will observe whether there will be a crash in the subsequent processing of other agreements.
Thank you again and Saudet for your help. This is the first time I asked a question on github. You guys really helped me a lot.
@hzw133 Do you get any crashes with FFmpegFrameGrabber?
@hzw133 Do you get any crashes with FFmpegFrameGrabber?
It also crashes when I use FFmpegFrameGrabber. At first I used javacv to complete my work, but then the business became simpler, so I switched to javacpp to perform these operations. When I use FFmpegFrameGrabber to perform these operations, the same crash message still appears, but the frequency of crashes is not high. At that time, I didn't go deep into it but switched to javacpp, so I didn't know what the cause of the crash was at that time.
Due to some restrictions, I still don't know the cause of the crash when using javacpp, but according to @devjeonghwan's suggestion I can skip avformat_find_stream_info()
to avoid the crash. I will continue to try to find out the reason if I have the opportunity in the follow-up. If I find anything, I will report it to you.
Hope I didn't bother you too much, thank you very much for your help and @devjeonghwan , and the framework you provided us.
Maybe crash frequency may have been reduced(solved the fundamentally error?). Use the standard usage of ffmpeg(standard way to create and release resources.)
hi @saudet @devjeonghwan ,first of all, thank you for your help last time. I'm sorry I'm back again. Now I have a new problem. The program code shown above will get an error after running for a long time:
2021-10-16 16:10:32.551 [TaskSchedulerThreadPool-1234] ERROR o.s.s.support.TaskUtils$LoggingErrorHandler:96 - Unexpected error occurred in scheduled task.
java.lang.OutOfMemoryError: Physical memory usage is too high: physicalBytes (54635M) > maxPhysicalBytes (54610M)
at org.bytedeco.javacpp.Pointer.deallocator(Pointer.java:584)
at org.bytedeco.javacpp.Pointer.init(Pointer.java:124)
at org.bytedeco.javacpp.avcodec$AVPacket.allocate(Native Method)
at org.bytedeco.javacpp.avcodec$AVPacket.<init>(avcodec.java:1516)
at com.analysis.util.Stream2Image.getSingleFrame(Stream2Image.java:299)
at com.analysis.util.Stream2Image.safeOpenMediaAndSaveImage(Stream2Image.java:151)
at com.analysis.service.impl.GrabberServiceImpl.grabOne(GrabberServiceImpl.java:92)
at com.analysis.task.util.GrabUtil.grabAndSave(GrabUtil.java:204)
at com.analysis.task.util.GrabUtil.longDiffTask(GrabUtil.java:187)
at com.analysis.task.util.GrabUtil.lambda$creatCronTask$0(GrabUtil.java:102)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:93)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
I found similar errors in other issues, so I tried to use pointerscope to solve the problem of memory growth, but it didn't seem to work. In my test code, I found that the memory was still growing slowly every time my code was executed:
try (PointerScope pointerScope = new PointerScope()) {
safeOpenMediaAndSaveImage(url, outFile);
}
log.info("physicalBytes:{}; totalBytes:{}", Pointer.physicalBytes(), Pointer.totalBytes());
....
physicalBytes:236363776; totalBytes:9504
physicalBytes:236478464; totalBytes:9936
physicalBytes:236498944; totalBytes:10368
....
After calling System.gc() manually, totalBytes no longer increases, but physicalBytes still increases after each execution, and the following is the increase of half an hour:
physicalBytes:236498944
....
physicalBytes:259645440
...
physicalBytes:261640192
...
physicalBytes:274259968
...
physicalBytes:331444224
So, is there something missing from my code? I guess my memory release related operation is not perfect, but I don't know what the problem is. I hope you can give me some suggestions.
Thank you.
FFmpeg is a C API, and it's quite tricky to deallocate everything properly. You'll need to read the API docs very carefully.
FFmpeg is a C API, and it's quite tricky to deallocate everything properly. You'll need to read the API docs very carefully.
This is not easy for me, but I will try my best to read it, thank you for your suggestion.
FFmpeg is a C API, and it's quite tricky to deallocate everything properly. You'll need to read the API docs very carefully.
This is not easy for me, but I will try my best to read it, thank you for your suggestion.
I found one problem usage in your getSingleFrame
method.
private AVFrame getSingleFrame(AVCodecContext pCodecCtx, AVFormatContext pFormatCtx, int videoStreamIndex) {
...
AVPacket packet = new AVPacket();
try {
while (av_read_frame(pFormatCtx, packet) >= 0) {
if (packet.stream_index() == videoStreamIndex) {
avcodec_decode_video2(pCodecCtx, pFrame, frameFinished, packet);
if (frameFinished != null && frameFinished[0] != 0 && !pFrame.isNull()) {
exists = true;
break;
}
}
}
} finally {
av_packet_unref(packet);
}
return exists ? pFrame : null;
}
private AVFrame getSingleFrame(AVCodecContext pCodecCtx, AVFormatContext pFormatCtx, int videoStreamIndex) {
...
AVPacket packet = av_packet_alloc();
av_init_packet(packet);
try {
while (av_read_frame(pFormatCtx, packet) >= 0) {
try {
if (packet.stream_index() == videoStreamIndex) {
avcodec_decode_video2(pCodecCtx, pFrame, frameFinished, packet);
if (frameFinished != null && frameFinished[0] != 0 && !pFrame.isNull()) {
exists = true;
break;
}
}
} finally {
av_packet_unref(packet);
}
}
} finally {
av_packet_unref(packet);
av_packet_free(packet);
}
return exists ? pFrame : null;
}
But, I can't go through all the code. Read the FFmpeg API Doc carefully. (Correct objects allocate way and correct timing or way of deallocate)
hi, @devjeonghwan. I’m sorry it took me so long to respond. First of all, thank you for taking the time to help me. I fixed the problem you pointed out and tried to run it for a while. Unfortunately, memory is still growing slowly. But this points out some of the irregularities in my use of FFMEP, and I want to first try to replace some outdated apis and more debugging to see the details of the memory increase. Thank you so much for your advice. If you have any further suggestions, please let me know. By the way, I think the learning of FFMEP is really hard, which makes me think you are really strong.
Hello, sorry for taking up your time. I have a question to ask you. My English is not very good, so these words are translated using translation software. I need to use javacpp to open a media URL every time and take a screenshot and save the picture. Since there are multiple URLs, I use a timed task to operate each stream individually. The main code is as follows,:
But every time (not more than 20 minutes), jvm will crash, the log is as follows:
Unfortunately, I'm a novice and don't know C and C + +. I really want to know what the problem is. I hope someone can help me, because I've tried many ways, but I still can't solve it. Thank you very much.