Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

ID3v2 TAG unpack uninitialized value

by thanos1983 (Pilgrim)
on Jan 05, 2014 at 03:37 UTC ( #1069345=perlquestion: print w/ replies, xml ) Need Help??
thanos1983 has asked for the wisdom of the Perl Monks concerning the following question:

use warnings; # it warns about undefined values use strict; # it's a lexically scoped declaration use Data::Dumper; use Fcntl qw( SEEK_SET ); $| = 1; #flushing output my ( $mp3_size , $lines , $lines_1 , $lines_2 , $lines_3 , $lines_4 ) += "\0"; my @size = "\0"; open(FH, ,"<", "song.mp3") or die "Can not open file: $!\n"; binmode(FH); # Open in binary mode. seek( FH , 6 , SEEK_SET ) or die "Could not seek: $!"; read( FH , $lines, 4 ); # Read 32 bits (4 Bytes) and store the data in + $lines Size (4 Bytes Size). ( $lines_1, $lines_2, $lines_3, $lines_4 ) = unpack ( "I I I I" , +$lines ); # (I) An unsigned integer. print ("This is the content of lines_1: $lines_1\n"); print ("This is the content of lines_2: $lines_2\n"); print ("This is the content of lines_3: $lines_3\n"); print ("This is the content of lines_4: $lines_4\n"); exit(0); $mp3_size = ($size[0] & 0xFF) | (( $size[1] & 0xFF ) << 7) | (( $size[2] & 0xFF ) << 14) | (( $size[3] & 0xFF ) << 21); print Dumper($mp3_size); close (FH) or die "Can not close file: $!\n"; $| = 1; #flushing output

I am trying to decode the ID3v2 TAG. As my first step (code: 1) I am trying to read 4 Bytes (32 bits) of unsigned integer into the $lines[0]-$lines3 which is the header size after the 6th Byte. The first 6 Bytes I have managed to read them and decode them effectively so far but I am having trouble with this one. The reason that I am trying to decode the message in 4 different strings is that I want to apply sync_safe process after as it is displayed on the code sample above.

seek( FH , 6 , SEEK_SET ) or die "Could not seek: $!"; read( FH , $lines, 1 ); ( $lines_1 ) = unpack ( "I" , $lines ); read( FH , $lines, 1 ); ( $lines_2 ) = unpack ( "I" , $lines ); read( FH , $lines, 1 ); ( $lines_3 ) = unpack ( "I" , $lines ); read( FH , $lines, 1 ); ( $lines_4 ) = unpack ( "I" , $lines );

Error when executing code:

This is the content of lines_0: 990183424 Use of uninitialized value $lines_1 in concatenation (.) or string at +test.pl line 63. This is the content of lines_2: Use of uninitialized value $lines_2 in concatenation (.) or string at +test.pl line 64. This is the content of lines_3: Use of uninitialized value $lines_3 in concatenation (.) or string at +test.pl line 65.

I tried also to read one byte (code: 2) each time by using the read() function and unpack() one by one the 4 Bytes but I keep getting the same error message.

In theory by reading one by one the Bytes with the read() function and applying the unpack I should not have a problem, at least so far worked fine for the previous Bytes.

But by doing to in the final step I keep getting the following error:

Use of uninitialized value $lines_0 in concatenation (.) or string at +test.pl line 62. This is the content of lines_0: Use of uninitialized value $lines_1 in concatenation (.) or string at +test.pl line 63. This is the content of lines_1: Use of uninitialized value $lines_2 in concatenation (.) or string at +test.pl line 64. This is the content of lines_2: Use of uninitialized value $lines_3 in concatenation (.) or string at +test.pl line 65. This is the content of lines_3:

I am a beginner in programming so I can not understand the reason that there is no value inside this values. Any guidance or assistance would be much appreciated

Thanks in advance for your time and effort.

Comment on ID3v2 TAG unpack uninitialized value
Select or Download Code
Re: ID3v2 TAG unpack uninitialized value
by BrowserUk (Pope) on Jan 05, 2014 at 04:32 UTC

    You are reading 4 bytes:

    read( FH , $lines, 4 ); # Read 32 bits (4 Bytes) and store the data in + $lines Size (4 Bytes Size).

    And then attempting to unpack four x 4-byte integers ("I I I I"):

    ( $lines_1, $lines_2, $lines_3, $lines_4 ) = unpack ( "I I I I" , + $lines ); # (I) An unsigned integer.

    Fix: read enough data to satisfy the unpack template (ie. 16 bytes):

    read( FH , $lines, 16 ); # Read 4x 32 bits (4 Bytes) and store the dat +a in $lines Size (16 Bytes Size). ( $lines_1, $lines_2, $lines_3, $lines_4 ) = unpack ( "I I I I" , + $lines ); # (I I I I ) FOUR unsigned integer(S).

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

      Actually, you want to unpack them as four bytes. unpack "CCCC". ID3 has this wacky format that stores a 28-bit integer with 7 bits per byte, which I see the OP is already aware of.

      The pack "I" format is not nearly as useful as you might think, because the length and byte order are both platform-dependent. You usually want to stick with "N" or "V".

        Thanks for the tip no_slogan, I actually print tried all of them and I got the same result for (I An unsigned integer and for V A long integer in VAX order). Output can be viewed under:

        This is the content of lines_0 with I: 990183424 This is the content of lines_1 with I: 826626132 This is the content of lines_2 with I: 167772160 This is the content of lines_3 with I: 1090519040 This is the content of lines_0 with V: 990183424 This is the content of lines_1 with V: 826626132 This is the content of lines_2 with V: 167772160 This is the content of lines_3 with V: 1090519040

        When I tried to print the (N A long integer in network order) option I got this result:

        This is the content of lines_0: 1339 This is the content of lines_1: 1414546737 This is the content of lines_2: 10 This is the content of lines_3: 65

        The reason that I was using the (I An unsigned integer) characters is that on the official website description says:

        http://id3.org/id3v2.4.0-structure
        %x is used to indicate a bit with unknown content. ID3v2 size 4 * %0xxxxxxx
        The ID3v2 tag size is stored as a 32 bit synchsafe integer (section 6. +2), making a total of 28 effective bits (representing up to 256MB).

      Thanks a lot it works just fine, but I am really confused. I have been trying to understand how the ID3v2 TAG works and I can not figure out this part (header size). Theoretically the whole header should be 10 Bytes. The size part is 4 Unsigned Bytes. So based on this theory if I read 4 Bytes I should be able to get the whole header size. In practice I failed.

      The information that I have take is from the official page of the TAG given under:

      http://id3.org/id3v2.3.0

      I can not still figure this out, because then by adding 16 Bytes (16 Bytes = 4 Unsigned Bytes x 32 Bits size each). So in theory the header size is 4 Bytes now will be 16 Bytes.

      Please correct me if I am wrong

        I can not still figure this out, because then by adding 16 Bytes (16 Bytes = 4 Unsigned Bytes x 32 Bits size each). So in theory the header size is 4 Bytes now will be 16 Bytes.

        As the spec you've now linked indicates that the 'size' field is a 28-bit value encoded in 7-lsbs of each of 4 bytes, my correction of your code was wrong. You should not read 16 byte and decode with a template of "I I I I" as I suggested.

        But rather read 4 bytes as you were, but then decode with a template of 'C C C C' (or 'CCCC' or 'C4').

        And if you unpack to a variable called my @size = unpack 'C4', ...; (rather than the 4 separate $lines_* variables), then the following code from your OP:

        $mp3_size = ($size[0] & 0xFF) | (( $size[1] & 0xFF ) << 7) | (( $size[2] & 0xFF ) << 14) | (( $size[3] & 0xFF ) << 21);

        starts to make sense. It extracts the 7-bit values from the 4 bytes and combines them together to produce the required 28-bit numeric value.

        BTW: reading 4 bytes into a variable called $lines is also misleading.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1069345]
Approved by boftx
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (9)
As of 2014-09-23 11:44 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (219 votes), past polls