From 21ad1f040873b55b8890819bdcb4c2a4f63da398 Mon Sep 17 00:00:00 2001 From: Dmitriy Gerashenko Date: Wed, 7 Jun 2017 17:43:47 +1000 Subject: [PATCH 1/7] FFmpegFrameGrabber's timeout for RTSP #711 --- samples/ConnectionIsLostDealing.java | 109 +++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 samples/ConnectionIsLostDealing.java diff --git a/samples/ConnectionIsLostDealing.java b/samples/ConnectionIsLostDealing.java new file mode 100644 index 00000000..f4cf2c39 --- /dev/null +++ b/samples/ConnectionIsLostDealing.java @@ -0,0 +1,109 @@ + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import org.bytedeco.javacpp.Pointer; +import org.bytedeco.javacpp.avformat; +import org.bytedeco.javacv.FFmpegFrameGrabber; +import org.bytedeco.javacv.Frame; +import org.bytedeco.javacv.FrameGrabber; + +/** + * + * @author Dmitriy Gerashenko + */ +public class ConnectionIsLostDealing { + + private static final String SOURCE = "rtsp://184.72.239.149/vod/mp4:BigBuckBunny_115k.mov"; + private static final int TIMEOUT = 10; // In seconds. + + public static void main(String[] args) { + testWithStimeoutOption(); // Right and simple way. + //testWithCallback(); // This is not working properly. It's just for test. + } + + private static void testWithStimeoutOption() { + System.out.println("testWithStimeoutOption called"); + try { + FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(SOURCE); + grabber.setOption("stimeout", String.valueOf(TIMEOUT * 1000000)); // In microseconds. + grabber.start(); + + Frame frame = null; + /** + * When network is disabled (before brabber was started) grabber + * throws exception: "org.bytedeco.javacv.FrameGrabber$Exception: + * avformat_open_input() error -138: Could not open input...". + * + * When connections is lost (after a few grabbed frames) + * grabber.grab() returns null without exception. + */ + while ((frame = grabber.grab()) != null) { + System.out.println("frame grabbed at " + grabber.getTimestamp()); + } + System.out.println("loop end with frame: " + frame); + } catch (FrameGrabber.Exception ex) { + System.out.println("exception: " + ex); + } + System.out.println("end"); + } + + private static void testWithCallback() { + System.out.println("testWithCallback called"); + try { + FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(SOURCE); + /** + * grabber.getFormatContext() is null before grabber.start(). + * + * But if network is disabled grabber.start() will never return. + * + * That's why interrupt_callback not suitable for "network disabled + * case". + */ + grabber.start(); + + final AtomicBoolean interruptFlag = new AtomicBoolean(false); + avformat.AVIOInterruptCB.Callback_Pointer CP = new avformat.AVIOInterruptCB.Callback_Pointer() { + @Override + public int call(Pointer pointer) { + // 0 - continue, 1 - exit + int interruptFlagInt = interruptFlag.get() ? 1 : 0; + System.out.println("callback, interrupt flag == " + interruptFlagInt); + return interruptFlagInt; + } + + }; + avformat.AVFormatContext oc = grabber.getFormatContext(); + avformat.avformat_alloc_context(); + avformat.AVIOInterruptCB cb = new avformat.AVIOInterruptCB(); + cb.callback(CP); + oc.interrupt_callback(cb); + new Thread(() -> { + try { + TimeUnit.SECONDS.sleep(TIMEOUT); + interruptFlag.set(true); + System.out.println("interrupt flag was changed"); + } catch (InterruptedException ex) { + System.out.println("exception in interruption thread: " + ex); + } + }).start(); + + Frame frame = null; + /** + * On one of my RTSP cams grabber stops calling callback on + * connection lost. I think it's has something to do with message: + * "[swscaler @ 0000000029af49e0] deprecated pixel format used, make + * sure you did set range correctly". + * + * So there is at least one case when grabber stops calling + * callback. + */ + while ((frame = grabber.grab()) != null) { + System.out.println("frame grabbed at " + grabber.getTimestamp()); + } + System.out.println("loop end with frame: " + frame); + } catch (FrameGrabber.Exception ex) { + System.out.println("exception: " + ex); + } + System.out.println("end"); + } +} From c26842a7999447bf55142e9467d5a4ba134bb9e6 Mon Sep 17 00:00:00 2001 From: Dmitriy Gerashenko Date: Wed, 7 Jun 2017 18:07:59 +1000 Subject: [PATCH 2/7] Update ConnectionIsLostDealing.java --- samples/ConnectionIsLostDealing.java | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/ConnectionIsLostDealing.java b/samples/ConnectionIsLostDealing.java index f4cf2c39..793da2c4 100644 --- a/samples/ConnectionIsLostDealing.java +++ b/samples/ConnectionIsLostDealing.java @@ -1,3 +1,4 @@ +package javacvtest; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; From efa03048c47e1b2f7fb4097ff205ab98abff7deb Mon Sep 17 00:00:00 2001 From: Dmitriy Gerashenko Date: Wed, 7 Jun 2017 18:13:34 +1000 Subject: [PATCH 3/7] Update ConnectionIsLostDealing.java --- samples/ConnectionIsLostDealing.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/samples/ConnectionIsLostDealing.java b/samples/ConnectionIsLostDealing.java index 793da2c4..3d0ab957 100644 --- a/samples/ConnectionIsLostDealing.java +++ b/samples/ConnectionIsLostDealing.java @@ -1,5 +1,3 @@ -package javacvtest; - import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.bytedeco.javacpp.Pointer; From 6b14bf3c7c7dafbf9c892d27e0628341bc834684 Mon Sep 17 00:00:00 2001 From: Dmitriy Gerashenko Date: Wed, 7 Jun 2017 21:17:34 +1000 Subject: [PATCH 4/7] Update and rename ConnectionIsLostDealing.java to RtspStreamingTimeout.java --- .../{ConnectionIsLostDealing.java => RtspStreamingTimeout.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename samples/{ConnectionIsLostDealing.java => RtspStreamingTimeout.java} (99%) diff --git a/samples/ConnectionIsLostDealing.java b/samples/RtspStreamingTimeout.java similarity index 99% rename from samples/ConnectionIsLostDealing.java rename to samples/RtspStreamingTimeout.java index 3d0ab957..39abb273 100644 --- a/samples/ConnectionIsLostDealing.java +++ b/samples/RtspStreamingTimeout.java @@ -10,7 +10,7 @@ * * @author Dmitriy Gerashenko */ -public class ConnectionIsLostDealing { +public class RtspStreamingTimeout { private static final String SOURCE = "rtsp://184.72.239.149/vod/mp4:BigBuckBunny_115k.mov"; private static final int TIMEOUT = 10; // In seconds. From cfa9243eaba68be1259a8183659288ef50b43a9a Mon Sep 17 00:00:00 2001 From: Dmitriy Gerashenko Date: Wed, 14 Jun 2017 17:23:18 +1000 Subject: [PATCH 5/7] Update RtspStreamingTimeout.java --- samples/RtspStreamingTimeout.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/samples/RtspStreamingTimeout.java b/samples/RtspStreamingTimeout.java index 39abb273..7d8834ee 100644 --- a/samples/RtspStreamingTimeout.java +++ b/samples/RtspStreamingTimeout.java @@ -1,3 +1,4 @@ + import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.bytedeco.javacpp.Pointer; @@ -24,6 +25,18 @@ private static void testWithStimeoutOption() { System.out.println("testWithStimeoutOption called"); try { FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(SOURCE); + /** + * "timeout" - IS IGNORED when a network cable have been unplugged + * before a connection and sometimes when connection is lost. + * + * "rw_timeout" (http://ffmpeg.org/ffmpeg-all.html#Protocols) - IS + * IGNORED when a network cable have been unplugged before a + * connection but the option takes effect after a connection was + * established. + * + * "stimeout" (http://ffmpeg.org/ffmpeg-all.html#rtsp) - socket TCP + * I/O timeout in microseconds for Real-Time Streaming Protocol. + */ grabber.setOption("stimeout", String.valueOf(TIMEOUT * 1000000)); // In microseconds. grabber.start(); From bf63a5fac1f50d39f045db366865e8a215fb4485 Mon Sep 17 00:00:00 2001 From: Dmitriy Gerashenko Date: Thu, 15 Jun 2017 12:14:17 +1000 Subject: [PATCH 6/7] Create FfmpegStreamingTimeout --- ...ingTimeout.java => FfmpegStreamingTimeout} | 70 ++++++++++++++----- 1 file changed, 52 insertions(+), 18 deletions(-) rename samples/{RtspStreamingTimeout.java => FfmpegStreamingTimeout} (70%) diff --git a/samples/RtspStreamingTimeout.java b/samples/FfmpegStreamingTimeout similarity index 70% rename from samples/RtspStreamingTimeout.java rename to samples/FfmpegStreamingTimeout index 7d8834ee..90d9b11e 100644 --- a/samples/RtspStreamingTimeout.java +++ b/samples/FfmpegStreamingTimeout @@ -11,33 +11,68 @@ * * @author Dmitriy Gerashenko */ -public class RtspStreamingTimeout { +public class FfmpegStreamingTimeout { - private static final String SOURCE = "rtsp://184.72.239.149/vod/mp4:BigBuckBunny_115k.mov"; + /** + * There is no universal option for streaming timeout. Each of protocols has + * its own list of options. + */ + private static enum TimeoutOption { + /** + * Depends on protocol. + * + * http://ffmpeg.org/ffmpeg-all.html + */ + TIMEOUT, + /** + * Protocols + * + * Maximum time to wait for (network) read/write operations to complete, + * in microseconds. + * + * http://ffmpeg.org/ffmpeg-all.html#Protocols + */ + RW_TIMEOUT, + /** + * Protocols -> RTSP + * + * Set socket TCP I/O timeout in microseconds. + * + * http://ffmpeg.org/ffmpeg-all.html#rtsp + */ + STIMEOUT; + + public String getKey() { + return toString().toLowerCase(); + } + + } + + private static final String SOURCE_RTSP = "rtsp://184.72.239.149/vod/mp4:BigBuckBunny_115k.mov"; private static final int TIMEOUT = 10; // In seconds. public static void main(String[] args) { - testWithStimeoutOption(); // Right and simple way. - //testWithCallback(); // This is not working properly. It's just for test. + rtspStreamingTest(); +// testWithCallback(); // This is not working properly. It's just for test. } - private static void testWithStimeoutOption() { - System.out.println("testWithStimeoutOption called"); + private static void rtspStreamingTest() { try { - FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(SOURCE); + FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(SOURCE_RTSP); /** * "timeout" - IS IGNORED when a network cable have been unplugged * before a connection and sometimes when connection is lost. * - * "rw_timeout" (http://ffmpeg.org/ffmpeg-all.html#Protocols) - IS - * IGNORED when a network cable have been unplugged before a - * connection but the option takes effect after a connection was - * established. + * "rw_timeout" - IS IGNORED when a network cable have been + * unplugged before a connection but the option takes effect after a + * connection was established. * - * "stimeout" (http://ffmpeg.org/ffmpeg-all.html#rtsp) - socket TCP - * I/O timeout in microseconds for Real-Time Streaming Protocol. + * "stimeout" - works fine. */ - grabber.setOption("stimeout", String.valueOf(TIMEOUT * 1000000)); // In microseconds. + grabber.setOption( + TimeoutOption.STIMEOUT.getKey(), + String.valueOf(TIMEOUT * 1000000) + ); // In microseconds. grabber.start(); Frame frame = null; @@ -60,9 +95,8 @@ private static void testWithStimeoutOption() { } private static void testWithCallback() { - System.out.println("testWithCallback called"); try { - FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(SOURCE); + FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(SOURCE_RTSP); /** * grabber.getFormatContext() is null before grabber.start(). * @@ -74,7 +108,7 @@ private static void testWithCallback() { grabber.start(); final AtomicBoolean interruptFlag = new AtomicBoolean(false); - avformat.AVIOInterruptCB.Callback_Pointer CP = new avformat.AVIOInterruptCB.Callback_Pointer() { + avformat.AVIOInterruptCB.Callback_Pointer cp = new avformat.AVIOInterruptCB.Callback_Pointer() { @Override public int call(Pointer pointer) { // 0 - continue, 1 - exit @@ -87,7 +121,7 @@ public int call(Pointer pointer) { avformat.AVFormatContext oc = grabber.getFormatContext(); avformat.avformat_alloc_context(); avformat.AVIOInterruptCB cb = new avformat.AVIOInterruptCB(); - cb.callback(CP); + cb.callback(cp); oc.interrupt_callback(cb); new Thread(() -> { try { From a7d7c2157073b83a4ea253fc5d0bc6e0dd378fbf Mon Sep 17 00:00:00 2001 From: Samuel Audet Date: Thu, 15 Jun 2017 12:09:25 +0900 Subject: [PATCH 7/7] Fix filename of FFmpegStreamingTimeout --- .../{FfmpegStreamingTimeout => FFmpegStreamingTimeout.java} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename samples/{FfmpegStreamingTimeout => FFmpegStreamingTimeout.java} (97%) diff --git a/samples/FfmpegStreamingTimeout b/samples/FFmpegStreamingTimeout.java similarity index 97% rename from samples/FfmpegStreamingTimeout rename to samples/FFmpegStreamingTimeout.java index 90d9b11e..eff08135 100644 --- a/samples/FfmpegStreamingTimeout +++ b/samples/FFmpegStreamingTimeout.java @@ -11,7 +11,7 @@ * * @author Dmitriy Gerashenko */ -public class FfmpegStreamingTimeout { +public class FFmpegStreamingTimeout { /** * There is no universal option for streaming timeout. Each of protocols has @@ -19,7 +19,7 @@ public class FfmpegStreamingTimeout { */ private static enum TimeoutOption { /** - * Depends on protocol. + * Depends on protocol (FTP, HTTP, RTMP, SMB, SSH, TCP, UDP, or UNIX). * * http://ffmpeg.org/ffmpeg-all.html */