test-ly-files: Display symlink creation, add `-v` to `ln`
[sunny256-utils.git] / enc-mp4
blob7ccf7071eb7686ef956aa296e8d82d903c9590f9
1 #!/usr/bin/env perl
3 #=======================================================================
4 # enc-mp4
5 # File ID: ccf5e412-f742-11dd-b99b-000475e441b9
6 # Encode videos for Nokia N95.
8 # Character set: UTF-8
9 # ©opyleft 2008– Øyvind A. Holm <sunny@sunbase.org>
10 # License: GNU General Public License version 2 or later, see end of
11 # file for legal stuff.
12 #=======================================================================
14 use strict;
15 use warnings;
16 use Getopt::Long;
18 $| = 1;
20 our $Debug = 0;
22 our %Std = (
23 'encoder' => "ffmpeg",
24 'frames-per-second' => 15,
27 our %Opt = (
29 'comment' => "",
30 'debug' => 0,
31 'encoder' => $Std{'encoder'},
32 'force' => 0,
33 'frames-per-second' => $Std{'frames-per-second'},
34 'help' => 0,
35 'output-file' => "",
36 'verbose' => 0,
37 'version' => 0,
41 our $progname = $0;
42 $progname =~ s/^.*\/(.*?)$/$1/;
43 our $VERSION = "0.00";
45 Getopt::Long::Configure("bundling");
46 GetOptions(
48 "comment|c=s" => \$Opt{'comment'},
49 "debug" => \$Opt{'debug'},
50 "encoder|e=s" => \$Opt{'encoder'},
51 "force|f" => \$Opt{'force'},
52 "frames-per-second|fps=i" => \$Opt{'frames-per-second'},
53 "help|h" => \$Opt{'help'},
54 "output-file|o=s" => \$Opt{'output-file'},
55 "verbose|v+" => \$Opt{'verbose'},
56 "version" => \$Opt{'version'},
58 ) || die("$progname: Option error. Use -h for help.\n");
60 $Opt{'debug'} && ($Debug = 1);
61 $Opt{'help'} && usage(0);
62 if ($Opt{'version'}) {
63 print_version();
64 exit(0);
67 if ($#ARGV >= 0) {
68 for (@ARGV) {
69 process_file($_);
71 } else {
72 process_file("-");
75 sub process_file {
76 # {{{
77 my $Filename = shift;
78 D("process_file('$Filename')");
79 my $use_stdin = ($Filename eq "-") ? 1 : 0;
80 my $Comment = length($Opt{'comment'})
81 ? $Opt{'comment'}
82 : "";
83 my $Fps = length($Opt{'frames-per-second'})
84 ? $Opt{'frames-per-second'}
85 : $Std{'frames-per-second'};
86 my $output_file = length($Opt{'output-file'})
87 ? $Opt{'output-file'}
88 : $use_stdin
89 ? "-"
90 : "$Filename.mp4";
91 if ($use_stdin || -e $Filename) {
92 if (-e "$Filename.mp4" && !$Opt{'force'}) {
93 warn("$progname: $Filename.mp4: Will not overwrite existing file. Use --force (-f) option to override.\n");
94 return;
96 msg(1, "Encoding \"$Filename\" to \"$output_file\"...");
97 if ($Opt{'encoder'} eq "ffmpeg") {
98 # Modified version of something found at
99 # <http://www.n95users.com/forum/general-95/2602-howto-convert-avi-nokia-n95-compatible-avi-embedded-subtitle-linux.html>.
100 # Does not keep aspect ratio, fills the entire N95 screen,
101 # but that’s probably better than using 30% of the screen in
102 # extreme cases.
103 my @Cmd = (
104 "ffmpeg",
105 "-i", $Filename, # Input filename
106 "-f", "mp4", # Format
107 "-vcodec", "mpeg4", # Video codec
108 "-b", "250000", # Video bitrate
109 "-r", $Fps, # Frames per second
110 "-s", "320x240", # Frame size
111 "-acodec", "aac", # Audio codec
112 "-ar", "44100", # Audio sampling frequency
113 "-ab", "64", # Audio bitrate in kbit/s
114 "-ac", "2", # Number of audio channels
115 "-me", "epzs", # Motion estimation method (best quality)
116 "-y", # Overwrite output files
117 $output_file # Output filename
119 if (length($Comment)) {
120 splice(@Cmd, 1, 0, "-comment", $Comment);
122 mysyst(@Cmd);
123 } elsif ($Opt{'encoder'} eq "mencoder") {
124 # Recipe created by Tomasz Sterna, found at
125 # <http://notes.xiaoka.com/2008/03/29/encode-mp4-files-for-nokia-n95-with-mencoder/>.
126 # Has sound sync issues.
127 my @Cmd = (
128 "mencoder",
129 "-of", "lavf",
130 "-lavfopts", "format=mp4",
131 "-oac", "lavc",
132 "-ovc", "lavc",
133 "-lavcopts", "aglobal=1:vglobal=1:acodec=libfaac:abitrate=128:vcodec=mpeg4:keyint=25",
134 "-ofps", $Fps,
135 "-af", "lavcresample=44100",
136 "-vf", "harddup,scale=320:-3",
137 "-mc", "0",
138 "-noskip",
139 $Filename,
140 "-o",
141 $output_file
143 if (length($Comment)) {
144 splice(@Cmd, 1, 0, "-info", "comment=$Comment");
146 mysyst(@Cmd);
147 } else {
148 die("$progname: $Opt{'encoder'}: Unknown --encoder value.\n");
150 } else {
151 warn("$progname: $Filename: File not found");
153 return;
154 # }}}
155 } # process_file()
157 sub mysyst {
158 # Customised system() {{{
159 my @Args = @_;
160 my $system_txt = sprintf("system(\"%s\");", join("\", \"", @Args));
161 msg(2, "Executing \"" . join(" ", @_) . "\"...");
162 system(@_);
163 # }}}
164 } # mysyst()
166 sub print_version {
167 # Print program version {{{
168 print("$progname v$VERSION\n");
169 # }}}
170 } # print_version()
172 sub usage {
173 # Send the help message to stdout {{{
174 my $Retval = shift;
176 if ($Opt{'verbose'}) {
177 print("\n");
178 print_version();
180 print(<<END);
182 Usage: $progname [options] [file [files [...]]]
184 Encode movies for the Nokia N95. If no files are specified, the program
185 encodes from stdin to stdout.
187 Options:
189 -c x, --comment x
190 Use x as comment in the encoded file.
191 -e x, --encoder x
192 Use encoder x:
193 ffmpeg
194 mencoder (may have audio/video sync problems)
195 Default: $Std{'encoder'}
196 --fps x, --frames-per-second x
197 Generate video with x frames per second.
198 Default: $Std{'frames-per-second'}.
199 -h, --help
200 Show this help.
201 -f, --force
202 Overwrite existing files (input filename with .mp4 extension).
203 -o x, --output-filename x
204 Use x as output filename.
205 -v, --verbose
206 Increase level of verbosity. Can be repeated.
207 --version
208 Print version information.
209 --debug
210 Print debugging messages.
213 exit($Retval);
214 # }}}
215 } # usage()
217 sub msg {
218 # Print a status message to stderr based on verbosity level {{{
219 my ($verbose_level, $Txt) = @_;
221 if ($Opt{'verbose'} >= $verbose_level) {
222 print(STDERR "$progname: $Txt\n");
224 # }}}
225 } # msg()
227 sub D {
228 # Print a debugging message {{{
229 $Debug || return;
230 my @call_info = caller;
231 chomp(my $Txt = shift);
232 my $File = $call_info[1];
233 $File =~ s#\\#/#g;
234 $File =~ s#^.*/(.*?)$#$1#;
235 print(STDERR "$File:$call_info[2] $$ $Txt\n");
236 return("");
237 # }}}
238 } # D()
240 __END__
242 # Plain Old Documentation (POD) {{{
244 =pod
246 =head1 NAME
250 =head1 SYNOPSIS
252 [options] [file [files [...]]]
254 =head1 DESCRIPTION
258 =head1 OPTIONS
260 =over 4
262 =item B<-h>, B<--help>
264 Print a brief help summary.
266 =item B<-v>, B<--verbose>
268 Increase level of verbosity. Can be repeated.
270 =item B<--version>
272 Print version information.
274 =item B<--debug>
276 Print debugging messages.
278 =back
280 =head1 BUGS
284 =head1 AUTHOR
286 Made by Øyvind A. Holm S<E<lt>sunny@sunbase.orgE<gt>>.
288 =head1 COPYRIGHT
290 Copyleft © Øyvind A. Holm E<lt>sunny@sunbase.orgE<gt>
291 This is free software; see the file F<COPYING> for legalese stuff.
293 =head1 LICENCE
295 This program is free software: you can redistribute it and/or modify it
296 under the terms of the GNU General Public License as published by the
297 Free Software Foundation, either version 2 of the License, or (at your
298 option) any later version.
300 This program is distributed in the hope that it will be useful, but
301 WITHOUT ANY WARRANTY; without even the implied warranty of
302 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
303 See the GNU General Public License for more details.
305 You should have received a copy of the GNU General Public License along
306 with this program.
307 If not, see L<http://www.gnu.org/licenses/>.
309 =head1 SEE ALSO
311 =cut
313 # }}}
315 # vim: set fenc=UTF-8 ft=perl fdm=marker ts=4 sw=4 sts=4 et fo+=w :