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

High quality gif with FfmpegFrameRecorder #1112

Open
Hosseinyzr opened this issue Dec 25, 2018 · 32 comments
Open

High quality gif with FfmpegFrameRecorder #1112

Hosseinyzr opened this issue Dec 25, 2018 · 32 comments

Comments

@Hosseinyzr
Copy link

Hosseinyzr commented Dec 25, 2018

Hi,
I'm using FfmpegFrameGrabber and FfmpegFrameRecorder to making Gif.
First I extract Gif frames by grabber and convert them to bitmaps by
Bitmap frameBitmap = new AndroidFrameConverter().convert(frame );

then I do some Edits on Them and convert them to Frame object again. and then make gif of them by recorder.
I have tested different PixelFormat But the quality is still bad.
also set videoquality to 1.
....
from ffmpeg documentation I have found these commands make the Gif with high quality..
ffmpeg -i StickAround.mp4 -filter_complex "[0:v] palettegen" palette.png
ffmpeg -i StickAround.mp4 -i palette.png -filter_complex "[0:v][1:v] paletteuse" prettyStickAround.gif
is it possible to do this?
I know it may be done by FrameFilter but I dont know how...

@Hosseinyzr Hosseinyzr changed the title High quality gif High quality gif with FfmpegFrameRecorder Dec 25, 2018
@saudet
Copy link
Member

saudet commented Dec 25, 2018 via email

@Hosseinyzr
Copy link
Author

You mean grabber and recorder?
They are not the same!
And I don't think it's about it. Because once I convert the final Frame objects to bitmap again and the quality was good. But i tested with the same codecs , the result was like before...
Actually I think it's about ffmpeg and quality settings. And those filters I mentioned. Isn't any way to implement those filters?
Could you please explain more?🙏

@saudet
Copy link
Member

saudet commented Dec 25, 2018 via email

@saudet
Copy link
Member

saudet commented Dec 26, 2018

Ah, I see what you mean, we can't set the palette as part of the settings of the codec, we need to go through filters. Sounds like issue #287. Try to do something similar to what is shown there.

@Hosseinyzr
Copy link
Author

Thanks, Yes I have seen that issue before, and it get me the idea... But didn't know how exactly do this...

@Hosseinyzr
Copy link
Author

I thnik palettegen needs the whole video, but we extract frame by frame...
and actually I have the gif in byte[] (because of encryption/decryption).
I think doing paletteuse is ok but what about palettegen...

@saudet
Copy link
Member

saudet commented Dec 26, 2018

We don't need to pass the whole video, and there's a single-frame mode too:
https://ffmpeg.org/ffmpeg-filters.html#palettegen-1

@Hosseinyzr
Copy link
Author

Aha.
I really did'nt find the solution to generate palette.
I have this exception:
E/FrameFilter.Exception: avfilter_graph_parse_ptr() error -22

any body can provide me the sample code to genearte palette?

@Hosseinyzr
Copy link
Author

No idea?
@saudet Are you sure that is possible to implement palettegen with FfmplegFrameFilter? or we should write our own classes?

@saudet
Copy link
Member

saudet commented Dec 28, 2018 via email

@Hosseinyzr
Copy link
Author

@saudet Ok, I will Try again and report the result.
You are one of the bests, thank you for your responses🌹

@Hosseinyzr
Copy link
Author

I have tried in many ways but no success.

one of trys:
filterCommand = " palettegen [myout]; [0:v][myout] paletteuse ";
FFmpegFrameFilter paletteFilter = new FFmpegFrameFilter(filterCommand, w,h);
paletteFilter.setPixelFormat(fFmpegFrameGrabber.getPixelFormat());
paletteFilter.setSampleFormat(fFmpegFrameGrabber.getSampleFormat());
try {
paletteFilter.start();
paletteFilter.push(myFrame);
Frame frame = paletteFilter.pull();
paletteFilter.stop();
paletteFilter.release();
} catch (FrameFilter.Exception e) {
Logger.e("FrameFilter.Exception ", e.getMessage());
}

but it trows this exception:
FrameFilter.Exception: avfilter_graph_config() error -22
......
another thing that we cant pass the file path for output of frame filter, is it true?

@saudet
Copy link
Member

saudet commented Dec 30, 2018

I don't think they were meant to be used together like that. In any case, try to follow what the documentation says...

@Hosseinyzr
Copy link
Author

I don't think it is possible to do this with ffmpegframefilter! I had tried another ways but no success!

@saudet saudet reopened this Dec 31, 2018
@saudet
Copy link
Member

saudet commented Dec 31, 2018

I'm pretty sure it's possible, we just need to spend more time trying things out... It would probably help to check the debug log of FFmpeg.

@Hosseinyzr
Copy link
Author

Hosseinyzr commented Jan 1, 2019

How can i get the log of this library?
whats the pckagename to search the logs for it?
I hava a lot of og logs in my logcat ..
I don't see any special loggs for ffmpeg...
...........................
I don't have problem to spending times on it but I do;nt have a clue!
............................
the command base way is simpe:

ffmpeg -i StickAround.mp4 -filter_complex "[0:v] palettegen" palette.png
ffmpeg -i StickAround.mp4 -i palette.png -filter_complex "[0:v][1:v] paletteuse" prettyStickAround.gif

I think we should do this in two step, once generating palette and the use it.
for generating , when I try:
//pathOfImage is something like this: /storage/emulated..../a.png
filterCommand = " palettegen "+pathOfImage;

I have this exception:
avfilter_graph_parse_ptr() error -22

so what should I do? any other users have any idea?

@Hosseinyzr
Copy link
Author

@saudet You have written this library and you know it better than me...
Could you please take some time to help me? I really need it.

@Hosseinyzr
Copy link
Author

@zhengxuzeng You have tried this before, Do have any Idea?

@saudet
Copy link
Member

saudet commented Jan 19, 2019

Please provide more information, such as the messages that appear on the console.
If you don't see anything there, make sure to call FFmpegLogCallback.set().

@Hosseinyzr
Copy link
Author

Hosseinyzr commented Jan 24, 2019

I did as You said , and these are results:

         FFmpegLogCallback.set();

        String myPath = G.APPLICATION_DIR + "/aatempPalletteGen.png";

        String filterCommand = "";
        filterCommand = " palettegen [myout]; [0:v][myout]  paletteuse ";
        FFmpegFrameFilter paletteFilter = new FFmpegFrameFilter(filterCommand, frames.get(0).getW(), frames.get(0).getH());



        try {
        paletteFilter.start();
        paletteFilter.push(myFrame);
        Frame frame = paletteFilter.pull();
        paletteFilter.stop();
        paletteFilter.release();
        FileOutputStream fileOutputStream = new FileOutputStream(new File(myPath));
        new AndroidFrameConverter().convert(frame)
        .compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);

        } catch (FrameFilter.Exception e) {
        Log.e("FrameFilter.Exception ", e.getMessage());
        } catch (FileNotFoundException e) {
        Log.e("FileNotFoundException ", e.getMessage());
        }
 //Logs:
 W/System.err: Error: Input pad "default" with type video of the filter instance "Parsed_paletteuse_1" of paletteuse not connected to any source
 E/FrameFilter.Exception: avfilter_graph_config() error -22
 I/System.out: Output #0, gif, to '':
 I/System.out:   Metadata:
 I/System.out:     encoder         :
 I/System.out: Lavf58.12.100
 I/System.out:     Stream #0:0
 I/System.out: : Video: gif, bgr8, 420x322, q=2-31, 400 kb/s
 I/System.out: ,
 I/System.out: 100 tbn

Second Try:

          FFmpegLogCallback.set();

         String myPath = G.APPLICATION_DIR + "/aatempPalletteGen.png";

         String myPalette = G.APPLICATION_DIR + "/MytempPalletteGen.png";

         String filterCommand = "";
      filterCommand = " palettegen  "+myPalette ;
         FFmpegFrameFilter paletteFilter = new FFmpegFrameFilter(filterCommand, frames.get(0).getW(), frames.get(0).getH());



         try {
             paletteFilter.start();
             paletteFilter.push(myFrame);
             Frame frame = paletteFilter.pull();
             paletteFilter.stop();
             paletteFilter.release();
             FileOutputStream fileOutputStream = new FileOutputStream(new File(myPath));
             new AndroidFrameConverter().convert(frame)
                     .compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);

         } catch (FrameFilter.Exception e) {
             Log.e("FrameFilter.Exception ", e.getMessage());
         } catch (FileNotFoundException e) {
             Log.e("FileNotFoundException ", e.getMessage());
         }

//Logs:

 W/System.err: Warning: Invalid return value 0 for stream protocol
 I/System.out: Input #0, gif, from 'java.io.ByteArrayInputStream@160d30c':
 I/System.out:   Duration:
 I/System.out: N/A
 I/System.out: , bitrate:
 I/System.out: N/A
 I/System.out:     Stream #0:0
 I/System.out: : Video: gif, bgra, 420x322
 I/System.out: ,
 I/System.out: 10 tbr,
 I/System.out: 100 tbn,
 I/System.out: 100 tbc
 W/System.err: Warning: Invalid return value 0 for stream protocol
 W/System.err: Warning: Invalid return value 0 for stream protocol
 W/System.err: Error: No such filter: 'palettegen  /storage/emulated/0/.MyToonAppDir/.nomedia/MytempPalletteGen.png'
 E/FrameFilter.Exception: avfilter_graph_parse_ptr() error -22
 I/System.out: Output #0, gif, to '':
 I/System.out:   Metadata:
 I/System.out:     encoder         :
 I/System.out: Lavf58.12.100
 I/System.out:     Stream #0:0
 I/System.out: : Video: gif, bgr8, 420x322, q=2-31, 400 kb/s
 I/System.out: ,
 I/System.out: 100 tbn

@saudet
Copy link
Member

saudet commented Jan 25, 2019

Do you have a filter command that works with ffmpeg on the command line? If so, try to start by using that!

@Hosseinyzr
Copy link
Author

Do you have a filter command that works with ffmpeg on the command line? If so, try to start by using that!

I don't understand what you mean?
you mean test another command?

I have tested palletgen in command line and it worked...

@saudet
Copy link
Member

saudet commented Jan 25, 2019

So try to use the same exact command with FFmpegFrameFilter. Don't add any filename or anything.

@Hosseinyzr
Copy link
Author

So try to use the same exact command with FFmpegFrameFilter. Don't add any filename or anything.

this is simple command:
ffmpeg -i movie.mp4 -filter_complex "[0:v] palettegen" palette.png
it needs one output.
and the out put will be used by paletteuse command.
so what did I added and is extra?

@saudet
Copy link
Member

saudet commented Jan 25, 2019

You're adding filenames and what not to the filter command itself: That won't work! You're not doing that with ffmpeg on the command line, so don't do it with FFmpegFrameFilter either.

@Hosseinyzr
Copy link
Author

Hosseinyzr commented Jan 25, 2019

What do you mean I'm not using file name in ffmpeg command line?

this is the command and it needs the out put file name and works fine:

command

Can you provide some piece of code ? or test it yourself?

@saudet
Copy link
Member

saudet commented Jan 26, 2019

That's the output filename, FFmpegFrameFilter doesn't support that. You'll need to use FFmpegFrameRecorder for that.

I already gave you a complete example above.

@saudet
Copy link
Member

saudet commented Jan 26, 2019

@Hosseinyzr
Copy link
Author

That's the output filename, FFmpegFrameFilter doesn't support that. You'll need to use FFmpegFrameRecorder for that.

I already gave you a complete example above.

Yes, I pointed that does FFmpegFrameFilter can do this filter ? and you said yes ...
#1112 (comment)


And I'm currently using FfmpegframeRecorder! Every thing is ok , but the problem is ffmpeg itself needs palettegen and paletuse to generate high quality gifs. and as I found from my searches this is the correct way to make high quality gifs. the pixel format and other things are effective but they aren't sufficient to make the most high quality ones.


Actually, no, I didn't, here are examples:
https://github.com/bytedeco/javacv/blob/master/platform/src/test/java/org/bytedeco/javacv/FrameFilterTest.java

I see this now, and I update my javacv and ffmpeg to latest version. thank for your update.but it seems it does'nt help in this case.

@saudet
Copy link
Member

saudet commented Jan 26, 2019

FrameFilterTest works, see on Travis CI: https://travis-ci.org/bytedeco/javacv

If it doesn't work for you, you're doing something else wrong that is unrelated to your filters.

@Hosseinyzr
Copy link
Author

FrameFilterTest works, see on Travis CI: https://travis-ci.org/bytedeco/javacv

If it doesn't work for you, you're doing something else wrong that is unrelated to your filters.

what was the clue in here?

I don't understand...

You mean FrameFilter can perform all of filters?!
And it's not about Framefilter defect?

I really need it man...
Although this repository is good and perfect but unfortunately it doesn't have good documentation.
so please take some time or explain better...

@saudet
Copy link
Member

saudet commented Jan 31, 2019

Happy to help, but I won't do everything for you. Start by getting the code from FrameFilterTest to run on your machine, and then start making modifications to it for your needs.

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