[Slim-Checkins] r10243 - in /branches/6.5/server:
Slim/Formats/MP3.pm Slim/Player/Source.pm lib/MP3/Info.pm
andy at svn.slimdevices.com
andy at svn.slimdevices.com
Fri Oct 6 12:02:55 PDT 2006
Author: andy
Date: Fri Oct 6 12:02:53 2006
New Revision: 10243
URL: http://svn.slimdevices.com?rev=10243&view=rev
Log:
Fix a bug where gapless mp3 files with no ID3 tags weren't scanned properly. Display information on whether or not a track will play gapless when using d_source
Modified:
branches/6.5/server/Slim/Formats/MP3.pm
branches/6.5/server/Slim/Player/Source.pm
branches/6.5/server/lib/MP3/Info.pm
Modified: branches/6.5/server/Slim/Formats/MP3.pm
URL: http://svn.slimdevices.com/branches/6.5/server/Slim/Formats/MP3.pm?rev=10243&r1=10242&r2=10243&view=diff
==============================================================================
--- branches/6.5/server/Slim/Formats/MP3.pm (original)
+++ branches/6.5/server/Slim/Formats/MP3.pm Fri Oct 6 12:02:53 2006
@@ -182,7 +182,7 @@
my ($start, $end) = $class->findFrameBoundaries($fh, 0, $info->{'SIZE'});
- if ($start) {
+ if ( defined $start ) {
$info->{'OFFSET'} = $start;
if ($end) {
@@ -350,6 +350,33 @@
} else {
return wantarray ? ($start, $end) : $start;
}
+}
+
+=head2 getFrame( $fh )
+
+Returns the first MPEG::Audio::Frame object found in the given filehandle.
+
+=cut
+
+sub getFrame {
+ my ( $class, $fh ) = @_;
+
+ my $offset = tell $fh;
+
+ # dup the filehandle, as MPEG::Audio::Frame uses read(), and not sysread()
+ open(my $mpeg, '<&=', $fh) or do {
+ errorMsg("getFrames: Couldn't dup filehandle!\n");
+ return;
+ };
+
+ my $frame = MPEG::Audio::Frame->read($mpeg);
+
+ # Seek back to where we started
+ seek $fh, $offset, 0;
+
+ close $mpeg;
+
+ return $frame;
}
=head2 scanBitrate( $fh )
Modified: branches/6.5/server/Slim/Player/Source.pm
URL: http://svn.slimdevices.com/branches/6.5/server/Slim/Player/Source.pm?rev=10243&r1=10242&r2=10243&view=diff
==============================================================================
--- branches/6.5/server/Slim/Player/Source.pm (original)
+++ branches/6.5/server/Slim/Player/Source.pm Fri Oct 6 12:02:53 2006
@@ -1507,6 +1507,35 @@
};
$offset -= $seekoffset;
}
+
+ if ( $::d_source && $format eq 'mp3' ) {
+ # report whether the track should play back gapless or not
+
+ my $streamClass = streamClassForFormat($client, 'mp3');
+ my $frame = $streamClass->getFrame( $client->audioFilehandle );
+
+ # Look for the LAME header and delay data in the frame
+ my $io = IO::String->new( \$frame->asbin );
+
+ if ( my $info = MP3::Info::get_mp3info($io) ) {
+ if ( $info->{LAME} ) {
+ $::d_source && msg('MP3 file was encoded with ' . $info->{LAME}->{encoder_version} . "\n");
+
+ if ( $info->{LAME}->{start_delay} ) {
+ $::d_source && msgf("MP3 file contains encoder delay information (%d/%d), will be played gapless\n",
+ $info->{LAME}->{start_delay},
+ $info->{LAME}->{end_padding},
+ );
+ }
+ else {
+ $::d_source && msg("MP3 file does not contain encoder delay information, will not play back gapless\n");
+ }
+ }
+ else {
+ $::d_source && msg("MP3 file was not encoded with LAME, will not play back gapless\n");
+ }
+ }
+ }
# pipe is a socket
if (-p $filepath) {
@@ -1847,9 +1876,9 @@
}
sub streamClassForFormat {
- my $client = shift;
-
- my $streamFormat = $client->streamformat;
+ my ( $client, $streamFormat ) = @_;
+
+ $streamFormat ||= $client->streamformat;
if (Slim::Formats->loadTagFormatForType($streamFormat)) {
Modified: branches/6.5/server/lib/MP3/Info.pm
URL: http://svn.slimdevices.com/branches/6.5/server/lib/MP3/Info.pm?rev=10243&r1=10242&r2=10243&view=diff
==============================================================================
--- branches/6.5/server/lib/MP3/Info.pm (original)
+++ branches/6.5/server/lib/MP3/Info.pm Fri Oct 6 12:02:53 2006
@@ -1476,14 +1476,14 @@
return undef;
}
- if (not -s $file) {
- $@ = "File is empty";
- return undef;
- }
-
if (ref $file) { # filehandle passed
$fh = $file;
} else {
+ if (not -s $file) {
+ $@ = "File is empty";
+ return undef;
+ }
+
if (not open $fh, '<', $file) {
$@ = "Can't open $file: $!";
return undef;
@@ -1547,7 +1547,9 @@
}
my $vbr = _get_vbr($fh, $h, \$off);
-
+
+ my $lame = _get_lame($fh, $h, \$off);
+
seek $fh, 0, SEEK_END;
$eof = tell $fh;
seek $fh, -128, SEEK_END;
@@ -1566,11 +1568,11 @@
$h->{size} = $eof - $off;
$h->{offset} = $off;
- return _get_info($h, $vbr);
+ return _get_info($h, $vbr, $lame);
}
sub _get_info {
- my($h, $vbr) = @_;
+ my($h, $vbr, $lame) = @_;
my $i;
# No bitrate or sample rate? Something's wrong.
@@ -1619,6 +1621,10 @@
# should we just return if ! FRAMES?
$i->{FRAME_LENGTH} = int($h->{size} / $i->{FRAMES}) if $i->{FRAMES};
$i->{FREQUENCY} = $frequency_tbl[3 * $h->{IDR} + $h->{sampling_freq}];
+
+ if ($lame) {
+ $i->{LAME} = $lame;
+ }
return $i;
}
@@ -1704,7 +1710,7 @@
}
_vbr_seek($fh, \$off, \$bytes);
- return unless $bytes eq 'Xing';
+ return unless $bytes =~ /(?:Xing|Info)/;
_vbr_seek($fh, \$off, \$bytes);
$vbr{flags} = _unpack_head($bytes);
@@ -1734,6 +1740,33 @@
$$roff = $off;
return \%vbr;
+}
+
+# Read LAME info tag
+# http://gabriel.mp3-tech.org/mp3infotag.html
+sub _get_lame {
+ my($fh, $h, $roff) = @_;
+
+ my($off, $bytes, @bytes, %lame);
+
+ $off = $$roff;
+
+ # Encode version, 9 bytes
+ _vbr_seek($fh, \$off, \$bytes, 9);
+ $lame{encoder_version} = $bytes;
+
+ return unless $bytes =~ /^LAME/;
+
+ # There's some stuff here but it's not too useful
+ _vbr_seek($fh, \$off, \$bytes, 12);
+
+ # Encoder delays (used for gapless decoding)
+ _vbr_seek($fh, \$off, \$bytes, 3);
+ my $bin = unpack 'B*', $bytes;
+ $lame{start_delay} = unpack('N', pack('B32', substr('0' x 32 . substr($bin, 0, 12), -32)));
+ $lame{end_padding} = unpack('N', pack('B32', substr('0' x 32 . substr($bin, 12, 12), -32)));
+
+ return \%lame;
}
# _get_v2head(file handle, start offset in file);
More information about the checkins
mailing list