How To Wiki
Advertisement

If you have a ton of videos and you are running out of room on your hard drive. You can use this script to reduce the file size of every video file in a directory.

Required[]

Description[]

This script uses mencoder to re-encode each file using the XVID video codec, and the mp3lame audio codec. The default settings are video quality #5 and 96kbs audio bitrate. 96kbs audio bitrate is fine for most things. Video quality #5 is fine for most low-action videos, like Law and Order type, or if you don't mind it getting chunky during explosions.

Features
  • Ignores non-video files
  • Copies instead of encodes files smaller than 100MB, so it won't compress already small files (size can be changed)
  • Moves new files to a directory
    • default small
  • Creates a log: /tmp/video_dir_smallify.log
  • Can set process priority
  • Displays estimate of time left based on last encoding time.
  • Displays final summary
Statistic
  • Average file size: 140MB for a 45min video
  • Compression time: 20m to compress a 45m show, based on a 3 GHz computer


Example of output[]

Detected 3 video files.  
Roughly est. 1.5 h to completion, based on encoding time 30min/file.
Creating 'small' directory
To Exit before completion hit Ctrl-C twice.

Smallifying: American.Dad.S05E01.In.Country.Club.PDTV.XviD-FQM.avi (1 of 3 files)
    Encoding video...  
    Encoding finished.
    Original file size: 175MB
    Final file size: 84 MB
    Encoding took 0.2 h
Smallifying: American.Dad.S05E02.Moon.Over.Isla.Island.PDTV.XviD-FQM.avi (2 of 3 files)
    Updated est. time left 0.4 h, based on last encoding 
    Encoding video...  
    Encoding finished.
    Original file size: 175MB
    Final file size: 69 MB
    Encoding took 0.2 h
Smallifying: American.Dad.S05E03.PDTV.XviD-2HD.avi (3 of 3 files)
    Updated est. time left 0.2 h, based on last encoding 
    Encoding video...  
    Encoding finished.
    Original file size: 175MB
    Final file size: 65 MB
    Encoding took 0.2 h

==========================================
Summary of encoding
------------------------------------------
American.Dad.S05E01.In.Country.Club.PDTV.XviD-FQM.avi
   Original Size: 175 MB Final: 84 MB
American.Dad.S05E02.Moon.Over.Isla.Island.PDTV.XviD-FQM.avi
   Original Size: 175 MB Final: 69 MB
American.Dad.S05E03.PDTV.XviD-2HD.avi
   Original Size: 175 MB Final: 65 MB

-----------------------------------------------
Original dir: shrink/
Final dir: shrink//small
Log file: /tmp/video_dir_smallify.log
Total encoding time: 0.5 h

All done.
Before deleting old files:
 Check a few files
 Check log for errors
 Look at the file sizes for inconsistency

Script[]

#!/usr/bin/perl 
#
use Time::HiRes qw ( time );
##################################
# Name: Video directory Smallifier
# Version: 0.2
# Creator: Jeff Israel
# Date: Oct 21, 2009
# License: GPL 3.0
# Description: This script reduces the file size of every video file 
#  in a directory
# Requirements: mencoder (part of mplayer), XVID library, mp3lame
# Usage: video_dir_smallify.pl [video directory]
# Example: video_dir_smallify.pl /pub/video/tv/castle/

##################################
# Configure

$video_quality=5; # 5 is good for most low action
# $video_bitrate=500; # not used, adjust $video_quality
$audio_bitrate=96;

$video_codec='xvid'; # currently only supports _xvid_
$audio_codec='libmp3lame'; # currently only supports _libmp3lame_

$video_output_dir = 'small'; # where the new videos go, relative dir, example input='videos/' output='videos/small/'
$min_file_size =100; # skips encoding video if small than x in MB, recomended 150MB for 1h videos, 100MB for 30m videos 

$niceness = '19'; # 19 is lowest priority, 0 is highest
$log_file = '/tmp/video_dir_smallify.log';

@video_file_extentions = ("avi","rm","mpg","mpeg","asf","ram","wmv","mp4","ogg",'ogm',"m4v","mkv",'rmvb','mov','divx'); #will only encode files with these extensions



#####################################
# Code
#
$directory_name = $ARGV[0];

#commands
# if ( $audio_codec eq 'vorbis' ) {
	# $audio_var = "-oac lavc -lavcopts acodec=vorbis:abitrate=$audio_bitrate"}
# if ( $video_codec eq 'xvid') {
	# $video_var = "-ovc lavc -lavcopts vcodec=mpeg4:vbitrate=$video_bitrate:vhq -ffourcc XVID";
# }

$encode_command = "nice -n $niceness mencoder -oac mp3lame -lameopts abr:br=$audio_bitrate -ovc xvid -xvidencopts fixed_quant=$video_quality ";
############################
# Some input error checking

if($directory_name eq ""){
  print "Error: no directory entered.\n the first arg is the directory\n";
  exit;
}

if ( !( -d $directory_name) ){ #check if directory exists
	print "Error: $directory_name is not a directory\n";
	exit;
}
if ( !( -w $directory_name) ){ #check if directory exists
	print "Error: $directory_name is not writeable\n";
	exit;
}

opendir(DIR, "$directory_name"); #precheck if video files in dir
$video_cnt=0;
while (defined($dir = readdir(DIR))) {
	if ( isVideo($dir) ) { 	$video_cnt++; }
} closedir(DIR);
if ( $video_cnt == 0 ) {
	print "Error: not video files in $directory_name\n";
	exit;
}

sub isVideo {	
	# doo
	my $filename = $_[0];
	foreach $ext (@video_file_extentions) {
		if ($filename =~ /$ext$/i) {
#			print "$ext: $filename: match\n";
			return 1;
		} else {
#			print "$ext: $filename: no match\n";
		}
	}
	0;
}
	

$est_time = 0.5 * $video_cnt;
print "Detected $video_cnt video files.  \nRoughly est. $est_time h to completion, based on encoding time 30min/file.\n";

if ( -d "$directory_name/$video_output_dir" ) { #checks to see if new dir exists
	print "Warning: directory, $video_output_dir, exists.  This is OK, but files within $video_output_dir may be overwritten\n";
} else {
	mkdir("$directory_name/$video_output_dir");
	print "Creating \'$video_output_dir\' directory\n";
}

if ( -e $log_file ) {
	my $log_file_old = $log_file . '.old';
	system("mv $log_file $log_file_old");
}

print "To Exit before completion hit Ctrl-C twice.\n\n";
$cnt=0;
$summary="\n\n==========================================\nSummary of encoding\n------------------------------------------\n";
$total_start_time=time;
opendir(DIR, "$directory_name");
$first=1;
while (defined($dir = readdir(DIR))) {
	if ( ($dir ne '.') && ($dir ne '..') && !( -d "$directory_name/$dir" ) ) {
		if ( isVideo($dir) ) { 
			$cnt++;			
			$file_size = (-s "$directory_name/$dir")/1024/1024;
			$file_size =~ s/\..*//;
			if ( $file_size < $min_file_size ) {
				print "Copying instead of re-encoding: $dir < $min_file_size\MB\n";
				system("cp \"$directory_name/$dir\" \"$directory_name/$video_output_dir/$dir\"");
				sleep(1);

			} else {	
				system("rm -f divx2pass.log frameno.avi"); # deleting temp files the might be left over
				$file_name_full = "$directory_name/$dir";
				$new_file_name = "$directory_name/$video_output_dir/$dir.avi";
				print "Smallifying: $dir ($cnt of $video_cnt files)\n";
				if ( $first == 0 ) {
					$time_elapst = sprintf("%.1f",($stop_time - $start_time) / 3600 ); # rounding time to one decimal
					print "    Updated est. time left " . ( 1 + $video_cnt - $cnt)*$time_elapst . " h, based on last encoding \n";
				}
				$first=0;
				$start_time = time;
				# print " Encoding audio...\n";
				# print "$audio_enc_command \"$file_name_full\"";
				# system();
				# print " Encoding video...\n";
				# print "$video_enc_command \"$file_name_full\" -o \"$new_file_name\"";
				# system();
				print "    Encoding video...  \n";
				system("echo \"\n\n\n============================================================\" >> $log_file");
				system("echo \"Encoding $dir\" >> $log_file");
				system("echo \"============================================================\" >> $log_file");
				system("$encode_command \"$file_name_full\" -o \"$new_file_name\" &>> $log_file ");
				# system("echo \"$mencoder_out\"  >> $log_file");
				sleep(1);
				print "    Encoding finished.\n";
			   	print "    Original file size: $file_size\MB\n";
				$org_file_size = $file_size;
				$file_size = (-s "$new_file_name")/1024/1024;
				$file_size =~ s/\..*//;
				print "    Final file size: $file_size MB\n";
				$summary .= "$dir\n   Original Size: $org_file_size MB Final: $file_size MB\n";
				$stop_time = time;
$time_elapst1 = ($stop_time - $start_time) / 3600 ;
				$time_elapst = sprintf("%.1f", ($stop_time - $start_time) / 3600 ); # rounding time to one decimal
				# print " start=$start_time, $stop_time, $time_elapst, $time_elapst1\n";
				print "    Encoding took $time_elapst h\n";
			}
		} else {
			print "Skipping: $dir is not a recognised video file\n";
		}	
	} 
}
closedir(DIR);
$total_stop_time=time;
$total_time=  sprintf("%.1f",($total_stop_time - $total_start_time) / 3600);
$summary .= "\n-----------------------------------------------\nOriginal dir: $directory_name\nFinal dir: $directory_name/$video_output_dir\nLog file: $log_file\nTotal encoding time: $total_time h\n\n";

print $summary;
system ("echo \"$summary\" >> $log_file");


#Post processing log file
# system("cat $log_file |grep -v '^Pos' |grep -v '^1 duplicate frame(s)!'|grep -v '^Skipping frame!' ");
$out_text = '';
open FILE, "<", "$log_file";
while (<FILE>) { 
	my $line = $_;
	if ( $line !~ /^Pos/ && $line !~ /^Skipping frame!/ && $line !~ /^. duplicate frame\(s\)!/ ) {
		$out_text .= $line;
	}
}
close FILE;
open FILE, ">$log_file" ;
print FILE $out_text;
close FILE;


print "All done.\n";
print "Before deleting old files:\n";
print " Check a few files\n";
print " Check log for errors\n";
print " Look at the file sizes for inconsistency\n";
print "\n";

External links[]

Advertisement