[ PHPXref.com ] [ Generated: Sun Jul 20 17:58:47 2008 ] [ getID3() 1.7.6 ]
[ Index ]     [ Variables ]     [ Functions ]     [ Classes ]     [ Constants ]     [ Statistics ]

title

Body

[close]

/getid3/ -> module.audio.ogg.php (source)

   1  <?php
   2  /////////////////////////////////////////////////////////////////
   3  /// getID3() by James Heinrich <info@getid3.org>               //
   4  //  available at http://getid3.sourceforge.net                 //
   5  //            or http://www.getid3.org                         //
   6  /////////////////////////////////////////////////////////////////
   7  // See readme.txt for more details                             //
   8  /////////////////////////////////////////////////////////////////
   9  //                                                             //
  10  // module.audio.ogg.php                                        //
  11  // module for analyzing Ogg Vorbis, OggFLAC and Speex files    //
  12  // dependencies: module.audio.flac.php                         //
  13  //                                                            ///
  14  /////////////////////////////////////////////////////////////////
  15  
  16  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.flac.php', __FILE__, true);
  17  
  18  class getid3_ogg
  19  {
  20  
  21  	function getid3_ogg(&$fd, &$ThisFileInfo) {
  22  
  23          $ThisFileInfo['fileformat'] = 'ogg';
  24  
  25          // Warn about illegal tags - only vorbiscomments are allowed
  26          if (isset($ThisFileInfo['id3v2'])) {
  27              $ThisFileInfo['warning'][] = 'Illegal ID3v2 tag present.';
  28          }
  29          if (isset($ThisFileInfo['id3v1'])) {
  30              $ThisFileInfo['warning'][] = 'Illegal ID3v1 tag present.';
  31          }
  32          if (isset($ThisFileInfo['ape'])) {
  33              $ThisFileInfo['warning'][] = 'Illegal APE tag present.';
  34          }
  35  
  36  
  37          // Page 1 - Stream Header
  38  
  39          fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
  40  
  41          $oggpageinfo = getid3_ogg::ParseOggPageHeader($fd);
  42          $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
  43  
  44          if (ftell($fd) >= GETID3_FREAD_BUFFER_SIZE) {
  45              $ThisFileInfo['error'][] = 'Could not find start of Ogg page in the first '.GETID3_FREAD_BUFFER_SIZE.' bytes (this might not be an Ogg-Vorbis file?)';
  46              unset($ThisFileInfo['fileformat']);
  47              unset($ThisFileInfo['ogg']);
  48              return false;
  49          }
  50  
  51          $filedata = fread($fd, $oggpageinfo['page_length']);
  52          $filedataoffset = 0;
  53  
  54          if (substr($filedata, 0, 4) == 'fLaC') {
  55  
  56              $ThisFileInfo['audio']['dataformat']   = 'flac';
  57              $ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
  58              $ThisFileInfo['audio']['lossless']     = true;
  59  
  60          } elseif (substr($filedata, 1, 6) == 'vorbis') {
  61  
  62              $ThisFileInfo['audio']['dataformat'] = 'vorbis';
  63              $ThisFileInfo['audio']['lossless']   = false;
  64  
  65              $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['packet_type'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
  66              $filedataoffset += 1;
  67              $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['stream_type'] = substr($filedata, $filedataoffset, 6); // hard-coded to 'vorbis'
  68              $filedataoffset += 6;
  69              $ThisFileInfo['ogg']['bitstreamversion'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
  70              $filedataoffset += 4;
  71              $ThisFileInfo['ogg']['numberofchannels'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
  72              $filedataoffset += 1;
  73              $ThisFileInfo['audio']['channels']                = $ThisFileInfo['ogg']['numberofchannels'];
  74              $ThisFileInfo['ogg']['samplerate']       = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
  75              $filedataoffset += 4;
  76              if ($ThisFileInfo['ogg']['samplerate'] == 0) {
  77                  $ThisFileInfo['error'][] = 'Corrupt Ogg file: sample rate == zero';
  78                  return false;
  79              }
  80              $ThisFileInfo['audio']['sample_rate']               = $ThisFileInfo['ogg']['samplerate'];
  81              $ThisFileInfo['ogg']['samples']          = 0; // filled in later
  82              $ThisFileInfo['ogg']['bitrate_average']  = 0; // filled in later
  83              $ThisFileInfo['ogg']['bitrate_max']      = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
  84              $filedataoffset += 4;
  85              $ThisFileInfo['ogg']['bitrate_nominal']  = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
  86              $filedataoffset += 4;
  87              $ThisFileInfo['ogg']['bitrate_min']      = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
  88              $filedataoffset += 4;
  89              $ThisFileInfo['ogg']['blocksize_small']  = pow(2,  getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)) & 0x0F);
  90              $ThisFileInfo['ogg']['blocksize_large']  = pow(2, (getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)) & 0xF0) >> 4);
  91              $ThisFileInfo['ogg']['stop_bit']         = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); // must be 1, marks end of packet
  92  
  93              $ThisFileInfo['audio']['bitrate_mode'] = 'vbr'; // overridden if actually abr
  94              if ($ThisFileInfo['ogg']['bitrate_max'] == 0xFFFFFFFF) {
  95                  unset($ThisFileInfo['ogg']['bitrate_max']);
  96                  $ThisFileInfo['audio']['bitrate_mode'] = 'abr';
  97              }
  98              if ($ThisFileInfo['ogg']['bitrate_nominal'] == 0xFFFFFFFF) {
  99                  unset($ThisFileInfo['ogg']['bitrate_nominal']);
 100              }
 101              if ($ThisFileInfo['ogg']['bitrate_min'] == 0xFFFFFFFF) {
 102                  unset($ThisFileInfo['ogg']['bitrate_min']);
 103                  $ThisFileInfo['audio']['bitrate_mode'] = 'abr';
 104              }
 105  
 106          } elseif (substr($filedata, 0, 8) == 'Speex   ') {
 107  
 108              // http://www.speex.org/manual/node10.html
 109  
 110              $ThisFileInfo['audio']['dataformat']   = 'speex';
 111              $ThisFileInfo['mime_type']             = 'audio/speex';
 112              $ThisFileInfo['audio']['bitrate_mode'] = 'abr';
 113              $ThisFileInfo['audio']['lossless']     = false;
 114  
 115              $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_string']           =                  substr($filedata, $filedataoffset, 8); // hard-coded to 'Speex   '
 116              $filedataoffset += 8;
 117              $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version']          =                  substr($filedata, $filedataoffset, 20);
 118              $filedataoffset += 20;
 119              $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version_id']       = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
 120              $filedataoffset += 4;
 121              $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['header_size']            = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
 122              $filedataoffset += 4;
 123              $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['rate']                   = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
 124              $filedataoffset += 4;
 125              $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode']                   = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
 126              $filedataoffset += 4;
 127              $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode_bitstream_version'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
 128              $filedataoffset += 4;
 129              $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['nb_channels']            = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
 130              $filedataoffset += 4;
 131              $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['bitrate']                = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
 132              $filedataoffset += 4;
 133              $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['framesize']              = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
 134              $filedataoffset += 4;
 135              $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['vbr']                    = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
 136              $filedataoffset += 4;
 137              $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['frames_per_packet']      = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
 138              $filedataoffset += 4;
 139              $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['extra_headers']          = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
 140              $filedataoffset += 4;
 141              $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['reserved1']              = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
 142              $filedataoffset += 4;
 143              $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['reserved2']              = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
 144              $filedataoffset += 4;
 145  
 146              $ThisFileInfo['speex']['speex_version'] = trim($ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version']);
 147              $ThisFileInfo['speex']['sample_rate']   = $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['rate'];
 148              $ThisFileInfo['speex']['channels']      = $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['nb_channels'];
 149              $ThisFileInfo['speex']['vbr']           = (bool) $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['vbr'];
 150              $ThisFileInfo['speex']['band_type']     = getid3_ogg::SpeexBandModeLookup($ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode']);
 151  
 152              $ThisFileInfo['audio']['sample_rate']   = $ThisFileInfo['speex']['sample_rate'];
 153              $ThisFileInfo['audio']['channels']      = $ThisFileInfo['speex']['channels'];
 154              if ($ThisFileInfo['speex']['vbr']) {
 155                  $ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
 156              }
 157  
 158          } else {
 159  
 160              $ThisFileInfo['error'][] = 'Expecting either "Speex   " or "vorbis" identifier strings, found neither';
 161              unset($ThisFileInfo['ogg']);
 162              unset($ThisFileInfo['mime_type']);
 163              return false;
 164  
 165          }
 166  
 167  
 168          // Page 2 - Comment Header
 169  
 170          $oggpageinfo = getid3_ogg::ParseOggPageHeader($fd);
 171          $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
 172  
 173          switch ($ThisFileInfo['audio']['dataformat']) {
 174  
 175              case 'vorbis':
 176                  $filedata = fread($fd, $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
 177                  $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['packet_type'] = getid3_lib::LittleEndian2Int(substr($filedata, 0, 1));
 178                  $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['stream_type'] =                  substr($filedata, 1, 6); // hard-coded to 'vorbis'
 179  
 180                  getid3_ogg::ParseVorbisCommentsFilepointer($fd, $ThisFileInfo);
 181                  break;
 182  
 183              case 'flac':
 184                  if (!getid3_flac::FLACparseMETAdata($fd, $ThisFileInfo)) {
 185                      $ThisFileInfo['error'][] = 'Failed to parse FLAC headers';
 186                      return false;
 187                  }
 188                  break;
 189  
 190              case 'speex':
 191                  fseek($fd, $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length'], SEEK_CUR);
 192                  getid3_ogg::ParseVorbisCommentsFilepointer($fd, $ThisFileInfo);
 193                  break;
 194  
 195          }
 196  
 197  
 198  
 199          // Last Page - Number of Samples
 200  
 201          fseek($fd, max($ThisFileInfo['avdataend'] - GETID3_FREAD_BUFFER_SIZE, 0), SEEK_SET);
 202          $LastChunkOfOgg = strrev(fread($fd, GETID3_FREAD_BUFFER_SIZE));
 203          if ($LastOggSpostion = strpos($LastChunkOfOgg, 'SggO')) {
 204              fseek($fd, $ThisFileInfo['avdataend'] - ($LastOggSpostion + strlen('SggO')), SEEK_SET);
 205              $ThisFileInfo['avdataend'] = ftell($fd);
 206              $ThisFileInfo['ogg']['pageheader']['eos'] = getid3_ogg::ParseOggPageHeader($fd);
 207              $ThisFileInfo['ogg']['samples']   = $ThisFileInfo['ogg']['pageheader']['eos']['pcm_abs_position'];
 208              if ($ThisFileInfo['ogg']['samples'] == 0) {
 209                  $ThisFileInfo['error'][] = 'Corrupt Ogg file: eos.number of samples == zero';
 210                  return false;
 211              }
 212              $ThisFileInfo['ogg']['bitrate_average'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / ($ThisFileInfo['ogg']['samples'] / $ThisFileInfo['audio']['sample_rate']);
 213          }
 214  
 215          if (!empty($ThisFileInfo['ogg']['bitrate_average'])) {
 216              $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['ogg']['bitrate_average'];
 217          } elseif (!empty($ThisFileInfo['ogg']['bitrate_nominal'])) {
 218              $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['ogg']['bitrate_nominal'];
 219          } elseif (!empty($ThisFileInfo['ogg']['bitrate_min']) && !empty($ThisFileInfo['ogg']['bitrate_max'])) {
 220              $ThisFileInfo['audio']['bitrate'] = ($ThisFileInfo['ogg']['bitrate_min'] + $ThisFileInfo['ogg']['bitrate_max']) / 2;
 221          }
 222          if (isset($ThisFileInfo['audio']['bitrate']) && !isset($ThisFileInfo['playtime_seconds'])) {
 223              if ($ThisFileInfo['audio']['bitrate'] == 0) {
 224                  $ThisFileInfo['error'][] = 'Corrupt Ogg file: bitrate_audio == zero';
 225                  return false;
 226              }
 227              $ThisFileInfo['playtime_seconds'] = (float) ((($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['audio']['bitrate']);
 228          }
 229  
 230          if (isset($ThisFileInfo['ogg']['vendor'])) {
 231              $ThisFileInfo['audio']['encoder'] = preg_replace('/^Encoded with /', '', $ThisFileInfo['ogg']['vendor']);
 232  
 233              // Vorbis only
 234              if ($ThisFileInfo['audio']['dataformat'] == 'vorbis') {
 235  
 236                  // Vorbis 1.0 starts with Xiph.Org
 237                  if  (preg_match('/^Xiph.Org/', $ThisFileInfo['audio']['encoder'])) {
 238  
 239                      if ($ThisFileInfo['audio']['bitrate_mode'] == 'abr') {
 240  
 241                          // Set -b 128 on abr files
 242                          $ThisFileInfo['audio']['encoder_options'] = '-b '.round($ThisFileInfo['ogg']['bitrate_nominal'] / 1000);
 243  
 244                      } elseif (($ThisFileInfo['audio']['bitrate_mode'] == 'vbr') && ($ThisFileInfo['audio']['channels'] == 2) && ($ThisFileInfo['audio']['sample_rate'] >= 44100) && ($ThisFileInfo['audio']['sample_rate'] <= 48000)) {
 245                          // Set -q N on vbr files
 246                          $ThisFileInfo['audio']['encoder_options'] = '-q '.$this->get_quality_from_nominal_bitrate($ThisFileInfo['ogg']['bitrate_nominal']);
 247  
 248                      }
 249                  }
 250  
 251                  if (empty($ThisFileInfo['audio']['encoder_options']) && !empty($ThisFileInfo['ogg']['bitrate_nominal'])) {
 252                      $ThisFileInfo['audio']['encoder_options'] = 'Nominal bitrate: '.intval(round($ThisFileInfo['ogg']['bitrate_nominal'] / 1000)).'kbps';
 253                  }
 254              }
 255          }
 256  
 257          return true;
 258      }
 259  
 260  
 261  	function ParseOggPageHeader(&$fd) {
 262          // http://xiph.org/ogg/vorbis/doc/framing.html
 263          $oggheader['page_start_offset'] = ftell($fd); // where we started from in the file
 264  
 265          $filedata = fread($fd, GETID3_FREAD_BUFFER_SIZE);
 266          $filedataoffset = 0;
 267          while ((substr($filedata, $filedataoffset++, 4) != 'OggS')) {
 268              if ((ftell($fd) - $oggheader['page_start_offset']) >= GETID3_FREAD_BUFFER_SIZE) {
 269                  // should be found before here
 270                  return false;
 271              }
 272              if ((($filedataoffset + 28) > strlen($filedata)) || (strlen($filedata) < 28)) {
 273                  if (feof($fd) || (($filedata .= fread($fd, GETID3_FREAD_BUFFER_SIZE)) === false)) {
 274                      // get some more data, unless eof, in which case fail
 275                      return false;
 276                  }
 277              }
 278          }
 279          $filedataoffset += strlen('OggS') - 1; // page, delimited by 'OggS'
 280  
 281          $oggheader['stream_structver']  = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
 282          $filedataoffset += 1;
 283          $oggheader['flags_raw']         = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
 284          $filedataoffset += 1;
 285          $oggheader['flags']['fresh']    = (bool) ($oggheader['flags_raw'] & 0x01); // fresh packet
 286          $oggheader['flags']['bos']      = (bool) ($oggheader['flags_raw'] & 0x02); // first page of logical bitstream (bos)
 287          $oggheader['flags']['eos']      = (bool) ($oggheader['flags_raw'] & 0x04); // last page of logical bitstream (eos)
 288  
 289          $oggheader['pcm_abs_position']  = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
 290          $filedataoffset += 8;
 291          $oggheader['stream_serialno']   = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
 292          $filedataoffset += 4;
 293          $oggheader['page_seqno']        = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
 294          $filedataoffset += 4;
 295          $oggheader['page_checksum']     = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
 296          $filedataoffset += 4;
 297          $oggheader['page_segments']     = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
 298          $filedataoffset += 1;
 299          $oggheader['page_length'] = 0;
 300          for ($i = 0; $i < $oggheader['page_segments']; $i++) {
 301              $oggheader['segment_table'][$i] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
 302              $filedataoffset += 1;
 303              $oggheader['page_length'] += $oggheader['segment_table'][$i];
 304          }
 305          $oggheader['header_end_offset'] = $oggheader['page_start_offset'] + $filedataoffset;
 306          $oggheader['page_end_offset']   = $oggheader['header_end_offset'] + $oggheader['page_length'];
 307          fseek($fd, $oggheader['header_end_offset'], SEEK_SET);
 308  
 309          return $oggheader;
 310      }
 311  
 312  
 313  	function ParseVorbisCommentsFilepointer(&$fd, &$ThisFileInfo) {
 314  
 315          $OriginalOffset = ftell($fd);
 316          $CommentStartOffset = $OriginalOffset;
 317          $commentdataoffset = 0;
 318          $VorbisCommentPage = 1;
 319  
 320          switch ($ThisFileInfo['audio']['dataformat']) {
 321              case 'vorbis':
 322                  $CommentStartOffset = $ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage]['page_start_offset'];  // Second Ogg page, after header block
 323                  fseek($fd, $CommentStartOffset, SEEK_SET);
 324                  $commentdataoffset = 27 + $ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage]['page_segments'];
 325                  $commentdata = fread($fd, getid3_ogg::OggPageSegmentLength($ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage], 1) + $commentdataoffset);
 326  
 327                  $commentdataoffset += (strlen('vorbis') + 1);
 328                  break;
 329  
 330              case 'flac':
 331                  fseek($fd, $ThisFileInfo['flac']['VORBIS_COMMENT']['raw']['offset'] + 4, SEEK_SET);
 332                  $commentdata = fread($fd, $ThisFileInfo['flac']['VORBIS_COMMENT']['raw']['block_length']);
 333                  break;
 334  
 335              case 'speex':
 336                  $CommentStartOffset = $ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage]['page_start_offset'];  // Second Ogg page, after header block
 337                  fseek($fd, $CommentStartOffset, SEEK_SET);
 338                  $commentdataoffset = 27 + $ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage]['page_segments'];
 339                  $commentdata = fread($fd, getid3_ogg::OggPageSegmentLength($ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage], 1) + $commentdataoffset);
 340                  break;
 341  
 342              default:
 343                  return false;
 344                  break;
 345          }
 346  
 347          $VendorSize = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));
 348          $commentdataoffset += 4;
 349  
 350          $ThisFileInfo['ogg']['vendor'] = substr($commentdata, $commentdataoffset, $VendorSize);
 351          $commentdataoffset += $VendorSize;
 352  
 353          $CommentsCount = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));
 354          $commentdataoffset += 4;
 355          $ThisFileInfo['avdataoffset'] = $CommentStartOffset + $commentdataoffset;
 356  
 357          $basicfields = array('TITLE', 'ARTIST', 'ALBUM', 'TRACKNUMBER', 'GENRE', 'DATE', 'DESCRIPTION', 'COMMENT');
 358          for ($i = 0; $i < $CommentsCount; $i++) {
 359  
 360              $ThisFileInfo['ogg']['comments_raw'][$i]['dataoffset'] = $CommentStartOffset + $commentdataoffset;
 361  
 362              if (ftell($fd) < ($ThisFileInfo['ogg']['comments_raw'][$i]['dataoffset'] + 4)) {
 363                  $VorbisCommentPage++;
 364  
 365                  $oggpageinfo = getid3_ogg::ParseOggPageHeader($fd);
 366                  $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
 367  
 368                  // First, save what we haven't read yet
 369                  $AsYetUnusedData = substr($commentdata, $commentdataoffset);
 370  
 371                  // Then take that data off the end
 372                  $commentdata     = substr($commentdata, 0, $commentdataoffset);
 373  
 374                  // Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct
 375                  $commentdata .= str_repeat("\x00", 27 + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
 376                  $commentdataoffset += (27 + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
 377  
 378                  // Finally, stick the unused data back on the end
 379                  $commentdata .= $AsYetUnusedData;
 380  
 381                  //$commentdata .= fread($fd, $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
 382                  $commentdata .= fread($fd, getid3_ogg::OggPageSegmentLength($ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage], 1));
 383  
 384              }
 385              $ThisFileInfo['ogg']['comments_raw'][$i]['size']       = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));
 386  
 387              // replace avdataoffset with position just after the last vorbiscomment
 388              $ThisFileInfo['avdataoffset'] = $ThisFileInfo['ogg']['comments_raw'][$i]['dataoffset'] + $ThisFileInfo['ogg']['comments_raw'][$i]['size'] + 4;
 389  
 390              $commentdataoffset += 4;
 391              while ((strlen($commentdata) - $commentdataoffset) < $ThisFileInfo['ogg']['comments_raw'][$i]['size']) {
 392                  if (($ThisFileInfo['ogg']['comments_raw'][$i]['size'] > $ThisFileInfo['avdataend']) || ($ThisFileInfo['ogg']['comments_raw'][$i]['size'] < 0)) {
 393                      $ThisFileInfo['error'][] = 'Invalid Ogg comment size (comment #'.$i.', claims to be '.number_format($ThisFileInfo['ogg']['comments_raw'][$i]['size']).' bytes) - aborting reading comments';
 394                      break 2;
 395                  }
 396  
 397                  $VorbisCommentPage++;
 398  
 399                  $oggpageinfo = getid3_ogg::ParseOggPageHeader($fd);
 400                  $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
 401  
 402                  // First, save what we haven't read yet
 403                  $AsYetUnusedData = substr($commentdata, $commentdataoffset);
 404  
 405                  // Then take that data off the end
 406                  $commentdata     = substr($commentdata, 0, $commentdataoffset);
 407  
 408                  // Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct
 409                  $commentdata .= str_repeat("\x00", 27 + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
 410                  $commentdataoffset += (27 + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
 411  
 412                  // Finally, stick the unused data back on the end
 413                  $commentdata .= $AsYetUnusedData;
 414  
 415                  //$commentdata .= fread($fd, $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
 416                  $commentdata .= fread($fd, getid3_ogg::OggPageSegmentLength($ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage], 1));
 417  
 418                  //$filebaseoffset += $oggpageinfo['header_end_offset'] - $oggpageinfo['page_start_offset'];
 419              }
 420              $commentstring = substr($commentdata, $commentdataoffset, $ThisFileInfo['ogg']['comments_raw'][$i]['size']);
 421              $commentdataoffset += $ThisFileInfo['ogg']['comments_raw'][$i]['size'];
 422  
 423              if (!$commentstring) {
 424  
 425                  // no comment?
 426                  $ThisFileInfo['warning'][] = 'Blank Ogg comment ['.$i.']';
 427  
 428              } elseif (strstr($commentstring, '=')) {
 429  
 430                  $commentexploded = explode('=', $commentstring, 2);
 431                  $ThisFileInfo['ogg']['comments_raw'][$i]['key']   = strtoupper($commentexploded[0]);
 432                  $ThisFileInfo['ogg']['comments_raw'][$i]['value'] = @$commentexploded[1];
 433                  $ThisFileInfo['ogg']['comments_raw'][$i]['data']  = base64_decode($ThisFileInfo['ogg']['comments_raw'][$i]['value']);
 434  
 435                  $ThisFileInfo['ogg']['comments'][strtolower($ThisFileInfo['ogg']['comments_raw'][$i]['key'])][] = $ThisFileInfo['ogg']['comments_raw'][$i]['value'];
 436  
 437                  $imagechunkcheck = getid3_lib::GetDataImageSize($ThisFileInfo['ogg']['comments_raw'][$i]['data']);
 438                  $ThisFileInfo['ogg']['comments_raw'][$i]['image_mime'] = getid3_lib::image_type_to_mime_type($imagechunkcheck[2]);
 439                  if (!$ThisFileInfo['ogg']['comments_raw'][$i]['image_mime'] || ($ThisFileInfo['ogg']['comments_raw'][$i]['image_mime'] == 'application/octet-stream')) {
 440                      unset($ThisFileInfo['ogg']['comments_raw'][$i]['image_mime']);
 441                      unset($ThisFileInfo['ogg']['comments_raw'][$i]['data']);
 442                  }
 443  
 444              } else {
 445  
 446                  $ThisFileInfo['warning'][] = '[known problem with CDex >= v1.40, < v1.50b7] Invalid Ogg comment name/value pair ['.$i.']: '.$commentstring;
 447  
 448              }
 449          }
 450  
 451  
 452          // Replay Gain Adjustment
 453          // http://privatewww.essex.ac.uk/~djmrob/replaygain/
 454          if (isset($ThisFileInfo['ogg']['comments']) && is_array($ThisFileInfo['ogg']['comments'])) {
 455              foreach ($ThisFileInfo['ogg']['comments'] as $index => $commentvalue) {
 456                  switch ($index) {
 457                      case 'rg_audiophile':
 458                      case 'replaygain_album_gain':
 459                          $ThisFileInfo['replay_gain']['album']['adjustment'] = (double) $commentvalue[0];
 460                          unset($ThisFileInfo['ogg']['comments'][$index]);
 461                          break;
 462  
 463                      case 'rg_radio':
 464                      case 'replaygain_track_gain':
 465                          $ThisFileInfo['replay_gain']['track']['adjustment'] = (double) $commentvalue[0];
 466                          unset($ThisFileInfo['ogg']['comments'][$index]);
 467                          break;
 468  
 469                      case 'replaygain_album_peak':
 470                          $ThisFileInfo['replay_gain']['album']['peak'] = (double) $commentvalue[0];
 471                          unset($ThisFileInfo['ogg']['comments'][$index]);
 472                          break;
 473  
 474                      case 'rg_peak':
 475                      case 'replaygain_track_peak':
 476                          $ThisFileInfo['replay_gain']['track']['peak'] = (double) $commentvalue[0];
 477                          unset($ThisFileInfo['ogg']['comments'][$index]);
 478                          break;
 479  
 480  
 481                      default:
 482                          // do nothing
 483                          break;
 484                  }
 485              }
 486          }
 487  
 488          fseek($fd, $OriginalOffset, SEEK_SET);
 489  
 490          return true;
 491      }
 492  
 493  	function SpeexBandModeLookup($mode) {
 494          static $SpeexBandModeLookup = array();
 495          if (empty($SpeexBandModeLookup)) {
 496              $SpeexBandModeLookup[0] = 'narrow';
 497              $SpeexBandModeLookup[1] = 'wide';
 498              $SpeexBandModeLookup[2] = 'ultra-wide';
 499          }
 500          return (isset($SpeexBandModeLookup[$mode]) ? $SpeexBandModeLookup[$mode] : null);
 501      }
 502  
 503  
 504  	function OggPageSegmentLength($OggInfoArray, $SegmentNumber=1) {
 505          for ($i = 0; $i < $SegmentNumber; $i++) {
 506              $segmentlength = 0;
 507              foreach ($OggInfoArray['segment_table'] as $key => $value) {
 508                  $segmentlength += $value;
 509                  if ($value < 255) {
 510                      break;
 511                  }
 512              }
 513          }
 514          return $segmentlength;
 515      }
 516  
 517  
 518  	function get_quality_from_nominal_bitrate($nominal_bitrate) {
 519  
 520          // decrease precision
 521          $nominal_bitrate = $nominal_bitrate / 1000;
 522  
 523          if ($nominal_bitrate < 128) {
 524              // q-1 to q4
 525              $qval = ($nominal_bitrate - 64) / 16;
 526          } elseif ($nominal_bitrate < 256) {
 527              // q4 to q8
 528              $qval = $nominal_bitrate / 32;
 529          } elseif ($nominal_bitrate < 320) {
 530              // q8 to q9
 531              $qval = ($nominal_bitrate + 256) / 64;
 532          } else {
 533              // q9 to q10
 534              $qval = ($nominal_bitrate + 1300) / 180;
 535          }
 536          //return $qval; // 5.031324
 537          //return intval($qval); // 5
 538          return round($qval, 1); // 5 or 4.9
 539      }
 540  
 541  }
 542  
 543  ?>


[ Powered by PHPXref - Served by Debian GNU/Linux ]