Since I got an iPhone back when they were new, I've been using a commercial application to convert movies and TV shows from the web for it. It runs on my old laptop, and converting any given video takes about five times longer than the duration of the video. I lived with it since it worked well and I didn't want to try to figure out how to use a command line tool on my faster Linux box.
Recently I got every episode of Buffy the Vampire Slayer in some format that my commercial application couldn't understand, and I was forced to go to the trusty command line. Those command lines being what they are, I naturally wrapped it all up in Perl.
One big problem I had was to get rid of the (Danish) subtitles, so that's part of this code's behavior. Otherwise, it simply takes what you give it and scales it down to the iPhone's resolution and reencodes it to an .m4v file. The gory details are in POD, readily available via Pod::Usage.
Enjoy!
Update: There are a couple of details I left out.
It uses mencoder to do the actual work.
It can fork multiple concurrent jobs to take advantage of multiple cores using code derived from tilly's Run commands in parallel.
#!/usr/bin/perl use strict; use warnings; use 5.010; use File::Find; use English '-no_match_vars'; use Getopt::Long; use Pod::Usage; my %OPT = ( unlink => 0, loud => 0, quiet => 0, abits => 128, vbits => 800, jobs => 1, ); Getopt::Long::Configure('bundling'); GetOptions( 'quiet|q' => \$OPT{quiet}, 'loud' => \$OPT{loud}, 'unlink|delete' => \$OPT{unlink}, 'audio-bitrate=i' => \$OPT{abits}, 'video-bitrate=i' => \$OPT{vbits}, 'jobs|j=i' => \$OPT{jobs}, 'help|h|?' => sub { pod2usage(1) }, 'man' => sub { pod2usage( -exitstatus => 0, -verbose => 2 ); }, ) or pod2usage(2); my @dirlist = grep -d, @ARGV; my @filelist = grep -f, @ARGV; if ( ! @ARGV ) { @dirlist = ( '.' ); } if ( @dirlist ) { find( \&wanted, @dirlist ); } if ( $OPT{jobs} > 1 ) { convert_many( $OPT{jobs}, sort @filelist ); } else { foreach my $filename ( sort @filelist ) { convert( $filename ); } } exit; # http://perlmonks.org/?node_id=28870 sub convert_many { my ( $jobs_wanted, @filelist ) = @_; my %running; while ( @filelist || %running ) { if ( @filelist && $jobs_wanted > scalar keys %running ) { my $file = shift @filelist; my $pid = fork // die "Can't fork: $!"; if ( $pid ) { # parent $running{ $pid } = $file; } else { # child convert( $file ); exit; } } else { my $pid = wait; if ( ! defined delete $running{ $pid } ) { die "reaped unknown child PID '$pid'"; } if ( $CHILD_ERROR ) { die "child exited with status ($CHILD_ERROR)"; } } } return; } # From the mplayer man page: # It plays most MPEG/VOB, AVI, ASF/WMA/WMV, RM, QT/MOV/MP4, Ogg/OGM, # MKV, VIVO, FLI, NuppelVideo, yuv4mpeg, FILM and RoQ files, # supported by many native and binary codecs. You can watch VCD, # SVCD, DVD, 3ivx, DivX 3/4/5, WMV and even H.264 movies, too. sub wanted { return if ! -f; return if ! m{ \. (?: avi | mkv | mpe?g | wmv | asf | rm | qt | mov | mp4 | ogm | fli ) \z }xmsi; push @filelist, $File::Find::name; return; } sub convert { my ( $src_file ) = @_; my $src_file_quoted = shell_quote( $src_file ); ( my $new_file = $src_file ) =~ s{ \. [^.]+ \z }{.m4v}xms; if ( $new_file eq $src_file ) { die "renamed '$src_file' to the same filename"; } my $new_file_quoted = shell_quote( $new_file ); # # Many of these options came from a web page I've since lost. # To remove subtitles, I added -noass and -noautosub, but that # didn't work. What worked was to add 'expand' to the end of # the -vf filter chain and add -noautoexpand to keep mencoder # from putting its own expand at the end (which added subtitles). # my $cmd = join q{ }, qq{mencoder $src_file_quoted -o $new_file_quoted}, qq{-vf dsize=480:320:0,scale=0:0,expand -noautoexpand}, qq{-oac faac -faacopts mpeg=4:object=2:raw:br=$OPT{abits}}, qq{-ovc x264 -x264encopts nocabac:level_idc=30:bframes=0:globa +l_header:bitrate=$OPT{vbits}:frameref=6:partitions=all}, q{-of lavf -lavfopts format=mp4}, q{-noass -noautosub}, (q{-really-quiet > /dev/null 2> /dev/null}) x! $OPT{loud} ; if ( ! $OPT{quiet} ) { say scalar localtime(), " $new_file_quoted"; } system( "$cmd" ) == 0 or die "MENCODER GAVE ERROR EXIT STATUS ($CHILD_ERROR) for $cm +d\n"; if ( $OPT{unlink} ) { unlink $src_file or die "Can't unlink '$src_file': $!"; } return; } sub shell_quote { my ($s) = @_; $s //= q{}; $s =~ s{ ([\\"`\$]) }{\\$1}xmsg; return qq{"$s"}; } __END__ =pod =head1 NAME mk-iphone-vid.pl - Convert videos for the iPhone =head1 SYNOPSIS mk-iphone-vid.pl [options] [files/directories] Options: -h, --help brief help message --man full documentation --unlink delete originals after converting -j, --jobs number of conversions to run at once --audio-bitrate set output audio bitrate --video-bitrate set output video bitrate -q, --quiet output only errors --loud output progress and more =head1 DESCRIPTION This uses mencoder to convert videos it can read into videos that can play on an Apple iPhone. =head1 USAGE Just run this with a list of files and/or directories as arguments. It will traverse directories recursively to find video files. If no arguments are given, it will default to looking in the current directory. All files it finds are converted to .m4v files suitable to play on an Apple iPhone. By default it will output one line per file with the date and output filename when processing of that file starts. Any file explicitly listed on the command line will be processed regardless of its name. Files discovered through directory traversal must match a list of file extensions. Output file names are the same as the input file names with the extension changed .m4v. =head1 OPTIONS =over 8 =item B<--help> =item B<-h> Print a brief help message and exit. =item B<--man> Print the full documentation and exit. =item B<--delete> =item B<--unlink> Delete the original file after a successful conversion. =item B<--jobs> =item B<-j> Specifies the number of conversions to run simultaneously. =item B<--audio-bitrate> Default: 128 Set the bitrate for audio output. =item B<--video-bitrate> Default: 800 Set the bitrate for video output. =item B<--quiet> =item B<-q> Output only errors during processing. =item B<--loud> This allows the normal output from mencoder during encoding. =back =head1 DEPENDENCIES This uses mencoder to do the real work, so that has to be in your path. The mencoder invocation uses AAC for audio encoding and libavformat for the container format, so those have to be available. =head1 BUGS AND LIMITATIONS There really is not nearly the control available that mencoder provides if used directly. In particular, the code is written explicitly to try to strip subtitles where possible. The list of file extensions that it will recognize as videos during searches is hard coded and might not be comprehensive. =head1 DIAGNOSTICS If mencoder exits with a non-zero exit status, processing will halt. Without the B<--loud> option, you might not know why (mencoder's output is normally supressed). =over =item MENCODER GAVE ERROR EXIT STATUS ($CHILD_ERROR) for $cmd This is the general error any time mencoder fails for any reason. The mencoder command line is given at the end in case you want to try it manually or look for obvious problems there. =item renamed '$src_file' to the same filename This probably means that the source file name ends in .m4v. It's refusing to overwrite it. =item Can't fork Try running without the B<--jobs> option. =item reaped unknown child PID '$pid' A call to wait() got back a child process ID for a child it does not remember spawning. This should never happen. =item child exited with status ($CHILD_ERROR) If running with multiple B<--jobs>, this is the error that appears if a job fails for some reason. Hopefully there's a more descriptive message above this one. =item Can't unlink '$src_file' Try running without the B<--unlink> option. For some reason, it can't delete the original files when it's done with them. =back =head1 COPYRIGHT AND LICENSE Copyright (c) 2009 Kyle Hasselbacher. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 AUTHOR Kyle Hasselbacher <kyle@cpan.org> =cut
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: Convert videos for my iPhone
by telemachus (Friar) on Mar 02, 2009 at 16:34 UTC | |
Re: Convert videos for my iPhone
by generator (Pilgrim) on Apr 27, 2009 at 04:55 UTC | |
by kyle (Abbot) on Apr 28, 2009 at 11:46 UTC | |
Re: Convert videos for my iPhone
by kyle (Abbot) on Dec 16, 2009 at 16:18 UTC |