Пример #1
0
 function FixedPoint2_30($rawdata)
 {
     $binarystring = BigEndian2Bin($rawdata);
     return Bin2Dec(substr($binarystring, 0, 2)) + (double) (Bin2Dec(substr($binarystring, 2, 30)) / pow(2, 30));
 }
Пример #2
0
function decodeMPEGaudioHeader($fd, $offset, &$ThisFileInfo, $recursivesearch = true, $ScanAsCBR = false, $FastMPEGheaderScan = false)
{
    static $MPEGaudioVersionLookup;
    static $MPEGaudioLayerLookup;
    static $MPEGaudioBitrateLookup;
    static $MPEGaudioFrequencyLookup;
    static $MPEGaudioChannelModeLookup;
    static $MPEGaudioModeExtensionLookup;
    static $MPEGaudioEmphasisLookup;
    if (empty($MPEGaudioVersionLookup)) {
        $MPEGaudioVersionLookup = MPEGaudioVersionArray();
        $MPEGaudioLayerLookup = MPEGaudioLayerArray();
        $MPEGaudioBitrateLookup = MPEGaudioBitrateArray();
        $MPEGaudioFrequencyLookup = MPEGaudioFrequencyArray();
        $MPEGaudioChannelModeLookup = MPEGaudioChannelModeArray();
        $MPEGaudioModeExtensionLookup = MPEGaudioModeExtensionArray();
        $MPEGaudioEmphasisLookup = MPEGaudioEmphasisArray();
    }
    if ($offset >= $ThisFileInfo['avdataend']) {
        $ThisFileInfo['error'] .= "\n" . 'end of file encounter looking for MPEG synch';
        return false;
    }
    fseek($fd, $offset, SEEK_SET);
    $headerstring = fread($fd, 192);
    // MP3 audio frame structure:
    // $aa $aa $aa $aa [$bb $bb] $cc...
    // where $aa..$aa is the four-byte mpeg-audio header (below)
    // $bb $bb is the optional 2-byte CRC
    // and $cc... is the audio data
    $head4 = substr($headerstring, 0, 4);
    static $MPEGaudioHeaderDecodeCache = array();
    if (isset($MPEGaudioHeaderDecodeCache[$head4])) {
        $MPEGheaderRawArray = $MPEGaudioHeaderDecodeCache[$head4];
    } else {
        $MPEGheaderRawArray = MPEGaudioHeaderDecode($head4);
        $MPEGaudioHeaderDecodeCache[$head4] = $MPEGheaderRawArray;
    }
    static $MPEGaudioHeaderValidCache = array();
    // Not in cache
    if (!isset($MPEGaudioHeaderValidCache[$head4])) {
        $MPEGaudioHeaderValidCache[$head4] = MPEGaudioHeaderValid($MPEGheaderRawArray);
    }
    if ($MPEGaudioHeaderValidCache[$head4]) {
        $ThisFileInfo['mpeg']['audio']['raw'] = $MPEGheaderRawArray;
    } else {
        $ThisFileInfo['error'] .= "\n" . 'Invalid MPEG audio header at offset ' . $offset;
        return false;
    }
    if (!$FastMPEGheaderScan) {
        $ThisFileInfo['mpeg']['audio']['version'] = $MPEGaudioVersionLookup[$ThisFileInfo['mpeg']['audio']['raw']['version']];
        $ThisFileInfo['mpeg']['audio']['layer'] = $MPEGaudioLayerLookup[$ThisFileInfo['mpeg']['audio']['raw']['layer']];
        $ThisFileInfo['mpeg']['audio']['channelmode'] = $MPEGaudioChannelModeLookup[$ThisFileInfo['mpeg']['audio']['raw']['channelmode']];
        $ThisFileInfo['mpeg']['audio']['channels'] = $ThisFileInfo['mpeg']['audio']['channelmode'] == 'mono' ? 1 : 2;
        $ThisFileInfo['mpeg']['audio']['sample_rate'] = $MPEGaudioFrequencyLookup[$ThisFileInfo['mpeg']['audio']['version']][$ThisFileInfo['mpeg']['audio']['raw']['sample_rate']];
        $ThisFileInfo['mpeg']['audio']['protection'] = !$ThisFileInfo['mpeg']['audio']['raw']['protection'];
        $ThisFileInfo['mpeg']['audio']['private'] = (bool) $ThisFileInfo['mpeg']['audio']['raw']['private'];
        $ThisFileInfo['mpeg']['audio']['modeextension'] = $MPEGaudioModeExtensionLookup[$ThisFileInfo['mpeg']['audio']['layer']][$ThisFileInfo['mpeg']['audio']['raw']['modeextension']];
        $ThisFileInfo['mpeg']['audio']['copyright'] = (bool) $ThisFileInfo['mpeg']['audio']['raw']['copyright'];
        $ThisFileInfo['mpeg']['audio']['original'] = (bool) $ThisFileInfo['mpeg']['audio']['raw']['original'];
        $ThisFileInfo['mpeg']['audio']['emphasis'] = $MPEGaudioEmphasisLookup[$ThisFileInfo['mpeg']['audio']['raw']['emphasis']];
        $ThisFileInfo['audio']['channels'] = $ThisFileInfo['mpeg']['audio']['channels'];
        $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['mpeg']['audio']['sample_rate'];
        if ($ThisFileInfo['mpeg']['audio']['protection']) {
            $ThisFileInfo['mpeg']['audio']['crc'] = BigEndian2Int(substr($headerstring, 4, 2));
        }
    }
    $ThisFileInfo['mpeg']['audio']['padding'] = (bool) $ThisFileInfo['mpeg']['audio']['raw']['padding'];
    $ThisFileInfo['mpeg']['audio']['bitrate'] = $MPEGaudioBitrateLookup[$ThisFileInfo['mpeg']['audio']['version']][$ThisFileInfo['mpeg']['audio']['layer']][$ThisFileInfo['mpeg']['audio']['raw']['bitrate']];
    // For Layer II there are some combinations of bitrate and mode which are not allowed.
    if (!$FastMPEGheaderScan && $ThisFileInfo['mpeg']['audio']['layer'] == 'II') {
        //$ThisFileInfo['fileformat']          = 'mp2';
        $ThisFileInfo['audio']['dataformat'] = 'mp2';
        switch ($ThisFileInfo['mpeg']['audio']['channelmode']) {
            case 'mono':
                if ($ThisFileInfo['mpeg']['audio']['bitrate'] == 'free' || $ThisFileInfo['mpeg']['audio']['bitrate'] <= 192) {
                    // these are ok
                } else {
                    $ThisFileInfo['error'] .= "\n" . $ThisFileInfo['mpeg']['audio']['bitrate'] . 'kbps not allowed in Layer II, ' . $ThisFileInfo['mpeg']['audio']['channelmode'] . '.';
                    return false;
                }
                break;
            case 'stereo':
            case 'joint stereo':
            case 'dual channel':
                if ($ThisFileInfo['mpeg']['audio']['bitrate'] == 'free' || $ThisFileInfo['mpeg']['audio']['bitrate'] == 64 || $ThisFileInfo['mpeg']['audio']['bitrate'] >= 96) {
                    // these are ok
                } else {
                    $ThisFileInfo['error'] .= "\n" . $ThisFileInfo['mpeg']['audio']['bitrate'] . 'kbps not allowed in Layer II, ' . $ThisFileInfo['mpeg']['audio']['channelmode'] . '.';
                    return false;
                }
                break;
        }
    }
    if ($ThisFileInfo['mpeg']['audio']['bitrate'] != 'free') {
        if ($ThisFileInfo['mpeg']['audio']['version'] == '1') {
            if ($ThisFileInfo['mpeg']['audio']['layer'] == 'I') {
                $FrameLengthCoefficient = 48;
                $FrameLengthPadding = $ThisFileInfo['mpeg']['audio']['padding'] ? 4 : 0;
                // For Layer I slot is 32 bits long, for Layer II and Layer III slot is 8 bits long.
            } else {
                // Layer II / III
                $FrameLengthCoefficient = 144;
                $FrameLengthPadding = $ThisFileInfo['mpeg']['audio']['padding'] ? 1 : 0;
                // For Layer I slot is 32 bits long, for Layer II and Layer III slot is 8 bits long.
            }
        } else {
            // MPEG-2 / MPEG-2.5
            if ($ThisFileInfo['mpeg']['audio']['layer'] == 'I') {
                $FrameLengthCoefficient = 24;
                $FrameLengthPadding = $ThisFileInfo['mpeg']['audio']['padding'] ? 4 : 0;
                // For Layer I slot is 32 bits long, for Layer II and Layer III slot is 8 bits long.
            } else {
                // Layer II / III
                $FrameLengthCoefficient = 72;
                $FrameLengthPadding = $ThisFileInfo['mpeg']['audio']['padding'] ? 1 : 0;
                // For Layer I slot is 32 bits long, for Layer II and Layer III slot is 8 bits long.
            }
        }
        // FrameLengthInBytes = ((Coefficient * BitRate) / SampleRate) + Padding
        // http://66.96.216.160/cgi-bin/YaBB.pl?board=c&action=display&num=1018474068
        // -> [Finding the next frame synch] on www.r3mix.net forums if the above link goes dead
        if ($ThisFileInfo['audio']['sample_rate'] > 0) {
            $ThisFileInfo['mpeg']['audio']['framelength'] = (int) floor($FrameLengthCoefficient * 1000 * $ThisFileInfo['mpeg']['audio']['bitrate'] / $ThisFileInfo['audio']['sample_rate']) + $FrameLengthPadding;
        }
    }
    $ThisFileInfo['audio']['bitrate'] = 1000 * $ThisFileInfo['mpeg']['audio']['bitrate'];
    if (isset($ThisFileInfo['mpeg']['audio']['framelength'])) {
        $nextframetestoffset = $offset + $ThisFileInfo['mpeg']['audio']['framelength'];
    } else {
        $ThisFileInfo['error'] .= "\n" . 'Frame at offset(' . $offset . ') is has an invalid frame length.';
        return false;
    }
    ////////////////////////////////////////////////////////////////////////////////////
    // Variable-bitrate headers
    if (substr($headerstring, 4 + 32, 4) == 'VBRI') {
        // Fraunhofer VBR header is hardcoded 'VBRI' at offset 0x24 (36)
        // specs taken from http://minnie.tuhs.org/pipermail/mp3encoder/2001-January/001800.html
        $ThisFileInfo['mpeg']['audio']['bitrate_mode'] = 'vbr';
        $ThisFileInfo['mpeg']['audio']['VBR_method'] = 'Fraunhofer';
        $ThisFileInfo['audio']['codec'] = 'Fraunhofer';
        $SideInfoData = substr($headerstring, 4 + 2, 32);
        $FraunhoferVBROffset = 4 + 32 + strlen('VBRI');
        $Fraunhofer_EncoderVersion = substr($headerstring, $FraunhoferVBROffset, 2);
        $FraunhoferVBROffset += 2;
        $ThisFileInfo['mpeg']['audio']['VBR_encoder_version'] = BigEndian2Int($Fraunhofer_EncoderVersion);
        $Fraunhofer_EncoderDelay = substr($headerstring, $FraunhoferVBROffset, 2);
        $FraunhoferVBROffset += 2;
        $ThisFileInfo['mpeg']['audio']['VBR_encoder_delay'] = BigEndian2Int($Fraunhofer_EncoderDelay);
        $Fraunhofer_quality = substr($headerstring, $FraunhoferVBROffset, 2);
        $FraunhoferVBROffset += 2;
        $ThisFileInfo['mpeg']['audio']['VBR_quality'] = BigEndian2Int($Fraunhofer_quality);
        $Fraunhofer_Bytes = substr($headerstring, $FraunhoferVBROffset, 4);
        $FraunhoferVBROffset += 4;
        $ThisFileInfo['mpeg']['audio']['VBR_bytes'] = BigEndian2Int($Fraunhofer_Bytes);
        $Fraunhofer_Frames = substr($headerstring, $FraunhoferVBROffset, 4);
        $FraunhoferVBROffset += 4;
        $ThisFileInfo['mpeg']['audio']['VBR_frames'] = BigEndian2Int($Fraunhofer_Frames);
        $Fraunhofer_SeekOffsets = substr($headerstring, $FraunhoferVBROffset, 2);
        $FraunhoferVBROffset += 2;
        $ThisFileInfo['mpeg']['audio']['VBR_seek_offsets'] = BigEndian2Int($Fraunhofer_SeekOffsets);
        $FraunhoferVBROffset += 4;
        // hardcoded $00 $01 $00 $02  - purpose unknown
        $Fraunhofer_OffsetStride = substr($headerstring, $FraunhoferVBROffset, 2);
        $FraunhoferVBROffset += 2;
        $ThisFileInfo['mpeg']['audio']['VBR_seek_offsets_stride'] = BigEndian2Int($Fraunhofer_OffsetStride);
        $previousbyteoffset = $offset;
        for ($i = 0; $i < $ThisFileInfo['mpeg']['audio']['VBR_seek_offsets']; $i++) {
            $Fraunhofer_OffsetN = BigEndian2Int(substr($headerstring, $FraunhoferVBROffset, 2));
            $FraunhoferVBROffset += 2;
            $ThisFileInfo['mpeg']['audio']['VBR_offsets_relative'][$i] = $Fraunhofer_OffsetN;
            $ThisFileInfo['mpeg']['audio']['VBR_offsets_absolute'][$i] = $Fraunhofer_OffsetN + $previousbyteoffset;
            $previousbyteoffset += $Fraunhofer_OffsetN;
        }
    } else {
        // Xing VBR header is hardcoded 'Xing' at a offset 0x0D (13), 0x15 (21) or 0x24 (36)
        // depending on MPEG layer and number of channels
        if ($ThisFileInfo['mpeg']['audio']['version'] == '1') {
            if ($ThisFileInfo['mpeg']['audio']['channelmode'] == 'mono') {
                // MPEG-1 (mono)
                $VBRidOffset = 4 + 17;
                // 0x15
                $SideInfoData = substr($headerstring, 4 + 2, 17);
            } else {
                // MPEG-1 (stereo, joint-stereo, dual-channel)
                $VBRidOffset = 4 + 32;
                // 0x24
                $SideInfoData = substr($headerstring, 4 + 2, 32);
            }
        } else {
            // 2 or 2.5
            if ($ThisFileInfo['mpeg']['audio']['channelmode'] == 'mono') {
                // MPEG-2, MPEG-2.5 (mono)
                $VBRidOffset = 4 + 9;
                // 0x0D
                $SideInfoData = substr($headerstring, 4 + 2, 9);
            } else {
                // MPEG-2, MPEG-2.5 (stereo, joint-stereo, dual-channel)
                $VBRidOffset = 4 + 17;
                // 0x15
                $SideInfoData = substr($headerstring, 4 + 2, 17);
            }
        }
        if (substr($headerstring, $VBRidOffset, strlen('Xing')) == 'Xing' || substr($headerstring, $VBRidOffset, strlen('Info')) == 'Info') {
            // 'Xing' is traditional Xing VBR frame, 'Info' is LAME-encoded CBR
            // 'This was done to avoid CBR files to be recognized as traditional Xing VBR files by some decoders.'
            $ThisFileInfo['mpeg']['audio']['bitrate_mode'] = 'vbr';
            $ThisFileInfo['mpeg']['audio']['VBR_method'] = 'Xing';
            $XingVBROffset = $VBRidOffset + strlen('Xing');
            $ThisFileInfo['mpeg']['audio']['xing_flags_raw'] = substr($headerstring, $XingVBROffset, 4);
            $XingVBROffset += 4;
            $XingHeader_byte4 = BigEndian2Bin(substr($ThisFileInfo['mpeg']['audio']['xing_flags_raw'], 3, 1));
            $ThisFileInfo['mpeg']['audio']['xing_flags']['frames'] = (bool) $XingHeader_byte4[4];
            $ThisFileInfo['mpeg']['audio']['xing_flags']['bytes'] = (bool) $XingHeader_byte4[5];
            $ThisFileInfo['mpeg']['audio']['xing_flags']['toc'] = (bool) $XingHeader_byte4[6];
            $ThisFileInfo['mpeg']['audio']['xing_flags']['vbr_scale'] = (bool) $XingHeader_byte4[7];
            if ($ThisFileInfo['mpeg']['audio']['xing_flags']['frames']) {
                $ThisFileInfo['mpeg']['audio']['VBR_frames'] = BigEndian2Int(substr($headerstring, $XingVBROffset, 4));
                $XingVBROffset += 4;
            }
            if ($ThisFileInfo['mpeg']['audio']['xing_flags']['bytes']) {
                $ThisFileInfo['mpeg']['audio']['VBR_bytes'] = BigEndian2Int(substr($headerstring, $XingVBROffset, 4));
                $XingVBROffset += 4;
            }
            if ($ThisFileInfo['mpeg']['audio']['xing_flags']['toc']) {
                $LAMEtocData = substr($headerstring, $XingVBROffset, 100);
                $XingVBROffset += 100;
                for ($i = 0; $i < 100; $i++) {
                    $ThisFileInfo['mpeg']['audio']['toc'][$i] = ord($LAMEtocData[$i]);
                }
            }
            if ($ThisFileInfo['mpeg']['audio']['xing_flags']['vbr_scale']) {
                $ThisFileInfo['mpeg']['audio']['VBR_scale'] = BigEndian2Int(substr($headerstring, $XingVBROffset, 4));
                $XingVBROffset += 4;
            }
            if (substr($headerstring, $XingVBROffset, 4) == 'LAME') {
                $ThisFileInfo['mpeg']['audio']['LAME']['short_version'] = substr($headerstring, $XingVBROffset, 9);
                $XingVBROffset += 9;
                $LAMEtagRevisionVBRmethod = BigEndian2Int(substr($headerstring, $XingVBROffset, 1));
                $XingVBROffset += 1;
                $ThisFileInfo['mpeg']['audio']['LAME']['tag_revision'] = ($LAMEtagRevisionVBRmethod & 0xf0) >> 4;
                $ThisFileInfo['mpeg']['audio']['LAME']['vbr_method_raw'] = $LAMEtagRevisionVBRmethod & 0xf;
                $ThisFileInfo['mpeg']['audio']['LAME']['vbr_method'] = LAMEvbrMethodLookup($ThisFileInfo['mpeg']['audio']['LAME']['vbr_method_raw']);
                $ThisFileInfo['mpeg']['audio']['LAME']['lowpass_frequency'] = 100 * BigEndian2Int(substr($headerstring, $XingVBROffset, 1));
                $XingVBROffset += 1;
                // http://privatewww.essex.ac.uk/~djmrob/replaygain/rg_data_format.html
                $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['peak_amplitude'] = BigEndian2Float(substr($headerstring, $XingVBROffset, 4));
                $XingVBROffset += 4;
                $RadioReplayGainRaw = BigEndian2Int(substr($headerstring, $XingVBROffset, 2));
                $XingVBROffset += 4;
                $ReplayGainID = ($RadioReplayGainRaw & 0xe000) >> 13;
                $ReplayGainNameKey = '';
                switch ($ReplayGainID) {
                    case 1:
                        $ReplayGainNameKey = 'radio';
                        break;
                    case 2:
                        $ReplayGainNameKey = 'audiophile';
                        break;
                    case 0:
                        // replay gain not set
                    // replay gain not set
                    default:
                        // reserved
                        break;
                }
                if ($ReplayGainNameKey) {
                    require_once GETID3_INCLUDEPATH . 'getid3.rgad.php';
                    $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']["{$ReplayGainNameKey}"]['raw']['name'] = ($RadioReplayGainRaw & 0xe000) >> 13;
                    $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']["{$ReplayGainNameKey}"]['raw']['originator'] = ($RadioReplayGainRaw & 0x1c00) >> 10;
                    $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']["{$ReplayGainNameKey}"]['raw']['sign_bit'] = ($RadioReplayGainRaw & 0x200) >> 9;
                    $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']["{$ReplayGainNameKey}"]['raw']['gain_adjust'] = $RadioReplayGainRaw & 0x1ff;
                    $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']["{$ReplayGainNameKey}"]['name'] = RGADnameLookup($ThisFileInfo['mpeg']['audio']['LAME']['RGAD']["{$ReplayGainNameKey}"]['raw']['name']);
                    $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']["{$ReplayGainNameKey}"]['originator'] = RGADoriginatorLookup($ThisFileInfo['mpeg']['audio']['LAME']['RGAD']["{$ReplayGainNameKey}"]['raw']['originator']);
                    $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']["{$ReplayGainNameKey}"]['gain_db'] = RGADadjustmentLookup($ThisFileInfo['mpeg']['audio']['LAME']['RGAD']["{$ReplayGainNameKey}"]['raw']['gain_adjust'], $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']["{$ReplayGainNameKey}"]['raw']['sign_bit']);
                    $ThisFileInfo['replay_gain']["{$ReplayGainNameKey}"]['peak'] = $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['peak_amplitude'];
                    $ThisFileInfo['replay_gain']["{$ReplayGainNameKey}"]['originator'] = $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']["{$ReplayGainNameKey}"]['originator'];
                    $ThisFileInfo['replay_gain']["{$ReplayGainNameKey}"]['adjustment'] = $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']["{$ReplayGainNameKey}"]['gain_db'];
                }
                $EncodingFlagsATHtype = BigEndian2Int(substr($headerstring, $XingVBROffset, 1));
                $XingVBROffset += 1;
                $ThisFileInfo['mpeg']['audio']['LAME']['encoding_flags']['nspsytune'] = (bool) ($EncodingFlagsATHtype & 0x10);
                $ThisFileInfo['mpeg']['audio']['LAME']['encoding_flags']['nssafejoint'] = (bool) ($EncodingFlagsATHtype & 0x20);
                $ThisFileInfo['mpeg']['audio']['LAME']['encoding_flags']['nogap_next'] = (bool) ($EncodingFlagsATHtype & 0x40);
                $ThisFileInfo['mpeg']['audio']['LAME']['encoding_flags']['nogap_prev'] = (bool) ($EncodingFlagsATHtype & 0x80);
                $ThisFileInfo['mpeg']['audio']['LAME']['ath_type'] = $EncodingFlagsATHtype & 0xf;
                $ABRbitrateMinBitrate = BigEndian2Int(substr($headerstring, $XingVBROffset, 1));
                $XingVBROffset += 1;
                if ($ThisFileInfo['mpeg']['audio']['LAME']['vbr_method_raw'] == 2) {
                    // Average BitRate (ABR)
                    $ThisFileInfo['mpeg']['audio']['LAME']['bitrate_abr'] = $ABRbitrateMinBitrate;
                } elseif ($ABRbitrateMinBitrate > 0) {
                    // Variable BitRate (VBR) - minimum bitrate
                    $ThisFileInfo['mpeg']['audio']['LAME']['bitrate_min'] = $ABRbitrateMinBitrate;
                }
                $EncoderDelays = BigEndian2Int(substr($headerstring, $XingVBROffset, 3));
                $XingVBROffset += 3;
                $ThisFileInfo['mpeg']['audio']['LAME']['encoder_delay'] = ($EncoderDelays & 0xfff000) >> 12;
                $ThisFileInfo['mpeg']['audio']['LAME']['end_padding'] = $EncoderDelays & 0xfff;
                $MiscByte = BigEndian2Int(substr($headerstring, $XingVBROffset, 1));
                $XingVBROffset += 1;
                $ThisFileInfo['mpeg']['audio']['LAME']['noise_shaping_raw'] = $EncodingFlagsATHtype & 0x3;
                $ThisFileInfo['mpeg']['audio']['LAME']['stereo_mode_raw'] = ($EncodingFlagsATHtype & 0x1c) >> 2;
                $ThisFileInfo['mpeg']['audio']['LAME']['not_optimal_quality_raw'] = ($EncodingFlagsATHtype & 0x20) >> 5;
                $ThisFileInfo['mpeg']['audio']['LAME']['source_sample_freq_raw'] = ($EncodingFlagsATHtype & 0xc0) >> 6;
                $ThisFileInfo['mpeg']['audio']['LAME']['noise_shaping'] = $ThisFileInfo['mpeg']['audio']['LAME']['noise_shaping_raw'];
                $ThisFileInfo['mpeg']['audio']['LAME']['stereo_mode'] = LAMEmiscStereoModeLookup($ThisFileInfo['mpeg']['audio']['LAME']['stereo_mode_raw']);
                $ThisFileInfo['mpeg']['audio']['LAME']['not_optimal_quality'] = (bool) $ThisFileInfo['mpeg']['audio']['LAME']['not_optimal_quality_raw'];
                $ThisFileInfo['mpeg']['audio']['LAME']['source_sample_freq'] = LAMEmiscSourceSampleFrequencyLookup($ThisFileInfo['mpeg']['audio']['LAME']['source_sample_freq_raw']);
                $ThisFileInfo['mpeg']['audio']['LAME']['mp3_gain_raw'] = BigEndian2Int(substr($headerstring, $XingVBROffset, 1), false, true);
                $XingVBROffset += 1;
                $ThisFileInfo['mpeg']['audio']['LAME']['mp3_gain_db'] = 1.5 * $ThisFileInfo['mpeg']['audio']['LAME']['mp3_gain_raw'];
                $ThisFileInfo['mpeg']['audio']['LAME']['mp3_gain_factor'] = pow(2, $ThisFileInfo['mpeg']['audio']['LAME']['mp3_gain_db'] / 6);
                $PresetSurroundBytes = BigEndian2Int(substr($headerstring, $XingVBROffset, 2));
                //$Reserved       = ($PresetSurroundBytes & 0xC000);
                $ThisFileInfo['mpeg']['audio']['LAME']['surround_info_id'] = $PresetSurroundBytes & 0x3800;
                $ThisFileInfo['mpeg']['audio']['LAME']['surround_info'] = LAMEsurroundInfoLookup($ThisFileInfo['mpeg']['audio']['LAME']['surround_info_id']);
                $ThisFileInfo['mpeg']['audio']['LAME']['preset_used_id'] = $PresetSurroundBytes & 0x7ff;
                $XingVBROffset += 2;
                $ThisFileInfo['mpeg']['audio']['LAME']['audio_bytes'] = BigEndian2Int(substr($headerstring, $XingVBROffset, 4));
                $XingVBROffset += 4;
                if ($ThisFileInfo['mpeg']['audio']['LAME']['audio_bytes'] > $ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) {
                    $ThisFileInfo['warning'] .= "\n" . 'Probable truncated file: expecting ' . $ThisFileInfo['mpeg']['audio']['LAME']['audio_bytes'] . ' bytes of audio data, only found ' . ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']);
                }
                $ThisFileInfo['mpeg']['audio']['LAME']['music_crc'] = BigEndian2Int(substr($headerstring, $XingVBROffset, 2));
                $XingVBROffset += 2;
                $ThisFileInfo['mpeg']['audio']['LAME']['lame_tag_crc'] = BigEndian2Int(substr($headerstring, $XingVBROffset, 2));
                $XingVBROffset += 2;
                // LAME CBR
                if ($ThisFileInfo['mpeg']['audio']['LAME']['vbr_method_raw'] == 1) {
                    $ThisFileInfo['mpeg']['audio']['bitrate_mode'] = 'cbr';
                    if (empty($ThisFileInfo['mpeg']['audio']['bitrate']) || $ThisFileInfo['mpeg']['audio']['LAME']['bitrate_min'] != 255) {
                        $ThisFileInfo['mpeg']['audio']['bitrate'] = $ThisFileInfo['mpeg']['audio']['LAME']['bitrate_min'];
                    }
                }
            }
        } else {
            // not Fraunhofer or Xing VBR methods, most likely CBR (but could be VBR with no header)
            $ThisFileInfo['mpeg']['audio']['bitrate_mode'] = 'cbr';
            if ($recursivesearch) {
                $ThisFileInfo['mpeg']['audio']['bitrate_mode'] = 'vbr';
                if (RecursiveFrameScanning($fd, $ThisFileInfo, $offset, $nextframetestoffset, true)) {
                    $recursivesearch = false;
                    $ThisFileInfo['mpeg']['audio']['bitrate_mode'] = 'cbr';
                }
                if ($ThisFileInfo['mpeg']['audio']['bitrate_mode'] == 'vbr') {
                    $ThisFileInfo['warning'] .= "\n" . 'VBR file with no VBR header. Bitrate values calculated from actual frame bitrates.';
                }
            }
        }
    }
    if ($ThisFileInfo['mpeg']['audio']['bitrate_mode'] == 'vbr' && isset($ThisFileInfo['mpeg']['audio']['VBR_frames']) && $ThisFileInfo['mpeg']['audio']['VBR_frames'] > 1) {
        $ThisFileInfo['mpeg']['audio']['VBR_frames']--;
        // don't count the Xing / VBRI frame
        if ($ThisFileInfo['mpeg']['audio']['version'] == '1' && $ThisFileInfo['mpeg']['audio']['layer'] == 'I') {
            $ThisFileInfo['mpeg']['audio']['VBR_bitrate'] = $ThisFileInfo['mpeg']['audio']['VBR_bytes'] / $ThisFileInfo['mpeg']['audio']['VBR_frames'] * 8 * ($ThisFileInfo['audio']['sample_rate'] / 384) / 1000;
        } elseif (($ThisFileInfo['mpeg']['audio']['version'] == '2' || $ThisFileInfo['mpeg']['audio']['version'] == '2.5') && $ThisFileInfo['mpeg']['audio']['layer'] == 'III') {
            $ThisFileInfo['mpeg']['audio']['VBR_bitrate'] = $ThisFileInfo['mpeg']['audio']['VBR_bytes'] / $ThisFileInfo['mpeg']['audio']['VBR_frames'] * 8 * ($ThisFileInfo['audio']['sample_rate'] / 576) / 1000;
        } else {
            $ThisFileInfo['mpeg']['audio']['VBR_bitrate'] = $ThisFileInfo['mpeg']['audio']['VBR_bytes'] / $ThisFileInfo['mpeg']['audio']['VBR_frames'] * 8 * ($ThisFileInfo['audio']['sample_rate'] / 1152) / 1000;
        }
        if ($ThisFileInfo['mpeg']['audio']['VBR_bitrate'] > 0) {
            $ThisFileInfo['audio']['bitrate'] = 1000 * $ThisFileInfo['mpeg']['audio']['VBR_bitrate'];
            $ThisFileInfo['mpeg']['audio']['bitrate'] = $ThisFileInfo['mpeg']['audio']['VBR_bitrate'];
            // to avoid confusion
        }
    }
    // End variable-bitrate headers
    ////////////////////////////////////////////////////////////////////////////////////
    if ($recursivesearch) {
        if (!RecursiveFrameScanning($fd, $ThisFileInfo, $offset, $nextframetestoffset, $ScanAsCBR)) {
            return false;
        }
    }
    if (false) {
        // experimental side info parsing section - not returning anything useful yet
        $SideInfoBitstream = BigEndian2Bin($SideInfoData);
        $SideInfoOffset = 0;
        if ($ThisFileInfo['mpeg']['audio']['version'] == '1') {
            if ($ThisFileInfo['mpeg']['audio']['channelmode'] == 'mono') {
                // MPEG-1 (mono)
                $ThisFileInfo['mpeg']['audio']['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 9);
                $SideInfoOffset += 9;
                $SideInfoOffset += 5;
            } else {
                // MPEG-1 (stereo, joint-stereo, dual-channel)
                $ThisFileInfo['mpeg']['audio']['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 9);
                $SideInfoOffset += 9;
                $SideInfoOffset += 3;
            }
        } else {
            // 2 or 2.5
            if ($ThisFileInfo['mpeg']['audio']['channelmode'] == 'mono') {
                // MPEG-2, MPEG-2.5 (mono)
                $ThisFileInfo['mpeg']['audio']['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 8);
                $SideInfoOffset += 8;
                $SideInfoOffset += 1;
            } else {
                // MPEG-2, MPEG-2.5 (stereo, joint-stereo, dual-channel)
                $ThisFileInfo['mpeg']['audio']['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 8);
                $SideInfoOffset += 8;
                $SideInfoOffset += 2;
            }
        }
        if ($ThisFileInfo['mpeg']['audio']['version'] == '1') {
            for ($channel = 0; $channel < $ThisFileInfo['audio']['channels']; $channel++) {
                for ($scfsi_band = 0; $scfsi_band < 4; $scfsi_band++) {
                    $ThisFileInfo['mpeg']['audio']['scfsi'][$channel][$scfsi_band] = substr($SideInfoBitstream, $SideInfoOffset, 1);
                    $SideInfoOffset += 2;
                }
            }
        }
        for ($granule = 0; $granule < ($ThisFileInfo['mpeg']['audio']['version'] == '1' ? 2 : 1); $granule++) {
            for ($channel = 0; $channel < $ThisFileInfo['audio']['channels']; $channel++) {
                $ThisFileInfo['mpeg']['audio']['part2_3_length'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 12);
                $SideInfoOffset += 12;
                $ThisFileInfo['mpeg']['audio']['big_values'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 9);
                $SideInfoOffset += 9;
                $ThisFileInfo['mpeg']['audio']['global_gain'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 8);
                $SideInfoOffset += 8;
                if ($ThisFileInfo['mpeg']['audio']['version'] == '1') {
                    $ThisFileInfo['mpeg']['audio']['scalefac_compress'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 4);
                    $SideInfoOffset += 4;
                } else {
                    $ThisFileInfo['mpeg']['audio']['scalefac_compress'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 9);
                    $SideInfoOffset += 9;
                }
                $ThisFileInfo['mpeg']['audio']['window_switching_flag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
                $SideInfoOffset += 1;
                if ($ThisFileInfo['mpeg']['audio']['window_switching_flag'][$granule][$channel] == '1') {
                    $ThisFileInfo['mpeg']['audio']['block_type'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 2);
                    $SideInfoOffset += 2;
                    $ThisFileInfo['mpeg']['audio']['mixed_block_flag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
                    $SideInfoOffset += 1;
                    for ($region = 0; $region < 2; $region++) {
                        $ThisFileInfo['mpeg']['audio']['table_select'][$granule][$channel][$region] = substr($SideInfoBitstream, $SideInfoOffset, 5);
                        $SideInfoOffset += 5;
                    }
                    $ThisFileInfo['mpeg']['audio']['table_select'][$granule][$channel][2] = 0;
                    for ($window = 0; $window < 3; $window++) {
                        $ThisFileInfo['mpeg']['audio']['subblock_gain'][$granule][$channel][$window] = substr($SideInfoBitstream, $SideInfoOffset, 3);
                        $SideInfoOffset += 3;
                    }
                } else {
                    for ($region = 0; $region < 3; $region++) {
                        $ThisFileInfo['mpeg']['audio']['table_select'][$granule][$channel][$region] = substr($SideInfoBitstream, $SideInfoOffset, 5);
                        $SideInfoOffset += 5;
                    }
                    $ThisFileInfo['mpeg']['audio']['region0_count'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 4);
                    $SideInfoOffset += 4;
                    $ThisFileInfo['mpeg']['audio']['region1_count'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 3);
                    $SideInfoOffset += 3;
                    $ThisFileInfo['mpeg']['audio']['block_type'][$granule][$channel] = 0;
                }
                if ($ThisFileInfo['mpeg']['audio']['version'] == '1') {
                    $ThisFileInfo['mpeg']['audio']['preflag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
                    $SideInfoOffset += 1;
                }
                $ThisFileInfo['mpeg']['audio']['scalefac_scale'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
                $SideInfoOffset += 1;
                $ThisFileInfo['mpeg']['audio']['count1table_select'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
                $SideInfoOffset += 1;
            }
        }
    }
    return true;
}
Пример #3
0
function GetAllFileInfo($filename, $assumedFormat = '', $MD5file = false, $MD5data = false, $MD5dataIfMD5SourceKnown = false)
{
    $ThisFileInfo = array();
    $localfilepointer = null;
    if (!InitializeFilepointerArray($filename, $localfilepointer, $ThisFileInfo)) {
        // remove unneeded/meaningless keys
        CleanUpGetAllMP3info($ThisFileInfo);
        // close & remove local filepointer
        CloseRemoveFilepointer($localfilepointer);
        return $ThisFileInfo;
    }
    // Handle ID3v1 & Lyrics3 tags
    HandleID3v1Tag($localfilepointer, $ThisFileInfo);
    HandleLyrics3Tag($localfilepointer, $ThisFileInfo);
    rewind($localfilepointer);
    //$formattest = fread($localfilepointer, 16);  // 16 bytes is sufficient for any format except ISO CD-image
    $formattest = fread($localfilepointer, 32774);
    // (ISO needs at least 32774 bytes)
    // Handle ID3v2 tag
    if (HandleID3v2Tag($localfilepointer, $ThisFileInfo)) {
        fseek($localfilepointer, $ThisFileInfo['avdataoffset'], SEEK_SET);
        $formattest = fread($localfilepointer, 32774);
        // (ISO9660 needs at least 32774 bytes)
    }
    // Handle APE tags
    HandleAPETag($localfilepointer, $ThisFileInfo);
    // Nothing-but-tags check
    if ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset'] > 0) {
        if ($assumedFormat) {
            $format_info = GetFileFormatArray();
            require_once GETID3_INCLUDEPATH . $format_info["{$assumedFormat}"]['include'];
            $VariableFunctionName = $format_info["{$assumedFormat}"]['function'];
            $VariableFunctionName($localfilepointer, $ThisFileInfo);
        } elseif ($DeterminedFormat = GetFileFormat($formattest)) {
            // break if ID3/APE tags found on illegal format
            if (!$DeterminedFormat['allowtags'] && $ThisFileInfo['avdataoffset'] > 0 && $ThisFileInfo['avdataend'] != $ThisFileInfo['filesize']) {
                $ThisFileInfo['error'] .= "\n" . 'Illegal ID3 and/or APE tag found on non multimedia file.';
                break;
            }
            // set mime type
            $ThisFileInfo['mime_type'] = $DeterminedFormat['mimetype'];
            // supported format signature pattern detected
            if (!file_exists(GETID3_INCLUDEPATH . $DeterminedFormat['include'])) {
                die('<HR><FONT COLOR="#FF0000">Cannot find required file: ' . GETID3_INCLUDEPATH . $DeterminedFormat['include'] . '</FONT>');
            }
            require_once GETID3_INCLUDEPATH . $DeterminedFormat['include'];
            $VariableFunctionName = $DeterminedFormat['function'];
            $VariableFunctionName($localfilepointer, $ThisFileInfo);
        } elseif ($assumedFormat == 'mp3' || $assumedFormat == '' && (substr($formattest, 0, 3) == 'ID3' || substr(BigEndian2Bin(substr($formattest, 0, 2)), 0, 11) == '11111111111')) {
            // assume AAC-ADTS format
            require_once GETID3_INCLUDEPATH . 'getid3.aac.php';
            $dummy = $ThisFileInfo;
            if (getAACADTSheaderFilepointer($localfilepointer, $dummy)) {
                $ThisFileInfo = $dummy;
            } else {
                // it's not AAC-ADTS format, probably MP3
                require_once GETID3_INCLUDEPATH . 'getid3.mp3.php';
                getMP3headerFilepointer($localfilepointer, $ThisFileInfo);
            }
        } else {
            // unknown format, do nothing
        }
    }
    if (!empty($ThisFileInfo['audio']['channels'])) {
        switch ($ThisFileInfo['audio']['channels']) {
            case 1:
                $ThisFileInfo['audio']['channelmode'] = 'mono';
                break;
            case 2:
                $ThisFileInfo['audio']['channelmode'] = 'stereo';
                break;
            default:
                // unknown?
                break;
        }
    }
    // Get the MD5 hash of the entire file
    if ($MD5file && empty($ThisFileInfo['md5_file'])) {
        set_time_limit(max($ThisFileInfo['filesize'] / 10000000, 30));
        $ThisFileInfo['md5_file'] = md5_file($filename);
    }
    // Get the MD5 hash of the audio/video portion of the file
    // (without ID3/APE/Lyrics3/etc header/footer tags
    if ($MD5data && empty($ThisFileInfo['md5_data'])) {
        if ($MD5dataIfMD5SourceKnown || empty($ThisFileInfo['md5_data_source'])) {
            // Only calculate ['md5_data'] if ['md5_data_source'] is unknown,
            // or if $MD5dataIfMD5SourceKnown is set to true
            getMD5data($ThisFileInfo);
        }
    }
    CalculateCompressionRatioVideo($ThisFileInfo);
    CalculateCompressionRatioAudio($ThisFileInfo);
    // return tags data in alphabetical order, without duplicates
    $ThisFileInfo['tags'] = array_unique($ThisFileInfo['tags']);
    sort($ThisFileInfo['tags']);
    // remove unneeded/meaningless keys
    CleanUpGetAllMP3info($ThisFileInfo);
    if (isset($ThisFileInfo['fileformat'])) {
        // Calculate combined bitrate - audio + video
        $CombinedBitrate = 0;
        $CombinedBitrate += isset($ThisFileInfo['audio']['bitrate']) ? $ThisFileInfo['audio']['bitrate'] : 0;
        $CombinedBitrate += isset($ThisFileInfo['video']['bitrate']) ? $ThisFileInfo['video']['bitrate'] : 0;
        if ($CombinedBitrate > 0 && !isset($ThisFileInfo['bitrate'])) {
            $ThisFileInfo['bitrate'] = $CombinedBitrate;
        }
        if (isset($ThisFileInfo['video']) && !isset($ThisFileInfo['video']['bitrate']) || isset($ThisFileInfo['audio']) && !isset($ThisFileInfo['audio']['bitrate'])) {
            // for example, VBR MPEG video files cannot determine video bitrate:
            // should not set overall bitrate and playtime from audio bitrate only
            unset($ThisFileInfo['bitrate']);
        }
        if (!isset($ThisFileInfo['playtime_seconds']) && !empty($ThisFileInfo['bitrate'])) {
            $ThisFileInfo['playtime_seconds'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 / $ThisFileInfo['bitrate'];
        }
        // Set playtime string
        if (!empty($ThisFileInfo['playtime_seconds']) && empty($ThisFileInfo['playtime_string'])) {
            $ThisFileInfo['playtime_string'] = PlaytimeString($ThisFileInfo['playtime_seconds']);
        }
    }
    // close & remove local filepointer
    CloseRemoveFilepointer($localfilepointer);
    return $ThisFileInfo;
}
Пример #4
0
function getOnlyMPEGaudioInfo($fd, &$MP3fileInfo, $audiodataoffset)
{
    // looks for synch, decodes MPEG audio header
    // you may call this function directly if you don't need any ID3 info
    fseek($fd, $audiodataoffset);
    $header = '';
    $SynchSeekOffset = 0;
    while (!isset($MP3fileInfo['fileformat']) || $MP3fileInfo['fileformat'] == '' || $MP3fileInfo['fileformat'] == 'id3') {
        if ($SynchSeekOffset > strlen($header) - 8192 && !feof($fd)) {
            if ($SynchSeekOffset > FREAD_BUFFER_SIZE * 4) {
                // if a synch's not found within the first 64k bytes, then give up
                $MP3fileInfo['error'] .= "\n" . 'could not find valid MPEG synch within the first ' . FREAD_BUFFER_SIZE * 4 . ' bytes';
                if (isset($MP3fileInfo['bitrate'])) {
                    unset($MP3fileInfo['bitrate']);
                }
                if (isset($MP3fileInfo['mpeg']['audio'])) {
                    unset($MP3fileInfo['mpeg']['audio']);
                }
                if (isset($MP3fileInfo['mpeg']) && (!is_array($MP3fileInfo['mpeg']) || count($MP3fileInfo['mpeg']) == 0)) {
                    unset($MP3fileInfo['mpeg']);
                }
                return FALSE;
            } else {
                if ($header .= fread($fd, FREAD_BUFFER_SIZE)) {
                    // great
                } else {
                    $MP3fileInfo['error'] .= "\n" . 'could not find valid MPEG synch before end of file';
                    if (isset($MP3fileInfo['bitrate'])) {
                        unset($MP3fileInfo['bitrate']);
                    }
                    if (isset($MP3fileInfo['mpeg']['audio'])) {
                        unset($MP3fileInfo['mpeg']['audio']);
                    }
                    if (isset($MP3fileInfo['mpeg']) && (!is_array($MP3fileInfo['mpeg']) || count($MP3fileInfo['mpeg']) == 0)) {
                        unset($MP3fileInfo['mpeg']);
                    }
                    return FALSE;
                }
            }
        }
        if (ord($header[$SynchSeekOffset]) == 0xff && substr(BigEndian2Bin(substr($header, $SynchSeekOffset, 2)), 0, 11) == '11111111111') {
            // synch detected
            if (decodeMPEGaudioHeader($fd, $audiodataoffset + $SynchSeekOffset, $MP3fileInfo, TRUE)) {
                $MP3fileInfo['audiodataoffset'] = $audiodataoffset + $SynchSeekOffset;
                $MP3fileInfo['fileformat'] = 'mp3';
                break;
                // exit for() and while()
            }
        }
        if (!isset($MP3fileInfo['fileformat']) || $MP3fileInfo['fileformat'] == '' || $MP3fileInfo['fileformat'] == 'id3') {
            $SynchSeekOffset++;
            if ($audiodataoffset + $SynchSeekOffset >= $MP3fileInfo['filesize']) {
                // end of file
                $MP3fileInfo['error'] .= "\n" . 'could not find valid MPEG synch before end of file';
                if (isset($MP3fileInfo['bitrate'])) {
                    unset($MP3fileInfo['bitrate']);
                }
                if (isset($MP3fileInfo['mpeg']['audio'])) {
                    unset($MP3fileInfo['mpeg']['audio']);
                }
                if (isset($MP3fileInfo['mpeg']) && (!is_array($MP3fileInfo['mpeg']) || count($MP3fileInfo['mpeg']) == 0)) {
                    unset($MP3fileInfo['mpeg']);
                }
                return FALSE;
            }
        }
    }
    return TRUE;
}
Пример #5
0
function getAACADIFheaderFilepointer(&$fd, &$ThisFileInfo)
{
    $ThisFileInfo['fileformat'] = 'aac';
    $ThisFileInfo['audio']['dataformat'] = 'aac';
    $ThisFileInfo['audio']['lossless'] = false;
    fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
    $AACheader = fread($fd, 1024);
    $offset = 0;
    if (substr($AACheader, 0, 4) == 'ADIF') {
        // http://faac.sourceforge.net/wiki/index.php?page=ADIF
        // http://libmpeg.org/mpeg4/doc/w2203tfs.pdf
        // adif_header() {
        //     adif_id                                32
        //     copyright_id_present                    1
        //     if( copyright_id_present )
        //         copyright_id                       72
        //     original_copy                           1
        //     home                                    1
        //     bitstream_type                          1
        //     bitrate                                23
        //     num_program_config_elements             4
        //     for (i = 0; i < num_program_config_elements + 1; i++ ) {
        //         if( bitstream_type == '0' )
        //             adif_buffer_fullness           20
        //         program_config_element()
        //     }
        // }
        $AACheaderBitstream = BigEndian2Bin($AACheader);
        $bitoffset = 0;
        $ThisFileInfo['aac']['header_type'] = 'ADIF';
        $bitoffset += 32;
        $ThisFileInfo['aac']['header']['mpeg_version'] = 4;
        $ThisFileInfo['aac']['header']['copyright'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1');
        $bitoffset += 1;
        if ($ThisFileInfo['aac']['header']['copyright']) {
            $ThisFileInfo['aac']['header']['copyright_id'] = Bin2String(substr($AACheaderBitstream, $bitoffset, 72));
            $bitoffset += 72;
        }
        $ThisFileInfo['aac']['header']['original_copy'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1');
        $bitoffset += 1;
        $ThisFileInfo['aac']['header']['home'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1');
        $bitoffset += 1;
        $ThisFileInfo['aac']['header']['is_vbr'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1');
        $bitoffset += 1;
        if ($ThisFileInfo['aac']['header']['is_vbr']) {
            $ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
            $ThisFileInfo['aac']['header']['bitrate_max'] = Bin2Dec(substr($AACheaderBitstream, $bitoffset, 23));
            $bitoffset += 23;
        } else {
            $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
            $ThisFileInfo['aac']['header']['bitrate'] = Bin2Dec(substr($AACheaderBitstream, $bitoffset, 23));
            $bitoffset += 23;
            $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['aac']['header']['bitrate'];
        }
        if ($ThisFileInfo['audio']['bitrate'] == 0) {
            $ThisFileInfo['error'] .= "\n" . 'Corrupt AAC file: bitrate_audio == zero';
            return false;
        }
        $ThisFileInfo['aac']['header']['num_program_configs'] = 1 + Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
        $bitoffset += 4;
        for ($i = 0; $i < $ThisFileInfo['aac']['header']['num_program_configs']; $i++) {
            // http://www.audiocoding.com/wiki/index.php?page=program_config_element
            // buffer_fullness                       20
            // element_instance_tag                   4
            // object_type                            2
            // sampling_frequency_index               4
            // num_front_channel_elements             4
            // num_side_channel_elements              4
            // num_back_channel_elements              4
            // num_lfe_channel_elements               2
            // num_assoc_data_elements                3
            // num_valid_cc_elements                  4
            // mono_mixdown_present                   1
            // mono_mixdown_element_number            4   if mono_mixdown_present == 1
            // stereo_mixdown_present                 1
            // stereo_mixdown_element_number          4   if stereo_mixdown_present == 1
            // matrix_mixdown_idx_present             1
            // matrix_mixdown_idx                     2   if matrix_mixdown_idx_present == 1
            // pseudo_surround_enable                 1   if matrix_mixdown_idx_present == 1
            // for (i = 0; i < num_front_channel_elements; i++) {
            //     front_element_is_cpe[i]            1
            //     front_element_tag_select[i]        4
            // }
            // for (i = 0; i < num_side_channel_elements; i++) {
            //     side_element_is_cpe[i]             1
            //     side_element_tag_select[i]         4
            // }
            // for (i = 0; i < num_back_channel_elements; i++) {
            //     back_element_is_cpe[i]             1
            //     back_element_tag_select[i]         4
            // }
            // for (i = 0; i < num_lfe_channel_elements; i++) {
            //     lfe_element_tag_select[i]          4
            // }
            // for (i = 0; i < num_assoc_data_elements; i++) {
            //     assoc_data_element_tag_select[i]   4
            // }
            // for (i = 0; i < num_valid_cc_elements; i++) {
            //     cc_element_is_ind_sw[i]            1
            //     valid_cc_element_tag_select[i]     4
            // }
            // byte_alignment()                       VAR
            // comment_field_bytes                    8
            // for (i = 0; i < comment_field_bytes; i++) {
            //     comment_field_data[i]              8
            // }
            if (!$ThisFileInfo['aac']['header']['is_vbr']) {
                $ThisFileInfo['aac']['program_configs'][$i]['buffer_fullness'] = Bin2Dec(substr($AACheaderBitstream, $bitoffset, 20));
                $bitoffset += 20;
            }
            $ThisFileInfo['aac']['program_configs'][$i]['element_instance_tag'] = Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
            $bitoffset += 4;
            $ThisFileInfo['aac']['program_configs'][$i]['object_type'] = Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2));
            $bitoffset += 2;
            $ThisFileInfo['aac']['program_configs'][$i]['sampling_frequency_index'] = Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
            $bitoffset += 4;
            $ThisFileInfo['aac']['program_configs'][$i]['num_front_channel_elements'] = Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
            $bitoffset += 4;
            $ThisFileInfo['aac']['program_configs'][$i]['num_side_channel_elements'] = Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
            $bitoffset += 4;
            $ThisFileInfo['aac']['program_configs'][$i]['num_back_channel_elements'] = Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
            $bitoffset += 4;
            $ThisFileInfo['aac']['program_configs'][$i]['num_lfe_channel_elements'] = Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2));
            $bitoffset += 2;
            $ThisFileInfo['aac']['program_configs'][$i]['num_assoc_data_elements'] = Bin2Dec(substr($AACheaderBitstream, $bitoffset, 3));
            $bitoffset += 3;
            $ThisFileInfo['aac']['program_configs'][$i]['num_valid_cc_elements'] = Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
            $bitoffset += 4;
            $ThisFileInfo['aac']['program_configs'][$i]['mono_mixdown_present'] = (bool) Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
            $bitoffset += 1;
            if ($ThisFileInfo['aac']['program_configs'][$i]['mono_mixdown_present']) {
                $ThisFileInfo['aac']['program_configs'][$i]['mono_mixdown_element_number'] = Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
                $bitoffset += 4;
            }
            $ThisFileInfo['aac']['program_configs'][$i]['stereo_mixdown_present'] = (bool) Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
            $bitoffset += 1;
            if ($ThisFileInfo['aac']['program_configs'][$i]['stereo_mixdown_present']) {
                $ThisFileInfo['aac']['program_configs'][$i]['stereo_mixdown_element_number'] = Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
                $bitoffset += 4;
            }
            $ThisFileInfo['aac']['program_configs'][$i]['matrix_mixdown_idx_present'] = (bool) Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
            $bitoffset += 1;
            if ($ThisFileInfo['aac']['program_configs'][$i]['matrix_mixdown_idx_present']) {
                $ThisFileInfo['aac']['program_configs'][$i]['matrix_mixdown_idx'] = Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2));
                $bitoffset += 2;
                $ThisFileInfo['aac']['program_configs'][$i]['pseudo_surround_enable'] = (bool) Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
                $bitoffset += 1;
            }
            for ($j = 0; $j < $ThisFileInfo['aac']['program_configs'][$i]['num_front_channel_elements']; $j++) {
                $ThisFileInfo['aac']['program_configs'][$i]['front_element_is_cpe'][$j] = (bool) Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
                $bitoffset += 1;
                $ThisFileInfo['aac']['program_configs'][$i]['front_element_tag_select'][$j] = Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
                $bitoffset += 4;
            }
            for ($j = 0; $j < $ThisFileInfo['aac']['program_configs'][$i]['num_side_channel_elements']; $j++) {
                $ThisFileInfo['aac']['program_configs'][$i]['side_element_is_cpe'][$j] = (bool) Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
                $bitoffset += 1;
                $ThisFileInfo['aac']['program_configs'][$i]['side_element_tag_select'][$j] = Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
                $bitoffset += 4;
            }
            for ($j = 0; $j < $ThisFileInfo['aac']['program_configs'][$i]['num_back_channel_elements']; $j++) {
                $ThisFileInfo['aac']['program_configs'][$i]['back_element_is_cpe'][$j] = (bool) Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
                $bitoffset += 1;
                $ThisFileInfo['aac']['program_configs'][$i]['back_element_tag_select'][$j] = Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
                $bitoffset += 4;
            }
            for ($j = 0; $j < $ThisFileInfo['aac']['program_configs'][$i]['num_lfe_channel_elements']; $j++) {
                $ThisFileInfo['aac']['program_configs'][$i]['lfe_element_tag_select'][$j] = Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
                $bitoffset += 4;
            }
            for ($j = 0; $j < $ThisFileInfo['aac']['program_configs'][$i]['num_assoc_data_elements']; $j++) {
                $ThisFileInfo['aac']['program_configs'][$i]['assoc_data_element_tag_select'][$j] = Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
                $bitoffset += 4;
            }
            for ($j = 0; $j < $ThisFileInfo['aac']['program_configs'][$i]['num_valid_cc_elements']; $j++) {
                $ThisFileInfo['aac']['program_configs'][$i]['cc_element_is_ind_sw'][$j] = (bool) Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
                $bitoffset += 1;
                $ThisFileInfo['aac']['program_configs'][$i]['valid_cc_element_tag_select'][$j] = Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
                $bitoffset += 4;
            }
            $bitoffset = ceil($bitoffset / 8) * 8;
            $ThisFileInfo['aac']['program_configs'][$i]['comment_field_bytes'] = Bin2Dec(substr($AACheaderBitstream, $bitoffset, 8));
            $bitoffset += 8;
            $ThisFileInfo['aac']['program_configs'][$i]['comment_field'] = Bin2String(substr($AACheaderBitstream, $bitoffset, 8 * $ThisFileInfo['aac']['program_configs'][$i]['comment_field_bytes']));
            $bitoffset += 8 * $ThisFileInfo['aac']['program_configs'][$i]['comment_field_bytes'];
            $ThisFileInfo['aac']['header']['profile_text'] = AACprofileLookup($ThisFileInfo['aac']['program_configs'][$i]['object_type'], $ThisFileInfo['aac']['header']['mpeg_version']);
            $ThisFileInfo['aac']['program_configs'][$i]['sampling_frequency'] = AACsampleRateLookup($ThisFileInfo['aac']['program_configs'][$i]['sampling_frequency_index']);
            $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['aac']['program_configs'][$i]['sampling_frequency'];
            $ThisFileInfo['audio']['channels'] = AACchannelCountCalculate($ThisFileInfo['aac']['program_configs'][$i]);
            if ($ThisFileInfo['aac']['program_configs'][$i]['comment_field']) {
                $ThisFileInfo['comments']['comment'][] = $ThisFileInfo['aac']['program_configs'][$i]['comment_field'];
            }
        }
        $ThisFileInfo['playtime_seconds'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 / $ThisFileInfo['audio']['bitrate'];
        return true;
    } else {
        unset($ThisFileInfo['fileformat']);
        unset($ThisFileInfo['aac']);
        $ThisFileInfo['error'] .= "\n" . 'AAC-ADIF synch not found (expected "ADIF", found "' . substr($AACheader, 0, 4) . '" instead)';
        return false;
    }
}
function ID3v2FrameProcessing($frame_name, $frame_flags, &$MP3fileInfo)
{
    // define $frame_arrayindex once here (used for many frames), override or ignore as neccesary
    $frame_arrayindex = count($MP3fileInfo['id3']['id3v2']["{$frame_name}"]);
    // 'data', 'datalength'
    if (isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'])) {
        $frame_arrayindex--;
    }
    if (isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'])) {
        $frame_arrayindex--;
    }
    if (isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'])) {
        $frame_arrayindex--;
    }
    if (isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'])) {
        $frame_arrayindex--;
    }
    if (isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['timestampformat'])) {
        $frame_arrayindex--;
    }
    if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
        // frame flags are not part of the ID3v2.2 standard
        if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 3) {
            //	Frame Header Flags
            //	%abc00000 %ijk00000
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['TagAlterPreservation'] = (bool) substr($frame_flags, 0, 1);
            // a - Tag alter preservation
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['FileAlterPreservation'] = (bool) substr($frame_flags, 1, 1);
            // b - File alter preservation
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['ReadOnly'] = (bool) substr($frame_flags, 2, 1);
            // c - Read only
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['compression'] = (bool) substr($frame_flags, 8, 1);
            // i - Compression
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['Encryption'] = (bool) substr($frame_flags, 9, 1);
            // j - Encryption
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['GroupingIdentity'] = (bool) substr($frame_flags, 10, 1);
            // k - Grouping identity
        } else {
            if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 4) {
                //	Frame Header Flags
                //	%0abc0000 %0h00kmnp
                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['TagAlterPreservation'] = (bool) substr($frame_flags, 1, 1);
                // a - Tag alter preservation
                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['FileAlterPreservation'] = (bool) substr($frame_flags, 2, 1);
                // b - File alter preservation
                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['ReadOnly'] = (bool) substr($frame_flags, 3, 1);
                // c - Read only
                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['GroupingIdentity'] = (bool) substr($frame_flags, 9, 1);
                // h - Grouping identity
                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['compression'] = (bool) substr($frame_flags, 12, 1);
                // k - Compression
                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['Encryption'] = (bool) substr($frame_flags, 13, 1);
                // m - Encryption
                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['Unsynchronisation'] = (bool) substr($frame_flags, 14, 1);
                // n - Unsynchronisation
                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['DataLengthIndicator'] = (bool) substr($frame_flags, 15, 1);
                // p - Data length indicator
            }
        }
        //	Frame-level de-unsynchronization - ID3v2.4
        if (isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['Unsynchronisation'])) {
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'] = DeUnSynchronise($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
        }
        //	Frame-level de-compression
        if (isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['compression'])) {
            // it's on the wishlist :)
        }
    }
    if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'UFID' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'UFI') {
        // 4.1   UFI  Unique file identifier
        //   There may be more than one 'UFID' frame in a tag,
        //   but only one with the same 'Owner identifier'.
        // <Header for 'Unique file identifier', ID: 'UFID'>
        // Owner identifier        <text string> $00
        // Identifier              <up to 64 bytes binary data>
        $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0));
        $frame_idstring = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], 0, $frame_terminatorpos);
        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['ownerid'] = $frame_idstring;
        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(chr(0)));
        if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
        }
        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
    } else {
        if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'TXXX' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'TXX') {
            // 4.2.2 TXX  User defined text information frame
            //   There may be more than one 'TXXX' frame in each tag,
            //   but only one with the same description.
            // <Header for 'User defined text information frame', ID: 'TXXX'>
            // Text encoding     $xx
            // Description       <text string according to encoding> $00 (00)
            // Value             <text string according to encoding>
            $frame_offset = 0;
            $frame_textencoding = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
            $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
            if (ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
                $frame_terminatorpos++;
                // strpos() fooled because 2nd byte of Unicode chars are often 0x00
            }
            $frame_description = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
            if (ord($frame_description) === 0) {
                $frame_description = '';
            }
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encodingid'] = $frame_textencoding;
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
            if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
            }
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['description'] = $frame_description;
            if (!isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression']) || $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression'] === FALSE) {
                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['asciidescription'] = RoughTranslateUnicodeToASCII($frame_description, $frame_textencoding);
            }
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)));
            if (!isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression']) || $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression'] === FALSE) {
                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['asciidata'] = RoughTranslateUnicodeToASCII($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data'], $frame_textencoding);
            }
            if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
            }
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
        } else {
            if ($frame_name[0] == 'T') {
                // 4.2. T??[?] Text information frame
                //   There may only be one text information frame of its kind in an tag.
                // <Header for 'Text information frame', ID: 'T000' - 'TZZZ',
                // excluding 'TXXX' described in 4.2.6.>
                // Text encoding                $xx
                // Information                  <text string(s) according to encoding>
                $frame_offset = 0;
                $frame_textencoding = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                // $MP3fileInfo['id3']['id3v2']["$frame_name"]['data'] = substr($MP3fileInfo['id3']['id3v2']["$frame_name"]['data'], $frame_offset);
                // this one-line method should work, but as a safeguard against null-padded data, do it the safe way
                $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
                if (ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
                    $frame_terminatorpos++;
                    // strpos() fooled because 2nd byte of Unicode chars are often 0x00
                }
                if ($frame_terminatorpos) {
                    // there are null bytes after the data - this is not according to spec
                    // only use data up to first null byte
                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                } else {
                    // no null bytes following data, just use all data
                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                }
                if (!isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['compression']) || !$MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['compression']) {
                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['asciidata'] = RoughTranslateUnicodeToASCII($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_textencoding);
                }
                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['encodingid'] = $frame_textencoding;
                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
            } else {
                if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'WXXX' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'WXX') {
                    // 4.3.2 WXX  User defined URL link frame
                    //   There may be more than one 'WXXX' frame in each tag,
                    //   but only one with the same description
                    // <Header for 'User defined URL link frame', ID: 'WXXX'>
                    // Text encoding     $xx
                    // Description       <text string according to encoding> $00 (00)
                    // URL               <text string>
                    $frame_offset = 0;
                    $frame_textencoding = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                    $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
                    if (ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
                        $frame_terminatorpos++;
                        // strpos() fooled because 2nd byte of Unicode chars are often 0x00
                    }
                    $frame_description = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                    if (ord($frame_description) === 0) {
                        $frame_description = '';
                    }
                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)));
                    $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding));
                    if (ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
                        $frame_terminatorpos++;
                        // strpos() fooled because 2nd byte of Unicode chars are often 0x00
                    }
                    if ($frame_terminatorpos) {
                        // there are null bytes after the data - this is not according to spec
                        // only use data up to first null byte
                        $frame_urldata = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], 0, $frame_terminatorpos);
                    } else {
                        // no null bytes following data, just use all data
                        $frame_urldata = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'];
                    }
                    if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                    }
                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encodingid'] = $frame_textencoding;
                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['url'] = $frame_urldata;
                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['description'] = $frame_description;
                    if (!isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression']) || $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression'] === FALSE) {
                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['asciidescription'] = RoughTranslateUnicodeToASCII($frame_description, $frame_textencoding);
                    }
                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                } else {
                    if ($frame_name[0] == 'W') {
                        // 4.3. W??? URL link frames
                        //   There may only be one URL link frame of its kind in a tag,
                        //   except when stated otherwise in the frame description
                        // <Header for 'URL link frame', ID: 'W000' - 'WZZZ', excluding 'WXXX'
                        // described in 4.3.2.>
                        // URL              <text string>
                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['url'] = trim($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                        if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                        }
                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                    } else {
                        if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 3 && $frame_name == 'IPLS' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'IPL') {
                            // 4.4  IPL  Involved people list (ID3v2.2 only)
                            //   There may only be one 'IPL' frame in each tag
                            // <Header for 'User defined URL link frame', ID: 'IPL'>
                            // Text encoding     $xx
                            // People list strings    <textstrings>
                            $frame_offset = 0;
                            $frame_textencoding = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['encodingid'] = $frame_textencoding;
                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['encoding'] = TextEncodingLookup('encoding', $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['encodingid']);
                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['asciidata'] = RoughTranslateUnicodeToASCII($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_textencoding);
                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                        } else {
                            if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'MCDI' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'MCI') {
                                // 4.5   MCI  Music CD identifier
                                //   There may only be one 'MCDI' frame in each tag
                                // <Header for 'Music CD identifier', ID: 'MCDI'>
                                // CD TOC                <binary data>
                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                // no other special processing needed
                            } else {
                                if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'ETCO' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'ETC') {
                                    // 4.6   ETC  Event timing codes
                                    //   There may only be one 'ETCO' frame in each tag
                                    // <Header for 'Event timing codes', ID: 'ETCO'>
                                    // Time stamp format    $xx
                                    //   Where time stamp format is:
                                    // $01  (32-bit value) MPEG frames from beginning of file
                                    // $02  (32-bit value) milliseconds from beginning of file
                                    //   Followed by a list of key events in the following format:
                                    // Type of event   $xx
                                    // Time stamp      $xx (xx ...)
                                    //   The 'Time stamp' is set to zero if directly at the beginning of the sound
                                    //   or after the previous event. All events MUST be sorted in chronological order.
                                    $frame_offset = 0;
                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['timestampformat'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                    while ($frame_offset < strlen($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'])) {
                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['typeid'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1);
                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['type'] = ETCOEventLookup($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['typeid']);
                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['timestamp'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 4));
                                        $frame_offset += 4;
                                    }
                                    if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                    }
                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                } else {
                                    if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'MLLT' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'MLL') {
                                        // 4.7   MLL MPEG location lookup table
                                        //   There may only be one 'MLLT' frame in each tag
                                        // <Header for 'Location lookup table', ID: 'MLLT'>
                                        // MPEG frames between reference  $xx xx
                                        // Bytes between reference        $xx xx xx
                                        // Milliseconds between reference $xx xx xx
                                        // Bits for bytes deviation       $xx
                                        // Bits for milliseconds dev.     $xx
                                        //   Then for every reference the following data is included;
                                        // Deviation in bytes         %xxx....
                                        // Deviation in milliseconds  %xxx....
                                        $frame_offset = 0;
                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['framesbetweenreferences'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], 0, 2));
                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['bytesbetweenreferences'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], 2, 3));
                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['msbetweenreferences'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], 5, 3));
                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['bitsforbytesdeviation'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], 8, 1));
                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['bitsformsdeviation'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], 9, 1));
                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], 10);
                                        while ($frame_offset < strlen($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'])) {
                                            $deviationbitstream .= BigEndian2Bin(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                        }
                                        while (strlen($deviationbitstream)) {
                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['bytedeviation'] = bindec(substr($deviationbitstream, 0, $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['bitsforbytesdeviation']));
                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['msdeviation'] = bindec(substr($deviationbitstream, $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['bitsforbytesdeviation'], $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['bitsformsdeviation']));
                                            $deviationbitstream = substr($deviationbitstream, $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['bitsforbytesdeviation'] + $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['bitsformsdeviation']);
                                            $frame_arrayindex++;
                                        }
                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                    } else {
                                        if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'SYTC' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'STC') {
                                            // 4.8   STC  Synchronised tempo codes
                                            //   There may only be one 'SYTC' frame in each tag
                                            // <Header for 'Synchronised tempo codes', ID: 'SYTC'>
                                            // Time stamp format   $xx
                                            // Tempo data          <binary data>
                                            //   Where time stamp format is:
                                            // $01  (32-bit value) MPEG frames from beginning of file
                                            // $02  (32-bit value) milliseconds from beginning of file
                                            $frame_offset = 0;
                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['timestampformat'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                            while ($frame_offset < strlen($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'])) {
                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['tempo'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                if ($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['tempo'] == 255) {
                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['tempo'] += ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                }
                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['timestamp'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 4));
                                                $frame_offset += 4;
                                                $frame_arrayindex++;
                                            }
                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                        } else {
                                            if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'USLT' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'ULT') {
                                                // 4.9   ULT  Unsynchronised lyric/text transcription
                                                //   There may be more than one 'Unsynchronised lyrics/text transcription' frame
                                                //   in each tag, but only one with the same language and content descriptor.
                                                // <Header for 'Unsynchronised lyrics/text transcription', ID: 'USLT'>
                                                // Text encoding        $xx
                                                // Language             $xx xx xx
                                                // Content descriptor   <text string according to encoding> $00 (00)
                                                // Lyrics/text          <full text string according to encoding>
                                                $frame_offset = 0;
                                                $frame_textencoding = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                $frame_language = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 3);
                                                $frame_offset += 3;
                                                $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
                                                if (ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
                                                    $frame_terminatorpos++;
                                                    // strpos() fooled because 2nd byte of Unicode chars are often 0x00
                                                }
                                                $frame_description = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                if (ord($frame_description) === 0) {
                                                    $frame_description = '';
                                                }
                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)));
                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encodingid'] = $frame_textencoding;
                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'];
                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['language'] = $frame_language;
                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['languagename'] = LanguageLookup($frame_language, FALSE);
                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['description'] = $frame_description;
                                                if (!isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression']) || $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression'] === FALSE) {
                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['asciidescription'] = RoughTranslateUnicodeToASCII($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['description'], $frame_textencoding);
                                                }
                                                if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                }
                                                if (!isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression']) || $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression'] === FALSE) {
                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['asciidata'] = RoughTranslateUnicodeToASCII($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data'], $frame_textencoding);
                                                }
                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                            } else {
                                                if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'SYLT' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'SLT') {
                                                    // 4.10  SLT  Synchronised lyric/text
                                                    //   There may be more than one 'SYLT' frame in each tag,
                                                    //   but only one with the same language and content descriptor.
                                                    // <Header for 'Synchronised lyrics/text', ID: 'SYLT'>
                                                    // Text encoding        $xx
                                                    // Language             $xx xx xx
                                                    // Time stamp format    $xx
                                                    //   $01  (32-bit value) MPEG frames from beginning of file
                                                    //   $02  (32-bit value) milliseconds from beginning of file
                                                    // Content type         $xx
                                                    // Content descriptor   <text string according to encoding> $00 (00)
                                                    //   Terminated text to be synced (typically a syllable)
                                                    //   Sync identifier (terminator to above string)   $00 (00)
                                                    //   Time stamp                                     $xx (xx ...)
                                                    $frame_offset = 0;
                                                    $frame_textencoding = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                    $frame_language = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 3);
                                                    $frame_offset += 3;
                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['timestampformat'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['contenttypeid'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['contenttype'] = SYTLContentTypeLookup($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['contenttypeid']);
                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encodingid'] = $frame_textencoding;
                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['language'] = $frame_language;
                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['languagename'] = LanguageLookup($frame_language, FALSE);
                                                    if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                    }
                                                    $timestampindex = 0;
                                                    $frame_remainingdata = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                    while (strlen($frame_remainingdata)) {
                                                        $frame_offset = 0;
                                                        $frame_terminatorpos = strpos($frame_remainingdata, TextEncodingLookup('terminator', $frame_textencoding));
                                                        if ($frame_terminatorpos === FALSE) {
                                                            $frame_remainingdata = '';
                                                        } else {
                                                            if (ord(substr($frame_remainingdata, $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
                                                                $frame_terminatorpos++;
                                                                // strpos() fooled because 2nd byte of Unicode chars are often 0x00
                                                            }
                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data']["{$timestampindex}"]['data'] = substr($frame_remainingdata, $frame_offset, $frame_terminatorpos - $frame_offset);
                                                            if (!isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression']) || $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression'] === FALSE) {
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data']["{$timestampindex}"]['asciidata'] = RoughTranslateUnicodeToASCII($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data']["{$timestampindex}"]['data'], $frame_textencoding);
                                                            }
                                                            $frame_remainingdata = substr($frame_remainingdata, $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)));
                                                            if ($timestampindex == 0 && ord($frame_remainingdata[0]) != 0) {
                                                                // timestamp probably omitted for first data item
                                                            } else {
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data']["{$timestampindex}"]['timestamp'] = BigEndian2Int(substr($frame_remainingdata, 0, 4));
                                                                $frame_remainingdata = substr($frame_remainingdata, 4);
                                                            }
                                                            $timestampindex++;
                                                        }
                                                    }
                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                } else {
                                                    if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'COMM' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'COM') {
                                                        // 4.11  COM  Comments
                                                        //   There may be more than one comment frame in each tag,
                                                        //   but only one with the same language and content descriptor.
                                                        // <Header for 'Comment', ID: 'COMM'>
                                                        // Text encoding          $xx
                                                        // Language               $xx xx xx
                                                        // Short content descrip. <text string according to encoding> $00 (00)
                                                        // The actual text        <full text string according to encoding>
                                                        $frame_offset = 0;
                                                        $frame_textencoding = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                        $frame_language = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 3);
                                                        $frame_offset += 3;
                                                        $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
                                                        if (ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
                                                            $frame_terminatorpos++;
                                                            // strpos() fooled because 2nd byte of Unicode chars are often 0x00
                                                        }
                                                        $frame_description = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                        if (ord($frame_description) === 0) {
                                                            $frame_description = '';
                                                        }
                                                        $frame_text = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)));
                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encodingid'] = $frame_textencoding;
                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['language'] = $frame_language;
                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['languagename'] = LanguageLookup($frame_language, FALSE);
                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['description'] = $frame_description;
                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data'] = $frame_text;
                                                        if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                        }
                                                        if (!isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression']) || $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression'] === FALSE) {
                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['asciidescription'] = RoughTranslateUnicodeToASCII($frame_description, $frame_textencoding);
                                                        }
                                                        if (!isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression']) || $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression'] === FALSE) {
                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['asciidata'] = RoughTranslateUnicodeToASCII($frame_text, $frame_textencoding);
                                                        }
                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                    } else {
                                                        if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 4 && $frame_name == 'RVA2') {
                                                            // 4.11  RVA2 Relative volume adjustment (2) (ID3v2.4+ only)
                                                            //   There may be more than one 'RVA2' frame in each tag,
                                                            //   but only one with the same identification string
                                                            // <Header for 'Relative volume adjustment (2)', ID: 'RVA2'>
                                                            // Identification          <text string> $00
                                                            //   The 'identification' string is used to identify the situation and/or
                                                            //   device where this adjustment should apply. The following is then
                                                            //   repeated for every channel:
                                                            // Type of channel         $xx
                                                            // Volume adjustment       $xx xx
                                                            // Bits representing peak  $xx
                                                            // Peak volume             $xx (xx ...)
                                                            $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0));
                                                            $frame_idstring = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], 0, $frame_terminatorpos);
                                                            if (ord($frame_idstring) === 0) {
                                                                $frame_idstring = '';
                                                            }
                                                            $frame_remainingdata = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(chr(0)));
                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['description'] = $frame_idstring;
                                                            while (strlen($frame_remainingdata)) {
                                                                $frame_offset = 0;
                                                                $frame_channeltypeid = substr($frame_remainingdata, $frame_offset++, 1);
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]["{$frame_channeltypeid}"]['channeltypeid'] = $frame_channeltypeid;
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]["{$frame_channeltypeid}"]['channeltype'] = RVA2ChannelTypeLookup($frame_channeltypeid);
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]["{$frame_channeltypeid}"]['volumeadjust'] = BigEndian2Int(substr($frame_remainingdata, $frame_offset, 2)) - 0x7fff;
                                                                // 16-bit signed
                                                                $frame_offset += 2;
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]["{$frame_channeltypeid}"]['bitspeakvolume'] = ord(substr($frame_remainingdata, $frame_offset++, 1));
                                                                $frame_bytespeakvolume = ceil($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_channeltypeid}"]['bitspeakvolume'] / 8);
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]["{$frame_channeltypeid}"]['peakvolume'] = BigEndian2Int(substr($frame_remainingdata, $frame_offset, $frame_bytespeakvolume));
                                                                $frame_remainingdata = substr($frame_remainingdata, $frame_offset + $frame_bytespeakvolume);
                                                            }
                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]["{$frame_channeltypeid}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                        } else {
                                                            if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 3 && $frame_name == 'RVAD' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'RVA') {
                                                                // 4.12  RVA  Relative volume adjustment (ID3v2.2 only)
                                                                //   There may only be one 'RVA' frame in each tag
                                                                // <Header for 'Relative volume adjustment', ID: 'RVA'>
                                                                // ID3v2.2 => Increment/decrement     %000000ba
                                                                // ID3v2.3 => Increment/decrement     %00fedcba
                                                                // Bits used for volume descr.        $xx
                                                                // Relative volume change, right      $xx xx (xx ...) // a
                                                                // Relative volume change, left       $xx xx (xx ...) // b
                                                                // Peak volume right                  $xx xx (xx ...)
                                                                // Peak volume left                   $xx xx (xx ...)
                                                                //   ID3v2.3 only, optional (not present in ID3v2.2):
                                                                // Relative volume change, right back $xx xx (xx ...) // c
                                                                // Relative volume change, left back  $xx xx (xx ...) // d
                                                                // Peak volume right back             $xx xx (xx ...)
                                                                // Peak volume left back              $xx xx (xx ...)
                                                                //   ID3v2.3 only, optional (not present in ID3v2.2):
                                                                // Relative volume change, center     $xx xx (xx ...) // e
                                                                // Peak volume center                 $xx xx (xx ...)
                                                                //   ID3v2.3 only, optional (not present in ID3v2.2):
                                                                // Relative volume change, bass       $xx xx (xx ...) // f
                                                                // Peak volume bass                   $xx xx (xx ...)
                                                                $frame_offset = 0;
                                                                $frame_incrdecrflags = BigEndian2Bin(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['incdec']['right'] = (bool) substr($frame_incrdecrflags, 6, 1);
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['incdec']['left'] = (bool) substr($frame_incrdecrflags, 7, 1);
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['bitsvolume'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                $frame_bytesvolume = ceil($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['bitsvolume'] / 8);
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['volumechange']['right'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                                                                if ($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['incdec']['right'] === FALSE) {
                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['volumechange']['right'] *= -1;
                                                                }
                                                                $frame_offset += $frame_bytesvolume;
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['volumechange']['left'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                                                                if ($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['incdec']['left'] === FALSE) {
                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['volumechange']['left'] *= -1;
                                                                }
                                                                $frame_offset += $frame_bytesvolume;
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['peakvolume']['right'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                                                                $frame_offset += $frame_bytesvolume;
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['peakvolume']['left'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                                                                $frame_offset += $frame_bytesvolume;
                                                                if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 3) {
                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                    if (strlen($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']) > 0) {
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['incdec']['rightrear'] = (bool) substr($frame_incrdecrflags, 4, 1);
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['incdec']['leftrear'] = (bool) substr($frame_incrdecrflags, 5, 1);
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['volumechange']['rightrear'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                                                                        if ($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['incdec']['rightrear'] === FALSE) {
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['volumechange']['rightrear'] *= -1;
                                                                        }
                                                                        $frame_offset += $frame_bytesvolume;
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['volumechange']['leftrear'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                                                                        if ($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['incdec']['leftrear'] === FALSE) {
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['volumechange']['leftrear'] *= -1;
                                                                        }
                                                                        $frame_offset += $frame_bytesvolume;
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['peakvolume']['rightrear'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                                                                        $frame_offset += $frame_bytesvolume;
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['peakvolume']['leftrear'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                                                                        $frame_offset += $frame_bytesvolume;
                                                                    }
                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                    if (strlen($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']) > 0) {
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['incdec']['center'] = (bool) substr($frame_incrdecrflags, 3, 1);
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['volumechange']['center'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                                                                        if ($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['incdec']['center'] === FALSE) {
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['volumechange']['center'] *= -1;
                                                                        }
                                                                        $frame_offset += $frame_bytesvolume;
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['peakvolume']['center'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                                                                        $frame_offset += $frame_bytesvolume;
                                                                    }
                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                    if (strlen($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']) > 0) {
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['incdec']['bass'] = (bool) substr($frame_incrdecrflags, 2, 1);
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['volumechange']['bass'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                                                                        if ($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['incdec']['bass'] === FALSE) {
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['volumechange']['bass'] *= -1;
                                                                        }
                                                                        $frame_offset += $frame_bytesvolume;
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['peakvolume']['bass'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                                                                        $frame_offset += $frame_bytesvolume;
                                                                    }
                                                                }
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                            } else {
                                                                if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 4 && $frame_name == 'EQU2') {
                                                                    // 4.12  EQU2 Equalisation (2) (ID3v2.4+ only)
                                                                    //   There may be more than one 'EQU2' frame in each tag,
                                                                    //   but only one with the same identification string
                                                                    // <Header of 'Equalisation (2)', ID: 'EQU2'>
                                                                    // Interpolation method  $xx
                                                                    //   $00  Band
                                                                    //   $01  Linear
                                                                    // Identification        <text string> $00
                                                                    //   The following is then repeated for every adjustment point
                                                                    // Frequency          $xx xx
                                                                    // Volume adjustment  $xx xx
                                                                    $frame_offset = 0;
                                                                    $frame_interpolationmethod = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                    $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                    $frame_idstring = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                    if (ord($frame_idstring) === 0) {
                                                                        $frame_idstring = '';
                                                                    }
                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['description'] = $frame_idstring;
                                                                    $frame_remainingdata = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(chr(0)));
                                                                    while (strlen($frame_remainingdata)) {
                                                                        $frame_frequency = BigEndian2Int(substr($frame_remainingdata, 0, 2)) / 2;
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data']["{$frame_frequency}"] = BigEndian2Int(substr($frame_remainingdata, 2, 2));
                                                                        $frame_remainingdata = substr($frame_remainingdata, 4);
                                                                    }
                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['interpolationmethod'] = $frame_interpolationmethod;
                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                                } else {
                                                                    if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 3 && $frame_name == 'EQUA' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'EQU') {
                                                                        // 4.13  EQU  Equalisation (ID3v2.2 only)
                                                                        //   There may only be one 'EQUA' frame in each tag
                                                                        // <Header for 'Relative volume adjustment', ID: 'EQU'>
                                                                        // Adjustment bits    $xx
                                                                        //   This is followed by 2 bytes + ('adjustment bits' rounded up to the
                                                                        //   nearest byte) for every equalisation band in the following format,
                                                                        //   giving a frequency range of 0 - 32767Hz:
                                                                        // Increment/decrement   %x (MSB of the Frequency)
                                                                        // Frequency             (lower 15 bits)
                                                                        // Adjustment            $xx (xx ...)
                                                                        $frame_offset = 0;
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['adjustmentbits'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1);
                                                                        $frame_adjustmentbytes = ceil($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['adjustmentbits'] / 8);
                                                                        $frame_remainingdata = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                        while (strlen($frame_remainingdata)) {
                                                                            $frame_frequencystr = BigEndian2Bin(substr($frame_remainingdata, 0, 2));
                                                                            $frame_incdec = (bool) substr($frame_frequencystr, 0, 1);
                                                                            $frame_frequency = bindec(substr($frame_frequencystr, 1, 15));
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_frequency}"]['incdec'] = $frame_incdec;
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_frequency}"]['adjustment'] = BigEndian2Int(substr($frame_remainingdata, 2, $frame_adjustmentbytes));
                                                                            if ($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_frequency}"]['incdec'] === FALSE) {
                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_frequency}"]['adjustment'] *= -1;
                                                                            }
                                                                            $frame_remainingdata = substr($frame_remainingdata, 2 + $frame_adjustmentbytes);
                                                                        }
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                    } else {
                                                                        if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'RVRB' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'REV') {
                                                                            // 4.14  REV  Reverb
                                                                            //   There may only be one 'RVRB' frame in each tag.
                                                                            // <Header for 'Reverb', ID: 'RVRB'>
                                                                            // Reverb left (ms)                 $xx xx
                                                                            // Reverb right (ms)                $xx xx
                                                                            // Reverb bounces, left             $xx
                                                                            // Reverb bounces, right            $xx
                                                                            // Reverb feedback, left to left    $xx
                                                                            // Reverb feedback, left to right   $xx
                                                                            // Reverb feedback, right to right  $xx
                                                                            // Reverb feedback, right to left   $xx
                                                                            // Premix left to right             $xx
                                                                            // Premix right to left             $xx
                                                                            $frame_offset = 0;
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['left'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 2));
                                                                            $frame_offset += 2;
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['right'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 2));
                                                                            $frame_offset += 2;
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['bouncesL'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['bouncesR'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['feedbackLL'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['feedbackLR'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['feedbackRR'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['feedbackRL'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['premixLR'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['premixRL'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                        } else {
                                                                            if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'APIC' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'PIC') {
                                                                                // 4.15  PIC  Attached picture
                                                                                //   There may be several pictures attached to one file,
                                                                                //   each in their individual 'APIC' frame, but only one
                                                                                //   with the same content descriptor
                                                                                // <Header for 'Attached picture', ID: 'APIC'>
                                                                                // Text encoding      $xx
                                                                                // ID3v2.3+ => MIME type          <text string> $00
                                                                                // ID3v2.2  => Image format       $xx xx xx
                                                                                // Picture type       $xx
                                                                                // Description        <text string according to encoding> $00 (00)
                                                                                // Picture data       <binary data>
                                                                                $frame_offset = 0;
                                                                                $frame_textencoding = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                                if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 2) {
                                                                                    $frame_imagetype = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 3);
                                                                                    if (strtolower($frame_imagetype) == 'ima') {
                                                                                        // complete hack for mp3Rage (www.chaoticsoftware.com) that puts ID3v2.3-formatted
                                                                                        // MIME type instead of 3-char ID3v2.2-format image type  (thanks xbhoff@pacbell.net)
                                                                                        $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                        $frame_mimetype = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                        if (ord($frame_mimetype) === 0) {
                                                                                            $frame_mimetype = '';
                                                                                        }
                                                                                        $frame_imagetype = strtoupper(str_replace('image/', '', strtolower($frame_mimetype)));
                                                                                        if ($frame_imagetype == 'JPEG') {
                                                                                            $frame_imagetype = 'JPG';
                                                                                        }
                                                                                        $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                    } else {
                                                                                        $frame_offset += 3;
                                                                                    }
                                                                                }
                                                                                if ($MP3fileInfo['id3']['id3v2']['majorversion'] > 2) {
                                                                                    $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                    $frame_mimetype = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                    if (ord($frame_mimetype) === 0) {
                                                                                        $frame_mimetype = '';
                                                                                    }
                                                                                    $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                }
                                                                                $frame_picturetype = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                                $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
                                                                                if (ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
                                                                                    $frame_terminatorpos++;
                                                                                    // strpos() fooled because 2nd byte of Unicode chars are often 0x00
                                                                                }
                                                                                $frame_description = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                if (ord($frame_description) === 0) {
                                                                                    $frame_description = '';
                                                                                }
                                                                                if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                                                }
                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encodingid'] = $frame_textencoding;
                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
                                                                                if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 2) {
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['imagetype'] = $frame_imagetype;
                                                                                } else {
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['mime'] = $frame_mimetype;
                                                                                }
                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['picturetypeid'] = $frame_picturetype;
                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['picturetype'] = APICPictureTypeLookup($frame_picturetype);
                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['description'] = $frame_description;
                                                                                if (!isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression']) || $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression'] === FALSE) {
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['asciidescription'] = RoughTranslateUnicodeToASCII($frame_description, $frame_textencoding);
                                                                                }
                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)));
                                                                                include_once GETID3_INCLUDEPATH . 'getid3.getimagesize.php';
                                                                                $imagechunkcheck = GetDataImageSize($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data']);
                                                                                if ($imagechunkcheck[2] >= 1 && $imagechunkcheck[2] <= 3) {
                                                                                    $imagetypes = array(1 => 'image/gif', 2 => 'image/jpeg', 3 => 'image/png');
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['image_mime'] = $imagetypes["{$imagechunkcheck[2]}"];
                                                                                    if ($imagechunkcheck[0]) {
                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['image_width'] = $imagechunkcheck[0];
                                                                                    }
                                                                                    if ($imagechunkcheck[1]) {
                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['image_height'] = $imagechunkcheck[1];
                                                                                    }
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['image_bytes'] = strlen($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data']);
                                                                                    //$MP3fileInfo['id3']['id3v2']["$frame_name"]["$frame_arrayindex"]['image_offset']  = $MP3fileInfo['id3']['id3v2']["$frame_name"]['dataoffset'] + $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)) + ID3v2HeaderLength($MP3fileInfo['id3']['id3v2']['majorversion']);
                                                                                }
                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                                            } else {
                                                                                if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'GEOB' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'GEO') {
                                                                                    // 4.16  GEO  General encapsulated object
                                                                                    //   There may be more than one 'GEOB' frame in each tag,
                                                                                    //   but only one with the same content descriptor
                                                                                    // <Header for 'General encapsulated object', ID: 'GEOB'>
                                                                                    // Text encoding          $xx
                                                                                    // MIME type              <text string> $00
                                                                                    // Filename               <text string according to encoding> $00 (00)
                                                                                    // Content description    <text string according to encoding> $00 (00)
                                                                                    // Encapsulated object    <binary data>
                                                                                    $frame_offset = 0;
                                                                                    $frame_textencoding = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                                    $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                    $frame_mimetype = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                    if (ord($frame_mimetype) === 0) {
                                                                                        $frame_mimetype = '';
                                                                                    }
                                                                                    $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                    $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
                                                                                    if (ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
                                                                                        $frame_terminatorpos++;
                                                                                        // strpos() fooled because 2nd byte of Unicode chars are often 0x00
                                                                                    }
                                                                                    $frame_filename = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                    if (ord($frame_filename) === 0) {
                                                                                        $frame_filename = '';
                                                                                    }
                                                                                    $frame_offset = $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding));
                                                                                    $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
                                                                                    if (ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
                                                                                        $frame_terminatorpos++;
                                                                                        // strpos() fooled because 2nd byte of Unicode chars are often 0x00
                                                                                    }
                                                                                    $frame_description = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                    if (ord($frame_description) === 0) {
                                                                                        $frame_description = '';
                                                                                    }
                                                                                    $frame_offset = $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding));
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['objectdata'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encodingid'] = $frame_textencoding;
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['mime'] = $frame_mimetype;
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['filename'] = $frame_filename;
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['description'] = $frame_description;
                                                                                    if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                                                        if (!isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression']) || $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression'] === FALSE) {
                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['asciidescription'] = RoughTranslateUnicodeToASCII($frame_description, $frame_textencoding);
                                                                                        }
                                                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                                                    }
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                                                } else {
                                                                                    if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'PCNT' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'CNT') {
                                                                                        // 4.17  CNT  Play counter
                                                                                        //   There may only be one 'PCNT' frame in each tag.
                                                                                        //   When the counter reaches all one's, one byte is inserted in
                                                                                        //   front of the counter thus making the counter eight bits bigger
                                                                                        // <Header for 'Play counter', ID: 'PCNT'>
                                                                                        // Counter        $xx xx xx xx (xx ...)
                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'] = BigEndian2Int($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                    } else {
                                                                                        if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'POPM' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'POP') {
                                                                                            // 4.18  POP  Popularimeter
                                                                                            //   There may be more than one 'POPM' frame in each tag,
                                                                                            //   but only one with the same email address
                                                                                            // <Header for 'Popularimeter', ID: 'POPM'>
                                                                                            // Email to user   <text string> $00
                                                                                            // Rating          $xx
                                                                                            // Counter         $xx xx xx xx (xx ...)
                                                                                            $frame_offset = 0;
                                                                                            $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                            $frame_emailaddress = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                            if (ord($frame_emailaddress) === 0) {
                                                                                                $frame_emailaddress = '';
                                                                                            }
                                                                                            $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                            $frame_rating = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset));
                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['email'] = $frame_emailaddress;
                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['rating'] = $frame_rating;
                                                                                            if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                                                            }
                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                                                        } else {
                                                                                            if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'RBUF' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'BUF') {
                                                                                                // 4.19  BUF  Recommended buffer size
                                                                                                //   There may only be one 'RBUF' frame in each tag
                                                                                                // <Header for 'Recommended buffer size', ID: 'RBUF'>
                                                                                                // Buffer size               $xx xx xx
                                                                                                // Embedded info flag        %0000000x
                                                                                                // Offset to next tag        $xx xx xx xx
                                                                                                $frame_offset = 0;
                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['buffersize'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 3));
                                                                                                $frame_offset += 3;
                                                                                                $frame_embeddedinfoflags = BigEndian2Bin(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['embededinfo'] = (bool) substr($frame_embeddedinfoflags, 7, 1);
                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['nexttagoffset'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 4));
                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                            } else {
                                                                                                if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'CRM') {
                                                                                                    // 4.20  Encrypted meta frame (ID3v2.2 only)
                                                                                                    //   There may be more than one 'CRM' frame in a tag,
                                                                                                    //   but only one with the same 'owner identifier'
                                                                                                    // <Header for 'Encrypted meta frame', ID: 'CRM'>
                                                                                                    // Owner identifier      <textstring> $00 (00)
                                                                                                    // Content/explanation   <textstring> $00 (00)
                                                                                                    // Encrypted datablock   <binary data>
                                                                                                    $frame_offset = 0;
                                                                                                    $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                                    $frame_ownerid = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                                    if (ord($frame_ownerid) === 0) {
                                                                                                        $frame_ownerid = count($MP3fileInfo['id3']['id3v2']["{$frame_name}"]) - 1;
                                                                                                    }
                                                                                                    $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                                    $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                                    $frame_description = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                                    if (ord($frame_description) === 0) {
                                                                                                        $frame_description = '';
                                                                                                    }
                                                                                                    $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['ownerid'] = $frame_ownerid;
                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['description'] = $frame_description;
                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                                                                } else {
                                                                                                    if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'AENC' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'CRA') {
                                                                                                        // 4.21  CRA  Audio encryption
                                                                                                        //   There may be more than one 'AENC' frames in a tag,
                                                                                                        //   but only one with the same 'Owner identifier'
                                                                                                        // <Header for 'Audio encryption', ID: 'AENC'>
                                                                                                        // Owner identifier   <text string> $00
                                                                                                        // Preview start      $xx xx
                                                                                                        // Preview length     $xx xx
                                                                                                        // Encryption info    <binary data>
                                                                                                        $frame_offset = 0;
                                                                                                        $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                                        $frame_ownerid = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                                        if (ord($frame_ownerid) === 0) {
                                                                                                            $frame_ownerid == '';
                                                                                                        }
                                                                                                        $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['ownerid'] = $frame_ownerid;
                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['previewstart'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 2));
                                                                                                        $frame_offset += 2;
                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['previewlength'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 2));
                                                                                                        $frame_offset += 2;
                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encryptioninfo'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                                                        if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_ownerid}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                                                                        }
                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                                                                    } else {
                                                                                                        if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'LINK' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'LNK') {
                                                                                                            // 4.22  LNK  Linked information
                                                                                                            //   There may be more than one 'LINK' frame in a tag,
                                                                                                            //   but only one with the same contents
                                                                                                            // <Header for 'Linked information', ID: 'LINK'>
                                                                                                            // ID3v2.3+ => Frame identifier   $xx xx xx xx
                                                                                                            // ID3v2.2  => Frame identifier   $xx xx xx
                                                                                                            // URL                            <text string> $00
                                                                                                            // ID and additional data         <text string(s)>
                                                                                                            $frame_offset = 0;
                                                                                                            if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 2) {
                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['frameid'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 3);
                                                                                                                $frame_offset += 3;
                                                                                                            } else {
                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['frameid'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 4);
                                                                                                                $frame_offset += 4;
                                                                                                            }
                                                                                                            $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                                            $frame_url = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                                            if (ord($frame_url) === 0) {
                                                                                                                $frame_url = '';
                                                                                                            }
                                                                                                            $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['url'] = $frame_url;
                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['additionaldata'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                                                            if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                                                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                                                                            }
                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                                                                        } else {
                                                                                                            if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'POSS') {
                                                                                                                // 4.21  POSS Position synchronisation frame (ID3v2.3+ only)
                                                                                                                //   There may only be one 'POSS' frame in each tag
                                                                                                                // <Head for 'Position synchronisation', ID: 'POSS'>
                                                                                                                // Time stamp format         $xx
                                                                                                                // Position                  $xx (xx ...)
                                                                                                                $frame_offset = 0;
                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['timestampformat'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['position'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset));
                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                                            } else {
                                                                                                                if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'USER') {
                                                                                                                    // 4.22  USER Terms of use (ID3v2.3+ only)
                                                                                                                    //   There may be more than one 'Terms of use' frame in a tag,
                                                                                                                    //   but only one with the same 'Language'
                                                                                                                    // <Header for 'Terms of use frame', ID: 'USER'>
                                                                                                                    // Text encoding        $xx
                                                                                                                    // Language             $xx xx xx
                                                                                                                    // The actual text      <text string according to encoding>
                                                                                                                    $frame_offset = 0;
                                                                                                                    $frame_textencoding = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                                                                    $frame_language = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 3);
                                                                                                                    $frame_offset += 3;
                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_language}"]['language'] = $frame_language;
                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_language}"]['languagename'] = LanguageLookup($frame_language, FALSE);
                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_language}"]['encodingid'] = $frame_textencoding;
                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_language}"]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_language}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                                                                    if (!$MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_language}"]['flags']['compression']) {
                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_language}"]['asciidata'] = RoughTranslateUnicodeToASCII($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_language}"]['data'], $frame_textencoding);
                                                                                                                    }
                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_language}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_language}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_language}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_language}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                                                                                } else {
                                                                                                                    if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'OWNE') {
                                                                                                                        // 4.23  OWNE Ownership frame (ID3v2.3+ only)
                                                                                                                        //   There may only be one 'OWNE' frame in a tag
                                                                                                                        // <Header for 'Ownership frame', ID: 'OWNE'>
                                                                                                                        // Text encoding     $xx
                                                                                                                        // Price paid        <text string> $00
                                                                                                                        // Date of purch.    <text string>
                                                                                                                        // Seller            <text string according to encoding>
                                                                                                                        $frame_offset = 0;
                                                                                                                        $frame_textencoding = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['encodingid'] = $frame_textencoding;
                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
                                                                                                                        $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                                                        $frame_pricepaid = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                                                        $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['pricepaid']['currencyid'] = substr($frame_pricepaid, 0, 3);
                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['pricepaid']['currency'] = LookupCurrency($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['pricepaid']['currencyid'], 'units');
                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['pricepaid']['value'] = substr($frame_pricepaid, 3);
                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['purchasedate'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 8);
                                                                                                                        if (!IsValidDateStampString($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['purchasedate'])) {
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['purchasedateunix'] = mktime(0, 0, 0, substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['purchasedate'], 4, 2), substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['purchasedate'], 6, 2), substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['purchasedate'], 0, 4));
                                                                                                                        }
                                                                                                                        $frame_offset += 8;
                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['seller'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                                                    } else {
                                                                                                                        if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'COMR') {
                                                                                                                            // 4.24  COMR Commercial frame (ID3v2.3+ only)
                                                                                                                            //   There may be more than one 'commercial frame' in a tag,
                                                                                                                            //   but no two may be identical
                                                                                                                            // <Header for 'Commercial frame', ID: 'COMR'>
                                                                                                                            // Text encoding      $xx
                                                                                                                            // Price string       <text string> $00
                                                                                                                            // Valid until        <text string>
                                                                                                                            // Contact URL        <text string> $00
                                                                                                                            // Received as        $xx
                                                                                                                            // Name of seller     <text string according to encoding> $00 (00)
                                                                                                                            // Description        <text string according to encoding> $00 (00)
                                                                                                                            // Picture MIME type  <string> $00
                                                                                                                            // Seller logo        <binary data>
                                                                                                                            $frame_offset = 0;
                                                                                                                            $frame_textencoding = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                                                                            $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                                                            $frame_pricestring = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                                                            $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                                                            $frame_rawpricearray = explode('/', $frame_pricestring);
                                                                                                                            foreach ($frame_rawpricearray as $key => $val) {
                                                                                                                                $frame_currencyid = substr($val, 0, 3);
                                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['price']["{$frame_currencyid}"]['currency'] = LookupCurrency($frame_currencyid, 'units');
                                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['price']["{$frame_currencyid}"]['value'] = substr($val, 3);
                                                                                                                            }
                                                                                                                            $frame_datestring = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 8);
                                                                                                                            $frame_offset += 8;
                                                                                                                            $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                                                            $frame_contacturl = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                                                            $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                                                            $frame_receivedasid = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                                                                            $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
                                                                                                                            if (ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
                                                                                                                                $frame_terminatorpos++;
                                                                                                                                // strpos() fooled because 2nd byte of Unicode chars are often 0x00
                                                                                                                            }
                                                                                                                            $frame_sellername = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                                                            if (ord($frame_sellername) === 0) {
                                                                                                                                $frame_sellername = '';
                                                                                                                            }
                                                                                                                            $frame_offset = $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding));
                                                                                                                            $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
                                                                                                                            if (ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
                                                                                                                                $frame_terminatorpos++;
                                                                                                                                // strpos() fooled because 2nd byte of Unicode chars are often 0x00
                                                                                                                            }
                                                                                                                            $frame_description = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                                                            if (ord($frame_description) === 0) {
                                                                                                                                $frame_description = '';
                                                                                                                            }
                                                                                                                            $frame_offset = $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding));
                                                                                                                            $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                                                            $frame_mimetype = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                                                            $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                                                            $frame_sellerlogo = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encodingid'] = $frame_textencoding;
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['pricevaliduntil'] = $frame_datestring;
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['contacturl'] = $frame_contacturl;
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['receivedasid'] = $frame_receivedasid;
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['receivedas'] = COMRReceivedAsLookup($frame_receivedasid);
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['sellername'] = $frame_sellername;
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['asciisellername'] = RoughTranslateUnicodeToASCII($frame_sellername, $frame_textencoding);
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['description'] = $frame_description;
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['asciidescription'] = RoughTranslateUnicodeToASCII($frame_description, $frame_textencoding);
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['mime'] = $frame_mimetype;
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['logo'] = $frame_sellerlogo;
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                                                                                        } else {
                                                                                                                            if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'ENCR') {
                                                                                                                                // 4.25  ENCR Encryption method registration (ID3v2.3+ only)
                                                                                                                                //   There may be several 'ENCR' frames in a tag,
                                                                                                                                //   but only one containing the same symbol
                                                                                                                                //   and only one containing the same owner identifier
                                                                                                                                // <Header for 'Encryption method registration', ID: 'ENCR'>
                                                                                                                                // Owner identifier    <text string> $00
                                                                                                                                // Method symbol       $xx
                                                                                                                                // Encryption data     <binary data>
                                                                                                                                $frame_offset = 0;
                                                                                                                                $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                                                                $frame_ownerid = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                                                                if (ord($frame_ownerid) === 0) {
                                                                                                                                    $frame_ownerid = '';
                                                                                                                                }
                                                                                                                                $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['ownerid'] = $frame_ownerid;
                                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['methodsymbol'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                                                                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                                                                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                                                                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                                                                                            } else {
                                                                                                                                if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'GRID') {
                                                                                                                                    // 4.26  GRID Group identification registration (ID3v2.3+ only)
                                                                                                                                    //   There may be several 'GRID' frames in a tag,
                                                                                                                                    //   but only one containing the same symbol
                                                                                                                                    //   and only one containing the same owner identifier
                                                                                                                                    // <Header for 'Group ID registration', ID: 'GRID'>
                                                                                                                                    // Owner identifier      <text string> $00
                                                                                                                                    // Group symbol          $xx
                                                                                                                                    // Group dependent data  <binary data>
                                                                                                                                    $frame_offset = 0;
                                                                                                                                    $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                                                                    $frame_ownerid = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                                                                    if (ord($frame_ownerid) === 0) {
                                                                                                                                        $frame_ownerid = '';
                                                                                                                                    }
                                                                                                                                    $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['ownerid'] = $frame_ownerid;
                                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['groupsymbol'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                                                                                                } else {
                                                                                                                                    if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'PRIV') {
                                                                                                                                        // 4.27  PRIV Private frame (ID3v2.3+ only)
                                                                                                                                        //   The tag may contain more than one 'PRIV' frame
                                                                                                                                        //   but only with different contents
                                                                                                                                        // <Header for 'Private frame', ID: 'PRIV'>
                                                                                                                                        // Owner identifier      <text string> $00
                                                                                                                                        // The private data      <binary data>
                                                                                                                                        $frame_offset = 0;
                                                                                                                                        $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                                                                        $frame_ownerid = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                                                                        if (ord($frame_ownerid) === 0) {
                                                                                                                                            $frame_ownerid = '';
                                                                                                                                        }
                                                                                                                                        $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['ownerid'] = $frame_ownerid;
                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                                                                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                                                                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                                                                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                                                                                                    } else {
                                                                                                                                        if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 4 && $frame_name == 'SIGN') {
                                                                                                                                            // 4.28  SIGN Signature frame (ID3v2.4+ only)
                                                                                                                                            //   There may be more than one 'signature frame' in a tag,
                                                                                                                                            //   but no two may be identical
                                                                                                                                            // <Header for 'Signature frame', ID: 'SIGN'>
                                                                                                                                            // Group symbol      $xx
                                                                                                                                            // Signature         <binary data>
                                                                                                                                            $frame_offset = 0;
                                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['groupsymbol'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                                                                                                        } else {
                                                                                                                                            if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 4 && $frame_name == 'SEEK') {
                                                                                                                                                // 4.29  SEEK Seek frame (ID3v2.4+ only)
                                                                                                                                                //   There may only be one 'seek frame' in a tag
                                                                                                                                                // <Header for 'Seek frame', ID: 'SEEK'>
                                                                                                                                                // Minimum offset to next tag       $xx xx xx xx
                                                                                                                                                $frame_offset = 0;
                                                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 4));
                                                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                                                            } else {
                                                                                                                                                if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 4 && $frame_name == 'ASPI') {
                                                                                                                                                    // 4.30  ASPI Audio seek point index (ID3v2.4+ only)
                                                                                                                                                    //   There may only be one 'audio seek point index' frame in a tag
                                                                                                                                                    // <Header for 'Seek Point Index', ID: 'ASPI'>
                                                                                                                                                    // Indexed data start (S)         $xx xx xx xx
                                                                                                                                                    // Indexed data length (L)        $xx xx xx xx
                                                                                                                                                    // Number of index points (N)     $xx xx
                                                                                                                                                    // Bits per index point (b)       $xx
                                                                                                                                                    //   Then for every index point the following data is included:
                                                                                                                                                    // Fraction at index (Fi)          $xx (xx)
                                                                                                                                                    $frame_offset = 0;
                                                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datastart'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 4));
                                                                                                                                                    $frame_offset += 4;
                                                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['indexeddatalength'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 4));
                                                                                                                                                    $frame_offset += 4;
                                                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['indexpoints'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 2));
                                                                                                                                                    $frame_offset += 2;
                                                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['bitsperpoint'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                                                                                                    $frame_bytesperpoint = ceil($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['bitsperpoint'] / 8);
                                                                                                                                                    for ($i = 0; $i < $frame_indexpoints; $i++) {
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['indexes']["{$i}"] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesperpoint));
                                                                                                                                                        $frame_offset += $frame_bytesperpoint;
                                                                                                                                                    }
                                                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                                                                                } else {
                                                                                                                                                    if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'RGAD') {
                                                                                                                                                        // Replay Gain Adjustment
                                                                                                                                                        // http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html
                                                                                                                                                        //   There may only be one 'RGAD' frame in a tag
                                                                                                                                                        // <Header for 'Replay Gain Adjustment', ID: 'RGAD'>
                                                                                                                                                        // Peak Amplitude                      $xx $xx $xx $xx
                                                                                                                                                        // Radio Replay Gain Adjustment        %aaabbbcd %dddddddd
                                                                                                                                                        // Audiophile Replay Gain Adjustment   %aaabbbcd %dddddddd
                                                                                                                                                        //   a - name code
                                                                                                                                                        //   b - originator code
                                                                                                                                                        //   c - sign bit
                                                                                                                                                        //   d - replay gain adjustment
                                                                                                                                                        $frame_offset = 0;
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['peakamplitude'] = BigEndian2Float(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 4));
                                                                                                                                                        $frame_offset += 4;
                                                                                                                                                        $radioadjustment = Dec2Bin(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 2));
                                                                                                                                                        $frame_offset += 2;
                                                                                                                                                        $audiophileadjustment = Dec2Bin(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 2));
                                                                                                                                                        $frame_offset += 2;
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['radio']['name'] = Bin2Dec(substr($radioadjustment, 0, 3));
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['radio']['originator'] = Bin2Dec(substr($radioadjustment, 3, 3));
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['radio']['signbit'] = Bin2Dec(substr($radioadjustment, 6, 1));
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['radio']['adjustment'] = Bin2Dec(substr($radioadjustment, 7, 9));
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['audiophile']['name'] = Bin2Dec(substr($audiophileadjustment, 0, 3));
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['audiophile']['originator'] = Bin2Dec(substr($audiophileadjustment, 3, 3));
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['audiophile']['signbit'] = Bin2Dec(substr($audiophileadjustment, 6, 1));
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['audiophile']['adjustment'] = Bin2Dec(substr($audiophileadjustment, 7, 9));
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['radio']['name'] = RGADnameLookup($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['radio']['name']);
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['radio']['originator'] = RGADoriginatorLookup($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['radio']['originator']);
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['radio']['adjustment'] = RGADadjustmentLookup($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['radio']['adjustment'], $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['radio']['signbit']);
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['audiophile']['name'] = RGADnameLookup($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['audiophile']['name']);
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['audiophile']['originator'] = RGADoriginatorLookup($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['audiophile']['originator']);
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['audiophile']['adjustment'] = RGADadjustmentLookup($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['audiophile']['adjustment'], $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['audiophile']['signbit']);
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                                                                                    }
                                                                                                                                                }
                                                                                                                                            }
                                                                                                                                        }
                                                                                                                                    }
                                                                                                                                }
                                                                                                                            }
                                                                                                                        }
                                                                                                                    }
                                                                                                                }
                                                                                                            }
                                                                                                        }
                                                                                                    }
                                                                                                }
                                                                                            }
                                                                                        }
                                                                                    }
                                                                                }
                                                                            }
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    return TRUE;
}
 } else {
     if ($id3info['id3']['id3v2']['majorversion'] > 2) {
         $frame_header = substr($framedata, 0, 10);
         // take next 10 bytes for header
         $framedata = substr($framedata, 10);
         // and leave the rest in $framedata
         $frame_name = substr($frame_header, 0, 4);
         if ($id3info['id3']['id3v2']['majorversion'] == 3) {
             $frame_size = BigEndian2Int(substr($frame_header, 4, 4), 0);
             // 32-bit integer
         } else {
             // ID3v2.4+
             $frame_size = BigEndian2Int(substr($frame_header, 4, 4), 1);
             // 32-bit synchsafe integer (28-bit value)
         }
         $frame_flags = BigEndian2Bin(substr($frame_header, 8, 2));
     }
 }
 if ($frame_size <= strlen($framedata) && IsValidID3v2FrameName($frame_name, $id3info['id3']['id3v2']['majorversion'])) {
     $id3info['id3']['id3v2']["{$frame_name}"]['data'] = substr($framedata, 0, $frame_size);
     // in getid3.frames.php - this function does all the FrameID-level parsing
     ID3v2FrameProcessing($frame_name, $frame_flags, $id3info);
     if (isset($id3info['id3']['id3v2']['APIC'][0]['data']) && strlen($id3info['id3']['id3v2']['APIC'][0]['data']) > 0) {
         if (isset($rawdata)) {
             echo $id3info['id3']['id3v2']['APIC'][0]['data'];
         } else {
             include_once GETID3_INCLUDEPATH . 'getid3.getimagesize.php';
             $imagechunkcheck = GetDataImageSize($id3info['id3']['id3v2']['APIC'][0]['data']);
             switch ($imagechunkcheck[2]) {
                 case 1:
                     header('Content-type: image/gif');
function BigEndian2Float($byteword)
{
    // ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic
    // http://www.psc.edu/general/software/packages/ieee/ieee.html
    // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html
    $bitword = BigEndian2Bin($byteword);
    $signbit = $bitword[0];
    if (strlen($byteword) == 4) {
        // 32-bit DWORD
        $exponentbits = 8;
        $fractionbits = 23;
    } else {
        if (strlen($byteword) == 8) {
            // 64-bit QWORD
            $exponentbits = 11;
            $fractionbits = 52;
        } else {
            return FALSE;
        }
    }
    $exponentstring = substr($bitword, 1, $exponentbits);
    $fractionstring = substr($bitword, 9, $fractionbits);
    $exponent = Bin2Dec($exponentstring);
    $fraction = Bin2Dec($fractionstring);
    if ($exponent == pow(2, $exponentbits) - 1 && $fraction != 0) {
        // Not a Number
        $floatvalue = FALSE;
    } else {
        if ($exponent == pow(2, $exponentbits) - 1 && $fraction == 0) {
            if ($signbit == '1') {
                $floatvalue = '-infinity';
            } else {
                $floatvalue = '+infinity';
            }
        } else {
            if ($exponent == 0 && $fraction == 0) {
                if ($signbit == '1') {
                    $floatvalue = -0;
                } else {
                    $floatvalue = 0;
                }
                $floatvalue = $signbit ? 0 : -0;
            } else {
                if ($exponent == 0 && $fraction != 0) {
                    // These are 'unnormalized' values
                    $floatvalue = pow(2, -1 * (pow(2, $exponentbits - 1) - 2)) * DecimalBinary2Float($fractionstring);
                    if ($signbit == '1') {
                        $floatvalue *= -1;
                    }
                } else {
                    if ($exponent != 0) {
                        $floatvalue = pow(2, $exponent - (pow(2, $exponentbits - 1) - 1)) * (1 + DecimalBinary2Float($fractionstring));
                        if ($signbit == '1') {
                            $floatvalue *= -1;
                        }
                    }
                }
            }
        }
    }
    return (double) $floatvalue;
}
function getMPEGHeaderFilepointer(&$fd, &$MP3fileInfo)
{
    // Start code                       32 bits
    // horizontal frame size            12 bits
    // vertical frame size              12 bits
    // pixel aspect ratio                4 bits
    // frame rate                        4 bits
    // bitrate                          18 bits
    // marker bit                        1 bit
    // VBV buffer size                  10 bits
    // constrained parameter flag        1 bit
    // intra quant. matrix flag          1 bit
    // intra quant. matrix values      512 bits (present if matrix flag == 1)
    // non-intra quant. matrix flag      1 bit
    // non-intra quant. matrix values  512 bits (present if matrix flag == 1)
    if (!$fd) {
        $MP3fileInfo['error'] .= "\n" . 'Could not open file';
        return FALSE;
    } else {
        // MPEG video information is found as $00 $00 $01 $B3
        $matching_pattern = chr(0x0) . chr(0x0) . chr(0x1) . chr(0xb3);
        rewind($fd);
        $MPEGvideoHeader = fread($fd, FREAD_BUFFER_SIZE);
        $offset = 0;
        while (substr($MPEGvideoHeader, $offset++, 4) !== $matching_pattern) {
            if ($offset >= strlen($MPEGvideoHeader) - 12) {
                $MPEGvideoHeader .= fread($fd, FREAD_BUFFER_SIZE);
                $MPEGvideoHeader = substr($MPEGvideoHeader, $offset);
                $offset = 0;
                if (strlen($MPEGvideoHeader) < 12) {
                    $MP3fileInfo['error'] = "\n" . 'Could not find start of video block before end of file';
                    return FALSE;
                    // return array('error'=>'Could not find start of video block before end of file');
                } else {
                    if (ftell($fd) >= 100000) {
                        $MP3fileInfo['error'] = "\n" . 'Could not find start of video block in the first 100,000 bytes (this might not be an MPEG-video file?)';
                        unset($MP3fileInfo['fileformat']);
                        return FALSE;
                        // return array('error'=>"\n".'Could not find start of video block in the first 100,000 bytes (this might not be an MPEG-video file?)', 'fileformat'=>'');
                    }
                }
            }
        }
        $offset += strlen($matching_pattern) - 1;
        $framesizes = BigEndian2Bin(substr($MPEGvideoHeader, $offset, 3));
        $offset += 3;
        $aspect_framerate = BigEndian2Bin(substr($MPEGvideoHeader, $offset, 1));
        $offset += 1;
        $assortedinformation = BigEndian2Bin(substr($MPEGvideoHeader, $offset, 4));
        $offset += 4;
        $MP3fileInfo['mpeg']['video']['raw']['framesize_horizontal'] = bindec(substr($framesizes, 0, 12));
        // 12 bits for horizontal frame size
        $MP3fileInfo['mpeg']['video']['raw']['framesize_vertical'] = bindec(substr($framesizes, 12, 12));
        // 12 bits for vertical frame size
        $MP3fileInfo['mpeg']['video']['framesize_horizontal'] = $MP3fileInfo['mpeg']['video']['raw']['framesize_horizontal'];
        $MP3fileInfo['mpeg']['video']['framesize_vertical'] = $MP3fileInfo['mpeg']['video']['raw']['framesize_vertical'];
        $MP3fileInfo['mpeg']['video']['raw']['pixel_aspect_ratio'] = bindec(substr($aspect_framerate, 0, 4));
        $MP3fileInfo['mpeg']['video']['raw']['frame_rate'] = bindec(substr($aspect_framerate, 4, 4));
        $MP3fileInfo['mpeg']['video']['pixel_aspect_ratio'] = MPEGvideoAspectRatioLookup($MP3fileInfo['mpeg']['video']['raw']['pixel_aspect_ratio']);
        $MP3fileInfo['mpeg']['video']['pixel_aspect_ratio_text'] = MPEGvideoAspectRatioTextLookup($MP3fileInfo['mpeg']['video']['raw']['pixel_aspect_ratio']);
        $MP3fileInfo['mpeg']['video']['frame_rate'] = MPEGvideoFramerateLookup($MP3fileInfo['mpeg']['video']['raw']['frame_rate']);
        $MP3fileInfo['mpeg']['video']['raw']['bitrate'] = bindec(substr($assortedinformation, 0, 18));
        if ($MP3fileInfo['mpeg']['video']['raw']['bitrate'] == 0x3ffff) {
            // 18 set bits
            $MP3fileInfo['mpeg']['video']['bitrate_type'] = 'variable';
        } else {
            $MP3fileInfo['mpeg']['video']['bitrate_type'] = 'constant';
            $MP3fileInfo['mpeg']['video']['bitrate_bps'] = $MP3fileInfo['mpeg']['video']['raw']['bitrate'] * 400;
            //$MP3fileInfo['mpeg']['video']['bitrate_kbytes'] = $MP3fileInfo['mpeg']['video']['bitrate_bps'] / 8192;
        }
        $MP3fileInfo['mpeg']['video']['raw']['marker_bit'] = bindec(substr($assortedinformation, 18, 1));
        $MP3fileInfo['mpeg']['video']['raw']['vbv_buffer_size'] = bindec(substr($assortedinformation, 19, 10));
        $MP3fileInfo['mpeg']['video']['raw']['constrained_param_flag'] = bindec(substr($assortedinformation, 29, 1));
        $MP3fileInfo['mpeg']['video']['raw']['intra_quant_flag'] = bindec(substr($assortedinformation, 30, 1));
        return TRUE;
    }
}
Пример #10
0
function FLACparseSTREAMINFO($METAdataBlockData, &$ThisFileInfo)
{
    $offset = 0;
    $ThisFileInfo['flac']['STREAMINFO']['min_block_size'] = BigEndian2Int(substr($METAdataBlockData, $offset, 2));
    $offset += 2;
    $ThisFileInfo['flac']['STREAMINFO']['max_block_size'] = BigEndian2Int(substr($METAdataBlockData, $offset, 2));
    $offset += 2;
    $ThisFileInfo['flac']['STREAMINFO']['min_frame_size'] = BigEndian2Int(substr($METAdataBlockData, $offset, 3));
    $offset += 3;
    $ThisFileInfo['flac']['STREAMINFO']['max_frame_size'] = BigEndian2Int(substr($METAdataBlockData, $offset, 3));
    $offset += 3;
    $SampleRateChannelsSampleBitsStreamSamples = BigEndian2Bin(substr($METAdataBlockData, $offset, 8));
    $ThisFileInfo['flac']['STREAMINFO']['sample_rate'] = Bin2Dec(substr($SampleRateChannelsSampleBitsStreamSamples, 0, 20));
    $ThisFileInfo['flac']['STREAMINFO']['channels'] = Bin2Dec(substr($SampleRateChannelsSampleBitsStreamSamples, 20, 3)) + 1;
    $ThisFileInfo['flac']['STREAMINFO']['bits_per_sample'] = Bin2Dec(substr($SampleRateChannelsSampleBitsStreamSamples, 23, 5)) + 1;
    $ThisFileInfo['flac']['STREAMINFO']['samples_stream'] = Bin2Dec(substr($SampleRateChannelsSampleBitsStreamSamples, 28, 36));
    $offset += 8;
    $ThisFileInfo['flac']['STREAMINFO']['audio_signature'] = substr($METAdataBlockData, $offset, 16);
    $offset += 16;
    if (!empty($ThisFileInfo['flac']['STREAMINFO']['sample_rate'])) {
        $ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
        $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['flac']['STREAMINFO']['sample_rate'];
        $ThisFileInfo['audio']['channels'] = $ThisFileInfo['flac']['STREAMINFO']['channels'];
        $ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['flac']['STREAMINFO']['bits_per_sample'];
        $ThisFileInfo['playtime_seconds'] = $ThisFileInfo['flac']['STREAMINFO']['samples_stream'] / $ThisFileInfo['flac']['STREAMINFO']['sample_rate'];
        $ThisFileInfo['audio']['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 / $ThisFileInfo['playtime_seconds'];
    } else {
        $ThisFileInfo['error'] .= "\n" . 'Corrupt METAdata block: STREAMINFO';
        return false;
    }
    return true;
}
Пример #11
0
function ParseOggPageHeader(&$fd)
{
    // http://xiph.org/ogg/vorbis/doc/framing.html
    $basefileoffset = ftell($fd);
    // where we started from in the file
    $filedata = fread($fd, FREAD_BUFFER_SIZE);
    $filedataoffset = 0;
    while (substr($filedata, $filedataoffset++, 4) != 'OggS') {
        if (ftell($fd) - $basefileoffset >= 10000) {
            // should be found before here
            return FALSE;
        }
        if (strlen($filedata) < 1024) {
            if (feof($fd) || ($filedata .= fread($fd, FREAD_BUFFER_SIZE)) === FALSE) {
                // get some more data, unless eof, in which case fail
                return FALSE;
            }
        }
    }
    $filedataoffset += strlen('OggS') - 1;
    // page, delimited by 'OggS'
    $stream_structure_version = ord(substr($filedata, $filedataoffset++, 1));
    $header_type_flag = BigEndian2Bin(substr($filedata, $filedataoffset++, 1));
    $header_type_flag_fresh = IntString2Bool($header_type_flag[5]);
    // fresh packet
    $header_type_flag_bos = IntString2Bool($header_type_flag[6]);
    // first page of logical bitstream (bos)
    $header_type_flag_eos = IntString2Bool($header_type_flag[7]);
    // last page of logical bitstream (eos)
    $pcm_absolute_position = LittleEndian2Int(substr($filedata, $filedataoffset, 8));
    $filedataoffset += 8;
    $stream_serial_number = LittleEndian2Int(substr($filedata, $filedataoffset, 4));
    $filedataoffset += 4;
    $page_seq_no = LittleEndian2Int(substr($filedata, $filedataoffset, 4));
    $filedataoffset += 4;
    $page_checksum = LittleEndian2Int(substr($filedata, $filedataoffset, 4));
    $filedataoffset += 4;
    $page_segments = LittleEndian2Int(substr($filedata, $filedataoffset, 1));
    $filedataoffset += 1;
    for ($i = 0; $i < $page_segments; $i++) {
        $segment_table["{$i}"] = LittleEndian2Int(substr($filedata, $filedataoffset++, 1));
    }
    $packettype = ord(substr($filedata, $filedataoffset, 1));
    $filedataoffset += 1;
    $streamtype = substr($filedata, $filedataoffset, 6);
    // hard-coded to 'vorbis'
    $filedataoffset += 6;
    fseek($fd, $filedataoffset + $basefileoffset, SEEK_SET);
    $oggheader['packet_type'] = $packettype;
    $oggheader['stream_type'] = $streamtype;
    $oggheader['stream_structver'] = $stream_structure_version;
    $oggheader['flag']['fresh'] = $header_type_flag_fresh;
    $oggheader['flag']['bos'] = $header_type_flag_fresh;
    $oggheader['flag']['eos'] = $header_type_flag_fresh;
    $oggheader['pcm_abs_position'] = $pcm_absolute_position;
    $oggheader['stream_serialno'] = $stream_serial_number;
    $oggheader['page_seqno'] = $page_seq_no;
    $oggheader['page_checksum'] = $page_checksum;
    $oggheader['page_segments'] = $page_segments;
    $oggheader['segment_table'] = $segment_table;
    return $oggheader;
}
Пример #12
0
function GetAllMP3info($filename, $assumedFormat = '', $allowedFormats = array('zip', 'ogg', 'riff', 'sdss', 'mpeg', 'midi', 'image', 'mp3'))
{
    include_once GETID3_INCLUDEPATH . 'getid3.lookup.php';
    // Lookup tables
    include_once GETID3_INCLUDEPATH . 'getid3.functions.php';
    // Function library
    include_once GETID3_INCLUDEPATH . 'getid3.getimagesize.php';
    if (!file_exists($filename)) {
        // this code segment is needed for the file browser demonstrated in check.php
        // but may interfere with finding a filename that actually does contain apparently
        // escaped characters (like "file\'name.mp3") and/or
        // %xx-format characters (like "file%20name.mp3")
        $filename = stripslashes($filename);
        if (!file_exists($filename)) {
            $filename = rawurldecode($filename);
        }
    }
    $fp = @fopen($filename, 'rb');
    $MP3fileInfo['getID3version'] = GETID3VERSION;
    $MP3fileInfo['exist'] = (bool) $fp;
    $MP3fileInfo['filename'] = basename($filename);
    $MP3fileInfo['fileformat'] = '';
    // filled in later
    $MP3fileInfo['error'] = '';
    // filled in later, unset if not used
    if ($MP3fileInfo['exist']) {
        if (strpos($filename, 'http://') !== FALSE || strpos($filename, 'ftp://') !== FALSE) {
            // remote file - copy locally first and work from there
            $localfilepointer = tmpfile();
            while ($buffer = fread($fp, FREAD_BUFFER_SIZE)) {
                $MP3fileInfo['filesize'] += fwrite($localfilepointer, $buffer);
            }
            fclose($fp);
        } else {
            clearstatcache();
            $MP3fileInfo['filesize'] = filesize($filename);
            $localfilepointer = $fp;
        }
        rewind($localfilepointer);
        $formattest = fread($localfilepointer, FREAD_BUFFER_SIZE);
        if (ParseAsThisFormat('zip', $assumedFormat, $allowedFormats, $formattest)) {
            $MP3fileInfo['fileformat'] = 'zip';
            include_once GETID3_INCLUDEPATH . 'getid3.zip.php';
            getZipHeaderFilepointer($filename, $MP3fileInfo);
        } else {
            if (ParseAsThisFormat('ogg', $assumedFormat, $allowedFormats, $formattest)) {
                $MP3fileInfo['fileformat'] = 'ogg';
                include_once GETID3_INCLUDEPATH . 'getid3.ogg.php';
                getOggHeaderFilepointer($localfilepointer, $MP3fileInfo);
            } else {
                if (ParseAsThisFormat('riff', $assumedFormat, $allowedFormats, $formattest) || ParseAsThisFormat('sdss', $assumedFormat, $allowedFormats, $formattest)) {
                    $MP3fileInfo['fileformat'] = 'riff';
                    include_once GETID3_INCLUDEPATH . 'getid3.riff.php';
                    getRIFFHeaderFilepointer($localfilepointer, $MP3fileInfo);
                } else {
                    if (ParseAsThisFormat('mpeg', $assumedFormat, $allowedFormats, $formattest)) {
                        $MP3fileInfo['fileformat'] = 'mpg';
                        include_once GETID3_INCLUDEPATH . 'getid3.mpeg.php';
                        getMPEGHeaderFilepointer($localfilepointer, $MP3fileInfo);
                    } else {
                        if (ParseAsThisFormat('midi', $assumedFormat, $allowedFormats, $formattest)) {
                            $MP3fileInfo['fileformat'] = 'midi';
                            include_once GETID3_INCLUDEPATH . 'getid3.midi.php';
                            if ($assumedFormat === FALSE) {
                                // do not parse all MIDI tracks - much faster
                                getMIDIHeaderFilepointer($localfilepointer, $MP3fileInfo, FALSE);
                            } else {
                                getMIDIHeaderFilepointer($localfilepointer, $MP3fileInfo);
                            }
                        } else {
                            if (in_array('image', $allowedFormats) && ($assumedFormat == 'image' || ($imagechunkcheck = GetDataImageSize($formattest)) && $imagechunkcheck[2] >= 1 && $imagechunkcheck[2] <= 3)) {
                                if ($assumedFormat == 'image') {
                                    $imagechunkcheck = GetDataImageSize($formattest);
                                }
                                $imagetypes = array(1 => 'gif', 2 => 'jpeg', 3 => 'png');
                                if (isset($imagechunkcheck[2]) && $imagechunkcheck[2] >= 1 && $imagechunkcheck[2] <= 3) {
                                    $MP3fileInfo['fileformat'] = $imagetypes["{$imagechunkcheck[2]}"];
                                    $MP3fileInfo["{$MP3fileInfo['fileformat']}"]['width'] = $imagechunkcheck[0];
                                    $MP3fileInfo["{$MP3fileInfo['fileformat']}"]['height'] = $imagechunkcheck[1];
                                } else {
                                    unset($MP3fileInfo['fileformat']);
                                    $MP3fileInfo['error'] = "\n" . 'Not a supported image format';
                                }
                            } else {
                                if (in_array('mp3', $allowedFormats) && $allowedFormats !== FALSE && ($assumedFormat == 'mp3' || $assumedFormat == '' && (substr($formattest, 0, 3) == 'ID3' || substr(BigEndian2Bin(substr($formattest, 0, 2)), 0, 11) == '11111111111'))) {
                                    // assume MP3 format
                                    include_once GETID3_INCLUDEPATH . 'getid3.mp3.php';
                                    getMP3headerFilepointer($localfilepointer, $MP3fileInfo);
                                    if (!isset($MP3fileInfo['audiodataoffset'])) {
                                        $MP3fileInfo['audiobytes'] = 0;
                                    } else {
                                        $MP3fileInfo['audiobytes'] = $MP3fileInfo['filesize'] - $MP3fileInfo['audiodataoffset'];
                                    }
                                    if (isset($MP3fileInfo['id3']['id3v1'])) {
                                        $MP3fileInfo['audiobytes'] -= 128;
                                    }
                                    if (isset($mp3info['lyrics3']['raw']['lyrics3tagsize'])) {
                                        $MP3fileInfo['audiobytes'] -= $mp3info['lyrics3']['raw']['lyrics3tagsize'];
                                    }
                                    if ($MP3fileInfo['audiobytes'] < 0) {
                                        unset($MP3fileInfo['audiobytes']);
                                    }
                                    if (isset($MP3fileInfo['audiobytes']) && isset($MP3fileInfo['bitrate']) && $MP3fileInfo['bitrate'] > 0) {
                                        $MP3fileInfo['playtime_seconds'] = $MP3fileInfo['audiobytes'] * 8 / $MP3fileInfo['bitrate'];
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    if (isset($MP3fileInfo['playtime_seconds']) && $MP3fileInfo['playtime_seconds'] > 0 && !isset($MP3fileInfo['playtime_string'])) {
        $contentseconds = round(($MP3fileInfo['playtime_seconds'] / 60 - floor($MP3fileInfo['playtime_seconds'] / 60)) * 60);
        $contentminutes = floor($MP3fileInfo['playtime_seconds'] / 60);
        $MP3fileInfo['playtime_string'] = number_format($contentminutes) . ':' . str_pad($contentseconds, 2, 0, STR_PAD_LEFT);
    }
    if (isset($MP3fileInfo['error']) && !$MP3fileInfo['error']) {
        unset($MP3fileInfo['error']);
    }
    if (isset($MP3fileInfo['fileformat']) && !$MP3fileInfo['fileformat']) {
        unset($MP3fileInfo['fileformat']);
    }
    unset($SourceArrayKey);
    if (isset($MP3fileInfo['id3']['id3v2'])) {
        $SourceArrayKey = $MP3fileInfo['id3']['id3v2'];
    } else {
        if (isset($MP3fileInfo['id3']['id3v1'])) {
            $SourceArrayKey = $MP3fileInfo['id3']['id3v1'];
        } else {
            if (isset($MP3fileInfo['ogg'])) {
                $SourceArrayKey = $MP3fileInfo['ogg'];
            } else {
                if (isset($MP3fileInfo['RIFF'])) {
                    $SourceArrayKey = $MP3fileInfo['RIFF'];
                }
            }
        }
    }
    if (isset($SourceArrayKey)) {
        $handyaccesskeystocopy = array('title', 'artist', 'album', 'year', 'genre', 'comment', 'track');
        foreach ($handyaccesskeystocopy as $keytocopy) {
            if (isset($SourceArrayKey["{$keytocopy}"])) {
                $MP3fileInfo["{$keytocopy}"] = $SourceArrayKey["{$keytocopy}"];
            }
        }
    }
    if (isset($fp) && is_resource($fp) && get_resource_type($fp) == 'file') {
        fclose($fp);
    }
    if (isset($localfilepointer) && is_resource($localfilepointer) && get_resource_type($localfilepointer) == 'file') {
        fclose($localfilepointer);
    }
    if (isset($fp)) {
        unset($fp);
    }
    if (isset($localfilepointer)) {
        unset($localfilepointer);
    }
    return $MP3fileInfo;
}
Пример #13
0
function getID3v2Filepointer(&$fd, &$ThisFileInfo)
{
    //    Overall tag structure:
    //        +-----------------------------+
    //        |      Header (10 bytes)      |
    //        +-----------------------------+
    //        |       Extended Header       |
    //        | (variable length, OPTIONAL) |
    //        +-----------------------------+
    //        |   Frames (variable length)  |
    //        +-----------------------------+
    //        |           Padding           |
    //        | (variable length, OPTIONAL) |
    //        +-----------------------------+
    //        | Footer (10 bytes, OPTIONAL) |
    //        +-----------------------------+
    //    Header
    //        ID3v2/file identifier      "ID3"
    //        ID3v2 version              $04 00
    //        ID3v2 flags                (%ab000000 in v2.2, %abc00000 in v2.3, %abcd0000 in v2.4.x)
    //        ID3v2 size             4 * %0xxxxxxx
    rewind($fd);
    $header = fread($fd, 10);
    if (substr($header, 0, 3) == 'ID3') {
        $ThisFileInfo['id3v2']['header'] = true;
        $ThisFileInfo['id3v2']['majorversion'] = ord($header[3]);
        $ThisFileInfo['id3v2']['minorversion'] = ord($header[4]);
    } else {
        return false;
    }
    if ($ThisFileInfo['id3v2']['majorversion'] > 4) {
        // this script probably won't correctly parse ID3v2.5.x and above.
        $ThisFileInfo['error'] .= "\n" . 'this script only parses up to ID3v2.4.x - this tag is ID3v2.' . $ThisFileInfo['id3v2']['majorversion'] . '.' . $ThisFileInfo['id3v2']['minorversion'];
        return false;
    }
    $id3_flags = BigEndian2Bin($header[5]);
    switch ($ThisFileInfo['id3v2']['majorversion']) {
        case 2:
            // %ab000000 in v2.2
            $ThisFileInfo['id3v2']['flags']['unsynch'] = $id3_flags[0];
            // a - Unsynchronisation
            $ThisFileInfo['id3v2']['flags']['compression'] = $id3_flags[1];
            // b - Compression
            break;
        case 3:
            // %abc00000 in v2.3
            $ThisFileInfo['id3v2']['flags']['unsynch'] = $id3_flags[0];
            // a - Unsynchronisation
            $ThisFileInfo['id3v2']['flags']['exthead'] = $id3_flags[1];
            // b - Extended header
            $ThisFileInfo['id3v2']['flags']['experim'] = $id3_flags[2];
            // c - Experimental indicator
            break;
        case 4:
            // %abcd0000 in v2.4
            $ThisFileInfo['id3v2']['flags']['unsynch'] = $id3_flags[0];
            // a - Unsynchronisation
            $ThisFileInfo['id3v2']['flags']['exthead'] = $id3_flags[1];
            // b - Extended header
            $ThisFileInfo['id3v2']['flags']['experim'] = $id3_flags[2];
            // c - Experimental indicator
            $ThisFileInfo['id3v2']['flags']['isfooter'] = $id3_flags[3];
            // d - Footer present
            break;
    }
    $ThisFileInfo['id3v2']['headerlength'] = BigEndian2Int(substr($header, 6, 4), 1) + ID3v2HeaderLength($ThisFileInfo['id3v2']['majorversion']);
    //    Extended Header
    if (isset($ThisFileInfo['id3v2']['flags']['exthead']) && $ThisFileInfo['id3v2']['flags']['exthead']) {
        //            Extended header size   4 * %0xxxxxxx
        //            Number of flag bytes       $01
        //            Extended Flags             $xx
        //            Where the 'Extended header size' is the size of the whole extended header, stored as a 32 bit synchsafe integer.
        $extheader = fread($fd, 4);
        $ThisFileInfo['id3v2']['extheaderlength'] = BigEndian2Int($extheader, 1);
        //            The extended flags field, with its size described by 'number of flag  bytes', is defined as:
        //                %0bcd0000
        //            b - Tag is an update
        //                Flag data length       $00
        //            c - CRC data present
        //                Flag data length       $05
        //                Total frame CRC    5 * %0xxxxxxx
        //            d - Tag restrictions
        //                Flag data length       $01
        $extheaderflagbytes = fread($fd, 1);
        $extheaderflags = fread($fd, $extheaderflagbytes);
        $id3_exthead_flags = BigEndian2Bin(substr($header, 5, 1));
        $ThisFileInfo['id3v2']['exthead_flags']['update'] = substr($id3_exthead_flags, 1, 1);
        $ThisFileInfo['id3v2']['exthead_flags']['CRC'] = substr($id3_exthead_flags, 2, 1);
        if ($ThisFileInfo['id3v2']['exthead_flags']['CRC']) {
            $extheaderrawCRC = fread($fd, 5);
            $ThisFileInfo['id3v2']['exthead_flags']['CRC'] = BigEndian2Int($extheaderrawCRC, 1);
        }
        $ThisFileInfo['id3v2']['exthead_flags']['restrictions'] = substr($id3_exthead_flags, 3, 1);
        if ($ThisFileInfo['id3v2']['exthead_flags']['restrictions']) {
            // Restrictions           %ppqrrstt
            $extheaderrawrestrictions = fread($fd, 1);
            $ThisFileInfo['id3v2']['exthead_flags']['restrictions_tagsize'] = (bindec('11000000') & ord($extheaderrawrestrictions)) >> 6;
            // p - Tag size restrictions
            $ThisFileInfo['id3v2']['exthead_flags']['restrictions_textenc'] = (bindec('00100000') & ord($extheaderrawrestrictions)) >> 5;
            // q - Text encoding restrictions
            $ThisFileInfo['id3v2']['exthead_flags']['restrictions_textsize'] = (bindec('00011000') & ord($extheaderrawrestrictions)) >> 3;
            // r - Text fields size restrictions
            $ThisFileInfo['id3v2']['exthead_flags']['restrictions_imgenc'] = (bindec('00000100') & ord($extheaderrawrestrictions)) >> 2;
            // s - Image encoding restrictions
            $ThisFileInfo['id3v2']['exthead_flags']['restrictions_imgsize'] = (bindec('00000011') & ord($extheaderrawrestrictions)) >> 0;
            // t - Image size restrictions
        }
    }
    // end extended header
    //    Frames
    //        All ID3v2 frames consists of one frame header followed by one or more
    //        fields containing the actual information. The header is always 10
    //        bytes and laid out as follows:
    //
    //        Frame ID      $xx xx xx xx  (four characters)
    //        Size      4 * %0xxxxxxx
    //        Flags         $xx xx
    $sizeofframes = $ThisFileInfo['id3v2']['headerlength'] - ID3v2HeaderLength($ThisFileInfo['id3v2']['majorversion']);
    if (isset($ThisFileInfo['id3v2']['extheaderlength'])) {
        $sizeofframes -= $ThisFileInfo['id3v2']['extheaderlength'];
    }
    if (isset($ThisFileInfo['id3v2']['flags']['isfooter']) && $ThisFileInfo['id3v2']['flags']['isfooter']) {
        $sizeofframes -= 10;
        // footer takes last 10 bytes of ID3v2 header, after frame data, before audio
    }
    if ($sizeofframes > 0) {
        $framedata = fread($fd, $sizeofframes);
        // read all frames from file into $framedata variable
        //    if entire frame data is unsynched, de-unsynch it now (ID3v2.3.x)
        if (isset($ThisFileInfo['id3v2']['flags']['unsynch']) && $ThisFileInfo['id3v2']['flags']['unsynch'] && $ThisFileInfo['id3v2']['majorversion'] <= 3) {
            $framedata = DeUnSynchronise($framedata);
        }
        //        [in ID3v2.4.0] Unsynchronisation [S:6.1] is done on frame level, instead
        //        of on tag level, making it easier to skip frames, increasing the streamability
        //        of the tag. The unsynchronisation flag in the header [S:3.1] indicates that
        //        there exists an unsynchronised frame, while the new unsynchronisation flag in
        //        the frame header [S:4.1.2] indicates unsynchronisation.
        $framedataoffset = 10;
        // how many bytes into the stream - start from after the 10-byte header
        while (isset($framedata) && strlen($framedata) > 0) {
            // cycle through until no more frame data is left to parse
            if (strlen($framedata) < ID3v2HeaderLength($ThisFileInfo['id3v2']['majorversion'])) {
                // insufficient room left in ID3v2 header for actual data - must be padding
                $ThisFileInfo['id3v2']['padding']['start'] = $framedataoffset;
                $ThisFileInfo['id3v2']['padding']['length'] = strlen($framedata);
                $ThisFileInfo['id3v2']['padding']['valid'] = true;
                for ($i = 0; $i < $ThisFileInfo['id3v2']['padding']['length']; $i++) {
                    if (substr($framedata, $i, 1) != chr(0)) {
                        $ThisFileInfo['id3v2']['padding']['valid'] = false;
                        $ThisFileInfo['id3v2']['padding']['errorpos'] = $ThisFileInfo['id3v2']['padding']['start'] + $i;
                        $ThisFileInfo['warning'] .= "\n" . 'Invalid ID3v2 padding found at offset ' . $ThisFileInfo['id3v2']['padding']['errorpos'];
                        break;
                    }
                }
                break;
                // skip rest of ID3v2 header
            }
            if ($ThisFileInfo['id3v2']['majorversion'] == 2) {
                // Frame ID  $xx xx xx (three characters)
                // Size      $xx xx xx (24-bit integer)
                // Flags     $xx xx
                $frame_header = substr($framedata, 0, 6);
                // take next 6 bytes for header
                $framedata = substr($framedata, 6);
                // and leave the rest in $framedata
                $frame_name = substr($frame_header, 0, 3);
                $frame_size = BigEndian2Int(substr($frame_header, 3, 3), 0);
                $frame_flags = '';
                // not used for anything, just to avoid E_NOTICEs
            } elseif ($ThisFileInfo['id3v2']['majorversion'] > 2) {
                // Frame ID  $xx xx xx xx (four characters)
                // Size      $xx xx xx xx (32-bit integer in v2.3, 28-bit synchsafe in v2.4+)
                // Flags     $xx xx
                $frame_header = substr($framedata, 0, 10);
                // take next 10 bytes for header
                $framedata = substr($framedata, 10);
                // and leave the rest in $framedata
                $frame_name = substr($frame_header, 0, 4);
                if ($ThisFileInfo['id3v2']['majorversion'] == 3) {
                    $frame_size = BigEndian2Int(substr($frame_header, 4, 4), 0);
                    // 32-bit integer
                } else {
                    // ID3v2.4+
                    $frame_size = BigEndian2Int(substr($frame_header, 4, 4), 1);
                    // 32-bit synchsafe integer (28-bit value)
                }
                if ($frame_size < strlen($framedata) + 4) {
                    $nextFrameID = substr($framedata, $frame_size, 4);
                    if (IsValidID3v2FrameName($nextFrameID, $ThisFileInfo['id3v2']['majorversion'])) {
                        // next frame is OK
                    } elseif ($frame_name == chr(0) . 'MP3' || $frame_name == chr(0) . chr(0) . 'MP' || $frame_name == ' MP3' || $frame_name == 'MP3e') {
                        // MP3ext known broken frames - "ok" for the purposes of this test
                    } elseif ($ThisFileInfo['id3v2']['majorversion'] == 4 && IsValidID3v2FrameName(substr($framedata, BigEndian2Int(substr($frame_header, 4, 4), 0), 4), 3)) {
                        $ThisFileInfo['warning'] .= "\n" . 'ID3v2 tag written as ID3v2.4, but with non-synchsafe integers (ID3v2.3 style). Older versions of Helium2 (www.helium2.com) is a known culprit of this. Tag has been parsed as ID3v2.3';
                        $ThisFileInfo['id3v2']['majorversion'] = 3;
                        $frame_size = BigEndian2Int(substr($frame_header, 4, 4), 0);
                        // 32-bit integer
                    }
                }
                $frame_flags = BigEndian2Bin(substr($frame_header, 8, 2));
            }
            if ($ThisFileInfo['id3v2']['majorversion'] == 2 && $frame_name == chr(0) . chr(0) . chr(0) || $frame_name == chr(0) . chr(0) . chr(0) . chr(0)) {
                // padding encountered
                $ThisFileInfo['id3v2']['padding']['start'] = $framedataoffset;
                $ThisFileInfo['id3v2']['padding']['length'] = strlen($framedata);
                $ThisFileInfo['id3v2']['padding']['valid'] = true;
                for ($i = 0; $i < $ThisFileInfo['id3v2']['padding']['length']; $i++) {
                    if (substr($framedata, $i, 1) != chr(0)) {
                        $ThisFileInfo['id3v2']['padding']['valid'] = false;
                        $ThisFileInfo['id3v2']['padding']['errorpos'] = $ThisFileInfo['id3v2']['padding']['start'] + $i;
                        $ThisFileInfo['warning'] .= "\n" . 'Invalid ID3v2 padding found at offset ' . $ThisFileInfo['id3v2']['padding']['errorpos'];
                        break;
                    }
                }
                break;
                // skip rest of ID3v2 header
            }
            if ($frame_name == 'COM ') {
                $ThisFileInfo['warning'] .= "\n" . 'error parsing "' . $frame_name . '" (' . $framedataoffset . ' bytes into the ID3v2.' . $ThisFileInfo['id3v2']['majorversion'] . ' tag). (ERROR: !IsValidID3v2FrameName("' . str_replace(chr(0), ' ', $frame_name) . '", ' . $ThisFileInfo['id3v2']['majorversion'] . '))). [Note: this particular error has been known to happen with tags edited by iTunes (versions "X v2.0.3", "v3.0.1" are known-guilty, probably others too)]';
                $frame_name = 'COMM';
            }
            if ($frame_size <= strlen($framedata) && IsValidID3v2FrameName($frame_name, $ThisFileInfo['id3v2']['majorversion'])) {
                $ThisFileInfo['id3v2']["{$frame_name}"]['data'] = substr($framedata, 0, $frame_size);
                $ThisFileInfo['id3v2']["{$frame_name}"]['datalength'] = CastAsInt($frame_size);
                $ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset'] = $framedataoffset;
                $framedata = substr($framedata, $frame_size);
                // in getid3.frames.php - this function does all the FrameID-level parsing
                ID3v2FrameProcessing($frame_name, $frame_flags, $ThisFileInfo);
            } else {
                // invalid frame length or FrameID
                if ($frame_size <= strlen($framedata)) {
                    if (IsValidID3v2FrameName(substr($framedata, $frame_size, 4), $ThisFileInfo['id3v2']['majorversion'])) {
                        // next frame is valid, just skip the current frame
                        $framedata = substr($framedata, $frame_size);
                        $InvalidFrameMessageType = 'warning';
                        $InvalidFrameMessageText = ' Next frame is valid, skipping current frame.';
                    } else {
                        // next frame is invalid too, abort processing
                        unset($framedata);
                        $InvalidFrameMessageType = 'error';
                        $InvalidFrameMessageText = ' Next frame is also invalid, aborting processing.';
                    }
                } elseif ($frame_size == strlen($framedata)) {
                    // this is the last frame, just skip
                    $InvalidFrameMessageType = 'warning';
                    $InvalidFrameMessageText = ' This was the last frame.';
                } else {
                    // next frame is invalid too, abort processing
                    unset($framedata);
                    $InvalidFrameMessageType = 'error';
                    $InvalidFrameMessageText = ' Invalid frame size, aborting.';
                }
                if (!IsValidID3v2FrameName($frame_name, $ThisFileInfo['id3v2']['majorversion'])) {
                    switch ($frame_name) {
                        case chr(0) . chr(0) . 'MP':
                        case chr(0) . 'MP3':
                        case ' MP3':
                        case 'MP3e':
                        case chr(0) . 'MP':
                        case ' MP':
                        case 'MP3':
                            $InvalidFrameMessageType = 'warning';
                            $ThisFileInfo["{$InvalidFrameMessageType}"] .= "\n" . 'error parsing "' . $frame_name . '" (' . $framedataoffset . ' bytes into the ID3v2.' . $ThisFileInfo['id3v2']['majorversion'] . ' tag). (ERROR: !IsValidID3v2FrameName("' . str_replace(chr(0), ' ', $frame_name) . '", ' . $ThisFileInfo['id3v2']['majorversion'] . '))). [Note: this particular error has been known to happen with tags edited by "MP3ext (www.mutschler.de/mp3ext/)"]';
                            break;
                        default:
                            $ThisFileInfo["{$InvalidFrameMessageType}"] .= "\n" . 'error parsing "' . $frame_name . '" (' . $framedataoffset . ' bytes into the ID3v2.' . $ThisFileInfo['id3v2']['majorversion'] . ' tag). (ERROR: !IsValidID3v2FrameName("' . str_replace(chr(0), ' ', $frame_name) . '", ' . $ThisFileInfo['id3v2']['majorversion'] . '))).';
                            break;
                    }
                } elseif ($frame_size > strlen($framedata)) {
                    $ThisFileInfo["{$InvalidFrameMessageType}"] .= "\n" . 'error parsing "' . $frame_name . '" (' . $framedataoffset . ' bytes into the ID3v2.' . $ThisFileInfo['id3v2']['majorversion'] . ' tag). (ERROR: $frame_size (' . $frame_size . ') > strlen($framedata) (' . strlen($framedata) . ')).';
                } else {
                    $ThisFileInfo["{$InvalidFrameMessageType}"] .= "\n" . 'error parsing "' . $frame_name . '" (' . $framedataoffset . ' bytes into the ID3v2.' . $ThisFileInfo['id3v2']['majorversion'] . ' tag).';
                }
                $ThisFileInfo["{$InvalidFrameMessageType}"] .= $InvalidFrameMessageText;
            }
            $framedataoffset += $frame_size + ID3v2HeaderLength($ThisFileInfo['id3v2']['majorversion']);
        }
    }
    //    Footer
    //    The footer is a copy of the header, but with a different identifier.
    //        ID3v2 identifier           "3DI"
    //        ID3v2 version              $04 00
    //        ID3v2 flags                %abcd0000
    //        ID3v2 size             4 * %0xxxxxxx
    if (isset($ThisFileInfo['id3v2']['flags']['isfooter']) && $ThisFileInfo['id3v2']['flags']['isfooter']) {
        $footer = fread($fd, 10);
        if (substr($footer, 0, 3) == '3DI') {
            $ThisFileInfo['id3v2']['footer'] = true;
            $ThisFileInfo['id3v2']['majorversion_footer'] = ord(substr($footer, 3, 1));
            $ThisFileInfo['id3v2']['minorversion_footer'] = ord(substr($footer, 4, 1));
        }
        if ($ThisFileInfo['id3v2']['majorversion_footer'] <= 4) {
            $id3_flags = BigEndian2Bin(substr($footer, 5, 1));
            $ThisFileInfo['id3v2']['flags']['unsynch_footer'] = substr($id3_flags, 0, 1);
            $ThisFileInfo['id3v2']['flags']['extfoot_footer'] = substr($id3_flags, 1, 1);
            $ThisFileInfo['id3v2']['flags']['experim_footer'] = substr($id3_flags, 2, 1);
            $ThisFileInfo['id3v2']['flags']['isfooter_footer'] = substr($id3_flags, 3, 1);
            $ThisFileInfo['id3v2']['footerlength'] = BigEndian2Int(substr($footer, 6, 4), 1);
        }
    }
    // end footer
    if (isset($ThisFileInfo['id3v2']['comments']['genre'])) {
        foreach ($ThisFileInfo['id3v2']['comments']['genre'] as $key => $value) {
            unset($ThisFileInfo['id3v2']['comments']['genre'][$key]);
            $ThisFileInfo['id3v2']['comments'] = array_merge_noclobber($ThisFileInfo['id3v2']['comments'], ParseID3v2GenreString($value));
        }
    }
    if (isset($ThisFileInfo['id3v2']['comments']['track'])) {
        foreach ($ThisFileInfo['id3v2']['comments']['track'] as $key => $value) {
            if (strstr($value, '/')) {
                list($ThisFileInfo['id3v2']['comments']['track'][$key], $ThisFileInfo['id3v2']['comments']['totaltracks'][$key]) = explode('/', $ThisFileInfo['id3v2']['comments']['track'][$key]);
            }
            // Convert track number to integer (ID3v2 track numbers could be returned as a
            // string ('03' for example) - this will ensure all track numbers are integers
            $ThisFileInfo['id3v2']['comments']['track'][$key] = intval($ThisFileInfo['id3v2']['comments']['track'][$key]);
        }
    }
    return true;
}
Пример #14
0
function GetAllFileInfo($filename, $assumedFormat = '', $MD5file = false, $MD5data = false)
{
    require_once GETID3_INCLUDEPATH . 'getid3.functions.php';
    // Function library
    $ThisFileInfo['getID3version'] = GETID3VERSION;
    $ThisFileInfo['fileformat'] = '';
    // filled in later
    $ThisFileInfo['audio']['dataformat'] = '';
    // filled in later, unset if not used
    $ThisFileInfo['video']['dataformat'] = '';
    // filled in later, unset if not used
    $ThisFileInfo['tags'] = array();
    // filled in later, unset if not used
    $ThisFileInfo['error'] = '';
    // filled in later, unset if not used
    $ThisFileInfo['warning'] = '';
    // filled in later, unset if not used
    $ThisFileInfo['exist'] = false;
    if (eregi('^(ht|f)tp://', $filename)) {
        // remote file
        $ThisFileInfo['filename'] = $filename;
        $ThisFileInfo['error'] .= "\n" . 'Remote files are not supported in this version of getID3() - please copy the file locally first';
    } else {
        // local file
        $ThisFileInfo['filename'] = basename($filename);
        $ThisFileInfo['filepath'] = str_replace('\\', '/', realpath(dirname($filename)));
        $ThisFileInfo['filenamepath'] = $ThisFileInfo['filepath'] . '/' . $ThisFileInfo['filename'];
        ob_start();
        if ($localfilepointer = fopen($filename, 'rb')) {
            $ThisFileInfo['exist'] = true;
            //$ThisFileInfo['filesize'] = filesize($ThisFileInfo['filenamepath']);
            // PHP doesn't support integers larger than 31-bit (~2GB)
            // filesize() simply returns (filesize % (pow(2, 32)), no matter the actual filesize
            // ftell() returns 0 if seeking to the end is beyond the range of unsigned integer
            fseek($localfilepointer, 0, SEEK_END);
            $ThisFileInfo['filesize'] = ftell($localfilepointer);
            ob_end_clean();
            if ($ThisFileInfo['filesize'] == 0) {
                if (filesize($ThisFileInfo['filenamepath']) != 0) {
                    unset($ThisFileInfo['filesize']);
                    $ThisFileInfo['error'] .= "\n" . 'File is most likely larger than 2GB and is not supported by PHP';
                }
                // remove unneeded/meaningless keys
                CleanUpGetAllMP3info($ThisFileInfo);
                // close & remove local filepointer
                CloseRemoveFilepointer($localfilepointer);
                return $ThisFileInfo;
            }
        } else {
            $ThisFileInfo['error'] .= "\n" . 'Error opening file: ' . trim(strip_tags(ob_get_contents()));
            ob_end_clean();
            // remove unneeded/meaningless keys
            CleanUpGetAllMP3info($ThisFileInfo);
            // close & remove local filepointer
            CloseRemoveFilepointer($localfilepointer);
            return $ThisFileInfo;
        }
    }
    // Initialize avdataoffset and avdataend
    $ThisFileInfo['avdataoffset'] = 0;
    $ThisFileInfo['avdataend'] = $ThisFileInfo['filesize'];
    // Handle APE tags
    HandleAPETag($localfilepointer, $ThisFileInfo);
    rewind($localfilepointer);
    //$formattest = fread($localfilepointer, 16);  // 16 bytes is sufficient for any format except ISO CD-image
    $formattest = fread($localfilepointer, 32774);
    // (ISO needs at least 32774 bytes)
    // Handle ID3v2 tag
    if (substr($formattest, 0, 3) == 'ID3') {
        HandleID3v2Tag($localfilepointer, $ThisFileInfo);
        rewind($localfilepointer);
        fseek($localfilepointer, $ThisFileInfo['avdataoffset'], SEEK_SET);
        $formattest = fread($localfilepointer, 32774);
        // (ISO9660 needs at least 32774 bytes)
    }
    // Handle ID3v1 tags
    HandleID3v1Tag($localfilepointer, $ThisFileInfo);
    // Nothing-but-tags check
    if ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset'] > 0) {
        if ($DeterminedFormat = GetFileFormat($formattest)) {
            // break if ID3/APE tags found on illegal format
            if (!$DeterminedFormat['allowtags'] && $ThisFileInfo['avdataoffset'] > 0 && $ThisFileInfo['avdataend'] != $ThisFileInfo['filesize']) {
                $ThisFileInfo['error'] .= "\n" . 'Illegal ID3 and/or APE tag found on non multimedia file.';
                break;
            }
            // set mime type
            $ThisFileInfo['mime_type'] = $DeterminedFormat['mimetype'];
            // supported format signature pattern detected
            require_once GETID3_INCLUDEPATH . $DeterminedFormat['include'];
            switch ($DeterminedFormat['format']) {
                //case 'midi':
                //    if ($assumedFormat === false) {
                //        // do not parse all MIDI tracks - much faster
                //        getMIDIHeaderFilepointer($localfilepointer, $ThisFileInfo, false);
                //    } else {
                //        getMIDIHeaderFilepointer($localfilepointer, $ThisFileInfo);
                //    }
                //    break;
                //case 'aac':
                //    if (!getAACADIFheaderFilepointer($localfilepointer, $ThisFileInfo)) {
                //        $dummy = $ThisFileInfo;
                //        unset($dummy['error']);
                //        if (getAACADTSheaderFilepointer($localfilepointer, $dummy)) {
                //            $ThisFileInfo = $dummy;
                //        }
                //    }
                //    break;
                default:
                    $VariableFunctionName = $DeterminedFormat['function'];
                    $VariableFunctionName($localfilepointer, $ThisFileInfo);
                    break;
            }
        } elseif ($assumedFormat == 'mp3' || $assumedFormat == '' && (substr($formattest, 0, 3) == 'ID3' || substr(BigEndian2Bin(substr($formattest, 0, 2)), 0, 11) == '11111111111')) {
            // assume AAC-ADTS format
            require_once GETID3_INCLUDEPATH . 'getid3.aac.php';
            $dummy = $ThisFileInfo;
            if (getAACADTSheaderFilepointer($localfilepointer, $dummy)) {
                $ThisFileInfo = $dummy;
            } else {
                // it's not AAC-ADTS format, probably MP3
                require_once GETID3_INCLUDEPATH . 'getid3.mp3.php';
                getMP3headerFilepointer($localfilepointer, $ThisFileInfo);
            }
        } else {
            // unknown format, do nothing
        }
    }
    if (isset($ThisFileInfo['fileformat'])) {
        // Calculate combined bitrate - audio + video
        $CombinedBitrate = 0;
        $CombinedBitrate += isset($ThisFileInfo['audio']['bitrate']) ? $ThisFileInfo['audio']['bitrate'] : 0;
        $CombinedBitrate += isset($ThisFileInfo['video']['bitrate']) ? $ThisFileInfo['video']['bitrate'] : 0;
        if ($CombinedBitrate > 0 && !isset($ThisFileInfo['bitrate'])) {
            $ThisFileInfo['bitrate'] = $CombinedBitrate;
        }
        // Set playtime string
        if (!empty($ThisFileInfo['playtime_seconds']) && empty($ThisFileInfo['playtime_string'])) {
            $ThisFileInfo['playtime_string'] = PlaytimeString($ThisFileInfo['playtime_seconds']);
        }
        if (!empty($ThisFileInfo['audio']['channels'])) {
            switch ($ThisFileInfo['audio']['channels']) {
                case 1:
                    $ThisFileInfo['audio']['channelmode'] = 'mono';
                    break;
                case 2:
                    $ThisFileInfo['audio']['channelmode'] = 'stereo';
                    break;
                default:
                    // unknown?
                    break;
            }
        }
    }
    // Get the MD5 hash of the entire file
    if ($MD5file && empty($ThisFileInfo['md5_file'])) {
        $ThisFileInfo['md5_file'] = md5_file($filename);
    }
    // Get the MD5 hash of the audio/video portion of the file
    // (without ID3/APE/Lyrics3/etc header/footer tags
    if ($MD5data && empty($ThisFileInfo['md5_data'])) {
        getMD5data($ThisFileInfo);
    }
    // return tags data in alphabetical order, without duplicates
    $ThisFileInfo['tags'] = array_unique($ThisFileInfo['tags']);
    sort($ThisFileInfo['tags']);
    // remove unneeded/meaningless keys
    CleanUpGetAllMP3info($ThisFileInfo);
    // close & remove local filepointer
    CloseRemoveFilepointer($localfilepointer);
    return $ThisFileInfo;
}
Пример #15
0
function getMPEGHeaderFilepointer(&$fd, &$ThisFileInfo)
{
    $ThisFileInfo['fileformat'] = 'mpeg';
    fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
    $MPEGstreamData = fread($fd, min(100000, $ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']));
    $MPEGstreamDataLength = strlen($MPEGstreamData);
    $foundVideo = true;
    $VideoChunkOffset = 0;
    while (substr($MPEGstreamData, $VideoChunkOffset++, 4) !== MPEG_VIDEO_SEQUENCE_HEADER) {
        if ($VideoChunkOffset >= $MPEGstreamDataLength) {
            $foundVideo = false;
            break 2;
        }
    }
    if ($foundVideo) {
        // Start code                       32 bits
        // horizontal frame size            12 bits
        // vertical frame size              12 bits
        // pixel aspect ratio                4 bits
        // frame rate                        4 bits
        // bitrate                          18 bits
        // marker bit                        1 bit
        // VBV buffer size                  10 bits
        // constrained parameter flag        1 bit
        // intra quant. matrix flag          1 bit
        // intra quant. matrix values      512 bits (present if matrix flag == 1)
        // non-intra quant. matrix flag      1 bit
        // non-intra quant. matrix values  512 bits (present if matrix flag == 1)
        $ThisFileInfo['video']['dataformat'] = 'mpeg';
        // I don't know how to differentiate between MPEG-1 and MPEG-2 video stream
        // Any information appreciated: info@getid3.org
        //$ThisFileInfo['video']['codec']      = 'MPEG-1';
        //$ThisFileInfo['video']['codec']      = 'MPEG-2';
        $ThisFileInfo['video']['codec'] = 'MPEG';
        $VideoChunkOffset += strlen(MPEG_VIDEO_SEQUENCE_HEADER) - 1;
        $FrameSizeDWORD = BigEndian2Int(substr($MPEGstreamData, $VideoChunkOffset, 3));
        $VideoChunkOffset += 3;
        $AspectRatioFrameRateDWORD = BigEndian2Int(substr($MPEGstreamData, $VideoChunkOffset, 1));
        $VideoChunkOffset += 1;
        $assortedinformation = BigEndian2Bin(substr($MPEGstreamData, $VideoChunkOffset, 4));
        $VideoChunkOffset += 4;
        $ThisFileInfo['mpeg']['video']['raw']['framesize_horizontal'] = ($FrameSizeDWORD & 0xfff000) >> 12;
        // 12 bits for horizontal frame size
        $ThisFileInfo['mpeg']['video']['raw']['framesize_vertical'] = $FrameSizeDWORD & 0xfff;
        // 12 bits for vertical frame size
        $ThisFileInfo['mpeg']['video']['raw']['pixel_aspect_ratio'] = ($AspectRatioFrameRateDWORD & 0xf0) >> 4;
        $ThisFileInfo['mpeg']['video']['raw']['frame_rate'] = $AspectRatioFrameRateDWORD & 0xf;
        $ThisFileInfo['mpeg']['video']['framesize_horizontal'] = $ThisFileInfo['mpeg']['video']['raw']['framesize_horizontal'];
        $ThisFileInfo['mpeg']['video']['framesize_vertical'] = $ThisFileInfo['mpeg']['video']['raw']['framesize_vertical'];
        $ThisFileInfo['mpeg']['video']['pixel_aspect_ratio'] = MPEGvideoAspectRatioLookup($ThisFileInfo['mpeg']['video']['raw']['pixel_aspect_ratio']);
        $ThisFileInfo['mpeg']['video']['pixel_aspect_ratio_text'] = MPEGvideoAspectRatioTextLookup($ThisFileInfo['mpeg']['video']['raw']['pixel_aspect_ratio']);
        $ThisFileInfo['mpeg']['video']['frame_rate'] = MPEGvideoFramerateLookup($ThisFileInfo['mpeg']['video']['raw']['frame_rate']);
        $ThisFileInfo['mpeg']['video']['raw']['bitrate'] = Bin2Dec(substr($assortedinformation, 0, 18));
        $ThisFileInfo['mpeg']['video']['raw']['marker_bit'] = Bin2Dec(substr($assortedinformation, 18, 1));
        $ThisFileInfo['mpeg']['video']['raw']['vbv_buffer_size'] = Bin2Dec(substr($assortedinformation, 19, 10));
        $ThisFileInfo['mpeg']['video']['raw']['constrained_param_flag'] = Bin2Dec(substr($assortedinformation, 29, 1));
        $ThisFileInfo['mpeg']['video']['raw']['intra_quant_flag'] = Bin2Dec(substr($assortedinformation, 30, 1));
        if ($ThisFileInfo['mpeg']['video']['raw']['bitrate'] == 0x3ffff) {
            // 18 set bits
            $ThisFileInfo['warning'] .= "\n" . 'This version of getID3() [' . GETID3VERSION . '] cannot determine average bitrate of VBR MPEG video files';
            $ThisFileInfo['mpeg']['video']['bitrate_mode'] = 'vbr';
        } else {
            $ThisFileInfo['mpeg']['video']['bitrate'] = $ThisFileInfo['mpeg']['video']['raw']['bitrate'] * 400;
            $ThisFileInfo['mpeg']['video']['bitrate_mode'] = 'cbr';
            $ThisFileInfo['video']['bitrate'] = $ThisFileInfo['mpeg']['video']['bitrate'];
        }
        $ThisFileInfo['video']['resolution_x'] = $ThisFileInfo['mpeg']['video']['framesize_horizontal'];
        $ThisFileInfo['video']['resolution_y'] = $ThisFileInfo['mpeg']['video']['framesize_vertical'];
        $ThisFileInfo['video']['frame_rate'] = $ThisFileInfo['mpeg']['video']['frame_rate'];
        $ThisFileInfo['video']['bitrate_mode'] = $ThisFileInfo['mpeg']['video']['bitrate_mode'];
        $ThisFileInfo['video']['lossless'] = false;
        $ThisFileInfo['video']['bits_per_sample'] = 24;
    } else {
        $ThisFileInfo['error'] .= "\n" . 'Could not find start of video block in the first 100,000 bytes (or before end of file) - this might not be an MPEG-video file?';
    }
    $AudioChunkOffset = 0;
    while (true) {
        while (substr($MPEGstreamData, $AudioChunkOffset++, 4) !== MPEG_AUDIO_START) {
            if ($AudioChunkOffset >= $MPEGstreamDataLength) {
                break 2;
            }
        }
        require_once GETID3_INCLUDEPATH . 'getid3.mp3.php';
        for ($i = 0; $i <= 2; $i++) {
            // some files have the MPEG-audio header 8 bytes after the end of the $00 $00 $01 $C0 signature, some have it 9 bytes, some 10 bytes after
            // I have no idea why or what the difference is, so this is a stupid hack.
            // If anybody has any better idea of what's going on, please let me know - info@getid3.org
            $dummy = $ThisFileInfo;
            if (decodeMPEGaudioHeader($fd, $AudioChunkOffset + 3 + 8 + $i, $dummy, false)) {
                $ThisFileInfo = $dummy;
                $ThisFileInfo['audio']['bits_per_sample'] = 16;
                $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
                $ThisFileInfo['audio']['lossless'] = false;
                break 2;
            }
        }
    }
    return true;
}
function getID3v2Filepointer($fd, &$MP3fileInfo)
{
    //	Overall tag structure:
    //		+-----------------------------+
    //		|      Header (10 bytes)      |
    //		+-----------------------------+
    //		|       Extended Header       |
    //		| (variable length, OPTIONAL) |
    //		+-----------------------------+
    //		|   Frames (variable length)  |
    //		+-----------------------------+
    //		|           Padding           |
    //		| (variable length, OPTIONAL) |
    //		+-----------------------------+
    //		| Footer (10 bytes, OPTIONAL) |
    //		+-----------------------------+
    //	Header
    //		ID3v2/file identifier      "ID3"
    //		ID3v2 version              $04 00
    //		ID3v2 flags                (%ab000000 in v2.2, %abc00000 in v2.3, %abcd0000 in v2.4.x)
    //		ID3v2 size             4 * %0xxxxxxx
    rewind($fd);
    $header = fread($fd, 10);
    if (substr($header, 0, 3) == 'ID3') {
        $MP3fileInfo['id3']['id3v2']['header'] = TRUE;
        $MP3fileInfo['id3']['id3v2']['majorversion'] = ord($header[3]);
        $MP3fileInfo['id3']['id3v2']['minorversion'] = ord($header[4]);
    }
    if (isset($MP3fileInfo['id3']['id3v2']['header']) && $MP3fileInfo['id3']['id3v2']['majorversion'] <= 4) {
        // this script probably won't correctly parse ID3v2.5.x and above.
        $id3_flags = BigEndian2Bin($header[5]);
        if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 2) {
            // %ab000000 in v2.2
            $MP3fileInfo['id3']['id3v2']['flags']['unsynch'] = $id3_flags[0];
            // a - Unsynchronisation
            $MP3fileInfo['id3']['id3v2']['flags']['compression'] = $id3_flags[1];
            // b - Compression
        } else {
            if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 3) {
                // %abc00000 in v2.3
                $MP3fileInfo['id3']['id3v2']['flags']['unsynch'] = $id3_flags[0];
                // a - Unsynchronisation
                $MP3fileInfo['id3']['id3v2']['flags']['exthead'] = $id3_flags[1];
                // b - Extended header
                $MP3fileInfo['id3']['id3v2']['flags']['experim'] = $id3_flags[2];
                // c - Experimental indicator
            } else {
                if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 4) {
                    // %abcd0000 in v2.4
                    $MP3fileInfo['id3']['id3v2']['flags']['unsynch'] = $id3_flags[0];
                    // a - Unsynchronisation
                    $MP3fileInfo['id3']['id3v2']['flags']['exthead'] = $id3_flags[1];
                    // b - Extended header
                    $MP3fileInfo['id3']['id3v2']['flags']['experim'] = $id3_flags[2];
                    // c - Experimental indicator
                    $MP3fileInfo['id3']['id3v2']['flags']['isfooter'] = $id3_flags[3];
                    // d - Footer present
                }
            }
        }
        $MP3fileInfo['id3']['id3v2']['headerlength'] = BigEndian2Int(substr($header, 6, 4), 1) + ID3v2HeaderLength($MP3fileInfo['id3']['id3v2']['majorversion']);
        //	Extended Header
        if (isset($MP3fileInfo['id3']['id3v2']['flags']['exthead']) && $MP3fileInfo['id3']['id3v2']['flags']['exthead']) {
            //			Extended header size   4 * %0xxxxxxx
            //			Number of flag bytes       $01
            //			Extended Flags             $xx
            //			Where the 'Extended header size' is the size of the whole extended header, stored as a 32 bit synchsafe integer.
            $extheader = fread($fd, 4);
            $MP3fileInfo['id3']['id3v2']['extheaderlength'] = BigEndian2Int($extheader, 1);
            //			The extended flags field, with its size described by 'number of flag  bytes', is defined as:
            //				%0bcd0000
            //			b - Tag is an update
            //				Flag data length       $00
            //			c - CRC data present
            //				Flag data length       $05
            //				Total frame CRC    5 * %0xxxxxxx
            //			d - Tag restrictions
            //				Flag data length       $01
            $extheaderflagbytes = fread($fd, 1);
            $extheaderflags = fread($fd, $extheaderflagbytes);
            $id3_exthead_flags = BigEndian2Bin(substr($header, 5, 1));
            $MP3fileInfo['id3']['id3v2']['exthead_flags']['update'] = substr($id3_exthead_flags, 1, 1);
            $MP3fileInfo['id3']['id3v2']['exthead_flags']['CRC'] = substr($id3_exthead_flags, 2, 1);
            if ($MP3fileInfo['id3']['id3v2']['exthead_flags']['CRC']) {
                $extheaderrawCRC = fread($fd, 5);
                $MP3fileInfo['id3']['id3v2']['exthead_flags']['CRC'] = BigEndian2Int($extheaderrawCRC, 1);
            }
            $MP3fileInfo['id3']['id3v2']['exthead_flags']['restrictions'] = substr($id3_exthead_flags, 3, 1);
            if ($MP3fileInfo['id3']['id3v2']['exthead_flags']['restrictions']) {
                // Restrictions           %ppqrrstt
                $extheaderrawrestrictions = fread($fd, 1);
                $MP3fileInfo['id3']['id3v2']['exthead_flags']['restrictions_tagsize'] = (bindec('11000000') & ord($extheaderrawrestrictions)) >> 6;
                // p - Tag size restrictions
                $MP3fileInfo['id3']['id3v2']['exthead_flags']['restrictions_textenc'] = (bindec('00100000') & ord($extheaderrawrestrictions)) >> 5;
                // q - Text encoding restrictions
                $MP3fileInfo['id3']['id3v2']['exthead_flags']['restrictions_textsize'] = (bindec('00011000') & ord($extheaderrawrestrictions)) >> 3;
                // r - Text fields size restrictions
                $MP3fileInfo['id3']['id3v2']['exthead_flags']['restrictions_imgenc'] = (bindec('00000100') & ord($extheaderrawrestrictions)) >> 2;
                // s - Image encoding restrictions
                $MP3fileInfo['id3']['id3v2']['exthead_flags']['restrictions_imgsize'] = (bindec('00000011') & ord($extheaderrawrestrictions)) >> 0;
                // t - Image size restrictions
            }
        }
        // end extended header
        //	Frames
        //		All ID3v2 frames consists of one frame header followed by one or more
        //		fields containing the actual information. The header is always 10
        //		bytes and laid out as follows:
        //
        //		Frame ID      $xx xx xx xx  (four characters)
        //		Size      4 * %0xxxxxxx
        //		Flags         $xx xx
        $sizeofframes = $MP3fileInfo['id3']['id3v2']['headerlength'] - ID3v2HeaderLength($MP3fileInfo['id3']['id3v2']['majorversion']);
        if (isset($MP3fileInfo['id3']['id3v2']['extheaderlength'])) {
            $sizeofframes -= $MP3fileInfo['id3']['id3v2']['extheaderlength'];
        }
        if (isset($MP3fileInfo['id3']['id3v2']['flags']['isfooter']) && $MP3fileInfo['id3']['id3v2']['flags']['isfooter']) {
            $sizeofframes -= 10;
            // footer takes last 10 bytes of ID3v2 header, after frame data, before audio
        }
        if ($sizeofframes > 0) {
            $framedata = fread($fd, $sizeofframes);
            // read all frames from file into $framedata variable
            //	if entire frame data is unsynched, de-unsynch it now (ID3v2.3.x)
            if (isset($MP3fileInfo['id3']['id3v2']['flags']['unsynch']) && $MP3fileInfo['id3']['id3v2']['flags']['unsynch'] && $MP3fileInfo['id3']['id3v2']['majorversion'] <= 3) {
                $framedata = DeUnSynchronise($framedata);
            }
            //		[in ID3v2.4.0] Unsynchronisation [S:6.1] is done on frame level, instead
            //		of on tag level, making it easier to skip frames, increasing the streamability
            //		of the tag. The unsynchronisation flag in the header [S:3.1] indicates that
            //		there exists an unsynchronised frame, while the new unsynchronisation flag in
            //		the frame header [S:4.1.2] indicates unsynchronisation.
            include_once GETID3_INCLUDEPATH . 'getid3.frames.php';
            // ID3v2FrameProcessing()
            $framedataoffset = 10;
            // how many bytes into the stream - start from after the 10-byte header
            while (isset($framedata) && strlen($framedata) > 0) {
                // cycle through until no more frame data is left to parse
                if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 2) {
                    // Frame ID  $xx xx xx (three characters)
                    // Size      $xx xx xx (24-bit integer)
                    // Flags     $xx xx
                    $frame_header = substr($framedata, 0, 6);
                    // take next 6 bytes for header
                    $framedata = substr($framedata, 6);
                    // and leave the rest in $framedata
                    $frame_name = substr($frame_header, 0, 3);
                    $frame_size = BigEndian2Int(substr($frame_header, 3, 3), 0);
                    $frame_flags = '';
                    // not used for anything, just to avoid E_NOTICEs
                } else {
                    if ($MP3fileInfo['id3']['id3v2']['majorversion'] > 2) {
                        // Frame ID  $xx xx xx xx (four characters)
                        // Size      $xx xx xx xx (32-bit integer in v2.3, 28-bit synchsafe in v2.4+)
                        // Flags     $xx xx
                        $frame_header = substr($framedata, 0, 10);
                        // take next 10 bytes for header
                        $framedata = substr($framedata, 10);
                        // and leave the rest in $framedata
                        $frame_name = substr($frame_header, 0, 4);
                        if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 3) {
                            $frame_size = BigEndian2Int(substr($frame_header, 4, 4), 0);
                            // 32-bit integer
                        } else {
                            // ID3v2.4+
                            $frame_size = BigEndian2Int(substr($frame_header, 4, 4), 1);
                            // 32-bit synchsafe integer (28-bit value)
                        }
                        if ($frame_size < strlen($framedata) + 4) {
                            $nextFrameID = substr($framedata, $frame_size, 4);
                            if (IsValidID3v2FrameName($nextFrameID, $MP3fileInfo['id3']['id3v2']['majorversion'])) {
                                // next frame is OK
                            } else {
                                if ($frame_name == chr(0) . 'MP3' || $frame_name == ' MP3' || $frame_name == 'MP3e') {
                                    // MP3ext known broken frames - "ok" for the purposes of this test
                                } else {
                                    if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 4 && IsValidID3v2FrameName(substr($framedata, BigEndian2Int(substr($frame_header, 4, 4), 0), 4), 3)) {
                                        $MP3fileInfo['error'] .= "\n" . 'ID3v2 tag written as ID3v2.4, but with non-synchsafe integers (ID3v2.3 style). Older versions of Helium2 (www.helium2.com) is a known culprit of this. Tag has been parsed as ID3v2.3';
                                        $MP3fileInfo['id3']['id3v2']['majorversion'] = 3;
                                        $frame_size = BigEndian2Int(substr($frame_header, 4, 4), 0);
                                        // 32-bit integer
                                    }
                                }
                            }
                        }
                        $frame_flags = BigEndian2Bin(substr($frame_header, 8, 2));
                    }
                }
                if ($frame_name == chr(0) . chr(0) . chr(0) . chr(0)) {
                    // padding encountered
                    // $MP3fileInfo['id3']['id3v2']['padding']['start']  = $MP3fileInfo['id3']['id3v2']['headerlength'] - strlen($framedata);
                    $MP3fileInfo['id3']['id3v2']['padding']['start'] = $framedataoffset;
                    $MP3fileInfo['id3']['id3v2']['padding']['length'] = strlen($framedata);
                    $MP3fileInfo['id3']['id3v2']['padding']['valid'] = TRUE;
                    for ($i = 0; $i < $MP3fileInfo['id3']['id3v2']['padding']['length']; $i++) {
                        if (substr($framedata, $i, 1) != chr(0)) {
                            $MP3fileInfo['id3']['id3v2']['padding']['valid'] = FALSE;
                            $MP3fileInfo['id3']['id3v2']['padding']['errorpos'] = $MP3fileInfo['id3']['id3v2']['padding']['start'] + $i;
                            break;
                        }
                    }
                    break;
                    // skip rest of ID3v2 header
                }
                if ($frame_size <= strlen($framedata) && IsValidID3v2FrameName($frame_name, $MP3fileInfo['id3']['id3v2']['majorversion'])) {
                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'] = substr($framedata, 0, $frame_size);
                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'] = CastAsInt($frame_size);
                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'] = $framedataoffset;
                    $framedata = substr($framedata, $frame_size);
                    // in getid3.frames.php - this function does all the FrameID-level parsing
                    ID3v2FrameProcessing($frame_name, $frame_flags, $MP3fileInfo);
                    $framedataoffset += $frame_size + ID3v2HeaderLength($MP3fileInfo['id3']['id3v2']['majorversion']);
                } else {
                    // invalid frame length or FrameID
                    $MP3fileInfo['error'] .= "\n" . 'error parsing "' . $frame_name . '" (' . $framedataoffset . ' bytes into the ID3v2.' . $MP3fileInfo['id3']['id3v2']['majorversion'] . ' tag).';
                    if ($frame_size > strlen($framedata)) {
                        $MP3fileInfo['error'] .= ' (ERROR: $frame_size (' . $frame_size . ') > strlen($framedata) (' . strlen($framedata) . ')).';
                    }
                    if (!IsValidID3v2FrameName($frame_name, $MP3fileInfo['id3']['id3v2']['majorversion'])) {
                        $MP3fileInfo['error'] .= ' (ERROR: !IsValidID3v2FrameName("' . str_replace(chr(0), ' ', $frame_name) . '", ' . $MP3fileInfo['id3']['id3v2']['majorversion'] . '))).';
                        if ($frame_name == chr(0) . 'MP3' || $frame_name == ' MP3' || $frame_name == 'MP3e') {
                            $MP3fileInfo['error'] .= ' [Note: this particular error has been known to happen with tags edited by "MP3ext V3.3.17(unicode)"]';
                        } else {
                            if ($frame_name == 'COM ') {
                                $MP3fileInfo['error'] .= ' [Note: this particular error has been known to happen with tags edited by "iTunes X v2.0.3"]';
                            }
                        }
                    }
                    if ($frame_size <= strlen($framedata) && IsValidID3v2FrameName(substr($framedata, $frame_size, 4), $MP3fileInfo['id3']['id3v2']['majorversion'])) {
                        // next frame is valid, just skip the current frame
                        $framedata = substr($framedata, $frame_size);
                    } else {
                        // next frame is invalid too, abort processing
                        unset($framedata);
                    }
                }
            }
        }
        //	Footer
        //	The footer is a copy of the header, but with a different identifier.
        //		ID3v2 identifier           "3DI"
        //		ID3v2 version              $04 00
        //		ID3v2 flags                %abcd0000
        //		ID3v2 size             4 * %0xxxxxxx
        if (isset($MP3fileInfo['id3']['id3v2']['flags']['isfooter']) && $MP3fileInfo['id3']['id3v2']['flags']['isfooter']) {
            $footer = fread($fd, 10);
            if (substr($footer, 0, 3) == '3DI') {
                $MP3fileInfo['id3']['id3v2']['footer'] = true;
                $MP3fileInfo['id3']['id3v2']['majorversion_footer'] = ord(substr($footer, 3, 1));
                $MP3fileInfo['id3']['id3v2']['minorversion_footer'] = ord(substr($footer, 4, 1));
            }
            if ($MP3fileInfo['id3']['id3v2']['majorversion_footer'] <= 4) {
                $id3_flags = BigEndian2Bin(substr($footer, 5, 1));
                $MP3fileInfo['id3']['id3v2']['flags']['unsynch_footer'] = substr($id3_flags, 0, 1);
                $MP3fileInfo['id3']['id3v2']['flags']['extfoot_footer'] = substr($id3_flags, 1, 1);
                $MP3fileInfo['id3']['id3v2']['flags']['experim_footer'] = substr($id3_flags, 2, 1);
                $MP3fileInfo['id3']['id3v2']['flags']['isfooter_footer'] = substr($id3_flags, 3, 1);
                $MP3fileInfo['id3']['id3v2']['footerlength'] = BigEndian2Int(substr($footer, 6, 4), 1);
            }
        }
        // end footer
        // Translate most common ID3v2 FrameIDs to easier-to-understand names
        if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 2) {
            if (isset($MP3fileInfo['id3']['id3v2']['TT2'])) {
                $MP3fileInfo['id3']['id3v2']['title'] = $MP3fileInfo['id3']['id3v2']['TT2']['asciidata'];
            }
            if (isset($MP3fileInfo['id3']['id3v2']['TP1'])) {
                $MP3fileInfo['id3']['id3v2']['artist'] = $MP3fileInfo['id3']['id3v2']['TP1']['asciidata'];
            }
            if (isset($MP3fileInfo['id3']['id3v2']['TAL'])) {
                $MP3fileInfo['id3']['id3v2']['album'] = $MP3fileInfo['id3']['id3v2']['TAL']['asciidata'];
            }
            if (isset($MP3fileInfo['id3']['id3v2']['TYE'])) {
                $MP3fileInfo['id3']['id3v2']['year'] = $MP3fileInfo['id3']['id3v2']['TYE']['asciidata'];
            }
            if (isset($MP3fileInfo['id3']['id3v2']['TRK'])) {
                $MP3fileInfo['id3']['id3v2']['track'] = $MP3fileInfo['id3']['id3v2']['TRK']['asciidata'];
            }
            if (isset($MP3fileInfo['id3']['id3v2']['TCO'])) {
                $MP3fileInfo['id3']['id3v2']['genre'] = $MP3fileInfo['id3']['id3v2']['TCO']['asciidata'];
            }
            if (isset($MP3fileInfo['id3']['id3v2']['COM'][0]['asciidata'])) {
                $MP3fileInfo['id3']['id3v2']['comment'] = $MP3fileInfo['id3']['id3v2']['COM'][0]['asciidata'];
            }
        } else {
            // $MP3fileInfo['id3']['id3v2']['majorversion'] > 2
            if (isset($MP3fileInfo['id3']['id3v2']['TIT2'])) {
                $MP3fileInfo['id3']['id3v2']['title'] = $MP3fileInfo['id3']['id3v2']['TIT2']['asciidata'];
            }
            if (isset($MP3fileInfo['id3']['id3v2']['TPE1'])) {
                $MP3fileInfo['id3']['id3v2']['artist'] = $MP3fileInfo['id3']['id3v2']['TPE1']['asciidata'];
            }
            if (isset($MP3fileInfo['id3']['id3v2']['TALB'])) {
                $MP3fileInfo['id3']['id3v2']['album'] = $MP3fileInfo['id3']['id3v2']['TALB']['asciidata'];
            }
            if (isset($MP3fileInfo['id3']['id3v2']['TYER'])) {
                $MP3fileInfo['id3']['id3v2']['year'] = $MP3fileInfo['id3']['id3v2']['TYER']['asciidata'];
            }
            if (isset($MP3fileInfo['id3']['id3v2']['TRCK'])) {
                $MP3fileInfo['id3']['id3v2']['track'] = $MP3fileInfo['id3']['id3v2']['TRCK']['asciidata'];
            }
            if (isset($MP3fileInfo['id3']['id3v2']['TCON'])) {
                $MP3fileInfo['id3']['id3v2']['genre'] = $MP3fileInfo['id3']['id3v2']['TCON']['asciidata'];
            }
            if (isset($MP3fileInfo['id3']['id3v2']['COMM'][0]['asciidata'])) {
                $MP3fileInfo['id3']['id3v2']['comment'] = $MP3fileInfo['id3']['id3v2']['COMM'][0]['asciidata'];
            }
        }
        if (isset($MP3fileInfo['id3']['id3v2']['genre'])) {
            $MP3fileInfo['id3']['id3v2']['genrelist'] = ParseID3v2GenreString($MP3fileInfo['id3']['id3v2']['genre']);
            if ($MP3fileInfo['id3']['id3v2']['genrelist']['genreid'][0] !== '') {
                $MP3fileInfo['id3']['id3v2']['genreid'] = $MP3fileInfo['id3']['id3v2']['genrelist']['genreid'][0];
            }
            $MP3fileInfo['id3']['id3v2']['genre'] = $MP3fileInfo['id3']['id3v2']['genrelist']['genre'][0];
        }
        if (isset($MP3fileInfo['id3']['id3v2']['track']) && strpos($MP3fileInfo['id3']['id3v2']['track'], '/') !== FALSE) {
            $tracktotaltracks = explode('/', $MP3fileInfo['id3']['id3v2']['track']);
            $MP3fileInfo['id3']['id3v2']['track'] = $tracktotaltracks[0];
            $MP3fileInfo['id3']['id3v2']['totaltracks'] = $tracktotaltracks[1];
        }
    } else {
        // MajorVersion is > 4, or no ID3v2 header present
        if (isset($MP3fileInfo['id3']['id3v2']['header'])) {
            // MajorVersion is > 4
            $MP3fileInfo['error'] .= "\n" . 'this script only parses up to ID3v2.4.x - this tag is ID3v2.' . $MP3fileInfo['id3']['id3v2']['majorversion'] . '.' . $MP3fileInfo['id3']['id3v2']['minorversion'];
        } else {
            // no ID3v2 header present - this is fine, just don't process anything.
        }
    }
    return TRUE;
}