Skip Menu |

This queue is for tickets about the MPEG-Audio-Frame CPAN distribution.

Report information
The Basics
Id: 24241
Status: open
Priority: 0/
Queue: MPEG-Audio-Frame

People
Owner: Nobody in particular
Requestors: nick.cpan [...] xlmt.com
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in: 0.09
Fixed in: (no value)



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.

strange, I missed this bug... I will apply and release tomorrow or the begining of next week. Thanks!