From bc1ea9d3c97839703b1b12d885e755794e583d5c Mon Sep 17 00:00:00 2001 From: Stanislav Chizhik Date: Tue, 2 Aug 2022 13:48:57 +0700 Subject: [PATCH] * Improve accuracy of `FFmpegFrameGrabber.setFrameNumber()` (pull #1851) --- CHANGELOG.md | 1 + .../java/org/bytedeco/javacv/FrameGrabberTest.java | 12 ++++++++++++ .../java/org/bytedeco/javacv/FFmpegFrameGrabber.java | 9 ++++----- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 182d02c6..2d43ef29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ + * Improve accuracy of `FFmpegFrameGrabber.setFrameNumber()` ([pull #1851](https://github.com/bytedeco/javacv/pull/1851)) * Add `FrameGrabber.resetStartTime()` to allow `grabAtFrameRate()` after operations such as seeking ([pull #1846](https://github.com/bytedeco/javacv/pull/1846)) * Add `FrameGrabber.videoSideData/audioSideData` properties and `FFmpegFrameGrabber.getDisplayRotation()` for convenience ([issue #1361](https://github.com/bytedeco/javacv/issues/1361)) * Add to `FFmpegFrameGrabber` and `FFmpegFrameRecorder` constructors taking a `URL` for convenience and clarity diff --git a/platform/src/test/java/org/bytedeco/javacv/FrameGrabberTest.java b/platform/src/test/java/org/bytedeco/javacv/FrameGrabberTest.java index b4f40691..d3d1e3ac 100644 --- a/platform/src/test/java/org/bytedeco/javacv/FrameGrabberTest.java +++ b/platform/src/test/java/org/bytedeco/javacv/FrameGrabberTest.java @@ -409,6 +409,7 @@ public void testFFmpegFrameGrabberSeeking() throws IOException { assertTrue(frame.image != null ^ frame.samples != null); System.out.println(timestamp2 + " - " + timestamp + " = " + delta + " type: " + frame.getTypes()); assertTrue(Math.abs(delta) < tolerance); + /* if (seektestnum==0) { boolean wasVideo = frame.image != null; boolean wasAudio = frame.samples != null; @@ -423,12 +424,23 @@ public void testFFmpegFrameGrabberSeeking() throws IOException { System.out.println(timestamp3 + " - " + timestamp + " = " + (timestamp3 - timestamp)); assertTrue(timestamp3 >= timestamp - tolerance && timestamp3 < timestamp + tolerance); } + */ } System.out.println(); System.out.println("------------------------------------"); System.out.println("delta from " + mindelta + " to " + maxdelta); System.out.println(); } + if (seektestnum==0) { + System.out.println(); + System.out.println("======== Check sequential setVideoFrameNumber (issue #1697) ========"); + for (int i = 0; i < 10; i++) { + grabber.setVideoFrameNumber(i); + long timestamp = grabber.grabImage().timestamp; + System.out.println("frame number:" + i + " timestamp:" + timestamp); + assertTrue(i == Math.round(timestamp * grabber.getFrameRate() / 1000000L)); + } + } if (seektestnum==2) { long count1 = 0; diff --git a/src/main/java/org/bytedeco/javacv/FFmpegFrameGrabber.java b/src/main/java/org/bytedeco/javacv/FFmpegFrameGrabber.java index e154cb41..e921a12d 100644 --- a/src/main/java/org/bytedeco/javacv/FFmpegFrameGrabber.java +++ b/src/main/java/org/bytedeco/javacv/FFmpegFrameGrabber.java @@ -652,7 +652,7 @@ public double getDisplayRotation() { /** default override of super.setFrameNumber implies setting * of a frame close to a video frame having that number */ @Override public void setFrameNumber(int frameNumber) throws Exception { - if (hasVideo()) setTimestamp((long)Math.floor(1000000L * frameNumber / getFrameRate())); + if (hasVideo()) setTimestamp(Math.round((1000000L * frameNumber + 500000L)/ getFrameRate())); else super.frameNumber = frameNumber; } @@ -660,7 +660,7 @@ public double getDisplayRotation() { * otherwise sets super.frameNumber only because frameRate==0 if there is no video stream */ public void setVideoFrameNumber(int frameNumber) throws Exception { // best guess, AVSEEK_FLAG_FRAME has not been implemented in FFmpeg... - if (hasVideo()) setVideoTimestamp((long)Math.floor(1000000L * frameNumber / getFrameRate())); + if (hasVideo()) setVideoTimestamp(Math.round((1000000L * frameNumber + 500000L)/ getFrameRate())); else super.frameNumber = frameNumber; } @@ -668,8 +668,7 @@ public void setVideoFrameNumber(int frameNumber) throws Exception { * ignoring otherwise */ public void setAudioFrameNumber(int frameNumber) throws Exception { // best guess, AVSEEK_FLAG_FRAME has not been implemented in FFmpeg... - if (hasAudio()) setAudioTimestamp((long)Math.floor(1000000L * frameNumber / getAudioFrameRate())); - + if (hasAudio()) setAudioTimestamp(Math.round((1000000L * frameNumber + 500000L)/ getAudioFrameRate())); } /** setTimestamp without checking frame content (using old code used in JavaCV versions prior to 1.4.1) */ @@ -1464,7 +1463,7 @@ public synchronized Frame grabFrame(boolean doAudio, boolean doVideo, boolean do AVRational time_base = video_st.time_base(); timestamp = 1000000L * pts * time_base.num() / time_base.den(); // best guess, AVCodecContext.frame_number = number of decoded frames... - frameNumber = (int)Math.floor(timestamp * getFrameRate() / 1000000L); + frameNumber = (int)Math.round(timestamp * getFrameRate() / 1000000L); frame.image = image_buf; if (doProcessing) { processImage();