Audio-Digest-MP3

 view release on metacpan or  search on metacpan

lib/Audio/Digest/MP3.pm  view on Meta::CPAN

    my $seconds = (shift)->seconds;
    return format_time($seconds, @_);
}

sub format_time {
    my $seconds = shift;
    my $digits = shift;
    local *_ = \$seconds;
    if(defined $digits) {
        my $abbrev = $digits =~ s/^-//;
        $_ = sprintf "%.$digits\Ef", $_;
        s/\.?0+$// if $abbrev;
    }
    s<^(\d+)>{
        $1 < 3600 ?
        sprintf "%d:%02d", $1 / 60, $1 % 60
        : sprintf "%d:%02d:%02d", $1 / 3600, int($1 / 60) % 60, $1 % 60
      }e;
    return $_;
}

sub digest_frames {
    my $file = shift;
    my $ctx = Digest->new(shift || 'MD5');
    open my($fh), "<", $file or croak "Can't open file \"$file\": $!";
    binmode $fh;
    my @digest;
    while(my $frame = MPEG::Audio::Frame->read($fh)){
        $ctx->reset;
        $ctx->add($frame->asbin);
        push @digest, $ctx->hexdigest;
    }
    return wantarray ? @digest : \@digest;
}

1;

__END__

=head1 NAME

Audio::Digest::MP3 - Get a message digest for the audio stream out of an MP3 file (skipping ID3 tags)

=head1 SYNOPSIS

  use Audio::Digest::MP3;
  my $streaminfo = Audio::Digest::MP3->scan($filepath, 'MD5');
  printf "%s: %s (%s) %s\n", $file,
      $streaminfo->playing_time,
      $streaminfo->bitrate,
      $streaminfo->digest;


=head1 DESCRIPTION

Sometimes you want to know if you have duplicate MP3 files on your disks. But
as soon as you start editing the ID3 tags, the file contents changes, and you
can no longer trust a plain MD5 checksum on the file, nor the file size, to
compare them.

This module scans the MP3 file, only including the audio stream (undecoded!) to
calculate the message digest.

While it scans, it compiles more metadata about the file, such as playing time,
either in seconds or as formatted string, bitrate (in kbits/sec), stream size
in bytes, and whether the file is a CBR or a VBR file.

In short: lots of info that you can use to compare MP3 files, but excluding any
info coming out of the ID3 tags.

By default, it uses L<Digest::MD5|Digest::MD5> to calculate the digest, but if you specify
'SHA1' (or any other specifier for a message digest module, that is compatible
with L<Digest>) it'll use that instead.

It uses L<MPEG::Audio::Frame|MPEG::Audio::Frame>, a Pure Perl module, to extract
the stream from the file. Average processing speed on my computer is about 1-2MB/sec.

=head2 METHODS

=over

=item C<$info-E<gt>digest>

The message digest for the stream

=item C<my $info = Audio::Digest::MP3-E<gt>scan($filepath)>

=item C<my $info = Audio::Digest::MP3-E<gt>scan($filepath, 'MD5')>

=item C<my $info = Audio::Digest::MP3-E<gt>scan($filepath, 'SHA1')>

This class method scans the audio stream for an MP3 file, calculating its message
digest and various other meta data, and constructing a summary data structure
in the form of an object. When used as a string, this object returns the hex
digest string.

Default digest type is MD5.

=item C<$info-E<gt>seconds>

=item C<$info-E<gt>playing_time>

=item C<$info-E<gt>playing_time(0)>

=item C<$info-E<gt>playing_time(1)>

=item C<$info-E<gt>playing_time(-1)>

Get the playing time for an MP3 file, either as a number (C<seconds>) or as a time
formatted string (C<playing_time>). For the latter you can pass a parameter
specifying the number of decimals for roundoff of fractional seconds.
If this number is negative, trailing zeros as well (as a trailing decimal point)
are dropped. Default is C<-1>.

=item C<$info-E<gt>frames>

The integer number of audio frames

=item C<$info-E<gt>bytes>

The number of bytes in the audio stream.



( run in 1.764 second using v1.01-cache-2.11-cpan-600a1bdf6e4 )