Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FPS filters can cause some problems #2121

Closed
git-newer opened this issue Nov 6, 2023 · 5 comments
Closed

FPS filters can cause some problems #2121

git-newer opened this issue Nov 6, 2023 · 5 comments

Comments

@git-newer
Copy link

I want to use the fps filter in FFmpegFrameFilter to convert a 25fps video to a 30fps video, like this:

int[] size = {360, 640};
int frameRate = 30;
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(new File(output), size[0], size[1]);
recorder.setFormat("mp4");
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(new File(input));
FFmpegFrameFilter filter = new FFmpegFrameFilter("fps=" + frameRate, size[0], size[1]);
filter.start();
recorder.start();
grabber.start();
System.out.println("original frameRate:" + grabber.getFrameRate());
Frame frame;
int pushI = 0;
int recordI = 0;
while ((frame = grabber.grabImage()) != null) {
    filter.push(frame);
    pushI++;
    frame = filter.pullImage();
    if (null != frame) {
        recorder.record(frame);
        recordI++;
    }
}
System.out.println("recordI:" + recordI);
while (null != (frame = filter.pullImage())) {
    recorder.record(frame);
    recordI++;
}
System.out.println("pushI:" + pushI);
System.out.println("recordI:" + recordI);
recorder.close();
grabber.close();

Even though I ended up with a 30fps video, it was a few seconds shorter.
I printed the number of pushes and the number of records, and they turned out to be like this when 25fps to 30fps

original frameRate:25.0
recordI:916
pushI:917
recordI:916

It looks like the filter isn't generating extra frames to fill the video.
When I use this code to convert the same video from 25 fps to 60 fps, the result of the program running becomes something like this:

original frameRate:25.0
recordI:916
pushI:917
recordI:1832

This time the filter successfully filled in the extra frames, but not enough frames. My video is about 36 seconds, the original video has 916 frames, but the recordI is only 1832 frames. Theoretically there should be about 36*60=2160 frames, which is about 360 frames less, resulting in my final recorded video being about 6 seconds less than the original video.
In addition, I tried it again using the ffmpeg command ffmpeg -i input.mp4 -filter "fps=60" -y 60fps.mp4, and the result was correct, the frame rate was 60fps and the video duration was the same.
So I'm wondering, is there some problem with the implementation of fps filters in JavaCV? Or maybe there's something wrong with my code.
Thank you for reading and look forward to your reply

@saudet
Copy link
Member

saudet commented Nov 6, 2023

Please try again with JavaCV 1.5.9.

@saudet
Copy link
Member

saudet commented Nov 6, 2023

Also we may also need to call push(null) to flush the filters, so please make sure you call push(null) somewhere.

@saudet
Copy link
Member

saudet commented Nov 6, 2023

Duplicate of #1315

@saudet saudet marked this as a duplicate of #1315 Nov 6, 2023
@saudet saudet closed this as completed Nov 6, 2023
@saudet saudet added the question label Nov 6, 2023
@saudet
Copy link
Member

saudet commented Nov 6, 2023

Also duplicate of #287 and #1727

@git-newer
Copy link
Author

Thank you for your reply
I tried with JavaCV 1.5.9, but it executes with the same result.
I call filter.push(null) before pull like this:

while ((frame = grabber.grabImage()) != null) {
    filter.push(frame);
    pushI++;
    filter.push(null);
    frame = filter.pullImage();
    if (null != frame) {
        recorder.record(frame);
        recordI++;
    }
}

But i got an error: "av_buffersrc_add_frame_flags() error -22: Error while feeding the filtergraph. (For more details, make sure FFmpegLogCallback.set() has been called.)"
Then i tried changing filter.push(null) to here:

System.out.println("recordI:" + recordI);
filter.push(null);
while (null != (frame = filter.pullImage())) {
    recorder.record(frame);
    recordI++;
    filter.push(null);
}

The program result is:

original frameRate:25.0
recordI:916
pushI:917
recordI:917

Compared with before, the last frame pushed into the filter is indeed pulled out, but the result of this filter is still inconsistent with the result of the ffmpeg command execution, and the video duration is still shorter than the original video.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants