MPEG-Audio-Frame
view release on metacpan or search on metacpan
lib/MPEG/Audio/Frame.pm view on Meta::CPAN
[ # MPEG 1
44100, # 0b00
48000, # 0b01
32000, # 0b10
undef, # 0b11 is reserved
],
);
# stolen from libmad, bin.c
my @crc_table = (
0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011,
0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022,
0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072,
0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041,
0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2,
0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1,
0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1,
0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082,
0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192,
0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1,
0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1,
0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2,
0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151,
0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162,
0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132,
0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101,
0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312,
0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321,
0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371,
0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342,
0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1,
0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2,
0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2,
0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381,
0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291,
0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2,
0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2,
0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1,
0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252,
0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261,
0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231,
0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202
);
sub CRC_POLY () { 0x8005 }
###
my @protbits = (
[ 128, 256 ], # layer one
undef,
[ 136, 256 ], # layer three
);
my @consts;
sub B ($) { $_[0] == 12 ? 3 : (1 + ($_[0] / 4)) }
sub M ($) {
my $s = 0;
$s += $consts[$_][1] for (0 .. $_[0]-1);
$s%=8;
my $v = '';
vec($v,8-$_,1) = 1 for $s+1 .. $s+$consts[$_[0]][1];
"0x" . unpack("H*", $v);
}
sub R ($) {
my $i = 0;
my $m = eval "M_$consts[$_[0]][0]()";
$i++ until (($m >> $i) & 1);
$i;
}
BEGIN {
@consts = (
# [ $name, $width ]
[ SYNC => 3 ],
[ VERSION => 2 ],
[ LAYER => 2 ],
[ CRC => 1 ],
[ BITRATE => 4 ],
[ SAMPLE => 2 ],
[ PAD => 1 ],
[ PRIVATE => 1 ],
[ CHANMODE => 2 ],
[ MODEXT => 2 ],
[ COPY => 1 ],
[ HOME => 1 ],
[ EMPH => 2 ],
);
my $i = 0;
foreach my $c (@consts){
my $CONST = $c->[0];
eval "sub $CONST () { $i }"; # offset in $self->{header}
eval "sub M_$CONST () { " . M($i) ." }"; # bit mask
eval "sub B_$CONST () { " . B($i) . " }"; # offset in read()'s @hb
eval "sub R_$CONST () { " . R($i) . " }"; # amount to right shift
$i++;
}
}
# constructor and work horse
sub read {
my $pkg = shift || return undef;
my $fh = shift || return undef; binmode($fh);
local $/ = "\xff"; # get readline to find 8 bits of sync.
my $offset; # where in the handle
my $header; # the binary header data... what a fabulous pun.
my @hr; # an array of integer
OUTER: {
while (defined(<$fh>)){ # readline, readline, find me a header, make me a header, catch me a header. somewhate wasteful, perhaps. But I don't want to seek.
$header = "\xff";
(read $fh, $header, 3, 1 or return undef) == 3 or return undef; # read the rest of the header
my @hb = unpack("CCCC",$header); # an array of 4 integers for convenient access, each representing a byte of the header
# I wish vec could take non powers of 2 for the bit width param... *sigh*
# make sure there are no illegal values in the header
($hr[SYNC] = ($hb[B_SYNC] & M_SYNC) >> R_SYNC) != 0x07 and next; # see if the sync remains
($hr[VERSION] = ($hb[B_VERSION] & M_VERSION) >> R_VERSION) == 0x00 and ($mpeg25 or next);
($hr[VERSION]) == 0x01 and next;
($hr[LAYER] = ($hb[B_LAYER] & M_LAYER) >> R_LAYER) == 0x00 and next;
($hr[BITRATE] = ($hb[B_BITRATE] & M_BITRATE) >> R_BITRATE) == 0x0f and next;
($hr[SAMPLE] = ($hb[B_SAMPLE] & M_SAMPLE) >> R_SAMPLE) == 0x03 and next;
( run in 2.022 seconds using v1.01-cache-2.11-cpan-524268b4103 )