lower fps when using ffmpeg to convert mp4 to gif - ffmpeg

I am using ffmpeg to convert high quality videos to gif, most of the videos are 60fps and over 720p, but when I use the code below, to convert the video to gif, I get very low fps for the gif output,
#!/usr/bin/env
palette=/tmp/pallete.png
filter="fps=50,scale=480:-1:flags=lanczos"
ffmpeg -y -i test.mov -vf $filter,palettegen=stats_mode=diff $palette
ffmpeg -y -i test.mov -i $palette -lavfi "$filter [x]; [x][1:v] paletteuse" test.gif
another issue I have noted is - as the width increases e.g 720 instead of 480 I get even lower fps.
here is output log example, the output fps is lower than the assigned 50fps
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/tmp/201631203815.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf56.36.100
Duration: 00:00:05.48, start: 0.016000, bitrate: 1579 kb/s
Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p, 1334x1334, 1576 kb/s, 60.18 fps, 60 tbr, 1000k tbn, 50 tbc (default)
Metadata:
handler_name : VideoHandler
Input #1, png_pipe, from '/tmp/pallete.png':
Duration: N/A, bitrate: N/A
Stream #1:0: Video: png, rgba(pc), 16x16 [SAR 1:1 DAR 1:1], 25 tbr, 25 tbn, 25 tbc
Output #0, gif, to '/tmp/201631203815.gif':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf56.40.101
Stream #0:0: Video: gif, pal8, 480x480, q=2-31, 200 kb/s, 50 fps, 100 tbn, 50 tbc (default)
Metadata:
encoder : Lavc56.60.100 gif
Stream mapping:
Stream #0:0 (h264) -> fps
Stream #1:0 (png) -> paletteuse:palette
paletteuse -> Stream #0:0 (gif)
Press [q] to stop, [?] for help
frame= 275 fps= 32 q=-0.0 Lsize= 2480kB time=00:00:05.50 bitrate=3693.5kbits/s
How do I ensure that the output fps is always whats set by the user?
Any resource on this is highly appreciated.
UPDATE
i have also noticed that the use of a higher fps eg filter="fps=90,scale=480:-1:flags=lanczos" has the effect of slowing down the gif,like a slow motion effect, the output fps is still lower around 15fps,

setting the fps value explicitly gave the same lower fps output
results frame= 346 fps= 24 q=-0.0 Lsize= 6506kB time=00:00:06.92
bitrate=7701.8kbits/s
This is not the output fps! It's the encoding speed. Most players don't properly play GIFs with a fps higher than 50. See the demo showing this behaviour.

I'm not experienced in making GIF files with FFmpeg, but as far as I know, the fps filter has an idividual "fps" parameter for the actual framerate value, so I think it may not work correctly if you omit that.
Just to make sure the filter gets the correct value, you should explicitly set the fps value:
filter="fps=fps=50,scale=480:-1:flags=lanczos"
If it doesn't working, I'd try the regular "rate" option too:
ffmpeg -y -i test.mov -i $palette -lavfi "$filter [x]; [x][1:v] paletteuse" -r 50 test.gif
Otherways, your console output looks good (it indicates the output will be 50fps), so the phenomena is a little bit mysterious.
Working Solution:
All you need to do is to break the process into three individual steps, and use the "-framerate" demux-option.
First, let's generate the palette file:
ffmpeg -i <input_file> -filter_complex "scale=w=480:h=-1:flags=lanczos, palettegen=stats_mode=diff" palette.png
Secondly, break the video frames into image files:
ffmpeg -i <input_file> -r 50 -f image2 image_%06d.png
And finally, join said images into one GIF sequence:
(the important part here is the image2 demuxer's framerate option!)
ffmpeg -framerate 50 -i image_%06d.png -i palette.png -filter_complex "[0]scale=w=400:h=-1[x];[x][1:v] paletteuse" -pix_fmt rgb24 output.gif
Edit: Finally find the answer!
You need to use image2 demuxer's -framerate option! (answer edited accordingly)
Alternative methods:
gifsickle - convert images to gif, can set frame delay
ImageMagic - can convert video to gif directly, excellent gif quality control options.

Related

ffmpeg concat filter is dropping first second of second video

con.txt
file one.mp4
file two.mp4
The command
ffmpeg -f concat -safe 0 -i con.txt out.mp4
produces a video that doesn't contain the first second of two.mp4.
ffprobe two.mp4
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'two.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
Duration: 00:00:15.20, start: 0.000000, bitrate: 1644 kb/s
Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p, 428x640, 1644 kb/s, 10 fps, 10 tbr, 10240 tbn, 20 tbc (default)
Metadata:
handler_name : VideoHandler
vendor_id : [0][0][0][0]
I get an interesting error attempting another concatenation method (neither video has audio btw)
ffmpeg -i one.mp4 -i two.mp4 -filter_complex "[0:v] [1:v] concat=n=2:v=1:a=0 [v]" -map "[v]" out.mp4
Input link in0:v0 parameters (size 428x640, SAR 0:1) do not match the corresponding output link in0:v0 parameters (428x640, SAR 1576:1575)
How can I join these two videos together sequentially without losing any frames from either?
The concat filter expects the streams to be concatenated to have the identical properties (size, sample aspect ratio (SAR), pix_fmt, etc.). The error message is saying that SARs are not matching up. You can insert setsar filters upstream of concat filter to resolve this. Assuming these videos have square pixels (1576:1575 is pretty darn close to 1:1), we can do this:
ffmpeg -i one.mp4 -i two.mp4 \
-filter_complex "[0:v]setsar=1:1[L0]; \
[1:v]setsar=1:1,fps=30[L1]; \
[L0][L1]concat=n=2:v=1:a=0 [v] " \
-map "[v]" out.mp4
If you get other errors, you need to prepend more filters to condition your streams to match each other.
Edit: Added fps filter to the second video (10 fps) to match the first (30 fps)

FFMPEG - concatenating mp4s from different sources - unable to stop "Non-monotonous DTS in output stream" warning

I need to concatenate mp4 files from different sources, this means some of the variables are out of my control such as timebase, aspect ratio and encoding. So to get around this I re-encode and attempt to standardise the files before concatenating them. Unfortunately, despite this I get Non-monotonous DTS in output stream warnings during the concatenation stage, and the output video seems to always have broken audio/video syncing by the last segment.
I know there are a lot of other questions out there about resolving the warning above, but I've been through them all and reviewed the documentation.. but unfortunately I've been still been unable to solve it..
I think the thing which I don't understand is: if I have mp4s from different sources, what exactly do I need to do to ensure that the files will always neatly concatenate together?
What I've tried so far
The script I'm using to standardise the mp4 files before concantenation is the following (amends resolution, frame rate, timebase, bitrate for audio, bitrate for video, audio encoding and video encoding):
ffmpeg -y -i $1 -vf 'scale=1280:720:force_original_aspect_ratio=1,pad=1280:720:(ow-iw)/2:(oh-ih)/2' -r 30 -video_track_timescale 90000 -b:a 128K -b:v 1200K -c:a aac -c:v libx264 $2
Here's the ffprobe output on two of the files, there are some differences but I'm not sure if they are significant?
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'intro.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf58.12.100
Duration: 00:00:08.98, start: 0.000000, bitrate: 1210 kb/s
Stream #0:0(eng): Video: h264 (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 1069 kb/s, 30 fps, 30 tbr, 90k tbn, 60 tbc (default)
Metadata:
handler_name : VideoHandler
Stream #0:1(eng): Audio: aac (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 132 kb/s (default)
Metadata:
handler_name : SoundHandler
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'middle.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf58.12.100
Duration: 00:00:59.72, start: 0.000000, bitrate: 1200 kb/s
Stream #0:0(und): Video: h264 (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 1063 kb/s, 30 fps, 30 tbr, 90k tbn, 60 tbc (default)
Metadata:
handler_name : VideoHandler
Stream #0:1(und): Audio: aac (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 128 kb/s (default)
Metadata:
handler_name : SoundHandler
They all have normal video and audio at this point.
After that I concatenate them and add a watermark using the following (it sucks that I need to re-encode here):
ffmpeg -y \
-f concat \
-safe 0 \
-i $INFILES \
-c:v libx264 \
-c:a copy \
-preset fast \
-vf drawtext=enable="'between(t, $DRAW_TEXT_DELAY, $DRAW_TEXT_DURATION)': fontfile=$FONT_DIR/$FONT: text='$TEXT': fontcolor=$FONTCOLOR: fontsize=$FONTSIZE: $POSITION" \
$OUTFILE
INFILES is a path to a text file formatted like:
file /usr/src/app/data/test/out/intro.mp4
file /usr/src/app/data/test/out/middle.mp4
file /usr/src/app/data/test/out/outro.mp4
What am I missing here? Is there a way to debug this further?
Your audio streams have distinct sampling rates, and may have distinct channel count as well. Also, compressed MPEG audio streams will introduce slight async upon concat.
Use
ffmpeg -y -i $1 -vf 'scale=1280:720:force_original_aspect_ratio=1,pad=1280:720:(ow-iw)/2:(oh-ih)/2,setsar=1,format=yuv420p' -r 30 -c:v libx264 -b:v 1200K -ac 2 -ar 48000 -c:a pcm_s16le -video_track_timescale 90000 $2
to standardize, but save to MOV.
Then during concat, change -c:a copy to -c:a aac.
There are three methods to concatenate files in FFmpeg.
Demuxer (You are using this)
This method can be used to concat files with the same paramters, like codecs, size, PAR, etc.
$ ffmpeg -concat -i files.txt [...] output.mp4
Protocol
Same as the first one, but on top of that, this method is useful for files that can be copied together bitwise - it doesn't involves re-encoding (some formats support this, like MpegTS or some lossless formats).
$ ffmpeg -i "concat:FILE_0| ... |FILE_N" [...] output.mp4
Filter
If you have videos with different codecs, you have to use this method:
$ ffmpeg -i <FILE_0> ... -i <FILE_N> [...] -filter_complex "[0:0][0:1]...[<N>:0][<N>:1] concat=n=<N>:v=1:a=1[v_out][a_out]" -map [v_out] -map [a_out] output.mp4
The concat filter decodes the video and reencodes it with the same parameters. It also takes care of the audio streams. I'm not entirely sure what does it do if the resolutions are different, but this should be a good start.

ffmpeg from pngs... Error with subset of PNGS?

I have about 1200 pngs that I'm converting into a movie. Some of them are missing: i.e. - _00003.png, _00005.png exist, but 1, 2, and 4 do not.
The following command works for other datasets, but not my current set of pngs:
ffmpeg -i pngs/_*.png -y -vcodec mpeg4 -pix_fmt yuv420p -r 25 -filter:v 'setpts=1.2*PTS' p3SN.mp4
I get this error:
Output #61, image2, to 'pngs/_00096.png':
Metadata:
encoder : Lavf57.83.100
Stream #61:0: Video: png, rgba, 3240x2160 [SAR 3937:3937 DAR 3:2], q=2-31, 200 kb/s, 25 fps, 25 tbn, 25 tbc
Metadata:
encoder : Lavc57.107.100 png
Output #62, image2, to 'pngs/_00097.png':
Metadata:
encoder : Lavf57.83.100
Stream #62:0: Video: png, rgba, 3240x2160 [SAR 3937:3937 DAR 3:2], q=2-31, 200 kb/s, 25 fps, 25 tbn, 25 tbc
Metadata:
encoder : Lavc57.107.100 png
[png # 0x7fae93170e00] ff_frame_thread_encoder_init failed
Error initializing output stream 63:0 -- Error while opening encoder for output stream #63:0 - maybe incorrect parameters such as bit_rate, rate, width or height
Conversion failed!
at image _00097.png. If I remove it, it just happens a little later (105).
I've checked the images by looking at their dimensions, etc. and all of them in this range look the same (I checked all those with _0009?.png).
Any idea why this is happening?
Here's the offending file (middle) and the one before/after:
Your command will overwrite all of the input files with the first input. This is an example of why to use caution when using -y which will automatically overwrite files without asking you.
You need to tell ffmpeg to use the glob pattern:
ffmpeg -y -pattern_type glob -framerate 25/1.2 -i "pngs/_*.png" -vcodec mpeg4 -pix_fmt yuv420p -r 25 p3SN.mp4
I believe the glob pattern option does not work on Windows, but if it has an equivalent to the Linux cat command you can pipe the output: cat *.png | ffmpeg -i - output.mp4
You can use -framerate and -r instead of setpts if desired.

how to convert videos to flv using ffmpeg in php?

i am trying to convert some different video formats to flv using ffmpeg. But it seems that only some videos go through.
ffmpeg -i /var/www/tmp/91640.avi -ar 22050 -ab 32 -f flv /var/www/videos/91640.flv
here is some debug info:
Seems stream 0 codec frame rate differs from container frame rate: 23.98 (65535/2733) -> 23.98 (5000000/208541)
Input #0, avi, from '/var/www/tmp/91640.avi':
Duration: 00:01:12.82, start: 0.000000, bitrate: 5022 kb/s
Stream #0.0: Video: mpeg4, yuv420p, 1280x528 [PAR 1:1 DAR 80:33], 23.98 tbr, 23.98 tbn, 23.98 tbc
Stream #0.1: Audio: ac3, 48000 Hz, 5.1, s16, 448 kb/s
WARNING: The bitrate parameter is set too low. It takes bits/s as argument, not kbits/s
Output #0, flv, to '/var/www/videos/91640.flv':
Stream #0.0: Video: flv, yuv420p, 1280x528 [PAR 1:1 DAR 80:33], q=2-31, 200 kb/s, 90k tbn, 23.98 tbc
Stream #0.1: Audio: adpcm_swf, 22050 Hz, 5.1, s16, 0 kb/s
Stream mapping:
Stream #0.0 -> #0.0
Stream #0.1 -> #0.1
Error while opening codec for output stream #0.1 - maybe incorrect parameters such as bit_rate, rate, width or height
also, if i try to grab one frame ad convert it to jpeg i get an error as well
ffmpeg -i /var/www/tmp/91640.avi -an -ss 00:00:03 -t 00:00:01 -r 1 -y /var/www/videos/91640.jpg
debug info
...
[mpeg4 # 0x1d7d810]Invalid and inefficient vfw-avi packed B frames detected
av_interleaved_write_frame(): I/O error occurred
Usually that means that input file is truncated and/or corrupted.
im thinking that the image fails because the video conversion failed in the first place, not sure though
any ideas what goes wrong?
Bits, not kbits
From your console output:
WARNING: The bitrate parameter is set too low. It takes bits/s as argument, not kbits/s
Use 32k, not just 32.
Only stereo or mono is supported
The encoder adpcm_swf ony supports mono or stereo, so add -ac 2 as an output option. The console output would have suggested this if you were using a recent ffmpeg build.
Use -vframes 1 for single image outputs
Instead of -t 00:00:01 -r 1 use -vframes 1.
A better encoder
Instead of using the encoders flv and adpcm_swf, I recommend libx264 and libmp3lame:
ffmpeg -i input -vcodec libx264 -preset medium -crf 23 -acodec libmp3lame -ar 44100 -q:a 5 output.flv
-preset – Controls the encoding speed to compression ratio. Use the slowest preset you have patience for: ultrafast,superfast, veryfast, faster, fast, medium, slow, slower, veryslow.
-crf – Constant Rate Factor. A lower value is a higher quality. Range is 0-51 for this encoder. 0 is lossless, 18 is roughly "visually lossless", 23 is default, and 51 is worst quality. Use the highest value that still gives an acceptable quality.
-q:a – Audio quality for libmp3lame. Range is 0-9 for this encoder. A lower value is a higher quality.
Also see
FFmpeg and x264 Encoding Guide
Encoding VBR (Variable Bit Rate) mp3 audio

ffmpeg vcodec copy does not work when start/duration is messed up in video file

My Video file shows below meta-data with ffprobe/ffmpeg:
Duration: 00:44:27.52, start: 1333.760000, bitrate: 335 kb/s
Stream #0.0(und): Video: h264 (Main), yuv420p, 640x480, 25 tbr, 90k tbn, 50 tbc
Note: The file does not contain audio.
I am trying to convert this video file to other video file, using ffmpeg/avconv.
This works: (but encodes h.264 video to mpeg4)
ffmpeg -i input.mp4 output.mp4
& it generates output file of proper duration (44:27 - 1333 seconds = 22:14)
This does not work:
ffmpeg -i input.mp4 -vcodec copy output.mp4
Generates file without video.
The output contains:
$ avconv -i input.mp4 -vcodec copy output.mp4
avconv version 0.8.9-6:0.8.9-0ubuntu0.13.10.1, Copyright (c) 2000-2013 the Libav developers
built on Nov 9 2013 19:09:46 with gcc 4.8.1
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'input.mp4':
Metadata:
major_brand : dash
minor_version : 0
compatible_brands: iso6avc1mp41
creation_time : 2014-01-19 22:43:21
Duration: 00:44:27.52, start: 1333.760000, bitrate: 335 kb/s
Stream #0.0(und): Video: h264 (Main), yuv420p, 640x480, 25 tbr, 90k tbn, 50 tbc
Metadata:
creation_time : 2014-01-19 22:43:21
Output #0, mp4, to 'output.mp4':
Metadata:
major_brand : dash
minor_version : 0
compatible_brands: iso6avc1mp41
creation_time : 2014-01-19 22:43:21
encoder : Lavf53.21.1
Stream #0.0(und): Video: ![0][0][0] / 0x0021, yuv420p, 640x480, q=2-31, 90k tbn, 90k tbc
Metadata:
creation_time : 2014-01-19 22:43:21
Stream mapping:
Stream #0:0 -> #0:0 (copy)
Press ctrl-c to stop encoding
frame= 0 fps= 0 q=-1.0 Lsize= 0kB time=10000000000.00 bitrate= 0.0kbits/s
video:0kB audio:0kB global headers:0kB muxing overhead inf%
FFmpeg development is very active
When experiencing an issue it is best to get a new build of ffmpeg from FFmpeg to ensure that you are not encountering a bug that has already been fixed.
Ubuntu uses a fork
Ubuntu does not use ffmpeg from FFmpeg, but an old, fake version from a fork. See Who can tell me the difference and relation between ffmpeg, libav, and avconv?
Get ffmpeg
You can:
Simply download a build of ffmpeg, or
Follow a step-by-step guide to compile ffmpeg.
Using the build
The build is easy. You just download, extract, and execute (notice the ./ before ffmpeg):
wget http://ffmpeg.gusari.org/static/32bit/ffmpeg.static.32bit.$(date +"%F").tar.gz
tar xzvf ffmpeg.static.32bit.$(date +"%F").tar.gz
./ffmpeg -i input -codec copy -map 0 output
Compiling
Compiling ffmpeg allows you to customize it how you like. The compile guide is non-invasive and easy to undo.
Reporting a bug
If a recent build still has the suspected bug then you can get help at the ffmpeg-user mailing list, or perform a search at the FFmpeg Bug Tracker and report it if it is a new bug. If you report the bug make sure to:
Check that you are using a recent build.
Provide the complete ffmpeg command and the complete ffmpeg console output.
Provide all necessary samples.
Use the minimal command that still shows the issue.
Provide any additional information that is useful for others who will attempt to duplicate the issue.

Resources