ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
getid3_mp3 Class Reference
+ Inheritance diagram for getid3_mp3:
+ Collaboration diagram for getid3_mp3:

Public Member Functions

 Analyze ()
 
 GuessEncoderOptions ()
 
 decodeMPEGaudioHeader ($offset, &$info, $recursivesearch=true, $ScanAsCBR=false, $FastMPEGheaderScan=false)
 
 RecursiveFrameScanning (&$offset, &$nextframetestoffset, $ScanAsCBR)
 
 FreeFormatFrameLength ($offset, $deepscan=false)
 
 getOnlyMPEGaudioInfoBruteForce ()
 
 getOnlyMPEGaudioInfo ($avdataoffset, $BitrateHistogram=false)
 
- Public Member Functions inherited from getid3_handler
 __construct (getID3 $getid3, $call_module=null)
 
 Analyze ()
 
 AnalyzeString ($string)
 
 setStringMode ($string)
 
 saveAttachment ($name, $offset, $length, $image_mime=null)
 

Static Public Member Functions

static MPEGaudioVersionArray ()
 
static MPEGaudioLayerArray ()
 
static MPEGaudioBitrateArray ()
 
static MPEGaudioFrequencyArray ()
 
static MPEGaudioChannelModeArray ()
 
static MPEGaudioModeExtensionArray ()
 
static MPEGaudioEmphasisArray ()
 
static MPEGaudioHeaderBytesValid ($head4, $allowBitrate15=false)
 
static MPEGaudioHeaderValid ($rawarray, $echoerrors=false, $allowBitrate15=false)
 
static MPEGaudioHeaderDecode ($Header4Bytes)
 
static MPEGaudioFrameLength (&$bitrate, &$version, &$layer, $padding, &$samplerate)
 
static ClosestStandardMP3Bitrate ($bit_rate)
 
static XingVBRidOffset ($version, $channelmode)
 
static LAMEvbrMethodLookup ($VBRmethodID)
 
static LAMEmiscStereoModeLookup ($StereoModeID)
 
static LAMEmiscSourceSampleFrequencyLookup ($SourceSampleFrequencyID)
 
static LAMEsurroundInfoLookup ($SurroundInfoID)
 
static LAMEpresetUsedLookup ($LAMEtag)
 

Data Fields

 $allow_bruteforce = false
 

Additional Inherited Members

- Protected Member Functions inherited from getid3_handler
 ftell ()
 
 fread ($bytes)
 
 fseek ($bytes, $whence=SEEK_SET)
 
 feof ()
 
 isDependencyFor ($module)
 
 error ($text)
 
 warning ($text)
 
 notice ($text)
 
- Protected Attributes inherited from getid3_handler
 $getid3
 
 $data_string_flag = false
 
 $data_string = ''
 
 $data_string_position = 0
 
 $data_string_length = 0
 

Detailed Description

Definition at line 25 of file module.audio.mp3.php.

Member Function Documentation

◆ Analyze()

getid3_mp3::Analyze ( )

Definition at line 30 of file module.audio.mp3.php.

References $info, getid3_handler\error(), getid3_handler\fread(), getid3_handler\fseek(), getOnlyMPEGaudioInfo(), getOnlyMPEGaudioInfoBruteForce(), GuessEncoderOptions(), and getid3_handler\warning().

30  {
31  $info = &$this->getid3->info;
32 
33  $initialOffset = $info['avdataoffset'];
34 
35  if (!$this->getOnlyMPEGaudioInfo($info['avdataoffset'])) {
36  if ($this->allow_bruteforce) {
37  $this->error('Rescanning file in BruteForce mode');
38  $this->getOnlyMPEGaudioInfoBruteForce($this->getid3->fp, $info);
39  }
40  }
41 
42 
43  if (isset($info['mpeg']['audio']['bitrate_mode'])) {
44  $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
45  }
46 
47  if (((isset($info['id3v2']['headerlength']) && ($info['avdataoffset'] > $info['id3v2']['headerlength'])) || (!isset($info['id3v2']) && ($info['avdataoffset'] > 0) && ($info['avdataoffset'] != $initialOffset)))) {
48 
49  $synchoffsetwarning = 'Unknown data before synch ';
50  if (isset($info['id3v2']['headerlength'])) {
51  $synchoffsetwarning .= '(ID3v2 header ends at '.$info['id3v2']['headerlength'].', then '.($info['avdataoffset'] - $info['id3v2']['headerlength']).' bytes garbage, ';
52  } elseif ($initialOffset > 0) {
53  $synchoffsetwarning .= '(should be at '.$initialOffset.', ';
54  } else {
55  $synchoffsetwarning .= '(should be at beginning of file, ';
56  }
57  $synchoffsetwarning .= 'synch detected at '.$info['avdataoffset'].')';
58  if (isset($info['audio']['bitrate_mode']) && ($info['audio']['bitrate_mode'] == 'cbr')) {
59 
60  if (!empty($info['id3v2']['headerlength']) && (($info['avdataoffset'] - $info['id3v2']['headerlength']) == $info['mpeg']['audio']['framelength'])) {
61 
62  $synchoffsetwarning .= '. This is a known problem with some versions of LAME (3.90-3.92) DLL in CBR mode.';
63  $info['audio']['codec'] = 'LAME';
64  $CurrentDataLAMEversionString = 'LAME3.';
65 
66  } elseif (empty($info['id3v2']['headerlength']) && ($info['avdataoffset'] == $info['mpeg']['audio']['framelength'])) {
67 
68  $synchoffsetwarning .= '. This is a known problem with some versions of LAME (3.90 - 3.92) DLL in CBR mode.';
69  $info['audio']['codec'] = 'LAME';
70  $CurrentDataLAMEversionString = 'LAME3.';
71 
72  }
73 
74  }
75  $this->warning($synchoffsetwarning);
76 
77  }
78 
79  if (isset($info['mpeg']['audio']['LAME'])) {
80  $info['audio']['codec'] = 'LAME';
81  if (!empty($info['mpeg']['audio']['LAME']['long_version'])) {
82  $info['audio']['encoder'] = rtrim($info['mpeg']['audio']['LAME']['long_version'], "\x00");
83  } elseif (!empty($info['mpeg']['audio']['LAME']['short_version'])) {
84  $info['audio']['encoder'] = rtrim($info['mpeg']['audio']['LAME']['short_version'], "\x00");
85  }
86  }
87 
88  $CurrentDataLAMEversionString = (!empty($CurrentDataLAMEversionString) ? $CurrentDataLAMEversionString : (isset($info['audio']['encoder']) ? $info['audio']['encoder'] : ''));
89  if (!empty($CurrentDataLAMEversionString) && (substr($CurrentDataLAMEversionString, 0, 6) == 'LAME3.') && !preg_match('[0-9\)]', substr($CurrentDataLAMEversionString, -1))) {
90  // a version number of LAME that does not end with a number like "LAME3.92"
91  // or with a closing parenthesis like "LAME3.88 (alpha)"
92  // or a version of LAME with the LAMEtag-not-filled-in-DLL-mode bug (3.90-3.92)
93 
94  // not sure what the actual last frame length will be, but will be less than or equal to 1441
95  $PossiblyLongerLAMEversion_FrameLength = 1441;
96 
97  // Not sure what version of LAME this is - look in padding of last frame for longer version string
98  $PossibleLAMEversionStringOffset = $info['avdataend'] - $PossiblyLongerLAMEversion_FrameLength;
99  $this->fseek($PossibleLAMEversionStringOffset);
100  $PossiblyLongerLAMEversion_Data = $this->fread($PossiblyLongerLAMEversion_FrameLength);
101  switch (substr($CurrentDataLAMEversionString, -1)) {
102  case 'a':
103  case 'b':
104  // "LAME3.94a" will have a longer version string of "LAME3.94 (alpha)" for example
105  // need to trim off "a" to match longer string
106  $CurrentDataLAMEversionString = substr($CurrentDataLAMEversionString, 0, -1);
107  break;
108  }
109  if (($PossiblyLongerLAMEversion_String = strstr($PossiblyLongerLAMEversion_Data, $CurrentDataLAMEversionString)) !== false) {
110  if (substr($PossiblyLongerLAMEversion_String, 0, strlen($CurrentDataLAMEversionString)) == $CurrentDataLAMEversionString) {
111  $PossiblyLongerLAMEversion_NewString = substr($PossiblyLongerLAMEversion_String, 0, strspn($PossiblyLongerLAMEversion_String, 'LAME0123456789., (abcdefghijklmnopqrstuvwxyzJFSOND)')); //"LAME3.90.3" "LAME3.87 (beta 1, Sep 27 2000)" "LAME3.88 (beta)"
112  if (empty($info['audio']['encoder']) || (strlen($PossiblyLongerLAMEversion_NewString) > strlen($info['audio']['encoder']))) {
113  $info['audio']['encoder'] = $PossiblyLongerLAMEversion_NewString;
114  }
115  }
116  }
117  }
118  if (!empty($info['audio']['encoder'])) {
119  $info['audio']['encoder'] = rtrim($info['audio']['encoder'], "\x00 ");
120  }
121 
122  switch (isset($info['mpeg']['audio']['layer']) ? $info['mpeg']['audio']['layer'] : '') {
123  case 1:
124  case 2:
125  $info['audio']['dataformat'] = 'mp'.$info['mpeg']['audio']['layer'];
126  break;
127  }
128  if (isset($info['fileformat']) && ($info['fileformat'] == 'mp3')) {
129  switch ($info['audio']['dataformat']) {
130  case 'mp1':
131  case 'mp2':
132  case 'mp3':
133  $info['fileformat'] = $info['audio']['dataformat'];
134  break;
135 
136  default:
137  $this->warning('Expecting [audio][dataformat] to be mp1/mp2/mp3 when fileformat == mp3, [audio][dataformat] actually "'.$info['audio']['dataformat'].'"');
138  break;
139  }
140  }
141 
142  if (empty($info['fileformat'])) {
143  unset($info['fileformat']);
144  unset($info['audio']['bitrate_mode']);
145  unset($info['avdataoffset']);
146  unset($info['avdataend']);
147  return false;
148  }
149 
150  $info['mime_type'] = 'audio/mpeg';
151  $info['audio']['lossless'] = false;
152 
153  // Calculate playtime
154  if (!isset($info['playtime_seconds']) && isset($info['audio']['bitrate']) && ($info['audio']['bitrate'] > 0)) {
155  $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['audio']['bitrate'];
156  }
157 
158  $info['audio']['encoder_options'] = $this->GuessEncoderOptions();
159 
160  return true;
161  }
error($text)
Definition: getid3.php:1752
warning($text)
Definition: getid3.php:1758
getOnlyMPEGaudioInfo($avdataoffset, $BitrateHistogram=false)
fread($bytes)
Definition: getid3.php:1683
fseek($bytes, $whence=SEEK_SET)
Definition: getid3.php:1711
$info
Definition: index.php:5
getOnlyMPEGaudioInfoBruteForce()
+ Here is the call graph for this function:

◆ ClosestStandardMP3Bitrate()

static getid3_mp3::ClosestStandardMP3Bitrate (   $bit_rate)
static

Definition at line 1873 of file module.audio.mp3.php.

1873  {
1874  static $standard_bit_rates = array (320000, 256000, 224000, 192000, 160000, 128000, 112000, 96000, 80000, 64000, 56000, 48000, 40000, 32000, 24000, 16000, 8000);
1875  static $bit_rate_table = array (0=>'-');
1876  $round_bit_rate = intval(round($bit_rate, -3));
1877  if (!isset($bit_rate_table[$round_bit_rate])) {
1878  if ($round_bit_rate > max($standard_bit_rates)) {
1879  $bit_rate_table[$round_bit_rate] = round($bit_rate, 2 - strlen($bit_rate));
1880  } else {
1881  $bit_rate_table[$round_bit_rate] = max($standard_bit_rates);
1882  foreach ($standard_bit_rates as $standard_bit_rate) {
1883  if ($round_bit_rate >= $standard_bit_rate + (($bit_rate_table[$round_bit_rate] - $standard_bit_rate) / 2)) {
1884  break;
1885  }
1886  $bit_rate_table[$round_bit_rate] = $standard_bit_rate;
1887  }
1888  }
1889  }
1890  return $bit_rate_table[$round_bit_rate];
1891  }

◆ decodeMPEGaudioHeader()

getid3_mp3::decodeMPEGaudioHeader (   $offset,
$info,
  $recursivesearch = true,
  $ScanAsCBR = false,
  $FastMPEGheaderScan = false 
)

Definition at line 408 of file module.audio.mp3.php.

References $i, $info, getid3_lib\BigEndian2Int(), getid3_handler\error(), getid3_handler\fread(), FreeFormatFrameLength(), getid3_handler\fseek(), getid3_handler\isDependencyFor(), getid3_lib\LittleEndian2Float(), getid3_lib\PrintHexBytes(), RecursiveFrameScanning(), getid3_lib\RGADadjustmentLookup(), getid3_lib\RGADamplitude2dB(), getid3_lib\RGADnameLookup(), getid3_lib\RGADoriginatorLookup(), and getid3_handler\warning().

Referenced by getOnlyMPEGaudioInfo(), and RecursiveFrameScanning().

408  {
409  static $MPEGaudioVersionLookup;
410  static $MPEGaudioLayerLookup;
411  static $MPEGaudioBitrateLookup;
412  static $MPEGaudioFrequencyLookup;
413  static $MPEGaudioChannelModeLookup;
414  static $MPEGaudioModeExtensionLookup;
415  static $MPEGaudioEmphasisLookup;
416  if (empty($MPEGaudioVersionLookup)) {
417  $MPEGaudioVersionLookup = self::MPEGaudioVersionArray();
418  $MPEGaudioLayerLookup = self::MPEGaudioLayerArray();
419  $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray();
420  $MPEGaudioFrequencyLookup = self::MPEGaudioFrequencyArray();
421  $MPEGaudioChannelModeLookup = self::MPEGaudioChannelModeArray();
422  $MPEGaudioModeExtensionLookup = self::MPEGaudioModeExtensionArray();
423  $MPEGaudioEmphasisLookup = self::MPEGaudioEmphasisArray();
424  }
425 
426  if ($this->fseek($offset) != 0) {
427  $this->error('decodeMPEGaudioHeader() failed to seek to next offset at '.$offset);
428  return false;
429  }
430  //$headerstring = $this->fread(1441); // worst-case max length = 32kHz @ 320kbps layer 3 = 1441 bytes/frame
431  $headerstring = $this->fread(226); // LAME header at offset 36 + 190 bytes of Xing/LAME data
432 
433  // MP3 audio frame structure:
434  // $aa $aa $aa $aa [$bb $bb] $cc...
435  // where $aa..$aa is the four-byte mpeg-audio header (below)
436  // $bb $bb is the optional 2-byte CRC
437  // and $cc... is the audio data
438 
439  $head4 = substr($headerstring, 0, 4);
440  static $MPEGaudioHeaderDecodeCache = array();
441  if (isset($MPEGaudioHeaderDecodeCache[$head4])) {
442  $MPEGheaderRawArray = $MPEGaudioHeaderDecodeCache[$head4];
443  } else {
444  $MPEGheaderRawArray = self::MPEGaudioHeaderDecode($head4);
445  $MPEGaudioHeaderDecodeCache[$head4] = $MPEGheaderRawArray;
446  }
447 
448  static $MPEGaudioHeaderValidCache = array();
449  if (!isset($MPEGaudioHeaderValidCache[$head4])) { // Not in cache
450  //$MPEGaudioHeaderValidCache[$head4] = self::MPEGaudioHeaderValid($MPEGheaderRawArray, false, true); // allow badly-formatted freeformat (from LAME 3.90 - 3.93.1)
451  $MPEGaudioHeaderValidCache[$head4] = self::MPEGaudioHeaderValid($MPEGheaderRawArray, false, false);
452  }
453 
454  // shortcut
455  if (!isset($info['mpeg']['audio'])) {
456  $info['mpeg']['audio'] = array();
457  }
458  $thisfile_mpeg_audio = &$info['mpeg']['audio'];
459 
460 
461  if ($MPEGaudioHeaderValidCache[$head4]) {
462  $thisfile_mpeg_audio['raw'] = $MPEGheaderRawArray;
463  } else {
464  $this->error('Invalid MPEG audio header ('.getid3_lib::PrintHexBytes($head4).') at offset '.$offset);
465  return false;
466  }
467 
468  if (!$FastMPEGheaderScan) {
469  $thisfile_mpeg_audio['version'] = $MPEGaudioVersionLookup[$thisfile_mpeg_audio['raw']['version']];
470  $thisfile_mpeg_audio['layer'] = $MPEGaudioLayerLookup[$thisfile_mpeg_audio['raw']['layer']];
471 
472  $thisfile_mpeg_audio['channelmode'] = $MPEGaudioChannelModeLookup[$thisfile_mpeg_audio['raw']['channelmode']];
473  $thisfile_mpeg_audio['channels'] = (($thisfile_mpeg_audio['channelmode'] == 'mono') ? 1 : 2);
474  $thisfile_mpeg_audio['sample_rate'] = $MPEGaudioFrequencyLookup[$thisfile_mpeg_audio['version']][$thisfile_mpeg_audio['raw']['sample_rate']];
475  $thisfile_mpeg_audio['protection'] = !$thisfile_mpeg_audio['raw']['protection'];
476  $thisfile_mpeg_audio['private'] = (bool) $thisfile_mpeg_audio['raw']['private'];
477  $thisfile_mpeg_audio['modeextension'] = $MPEGaudioModeExtensionLookup[$thisfile_mpeg_audio['layer']][$thisfile_mpeg_audio['raw']['modeextension']];
478  $thisfile_mpeg_audio['copyright'] = (bool) $thisfile_mpeg_audio['raw']['copyright'];
479  $thisfile_mpeg_audio['original'] = (bool) $thisfile_mpeg_audio['raw']['original'];
480  $thisfile_mpeg_audio['emphasis'] = $MPEGaudioEmphasisLookup[$thisfile_mpeg_audio['raw']['emphasis']];
481 
482  $info['audio']['channels'] = $thisfile_mpeg_audio['channels'];
483  $info['audio']['sample_rate'] = $thisfile_mpeg_audio['sample_rate'];
484 
485  if ($thisfile_mpeg_audio['protection']) {
486  $thisfile_mpeg_audio['crc'] = getid3_lib::BigEndian2Int(substr($headerstring, 4, 2));
487  }
488  }
489 
490  if ($thisfile_mpeg_audio['raw']['bitrate'] == 15) {
491  // http://www.hydrogenaudio.org/?act=ST&f=16&t=9682&st=0
492  $this->warning('Invalid bitrate index (15), this is a known bug in free-format MP3s encoded by LAME v3.90 - 3.93.1');
493  $thisfile_mpeg_audio['raw']['bitrate'] = 0;
494  }
495  $thisfile_mpeg_audio['padding'] = (bool) $thisfile_mpeg_audio['raw']['padding'];
496  $thisfile_mpeg_audio['bitrate'] = $MPEGaudioBitrateLookup[$thisfile_mpeg_audio['version']][$thisfile_mpeg_audio['layer']][$thisfile_mpeg_audio['raw']['bitrate']];
497 
498  if (($thisfile_mpeg_audio['bitrate'] == 'free') && ($offset == $info['avdataoffset'])) {
499  // only skip multiple frame check if free-format bitstream found at beginning of file
500  // otherwise is quite possibly simply corrupted data
501  $recursivesearch = false;
502  }
503 
504  // For Layer 2 there are some combinations of bitrate and mode which are not allowed.
505  if (!$FastMPEGheaderScan && ($thisfile_mpeg_audio['layer'] == '2')) {
506 
507  $info['audio']['dataformat'] = 'mp2';
508  switch ($thisfile_mpeg_audio['channelmode']) {
509 
510  case 'mono':
511  if (($thisfile_mpeg_audio['bitrate'] == 'free') || ($thisfile_mpeg_audio['bitrate'] <= 192000)) {
512  // these are ok
513  } else {
514  $this->error($thisfile_mpeg_audio['bitrate'].'kbps not allowed in Layer 2, '.$thisfile_mpeg_audio['channelmode'].'.');
515  return false;
516  }
517  break;
518 
519  case 'stereo':
520  case 'joint stereo':
521  case 'dual channel':
522  if (($thisfile_mpeg_audio['bitrate'] == 'free') || ($thisfile_mpeg_audio['bitrate'] == 64000) || ($thisfile_mpeg_audio['bitrate'] >= 96000)) {
523  // these are ok
524  } else {
525  $this->error(intval(round($thisfile_mpeg_audio['bitrate'] / 1000)).'kbps not allowed in Layer 2, '.$thisfile_mpeg_audio['channelmode'].'.');
526  return false;
527  }
528  break;
529 
530  }
531 
532  }
533 
534 
535  if ($info['audio']['sample_rate'] > 0) {
536  $thisfile_mpeg_audio['framelength'] = self::MPEGaudioFrameLength($thisfile_mpeg_audio['bitrate'], $thisfile_mpeg_audio['version'], $thisfile_mpeg_audio['layer'], (int) $thisfile_mpeg_audio['padding'], $info['audio']['sample_rate']);
537  }
538 
539  $nextframetestoffset = $offset + 1;
540  if ($thisfile_mpeg_audio['bitrate'] != 'free') {
541 
542  $info['audio']['bitrate'] = $thisfile_mpeg_audio['bitrate'];
543 
544  if (isset($thisfile_mpeg_audio['framelength'])) {
545  $nextframetestoffset = $offset + $thisfile_mpeg_audio['framelength'];
546  } else {
547  $this->error('Frame at offset('.$offset.') is has an invalid frame length.');
548  return false;
549  }
550 
551  }
552 
553  $ExpectedNumberOfAudioBytes = 0;
554 
556  // Variable-bitrate headers
557 
558  if (substr($headerstring, 4 + 32, 4) == 'VBRI') {
559  // Fraunhofer VBR header is hardcoded 'VBRI' at offset 0x24 (36)
560  // specs taken from http://minnie.tuhs.org/pipermail/mp3encoder/2001-January/001800.html
561 
562  $thisfile_mpeg_audio['bitrate_mode'] = 'vbr';
563  $thisfile_mpeg_audio['VBR_method'] = 'Fraunhofer';
564  $info['audio']['codec'] = 'Fraunhofer';
565 
566  $SideInfoData = substr($headerstring, 4 + 2, 32);
567 
568  $FraunhoferVBROffset = 36;
569 
570  $thisfile_mpeg_audio['VBR_encoder_version'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 4, 2)); // VbriVersion
571  $thisfile_mpeg_audio['VBR_encoder_delay'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 6, 2)); // VbriDelay
572  $thisfile_mpeg_audio['VBR_quality'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 8, 2)); // VbriQuality
573  $thisfile_mpeg_audio['VBR_bytes'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 10, 4)); // VbriStreamBytes
574  $thisfile_mpeg_audio['VBR_frames'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 14, 4)); // VbriStreamFrames
575  $thisfile_mpeg_audio['VBR_seek_offsets'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 18, 2)); // VbriTableSize
576  $thisfile_mpeg_audio['VBR_seek_scale'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 20, 2)); // VbriTableScale
577  $thisfile_mpeg_audio['VBR_entry_bytes'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 22, 2)); // VbriEntryBytes
578  $thisfile_mpeg_audio['VBR_entry_frames'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 24, 2)); // VbriEntryFrames
579 
580  $ExpectedNumberOfAudioBytes = $thisfile_mpeg_audio['VBR_bytes'];
581 
582  $previousbyteoffset = $offset;
583  for ($i = 0; $i < $thisfile_mpeg_audio['VBR_seek_offsets']; $i++) {
584  $Fraunhofer_OffsetN = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset, $thisfile_mpeg_audio['VBR_entry_bytes']));
585  $FraunhoferVBROffset += $thisfile_mpeg_audio['VBR_entry_bytes'];
586  $thisfile_mpeg_audio['VBR_offsets_relative'][$i] = ($Fraunhofer_OffsetN * $thisfile_mpeg_audio['VBR_seek_scale']);
587  $thisfile_mpeg_audio['VBR_offsets_absolute'][$i] = ($Fraunhofer_OffsetN * $thisfile_mpeg_audio['VBR_seek_scale']) + $previousbyteoffset;
588  $previousbyteoffset += $Fraunhofer_OffsetN;
589  }
590 
591 
592  } else {
593 
594  // Xing VBR header is hardcoded 'Xing' at a offset 0x0D (13), 0x15 (21) or 0x24 (36)
595  // depending on MPEG layer and number of channels
596 
597  $VBRidOffset = self::XingVBRidOffset($thisfile_mpeg_audio['version'], $thisfile_mpeg_audio['channelmode']);
598  $SideInfoData = substr($headerstring, 4 + 2, $VBRidOffset - 4);
599 
600  if ((substr($headerstring, $VBRidOffset, strlen('Xing')) == 'Xing') || (substr($headerstring, $VBRidOffset, strlen('Info')) == 'Info')) {
601  // 'Xing' is traditional Xing VBR frame
602  // 'Info' is LAME-encoded CBR (This was done to avoid CBR files to be recognized as traditional Xing VBR files by some decoders.)
603  // 'Info' *can* legally be used to specify a VBR file as well, however.
604 
605  // http://www.multiweb.cz/twoinches/MP3inside.htm
606  //00..03 = "Xing" or "Info"
607  //04..07 = Flags:
608  // 0x01 Frames Flag set if value for number of frames in file is stored
609  // 0x02 Bytes Flag set if value for filesize in bytes is stored
610  // 0x04 TOC Flag set if values for TOC are stored
611  // 0x08 VBR Scale Flag set if values for VBR scale is stored
612  //08..11 Frames: Number of frames in file (including the first Xing/Info one)
613  //12..15 Bytes: File length in Bytes
614  //16..115 TOC (Table of Contents):
615  // Contains of 100 indexes (one Byte length) for easier lookup in file. Approximately solves problem with moving inside file.
616  // Each Byte has a value according this formula:
617  // (TOC[i] / 256) * fileLenInBytes
618  // So if song lasts eg. 240 sec. and you want to jump to 60. sec. (and file is 5 000 000 Bytes length) you can use:
619  // TOC[(60/240)*100] = TOC[25]
620  // and corresponding Byte in file is then approximately at:
621  // (TOC[25]/256) * 5000000
622  //116..119 VBR Scale
623 
624 
625  // should be safe to leave this at 'vbr' and let it be overriden to 'cbr' if a CBR preset/mode is used by LAME
626 // if (substr($headerstring, $VBRidOffset, strlen('Info')) == 'Xing') {
627  $thisfile_mpeg_audio['bitrate_mode'] = 'vbr';
628  $thisfile_mpeg_audio['VBR_method'] = 'Xing';
629 // } else {
630 // $ScanAsCBR = true;
631 // $thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
632 // }
633 
634  $thisfile_mpeg_audio['xing_flags_raw'] = getid3_lib::BigEndian2Int(substr($headerstring, $VBRidOffset + 4, 4));
635 
636  $thisfile_mpeg_audio['xing_flags']['frames'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000001);
637  $thisfile_mpeg_audio['xing_flags']['bytes'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000002);
638  $thisfile_mpeg_audio['xing_flags']['toc'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000004);
639  $thisfile_mpeg_audio['xing_flags']['vbr_scale'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000008);
640 
641  if ($thisfile_mpeg_audio['xing_flags']['frames']) {
642  $thisfile_mpeg_audio['VBR_frames'] = getid3_lib::BigEndian2Int(substr($headerstring, $VBRidOffset + 8, 4));
643  //$thisfile_mpeg_audio['VBR_frames']--; // don't count header Xing/Info frame
644  }
645  if ($thisfile_mpeg_audio['xing_flags']['bytes']) {
646  $thisfile_mpeg_audio['VBR_bytes'] = getid3_lib::BigEndian2Int(substr($headerstring, $VBRidOffset + 12, 4));
647  }
648 
649  //if (($thisfile_mpeg_audio['bitrate'] == 'free') && !empty($thisfile_mpeg_audio['VBR_frames']) && !empty($thisfile_mpeg_audio['VBR_bytes'])) {
650  //if (!empty($thisfile_mpeg_audio['VBR_frames']) && !empty($thisfile_mpeg_audio['VBR_bytes'])) {
651  if (!empty($thisfile_mpeg_audio['VBR_frames'])) {
652  $used_filesize = 0;
653  if (!empty($thisfile_mpeg_audio['VBR_bytes'])) {
654  $used_filesize = $thisfile_mpeg_audio['VBR_bytes'];
655  } elseif (!empty($info['filesize'])) {
656  $used_filesize = $info['filesize'];
657  $used_filesize -= intval(@$info['id3v2']['headerlength']);
658  $used_filesize -= (isset($info['id3v1']) ? 128 : 0);
659  $used_filesize -= (isset($info['tag_offset_end']) ? $info['tag_offset_end'] - $info['tag_offset_start'] : 0);
660  $this->warning('MP3.Xing header missing VBR_bytes, assuming MPEG audio portion of file is '.number_format($used_filesize).' bytes');
661  }
662 
663  $framelengthfloat = $used_filesize / $thisfile_mpeg_audio['VBR_frames'];
664 
665  if ($thisfile_mpeg_audio['layer'] == '1') {
666  // BitRate = (((FrameLengthInBytes / 4) - Padding) * SampleRate) / 12
667  //$info['audio']['bitrate'] = ((($framelengthfloat / 4) - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 12;
668  $info['audio']['bitrate'] = ($framelengthfloat / 4) * $thisfile_mpeg_audio['sample_rate'] * (2 / $info['audio']['channels']) / 12;
669  } else {
670  // Bitrate = ((FrameLengthInBytes - Padding) * SampleRate) / 144
671  //$info['audio']['bitrate'] = (($framelengthfloat - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 144;
672  $info['audio']['bitrate'] = $framelengthfloat * $thisfile_mpeg_audio['sample_rate'] * (2 / $info['audio']['channels']) / 144;
673  }
674  $thisfile_mpeg_audio['framelength'] = floor($framelengthfloat);
675  }
676 
677  if ($thisfile_mpeg_audio['xing_flags']['toc']) {
678  $LAMEtocData = substr($headerstring, $VBRidOffset + 16, 100);
679  for ($i = 0; $i < 100; $i++) {
680  $thisfile_mpeg_audio['toc'][$i] = ord($LAMEtocData{$i});
681  }
682  }
683  if ($thisfile_mpeg_audio['xing_flags']['vbr_scale']) {
684  $thisfile_mpeg_audio['VBR_scale'] = getid3_lib::BigEndian2Int(substr($headerstring, $VBRidOffset + 116, 4));
685  }
686 
687 
688  // http://gabriel.mp3-tech.org/mp3infotag.html
689  if (substr($headerstring, $VBRidOffset + 120, 4) == 'LAME') {
690 
691  // shortcut
692  $thisfile_mpeg_audio['LAME'] = array();
693  $thisfile_mpeg_audio_lame = &$thisfile_mpeg_audio['LAME'];
694 
695 
696  $thisfile_mpeg_audio_lame['long_version'] = substr($headerstring, $VBRidOffset + 120, 20);
697  $thisfile_mpeg_audio_lame['short_version'] = substr($thisfile_mpeg_audio_lame['long_version'], 0, 9);
698 
699  if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.90') {
700 
701  // extra 11 chars are not part of version string when LAMEtag present
702  unset($thisfile_mpeg_audio_lame['long_version']);
703 
704  // It the LAME tag was only introduced in LAME v3.90
705  // http://www.hydrogenaudio.org/?act=ST&f=15&t=9933
706 
707  // Offsets of various bytes in http://gabriel.mp3-tech.org/mp3infotag.html
708  // are assuming a 'Xing' identifier offset of 0x24, which is the case for
709  // MPEG-1 non-mono, but not for other combinations
710  $LAMEtagOffsetContant = $VBRidOffset - 0x24;
711 
712  // shortcuts
713  $thisfile_mpeg_audio_lame['RGAD'] = array('track'=>array(), 'album'=>array());
714  $thisfile_mpeg_audio_lame_RGAD = &$thisfile_mpeg_audio_lame['RGAD'];
715  $thisfile_mpeg_audio_lame_RGAD_track = &$thisfile_mpeg_audio_lame_RGAD['track'];
716  $thisfile_mpeg_audio_lame_RGAD_album = &$thisfile_mpeg_audio_lame_RGAD['album'];
717  $thisfile_mpeg_audio_lame['raw'] = array();
718  $thisfile_mpeg_audio_lame_raw = &$thisfile_mpeg_audio_lame['raw'];
719 
720  // byte $9B VBR Quality
721  // This field is there to indicate a quality level, although the scale was not precised in the original Xing specifications.
722  // Actually overwrites original Xing bytes
723  unset($thisfile_mpeg_audio['VBR_scale']);
724  $thisfile_mpeg_audio_lame['vbr_quality'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0x9B, 1));
725 
726  // bytes $9C-$A4 Encoder short VersionString
727  $thisfile_mpeg_audio_lame['short_version'] = substr($headerstring, $LAMEtagOffsetContant + 0x9C, 9);
728 
729  // byte $A5 Info Tag revision + VBR method
730  $LAMEtagRevisionVBRmethod = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA5, 1));
731 
732  $thisfile_mpeg_audio_lame['tag_revision'] = ($LAMEtagRevisionVBRmethod & 0xF0) >> 4;
733  $thisfile_mpeg_audio_lame_raw['vbr_method'] = $LAMEtagRevisionVBRmethod & 0x0F;
734  $thisfile_mpeg_audio_lame['vbr_method'] = self::LAMEvbrMethodLookup($thisfile_mpeg_audio_lame_raw['vbr_method']);
735  $thisfile_mpeg_audio['bitrate_mode'] = substr($thisfile_mpeg_audio_lame['vbr_method'], 0, 3); // usually either 'cbr' or 'vbr', but truncates 'vbr-old / vbr-rh' to 'vbr'
736 
737  // byte $A6 Lowpass filter value
738  $thisfile_mpeg_audio_lame['lowpass_frequency'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA6, 1)) * 100;
739 
740  // bytes $A7-$AE Replay Gain
741  // http://privatewww.essex.ac.uk/~djmrob/replaygain/rg_data_format.html
742  // bytes $A7-$AA : 32 bit floating point "Peak signal amplitude"
743  if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.94b') {
744  // LAME 3.94a16 and later - 9.23 fixed point
745  // ie 0x0059E2EE / (2^23) = 5890798 / 8388608 = 0.7022378444671630859375
746  $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = (float) ((getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4))) / 8388608);
747  } else {
748  // LAME 3.94a15 and earlier - 32-bit floating point
749  // Actually 3.94a16 will fall in here too and be WRONG, but is hard to detect 3.94a16 vs 3.94a15
750  $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = getid3_lib::LittleEndian2Float(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4));
751  }
752  if ($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] == 0) {
753  unset($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']);
754  } else {
755  $thisfile_mpeg_audio_lame_RGAD['peak_db'] = getid3_lib::RGADamplitude2dB($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']);
756  }
757 
758  $thisfile_mpeg_audio_lame_raw['RGAD_track'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAB, 2));
759  $thisfile_mpeg_audio_lame_raw['RGAD_album'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAD, 2));
760 
761 
762  if ($thisfile_mpeg_audio_lame_raw['RGAD_track'] != 0) {
763 
764  $thisfile_mpeg_audio_lame_RGAD_track['raw']['name'] = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0xE000) >> 13;
765  $thisfile_mpeg_audio_lame_RGAD_track['raw']['originator'] = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x1C00) >> 10;
766  $thisfile_mpeg_audio_lame_RGAD_track['raw']['sign_bit'] = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x0200) >> 9;
767  $thisfile_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'] = $thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x01FF;
768  $thisfile_mpeg_audio_lame_RGAD_track['name'] = getid3_lib::RGADnameLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['name']);
769  $thisfile_mpeg_audio_lame_RGAD_track['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['originator']);
770  $thisfile_mpeg_audio_lame_RGAD_track['gain_db'] = getid3_lib::RGADadjustmentLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_RGAD_track['raw']['sign_bit']);
771 
772  if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) {
773  $info['replay_gain']['track']['peak'] = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'];
774  }
775  $info['replay_gain']['track']['originator'] = $thisfile_mpeg_audio_lame_RGAD_track['originator'];
776  $info['replay_gain']['track']['adjustment'] = $thisfile_mpeg_audio_lame_RGAD_track['gain_db'];
777  } else {
778  unset($thisfile_mpeg_audio_lame_RGAD['track']);
779  }
780  if ($thisfile_mpeg_audio_lame_raw['RGAD_album'] != 0) {
781 
782  $thisfile_mpeg_audio_lame_RGAD_album['raw']['name'] = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0xE000) >> 13;
783  $thisfile_mpeg_audio_lame_RGAD_album['raw']['originator'] = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x1C00) >> 10;
784  $thisfile_mpeg_audio_lame_RGAD_album['raw']['sign_bit'] = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x0200) >> 9;
785  $thisfile_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'] = $thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x01FF;
786  $thisfile_mpeg_audio_lame_RGAD_album['name'] = getid3_lib::RGADnameLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['name']);
787  $thisfile_mpeg_audio_lame_RGAD_album['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['originator']);
788  $thisfile_mpeg_audio_lame_RGAD_album['gain_db'] = getid3_lib::RGADadjustmentLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_RGAD_album['raw']['sign_bit']);
789 
790  if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) {
791  $info['replay_gain']['album']['peak'] = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'];
792  }
793  $info['replay_gain']['album']['originator'] = $thisfile_mpeg_audio_lame_RGAD_album['originator'];
794  $info['replay_gain']['album']['adjustment'] = $thisfile_mpeg_audio_lame_RGAD_album['gain_db'];
795  } else {
796  unset($thisfile_mpeg_audio_lame_RGAD['album']);
797  }
798  if (empty($thisfile_mpeg_audio_lame_RGAD)) {
799  unset($thisfile_mpeg_audio_lame['RGAD']);
800  }
801 
802 
803  // byte $AF Encoding flags + ATH Type
804  $EncodingFlagsATHtype = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAF, 1));
805  $thisfile_mpeg_audio_lame['encoding_flags']['nspsytune'] = (bool) ($EncodingFlagsATHtype & 0x10);
806  $thisfile_mpeg_audio_lame['encoding_flags']['nssafejoint'] = (bool) ($EncodingFlagsATHtype & 0x20);
807  $thisfile_mpeg_audio_lame['encoding_flags']['nogap_next'] = (bool) ($EncodingFlagsATHtype & 0x40);
808  $thisfile_mpeg_audio_lame['encoding_flags']['nogap_prev'] = (bool) ($EncodingFlagsATHtype & 0x80);
809  $thisfile_mpeg_audio_lame['ath_type'] = $EncodingFlagsATHtype & 0x0F;
810 
811  // byte $B0 if ABR {specified bitrate} else {minimal bitrate}
812  $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB0, 1));
813  if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 2) { // Average BitRate (ABR)
814  $thisfile_mpeg_audio_lame['bitrate_abr'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'];
815  } elseif ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) { // Constant BitRate (CBR)
816  // ignore
817  } elseif ($thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] > 0) { // Variable BitRate (VBR) - minimum bitrate
818  $thisfile_mpeg_audio_lame['bitrate_min'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'];
819  }
820 
821  // bytes $B1-$B3 Encoder delays
822  $EncoderDelays = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB1, 3));
823  $thisfile_mpeg_audio_lame['encoder_delay'] = ($EncoderDelays & 0xFFF000) >> 12;
824  $thisfile_mpeg_audio_lame['end_padding'] = $EncoderDelays & 0x000FFF;
825 
826  // byte $B4 Misc
827  $MiscByte = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB4, 1));
828  $thisfile_mpeg_audio_lame_raw['noise_shaping'] = ($MiscByte & 0x03);
829  $thisfile_mpeg_audio_lame_raw['stereo_mode'] = ($MiscByte & 0x1C) >> 2;
830  $thisfile_mpeg_audio_lame_raw['not_optimal_quality'] = ($MiscByte & 0x20) >> 5;
831  $thisfile_mpeg_audio_lame_raw['source_sample_freq'] = ($MiscByte & 0xC0) >> 6;
832  $thisfile_mpeg_audio_lame['noise_shaping'] = $thisfile_mpeg_audio_lame_raw['noise_shaping'];
833  $thisfile_mpeg_audio_lame['stereo_mode'] = self::LAMEmiscStereoModeLookup($thisfile_mpeg_audio_lame_raw['stereo_mode']);
834  $thisfile_mpeg_audio_lame['not_optimal_quality'] = (bool) $thisfile_mpeg_audio_lame_raw['not_optimal_quality'];
835  $thisfile_mpeg_audio_lame['source_sample_freq'] = self::LAMEmiscSourceSampleFrequencyLookup($thisfile_mpeg_audio_lame_raw['source_sample_freq']);
836 
837  // byte $B5 MP3 Gain
838  $thisfile_mpeg_audio_lame_raw['mp3_gain'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB5, 1), false, true);
839  $thisfile_mpeg_audio_lame['mp3_gain_db'] = (getid3_lib::RGADamplitude2dB(2) / 4) * $thisfile_mpeg_audio_lame_raw['mp3_gain'];
840  $thisfile_mpeg_audio_lame['mp3_gain_factor'] = pow(2, ($thisfile_mpeg_audio_lame['mp3_gain_db'] / 6));
841 
842  // bytes $B6-$B7 Preset and surround info
843  $PresetSurroundBytes = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB6, 2));
844  // Reserved = ($PresetSurroundBytes & 0xC000);
845  $thisfile_mpeg_audio_lame_raw['surround_info'] = ($PresetSurroundBytes & 0x3800);
846  $thisfile_mpeg_audio_lame['surround_info'] = self::LAMEsurroundInfoLookup($thisfile_mpeg_audio_lame_raw['surround_info']);
847  $thisfile_mpeg_audio_lame['preset_used_id'] = ($PresetSurroundBytes & 0x07FF);
848  $thisfile_mpeg_audio_lame['preset_used'] = self::LAMEpresetUsedLookup($thisfile_mpeg_audio_lame);
849  if (!empty($thisfile_mpeg_audio_lame['preset_used_id']) && empty($thisfile_mpeg_audio_lame['preset_used'])) {
850  $this->warning('Unknown LAME preset used ('.$thisfile_mpeg_audio_lame['preset_used_id'].') - please report to info@getid3.org');
851  }
852  if (($thisfile_mpeg_audio_lame['short_version'] == 'LAME3.90.') && !empty($thisfile_mpeg_audio_lame['preset_used_id'])) {
853  // this may change if 3.90.4 ever comes out
854  $thisfile_mpeg_audio_lame['short_version'] = 'LAME3.90.3';
855  }
856 
857  // bytes $B8-$BB MusicLength
858  $thisfile_mpeg_audio_lame['audio_bytes'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB8, 4));
859  $ExpectedNumberOfAudioBytes = (($thisfile_mpeg_audio_lame['audio_bytes'] > 0) ? $thisfile_mpeg_audio_lame['audio_bytes'] : $thisfile_mpeg_audio['VBR_bytes']);
860 
861  // bytes $BC-$BD MusicCRC
862  $thisfile_mpeg_audio_lame['music_crc'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBC, 2));
863 
864  // bytes $BE-$BF CRC-16 of Info Tag
865  $thisfile_mpeg_audio_lame['lame_tag_crc'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBE, 2));
866 
867 
868  // LAME CBR
869  if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) {
870 
871  $thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
872  $thisfile_mpeg_audio['bitrate'] = self::ClosestStandardMP3Bitrate($thisfile_mpeg_audio['bitrate']);
873  $info['audio']['bitrate'] = $thisfile_mpeg_audio['bitrate'];
874  //if (empty($thisfile_mpeg_audio['bitrate']) || (!empty($thisfile_mpeg_audio_lame['bitrate_min']) && ($thisfile_mpeg_audio_lame['bitrate_min'] != 255))) {
875  // $thisfile_mpeg_audio['bitrate'] = $thisfile_mpeg_audio_lame['bitrate_min'];
876  //}
877 
878  }
879 
880  }
881  }
882 
883  } else {
884 
885  // not Fraunhofer or Xing VBR methods, most likely CBR (but could be VBR with no header)
886  $thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
887  if ($recursivesearch) {
888  $thisfile_mpeg_audio['bitrate_mode'] = 'vbr';
889  if ($this->RecursiveFrameScanning($offset, $nextframetestoffset, true)) {
890  $recursivesearch = false;
891  $thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
892  }
893  if ($thisfile_mpeg_audio['bitrate_mode'] == 'vbr') {
894  $this->warning('VBR file with no VBR header. Bitrate values calculated from actual frame bitrates.');
895  }
896  }
897 
898  }
899 
900  }
901 
902  if (($ExpectedNumberOfAudioBytes > 0) && ($ExpectedNumberOfAudioBytes != ($info['avdataend'] - $info['avdataoffset']))) {
903  if ($ExpectedNumberOfAudioBytes > ($info['avdataend'] - $info['avdataoffset'])) {
904  if ($this->isDependencyFor('matroska') || $this->isDependencyFor('riff')) {
905  // ignore, audio data is broken into chunks so will always be data "missing"
906  }
907  elseif (($ExpectedNumberOfAudioBytes - ($info['avdataend'] - $info['avdataoffset'])) == 1) {
908  $this->warning('Last byte of data truncated (this is a known bug in Meracl ID3 Tag Writer before v1.3.5)');
909  }
910  else {
911  $this->warning('Probable truncated file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, only found '.($info['avdataend'] - $info['avdataoffset']).' (short by '.($ExpectedNumberOfAudioBytes - ($info['avdataend'] - $info['avdataoffset'])).' bytes)');
912  }
913  } else {
914  if ((($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes) == 1) {
915  // $prenullbytefileoffset = $this->ftell();
916  // $this->fseek($info['avdataend']);
917  // $PossibleNullByte = $this->fread(1);
918  // $this->fseek($prenullbytefileoffset);
919  // if ($PossibleNullByte === "\x00") {
920  $info['avdataend']--;
921  // $this->warning('Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored');
922  // } else {
923  // $this->warning('Too much data in file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']).' ('.(($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes).' bytes too many)');
924  // }
925  } else {
926  $this->warning('Too much data in file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']).' ('.(($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes).' bytes too many)');
927  }
928  }
929  }
930 
931  if (($thisfile_mpeg_audio['bitrate'] == 'free') && empty($info['audio']['bitrate'])) {
932  if (($offset == $info['avdataoffset']) && empty($thisfile_mpeg_audio['VBR_frames'])) {
933  $framebytelength = $this->FreeFormatFrameLength($offset, true);
934  if ($framebytelength > 0) {
935  $thisfile_mpeg_audio['framelength'] = $framebytelength;
936  if ($thisfile_mpeg_audio['layer'] == '1') {
937  // BitRate = (((FrameLengthInBytes / 4) - Padding) * SampleRate) / 12
938  $info['audio']['bitrate'] = ((($framebytelength / 4) - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 12;
939  } else {
940  // Bitrate = ((FrameLengthInBytes - Padding) * SampleRate) / 144
941  $info['audio']['bitrate'] = (($framebytelength - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 144;
942  }
943  } else {
944  $this->error('Error calculating frame length of free-format MP3 without Xing/LAME header');
945  }
946  }
947  }
948 
949  if (isset($thisfile_mpeg_audio['VBR_frames']) ? $thisfile_mpeg_audio['VBR_frames'] : '') {
950  switch ($thisfile_mpeg_audio['bitrate_mode']) {
951  case 'vbr':
952  case 'abr':
953  $bytes_per_frame = 1152;
954  if (($thisfile_mpeg_audio['version'] == '1') && ($thisfile_mpeg_audio['layer'] == 1)) {
955  $bytes_per_frame = 384;
956  } elseif ((($thisfile_mpeg_audio['version'] == '2') || ($thisfile_mpeg_audio['version'] == '2.5')) && ($thisfile_mpeg_audio['layer'] == 3)) {
957  $bytes_per_frame = 576;
958  }
959  $thisfile_mpeg_audio['VBR_bitrate'] = (isset($thisfile_mpeg_audio['VBR_bytes']) ? (($thisfile_mpeg_audio['VBR_bytes'] / $thisfile_mpeg_audio['VBR_frames']) * 8) * ($info['audio']['sample_rate'] / $bytes_per_frame) : 0);
960  if ($thisfile_mpeg_audio['VBR_bitrate'] > 0) {
961  $info['audio']['bitrate'] = $thisfile_mpeg_audio['VBR_bitrate'];
962  $thisfile_mpeg_audio['bitrate'] = $thisfile_mpeg_audio['VBR_bitrate']; // to avoid confusion
963  }
964  break;
965  }
966  }
967 
968  // End variable-bitrate headers
970 
971  if ($recursivesearch) {
972 
973  if (!$this->RecursiveFrameScanning($offset, $nextframetestoffset, $ScanAsCBR)) {
974  return false;
975  }
976 
977  }
978 
979 
980  //if (false) {
981  // // experimental side info parsing section - not returning anything useful yet
982  //
983  // $SideInfoBitstream = getid3_lib::BigEndian2Bin($SideInfoData);
984  // $SideInfoOffset = 0;
985  //
986  // if ($thisfile_mpeg_audio['version'] == '1') {
987  // if ($thisfile_mpeg_audio['channelmode'] == 'mono') {
988  // // MPEG-1 (mono)
989  // $thisfile_mpeg_audio['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 9);
990  // $SideInfoOffset += 9;
991  // $SideInfoOffset += 5;
992  // } else {
993  // // MPEG-1 (stereo, joint-stereo, dual-channel)
994  // $thisfile_mpeg_audio['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 9);
995  // $SideInfoOffset += 9;
996  // $SideInfoOffset += 3;
997  // }
998  // } else { // 2 or 2.5
999  // if ($thisfile_mpeg_audio['channelmode'] == 'mono') {
1000  // // MPEG-2, MPEG-2.5 (mono)
1001  // $thisfile_mpeg_audio['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 8);
1002  // $SideInfoOffset += 8;
1003  // $SideInfoOffset += 1;
1004  // } else {
1005  // // MPEG-2, MPEG-2.5 (stereo, joint-stereo, dual-channel)
1006  // $thisfile_mpeg_audio['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 8);
1007  // $SideInfoOffset += 8;
1008  // $SideInfoOffset += 2;
1009  // }
1010  // }
1011  //
1012  // if ($thisfile_mpeg_audio['version'] == '1') {
1013  // for ($channel = 0; $channel < $info['audio']['channels']; $channel++) {
1014  // for ($scfsi_band = 0; $scfsi_band < 4; $scfsi_band++) {
1015  // $thisfile_mpeg_audio['scfsi'][$channel][$scfsi_band] = substr($SideInfoBitstream, $SideInfoOffset, 1);
1016  // $SideInfoOffset += 2;
1017  // }
1018  // }
1019  // }
1020  // for ($granule = 0; $granule < (($thisfile_mpeg_audio['version'] == '1') ? 2 : 1); $granule++) {
1021  // for ($channel = 0; $channel < $info['audio']['channels']; $channel++) {
1022  // $thisfile_mpeg_audio['part2_3_length'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 12);
1023  // $SideInfoOffset += 12;
1024  // $thisfile_mpeg_audio['big_values'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 9);
1025  // $SideInfoOffset += 9;
1026  // $thisfile_mpeg_audio['global_gain'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 8);
1027  // $SideInfoOffset += 8;
1028  // if ($thisfile_mpeg_audio['version'] == '1') {
1029  // $thisfile_mpeg_audio['scalefac_compress'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 4);
1030  // $SideInfoOffset += 4;
1031  // } else {
1032  // $thisfile_mpeg_audio['scalefac_compress'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 9);
1033  // $SideInfoOffset += 9;
1034  // }
1035  // $thisfile_mpeg_audio['window_switching_flag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
1036  // $SideInfoOffset += 1;
1037  //
1038  // if ($thisfile_mpeg_audio['window_switching_flag'][$granule][$channel] == '1') {
1039  //
1040  // $thisfile_mpeg_audio['block_type'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 2);
1041  // $SideInfoOffset += 2;
1042  // $thisfile_mpeg_audio['mixed_block_flag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
1043  // $SideInfoOffset += 1;
1044  //
1045  // for ($region = 0; $region < 2; $region++) {
1046  // $thisfile_mpeg_audio['table_select'][$granule][$channel][$region] = substr($SideInfoBitstream, $SideInfoOffset, 5);
1047  // $SideInfoOffset += 5;
1048  // }
1049  // $thisfile_mpeg_audio['table_select'][$granule][$channel][2] = 0;
1050  //
1051  // for ($window = 0; $window < 3; $window++) {
1052  // $thisfile_mpeg_audio['subblock_gain'][$granule][$channel][$window] = substr($SideInfoBitstream, $SideInfoOffset, 3);
1053  // $SideInfoOffset += 3;
1054  // }
1055  //
1056  // } else {
1057  //
1058  // for ($region = 0; $region < 3; $region++) {
1059  // $thisfile_mpeg_audio['table_select'][$granule][$channel][$region] = substr($SideInfoBitstream, $SideInfoOffset, 5);
1060  // $SideInfoOffset += 5;
1061  // }
1062  //
1063  // $thisfile_mpeg_audio['region0_count'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 4);
1064  // $SideInfoOffset += 4;
1065  // $thisfile_mpeg_audio['region1_count'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 3);
1066  // $SideInfoOffset += 3;
1067  // $thisfile_mpeg_audio['block_type'][$granule][$channel] = 0;
1068  // }
1069  //
1070  // if ($thisfile_mpeg_audio['version'] == '1') {
1071  // $thisfile_mpeg_audio['preflag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
1072  // $SideInfoOffset += 1;
1073  // }
1074  // $thisfile_mpeg_audio['scalefac_scale'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
1075  // $SideInfoOffset += 1;
1076  // $thisfile_mpeg_audio['count1table_select'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
1077  // $SideInfoOffset += 1;
1078  // }
1079  // }
1080  //}
1081 
1082  return true;
1083  }
isDependencyFor($module)
Definition: getid3.php:1748
error($text)
Definition: getid3.php:1752
static RGADnameLookup($namecode)
static RGADoriginatorLookup($originatorcode)
warning($text)
Definition: getid3.php:1758
static RGADamplitude2dB($amplitude)
FreeFormatFrameLength($offset, $deepscan=false)
static RGADadjustmentLookup($rawadjustment, $signbit)
static PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8')
Definition: getid3.lib.php:18
fread($bytes)
Definition: getid3.php:1683
static LittleEndian2Float($byteword)
Definition: getid3.lib.php:180
$i
Definition: disco.tpl.php:19
fseek($bytes, $whence=SEEK_SET)
Definition: getid3.php:1711
$info
Definition: index.php:5
RecursiveFrameScanning(&$offset, &$nextframetestoffset, $ScanAsCBR)
static BigEndian2Int($byteword, $synchsafe=false, $signed=false)
Definition: getid3.lib.php:263
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ FreeFormatFrameLength()

getid3_mp3::FreeFormatFrameLength (   $offset,
  $deepscan = false 
)

Definition at line 1131 of file module.audio.mp3.php.

References $info, getid3_handler\error(), getid3_handler\fread(), getid3_handler\fseek(), getid3_lib\PrintHexBytes(), and getid3_handler\warning().

Referenced by decodeMPEGaudioHeader().

1131  {
1132  $info = &$this->getid3->info;
1133 
1134  $this->fseek($offset);
1135  $MPEGaudioData = $this->fread(32768);
1136 
1137  $SyncPattern1 = substr($MPEGaudioData, 0, 4);
1138  // may be different pattern due to padding
1139  $SyncPattern2 = $SyncPattern1{0}.$SyncPattern1{1}.chr(ord($SyncPattern1{2}) | 0x02).$SyncPattern1{3};
1140  if ($SyncPattern2 === $SyncPattern1) {
1141  $SyncPattern2 = $SyncPattern1{0}.$SyncPattern1{1}.chr(ord($SyncPattern1{2}) & 0xFD).$SyncPattern1{3};
1142  }
1143 
1144  $framelength = false;
1145  $framelength1 = strpos($MPEGaudioData, $SyncPattern1, 4);
1146  $framelength2 = strpos($MPEGaudioData, $SyncPattern2, 4);
1147  if ($framelength1 > 4) {
1148  $framelength = $framelength1;
1149  }
1150  if (($framelength2 > 4) && ($framelength2 < $framelength1)) {
1151  $framelength = $framelength2;
1152  }
1153  if (!$framelength) {
1154 
1155  // LAME 3.88 has a different value for modeextension on the first frame vs the rest
1156  $framelength1 = strpos($MPEGaudioData, substr($SyncPattern1, 0, 3), 4);
1157  $framelength2 = strpos($MPEGaudioData, substr($SyncPattern2, 0, 3), 4);
1158 
1159  if ($framelength1 > 4) {
1160  $framelength = $framelength1;
1161  }
1162  if (($framelength2 > 4) && ($framelength2 < $framelength1)) {
1163  $framelength = $framelength2;
1164  }
1165  if (!$framelength) {
1166  $this->error('Cannot find next free-format synch pattern ('.getid3_lib::PrintHexBytes($SyncPattern1).' or '.getid3_lib::PrintHexBytes($SyncPattern2).') after offset '.$offset);
1167  return false;
1168  } else {
1169  $this->warning('ModeExtension varies between first frame and other frames (known free-format issue in LAME 3.88)');
1170  $info['audio']['codec'] = 'LAME';
1171  $info['audio']['encoder'] = 'LAME3.88';
1172  $SyncPattern1 = substr($SyncPattern1, 0, 3);
1173  $SyncPattern2 = substr($SyncPattern2, 0, 3);
1174  }
1175  }
1176 
1177  if ($deepscan) {
1178 
1179  $ActualFrameLengthValues = array();
1180  $nextoffset = $offset + $framelength;
1181  while ($nextoffset < ($info['avdataend'] - 6)) {
1182  $this->fseek($nextoffset - 1);
1183  $NextSyncPattern = $this->fread(6);
1184  if ((substr($NextSyncPattern, 1, strlen($SyncPattern1)) == $SyncPattern1) || (substr($NextSyncPattern, 1, strlen($SyncPattern2)) == $SyncPattern2)) {
1185  // good - found where expected
1186  $ActualFrameLengthValues[] = $framelength;
1187  } elseif ((substr($NextSyncPattern, 0, strlen($SyncPattern1)) == $SyncPattern1) || (substr($NextSyncPattern, 0, strlen($SyncPattern2)) == $SyncPattern2)) {
1188  // ok - found one byte earlier than expected (last frame wasn't padded, first frame was)
1189  $ActualFrameLengthValues[] = ($framelength - 1);
1190  $nextoffset--;
1191  } elseif ((substr($NextSyncPattern, 2, strlen($SyncPattern1)) == $SyncPattern1) || (substr($NextSyncPattern, 2, strlen($SyncPattern2)) == $SyncPattern2)) {
1192  // ok - found one byte later than expected (last frame was padded, first frame wasn't)
1193  $ActualFrameLengthValues[] = ($framelength + 1);
1194  $nextoffset++;
1195  } else {
1196  $this->error('Did not find expected free-format sync pattern at offset '.$nextoffset);
1197  return false;
1198  }
1199  $nextoffset += $framelength;
1200  }
1201  if (count($ActualFrameLengthValues) > 0) {
1202  $framelength = intval(round(array_sum($ActualFrameLengthValues) / count($ActualFrameLengthValues)));
1203  }
1204  }
1205  return $framelength;
1206  }
error($text)
Definition: getid3.php:1752
warning($text)
Definition: getid3.php:1758
static PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8')
Definition: getid3.lib.php:18
fread($bytes)
Definition: getid3.php:1683
fseek($bytes, $whence=SEEK_SET)
Definition: getid3.php:1711
$info
Definition: index.php:5
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getOnlyMPEGaudioInfo()

getid3_mp3::getOnlyMPEGaudioInfo (   $avdataoffset,
  $BitrateHistogram = false 
)

Definition at line 1356 of file module.audio.mp3.php.

References $header, $info, getid3_lib\CastAsInt(), decodeMPEGaudioHeader(), getid3_handler\error(), getid3_handler\feof(), getid3_handler\fread(), getid3_handler\fseek(), getid3_handler\ftell(), GETID3_MP3_VALID_CHECK_FRAMES, getid3_lib\safe_inc(), and getid3_handler\warning().

Referenced by Analyze().

1356  {
1357  // looks for synch, decodes MPEG audio header
1358 
1359  $info = &$this->getid3->info;
1360 
1361  static $MPEGaudioVersionLookup;
1362  static $MPEGaudioLayerLookup;
1363  static $MPEGaudioBitrateLookup;
1364  if (empty($MPEGaudioVersionLookup)) {
1365  $MPEGaudioVersionLookup = self::MPEGaudioVersionArray();
1366  $MPEGaudioLayerLookup = self::MPEGaudioLayerArray();
1367  $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray();
1368 
1369  }
1370 
1371  $this->fseek($avdataoffset);
1372  $sync_seek_buffer_size = min(128 * 1024, $info['avdataend'] - $avdataoffset);
1373  if ($sync_seek_buffer_size <= 0) {
1374  $this->error('Invalid $sync_seek_buffer_size at offset '.$avdataoffset);
1375  return false;
1376  }
1377  $header = $this->fread($sync_seek_buffer_size);
1378  $sync_seek_buffer_size = strlen($header);
1379  $SynchSeekOffset = 0;
1380  while ($SynchSeekOffset < $sync_seek_buffer_size) {
1381  if ((($avdataoffset + $SynchSeekOffset) < $info['avdataend']) && !feof($this->getid3->fp)) {
1382 
1383  if ($SynchSeekOffset > $sync_seek_buffer_size) {
1384  // if a synch's not found within the first 128k bytes, then give up
1385  $this->error('Could not find valid MPEG audio synch within the first '.round($sync_seek_buffer_size / 1024).'kB');
1386  if (isset($info['audio']['bitrate'])) {
1387  unset($info['audio']['bitrate']);
1388  }
1389  if (isset($info['mpeg']['audio'])) {
1390  unset($info['mpeg']['audio']);
1391  }
1392  if (empty($info['mpeg'])) {
1393  unset($info['mpeg']);
1394  }
1395  return false;
1396 
1397  } elseif (feof($this->getid3->fp)) {
1398 
1399  $this->error('Could not find valid MPEG audio synch before end of file');
1400  if (isset($info['audio']['bitrate'])) {
1401  unset($info['audio']['bitrate']);
1402  }
1403  if (isset($info['mpeg']['audio'])) {
1404  unset($info['mpeg']['audio']);
1405  }
1406  if (isset($info['mpeg']) && (!is_array($info['mpeg']) || (count($info['mpeg']) == 0))) {
1407  unset($info['mpeg']);
1408  }
1409  return false;
1410  }
1411  }
1412 
1413  if (($SynchSeekOffset + 1) >= strlen($header)) {
1414  $this->error('Could not find valid MPEG synch before end of file');
1415  return false;
1416  }
1417 
1418  if (($header{$SynchSeekOffset} == "\xFF") && ($header{($SynchSeekOffset + 1)} > "\xE0")) { // synch detected
1419  if (!isset($FirstFrameThisfileInfo) && !isset($info['mpeg']['audio'])) {
1420  $FirstFrameThisfileInfo = $info;
1421  $FirstFrameAVDataOffset = $avdataoffset + $SynchSeekOffset;
1422  if (!$this->decodeMPEGaudioHeader($FirstFrameAVDataOffset, $FirstFrameThisfileInfo, false)) {
1423  // if this is the first valid MPEG-audio frame, save it in case it's a VBR header frame and there's
1424  // garbage between this frame and a valid sequence of MPEG-audio frames, to be restored below
1425  unset($FirstFrameThisfileInfo);
1426  }
1427  }
1428 
1429  $dummy = $info; // only overwrite real data if valid header found
1430  if ($this->decodeMPEGaudioHeader($avdataoffset + $SynchSeekOffset, $dummy, true)) {
1431  $info = $dummy;
1432  $info['avdataoffset'] = $avdataoffset + $SynchSeekOffset;
1433  switch (isset($info['fileformat']) ? $info['fileformat'] : '') {
1434  case '':
1435  case 'id3':
1436  case 'ape':
1437  case 'mp3':
1438  $info['fileformat'] = 'mp3';
1439  $info['audio']['dataformat'] = 'mp3';
1440  break;
1441  }
1442  if (isset($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode']) && ($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode'] == 'vbr')) {
1443  if (!(abs($info['audio']['bitrate'] - $FirstFrameThisfileInfo['audio']['bitrate']) <= 1)) {
1444  // If there is garbage data between a valid VBR header frame and a sequence
1445  // of valid MPEG-audio frames the VBR data is no longer discarded.
1446  $info = $FirstFrameThisfileInfo;
1447  $info['avdataoffset'] = $FirstFrameAVDataOffset;
1448  $info['fileformat'] = 'mp3';
1449  $info['audio']['dataformat'] = 'mp3';
1450  $dummy = $info;
1451  unset($dummy['mpeg']['audio']);
1452  $GarbageOffsetStart = $FirstFrameAVDataOffset + $FirstFrameThisfileInfo['mpeg']['audio']['framelength'];
1453  $GarbageOffsetEnd = $avdataoffset + $SynchSeekOffset;
1454  if ($this->decodeMPEGaudioHeader($GarbageOffsetEnd, $dummy, true, true)) {
1455  $info = $dummy;
1456  $info['avdataoffset'] = $GarbageOffsetEnd;
1457  $this->warning('apparently-valid VBR header not used because could not find '.GETID3_MP3_VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.'), but did find valid CBR stream starting at '.$GarbageOffsetEnd);
1458  } else {
1459  $this->warning('using data from VBR header even though could not find '.GETID3_MP3_VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.')');
1460  }
1461  }
1462  }
1463  if (isset($info['mpeg']['audio']['bitrate_mode']) && ($info['mpeg']['audio']['bitrate_mode'] == 'vbr') && !isset($info['mpeg']['audio']['VBR_method'])) {
1464  // VBR file with no VBR header
1465  $BitrateHistogram = true;
1466  }
1467 
1468  if ($BitrateHistogram) {
1469 
1470  $info['mpeg']['audio']['stereo_distribution'] = array('stereo'=>0, 'joint stereo'=>0, 'dual channel'=>0, 'mono'=>0);
1471  $info['mpeg']['audio']['version_distribution'] = array('1'=>0, '2'=>0, '2.5'=>0);
1472 
1473  if ($info['mpeg']['audio']['version'] == '1') {
1474  if ($info['mpeg']['audio']['layer'] == 3) {
1475  $info['mpeg']['audio']['bitrate_distribution'] = array('free'=>0, 32000=>0, 40000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 160000=>0, 192000=>0, 224000=>0, 256000=>0, 320000=>0);
1476  } elseif ($info['mpeg']['audio']['layer'] == 2) {
1477  $info['mpeg']['audio']['bitrate_distribution'] = array('free'=>0, 32000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 160000=>0, 192000=>0, 224000=>0, 256000=>0, 320000=>0, 384000=>0);
1478  } elseif ($info['mpeg']['audio']['layer'] == 1) {
1479  $info['mpeg']['audio']['bitrate_distribution'] = array('free'=>0, 32000=>0, 64000=>0, 96000=>0, 128000=>0, 160000=>0, 192000=>0, 224000=>0, 256000=>0, 288000=>0, 320000=>0, 352000=>0, 384000=>0, 416000=>0, 448000=>0);
1480  }
1481  } elseif ($info['mpeg']['audio']['layer'] == 1) {
1482  $info['mpeg']['audio']['bitrate_distribution'] = array('free'=>0, 32000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 144000=>0, 160000=>0, 176000=>0, 192000=>0, 224000=>0, 256000=>0);
1483  } else {
1484  $info['mpeg']['audio']['bitrate_distribution'] = array('free'=>0, 8000=>0, 16000=>0, 24000=>0, 32000=>0, 40000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 144000=>0, 160000=>0);
1485  }
1486 
1487  $dummy = array('error'=>$info['error'], 'warning'=>$info['warning'], 'avdataend'=>$info['avdataend'], 'avdataoffset'=>$info['avdataoffset']);
1488  $synchstartoffset = $info['avdataoffset'];
1489  $this->fseek($info['avdataoffset']);
1490 
1491  // you can play with these numbers:
1492  $max_frames_scan = 50000;
1493  $max_scan_segments = 10;
1494 
1495  // don't play with these numbers:
1496  $FastMode = false;
1497  $SynchErrorsFound = 0;
1498  $frames_scanned = 0;
1499  $this_scan_segment = 0;
1500  $frames_scan_per_segment = ceil($max_frames_scan / $max_scan_segments);
1501  $pct_data_scanned = 0;
1502  for ($current_segment = 0; $current_segment < $max_scan_segments; $current_segment++) {
1503  $frames_scanned_this_segment = 0;
1504  if ($this->ftell() >= $info['avdataend']) {
1505  break;
1506  }
1507  $scan_start_offset[$current_segment] = max($this->ftell(), $info['avdataoffset'] + round($current_segment * (($info['avdataend'] - $info['avdataoffset']) / $max_scan_segments)));
1508  if ($current_segment > 0) {
1509  $this->fseek($scan_start_offset[$current_segment]);
1510  $buffer_4k = $this->fread(4096);
1511  for ($j = 0; $j < (strlen($buffer_4k) - 4); $j++) {
1512  if (($buffer_4k{$j} == "\xFF") && ($buffer_4k{($j + 1)} > "\xE0")) { // synch detected
1513  if ($this->decodeMPEGaudioHeader($scan_start_offset[$current_segment] + $j, $dummy, false, false, $FastMode)) {
1514  $calculated_next_offset = $scan_start_offset[$current_segment] + $j + $dummy['mpeg']['audio']['framelength'];
1515  if ($this->decodeMPEGaudioHeader($calculated_next_offset, $dummy, false, false, $FastMode)) {
1516  $scan_start_offset[$current_segment] += $j;
1517  break;
1518  }
1519  }
1520  }
1521  }
1522  }
1523  $synchstartoffset = $scan_start_offset[$current_segment];
1524  while ($this->decodeMPEGaudioHeader($synchstartoffset, $dummy, false, false, $FastMode)) {
1525  $FastMode = true;
1526  $thisframebitrate = $MPEGaudioBitrateLookup[$MPEGaudioVersionLookup[$dummy['mpeg']['audio']['raw']['version']]][$MPEGaudioLayerLookup[$dummy['mpeg']['audio']['raw']['layer']]][$dummy['mpeg']['audio']['raw']['bitrate']];
1527 
1528  if (empty($dummy['mpeg']['audio']['framelength'])) {
1529  $SynchErrorsFound++;
1530  $synchstartoffset++;
1531  } else {
1532  getid3_lib::safe_inc($info['mpeg']['audio']['bitrate_distribution'][$thisframebitrate]);
1533  getid3_lib::safe_inc($info['mpeg']['audio']['stereo_distribution'][$dummy['mpeg']['audio']['channelmode']]);
1534  getid3_lib::safe_inc($info['mpeg']['audio']['version_distribution'][$dummy['mpeg']['audio']['version']]);
1535  $synchstartoffset += $dummy['mpeg']['audio']['framelength'];
1536  }
1537  $frames_scanned++;
1538  if ($frames_scan_per_segment && (++$frames_scanned_this_segment >= $frames_scan_per_segment)) {
1539  $this_pct_scanned = ($this->ftell() - $scan_start_offset[$current_segment]) / ($info['avdataend'] - $info['avdataoffset']);
1540  if (($current_segment == 0) && (($this_pct_scanned * $max_scan_segments) >= 1)) {
1541  // file likely contains < $max_frames_scan, just scan as one segment
1542  $max_scan_segments = 1;
1543  $frames_scan_per_segment = $max_frames_scan;
1544  } else {
1545  $pct_data_scanned += $this_pct_scanned;
1546  break;
1547  }
1548  }
1549  }
1550  }
1551  if ($pct_data_scanned > 0) {
1552  $this->warning('too many MPEG audio frames to scan, only scanned '.$frames_scanned.' frames in '.$max_scan_segments.' segments ('.number_format($pct_data_scanned * 100, 1).'% of file) and extrapolated distribution, playtime and bitrate may be incorrect.');
1553  foreach ($info['mpeg']['audio'] as $key1 => $value1) {
1554  if (!preg_match('#_distribution$#i', $key1)) {
1555  continue;
1556  }
1557  foreach ($value1 as $key2 => $value2) {
1558  $info['mpeg']['audio'][$key1][$key2] = round($value2 / $pct_data_scanned);
1559  }
1560  }
1561  }
1562 
1563  if ($SynchErrorsFound > 0) {
1564  $this->warning('Found '.$SynchErrorsFound.' synch errors in histogram analysis');
1565  //return false;
1566  }
1567 
1568  $bittotal = 0;
1569  $framecounter = 0;
1570  foreach ($info['mpeg']['audio']['bitrate_distribution'] as $bitratevalue => $bitratecount) {
1571  $framecounter += $bitratecount;
1572  if ($bitratevalue != 'free') {
1573  $bittotal += ($bitratevalue * $bitratecount);
1574  }
1575  }
1576  if ($framecounter == 0) {
1577  $this->error('Corrupt MP3 file: framecounter == zero');
1578  return false;
1579  }
1580  $info['mpeg']['audio']['frame_count'] = getid3_lib::CastAsInt($framecounter);
1581  $info['mpeg']['audio']['bitrate'] = ($bittotal / $framecounter);
1582 
1583  $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate'];
1584 
1585 
1586  // Definitively set VBR vs CBR, even if the Xing/LAME/VBRI header says differently
1587  $distinct_bitrates = 0;
1588  foreach ($info['mpeg']['audio']['bitrate_distribution'] as $bitrate_value => $bitrate_count) {
1589  if ($bitrate_count > 0) {
1590  $distinct_bitrates++;
1591  }
1592  }
1593  if ($distinct_bitrates > 1) {
1594  $info['mpeg']['audio']['bitrate_mode'] = 'vbr';
1595  } else {
1596  $info['mpeg']['audio']['bitrate_mode'] = 'cbr';
1597  }
1598  $info['audio']['bitrate_mode'] = $info['mpeg']['audio']['bitrate_mode'];
1599 
1600  }
1601 
1602  break; // exit while()
1603  }
1604  }
1605 
1606  $SynchSeekOffset++;
1607  if (($avdataoffset + $SynchSeekOffset) >= $info['avdataend']) {
1608  // end of file/data
1609 
1610  if (empty($info['mpeg']['audio'])) {
1611 
1612  $this->error('could not find valid MPEG synch before end of file');
1613  if (isset($info['audio']['bitrate'])) {
1614  unset($info['audio']['bitrate']);
1615  }
1616  if (isset($info['mpeg']['audio'])) {
1617  unset($info['mpeg']['audio']);
1618  }
1619  if (isset($info['mpeg']) && (!is_array($info['mpeg']) || empty($info['mpeg']))) {
1620  unset($info['mpeg']);
1621  }
1622  return false;
1623 
1624  }
1625  break;
1626  }
1627 
1628  }
1629  $info['audio']['channels'] = $info['mpeg']['audio']['channels'];
1630  $info['audio']['channelmode'] = $info['mpeg']['audio']['channelmode'];
1631  $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate'];
1632  return true;
1633  }
static safe_inc(&$variable, $increment=1)
Definition: getid3.lib.php:56
error($text)
Definition: getid3.php:1752
warning($text)
Definition: getid3.php:1758
static CastAsInt($floatnum)
Definition: getid3.lib.php:65
fread($bytes)
Definition: getid3.php:1683
decodeMPEGaudioHeader($offset, &$info, $recursivesearch=true, $ScanAsCBR=false, $FastMPEGheaderScan=false)
fseek($bytes, $whence=SEEK_SET)
Definition: getid3.php:1711
$info
Definition: index.php:5
const GETID3_MP3_VALID_CHECK_FRAMES
getID3() by James Heinrich info@getid3.org //
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getOnlyMPEGaudioInfoBruteForce()

getid3_mp3::getOnlyMPEGaudioInfoBruteForce ( )

Definition at line 1208 of file module.audio.mp3.php.

References $i, $info, $key, getid3_lib\array_max(), getid3_handler\error(), getid3_handler\fread(), getid3_handler\fseek(), getid3_handler\ftell(), getid3_lib\safe_inc(), and getid3_handler\warning().

Referenced by Analyze().

1208  {
1209  $MPEGaudioHeaderDecodeCache = array();
1210  $MPEGaudioHeaderValidCache = array();
1211  $MPEGaudioHeaderLengthCache = array();
1212  $MPEGaudioVersionLookup = self::MPEGaudioVersionArray();
1213  $MPEGaudioLayerLookup = self::MPEGaudioLayerArray();
1214  $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray();
1215  $MPEGaudioFrequencyLookup = self::MPEGaudioFrequencyArray();
1216  $MPEGaudioChannelModeLookup = self::MPEGaudioChannelModeArray();
1217  $MPEGaudioModeExtensionLookup = self::MPEGaudioModeExtensionArray();
1218  $MPEGaudioEmphasisLookup = self::MPEGaudioEmphasisArray();
1219  $LongMPEGversionLookup = array();
1220  $LongMPEGlayerLookup = array();
1221  $LongMPEGbitrateLookup = array();
1222  $LongMPEGpaddingLookup = array();
1223  $LongMPEGfrequencyLookup = array();
1224  $Distribution['bitrate'] = array();
1225  $Distribution['frequency'] = array();
1226  $Distribution['layer'] = array();
1227  $Distribution['version'] = array();
1228  $Distribution['padding'] = array();
1229 
1230  $info = &$this->getid3->info;
1231  $this->fseek($info['avdataoffset']);
1232 
1233  $max_frames_scan = 5000;
1234  $frames_scanned = 0;
1235 
1236  $previousvalidframe = $info['avdataoffset'];
1237  while ($this->ftell() < $info['avdataend']) {
1238  set_time_limit(30);
1239  $head4 = $this->fread(4);
1240  if (strlen($head4) < 4) {
1241  break;
1242  }
1243  if ($head4{0} != "\xFF") {
1244  for ($i = 1; $i < 4; $i++) {
1245  if ($head4{$i} == "\xFF") {
1246  $this->fseek($i - 4, SEEK_CUR);
1247  continue 2;
1248  }
1249  }
1250  continue;
1251  }
1252  if (!isset($MPEGaudioHeaderDecodeCache[$head4])) {
1253  $MPEGaudioHeaderDecodeCache[$head4] = self::MPEGaudioHeaderDecode($head4);
1254  }
1255  if (!isset($MPEGaudioHeaderValidCache[$head4])) {
1256  $MPEGaudioHeaderValidCache[$head4] = self::MPEGaudioHeaderValid($MPEGaudioHeaderDecodeCache[$head4], false, false);
1257  }
1258  if ($MPEGaudioHeaderValidCache[$head4]) {
1259 
1260  if (!isset($MPEGaudioHeaderLengthCache[$head4])) {
1261  $LongMPEGversionLookup[$head4] = $MPEGaudioVersionLookup[$MPEGaudioHeaderDecodeCache[$head4]['version']];
1262  $LongMPEGlayerLookup[$head4] = $MPEGaudioLayerLookup[$MPEGaudioHeaderDecodeCache[$head4]['layer']];
1263  $LongMPEGbitrateLookup[$head4] = $MPEGaudioBitrateLookup[$LongMPEGversionLookup[$head4]][$LongMPEGlayerLookup[$head4]][$MPEGaudioHeaderDecodeCache[$head4]['bitrate']];
1264  $LongMPEGpaddingLookup[$head4] = (bool) $MPEGaudioHeaderDecodeCache[$head4]['padding'];
1265  $LongMPEGfrequencyLookup[$head4] = $MPEGaudioFrequencyLookup[$LongMPEGversionLookup[$head4]][$MPEGaudioHeaderDecodeCache[$head4]['sample_rate']];
1266  $MPEGaudioHeaderLengthCache[$head4] = self::MPEGaudioFrameLength(
1267  $LongMPEGbitrateLookup[$head4],
1268  $LongMPEGversionLookup[$head4],
1269  $LongMPEGlayerLookup[$head4],
1270  $LongMPEGpaddingLookup[$head4],
1271  $LongMPEGfrequencyLookup[$head4]);
1272  }
1273  if ($MPEGaudioHeaderLengthCache[$head4] > 4) {
1274  $WhereWeWere = $this->ftell();
1275  $this->fseek($MPEGaudioHeaderLengthCache[$head4] - 4, SEEK_CUR);
1276  $next4 = $this->fread(4);
1277  if ($next4{0} == "\xFF") {
1278  if (!isset($MPEGaudioHeaderDecodeCache[$next4])) {
1279  $MPEGaudioHeaderDecodeCache[$next4] = self::MPEGaudioHeaderDecode($next4);
1280  }
1281  if (!isset($MPEGaudioHeaderValidCache[$next4])) {
1282  $MPEGaudioHeaderValidCache[$next4] = self::MPEGaudioHeaderValid($MPEGaudioHeaderDecodeCache[$next4], false, false);
1283  }
1284  if ($MPEGaudioHeaderValidCache[$next4]) {
1285  $this->fseek(-4, SEEK_CUR);
1286 
1287  getid3_lib::safe_inc($Distribution['bitrate'][$LongMPEGbitrateLookup[$head4]]);
1288  getid3_lib::safe_inc($Distribution['layer'][$LongMPEGlayerLookup[$head4]]);
1289  getid3_lib::safe_inc($Distribution['version'][$LongMPEGversionLookup[$head4]]);
1290  getid3_lib::safe_inc($Distribution['padding'][intval($LongMPEGpaddingLookup[$head4])]);
1291  getid3_lib::safe_inc($Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]]);
1292  if ($max_frames_scan && (++$frames_scanned >= $max_frames_scan)) {
1293  $pct_data_scanned = ($this->ftell() - $info['avdataoffset']) / ($info['avdataend'] - $info['avdataoffset']);
1294  $this->warning('too many MPEG audio frames to scan, only scanned first '.$max_frames_scan.' frames ('.number_format($pct_data_scanned * 100, 1).'% of file) and extrapolated distribution, playtime and bitrate may be incorrect.');
1295  foreach ($Distribution as $key1 => $value1) {
1296  foreach ($value1 as $key2 => $value2) {
1297  $Distribution[$key1][$key2] = round($value2 / $pct_data_scanned);
1298  }
1299  }
1300  break;
1301  }
1302  continue;
1303  }
1304  }
1305  unset($next4);
1306  $this->fseek($WhereWeWere - 3);
1307  }
1308 
1309  }
1310  }
1311  foreach ($Distribution as $key => $value) {
1312  ksort($Distribution[$key], SORT_NUMERIC);
1313  }
1314  ksort($Distribution['version'], SORT_STRING);
1315  $info['mpeg']['audio']['bitrate_distribution'] = $Distribution['bitrate'];
1316  $info['mpeg']['audio']['frequency_distribution'] = $Distribution['frequency'];
1317  $info['mpeg']['audio']['layer_distribution'] = $Distribution['layer'];
1318  $info['mpeg']['audio']['version_distribution'] = $Distribution['version'];
1319  $info['mpeg']['audio']['padding_distribution'] = $Distribution['padding'];
1320  if (count($Distribution['version']) > 1) {
1321  $this->error('Corrupt file - more than one MPEG version detected');
1322  }
1323  if (count($Distribution['layer']) > 1) {
1324  $this->error('Corrupt file - more than one MPEG layer detected');
1325  }
1326  if (count($Distribution['frequency']) > 1) {
1327  $this->error('Corrupt file - more than one MPEG sample rate detected');
1328  }
1329 
1330 
1331  $bittotal = 0;
1332  foreach ($Distribution['bitrate'] as $bitratevalue => $bitratecount) {
1333  if ($bitratevalue != 'free') {
1334  $bittotal += ($bitratevalue * $bitratecount);
1335  }
1336  }
1337  $info['mpeg']['audio']['frame_count'] = array_sum($Distribution['bitrate']);
1338  if ($info['mpeg']['audio']['frame_count'] == 0) {
1339  $this->error('no MPEG audio frames found');
1340  return false;
1341  }
1342  $info['mpeg']['audio']['bitrate'] = ($bittotal / $info['mpeg']['audio']['frame_count']);
1343  $info['mpeg']['audio']['bitrate_mode'] = ((count($Distribution['bitrate']) > 0) ? 'vbr' : 'cbr');
1344  $info['mpeg']['audio']['sample_rate'] = getid3_lib::array_max($Distribution['frequency'], true);
1345 
1346  $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate'];
1347  $info['audio']['bitrate_mode'] = $info['mpeg']['audio']['bitrate_mode'];
1348  $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate'];
1349  $info['audio']['dataformat'] = 'mp'.getid3_lib::array_max($Distribution['layer'], true);
1350  $info['fileformat'] = $info['audio']['dataformat'];
1351 
1352  return true;
1353  }
static safe_inc(&$variable, $increment=1)
Definition: getid3.lib.php:56
error($text)
Definition: getid3.php:1752
warning($text)
Definition: getid3.php:1758
fread($bytes)
Definition: getid3.php:1683
$i
Definition: disco.tpl.php:19
fseek($bytes, $whence=SEEK_SET)
Definition: getid3.php:1711
$info
Definition: index.php:5
$key
Definition: croninfo.php:18
static array_max($arraydata, $returnkey=false)
Definition: getid3.lib.php:507
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ GuessEncoderOptions()

getid3_mp3::GuessEncoderOptions ( )

Definition at line 164 of file module.audio.mp3.php.

References $info.

Referenced by Analyze().

164  {
165  // shortcuts
166  $info = &$this->getid3->info;
167  if (!empty($info['mpeg']['audio'])) {
168  $thisfile_mpeg_audio = &$info['mpeg']['audio'];
169  if (!empty($thisfile_mpeg_audio['LAME'])) {
170  $thisfile_mpeg_audio_lame = &$thisfile_mpeg_audio['LAME'];
171  }
172  }
173 
174  $encoder_options = '';
175  static $NamedPresetBitrates = array(16, 24, 40, 56, 112, 128, 160, 192, 256);
176 
177  if (isset($thisfile_mpeg_audio['VBR_method']) && ($thisfile_mpeg_audio['VBR_method'] == 'Fraunhofer') && !empty($thisfile_mpeg_audio['VBR_quality'])) {
178 
179  $encoder_options = 'VBR q'.$thisfile_mpeg_audio['VBR_quality'];
180 
181  } elseif (!empty($thisfile_mpeg_audio_lame['preset_used']) && (!in_array($thisfile_mpeg_audio_lame['preset_used_id'], $NamedPresetBitrates))) {
182 
183  $encoder_options = $thisfile_mpeg_audio_lame['preset_used'];
184 
185  } elseif (!empty($thisfile_mpeg_audio_lame['vbr_quality'])) {
186 
187  static $KnownEncoderValues = array();
188  if (empty($KnownEncoderValues)) {
189 
190  //$KnownEncoderValues[abrbitrate_minbitrate][vbr_quality][raw_vbr_method][raw_noise_shaping][raw_stereo_mode][ath_type][lowpass_frequency] = 'preset name';
191  $KnownEncoderValues[0xFF][58][1][1][3][2][20500] = '--alt-preset insane'; // 3.90, 3.90.1, 3.92
192  $KnownEncoderValues[0xFF][58][1][1][3][2][20600] = '--alt-preset insane'; // 3.90.2, 3.90.3, 3.91
193  $KnownEncoderValues[0xFF][57][1][1][3][4][20500] = '--alt-preset insane'; // 3.94, 3.95
194  $KnownEncoderValues['**'][78][3][2][3][2][19500] = '--alt-preset extreme'; // 3.90, 3.90.1, 3.92
195  $KnownEncoderValues['**'][78][3][2][3][2][19600] = '--alt-preset extreme'; // 3.90.2, 3.91
196  $KnownEncoderValues['**'][78][3][1][3][2][19600] = '--alt-preset extreme'; // 3.90.3
197  $KnownEncoderValues['**'][78][4][2][3][2][19500] = '--alt-preset fast extreme'; // 3.90, 3.90.1, 3.92
198  $KnownEncoderValues['**'][78][4][2][3][2][19600] = '--alt-preset fast extreme'; // 3.90.2, 3.90.3, 3.91
199  $KnownEncoderValues['**'][78][3][2][3][4][19000] = '--alt-preset standard'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
200  $KnownEncoderValues['**'][78][3][1][3][4][19000] = '--alt-preset standard'; // 3.90.3
201  $KnownEncoderValues['**'][78][4][2][3][4][19000] = '--alt-preset fast standard'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
202  $KnownEncoderValues['**'][78][4][1][3][4][19000] = '--alt-preset fast standard'; // 3.90.3
203  $KnownEncoderValues['**'][88][4][1][3][3][19500] = '--r3mix'; // 3.90, 3.90.1, 3.92
204  $KnownEncoderValues['**'][88][4][1][3][3][19600] = '--r3mix'; // 3.90.2, 3.90.3, 3.91
205  $KnownEncoderValues['**'][67][4][1][3][4][18000] = '--r3mix'; // 3.94, 3.95
206  $KnownEncoderValues['**'][68][3][2][3][4][18000] = '--alt-preset medium'; // 3.90.3
207  $KnownEncoderValues['**'][68][4][2][3][4][18000] = '--alt-preset fast medium'; // 3.90.3
208 
209  $KnownEncoderValues[0xFF][99][1][1][1][2][0] = '--preset studio'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
210  $KnownEncoderValues[0xFF][58][2][1][3][2][20600] = '--preset studio'; // 3.90.3, 3.93.1
211  $KnownEncoderValues[0xFF][58][2][1][3][2][20500] = '--preset studio'; // 3.93
212  $KnownEncoderValues[0xFF][57][2][1][3][4][20500] = '--preset studio'; // 3.94, 3.95
213  $KnownEncoderValues[0xC0][88][1][1][1][2][0] = '--preset cd'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
214  $KnownEncoderValues[0xC0][58][2][2][3][2][19600] = '--preset cd'; // 3.90.3, 3.93.1
215  $KnownEncoderValues[0xC0][58][2][2][3][2][19500] = '--preset cd'; // 3.93
216  $KnownEncoderValues[0xC0][57][2][1][3][4][19500] = '--preset cd'; // 3.94, 3.95
217  $KnownEncoderValues[0xA0][78][1][1][3][2][18000] = '--preset hifi'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
218  $KnownEncoderValues[0xA0][58][2][2][3][2][18000] = '--preset hifi'; // 3.90.3, 3.93, 3.93.1
219  $KnownEncoderValues[0xA0][57][2][1][3][4][18000] = '--preset hifi'; // 3.94, 3.95
220  $KnownEncoderValues[0x80][67][1][1][3][2][18000] = '--preset tape'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
221  $KnownEncoderValues[0x80][67][1][1][3][2][15000] = '--preset radio'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
222  $KnownEncoderValues[0x70][67][1][1][3][2][15000] = '--preset fm'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
223  $KnownEncoderValues[0x70][58][2][2][3][2][16000] = '--preset tape/radio/fm'; // 3.90.3, 3.93, 3.93.1
224  $KnownEncoderValues[0x70][57][2][1][3][4][16000] = '--preset tape/radio/fm'; // 3.94, 3.95
225  $KnownEncoderValues[0x38][58][2][2][0][2][10000] = '--preset voice'; // 3.90.3, 3.93, 3.93.1
226  $KnownEncoderValues[0x38][57][2][1][0][4][15000] = '--preset voice'; // 3.94, 3.95
227  $KnownEncoderValues[0x38][57][2][1][0][4][16000] = '--preset voice'; // 3.94a14
228  $KnownEncoderValues[0x28][65][1][1][0][2][7500] = '--preset mw-us'; // 3.90, 3.90.1, 3.92
229  $KnownEncoderValues[0x28][65][1][1][0][2][7600] = '--preset mw-us'; // 3.90.2, 3.91
230  $KnownEncoderValues[0x28][58][2][2][0][2][7000] = '--preset mw-us'; // 3.90.3, 3.93, 3.93.1
231  $KnownEncoderValues[0x28][57][2][1][0][4][10500] = '--preset mw-us'; // 3.94, 3.95
232  $KnownEncoderValues[0x28][57][2][1][0][4][11200] = '--preset mw-us'; // 3.94a14
233  $KnownEncoderValues[0x28][57][2][1][0][4][8800] = '--preset mw-us'; // 3.94a15
234  $KnownEncoderValues[0x18][58][2][2][0][2][4000] = '--preset phon+/lw/mw-eu/sw'; // 3.90.3, 3.93.1
235  $KnownEncoderValues[0x18][58][2][2][0][2][3900] = '--preset phon+/lw/mw-eu/sw'; // 3.93
236  $KnownEncoderValues[0x18][57][2][1][0][4][5900] = '--preset phon+/lw/mw-eu/sw'; // 3.94, 3.95
237  $KnownEncoderValues[0x18][57][2][1][0][4][6200] = '--preset phon+/lw/mw-eu/sw'; // 3.94a14
238  $KnownEncoderValues[0x18][57][2][1][0][4][3200] = '--preset phon+/lw/mw-eu/sw'; // 3.94a15
239  $KnownEncoderValues[0x10][58][2][2][0][2][3800] = '--preset phone'; // 3.90.3, 3.93.1
240  $KnownEncoderValues[0x10][58][2][2][0][2][3700] = '--preset phone'; // 3.93
241  $KnownEncoderValues[0x10][57][2][1][0][4][5600] = '--preset phone'; // 3.94, 3.95
242  }
243 
244  if (isset($KnownEncoderValues[$thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate']][$thisfile_mpeg_audio_lame['vbr_quality']][$thisfile_mpeg_audio_lame['raw']['vbr_method']][$thisfile_mpeg_audio_lame['raw']['noise_shaping']][$thisfile_mpeg_audio_lame['raw']['stereo_mode']][$thisfile_mpeg_audio_lame['ath_type']][$thisfile_mpeg_audio_lame['lowpass_frequency']])) {
245 
246  $encoder_options = $KnownEncoderValues[$thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate']][$thisfile_mpeg_audio_lame['vbr_quality']][$thisfile_mpeg_audio_lame['raw']['vbr_method']][$thisfile_mpeg_audio_lame['raw']['noise_shaping']][$thisfile_mpeg_audio_lame['raw']['stereo_mode']][$thisfile_mpeg_audio_lame['ath_type']][$thisfile_mpeg_audio_lame['lowpass_frequency']];
247 
248  } elseif (isset($KnownEncoderValues['**'][$thisfile_mpeg_audio_lame['vbr_quality']][$thisfile_mpeg_audio_lame['raw']['vbr_method']][$thisfile_mpeg_audio_lame['raw']['noise_shaping']][$thisfile_mpeg_audio_lame['raw']['stereo_mode']][$thisfile_mpeg_audio_lame['ath_type']][$thisfile_mpeg_audio_lame['lowpass_frequency']])) {
249 
250  $encoder_options = $KnownEncoderValues['**'][$thisfile_mpeg_audio_lame['vbr_quality']][$thisfile_mpeg_audio_lame['raw']['vbr_method']][$thisfile_mpeg_audio_lame['raw']['noise_shaping']][$thisfile_mpeg_audio_lame['raw']['stereo_mode']][$thisfile_mpeg_audio_lame['ath_type']][$thisfile_mpeg_audio_lame['lowpass_frequency']];
251 
252  } elseif ($info['audio']['bitrate_mode'] == 'vbr') {
253 
254  // http://gabriel.mp3-tech.org/mp3infotag.html
255  // int Quality = (100 - 10 * gfp->VBR_q - gfp->quality)h
256 
257 
258  $LAME_V_value = 10 - ceil($thisfile_mpeg_audio_lame['vbr_quality'] / 10);
259  $LAME_q_value = 100 - $thisfile_mpeg_audio_lame['vbr_quality'] - ($LAME_V_value * 10);
260  $encoder_options = '-V'.$LAME_V_value.' -q'.$LAME_q_value;
261 
262  } elseif ($info['audio']['bitrate_mode'] == 'cbr') {
263 
264  $encoder_options = strtoupper($info['audio']['bitrate_mode']).ceil($info['audio']['bitrate'] / 1000);
265 
266  } else {
267 
268  $encoder_options = strtoupper($info['audio']['bitrate_mode']);
269 
270  }
271 
272  } elseif (!empty($thisfile_mpeg_audio_lame['bitrate_abr'])) {
273 
274  $encoder_options = 'ABR'.$thisfile_mpeg_audio_lame['bitrate_abr'];
275 
276  } elseif (!empty($info['audio']['bitrate'])) {
277 
278  if ($info['audio']['bitrate_mode'] == 'cbr') {
279  $encoder_options = strtoupper($info['audio']['bitrate_mode']).ceil($info['audio']['bitrate'] / 1000);
280  } else {
281  $encoder_options = strtoupper($info['audio']['bitrate_mode']);
282  }
283 
284  }
285  if (!empty($thisfile_mpeg_audio_lame['bitrate_min'])) {
286  $encoder_options .= ' -b'.$thisfile_mpeg_audio_lame['bitrate_min'];
287  }
288 
289  if (!empty($thisfile_mpeg_audio_lame['encoding_flags']['nogap_prev']) || !empty($thisfile_mpeg_audio_lame['encoding_flags']['nogap_next'])) {
290  $encoder_options .= ' --nogap';
291  }
292 
293  if (!empty($thisfile_mpeg_audio_lame['lowpass_frequency'])) {
294  $ExplodedOptions = explode(' ', $encoder_options, 4);
295  if ($ExplodedOptions[0] == '--r3mix') {
296  $ExplodedOptions[1] = 'r3mix';
297  }
298  switch ($ExplodedOptions[0]) {
299  case '--preset':
300  case '--alt-preset':
301  case '--r3mix':
302  if ($ExplodedOptions[1] == 'fast') {
303  $ExplodedOptions[1] .= ' '.$ExplodedOptions[2];
304  }
305  switch ($ExplodedOptions[1]) {
306  case 'portable':
307  case 'medium':
308  case 'standard':
309  case 'extreme':
310  case 'insane':
311  case 'fast portable':
312  case 'fast medium':
313  case 'fast standard':
314  case 'fast extreme':
315  case 'fast insane':
316  case 'r3mix':
317  static $ExpectedLowpass = array(
318  'insane|20500' => 20500,
319  'insane|20600' => 20600, // 3.90.2, 3.90.3, 3.91
320  'medium|18000' => 18000,
321  'fast medium|18000' => 18000,
322  'extreme|19500' => 19500, // 3.90, 3.90.1, 3.92, 3.95
323  'extreme|19600' => 19600, // 3.90.2, 3.90.3, 3.91, 3.93.1
324  'fast extreme|19500' => 19500, // 3.90, 3.90.1, 3.92, 3.95
325  'fast extreme|19600' => 19600, // 3.90.2, 3.90.3, 3.91, 3.93.1
326  'standard|19000' => 19000,
327  'fast standard|19000' => 19000,
328  'r3mix|19500' => 19500, // 3.90, 3.90.1, 3.92
329  'r3mix|19600' => 19600, // 3.90.2, 3.90.3, 3.91
330  'r3mix|18000' => 18000, // 3.94, 3.95
331  );
332  if (!isset($ExpectedLowpass[$ExplodedOptions[1].'|'.$thisfile_mpeg_audio_lame['lowpass_frequency']]) && ($thisfile_mpeg_audio_lame['lowpass_frequency'] < 22050) && (round($thisfile_mpeg_audio_lame['lowpass_frequency'] / 1000) < round($thisfile_mpeg_audio['sample_rate'] / 2000))) {
333  $encoder_options .= ' --lowpass '.$thisfile_mpeg_audio_lame['lowpass_frequency'];
334  }
335  break;
336 
337  default:
338  break;
339  }
340  break;
341  }
342  }
343 
344  if (isset($thisfile_mpeg_audio_lame['raw']['source_sample_freq'])) {
345  if (($thisfile_mpeg_audio['sample_rate'] == 44100) && ($thisfile_mpeg_audio_lame['raw']['source_sample_freq'] != 1)) {
346  $encoder_options .= ' --resample 44100';
347  } elseif (($thisfile_mpeg_audio['sample_rate'] == 48000) && ($thisfile_mpeg_audio_lame['raw']['source_sample_freq'] != 2)) {
348  $encoder_options .= ' --resample 48000';
349  } elseif ($thisfile_mpeg_audio['sample_rate'] < 44100) {
350  switch ($thisfile_mpeg_audio_lame['raw']['source_sample_freq']) {
351  case 0: // <= 32000
352  // may or may not be same as source frequency - ignore
353  break;
354  case 1: // 44100
355  case 2: // 48000
356  case 3: // 48000+
357  $ExplodedOptions = explode(' ', $encoder_options, 4);
358  switch ($ExplodedOptions[0]) {
359  case '--preset':
360  case '--alt-preset':
361  switch ($ExplodedOptions[1]) {
362  case 'fast':
363  case 'portable':
364  case 'medium':
365  case 'standard':
366  case 'extreme':
367  case 'insane':
368  $encoder_options .= ' --resample '.$thisfile_mpeg_audio['sample_rate'];
369  break;
370 
371  default:
372  static $ExpectedResampledRate = array(
373  'phon+/lw/mw-eu/sw|16000' => 16000,
374  'mw-us|24000' => 24000, // 3.95
375  'mw-us|32000' => 32000, // 3.93
376  'mw-us|16000' => 16000, // 3.92
377  'phone|16000' => 16000,
378  'phone|11025' => 11025, // 3.94a15
379  'radio|32000' => 32000, // 3.94a15
380  'fm/radio|32000' => 32000, // 3.92
381  'fm|32000' => 32000, // 3.90
382  'voice|32000' => 32000);
383  if (!isset($ExpectedResampledRate[$ExplodedOptions[1].'|'.$thisfile_mpeg_audio['sample_rate']])) {
384  $encoder_options .= ' --resample '.$thisfile_mpeg_audio['sample_rate'];
385  }
386  break;
387  }
388  break;
389 
390  case '--r3mix':
391  default:
392  $encoder_options .= ' --resample '.$thisfile_mpeg_audio['sample_rate'];
393  break;
394  }
395  break;
396  }
397  }
398  }
399  if (empty($encoder_options) && !empty($info['audio']['bitrate']) && !empty($info['audio']['bitrate_mode'])) {
400  //$encoder_options = strtoupper($info['audio']['bitrate_mode']).ceil($info['audio']['bitrate'] / 1000);
401  $encoder_options = strtoupper($info['audio']['bitrate_mode']);
402  }
403 
404  return $encoder_options;
405  }
$info
Definition: index.php:5
+ Here is the caller graph for this function:

◆ LAMEmiscSourceSampleFrequencyLookup()

static getid3_mp3::LAMEmiscSourceSampleFrequencyLookup (   $SourceSampleFrequencyID)
static

Definition at line 1949 of file module.audio.mp3.php.

1949  {
1950  static $LAMEmiscSourceSampleFrequencyLookup = array(
1951  0 => '<= 32 kHz',
1952  1 => '44.1 kHz',
1953  2 => '48 kHz',
1954  3 => '> 48kHz'
1955  );
1956  return (isset($LAMEmiscSourceSampleFrequencyLookup[$SourceSampleFrequencyID]) ? $LAMEmiscSourceSampleFrequencyLookup[$SourceSampleFrequencyID] : '');
1957  }

◆ LAMEmiscStereoModeLookup()

static getid3_mp3::LAMEmiscStereoModeLookup (   $StereoModeID)
static

Definition at line 1935 of file module.audio.mp3.php.

1935  {
1936  static $LAMEmiscStereoModeLookup = array(
1937  0 => 'mono',
1938  1 => 'stereo',
1939  2 => 'dual mono',
1940  3 => 'joint stereo',
1941  4 => 'forced stereo',
1942  5 => 'auto',
1943  6 => 'intensity stereo',
1944  7 => 'other'
1945  );
1946  return (isset($LAMEmiscStereoModeLookup[$StereoModeID]) ? $LAMEmiscStereoModeLookup[$StereoModeID] : '');
1947  }

◆ LAMEpresetUsedLookup()

static getid3_mp3::LAMEpresetUsedLookup (   $LAMEtag)
static

Definition at line 1969 of file module.audio.mp3.php.

References $i.

1969  {
1970 
1971  if ($LAMEtag['preset_used_id'] == 0) {
1972  // no preset used (LAME >=3.93)
1973  // no preset recorded (LAME <3.93)
1974  return '';
1975  }
1976  $LAMEpresetUsedLookup = array();
1977 
1979  for ($i = 8; $i <= 320; $i++) {
1980  switch ($LAMEtag['vbr_method']) {
1981  case 'cbr':
1982  $LAMEpresetUsedLookup[$i] = '--alt-preset '.$LAMEtag['vbr_method'].' '.$i;
1983  break;
1984  case 'abr':
1985  default: // other VBR modes shouldn't be here(?)
1986  $LAMEpresetUsedLookup[$i] = '--alt-preset '.$i;
1987  break;
1988  }
1989  }
1990 
1991  // named old-style presets (studio, phone, voice, etc) are handled in GuessEncoderOptions()
1992 
1993  // named alt-presets
1994  $LAMEpresetUsedLookup[1000] = '--r3mix';
1995  $LAMEpresetUsedLookup[1001] = '--alt-preset standard';
1996  $LAMEpresetUsedLookup[1002] = '--alt-preset extreme';
1997  $LAMEpresetUsedLookup[1003] = '--alt-preset insane';
1998  $LAMEpresetUsedLookup[1004] = '--alt-preset fast standard';
1999  $LAMEpresetUsedLookup[1005] = '--alt-preset fast extreme';
2000  $LAMEpresetUsedLookup[1006] = '--alt-preset medium';
2001  $LAMEpresetUsedLookup[1007] = '--alt-preset fast medium';
2002 
2003  // LAME 3.94 additions/changes
2004  $LAMEpresetUsedLookup[1010] = '--preset portable'; // 3.94a15 Oct 21 2003
2005  $LAMEpresetUsedLookup[1015] = '--preset radio'; // 3.94a15 Oct 21 2003
2006 
2007  $LAMEpresetUsedLookup[320] = '--preset insane'; // 3.94a15 Nov 12 2003
2008  $LAMEpresetUsedLookup[410] = '-V9';
2009  $LAMEpresetUsedLookup[420] = '-V8';
2010  $LAMEpresetUsedLookup[440] = '-V6';
2011  $LAMEpresetUsedLookup[430] = '--preset radio'; // 3.94a15 Nov 12 2003
2012  $LAMEpresetUsedLookup[450] = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'portable'; // 3.94a15 Nov 12 2003
2013  $LAMEpresetUsedLookup[460] = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'medium'; // 3.94a15 Nov 12 2003
2014  $LAMEpresetUsedLookup[470] = '--r3mix'; // 3.94b1 Dec 18 2003
2015  $LAMEpresetUsedLookup[480] = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'standard'; // 3.94a15 Nov 12 2003
2016  $LAMEpresetUsedLookup[490] = '-V1';
2017  $LAMEpresetUsedLookup[500] = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'extreme'; // 3.94a15 Nov 12 2003
2018 
2019  return (isset($LAMEpresetUsedLookup[$LAMEtag['preset_used_id']]) ? $LAMEpresetUsedLookup[$LAMEtag['preset_used_id']] : 'new/unknown preset: '.$LAMEtag['preset_used_id'].' - report to info@getid3.org');
2020  }
$i
Definition: disco.tpl.php:19

◆ LAMEsurroundInfoLookup()

static getid3_mp3::LAMEsurroundInfoLookup (   $SurroundInfoID)
static

Definition at line 1959 of file module.audio.mp3.php.

1959  {
1960  static $LAMEsurroundInfoLookup = array(
1961  0 => 'no surround info',
1962  1 => 'DPL encoding',
1963  2 => 'DPL2 encoding',
1964  3 => 'Ambisonic encoding'
1965  );
1966  return (isset($LAMEsurroundInfoLookup[$SurroundInfoID]) ? $LAMEsurroundInfoLookup[$SurroundInfoID] : 'reserved');
1967  }

◆ LAMEvbrMethodLookup()

static getid3_mp3::LAMEvbrMethodLookup (   $VBRmethodID)
static

Definition at line 1919 of file module.audio.mp3.php.

1919  {
1920  static $LAMEvbrMethodLookup = array(
1921  0x00 => 'unknown',
1922  0x01 => 'cbr',
1923  0x02 => 'abr',
1924  0x03 => 'vbr-old / vbr-rh',
1925  0x04 => 'vbr-new / vbr-mtrh',
1926  0x05 => 'vbr-mt',
1927  0x06 => 'vbr (full vbr method 4)',
1928  0x08 => 'cbr (constant bitrate 2 pass)',
1929  0x09 => 'abr (2 pass)',
1930  0x0F => 'reserved'
1931  );
1932  return (isset($LAMEvbrMethodLookup[$VBRmethodID]) ? $LAMEvbrMethodLookup[$VBRmethodID] : '');
1933  }

◆ MPEGaudioBitrateArray()

static getid3_mp3::MPEGaudioBitrateArray ( )
static

Definition at line 1646 of file module.audio.mp3.php.

1646  {
1647  static $MPEGaudioBitrate;
1648  if (empty($MPEGaudioBitrate)) {
1649  $MPEGaudioBitrate = array (
1650  '1' => array (1 => array('free', 32000, 64000, 96000, 128000, 160000, 192000, 224000, 256000, 288000, 320000, 352000, 384000, 416000, 448000),
1651  2 => array('free', 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, 384000),
1652  3 => array('free', 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000)
1653  ),
1654 
1655  '2' => array (1 => array('free', 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 176000, 192000, 224000, 256000),
1656  2 => array('free', 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000),
1657  )
1658  );
1659  $MPEGaudioBitrate['2'][3] = $MPEGaudioBitrate['2'][2];
1660  $MPEGaudioBitrate['2.5'] = $MPEGaudioBitrate['2'];
1661  }
1662  return $MPEGaudioBitrate;
1663  }

◆ MPEGaudioChannelModeArray()

static getid3_mp3::MPEGaudioChannelModeArray ( )
static

Definition at line 1677 of file module.audio.mp3.php.

1677  {
1678  static $MPEGaudioChannelMode = array('stereo', 'joint stereo', 'dual channel', 'mono');
1679  return $MPEGaudioChannelMode;
1680  }

◆ MPEGaudioEmphasisArray()

static getid3_mp3::MPEGaudioEmphasisArray ( )
static

Definition at line 1694 of file module.audio.mp3.php.

1694  {
1695  static $MPEGaudioEmphasis = array('none', '50/15ms', false, 'CCIT J.17');
1696  return $MPEGaudioEmphasis;
1697  }

◆ MPEGaudioFrameLength()

static getid3_mp3::MPEGaudioFrameLength ( $bitrate,
$version,
$layer,
  $padding,
$samplerate 
)
static

Definition at line 1812 of file module.audio.mp3.php.

References $version.

1812  {
1813  static $AudioFrameLengthCache = array();
1814 
1815  if (!isset($AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate])) {
1816  $AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate] = false;
1817  if ($bitrate != 'free') {
1818 
1819  if ($version == '1') {
1820 
1821  if ($layer == '1') {
1822 
1823  // For Layer I slot is 32 bits long
1824  $FrameLengthCoefficient = 48;
1825  $SlotLength = 4;
1826 
1827  } else { // Layer 2 / 3
1828 
1829  // for Layer 2 and Layer 3 slot is 8 bits long.
1830  $FrameLengthCoefficient = 144;
1831  $SlotLength = 1;
1832 
1833  }
1834 
1835  } else { // MPEG-2 / MPEG-2.5
1836 
1837  if ($layer == '1') {
1838 
1839  // For Layer I slot is 32 bits long
1840  $FrameLengthCoefficient = 24;
1841  $SlotLength = 4;
1842 
1843  } elseif ($layer == '2') {
1844 
1845  // for Layer 2 and Layer 3 slot is 8 bits long.
1846  $FrameLengthCoefficient = 144;
1847  $SlotLength = 1;
1848 
1849  } else { // layer 3
1850 
1851  // for Layer 2 and Layer 3 slot is 8 bits long.
1852  $FrameLengthCoefficient = 72;
1853  $SlotLength = 1;
1854 
1855  }
1856 
1857  }
1858 
1859  // FrameLengthInBytes = ((Coefficient * BitRate) / SampleRate) + Padding
1860  if ($samplerate > 0) {
1861  $NewFramelength = ($FrameLengthCoefficient * $bitrate) / $samplerate;
1862  $NewFramelength = floor($NewFramelength / $SlotLength) * $SlotLength; // round to next-lower multiple of SlotLength (1 byte for Layer 2/3, 4 bytes for Layer I)
1863  if ($padding) {
1864  $NewFramelength += $SlotLength;
1865  }
1866  $AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate] = (int) $NewFramelength;
1867  }
1868  }
1869  }
1870  return $AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate];
1871  }
$version
Definition: build.php:27

◆ MPEGaudioFrequencyArray()

static getid3_mp3::MPEGaudioFrequencyArray ( )
static

Definition at line 1665 of file module.audio.mp3.php.

1665  {
1666  static $MPEGaudioFrequency;
1667  if (empty($MPEGaudioFrequency)) {
1668  $MPEGaudioFrequency = array (
1669  '1' => array(44100, 48000, 32000),
1670  '2' => array(22050, 24000, 16000),
1671  '2.5' => array(11025, 12000, 8000)
1672  );
1673  }
1674  return $MPEGaudioFrequency;
1675  }

◆ MPEGaudioHeaderBytesValid()

static getid3_mp3::MPEGaudioHeaderBytesValid (   $head4,
  $allowBitrate15 = false 
)
static

Definition at line 1699 of file module.audio.mp3.php.

Referenced by getid3_riff\ParseRIFF().

1699  {
1700  return self::MPEGaudioHeaderValid(self::MPEGaudioHeaderDecode($head4), false, $allowBitrate15);
1701  }
+ Here is the caller graph for this function:

◆ MPEGaudioHeaderDecode()

static getid3_mp3::MPEGaudioHeaderDecode (   $Header4Bytes)
static

Definition at line 1775 of file module.audio.mp3.php.

References getid3_lib\BigEndian2Int().

1775  {
1776  // AAAA AAAA AAAB BCCD EEEE FFGH IIJJ KLMM
1777  // A - Frame sync (all bits set)
1778  // B - MPEG Audio version ID
1779  // C - Layer description
1780  // D - Protection bit
1781  // E - Bitrate index
1782  // F - Sampling rate frequency index
1783  // G - Padding bit
1784  // H - Private bit
1785  // I - Channel Mode
1786  // J - Mode extension (Only if Joint stereo)
1787  // K - Copyright
1788  // L - Original
1789  // M - Emphasis
1790 
1791  if (strlen($Header4Bytes) != 4) {
1792  return false;
1793  }
1794 
1795  $MPEGrawHeader['synch'] = (getid3_lib::BigEndian2Int(substr($Header4Bytes, 0, 2)) & 0xFFE0) >> 4;
1796  $MPEGrawHeader['version'] = (ord($Header4Bytes{1}) & 0x18) >> 3; // BB
1797  $MPEGrawHeader['layer'] = (ord($Header4Bytes{1}) & 0x06) >> 1; // CC
1798  $MPEGrawHeader['protection'] = (ord($Header4Bytes{1}) & 0x01); // D
1799  $MPEGrawHeader['bitrate'] = (ord($Header4Bytes{2}) & 0xF0) >> 4; // EEEE
1800  $MPEGrawHeader['sample_rate'] = (ord($Header4Bytes{2}) & 0x0C) >> 2; // FF
1801  $MPEGrawHeader['padding'] = (ord($Header4Bytes{2}) & 0x02) >> 1; // G
1802  $MPEGrawHeader['private'] = (ord($Header4Bytes{2}) & 0x01); // H
1803  $MPEGrawHeader['channelmode'] = (ord($Header4Bytes{3}) & 0xC0) >> 6; // II
1804  $MPEGrawHeader['modeextension'] = (ord($Header4Bytes{3}) & 0x30) >> 4; // JJ
1805  $MPEGrawHeader['copyright'] = (ord($Header4Bytes{3}) & 0x08) >> 3; // K
1806  $MPEGrawHeader['original'] = (ord($Header4Bytes{3}) & 0x04) >> 2; // L
1807  $MPEGrawHeader['emphasis'] = (ord($Header4Bytes{3}) & 0x03); // MM
1808 
1809  return $MPEGrawHeader;
1810  }
static BigEndian2Int($byteword, $synchsafe=false, $signed=false)
Definition: getid3.lib.php:263
+ Here is the call graph for this function:

◆ MPEGaudioHeaderValid()

static getid3_mp3::MPEGaudioHeaderValid (   $rawarray,
  $echoerrors = false,
  $allowBitrate15 = false 
)
static

Definition at line 1703 of file module.audio.mp3.php.

1703  {
1704  if (($rawarray['synch'] & 0x0FFE) != 0x0FFE) {
1705  return false;
1706  }
1707 
1708  static $MPEGaudioVersionLookup;
1709  static $MPEGaudioLayerLookup;
1710  static $MPEGaudioBitrateLookup;
1711  static $MPEGaudioFrequencyLookup;
1712  static $MPEGaudioChannelModeLookup;
1713  static $MPEGaudioModeExtensionLookup;
1714  static $MPEGaudioEmphasisLookup;
1715  if (empty($MPEGaudioVersionLookup)) {
1716  $MPEGaudioVersionLookup = self::MPEGaudioVersionArray();
1717  $MPEGaudioLayerLookup = self::MPEGaudioLayerArray();
1718  $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray();
1719  $MPEGaudioFrequencyLookup = self::MPEGaudioFrequencyArray();
1720  $MPEGaudioChannelModeLookup = self::MPEGaudioChannelModeArray();
1721  $MPEGaudioModeExtensionLookup = self::MPEGaudioModeExtensionArray();
1722  $MPEGaudioEmphasisLookup = self::MPEGaudioEmphasisArray();
1723  }
1724 
1725  if (isset($MPEGaudioVersionLookup[$rawarray['version']])) {
1726  $decodedVersion = $MPEGaudioVersionLookup[$rawarray['version']];
1727  } else {
1728  echo ($echoerrors ? "\n".'invalid Version ('.$rawarray['version'].')' : '');
1729  return false;
1730  }
1731  if (isset($MPEGaudioLayerLookup[$rawarray['layer']])) {
1732  $decodedLayer = $MPEGaudioLayerLookup[$rawarray['layer']];
1733  } else {
1734  echo ($echoerrors ? "\n".'invalid Layer ('.$rawarray['layer'].')' : '');
1735  return false;
1736  }
1737  if (!isset($MPEGaudioBitrateLookup[$decodedVersion][$decodedLayer][$rawarray['bitrate']])) {
1738  echo ($echoerrors ? "\n".'invalid Bitrate ('.$rawarray['bitrate'].')' : '');
1739  if ($rawarray['bitrate'] == 15) {
1740  // known issue in LAME 3.90 - 3.93.1 where free-format has bitrate ID of 15 instead of 0
1741  // let it go through here otherwise file will not be identified
1742  if (!$allowBitrate15) {
1743  return false;
1744  }
1745  } else {
1746  return false;
1747  }
1748  }
1749  if (!isset($MPEGaudioFrequencyLookup[$decodedVersion][$rawarray['sample_rate']])) {
1750  echo ($echoerrors ? "\n".'invalid Frequency ('.$rawarray['sample_rate'].')' : '');
1751  return false;
1752  }
1753  if (!isset($MPEGaudioChannelModeLookup[$rawarray['channelmode']])) {
1754  echo ($echoerrors ? "\n".'invalid ChannelMode ('.$rawarray['channelmode'].')' : '');
1755  return false;
1756  }
1757  if (!isset($MPEGaudioModeExtensionLookup[$decodedLayer][$rawarray['modeextension']])) {
1758  echo ($echoerrors ? "\n".'invalid Mode Extension ('.$rawarray['modeextension'].')' : '');
1759  return false;
1760  }
1761  if (!isset($MPEGaudioEmphasisLookup[$rawarray['emphasis']])) {
1762  echo ($echoerrors ? "\n".'invalid Emphasis ('.$rawarray['emphasis'].')' : '');
1763  return false;
1764  }
1765  // These are just either set or not set, you can't mess that up :)
1766  // $rawarray['protection'];
1767  // $rawarray['padding'];
1768  // $rawarray['private'];
1769  // $rawarray['copyright'];
1770  // $rawarray['original'];
1771 
1772  return true;
1773  }

◆ MPEGaudioLayerArray()

static getid3_mp3::MPEGaudioLayerArray ( )
static

Definition at line 1641 of file module.audio.mp3.php.

1641  {
1642  static $MPEGaudioLayer = array(false, 3, 2, 1);
1643  return $MPEGaudioLayer;
1644  }

◆ MPEGaudioModeExtensionArray()

static getid3_mp3::MPEGaudioModeExtensionArray ( )
static

Definition at line 1682 of file module.audio.mp3.php.

1682  {
1683  static $MPEGaudioModeExtension;
1684  if (empty($MPEGaudioModeExtension)) {
1685  $MPEGaudioModeExtension = array (
1686  1 => array('4-31', '8-31', '12-31', '16-31'),
1687  2 => array('4-31', '8-31', '12-31', '16-31'),
1688  3 => array('', 'IS', 'MS', 'IS+MS')
1689  );
1690  }
1691  return $MPEGaudioModeExtension;
1692  }

◆ MPEGaudioVersionArray()

static getid3_mp3::MPEGaudioVersionArray ( )
static

Definition at line 1636 of file module.audio.mp3.php.

1636  {
1637  static $MPEGaudioVersion = array('2.5', false, '2', '1');
1638  return $MPEGaudioVersion;
1639  }

◆ RecursiveFrameScanning()

getid3_mp3::RecursiveFrameScanning ( $offset,
$nextframetestoffset,
  $ScanAsCBR 
)

Definition at line 1085 of file module.audio.mp3.php.

References $i, $info, decodeMPEGaudioHeader(), getid3_handler\error(), GETID3_MP3_VALID_CHECK_FRAMES, and getid3_handler\warning().

Referenced by decodeMPEGaudioHeader().

1085  {
1086  $info = &$this->getid3->info;
1087  $firstframetestarray = array('error' => array(), 'warning'=> array(), 'avdataend' => $info['avdataend'], 'avdataoffset' => $info['avdataoffset']);
1088  $this->decodeMPEGaudioHeader($offset, $firstframetestarray, false);
1089 
1090  for ($i = 0; $i < GETID3_MP3_VALID_CHECK_FRAMES; $i++) {
1091  // check next GETID3_MP3_VALID_CHECK_FRAMES frames for validity, to make sure we haven't run across a false synch
1092  if (($nextframetestoffset + 4) >= $info['avdataend']) {
1093  // end of file
1094  return true;
1095  }
1096 
1097  $nextframetestarray = array('error' => array(), 'warning' => array(), 'avdataend' => $info['avdataend'], 'avdataoffset'=>$info['avdataoffset']);
1098  if ($this->decodeMPEGaudioHeader($nextframetestoffset, $nextframetestarray, false)) {
1099  if ($ScanAsCBR) {
1100  // force CBR mode, used for trying to pick out invalid audio streams with valid(?) VBR headers, or VBR streams with no VBR header
1101  if (!isset($nextframetestarray['mpeg']['audio']['bitrate']) || !isset($firstframetestarray['mpeg']['audio']['bitrate']) || ($nextframetestarray['mpeg']['audio']['bitrate'] != $firstframetestarray['mpeg']['audio']['bitrate'])) {
1102  return false;
1103  }
1104  }
1105 
1106 
1107  // next frame is OK, get ready to check the one after that
1108  if (isset($nextframetestarray['mpeg']['audio']['framelength']) && ($nextframetestarray['mpeg']['audio']['framelength'] > 0)) {
1109  $nextframetestoffset += $nextframetestarray['mpeg']['audio']['framelength'];
1110  } else {
1111  $this->error('Frame at offset ('.$offset.') is has an invalid frame length.');
1112  return false;
1113  }
1114 
1115  } elseif (!empty($firstframetestarray['mpeg']['audio']['framelength']) && (($nextframetestoffset + $firstframetestarray['mpeg']['audio']['framelength']) > $info['avdataend'])) {
1116 
1117  // it's not the end of the file, but there's not enough data left for another frame, so assume it's garbage/padding and return OK
1118  return true;
1119 
1120  } else {
1121 
1122  // next frame is not valid, note the error and fail, so scanning can contiue for a valid frame sequence
1123  $this->warning('Frame at offset ('.$offset.') is valid, but the next one at ('.$nextframetestoffset.') is not.');
1124 
1125  return false;
1126  }
1127  }
1128  return true;
1129  }
error($text)
Definition: getid3.php:1752
warning($text)
Definition: getid3.php:1758
decodeMPEGaudioHeader($offset, &$info, $recursivesearch=true, $ScanAsCBR=false, $FastMPEGheaderScan=false)
$i
Definition: disco.tpl.php:19
$info
Definition: index.php:5
const GETID3_MP3_VALID_CHECK_FRAMES
getID3() by James Heinrich info@getid3.org //
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ XingVBRidOffset()

static getid3_mp3::XingVBRidOffset (   $version,
  $channelmode 
)
static

Definition at line 1893 of file module.audio.mp3.php.

References $version.

1893  {
1894  static $XingVBRidOffsetCache = array();
1895  if (empty($XingVBRidOffset)) {
1896  $XingVBRidOffset = array (
1897  '1' => array ('mono' => 0x15, // 4 + 17 = 21
1898  'stereo' => 0x24, // 4 + 32 = 36
1899  'joint stereo' => 0x24,
1900  'dual channel' => 0x24
1901  ),
1902 
1903  '2' => array ('mono' => 0x0D, // 4 + 9 = 13
1904  'stereo' => 0x15, // 4 + 17 = 21
1905  'joint stereo' => 0x15,
1906  'dual channel' => 0x15
1907  ),
1908 
1909  '2.5' => array ('mono' => 0x15,
1910  'stereo' => 0x15,
1911  'joint stereo' => 0x15,
1912  'dual channel' => 0x15
1913  )
1914  );
1915  }
1916  return $XingVBRidOffset[$version][$channelmode];
1917  }
$version
Definition: build.php:27

Field Documentation

◆ $allow_bruteforce

getid3_mp3::$allow_bruteforce = false

Definition at line 28 of file module.audio.mp3.php.


The documentation for this class was generated from the following file: