Subject: | seconds() and length() calculation wrong for MPEG2 LSF |
The seconds() calculation relies on knowing the number of audio samples
encoded within the MPEG frame. The values coded within this module are
incorrect for MPEG Version 2 and 2.5, Layer I and Layer II.
The length() calculation is also related to the number of audio samples.
The factors coded here are also incorrect.
ISO/IEC 13818-3:1995 - page 76 says that for MPEG version 2, each frame
represents:
Layer I : 384 audio samples
Layer II : 1152 audiosamples
It also shows the calculations for Layer I and Layer II:
Layer I slots = bitrate * 12 / Fs
Layer II slots = bitrate * 144 / Fs
Layer I slots are 1 byte, Layer II and II slots are 4 bytes.
The audio sample information is also summarised at:
http://www.codeproject.com/audio/MPEGAudioInfo.asp#MPEGAudioFrame
I've not found a concise byte calculation for MPEG2 Layer III, but
believe the figures currently used to be correct, based on the tests
included with the distribution.
I attach a patch for consideration and a test for this bug.
I am using MPEG-Audio-Frame-0.09, running Perl v5.8.8 on Linux 2.6.17.
Best wishes for a happy New Year!
Nick
Subject: | frame_length.diff |
--- ./blib/lib/MPEG/Audio/Frame.pm 2007-01-05 14:31:07.000000000 +0000
+++ /usr/lib/perl5/vendor_perl/5.8.8/MPEG/Audio/Frame.pm 2007-01-05 18:11:24.000000000 +0000
@@ -92,6 +92,57 @@
);
+my @samples_per_frame = (
+ [ # 0b00 - MPEG Version 2.5
+ undef, # 0b00 is reserved
+ 576, # 0b01 Layer III
+ 1152, # 0b10 Layer II
+ 384 # 0b11 Layer I
+ ],
+ undef, # 0b01 is reserved
+ [ # 0b10 - MPEG Version 2
+ undef, # 0b00 is reserved
+ 576, # 0b01 Layer III
+ 1152, # 0b10 Layer II
+ 384 # 0b11 Layer I
+ ],
+ [ # 0b11 - MPEG Version 1
+ undef, # 0b00 is reserved
+ 1152, # 0b01 Layer III
+ 1152, # 0b10 Layer II
+ 384 # 0b11 Layer I
+ ]
+);
+
+
+# length_factor to use in calculating number of bytes for a frame
+# slots = ( [factor] * bits_per_second / sample_rate ) [+ 1 if padding]
+# bytes = slots * 4 for Layer-I
+# bytes = slots for Layer-II and Layer-III
+my @length_factor = (
+ [ # 0b00 - MPEG Version 2.5
+ undef, # 0b00 is reserved
+ 72, # 0b01 Layer III
+ 144, # 0b10 Layer II
+ 12 # 0b11 Layer I
+ ],
+ undef, # 0b01 is reserved
+ [ # 0b10 - MPEG Version 2
+ undef, # 0b00 is reserved
+ 72, # 0b01 Layer III
+ 144, # 0b10 Layer II
+ 12 # 0b11 Layer I
+ ],
+ [ # 0b11 - MPEG Version 1
+ undef, # 0b00 is reserved
+ 144, # 0b01 Layer III
+ 144, # 0b10 Layer II
+ 12 # 0b11 Layer I
+ ]
+);
+
+
+
# stolen from libmad, bin.c
my @crc_table = (
0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011,
@@ -241,10 +292,8 @@
my $bitrate = $bitrates[$version[$hr[VERSION]]][$layer[$hr[LAYER]]][$hr[BITRATE]] || $free_bitrate or return undef;
my $sample = $samples[$hr[VERSION]][$hr[SAMPLE]];
- my $use_smaller = $hr[VERSION] == 2 || $hr[VERSION] == 0; # FIXME VERSION == 2 means no support for MPEG2 multichannel
- my $length = $layer[$hr[LAYER]]
- ? (($use_smaller ? 72 : 144) * ($bitrate * 1000) / $sample + $hr[PAD]) # layers 2 & 3
- : ((($use_smaller ? 6 : 12 ) * ($bitrate * 1000) / $sample + $hr[PAD]) * 4); # layer 1
+ my $length = $length_factor[$hr[VERSION]][$hr[LAYER]] * ($bitrate * 1000) / $sample + $hr[PAD];
+ $length *= 4 unless $layer[$hr[LAYER]]; # Layer-I slots are 4 bytes, Layer-II & Layer-III are 1 byte
my $clength = $length - 4 - ($hr[CRC] ? 0 : 2);
(read $fh, my($content), $clength or return undef) == $clength or return undef; # appearantly header length is included... learned this the hard way.
@@ -414,9 +463,8 @@
my $self = shift;
no integer;
- $layer[$self->{header}[LAYER]]
- ? (($version[$self->{header}[VERSION]] == 0 ? 1152 : 576) / $self->sample())
- : (($version[$self->{header}[VERSION]] == 0 ? 384 : 192) / $self->sample())
+ $samples_per_frame[ $self->{header}[VERSION] ][ $self->{header}[LAYER] ] / $self->sample();
+
}
sub framerate {
Subject: | 20-mpeg2-layerII-24khz.t |
Message body is not shown because it is too large.