Created
November 13, 2012 19:32
-
-
Save jbarrett/4067848 to your computer and use it in GitHub Desktop.
Quick and dirty script to report on audio files encoded at less than a given bitrate
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env perl | |
use strict; | |
use warnings; | |
use v5.10.1; | |
use Image::ExifTool qw/:Public/; | |
use Getopt::Long; | |
use File::Which qw/which/; | |
use File::Find; | |
use Pod::Usage; | |
use IPC::Open3; | |
my $VERSION = "0.1"; | |
my $EXIF_BIT_RE = '^(AudioBitrate|MaxBitrate|AvgBitrate|NominalBitrate)$'; | |
my %opts = ( | |
exts => 'ogg,mp3,wma,mpc,aac,m4a', | |
bits => 192, | |
dir => '', | |
mplayer => which('mplayer'), | |
verbose => 0 | |
); | |
sub get_options { | |
GetOptions( | |
"e|exts=s" => \$opts{exts}, | |
"d|dir=s" => \$opts{dir}, | |
"m|mplayer=s" => \$opts{mplayer}, | |
"b|bitrate=i" => \$opts{bits}, | |
"h|help" => \$opts{help}, | |
"v|verbose" => \$opts{verbose}, | |
) or pod2usage(-verbose => 1) && exit; | |
pod2usage(-msg => 'FATAL: Directory not supplied', -verbose => 1) unless $opts{dir}; | |
$opts{exts_re} = join ('|', map {qr/$_/} split (' *, *', $opts{exts})); | |
} | |
# Best effort attempt to get an audio file's bit rate. | |
# First attempt is to retrieve it from Image::ExifTool::ImageInfo | |
# Second attempt retrieves ID_AUDIO_BITRATE from mplayer -identify output | |
# Last ditch effort is to try get a rough result from (file size / track length) | |
sub low_bits { | |
my ($filename) = @_; | |
my $pid; | |
my $bitrate=0; | |
my $length=0; | |
my $size=0; | |
my ($out, $in, $err); | |
my $info = ImageInfo($filename); | |
for (keys %{$info}) { | |
when (/$EXIF_BIT_RE/) { | |
($bitrate = $info->{$_}) =~ s/[^0-9]//g; | |
if ($bitrate > 0 && $bitrate < $opts{bits}) { | |
print "($bitrate) " if $opts{verbose}; | |
return 1; | |
} | |
} | |
} | |
if (!$bitrate && $opts{mplayer}) { | |
$pid = open3($out, $in, $err, $opts{mplayer}, '-frames', '0', '-identify', $filename); | |
waitpid($pid, 0); | |
for (<$in>) { | |
when (/ID_LENGTH=(.*)/) { | |
$length = $1; | |
} | |
when (/ID_AUDIO_BITRATE=(.*)/) { | |
$bitrate = ($1 / 1024); | |
if ($bitrate > 0 && $bitrate < $opts{bits}) { | |
print "($bitrate) " if $opts{verbose}; | |
return 1; | |
} | |
} | |
} | |
if (!$bitrate && $length) { | |
$size = -s $filename; | |
if ($size) { | |
$bitrate = int((($size / $length) * 8) / 1024); | |
if ($bitrate > 0 && $bitrate < $opts{bits}) { | |
print "(EST. $bitrate) " if $opts{verbose}; | |
return 1; | |
} | |
} | |
} | |
} | |
return 0; | |
} | |
sub wanted { | |
/($opts{exts_re})$/i || return; | |
print "$File::Find::name \n" if (low_bits($File::Find::name)); | |
} | |
get_options(); | |
find(\&wanted, $opts{dir}); | |
=encoding utf8 | |
=head1 NAME | |
bitrate_report | |
=head1 SYNOPSIS | |
bitrate_report -d music directory [OPTIONS] | |
=head1 DESCRIPTION | |
Find audio files which appear to be below a given average bitrate. | |
Recursively scan a given directory for audio files using lossy codecs, such as | |
Ogg Vorbis and MP3, then print a report on which files fall below a given | |
threshold bitrate to STDOUT. | |
We use a couple of mechanisms to discover the bitrate, but some files will | |
probably fall through the cracks. | |
=head1 ARGUMENTS | |
-d, --dir Directory containing music files. | |
-e, --ext Comma separated list of extensions to search for. | |
Default is ogg,mp3,wma,mpc,aac,m4a | |
-b, --bitrate Threshold bitrate. Any track falling below this bitrate is | |
reported. | |
Default is 192kbps. | |
-m, --mplayer Path to mplayer. Mplayer is used for Musepack files and as a | |
fallback when Image::ExifTool fails to extract metadata. | |
If mplayer is unavailable, no fallback is attempted. | |
Default is search in $PATH. | |
-v, --verbose Display detected bitrate alongside filename. | |
-h, --help Display this help message. | |
=head1 DEPENDENCIES | |
bitrate_report requires non-core modules Image::ExifTool and File::Which | |
and perl > v5.10.1 | |
=head1 AUTHOR | |
John Barrett <johna.barrett@gmail.com> | |
=head1 CHARACTERISTICS | |
Quick and dirty. | |
=cut |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment