Skip to content

Commit

Permalink
* Improve accuracy of FFmpegFrameGrabber.setFrameNumber() (pull #1851
Browse files Browse the repository at this point in the history
)
  • Loading branch information
anotherche authored Aug 2, 2022
1 parent 7ce2b98 commit bc1ea9d
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
12 changes: 12 additions & 0 deletions platform/src/test/java/org/bytedeco/javacv/FrameGrabberTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
9 changes: 4 additions & 5 deletions src/main/java/org/bytedeco/javacv/FFmpegFrameGrabber.java
Original file line number Diff line number Diff line change
Expand Up @@ -652,24 +652,23 @@ 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;
}

/** if there is video stream tries to seek to video frame with corresponding timestamp
* 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;
}

/** if there is audio stream tries to seek to audio frame with corresponding timestamp
* 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) */
Expand Down Expand Up @@ -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();
Expand Down

0 comments on commit bc1ea9d

Please sign in to comment.