22                                  {
   23                $info = &$this->getid3->info;
 
   24 
   25                $info[
'fileformat'] = 
'ogg';
 
   26 
   27                
   28                if (isset(
$info[
'id3v2'])) {
 
   29                        $this->
warning(
'Illegal ID3v2 tag present.');
 
   30                }
   31                if (isset(
$info[
'id3v1'])) {
 
   32                        $this->
warning(
'Illegal ID3v1 tag present.');
 
   33                }
   34                if (isset(
$info[
'ape'])) {
 
   35                        $this->
warning(
'Illegal APE tag present.');
 
   36                }
   37 
   38 
   39                
   40 
   42 
   44                $info[
'ogg'][
'pageheader'][$oggpageinfo[
'page_seqno']] = $oggpageinfo;
 
   45 
   46                if ($this->
ftell() >= $this->getid3->fread_buffer_size()) {
 
   47                        $this->
error(
'Could not find start of Ogg page in the first '.$this->getid3->fread_buffer_size().
' bytes (this might not be an Ogg-Vorbis file?)');
 
   48                        unset(
$info[
'fileformat']);
 
   50                        return false;
   51                }
   52 
   53                $filedata = $this->
fread($oggpageinfo[
'page_length']);
 
   54                $filedataoffset = 0;
   55 
   56                if (substr($filedata, 0, 4) == 'fLaC') {
   57 
   58                        $info[
'audio'][
'dataformat']   = 
'flac';
 
   59                        $info[
'audio'][
'bitrate_mode'] = 
'vbr';
 
   60                        $info[
'audio'][
'lossless']     = 
true;
 
   61 
   62                } elseif (substr($filedata, 1, 6) == 'vorbis') {
   63 
   65 
   66                } elseif (substr($filedata, 0, 8) == 'OpusHead') {
   67 
   69                                return false;
   70                        }
   71 
   72                } elseif (substr($filedata, 0, 8) == 'Speex   ') {
   73 
   74                        
   75 
   76                        $info[
'audio'][
'dataformat']   = 
'speex';
 
   77                        $info[
'mime_type']             = 
'audio/speex';
 
   78                        $info[
'audio'][
'bitrate_mode'] = 
'abr';
 
   79                        $info[
'audio'][
'lossless']     = 
false;
 
   80 
   81                        $info[
'ogg'][
'pageheader'][$oggpageinfo[
'page_seqno']][
'speex_string']           =                              substr($filedata, $filedataoffset, 8); 
 
   82                        $filedataoffset += 8;
   83                        $info[
'ogg'][
'pageheader'][$oggpageinfo[
'page_seqno']][
'speex_version']          =                              substr($filedata, $filedataoffset, 20);
 
   84                        $filedataoffset += 20;
   86                        $filedataoffset += 4;
   88                        $filedataoffset += 4;
   90                        $filedataoffset += 4;
   92                        $filedataoffset += 4;
   94                        $filedataoffset += 4;
   96                        $filedataoffset += 4;
   98                        $filedataoffset += 4;
  100                        $filedataoffset += 4;
  102                        $filedataoffset += 4;
  104                        $filedataoffset += 4;
  106                        $filedataoffset += 4;
  108                        $filedataoffset += 4;
  110                        $filedataoffset += 4;
  111 
  112                        $info[
'speex'][
'speex_version'] = trim(
$info[
'ogg'][
'pageheader'][$oggpageinfo[
'page_seqno']][
'speex_version']);
 
  113                        $info[
'speex'][
'sample_rate']   = 
$info[
'ogg'][
'pageheader'][$oggpageinfo[
'page_seqno']][
'rate'];
 
  114                        $info[
'speex'][
'channels']      = 
$info[
'ogg'][
'pageheader'][$oggpageinfo[
'page_seqno']][
'nb_channels'];
 
  115                        $info[
'speex'][
'vbr']           = (bool) 
$info[
'ogg'][
'pageheader'][$oggpageinfo[
'page_seqno']][
'vbr'];
 
  117 
  118                        $info[
'audio'][
'sample_rate']   = 
$info[
'speex'][
'sample_rate'];
 
  119                        $info[
'audio'][
'channels']      = 
$info[
'speex'][
'channels'];
 
  120                        if (
$info[
'speex'][
'vbr']) {
 
  121                                $info[
'audio'][
'bitrate_mode'] = 
'vbr';
 
  122                        }
  123 
  124                } elseif (substr($filedata, 0, 7) == "\x80".'theora') {
  125 
  126                        
  127 
  128                        $info[
'ogg'][
'pageheader'][
'theora'][
'theora_magic']             =                           substr($filedata, $filedataoffset,  7); 
 
  129                        $filedataoffset += 7;
  131                        $filedataoffset += 1;
  133                        $filedataoffset += 1;
  135                        $filedataoffset += 1;
  137                        $filedataoffset += 2;
  139                        $filedataoffset += 2;
  141                        $filedataoffset += 3;
  143                        $filedataoffset += 3;
  145                        $filedataoffset += 1;
  147                        $filedataoffset += 1;
  149                        $filedataoffset += 4;
  151                        $filedataoffset += 4;
  153                        $filedataoffset += 3;
  155                        $filedataoffset += 3;
  157                        $filedataoffset += 1;
  159                        $filedataoffset += 3;
  161                        $filedataoffset += 2;
  162 
  163                        $info[
'ogg'][
'pageheader'][
'theora'][
'quality']         = (
$info[
'ogg'][
'pageheader'][
'theora'][
'flags'] & 0xFC00) >> 10;
 
  164                        $info[
'ogg'][
'pageheader'][
'theora'][
'kfg_shift']       = (
$info[
'ogg'][
'pageheader'][
'theora'][
'flags'] & 0x03E0) >>  5;
 
  165                        $info[
'ogg'][
'pageheader'][
'theora'][
'pixel_format_id'] = (
$info[
'ogg'][
'pageheader'][
'theora'][
'flags'] & 0x0018) >>  3;
 
  166                        $info[
'ogg'][
'pageheader'][
'theora'][
'reserved']        = (
$info[
'ogg'][
'pageheader'][
'theora'][
'flags'] & 0x0007) >>  0; 
 
  169 
  170                        $info[
'video'][
'dataformat']   = 
'theora';
 
  171                        $info[
'mime_type']             = 
'video/ogg';
 
  172                        
  173                        
  174                        $info[
'video'][
'resolution_x'] = 
$info[
'ogg'][
'pageheader'][
'theora'][
'resolution_x'];
 
  175                        $info[
'video'][
'resolution_y'] = 
$info[
'ogg'][
'pageheader'][
'theora'][
'resolution_y'];
 
  176                        if (
$info[
'ogg'][
'pageheader'][
'theora'][
'frame_rate_denominator'] > 0) {
 
  177                                $info[
'video'][
'frame_rate'] = (float) 
$info[
'ogg'][
'pageheader'][
'theora'][
'frame_rate_numerator'] / 
$info[
'ogg'][
'pageheader'][
'theora'][
'frame_rate_denominator'];
 
  178                        }
  179                        if (
$info[
'ogg'][
'pageheader'][
'theora'][
'pixel_aspect_denominator'] > 0) {
 
  180                                $info[
'video'][
'pixel_aspect_ratio'] = (float) 
$info[
'ogg'][
'pageheader'][
'theora'][
'pixel_aspect_numerator'] / 
$info[
'ogg'][
'pageheader'][
'theora'][
'pixel_aspect_denominator'];
 
  181                        }
  182$this->
warning(
'Ogg Theora (v3) not fully supported in this version of getID3 ['.$this->getid3->version().
'] -- bitrate, playtime and all audio data are currently unavailable');
 
  183 
  184 
  185                } elseif (substr($filedata, 0, 8) == "fishead\x00") {
  186 
  187                        
  188                        
  189                        $filedataoffset += 8;
  191                        $filedataoffset += 2;
  193                        $filedataoffset += 2;
  195                        $filedataoffset += 8;
  197                        $filedataoffset += 8;
  199                        $filedataoffset += 8;
  201                        $filedataoffset += 8;
  203                        $filedataoffset += 20;
  204 
  205                        $info[
'ogg'][
'skeleton'][
'fishead'][
'version']          = 
$info[
'ogg'][
'skeleton'][
'fishead'][
'raw'][
'version_major'].
'.'.
$info[
'ogg'][
'skeleton'][
'fishead'][
'raw'][
'version_minor'];
 
  206                        $info[
'ogg'][
'skeleton'][
'fishead'][
'presentationtime'] = 
$info[
'ogg'][
'skeleton'][
'fishead'][
'raw'][
'presentationtime_numerator'] / 
$info[
'ogg'][
'skeleton'][
'fishead'][
'raw'][
'presentationtime_denominator'];
 
  207                        $info[
'ogg'][
'skeleton'][
'fishead'][
'basetime']         = 
$info[
'ogg'][
'skeleton'][
'fishead'][
'raw'][
'basetime_numerator']         / 
$info[
'ogg'][
'skeleton'][
'fishead'][
'raw'][
'basetime_denominator'];
 
  208                        $info[
'ogg'][
'skeleton'][
'fishead'][
'utc']              = 
$info[
'ogg'][
'skeleton'][
'fishead'][
'raw'][
'utc'];
 
  209 
  210 
  212                        do {
  214                                $info[
'ogg'][
'pageheader'][$oggpageinfo[
'page_seqno'].
'.'.
$counter++] = $oggpageinfo;
 
  215                                $filedata = $this->
fread($oggpageinfo[
'page_length']);
 
  216                                $this->
fseek($oggpageinfo[
'page_end_offset']);
 
  217 
  218                                if (substr($filedata, 0, 8) == "fisbone\x00") {
  219 
  220                                        $filedataoffset = 8;
  222                                        $filedataoffset += 4;
  224                                        $filedataoffset += 4;
  226                                        $filedataoffset += 4;
  228                                        $filedataoffset += 8;
  230                                        $filedataoffset += 8;
  232                                        $filedataoffset += 8;
  234                                        $filedataoffset += 4;
  236                                        $filedataoffset += 1;
  237                                        $info[
'ogg'][
'skeleton'][
'fisbone'][
'raw'][
'padding']                 =                              substr($filedata, $filedataoffset,  3);
 
  238                                        $filedataoffset += 3;
  239 
  240                                } elseif (substr($filedata, 1, 6) == 'theora') {
  241 
  242                                        $info[
'video'][
'dataformat'] = 
'theora1';
 
  243                                        $this->
error(
'Ogg Theora (v1) not correctly handled in this version of getID3 ['.$this->getid3->version().
']');
 
  244                                        
  245 
  246                                } elseif (substr($filedata, 1, 6) == 'vorbis') {
  247 
  249 
  250                                } else {
  251                                        $this->
error(
'unexpected');
 
  252                                        
  253                                }
  254                        
  255                        } while (($oggpageinfo['page_seqno'] == 0) && (substr($filedata, 0, 8) != "fisbone\x00"));
  256 
  257                        $this->
fseek($oggpageinfo[
'page_start_offset']);
 
  258 
  259                        $this->
error(
'Ogg Skeleton not correctly handled in this version of getID3 ['.$this->getid3->version().
']');
 
  260                        
  261 
  262                } else {
  263 
  264                        $this->
error(
'Expecting either "Speex   ", "OpusHead" or "vorbis" identifier strings, found "'.substr($filedata, 0, 8).
'"');
 
  266                        unset(
$info[
'mime_type']);
 
  267                        return false;
  268 
  269                }
  270 
  271                
  273                $info[
'ogg'][
'pageheader'][$oggpageinfo[
'page_seqno']] = $oggpageinfo;
 
  274 
  275                switch (
$info[
'audio'][
'dataformat']) {
 
  276                        case 'vorbis':
  277                                $filedata = $this->
fread(
$info[
'ogg'][
'pageheader'][$oggpageinfo[
'page_seqno']][
'page_length']);
 
  279                                $info[
'ogg'][
'pageheader'][$oggpageinfo[
'page_seqno']][
'stream_type'] =                              substr($filedata, 1, 6); 
 
  280 
  282                                break;
  283 
  284                        case 'flac':
  286                                if (!$flac->parseMETAdata()) {
  287                                        $this->
error(
'Failed to parse FLAC headers');
 
  288                                        return false;
  289                                }
  290                                unset($flac);
  291                                break;
  292 
  293                        case 'speex':
  294                                $this->
fseek(
$info[
'ogg'][
'pageheader'][$oggpageinfo[
'page_seqno']][
'page_length'], SEEK_CUR);
 
  296                                break;
  297 
  298                        case 'opus':
  299                                $filedata = $this->
fread(
$info[
'ogg'][
'pageheader'][$oggpageinfo[
'page_seqno']][
'page_length']);
 
  300                                $info[
'ogg'][
'pageheader'][$oggpageinfo[
'page_seqno']][
'stream_type'] = substr($filedata, 0, 8); 
 
  301                                if(substr($filedata, 0, 8)  != 'OpusTags') {
  302                                        $this->
error(
'Expected "OpusTags" as header but got "'.substr($filedata, 0, 8).
'"');
 
  303                                        return false;
  304                                }
  305 
  307                                break;
  308 
  309                }
  310 
  311                
  313 
  314                        $this->
warning(
'Unable to parse Ogg end chunk file (PHP does not support file operations beyond '.round(PHP_INT_MAX / 1073741824).
'GB)');
 
  315 
  316                } else {
  317 
  318                        $this->
fseek(max(
$info[
'avdataend'] - $this->getid3->fread_buffer_size(), 0));
 
  319                        $LastChunkOfOgg = strrev($this->
fread($this->getid3->fread_buffer_size()));
 
  320                        if ($LastOggSpostion = strpos($LastChunkOfOgg, 'SggO')) {
  321                                $this->
fseek(
$info[
'avdataend'] - ($LastOggSpostion + strlen(
'SggO')));
 
  324                                $info[
'ogg'][
'samples']   = 
$info[
'ogg'][
'pageheader'][
'eos'][
'pcm_abs_position'];
 
  325                                if (
$info[
'ogg'][
'samples'] == 0) {
 
  326                                        $this->
error(
'Corrupt Ogg file: eos.number of samples == zero');
 
  327                                        return false;
  328                                }
  329                                if (!empty(
$info[
'audio'][
'sample_rate'])) {
 
  330                                        $info[
'ogg'][
'bitrate_average'] = ((
$info[
'avdataend'] - 
$info[
'avdataoffset']) * 8) / (
$info[
'ogg'][
'samples'] / 
$info[
'audio'][
'sample_rate']);
 
  331                                }
  332                        }
  333 
  334                }
  335 
  336                if (!empty(
$info[
'ogg'][
'bitrate_average'])) {
 
  337                        $info[
'audio'][
'bitrate'] = 
$info[
'ogg'][
'bitrate_average'];
 
  338                } elseif (!empty(
$info[
'ogg'][
'bitrate_nominal'])) {
 
  339                        $info[
'audio'][
'bitrate'] = 
$info[
'ogg'][
'bitrate_nominal'];
 
  340                } elseif (!empty(
$info[
'ogg'][
'bitrate_min']) && !empty(
$info[
'ogg'][
'bitrate_max'])) {
 
  341                        $info[
'audio'][
'bitrate'] = (
$info[
'ogg'][
'bitrate_min'] + 
$info[
'ogg'][
'bitrate_max']) / 2;
 
  342                }
  343                if (isset(
$info[
'audio'][
'bitrate']) && !isset(
$info[
'playtime_seconds'])) {
 
  344                        if (
$info[
'audio'][
'bitrate'] == 0) {
 
  345                                $this->
error(
'Corrupt Ogg file: bitrate_audio == zero');
 
  346                                return false;
  347                        }
  348                        $info[
'playtime_seconds'] = (float) (((
$info[
'avdataend'] - 
$info[
'avdataoffset']) * 8) / 
$info[
'audio'][
'bitrate']);
 
  349                }
  350 
  351                if (isset(
$info[
'ogg'][
'vendor'])) {
 
  352                        $info[
'audio'][
'encoder'] = preg_replace(
'/^Encoded with /', 
'', 
$info[
'ogg'][
'vendor']);
 
  353 
  354                        
  355                        if (
$info[
'audio'][
'dataformat'] == 
'vorbis') {
 
  356 
  357                                
  358                                if  (preg_match(
'/^Xiph.Org/', 
$info[
'audio'][
'encoder'])) {
 
  359 
  360                                        if (
$info[
'audio'][
'bitrate_mode'] == 
'abr') {
 
  361 
  362                                                
  363                                                $info[
'audio'][
'encoder_options'] = 
'-b '.round(
$info[
'ogg'][
'bitrate_nominal'] / 1000);
 
  364 
  365                                        } elseif ((
$info[
'audio'][
'bitrate_mode'] == 
'vbr') && (
$info[
'audio'][
'channels'] == 2) && (
$info[
'audio'][
'sample_rate'] >= 44100) && (
$info[
'audio'][
'sample_rate'] <= 48000)) {
 
  366                                                
  367                                                $info[
'audio'][
'encoder_options'] = 
'-q '.$this->get_quality_from_nominal_bitrate(
$info[
'ogg'][
'bitrate_nominal']);
 
  368 
  369                                        }
  370                                }
  371 
  372                                if (empty(
$info[
'audio'][
'encoder_options']) && !empty(
$info[
'ogg'][
'bitrate_nominal'])) {
 
  373                                        $info[
'audio'][
'encoder_options'] = 
'Nominal bitrate: '.intval(round(
$info[
'ogg'][
'bitrate_nominal'] / 1000)).
'kbps';
 
  374                                }
  375                        }
  376                }
  377 
  378                return true;
  379        }
@tutorial http://flac.sourceforge.net/format.html
fseek($bytes, $whence=SEEK_SET)
static LittleEndian2Int($byteword, $signed=false)
static intValueSupported($num)
static BigEndian2Int($byteword, $synchsafe=false, $signed=false)
static TheoraPixelFormat($pixelformat_id)
ParseOpusPageHeader(&$filedata, &$filedataoffset, &$oggpageinfo)
static SpeexBandModeLookup($mode)
ParseVorbisPageHeader(&$filedata, &$filedataoffset, &$oggpageinfo)
static TheoraColorSpace($colorspace_id)