File Coverage

blib/lib/Audio/Digest/MP3.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Audio::Digest::MP3;
2              
3 1     1   41111 use 5.006;
  1         4  
  1         37  
4 1     1   5 use strict;
  1         2  
  1         187  
5 1     1   6 use warnings;
  1         6  
  1         145  
6              
7             require Exporter;
8              
9             our $VERSION = 0.10;
10             our @EXPORT_OK = qw(format_time digest_frames);
11             our @ISA = 'Exporter';
12              
13 1     1   2302 use MPEG::Audio::Frame;
  0            
  0            
14             use Digest;
15             use Carp;
16              
17             sub scan {
18             my $class = shift;
19             my $file = shift;
20             my $ctx = Digest->new(shift || 'MD5');
21             open my($fh), "<", $file or croak "Can't open file \"$file\": $!";
22             binmode $fh;
23             my $frames = 0;
24             my $seconds = 0;
25             my $bytes = 0;
26             my %histogram;
27             while(my $frame = MPEG::Audio::Frame->read($fh)){
28             $ctx->add($frame->asbin);
29             $frames++;
30             $seconds += $frame->seconds;
31             $bytes += length $frame->asbin;
32             $histogram{$frame->bitrate}++;
33             }
34             return bless [ $ctx->hexdigest, $seconds, $frames, $bytes, \%histogram ], $class;
35             }
36              
37             use overload '""' => \&digest;
38             sub digest { shift->[0] };
39             sub seconds { shift->[1] };
40             sub frames { shift->[2] };
41             sub bytes { shift->[3] };
42             sub histogram { shift->[4] };
43             sub cbr { 1 == keys %{&histogram} }
44             sub vbr { 1 < keys %{&histogram} }
45              
46             sub bitrate {
47             my $self = shift;
48             my $seconds = $self->seconds or return undef;
49             if($self->cbr) { return +(keys %{$self->histogram})[0] }
50             (my $bitrate = sprintf "%.1f", ($self->bytes/$seconds)*8/1000) =~ s/\.0//;
51             return $bitrate;
52             }
53              
54             sub playing_time {
55             my $seconds = (shift)->seconds;
56             return format_time($seconds, @_);
57             }
58              
59             sub format_time {
60             my $seconds = shift;
61             my $digits = shift;
62             local *_ = \$seconds;
63             if(defined $digits) {
64             my $abbrev = $digits =~ s/^-//;
65             $_ = sprintf "%.$digits\Ef", $_;
66             s/\.?0+$// if $abbrev;
67             }
68             s<^(\d+)>{
69             $1 < 3600 ?
70             sprintf "%d:%02d", $1 / 60, $1 % 60
71             : sprintf "%d:%02d:%02d", $1 / 3600, int($1 / 60) % 60, $1 % 60
72             }e;
73             return $_;
74             }
75              
76             sub digest_frames {
77             my $file = shift;
78             my $ctx = Digest->new(shift || 'MD5');
79             open my($fh), "<", $file or croak "Can't open file \"$file\": $!";
80             binmode $fh;
81             my @digest;
82             while(my $frame = MPEG::Audio::Frame->read($fh)){
83             $ctx->reset;
84             $ctx->add($frame->asbin);
85             push @digest, $ctx->hexdigest;
86             }
87             return wantarray ? @digest : \@digest;
88             }
89              
90             1;
91              
92             __END__