function MPEGaudioHeaderBytesValid($head4) { return MPEGaudioHeaderValid(MPEGaudioHeaderDecode($head4)); }
function decodeMPEGaudioHeader($fd, $offset, &$MP3fileInfo, $recursivesearch = TRUE) { if ($offset >= $MP3fileInfo['filesize']) { $MP3fileInfo['error'] .= "\n" . 'end of file encounter looking for MPEG synch'; return FALSE; } fseek($fd, $offset, SEEK_SET); $headerstring = fread($fd, FREAD_BUFFER_SIZE); // 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 // AAAAAAAA AAABBCCD EEEEFFGH IIJJKLMM // 01234567 01234567 01234567 01234567 // A - Frame sync (all bits set) // B - MPEG Audio version ID // C - Layer description // D - Protection bit // E - Bitrate index // F - Sampling rate frequency index // G - Padding bit // H - Private bit // I - Channel Mode // J - Mode extension (Only if Joint stereo) // K - Copyright // L - Original // M - Emphasis $byte1 = BigEndian2Bin(substr($headerstring, 0, 1)); $byte2 = BigEndian2Bin(substr($headerstring, 1, 1)); $byte3 = BigEndian2Bin(substr($headerstring, 2, 1)); $byte4 = BigEndian2Bin(substr($headerstring, 3, 1)); if (substr(BigEndian2Bin(substr($headerstring, 0, 2)), 0, 11) == '11111111111') { // synch detected (11 set bits in a row) } else { $MP3fileInfo['error'] .= "\n" . 'MPEG-audio synch not found where expected (at offset ' . $offset . ')'; return FALSE; } $MP3fileInfo['mpeg']['audio']['raw']['version'] = bindec(substr($byte2, 3, 2)); $MP3fileInfo['mpeg']['audio']['raw']['layer'] = bindec(substr($byte2, 5, 2)); $MP3fileInfo['mpeg']['audio']['raw']['protection'] = bindec(substr($byte2, 7, 1)); $MP3fileInfo['mpeg']['audio']['raw']['bitrate'] = bindec(substr($byte3, 0, 4)); $MP3fileInfo['mpeg']['audio']['raw']['frequency'] = bindec(substr($byte3, 4, 2)); $MP3fileInfo['mpeg']['audio']['raw']['padding'] = bindec(substr($byte3, 6, 1)); $MP3fileInfo['mpeg']['audio']['raw']['private'] = bindec(substr($byte3, 7, 1)); $MP3fileInfo['mpeg']['audio']['raw']['channelmode'] = bindec(substr($byte4, 0, 2)); $MP3fileInfo['mpeg']['audio']['raw']['modeextension'] = bindec(substr($byte4, 2, 2)); $MP3fileInfo['mpeg']['audio']['raw']['copyright'] = bindec(substr($byte4, 4, 1)); $MP3fileInfo['mpeg']['audio']['raw']['original'] = bindec(substr($byte4, 5, 1)); $MP3fileInfo['mpeg']['audio']['raw']['emphasis'] = bindec(substr($byte4, 6, 2)); if (!MPEGaudioHeaderValid($MP3fileInfo['mpeg']['audio']['raw'])) { $MP3fileInfo['error'] .= "\n" . 'invalid MPEG audio header at offset ' . $offset; return FALSE; } $MP3fileInfo['mpeg']['audio']['version'] = MPEGaudioVersionLookup($MP3fileInfo['mpeg']['audio']['raw']['version']); $MP3fileInfo['mpeg']['audio']['layer'] = MPEGaudioLayerLookup($MP3fileInfo['mpeg']['audio']['raw']['layer']); $MP3fileInfo['mpeg']['audio']['protection'] = MPEGaudioCRCLookup($MP3fileInfo['mpeg']['audio']['raw']['protection']); $MP3fileInfo['mpeg']['audio']['bitrate'] = MPEGaudioBitrateLookup($MP3fileInfo['mpeg']['audio']['version'], $MP3fileInfo['mpeg']['audio']['layer'], $MP3fileInfo['mpeg']['audio']['raw']['bitrate']); $MP3fileInfo['mpeg']['audio']['frequency'] = MPEGaudioFrequencyLookup($MP3fileInfo['mpeg']['audio']['version'], $MP3fileInfo['mpeg']['audio']['raw']['frequency']); $MP3fileInfo['mpeg']['audio']['padding'] = (bool) $MP3fileInfo['mpeg']['audio']['raw']['padding']; $MP3fileInfo['mpeg']['audio']['private'] = (bool) $MP3fileInfo['mpeg']['audio']['raw']['private']; $MP3fileInfo['mpeg']['audio']['channelmode'] = MPEGaudioChannelModeLookup($MP3fileInfo['mpeg']['audio']['raw']['channelmode']); $MP3fileInfo['mpeg']['audio']['channels'] = $MP3fileInfo['mpeg']['audio']['channelmode'] == 'mono' ? 1 : 2; $MP3fileInfo['mpeg']['audio']['modeextension'] = MPEGaudioModeExtensionLookup($MP3fileInfo['mpeg']['audio']['layer'], $MP3fileInfo['mpeg']['audio']['raw']['modeextension']); $MP3fileInfo['mpeg']['audio']['copyright'] = (bool) $MP3fileInfo['mpeg']['audio']['raw']['copyright']; $MP3fileInfo['mpeg']['audio']['original'] = (bool) $MP3fileInfo['mpeg']['audio']['raw']['original']; $MP3fileInfo['mpeg']['audio']['emphasis'] = MPEGaudioEmphasisLookup($MP3fileInfo['mpeg']['audio']['raw']['emphasis']); if ($MP3fileInfo['mpeg']['audio']['protection']) { $MP3fileInfo['mpeg']['audio']['crc'] = BigEndian2Int(substr($headerstring, 4, 2)); } if ($MP3fileInfo['mpeg']['audio']['bitrate'] != 'free') { if ($MP3fileInfo['mpeg']['audio']['version'] == '1') { if ($MP3fileInfo['mpeg']['audio']['layer'] == 'I') { $FrameLengthCoefficient = 48; $FrameLengthPadding = $MP3fileInfo['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 = $MP3fileInfo['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 ($MP3fileInfo['mpeg']['audio']['layer'] == 'I') { $FrameLengthCoefficient = 24; $FrameLengthPadding = $MP3fileInfo['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 = $MP3fileInfo['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 $MP3fileInfo['mpeg']['audio']['framelength'] = (int) floor($FrameLengthCoefficient * 1000 * $MP3fileInfo['mpeg']['audio']['bitrate'] / $MP3fileInfo['mpeg']['audio']['frequency']) + $FrameLengthPadding; } $MP3fileInfo['bitrate'] = 1000 * $MP3fileInfo['mpeg']['audio']['bitrate']; $nextframetestarray = array('error' => '', 'filesize' => $MP3fileInfo['filesize']); if (isset($MP3fileInfo['mpeg']['audio']['framelength'])) { $nextframetestoffset = $offset + $MP3fileInfo['mpeg']['audio']['framelength']; } else { $nextframetestoffset = $MP3fileInfo['filesize']; } if ($recursivesearch && isset($MP3fileInfo['mpeg']['audio']['framelength']) && $MP3fileInfo['mpeg']['audio']['framelength']) { for ($i = 0; $i < 5; $i++) { // check next 5 frames for validity, to make sure we haven't run across a false synch if ($nextframetestoffset >= $MP3fileInfo['filesize']) { // end of file break; } if (decodeMPEGaudioHeader($fd, $nextframetestoffset, $nextframetestarray, FALSE)) { // next frame is OK, get ready to check the one after that $nextframetestoffset += $nextframetestarray['mpeg']['audio']['framelength']; } else { // next frame is not valid, note the error and fail, so scanning can contiue for a valid frame sequence $MP3fileInfo['error'] .= "\n" . 'Frame at offset(' . $offset . ') is valid, but the next one at (' . $nextframetestoffset . ') is not.'; return FALSE; } } } // For Layer II there are some combinations of bitrate and mode which are not allowed. if ($MP3fileInfo['mpeg']['audio']['layer'] == 'II') { switch ($MP3fileInfo['mpeg']['audio']['channelmode']) { case 'mono': if ($MP3fileInfo['mpeg']['audio']['bitrate'] == 'free' || $MP3fileInfo['mpeg']['audio']['bitrate'] <= 192) { // these are ok } else { $MP3fileInfo['error'] .= "\n" . $MP3fileInfo['mpeg']['audio']['bitrate'] . 'kbps not allowed in Layer II, ' . $MP3fileInfo['mpeg']['audio']['channelmode'] . '.'; } break; case 'stereo': case 'joint stereo': case 'dual channel': if ($MP3fileInfo['mpeg']['audio']['bitrate'] == 'free' || $MP3fileInfo['mpeg']['audio']['bitrate'] == 64 || $MP3fileInfo['mpeg']['audio']['bitrate'] >= 96) { // these are ok } else { $MP3fileInfo['error'] .= "\n" . $MP3fileInfo['mpeg']['audio']['bitrate'] . 'kbps not allowed in Layer II, ' . $MP3fileInfo['mpeg']['audio']['channelmode'] . '.'; } break; } } //////////////////////////////////////////////////////////////////////////////////// // Variable-bitrate headers if ($MP3fileInfo['mpeg']['audio']['version'] == '1') { if ($MP3fileInfo['mpeg']['audio']['channelmode'] == 'mono') { $VBRidOffset = 17 + 4; // 21 bytes } else { $VBRidOffset = 32 + 4; // 36 bytes } } else { // 2 or 2.5 if ($MP3fileInfo['mpeg']['audio']['channelmode'] == 'mono') { $VBRidOffset = 9 + 4; // 13 bytes } else { $VBRidOffset = 17 + 4; // 21 bytes } } $VBRid = substr($headerstring, $VBRidOffset, 4); if ($VBRid == 'Xing') { $MP3fileInfo['mpeg']['audio']['bitratemode'] = 'VBR'; $MP3fileInfo['mpeg']['audio']['VBR_method'] = 'Xing'; } else { if ($VBRid == 'VBRI') { $MP3fileInfo['mpeg']['audio']['bitratemode'] = 'VBR'; $MP3fileInfo['mpeg']['audio']['VBR_method'] = 'Fraunhofer'; } else { $MP3fileInfo['mpeg']['audio']['bitratemode'] = 'CBR'; } } if ($MP3fileInfo['mpeg']['audio']['bitratemode'] == 'VBR') { if ($MP3fileInfo['mpeg']['audio']['VBR_method'] == 'Xing') { $XingVBROffset = $VBRidOffset + 4; $XingHeader_Flags = substr($headerstring, $XingVBROffset, 4); $XingVBROffset += 4; $XingHeader_byte4 = BigEndian2Bin(substr($XingHeader_Flags, 3, 1)); $XingHeader_flags['frames'] = substr($XingHeader_byte4, 4, 1); $XingHeader_flags['bytes'] = substr($XingHeader_byte4, 5, 1); $XingHeader_flags['toc'] = substr($XingHeader_byte4, 6, 1); $XingHeader_flags['vbr_scale'] = substr($XingHeader_byte4, 7, 1); if ($XingHeader_flags['frames'] == '1') { $XingHeader_Frames = substr($headerstring, $XingVBROffset, 4); $XingVBROffset += 4; $MP3fileInfo['mpeg']['audio']['VBR_frames'] = BigEndian2Int($XingHeader_Frames); } if ($XingHeader_flags['bytes'] == '1') { $XingHeader_Bytes = substr($headerstring, $XingVBROffset, 4); $XingVBROffset += 4; $MP3fileInfo['mpeg']['audio']['VBR_bytes'] = BigEndian2Int($XingHeader_Bytes); } } else { if ($MP3fileInfo['mpeg']['audio']['VBR_method'] == 'Fraunhofer') { // specs taken from http://minnie.tuhs.org/pipermail/mp3encoder/2001-January/001800.html $FraunhoferVBROffset = $VBRidOffset + 4; $Fraunhofer_version = substr($headerstring, $FraunhoferVBROffset, 4); $FraunhoferVBROffset += 4; $Fraunhofer_quality = substr($headerstring, $FraunhoferVBROffset, 2); $FraunhoferVBROffset += 2; $MP3fileInfo['mpeg']['audio']['VBR_quality'] = BigEndian2Int($Fraunhofer_quality); $Fraunhofer_Bytes = substr($headerstring, $FraunhoferVBROffset, 4); $FraunhoferVBROffset += 4; $MP3fileInfo['mpeg']['audio']['VBR_bytes'] = BigEndian2Int($Fraunhofer_Bytes); $Fraunhofer_Frames = substr($headerstring, $FraunhoferVBROffset, 4); $FraunhoferVBROffset += 4; $MP3fileInfo['mpeg']['audio']['VBR_frames'] = BigEndian2Int($Fraunhofer_Frames); } } $MP3fileInfo['mpeg']['audio']['VBR_frames']--; // don't count the Xing / VBRI frame if ($MP3fileInfo['mpeg']['audio']['version'] == '1' && $MP3fileInfo['mpeg']['audio']['layer'] == 'I') { $MP3fileInfo['mpeg']['audio']['VBR_bitrate'] = $MP3fileInfo['mpeg']['audio']['VBR_bytes'] / $MP3fileInfo['mpeg']['audio']['VBR_frames'] * 8 * ($MP3fileInfo['mpeg']['audio']['frequency'] / 384) / 1000; } else { if (($MP3fileInfo['mpeg']['audio']['version'] == '2' || $MP3fileInfo['mpeg']['audio']['version'] == '2.5') && $MP3fileInfo['mpeg']['audio']['layer'] == 'III') { $MP3fileInfo['mpeg']['audio']['VBR_bitrate'] = $MP3fileInfo['mpeg']['audio']['VBR_bytes'] / $MP3fileInfo['mpeg']['audio']['VBR_frames'] * 8 * ($MP3fileInfo['mpeg']['audio']['frequency'] / 576) / 1000; } else { $MP3fileInfo['mpeg']['audio']['VBR_bitrate'] = $MP3fileInfo['mpeg']['audio']['VBR_bytes'] / $MP3fileInfo['mpeg']['audio']['VBR_frames'] * 8 * ($MP3fileInfo['mpeg']['audio']['frequency'] / 1152) / 1000; } } if ($MP3fileInfo['mpeg']['audio']['VBR_bitrate'] > 0) { $MP3fileInfo['bitrate'] = 1000 * $MP3fileInfo['mpeg']['audio']['VBR_bitrate']; unset($MP3fileInfo['mpeg']['audio']['bitrate']); // to avoid confusion } } return TRUE; }
function getQuicktimeHeaderFilepointer(&$fd, &$ThisFileInfo) { $ThisFileInfo['fileformat'] = 'quicktime'; $ThisFileInfo['audio']['dataformat'] = 'quicktime'; $ThisFileInfo['video']['dataformat'] = 'quicktime'; fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET); $offset = 0; $atomcounter = 0; while ($offset < $ThisFileInfo['avdataend']) { fseek($fd, $offset, SEEK_SET); $AtomHeader = fread($fd, 8); $atomsize = BigEndian2Int(substr($AtomHeader, 0, 4)); $atomname = substr($AtomHeader, 4, 4); $ThisFileInfo['quicktime']["{$atomname}"]['name'] = $atomname; $ThisFileInfo['quicktime']["{$atomname}"]['size'] = $atomsize; $ThisFileInfo['quicktime']["{$atomname}"]['offset'] = $offset; if ($offset + $atomsize > $ThisFileInfo['avdataend']) { $ThisFileInfo['error'] .= "\n" . 'Atom at offset ' . $offset . ' claims to go beyond end-of-file (length: ' . $atomsize . ' bytes)'; return false; } switch ($atomname) { case 'mdat': // Media DATa atom // 'mdat' contains the actual data for the audio/video if (!isset($ThisFileInfo['avdataend_tmp']) || $ThisFileInfo['quicktime']["{$atomname}"]['size'] > $ThisFileInfo['avdataend_tmp'] - $ThisFileInfo['avdataoffset']) { $ThisFileInfo['avdataoffset'] = $ThisFileInfo['quicktime']["{$atomname}"]['offset'] + 8; $OldAVDataEnd = $ThisFileInfo['avdataend']; $ThisFileInfo['avdataend'] = $ThisFileInfo['quicktime']["{$atomname}"]['offset'] + $ThisFileInfo['quicktime']["{$atomname}"]['size']; require_once GETID3_INCLUDEPATH . 'getid3.mp3.php'; if (MPEGaudioHeaderValid(MPEGaudioHeaderDecode(fread($fd, 4)))) { getOnlyMPEGaudioInfo($fd, $ThisFileInfo, $ThisFileInfo['avdataoffset'], false); if (isset($ThisFileInfo['mpeg']['audio'])) { $ThisFileInfo['audio']['dataformat'] = 'mp3'; $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['mpeg']['audio']['sample_rate']; $ThisFileInfo['audio']['channels'] = $ThisFileInfo['mpeg']['audio']['channels']; $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['mpeg']['audio']['bitrate'] * 1000; $ThisFileInfo['audio']['bitrate_mode'] = strtolower($ThisFileInfo['mpeg']['audio']['bitratemode']); $ThisFileInfo['bitrate'] = $ThisFileInfo['audio']['bitrate']; } } $ThisFileInfo['avdataend'] = $OldAVDataEnd; unset($OldAVDataEnd); } break; case 'free': // FREE space atom // FREE space atom case 'skip': // SKIP atom // SKIP atom case 'wide': // 64-bit expansion placeholder atom // 'free', 'skip' and 'wide' are just padding, contains no useful data at all break; default: $atomHierarchy = array(); $ThisFileInfo['quicktime']["{$atomname}"] = QuicktimeParseAtom($atomname, $atomsize, fread($fd, $atomsize), $ThisFileInfo, $offset, $atomHierarchy); break; } $offset += $atomsize; $atomcounter++; } if (!empty($ThisFileInfo['avdataend_tmp'])) { // this value is assigned to a temp value and then erased because // otherwise any atoms beyond the 'mdat' atom would not get parsed $ThisFileInfo['avdataend'] = $ThisFileInfo['avdataend_tmp']; unset($ThisFileInfo['avdataend_tmp']); } // Quicktime tags have highest priority if (isset($ThisFileInfo['quicktime']['comments'])) { CopyFormatCommentsToRootComments($ThisFileInfo['quicktime']['comments'], $ThisFileInfo, true, true, true); // add tag to array of tags $ThisFileInfo['tags'][] = 'quicktime'; } if (!isset($ThisFileInfo['bitrate']) && isset($ThisFileInfo['playtime_seconds'])) { $ThisFileInfo['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 / $ThisFileInfo['playtime_seconds']; } if (isset($ThisFileInfo['bitrate']) && !isset($ThisFileInfo['audio']['bitrate']) && !isset($ThisFileInfo['quicktime']['video'])) { $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['bitrate']; } return true; }
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']['bitratemode'] = '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']['bitratemode'] = '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']['radio_replay_gain']['raw']['name']); $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']["{$ReplayGainNameKey}"]['originator'] = RGADoriginatorLookup($ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio_replay_gain']['raw']['originator']); $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']["{$ReplayGainNameKey}"]['gain_db'] = RGADadjustmentLookup($ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio_replay_gain']['raw']['gain_adjust'], $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio_replay_gain']['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'] = 1.5 * $ThisFileInfo['mpeg']['audio']['LAME']['mp3_gain_raw']; $ReservedBytes = BigEndian2Int(substr($headerstring, $XingVBROffset, 2)); $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']['bitratemode'] = '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']['bitratemode'] = 'cbr'; if ($recursivesearch) { $ThisFileInfo['mpeg']['audio']['bitratemode'] = 'vbr'; if (RecursiveFrameScanning($fd, $ThisFileInfo, $offset, $nextframetestoffset, true)) { $recursivesearch = false; $ThisFileInfo['mpeg']['audio']['bitratemode'] = 'cbr'; } if ($ThisFileInfo['mpeg']['audio']['bitratemode'] == 'vbr') { $ThisFileInfo['warning'] .= "\n" . 'VBR file with no VBR header. Bitrate values calculated from actual frame bitrates.'; } } } } if ($ThisFileInfo['mpeg']['audio']['bitratemode'] == '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']; unset($ThisFileInfo['mpeg']['audio']['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; }