I am (for my sins) the maintainer of Audio::TagLib. There, I said it. My question arises out of constructing code that creates a 32-bit header for MPEG files. The header consists of bit fields of various widths.
This question concerns the ordering of bits in a 8-bit byte, packed into an integer. If I number the bits 7..0, the assignment results in a value when unpacked with 'b*' gives me the expected result: 11110010, with bit #7 on the left. The TagLib C++ library with which I communicate expects the field to look like this: 01001111, which is what one gets when unpacking with B*.
A pointer to doc that explains what's behind b vs B decoding would be greatly appreciated.
The actual code is attached.
Thanks.
#!/usr/bin/perl
# Reference taglib-1.9.1 doc TagLib::MPEG::Header
# and http://www.mp3-tech.org/programmer/frame_header.html
package MPEG_Header;
my %header = ( 'FrameSync' => [31,21], # Frame sync (all bits m
+ust be set)
'VersionID' => [20,19], # MPEG Audio version ID
'Layer' => [18,17], # Layer description
'Protection' => [16,16], # Protection bit
'BitRate' => [15,12], # Bitrate index
'SamplingRate' => [11,10], # Sampling rate frequenc
+y index
'Padding' => [9,9], # Padding bit
'Private' => [8,8], # Private bit. This one
+is only informative.
'ChannelMode' => [7,6], # Channel Mode
'ModeExtension' => [5,4], # Mode extension (Only u
+sed in Joint stereo)
'Copyright' => [3,3], # Copyright
'Original' => [2,2], # Original
'Emphasis' => [1,0], # Emphasis
);
my %VersionID = ('2.5' => 0b00,
'2' => 0b10,
'1' => 0b11,
);
my %Layer = ('III' => 0b01,
'II' => 0b10,
'I' => 0b11,
);
my %Padding = ('Pad' => 0b1,
'NoPad' => 0b0,
);
my %Protection = ('Protected' => 0b0,
'NotProtected' => 0b1,
);
my %ChannelMode = ('Stereo' => 0b00,
'JointStereo' => 0b01,
'DualChannel' => 0b10,
'SingleChannel' => 0b11,
);
my %Copyright = ('No', => 0b0,
'Yes' => 0b1,
);
my %Original = ('Copy' => 0b0,
'Original' => 0b1,
);
my %Emphasis = ('None' => 0b00,
'5015' => 0b01,
'CCIT' => 0b11,
);
sub _set_header_field {
my ($hdr, $field, $value) = @_;
warn "Field $field is not defined in the MPEG header\n" unless $he
+ader{$field};
my $first = $header{$field}->[0];
my $last = $header{$field}->[1];
$hdr = pack("B*", "0"x32) unless defined $hdr;
my ($pos, $off);
if ( defined $value ) {
# Field value assignment
# Possible symbolic reference
no strict 'refs'; # For symbolic reference
$value = $$field{$value} if exists $$field{$value};
my $width = $first - $last + 1;
for ($pos = $first; $width; $width --, $pos --) {
$off = 31 - $pos;
vec($hdr, $off, 1) = vec($value, $width - 1, 1);
}
return $hdr;
}
# Fill field with 1s
for ($pos = $first; $pos >= $last; $pos --) {
$off = 31 - $pos;
vec($hdr, $off, 1) = 1;
}
return $hdr;
}
sub build_header {
my %args = @_;
my $header;
$header = _set_header_field( $header, 'FrameSync' ); # All headers
+ have this
foreach my $key ( keys %args ) {
$header = _set_header_field( $header, $key, $args{$key} );
}
return $header;
}
1;
=if 0
#! /usr/bin/perl
use lib '.';
use MPEG_Header;
my $mpeg_header = MPEG_Header::build_header( 'VersionID' => 2,
'Layer' => 'III',
'Protection' => 'NotPro
+tected',
'BitRate' => 0b1000,
+ # 64 kbps for V2 and L3
'SamplingRate' => 0b10, #
+ 16000 Hz for V2
'Padding' => 'Pad',
'ChannelMode' => 'Stereo
+',
'Copyright' => 'No',
'Original' => 'Yes',
'Emphasis' => 'CCIT',
);
printf "b %-s\n", unpack("b*", $mpeg_header);
printf "B %-s\n", unpack("B*", $mpeg_header);
Spaces added. Unpack with b vs B.
b 11111111 11110010 10001000 11000111 00001100
B 11111111 01001111 00010001 11100011 00110000
=cut
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.