Skip to content

Commit

Permalink
Update CHANGELOG.md and fix nits
Browse files Browse the repository at this point in the history
  • Loading branch information
saudet committed Dec 23, 2023
1 parent 17f3546 commit 7ae68f4
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 17 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@

* Improve `FFmpegFrameGrabber.setTimestamp()` further for MPEG-TS streams ([pull #2144](https://github.com/bytedeco/javacv/pull/2144))
* Fix `module-info.java` broken since last release ([issue bytedeco/javacpp-presets#1414](https://github.com/bytedeco/javacpp-presets/issues/1414))
* Add new `AudioSplitMergeHelper` sample for processing raw audio frames ([pull #2052](https://github.com/bytedeco/javacv/pull/2052))
* Upgrade dependencies for OpenBLAS 0.3.24, OpenCV 4.8.1, FFmpeg 6.1, Leptonica 1.83.1, Tesseract 5.3.3
Expand Down
30 changes: 13 additions & 17 deletions src/main/java/org/bytedeco/javacv/FFmpegFrameGrabber.java
Original file line number Diff line number Diff line change
Expand Up @@ -721,9 +721,8 @@ private synchronized void setTimestamp(long timestamp, EnumSet<Frame.Type> frame
timestamp = timestamp * AV_TIME_BASE / 1000000L;

/* the stream start time */
long ts0 = 0;
if (oc.start_time() != AV_NOPTS_VALUE) ts0 = oc.start_time();

long ts0 = oc.start_time() != AV_NOPTS_VALUE ? oc.start_time() : 0;

if (frameTypesToSeek != null //new code providing check of frame content while seeking to the timestamp
&& (frameTypesToSeek.contains(Frame.Type.VIDEO) || frameTypesToSeek.contains(Frame.Type.AUDIO))
&& (hasVideo() || hasAudio())) {
Expand All @@ -743,12 +742,12 @@ private synchronized void setTimestamp(long timestamp, EnumSet<Frame.Type> frame
* The setting means only a preference in the type. That is, if VIDEO or AUDIO is
* specified but the file does not have video or audio stream - any type will be used instead.
*/

/* Check if file contains requested streams */
if ((frameTypesToSeek.contains(Frame.Type.VIDEO) && !hasVideo() ) ||
(frameTypesToSeek.contains(Frame.Type.AUDIO) && !hasAudio() ))
frameTypesToSeek = EnumSet.of(Frame.Type.VIDEO, Frame.Type.AUDIO);

/* If frameTypesToSeek is set explicitly to VIDEO or AUDIO
* we need to use start time of the corresponding stream
* instead of the common start time
Expand All @@ -767,17 +766,17 @@ else if (frameTypesToSeek.contains(Frame.Type.AUDIO)) {
}
}
}

/* Sometimes the ffmpeg's avformat_seek_file(...) function brings us not to a position before
* the desired but few frames after. In case we need a frame-precision seek we may
* try to request an earlier timestamp.
*/
long early_ts = timestamp;

/* add the stream start time */
timestamp += ts0;
early_ts += ts0;

long initialSeekPosition = Long.MIN_VALUE;
long maxSeekSteps = 0;
long count = 0;
Expand Down Expand Up @@ -808,28 +807,28 @@ else if (frameTypesToSeek.contains(Frame.Type.AUDIO)) {
else if (seekFrame.samples != null && samples_frame != null && getSampleRate() > 0) {
frameDuration = AV_TIME_BASE * samples_frame.nb_samples() / (double)getSampleRate();
}

if(frameDuration>0.0) {
maxSeekSteps = 0; //no more grab if the distance to the requested timestamp is smaller than frameDuration
if (timestamp - initialSeekPosition + 1 > frameDuration) //allow for a rounding error
maxSeekSteps = (long)(10*(timestamp - initialSeekPosition)/frameDuration);
}
else if (initialSeekPosition < timestamp) maxSeekSteps = 1000;

double delta = 0.0; //for the timestamp correction
count = 0;
while(count < maxSeekSteps) {
seekFrame = grabFrame(frameTypesToSeek.contains(Frame.Type.AUDIO), frameTypesToSeek.contains(Frame.Type.VIDEO), false, false, false);
if (seekFrame == null) return; //is it better to throw NullPointerException?

count++;
double ts=seekFrame.timestamp;
frameDuration = 0.0;
if (seekFrame.image != null && this.getFrameRate() > 0)
frameDuration = AV_TIME_BASE / (double)getFrameRate();
else if (seekFrame.samples != null && samples_frame != null && getSampleRate() > 0)
frameDuration = AV_TIME_BASE * samples_frame.nb_samples() / (double)getSampleRate();

delta = 0.0;
if (frameDuration>0.0) {
delta = (ts-ts0)/frameDuration - Math.round((ts-ts0)/frameDuration);
Expand All @@ -838,8 +837,6 @@ else if (seekFrame.samples != null && samples_frame != null && getSampleRate() >
ts-=delta*frameDuration; // corrected timestamp
if (ts + frameDuration > timestamp) break;
}
frameGrabbed = true;

} else { //old quick seeking code used in JavaCV versions prior to 1.4.1
/* add the stream start time */
timestamp += ts0;
Expand Down Expand Up @@ -870,8 +867,8 @@ else if (seekFrame.samples != null && samples_frame != null && getSampleRate() >
while (this.timestamp < timestamp - 1 && grabFrame(true, true, false, false) != null && count++ < 1000) {
// decode up to the desired frame
}
frameGrabbed = true;
}
frameGrabbed = true;
}
}

Expand Down Expand Up @@ -1497,8 +1494,7 @@ public synchronized Frame grabFrame(boolean doAudio, boolean doVideo, boolean do
long pts = picture.best_effort_timestamp();
AVRational time_base = video_st.time_base();
timestamp = 1000000L * pts * time_base.num() / time_base.den();
long ts0 = 0;
if (oc.start_time() != AV_NOPTS_VALUE) ts0 = oc.start_time();
long ts0 = oc.start_time() != AV_NOPTS_VALUE ? oc.start_time() : 0;
// best guess, AVCodecContext.frame_number = number of decoded frames...
frameNumber = (int)Math.round((timestamp - ts0) * getFrameRate() / 1000000L);
frame.image = image_buf;
Expand Down

0 comments on commit 7ae68f4

Please sign in to comment.