PageRenderTime 51ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/extensions/MetavidWiki/skins/mv_embed/oggServer/PEAR/File_Ogg/File/Ogg/Theora.php

https://github.com/ChuguluGames/mediawiki-svn
PHP | 267 lines | 162 code | 25 blank | 80 comment | 20 complexity | 15b222f59dec018f15977cc2c2382ab3 MD5 | raw file
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. // +----------------------------------------------------------------------------+
  4. // | File_Ogg PEAR Package for Accessing Ogg Bitstreams |
  5. // | Copyright (c) 2005-2007 |
  6. // | David Grant <david@grant.org.uk> |
  7. // | Tim Starling <tstarling@wikimedia.org> |
  8. // +----------------------------------------------------------------------------+
  9. // | This library is free software; you can redistribute it and/or |
  10. // | modify it under the terms of the GNU Lesser General Public |
  11. // | License as published by the Free Software Foundation; either |
  12. // | version 2.1 of the License, or (at your option) any later version. |
  13. // | |
  14. // | This library is distributed in the hope that it will be useful, |
  15. // | but WITHOUT ANY WARRANTY; without even the implied warranty of |
  16. // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
  17. // | Lesser General Public License for more details. |
  18. // | |
  19. // | You should have received a copy of the GNU Lesser General Public |
  20. // | License along with this library; if not, write to the Free Software |
  21. // | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
  22. // +----------------------------------------------------------------------------+
  23. require_once dirname(__FILE__) . '/Bitstream.php';
  24. define( 'OGG_THEORA_IDENTIFICATION_HEADER', 0x80 );
  25. define( 'OGG_THEORA_COMMENTS_HEADER', 0x81 );
  26. define( 'OGG_THEORA_IDENTIFICATION_PAGE_OFFSET', 0 );
  27. define( 'OGG_THEORA_COMMENTS_PAGE_OFFSET', 1 );
  28. /**
  29. * @author David Grant <david@grant.org.uk>, Tim Starling <tstarling@wikimedia.org>
  30. * @category File
  31. * @copyright David Grant <david@grant.org.uk>, Tim Starling <tstarling@wikimedia.org>
  32. * @license http://www.gnu.org/copyleft/lesser.html GNU LGPL
  33. * @link http://pear.php.net/package/File_Ogg
  34. * @link http://www.xiph.org/theora/
  35. * @package File_Ogg
  36. * @version CVS: $Id: Theora.php,v 1.9 2005/11/16 20:43:27 djg Exp $
  37. */
  38. class File_Ogg_Theora extends File_Ogg_Media
  39. {
  40. /**
  41. * @access private
  42. */
  43. function __construct($streamSerial, $streamData, $filePointer)
  44. {
  45. parent::__construct($streamSerial, $streamData, $filePointer);
  46. $this->_decodeIdentificationHeader();
  47. $this->_decodeCommentsHeader();
  48. $endSec = $this->getSecondsFromGranulePos( $this->_lastGranulePos );
  49. $startSec = $this->getSecondsFromGranulePos( $this->_firstGranulePos );
  50. //make sure the offset is worth taking into account oggz_chop related hack
  51. if( $startSec > 1){
  52. $this->_streamLength = $endSec - $startSec;
  53. $this->_startOffset = $startSec;
  54. }else{
  55. $this->_streamLength = $endSec;
  56. }
  57. $this->_avgBitrate = $this->_streamLength ? ($this->_streamSize * 8) / $this->_streamLength : 0;
  58. }
  59. function getKeyFrameIndex(){
  60. $kAry = array();
  61. foreach($this->_streamList as & $packet){
  62. # Reject -1 as a granule pos, that means no segment finished in the packet
  63. if ( $packet['abs_granule_pos'] != 'ffffffffffffffff' ) {
  64. //get the top & bottom word:
  65. $topWord = floatval( base_convert( substr( $packet['abs_granule_pos'], 0, 8 ), 16, 10 ) );
  66. $bottomWord = floatval( base_convert( substr( $packet['abs_granule_pos'], 8, 8 ), 16, 10 ) );
  67. $keyFramePos = $topWord / pow(2, $this->_kfgShift - 32) +
  68. floor( $bottomWord / pow(2, $this->_kfgShift) );
  69. $offset = fmod( $bottomWord, pow(2, $this->_kfgShift) );
  70. $kTime = ( $keyFramePos ) / $this->_frameRate;
  71. $time = ( $keyFramePos + $offset ) / $this->_frameRate;
  72. /*print "paket:: " . print_r($packet, true) . "
  73. K:$kTime
  74. rt:$time ( " . ( $offset / $this->_frameRate ) . " \n\n";*/
  75. if(!isset($kAry[ (string)$kTime ])){
  76. $kAry[ (string)$kTime ] = $packet['head_offset'];
  77. }
  78. }
  79. }
  80. return $kAry;
  81. }
  82. function getSecondsFromGranulePos($granulePos){
  83. // Calculate GranulePos seconds
  84. // First make some "numeric strings"
  85. // These might not fit into PHP's integer type, but they will fit into
  86. // the 53-bit mantissa of a double-precision number
  87. $topWord = floatval( base_convert( substr( $granulePos, 0, 8 ), 16, 10 ) );
  88. $bottomWord = floatval( base_convert( substr( $granulePos, 8, 8 ), 16, 10 ) );
  89. // Calculate the keyframe position by shifting right by KFGSHIFT
  90. // We don't use PHP's shift operators because they're terribly broken
  91. // This is made slightly simpler by the fact that KFGSHIFT < 32
  92. $keyFramePos = $topWord / pow(2, $this->_kfgShift - 32) +
  93. floor( $bottomWord / pow(2, $this->_kfgShift) );
  94. // Calculate the frame offset by masking off the top 64-KFGSHIFT bits
  95. // This requires a bit of floating point trickery
  96. $offset = fmod( $bottomWord, pow(2, $this->_kfgShift) );
  97. // They didn't teach you that one at school did they?
  98. // Now put it together with the frame rate to calculate time in seconds
  99. return ( $keyFramePos + $offset ) / $this->_frameRate;
  100. }
  101. /**
  102. * Get the 6-byte identification string expected in the common header
  103. */
  104. function getIdentificationString()
  105. {
  106. return OGG_STREAM_CAPTURE_THEORA;
  107. }
  108. /**
  109. * Parse the identification header in a Theora stream.
  110. * @access private
  111. */
  112. function _decodeIdentificationHeader()
  113. {
  114. $this->_decodeCommonHeader(OGG_THEORA_IDENTIFICATION_HEADER, OGG_THEORA_IDENTIFICATION_PAGE_OFFSET);
  115. $h = File_Ogg::_readBigEndian( $this->_filePointer, array(
  116. 'VMAJ' => 8,
  117. 'VMIN' => 8,
  118. 'VREV' => 8,
  119. 'FMBW' => 16,
  120. 'FMBH' => 16,
  121. 'PICW' => 24,
  122. 'PICH' => 24,
  123. 'PICX' => 8,
  124. 'PICY' => 8,
  125. 'FRN' => 32,
  126. 'FRD' => 32,
  127. 'PARN' => 24,
  128. 'PARD' => 24,
  129. 'CS' => 8,
  130. 'NOMBR' => 24,
  131. 'QUAL' => 6,
  132. 'KFGSHIFT' => 5,
  133. 'PF' => 2));
  134. if ( !$h ) {
  135. throw new PEAR_Exception("Stream is undecodable due to a truncated header.", OGG_ERROR_UNDECODABLE);
  136. }
  137. // Theora version
  138. // Seems overly strict but this is what the spec says
  139. // VREV is for backwards-compatible changes, apparently
  140. if ( $h['VMAJ'] != 3 || $h['VMIN'] != 2 ) {
  141. throw new PEAR_Exception("Stream is undecodable due to an invalid theora version.", OGG_ERROR_UNDECODABLE);
  142. }
  143. $this->_theoraVersion = "{$h['VMAJ']}.{$h['VMIN']}.{$h['VREV']}";
  144. // Frame height/width
  145. if ( !$h['FMBW'] || !$h['FMBH'] ) {
  146. throw new PEAR_Exception("Stream is undecodable because it has frame size of zero.", OGG_ERROR_UNDECODABLE);
  147. }
  148. $this->_frameWidth = $h['FMBW'] * 16;
  149. $this->_frameHeight = $h['FMBH'] * 16;
  150. // Picture height/width
  151. if ( $h['PICW'] > $this->_frameWidth || $h['PICH'] > $this->_frameHeight ) {
  152. throw new PEAR_Exception("Stream is undecodable because the picture width is greater than the frame width.", OGG_ERROR_UNDECODABLE);
  153. }
  154. $this->_pictureWidth = $h['PICW'];
  155. $this->_pictureHeight = $h['PICH'];
  156. // Picture offset
  157. $this->_offsetX = $h['PICX'];
  158. $this->_offsetY = $h['PICY'];
  159. // Frame rate
  160. $this->_frameRate = $h['FRD'] == 0 ? 0 : $h['FRN'] / $h['FRD'];
  161. // Physical aspect ratio
  162. if ( !$h['PARN'] || !$h['PARD'] ) {
  163. $this->_physicalAspectRatio = 1;
  164. } else {
  165. $this->_physicalAspectRatio = $h['PARN'] / $h['PARD'];
  166. }
  167. // Color space
  168. $colorSpaces = array(
  169. 0 => 'Undefined',
  170. 1 => 'Rec. 470M',
  171. 2 => 'Rec. 470BG',
  172. );
  173. if ( isset( $colorSpaces[$h['CS']] ) ) {
  174. $this->_colorSpace = $colorSpaces[$h['CS']];
  175. } else {
  176. $this->_colorSpace = 'Unknown (reserved)';
  177. }
  178. $this->_nomBitrate = $h['NOMBR'];
  179. $this->_quality = $h['QUAL'];
  180. $this->_kfgShift = $h['KFGSHIFT'];
  181. $pixelFormats = array(
  182. 0 => '4:2:0',
  183. 1 => 'Unknown (reserved)',
  184. 2 => '4:2:2',
  185. 3 => '4:4:4',
  186. );
  187. $this->_pixelFormat = $pixelFormats[$h['PF']];
  188. switch ( $h['PF'] ) {
  189. case 0:
  190. $h['NSBS'] =
  191. floor( ($h['FMBW'] + 1) / 2 ) *
  192. floor( ($h['FMBH'] + 1) / 2 ) + 2 *
  193. floor( ($h['FMBW'] + 3) / 4 ) *
  194. floor( ($h['FMBH'] + 3) / 4 );
  195. $h['NBS'] = 6 * $h['FMBW'] * $h['FMBH'];
  196. break;
  197. case 2:
  198. $h['NSBS'] =
  199. floor( ($h['FMBW'] + 1) / 2 ) *
  200. floor( ($h['FMBH'] + 1) / 2 ) + 2 *
  201. floor( ($h['FMBW'] + 3) / 4 ) *
  202. floor( ($h['FMBH'] + 1) / 2 );
  203. $h['NBS'] = 8 * $h['FMBW'] * $h['FMBH'];
  204. break;
  205. case 3:
  206. $h['NSBS'] =
  207. 3 * floor( ($h['FMBW'] + 1) / 2 ) *
  208. floor( ($h['FMBH'] + 1) / 2 );
  209. $h['NBS'] = 12 * $h['FMBW'] * $h['FMBH'];
  210. break;
  211. default:
  212. $h['NSBS'] = $h['NBS'] = 0;
  213. }
  214. $h['NMBS'] = $h['FMBW'] * $h['FMBH'];
  215. $this->_idHeader = $h;
  216. }
  217. /**
  218. * Get an associative array containing header information about the stream
  219. * @access public
  220. * @return array
  221. */
  222. function getHeader() {
  223. return $this->_idHeader;
  224. }
  225. /**
  226. * Get a short string describing the type of the stream
  227. * @return string
  228. */
  229. function getType() {
  230. return 'Theora';
  231. }
  232. /**
  233. * Decode the comments header
  234. * @access private
  235. */
  236. function _decodeCommentsHeader()
  237. {
  238. $this->_decodeCommonHeader(OGG_THEORA_COMMENTS_HEADER, OGG_THEORA_COMMENTS_PAGE_OFFSET);
  239. $this->_decodeBareCommentsHeader();
  240. }
  241. }
  242. ?>