function _decodeCommentsHeader() { fseek($this->_filePointer, $this->_streamData['pages'][1]['body_offset'], SEEK_SET); $blockHeader = File_Ogg::_readBigEndian($this->_filePointer, array('last_block' => 1, 'block_type' => 7, 'length' => 24)); if ($blockHeader['block_type'] != 4) { throw new PEAR_Exception("Stream Undecodable", OGG_ERROR_UNDECODABLE); } $this->_decodeBareCommentsHeader(); }
/** * Parse the identification header in a Theora stream. * @access private */ function _decodeIdentificationHeader() { $this->_decodeCommonHeader(OGG_THEORA_IDENTIFICATION_HEADER, OGG_THEORA_IDENTIFICATION_PAGE_OFFSET); $h = File_Ogg::_readBigEndian($this->_filePointer, array('VMAJ' => 8, 'VMIN' => 8, 'VREV' => 8, 'FMBW' => 16, 'FMBH' => 16, 'PICW' => 24, 'PICH' => 24, 'PICX' => 8, 'PICY' => 8, 'FRN' => 32, 'FRD' => 32, 'PARN' => 24, 'PARD' => 24, 'CS' => 8, 'NOMBR' => 24, 'QUAL' => 6, 'KFGSHIFT' => 5, 'PF' => 2)); if (!$h) { throw new PEAR_Exception("Stream is undecodable due to a truncated header.", OGG_ERROR_UNDECODABLE); } // Theora version // Seems overly strict but this is what the spec says // VREV is for backwards-compatible changes, apparently if ($h['VMAJ'] != 3 || $h['VMIN'] != 2) { throw new PEAR_Exception("Stream is undecodable due to an invalid theora version.", OGG_ERROR_UNDECODABLE); } $this->_theoraVersion = "{$h['VMAJ']}.{$h['VMIN']}.{$h['VREV']}"; // Frame height/width if (!$h['FMBW'] || !$h['FMBH']) { throw new PEAR_Exception("Stream is undecodable because it has frame size of zero.", OGG_ERROR_UNDECODABLE); } $this->_frameWidth = $h['FMBW'] * 16; $this->_frameHeight = $h['FMBH'] * 16; // Picture height/width if ($h['PICW'] > $this->_frameWidth || $h['PICH'] > $this->_frameHeight) { throw new PEAR_Exception("Stream is undecodable because the picture width is greater than the frame width.", OGG_ERROR_UNDECODABLE); } $this->_pictureWidth = $h['PICW']; $this->_pictureHeight = $h['PICH']; // Picture offset $this->_offsetX = $h['PICX']; $this->_offsetY = $h['PICY']; // Frame rate $this->_frameRate = $h['FRD'] == 0 ? 0 : $h['FRN'] / $h['FRD']; // Physical aspect ratio if (!$h['PARN'] || !$h['PARD']) { $this->_physicalAspectRatio = 1; } else { $this->_physicalAspectRatio = $h['PARN'] / $h['PARD']; } // Color space $colorSpaces = array(0 => 'Undefined', 1 => 'Rec. 470M', 2 => 'Rec. 470BG'); if (isset($colorSpaces[$h['CS']])) { $this->_colorSpace = $colorSpaces[$h['CS']]; } else { $this->_colorSpace = 'Unknown (reserved)'; } $this->_nomBitrate = $h['NOMBR']; $this->_quality = $h['QUAL']; $this->_kfgShift = $h['KFGSHIFT']; $pixelFormats = array(0 => '4:2:0', 1 => 'Unknown (reserved)', 2 => '4:2:2', 3 => '4:4:4'); $this->_pixelFormat = $pixelFormats[$h['PF']]; switch ($h['PF']) { case 0: $h['NSBS'] = floor(($h['FMBW'] + 1) / 2) * floor(($h['FMBH'] + 1) / 2) + 2 * floor(($h['FMBW'] + 3) / 4) * floor(($h['FMBH'] + 3) / 4); $h['NBS'] = 6 * $h['FMBW'] * $h['FMBH']; break; case 2: $h['NSBS'] = floor(($h['FMBW'] + 1) / 2) * floor(($h['FMBH'] + 1) / 2) + 2 * floor(($h['FMBW'] + 3) / 4) * floor(($h['FMBH'] + 1) / 2); $h['NBS'] = 8 * $h['FMBW'] * $h['FMBH']; break; case 3: $h['NSBS'] = 3 * floor(($h['FMBW'] + 1) / 2) * floor(($h['FMBH'] + 1) / 2); $h['NBS'] = 12 * $h['FMBW'] * $h['FMBH']; break; default: $h['NSBS'] = $h['NBS'] = 0; } $h['NMBS'] = $h['FMBW'] * $h['FMBH']; $this->_idHeader = $h; }