Created
December 2, 2013 05:49
-
-
Save angelbotto/7745655 to your computer and use it in GitHub Desktop.
Create gif from video .... #newproject
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl | |
# Quick script to convert a video file to a GIF based on time indicators. | |
# Inspired by the ugly Bash script at http://www.davidgouveia.net/2011/09/how-to-convert-video-to-animated-gifs-from-a-linux-console/ | |
# See `vid2gif --help` for more info. | |
use strict; | |
use warnings; | |
use diagnostics; # useful for debugging; | |
use feature 'say'; # beats print; | |
use Getopt::Long; # for parsing command-line options; | |
use File::Temp; # for tempdirs to store scratch files; | |
use File::Find; # for traversing directories and pruning files; | |
use File::Spec; # for converting relative paths to absolute paths; | |
$|++; # disable line-buffering, for real-time output; | |
my $usage = <<'END'; | |
vid2gif | |
Convert a video file to an animated GIF. Accepts arguments for start time | |
of GIF in the video file, length of video segment to convert to GIF, and | |
resolution for the product GIF. Provides sane defaults for all of these, too. | |
Usage: | |
vid2gif --start 00:01:10 # begin GIF at time HH::MM::SS | |
vid2gif --length 2 # GIF should include 2 seconds of video | |
vid2gif --resolution 425x320 # reformat GIF to given dimensions | |
vid2gif --output # name the product GIF | |
vid2gif --help # show this usage information | |
vid2gif --start 00:00:07 --length 7 --resolution 50x50 video.mp4 | |
Supported options: | |
-s, --start # begin GIF at time (HH:MM:SS format) | |
-l, --length # number of seconds of video to convert to GIF | |
-r, --resolution # GIF should be rendered in given dimensions (640x480 format) | |
-o, --output # GIF should be named with the specified string | |
-h, --help # show this usage information | |
-v, --verbose # enable chatty output | |
END | |
GetOptions( | |
'start|s=s' => \my $start_time, | |
'resolution|r=s' => \my $resolution, | |
'length|l=s' => \my $length, | |
'output|o=s' => \my $output_file, | |
'help|h|usage|?' => \my $help, | |
'verbose|v' => \my $verbose, | |
) or die "$usage"; | |
check_options(); # run options-checking subroutine; | |
my $video_file = pop @ARGV or die "$usage"; # grab video file as last element on command line; | |
my $tempdir = File::Temp->newdir # create temporary directory for writing image files to; | |
or die "Could not create temporary directory $!"; # die on failure; | |
print "Generating intermediate images... " if $verbose; # chatty output; | |
system( "mplayer -quiet -ao null -ss $start_time -endpos $length $video_file -vo jpeg:outdir=$tempdir/ $resolution >/dev/null 2>&1" ) == 0 | |
or die "Could not generate temporary images; please manually cleanup $tempdir."; # die on failure | |
say "done." if $verbose; # chatty output; | |
my $orig_count = `ls $tempdir | wc -l`; # grab original file count; | |
print "Optimizing base frame count... " if $verbose; # chatty output; | |
my $counter = 1; # initialize counter for use while iterating over files; | |
find( | |
{ | |
wanted => sub { # declare &wanted subroutine anonymously; | |
unlink if $counter % $length; # keep 25% of the files, toss the rest; | |
$counter++; # increment that counter; | |
}, | |
preprocess => sub { # prepare directory before running &wanted subroutine; | |
return sort @_; # sort all filenames in this directory, so destruction is ordered; | |
} | |
}, | |
$tempdir # declare temp directory as target for this find operation; | |
); | |
my $final_count = `ls $tempdir | wc -l`; # grab new file count; | |
chomp( $orig_count, $final_count ); # remove pesky trailing newline; | |
say "$orig_count -> $final_count, done." if $verbose; # chatty output; | |
print "Assembling full animated GIF... " if $verbose; # chatty output; | |
my $delay = $length > 10 ? $length : 10; # check whether more than 10 seconds of video conversion was requested; | |
system( "convert -delay $delay $tempdir/*.jpg '$output_file'" ) # shell out to convert to run conversion; | |
== 0 or die "Could not create assembled GIF image."; # die on failure; | |
say "done." if $verbose; # chatty output; | |
say "View the file at: $output_file" if $verbose; | |
File::Temp::cleanup; # remove any unused temp files; | |
system( "rm -rf $tempdir" ) # hard-remove the temp directory, because cleanup() doesn't work if there are files; | |
== 0 or die "Failed to clean up temp directory at $tempdir"; # die on failure to remove temp directory; | |
sub check_options { # run initialization on command-line options, set defaults; | |
if ( $resolution ) { # check whether user specified a custom resolution for GIF; | |
$resolution = '1280x720' if $resolution =~ m/^full$/; # expand to full resolution if asked; | |
$resolution =~ s/x/:/; # swap in a colon where x is more user-friendly; | |
$resolution = "-vf scale=$resolution"; # prepend option title if user requested certain resolution; | |
} | |
else { # if no custom resolution was requested; | |
$resolution = '-vf scale=425:320'; # set to small format, which can be overridden with 'full' option to --resolution | |
} | |
if ( $output_file ) { # check whether user specified a custom filename for product GIF; | |
$output_file .= '.gif' # append GIF file extension; | |
unless $output_file =~ m/\.gif$/i; # don't append if file extension is there already; | |
} | |
else { # if user did not specify a custom name for product GIF; | |
$output_file = 'output.gif'; # choose a rather bland default; | |
} | |
$output_file = File::Spec->rel2abs( $output_file ); # expand to fullpath for better feedback; | |
$start_time = '00:00:00' unless $start_time; # set default to start at beginning of GIF; | |
$length = 5 unless $length; # set default of 5 seconds to loop; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment