Permalink
Cannot retrieve contributors at this time
Fetching contributors…
| #!/usr/bin/perl | |
| # ************************************************************ | |
| # * gifmaker - A tool for making animated GIFs from video | |
| # files. This works as a wrapper around | |
| # FFmpeg and ImageMagick's convert. | |
| # | |
| # For more details see: | |
| # http://www.leshylabs.com/blog/dev/2013-08-04-Making_Animated_GIFs_from_the_Linux_Command_Line.html | |
| # ************************************************************ | |
| # | |
| # Copyright (c) 2013, Leshy Labs LLC | |
| # All rights reserved. | |
| # | |
| # Redistribution and use in source and binary forms, with or without | |
| # modification, are permitted provided that the following conditions | |
| # are met: | |
| # * Redistributions of source code must retain the above copyright | |
| # notice, this list of conditions and the following disclaimer. | |
| # * Redistributions in binary form must reproduce the above | |
| # copyright notice, this list of conditions and the following | |
| # disclaimer in the documentation and/or other materials provided | |
| # with the distribution. | |
| # * The names names of the authors may not be used to endorse or | |
| # promote products derived from this software without specific | |
| # prior written permission. | |
| # | |
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS | |
| # CONTRIBUTERS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
| # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
| # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
| # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS | |
| # CONTRIBUTERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
| # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
| # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
| # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
| # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| # SUCH DAMAGE. | |
| # | |
| # Changes | |
| # 8/9/13 - Added some default optimizations to convert | |
| use strict; | |
| use File::Temp qw/ tempdir /; | |
| my $CONFIG = { | |
| ffmpeg => 'ffmpeg', # ffmpeg binary | |
| convert => 'convert', # ImageMagick convert binary | |
| output_file => 'out.gif', # Default file to write to | |
| default_fps => 10, # Default frames per second | |
| ffmpeg_args => '', # Extra arguments for ffmpeg | |
| convert_args => '-layers removeDups -layers Optimize' # Extra arguments for convert | |
| }; | |
| sub usage { | |
| die "USAGE: $0 [input_file] [output_file] [frames_per_second]\n" . | |
| " input_file - The input video file to convert (Required)\n" . | |
| " output_file - The GIF file to be created (Default=$CONFIG->{output_file})\n" . | |
| " frames_per_second - The GIF's frame rate. (Default=$CONFIG->{default_fps})\n\n" . | |
| "ENVIRONMENT:\n" . | |
| " FFMPEG_ARGS - Extra arguments for ffmpeg\n" . | |
| " CONVERT_ARGS - Extra arguments for ImageMagick's convert command\n"; | |
| } | |
| sub verify { | |
| # Verify all parameters and settings before proceeding | |
| my ($input_file, $output_file, $fps) = @_; | |
| if (! -e $input_file) { | |
| die "ERROR: Input file '$input_file' does not exist.\n"; | |
| } | |
| elsif ($fps !~ /^\d{1,2}$/ || $fps == 0) { | |
| die "ERROR: FPS value '$fps' is not valid. A number from 1 to 99 must be provided\n"; | |
| } | |
| elsif ($output_file !~ /\.gif$/i) { | |
| die "ERROR: Output file must use the '.gif' extension\n"; | |
| } | |
| elsif (-e $output_file) { | |
| die "ERROR: Output file '$output_file' already exists\n"; | |
| } | |
| } | |
| sub run_command { | |
| my ($command) = @_; | |
| print "*** $command\n"; | |
| system($command); | |
| print "\n"; | |
| if ($? >> 8 != 0) { | |
| die "ERROR: Command did not return a 0 exit status. Aborting.\n"; | |
| } | |
| } | |
| sub make_gif { | |
| my ($input_file, $output_file, $fps) = @_; | |
| my $temp_dir = tempdir(CLEANUP => 1); | |
| my $real_output_file = $output_file; | |
| my $delay = sprintf("%.0f", (100 / $fps)); # Delay value for convert in hundreths of second and rounded | |
| # Protect some special characters | |
| $output_file =~ s/([;\$\\`])/\\\1/g; | |
| run_command("$CONFIG->{ffmpeg} $CONFIG->{ffmpeg_args} $ENV{FFMPEG_ARGS} " . | |
| "-i $input_file -r $fps $temp_dir/frame.\%05d.gif"); | |
| run_command("$CONFIG->{convert} $CONFIG->{convert_args} -loop 0 $ENV{CONVERT_ARGS} " . | |
| "-delay $delay $temp_dir/frame.*.gif $output_file"); | |
| print "Animated gif saved to '$real_output_file'\n"; | |
| } | |
| sub main { | |
| my ($input_file, $output_file, $fps) = @ARGV; | |
| if ($#ARGV < 0 || $#ARGV > 2) { | |
| usage(); | |
| } | |
| # If the arguments are not provided, set the default values | |
| $fps ||= $CONFIG->{default_fps}; | |
| $output_file ||= $CONFIG->{output_file}; | |
| verify($input_file, $output_file, $fps); # Verify all parameters | |
| make_gif($input_file, $output_file, $fps); # Create the animated GIF | |
| } | |
| main(); |