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

GIF File to GIF File #2057

Closed
LemuriaX opened this issue Jul 10, 2023 · 7 comments
Closed

GIF File to GIF File #2057

LemuriaX opened this issue Jul 10, 2023 · 7 comments

Comments

@LemuriaX
Copy link

LemuriaX commented Jul 10, 2023

Hello, I want to use FFmpeg to split a GIF into frames and splicing it into GIF again (although it sounds pointless, but it is important to me), for this, I refer to these documents.

https://github.com/yokra9/JavaCV-Movie2Gif-example/blob/main/src/Movie2Gif.java

#1137

#2045

I read a lot of issues about this project, but my problem is still not solved, so I raised this issue, I hope you can answer it for me.

I have the following code

public class TestA {
    @Test
    public void test() throws FFmpegFrameGrabber.Exception, FFmpegFrameFilter.Exception, FFmpegFrameRecorder.Exception {
        String input = "C:\\Users\\Yuki\\Desktop\\in.gif";
        String output = "C:\\Users\\Yuki\\Desktop\\out.gif";
        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(input);
        grabber.setImageMode(FrameGrabber.ImageMode.RAW);
        grabber.start();
        FFmpegFrameFilter filter = new FFmpegFrameFilter("split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse", grabber.getImageWidth(), grabber.getImageHeight());
        FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(output, grabber.getImageWidth(), grabber.getImageHeight());
        filter.setPixelFormat(avutil.AV_PIX_FMT_PAL8);
        filter.setImageHeight(grabber.getImageHeight());
        filter.setImageWidth(grabber.getImageWidth());
        filter.setFrameRate(grabber.getFrameRate());
        filter.start();

        // specify supported pixel format.
        recorder.setPixelFormat(avutil.AV_PIX_FMT_PAL8);
        recorder.setVideoCodec(avcodec.AV_CODEC_ID_GIF);
        recorder.setImageWidth(grabber.getImageWidth());
        recorder.setImageHeight(grabber.getImageHeight());
        recorder.setFrameRate(grabber.getFrameRate());
        recorder.start();

        Frame frame, filteredFrame;
        while (Objects.nonNull((frame = grabber.grabFrame(false, true, true, false)))) {

            if (Objects.nonNull(frame.image) || Objects.nonNull(frame.samples)) {
                filter.push(frame);
            }

            if (Objects.nonNull((filteredFrame = filter.pull()))) {
                if (Objects.nonNull(filteredFrame.image) || Objects.nonNull(filteredFrame.samples)) {
                    recorder.record(filteredFrame, avutil.AV_PIX_FMT_PAL8);
                }
            }

        }
        grabber.stop();
        grabber.release();
        filter.stop();
        filter.release();
        recorder.stop();
        recorder.release();
    }

}

In this code, after filter.push(frame), the return value of filter.pull() is null.

Here is the output of my program。

Input #0, gif, from 'C:\Users\Yuki\Desktop\in.gif':
  Metadata:
    comment         : Made with ScreenToGif
  Duration: 00:00:12.72, start: 0.000000, bitrate: 818 kb/s
  Stream #0:0: Video: gif, bgra, 879x355, 6.92 fps, 14.42 tbr, 100 tbn
Output #0, gif, to 'C:\Users\Yuki\Desktop\out.gif':
  Metadata:
    encoder         : Lavf60.3.100
  Stream #0:0: Video: gif, pal8, 880x355, q=2-31, 400 kb/s, 6.92 fps, 100 tbn
[in @ 000000002fe2b000] filter context - w: 879 h: 355 fmt: 11, incoming frame - w: 879 h: 355 fmt: 28 pts_time: 0
[in @ 000000002fe2b000] Changing video frame properties on the fly is not supported by all filters.
[in @ 000000002fe2b000] filter context - w: 879 h: 355 fmt: 11, incoming frame - w: 879 h: 355 fmt: 28 pts_time: 0.144578
[in @ 000000002fe2b000] Changing video frame properties on the fly is not supported by all filters.
[in @ 000000002fe2b000] filter context - w: 879 h: 355 fmt: 11, incoming frame - w: 879 h: 355 fmt: 28 pts_time: 0.289157
[in @ 000000002fe2b000] Changing video frame properties on the fly is not supported by all filters.
[in @ 000000002fe2b000] filter context - w: 879 h: 355 fmt: 11, incoming frame - w: 879 h: 355 fmt: 28 pts_time: 1.59036
[in @ 000000002fe2b000] Changing video frame properties on the fly is not supported by all filters.
[in @ 000000002fe2b000] filter context - w: 879 h: 355 fmt: 11, incoming frame - w: 879 h: 355 fmt: 28 pts_time: 1.59036
[in @ 000000002fe2b000] Changing video frame properties on the fly is not supported by all filters.
[in @ 000000002fe2b000] filter context - w: 879 h: 355 fmt: 11, incoming frame - w: 879 h: 355 fmt: 28 pts_time: 1.73494
[in @ 000000002fe2b000] Changing video frame properties on the fly is not supported by all filters.
[in @ 000000002fe2b000] filter context - w: 879 h: 355 fmt: 11, incoming frame - w: 879 h: 355 fmt: 28 pts_time: 1.73494
[in @ 000000002fe2b000] Changing video frame properties on the fly is not supported by all filters.
[in @ 000000002fe2b000] filter context - w: 879 h: 355 fmt: 11, incoming frame - w: 879 h: 355 fmt: 28 pts_time: 1.87952
[in @ 000000002fe2b000] Changing video frame properties on the fly is not supported by all filters.
[in @ 000000002fe2b000] filter context - w: 879 h: 355 fmt: 11, incoming frame - w: 879 h: 355 fmt: 28 pts_time: 1.87952
[in @ 000000002fe2b000] Changing video frame properties on the fly is not supported by all filters.
[in @ 000000002fe2b000] filter context - w: 879 h: 355 fmt: 11, incoming frame - w: 879 h: 355 fmt: 28 pts_time: 2.0241
[in @ 000000002fe2b000] Changing video frame properties on the fly is not supported by all filters.
[in @ 000000002fe2b000] filter context - w: 879 h: 355 fmt: 11, incoming frame - w: 879 h: 355 fmt: 28 pts_time: 2.0241
[in @ 000000002fe2b000] Changing video frame properties on the fly is not supported by all filters.
[in @ 000000002fe2b000] filter context - w: 879 h: 355 fmt: 11, incoming frame - w: 879 h: 355 fmt: 28 pts_time: 2.16867
[in @ 000000002fe2b000] Changing video frame properties on the fly is not supported by all filters.
[in @ 000000002fe2b000] filter context - w: 879 h: 355 fmt: 11, incoming frame - w: 879 h: 355 fmt: 28 pts_time: 2.16867
[in @ 000000002fe2b000] Changing video frame properties on the fly is not supported by all filters.
[in @ 000000002fe2b000] filter context - w: 879 h: 355 fmt: 11, incoming frame - w: 879 h: 355 fmt: 28 pts_time: 2.31325
[in @ 000000002fe2b000] Changing video frame properties on the fly is not supported by all filters.
[in @ 000000002fe2b000] filter context - w: 879 h: 355 fmt: 11, incoming frame - w: 879 h: 355 fmt: 28 pts_time: 2.31325
[in @ 000000002fe2b000] Changing video frame properties on the fly is not supported by all filters.
[in @ 000000002fe2b000] filter context - w: 879 h: 355 fmt: 11, incoming frame - w: 879 h: 355 fmt: 28 pts_time: 2.45783
[in @ 000000002fe2b000] Changing video frame properties on the fly is not supported by all filters.
[in @ 000000002fe2b000] filter context - w: 879 h: 355 fmt: 11, incoming frame - w: 879 h: 355 fmt: 28 pts_time: 2.45783

If I set the pixel encoding to AV_PIX_FMT_BGR8, it works fine, but the output image quality is poor. I've been stuck with this problem for a week, don't know if I missed something, hope you can help me to see what's wrong in my code, thank you very much.

@LemuriaX
Copy link
Author

This is the gif I used for testing
https://github.com/LemuriaX/img/blob/main/in.gif

@LemuriaX
Copy link
Author

Hello, I have a new progress now. I set filter.push(frame, AV_PIX_FMT_PAL8) and now it shows no error. But pull() still returns null

@LemuriaX
Copy link
Author

I read this issus
#287

Called filter.push(null) before pull, and now it can read the frame, but there is still a problem with recorder.record(filteredFrame, avutil.AV_PIX_FMT_PAL8), I opened the debug, FFmpegLogCallback.set(), it prompts Me, pal8 is not supported as output pixel format.

sws_getCachedContext() error: Cannot initialize the conversion context.

@saudet
Copy link
Member

saudet commented Jul 11, 2023

We can easily accomplish this with the ffmpeg program:
http://bytedeco.org/javacpp-presets/ffmpeg/apidocs/org/bytedeco/ffmpeg/ffmpeg.html

@LemuriaX
Copy link
Author

我们可以使用 ffmpeg 程序轻松完成此操作: http://bytedeco.org/javacpp-presets/ffmpeg/apidocs/org/bytedeco/ffmpeg/ffmpeg.html

thank you for your reply. Yes, I did the process using ProcessBuilder. Besides, is there anything wrong with my code above? I don't expect to use ProcessBuilder directly, I would rather use FFmpegFrameRecorder and FFmpegFrameFilter.

@LemuriaX
Copy link
Author

I found the problem. The resolution of the gif I used for testing will change, causing video_c.width() to return a different value from the initial value. How should I deal with this situation?
I noticed the description of video_c.width(), can I set this value by myself? Or can I fix the resolution to a value?

picture width / height. \note Those fields may not match the values of the last AVFrame output by avcodec_receive_frame() due frame reordering. - encoding: MUST be set by user. - decoding: May be set by the user before opening the decoder if known e.g. from the container. Some decoders will require the dimensions to be set by the caller. During decoding, the decoder may overwrite those values as required while parsing the data.

@saudet
Copy link
Member

saudet commented Jul 24, 2023

JavaCV probably needs to be enhanced to support all that you need here...

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