Skip to content

Instantly share code, notes, and snippets.

@angelbotto
Created December 2, 2013 05:49
Show Gist options
  • Save angelbotto/7745655 to your computer and use it in GitHub Desktop.
Save angelbotto/7745655 to your computer and use it in GitHub Desktop.
Create gif from video .... #newproject
#!/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