add license file
[undvd.git] / encvid
blobe5bceb48408e2b44aa0425a5efad77870c2e383b
1 #!/usr/bin/perl
3 # Author: Martin Matusiak <numerodix@gmail.com>
4 # Licensed under the GNU Public License, version 3.
6 use strict;
7 use Getopt::Long qw(:config no_ignore_case);
9 use FindBin qw($RealBin);
10 use lib $RealBin;
11 use colors;
12 use common qw(:DEFAULT $suite $defaults $tools);
15 my $usage = "Usage: " . s_b($suite->{tool_name}) . " "
16 . s_bb("<file(s)>")
17 . " [" . s_b("options") . "]
18 <file(s)> files to encode\n
19 --start start after this many seconds (usually for testing)
20 -e --end end after this many seconds (usually for testing)\n
21 -C do sanity check (check for missing tools)
22 -z --adv <show advanced options>
23 --version show " . $suite->{suite_name} . " version\n";
25 my $adv_usage = "Advanced usage: " . s_b($suite->{tool_name}) . " "
26 . s_bb("<file(s)>")
27 . " [" . s_b("options") . "]
28 -o --size output file size in mb (integer value)
29 --bpp bits per pixel (float value)
30 -1 force 1-pass encoding
31 -2 force 2-pass encoding
32 -c --crop autocrop video
33 -r --scale scale video to x:y (integer value or " . s_bb("0") . ") or " . s_bb("off") . " to disable
34 -f --smooth use picture smoothing filter
35 -D --dryrun dry run (display encoding parameters without encoding)\n
36 --cont set container format
37 --acodec set audio codec
38 --vcodec set video codec\n";
40 my ($opts_start, $opts_end, $target_size, $bpp, $autocrop);
41 my ($dry_run, $opts_acodec, $opts_vcodec, $opts_cont);
43 my $custom_scale = "off";
44 my $target_passes = 1;
45 my $prescale = $defaults->{prescale};
46 my $postscale = $defaults->{postscale};
48 my $parse = GetOptions(
49 "start=f"=>\$opts_start,
50 "e|end=f"=>\$opts_end,
52 "C"=> sub { init_cmds(1); exit; },
53 "z|adv"=> sub { print $adv_usage; exit; },
54 "version"=>\&print_version,
56 "o|size=i"=>\$target_size,
57 "bpp=f"=>\$bpp,
58 "1"=> sub { $target_passes = 1; },
59 "2"=> sub { $target_passes = 2; },
60 "c|crop"=> sub { $autocrop = 1; },
61 "r|scale=s"=>\$custom_scale,
62 "f|smooth"=> sub { $prescale .= "spp,"; $postscale = ",hqdn3d$postscale"; },
63 "D|dryrun"=> sub { $dry_run = 1; },
65 "cont=s"=>\$opts_cont,
66 "acodec=s"=>\$opts_acodec,
67 "vcodec=s"=>\$opts_vcodec,
70 print_tool_banner();
72 if (! $parse) {
73 print $usage;
74 exit 2;
77 my @startpos = ("-ss", $opts_start ? $opts_start : 0);
78 my @endpos;
79 if ($opts_end) {
80 push(@endpos, "-endpos", $opts_end);
83 my @files = @ARGV;
84 if (scalar @files < 1) {
85 nonfatal("No files to encode, exiting");
86 print $usage;
87 exit 2;
91 init_logdir();
94 # Set container and codecs
96 my $container = $opts_cont ? $opts_cont : $defaults->{container};
97 my ($audio_codec, $video_codec, $ext, @cont_args) = set_container_opts($opts_acodec,
98 $opts_vcodec, $container);
100 print " - Output format :: "
101 . "container: " . s_it($container)
102 . " audio: " . s_it($audio_codec)
103 . " video: " . s_it($video_codec) . "\n";
106 # Display dry-run status
108 if ($dry_run) {
109 print " * Performing dry-run\n";
110 print_title_line(1);
113 foreach my $file (@files) {
115 if (! -e $file) {
116 nonfatal("File %%%$file%%% does not exist");
117 next;
118 } elsif (-d $file) {
119 nonfatal("%%%$file%%% is a directory");
120 next;
123 my $title_name = $file;
124 $title_name =~ s/^(.*)\..*$/$1/g;
127 # Display encode status
129 if (! $dry_run) {
130 print " * Now encoding file " . s_bb(trunc(38, 1, $file, "..."));
131 if ($opts_start and $opts_end) {
132 print " [" . s_bb($opts_start) . "s - " . s_bb($opts_end) . "s]";
133 } elsif ($opts_start) {
134 print " [" . s_bb($opts_start) . "s -> ]";
135 } elsif ($opts_end) {
136 print " [ -> " . s_bb($opts_end) . "s]";
138 print "\n";
142 # Extract information from the title
144 my $title = examine_title($file);
146 # Init encoding target info
148 my $ntitle = copy_hashref($title);
149 $ntitle->{aformat} = $audio_codec;
150 $ntitle->{vformat} = $video_codec;
151 $ntitle->{filename} = "$title_name.$ext";
154 # Do we need to crop?
156 my $crop_arg;
157 if ($autocrop) {
158 my $est = get_crop_eta($ntitle->{length}, $ntitle->{fps});
159 print " + Finding out how much to crop... (est: ${est}min)\r";
160 my ($width, $height);
161 ($width, $height, $crop_arg) = crop_title($file);
162 if (! $width or ! $height or ! $crop_arg) {
163 fatal("Crop detection failed");
165 $ntitle->{width} = $width;
166 $ntitle->{height} = $height;
169 # Find out how to scale the dimensions
171 my ($width, $height) =
172 scale_title($ntitle->{width}, $ntitle->{height}, $custom_scale);
173 $ntitle->{width} = $width;
174 $ntitle->{height} = $height;
175 my $scale_arg = "scale=$width:$height";
177 # Estimate filesize of audio
179 $ntitle->{abitrate} = set_acodec_opts($container, $ntitle->{aformat},
180 $ntitle->{abitrate}, 1);
181 my $audio_size = compute_media_size($ntitle->{length}, $ntitle->{abitrate});
182 my @acodec_args = set_acodec_opts($container, $ntitle->{aformat},
183 $ntitle->{abitrate});
185 # Decide bpp
187 if ($bpp) {
188 $ntitle->{bpp} = $bpp;
189 } elsif ($target_size) {
190 my $video_size = $target_size - $audio_size;
191 $video_size = 1 if $video_size <= 0;
192 $ntitle->{bpp} = compute_bpp($ntitle->{width}, $ntitle->{height},
193 $ntitle->{fps}, $ntitle->{length}, $video_size);
194 } else {
195 $ntitle->{bpp} = set_bpp($video_codec, $target_passes);
198 # Reset the number of passes based on the bpp
200 if ($target_passes) {
201 $ntitle->{passes} = $target_passes;
202 } else {
203 $ntitle->{passes} = set_passes($video_codec, $ntitle->{bpp});
206 # Compute bitrate
208 $ntitle->{vbitrate} = compute_vbitrate($ntitle->{width},
209 $ntitle->{height}, $ntitle->{fps}, $ntitle->{bpp});
212 # Dry run
214 if ($dry_run) {
216 # Estimate output size
218 if ($target_size) {
219 $ntitle->{filesize} = $target_size;
220 } else {
221 my $video_size = compute_media_size($ntitle->{length},
222 $ntitle->{vbitrate});
223 $ntitle->{filesize} = int($video_size + $audio_size);
226 $ntitle->{filename} = "$title_name.$container";
228 print_title_line(0, $title);
229 print_title_line(0, $ntitle);
232 # Encode video
234 } else {
236 for (my $pass = 1; $pass <= $ntitle->{passes}; $pass++) {
237 my @vcodec_args = set_vcodec_opts($ntitle->{vformat},
238 $ntitle->{passes}, $pass, $ntitle->{vbitrate});
240 my @args = (@startpos, @endpos);
241 push(@args, "-vf", "${crop_arg}${prescale}${scale_arg}${postscale}");
242 push(@args, "-oac", @acodec_args);
243 push(@args, "-ovc", @vcodec_args);
244 push(@args, "-of", @cont_args);
246 run_encode(\@args, $file, $title_name, $ext, $ntitle->{length},
247 $ntitle->{passes}, $pass);
250 if (-f "$title_name.$ext.partial") {
251 rename("$title_name.$ext.partial", "$title_name.$ext");
254 if (-f "divx2pass.log") {
255 unlink("divx2pass.log");
258 remux_container($title_name, $ext, $ntitle->{fps}, $container,
259 $ntitle->{aformat}, $ntitle->{vformat});