r56769 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r56768‎ | r56769 | r56770 >
Date:16:52, 22 September 2009
Author:dale
Status:deferred
Tags:
Comment:
* stored the in-development oggServer near the flvServer
Modified paths:
  • /trunk/extensions/MetavidWiki/skins/mv_embed/oggServer (added) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/oggServer/PEAR (added) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/oggServer/PEAR/File_Ogg (added) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/oggServer/PEAR/File_Ogg/File (added) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/oggServer/PEAR/File_Ogg/File/Ogg (added) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/oggServer/PEAR/File_Ogg/File/Ogg.php (added) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/oggServer/PEAR/File_Ogg/File/Ogg/Bitstream.php (added) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/oggServer/PEAR/File_Ogg/File/Ogg/Flac.php (added) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/oggServer/PEAR/File_Ogg/File/Ogg/Media.php (added) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/oggServer/PEAR/File_Ogg/File/Ogg/Speex.php (added) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/oggServer/PEAR/File_Ogg/File/Ogg/Theora.php (added) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/oggServer/PEAR/File_Ogg/File/Ogg/Vorbis.php (added) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/oggServer/PEAR/File_Ogg/File/README (added) (history)
  • /trunk/extensions/MetavidWiki/skins/mv_embed/oggServer/PEAR/File_Ogg/package.xml (added) (history)

Diff [purge]

Index: trunk/extensions/MetavidWiki/skins/mv_embed/oggServer/PEAR/File_Ogg/package.xml
@@ -0,0 +1,149 @@
 2+<?xml version="1.0" encoding="UTF-8"?>
 3+<package packagerversion="1.6.1" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
 4+ <name>File_Ogg</name>
 5+ <channel>pear.php.net</channel>
 6+ <summary>Retrieves metadata from Ogg files.</summary>
 7+ <description>Decodes Ogg file headers to provide metadata. Supports Vorbis,
 8+Theora, Speex and FLAC stream headers. This package does
 9+NOT provide codecs for these formats.
 10+ </description>
 11+ <lead>
 12+ <name>Tim Starling</name>
 13+ <user>tstarling</user>
 14+ <email>tstarling@wikimedia.org</email>
 15+ <active>yes</active>
 16+ </lead>
 17+ <date>2008-01-31</date>
 18+ <time>15:25:07</time>
 19+ <version>
 20+ <release>0.3.0</release>
 21+ <api>0.3.0</api>
 22+ </version>
 23+ <stability>
 24+ <release>beta</release>
 25+ <api>beta</api>
 26+ </stability>
 27+ <license>GNU LGPL</license>
 28+ <notes>* Change in maintainership
 29+* Added header parsing for Theora, Speex and Flac.
 30+* Removed partially written save/encode code.
 31+* Introduced some PHP 5 features, no longer supports PHP 4.
 32+* Introduced convenience functions getHeader() and getComments() to retrieve metadata in associative array format.
 33+* Fixed the error handling, using exceptions instead of inappropriate continuation.
 34+* Added overall length calculation for multiplexed streams
 35+* Fixed a page splitting bug
 36+
 37+ </notes>
 38+ <contents>
 39+ <dir name="/">
 40+ <dir name="File">
 41+ <dir name="Ogg">
 42+ <file name="Bitstream.php" role="php" />
 43+ <file name="Flac.php" role="php" />
 44+ <file name="Media.php" role="php" />
 45+ <file name="Speex.php" role="php" />
 46+ <file name="Theora.php" role="php" />
 47+ <file name="Vorbis.php" role="php" />
 48+ </dir> <!-- //File/Ogg -->
 49+ <file name="Ogg.php" role="php" />
 50+ </dir> <!-- //File -->
 51+ </dir> <!-- / -->
 52+ </contents>
 53+ <dependencies>
 54+ <required>
 55+ <php>
 56+ <min>5.0.0</min>
 57+ </php>
 58+ <pearinstaller>
 59+ <min>1.4.0b1</min>
 60+ </pearinstaller>
 61+ </required>
 62+ </dependencies>
 63+ <phprelease />
 64+ <changelog>
 65+ <release>
 66+ <version>
 67+ <release>0.2.1</release>
 68+ <api>0.2.1</api>
 69+ </version>
 70+ <stability>
 71+ <release>beta</release>
 72+ <api>beta</api>
 73+ </stability>
 74+ <date>2005-11-03</date>
 75+ <license>GNU LGPL</license>
 76+ <notes>Fixed some basic bugs from the previous release.
 77+ </notes>
 78+ </release>
 79+ <release>
 80+ <version>
 81+ <release>0.2.0</release>
 82+ <api>0.2.0</api>
 83+ </version>
 84+ <stability>
 85+ <release>beta</release>
 86+ <api>beta</api>
 87+ </stability>
 88+ <date>2005-11-03</date>
 89+ <license>GNU LGPL</license>
 90+ <notes>Updated to beta release, changed license to LGPL.
 91+ </notes>
 92+ </release>
 93+ <release>
 94+ <version>
 95+ <release>0.1.3</release>
 96+ <api>0.1.3</api>
 97+ </version>
 98+ <stability>
 99+ <release>alpha</release>
 100+ <api>alpha</api>
 101+ </stability>
 102+ <date>2005-09-21</date>
 103+ <license>GNU LGPL</license>
 104+ <notes>Change to package.xml.
 105+ </notes>
 106+ </release>
 107+ <release>
 108+ <version>
 109+ <release>0.1.2</release>
 110+ <api>0.1.2</api>
 111+ </version>
 112+ <stability>
 113+ <release>alpha</release>
 114+ <api>alpha</api>
 115+ </stability>
 116+ <date>2003-09-09</date>
 117+ <license>GNU LGPL</license>
 118+ <notes>Extensive documentation for the majority of PHP elements.
 119+ </notes>
 120+ </release>
 121+ <release>
 122+ <version>
 123+ <release>0.1.1</release>
 124+ <api>0.1.1</api>
 125+ </version>
 126+ <stability>
 127+ <release>alpha</release>
 128+ <api>alpha</api>
 129+ </stability>
 130+ <date>2003-09-02</date>
 131+ <license>GNU LGPL</license>
 132+ <notes>Bugfix release: package was installing in the wrong location.
 133+ </notes>
 134+ </release>
 135+ <release>
 136+ <version>
 137+ <release>0.1</release>
 138+ <api>0.1</api>
 139+ </version>
 140+ <stability>
 141+ <release>alpha</release>
 142+ <api>alpha</api>
 143+ </stability>
 144+ <date>2003-09-02</date>
 145+ <license>GNU LGPL</license>
 146+ <notes>The first release!
 147+ </notes>
 148+ </release>
 149+ </changelog>
 150+</package>
Index: trunk/extensions/MetavidWiki/skins/mv_embed/oggServer/PEAR/File_Ogg/File/Ogg/Speex.php
@@ -0,0 +1,123 @@
 2+<?php
 3+/* vim: set expandtab tabstop=4 shiftwidth=4: */
 4+// +----------------------------------------------------------------------------+
 5+// | File_Ogg PEAR Package for Accessing Ogg Bitstreams |
 6+// | Copyright (c) 2005-2007 |
 7+// | David Grant <david@grant.org.uk> |
 8+// | Tim Starling <tstarling@wikimedia.org> |
 9+// +----------------------------------------------------------------------------+
 10+// | This library is free software; you can redistribute it and/or |
 11+// | modify it under the terms of the GNU Lesser General Public |
 12+// | License as published by the Free Software Foundation; either |
 13+// | version 2.1 of the License, or (at your option) any later version. |
 14+// | |
 15+// | This library is distributed in the hope that it will be useful, |
 16+// | but WITHOUT ANY WARRANTY; without even the implied warranty of |
 17+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
 18+// | Lesser General Public License for more details. |
 19+// | |
 20+// | You should have received a copy of the GNU Lesser General Public |
 21+// | License along with this library; if not, write to the Free Software |
 22+// | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
 23+// +----------------------------------------------------------------------------+
 24+
 25+require_once('File/Ogg/Media.php');
 26+
 27+/**
 28+ * @author David Grant <david@grant.org.uk>, Tim Starling <tstarling@wikimedia.org>
 29+ * @category File
 30+ * @copyright David Grant <david@grant.org.uk>, Tim Starling <tstarling@wikimedia.org>
 31+ * @license http://www.gnu.org/copyleft/lesser.html GNU LGPL
 32+ * @link http://pear.php.net/package/File_Ogg
 33+ * @link http://www.speex.org/docs.html
 34+ * @package File_Ogg
 35+ * @version CVS: $Id: Speex.php,v 1.10 2005/11/16 20:43:27 djg Exp $
 36+ */
 37+class File_Ogg_Speex extends File_Ogg_Media
 38+{
 39+ /**
 40+ * @access private
 41+ */
 42+ function __construct($streamSerial, $streamData, $filePointer)
 43+ {
 44+ parent::__construct($streamSerial, $streamData, $filePointer);
 45+ $this->_decodeHeader();
 46+ $this->_decodeCommentsHeader();
 47+ $endSec =
 48+ (( '0x' . substr( $this->_lastGranulePos, 0, 8 ) ) * pow(2, 32)
 49+ + ( '0x' . substr( $this->_lastGranulePos, 8, 8 ) ))
 50+ / $this->_header['rate'];
 51+
 52+ $startSec =
 53+ (( '0x' . substr( $this->_firstGranulePos, 0, 8 ) ) * pow(2, 32)
 54+ + ( '0x' . substr( $this->_firstGranulePos, 8, 8 ) ))
 55+ / $this->_header['rate'];
 56+
 57+ //make sure the offset is worth taking into account oggz_chop related hack
 58+ if( $startSec > 1){
 59+ $this->_streamLength = $endSec - $startSec;
 60+ $this->_startOffset = $startSec;
 61+ }else{
 62+ $this->_streamLength = $endSec;
 63+ }
 64+ }
 65+
 66+ /**
 67+ * Get a short string describing the type of the stream
 68+ * @return string
 69+ */
 70+ function getType()
 71+ {
 72+ return 'Speex';
 73+ }
 74+
 75+ /**
 76+ * Decode the stream header
 77+ * @access private
 78+ */
 79+ function _decodeHeader()
 80+ {
 81+ fseek($this->_filePointer, $this->_streamList[0]['body_offset'], SEEK_SET);
 82+ // The first 8 characters should be "Speex ".
 83+ if (fread($this->_filePointer, 8) != 'Speex ')
 84+ throw new PEAR_Exception("Stream is undecodable due to a malformed header.", OGG_ERROR_UNDECODABLE);
 85+
 86+ $this->_version = fread($this->_filePointer, 20);
 87+ $this->_header = File_Ogg::_readLittleEndian($this->_filePointer, array(
 88+ 'speex_version_id' => 32,
 89+ 'header_size' => 32,
 90+ 'rate' => 32,
 91+ 'mode' => 32,
 92+ 'mode_bitstream_version'=> 32,
 93+ 'nb_channels' => 32,
 94+ 'bitrate' => 32,
 95+ 'frame_size' => 32,
 96+ 'vbr' => 32,
 97+ 'frames_per_packet' => 32,
 98+ 'extra_headers' => 32,
 99+ 'reserved1' => 32,
 100+ 'reserved2' => 32
 101+ ));
 102+ $this->_header['speex_version'] = $this->_version;
 103+ }
 104+
 105+ /**
 106+ * Get an associative array containing header information about the stream
 107+ * @access public
 108+ * @return array
 109+ */
 110+ function getHeader() {
 111+ return $this->_header;
 112+ }
 113+
 114+ /**
 115+ * Decode the comments header
 116+ * @access private
 117+ */
 118+ function _decodeCommentsHeader()
 119+ {
 120+ fseek($this->_filePointer, $this->_streamList[1]['body_offset'], SEEK_SET);
 121+ $this->_decodeBareCommentsHeader();
 122+ }
 123+}
 124+?>
Index: trunk/extensions/MetavidWiki/skins/mv_embed/oggServer/PEAR/File_Ogg/File/Ogg/Vorbis.php
@@ -0,0 +1,808 @@
 2+<?php
 3+/* vim: set expandtab tabstop=4 shiftwidth=4: */
 4+// +----------------------------------------------------------------------------+
 5+// | File_Ogg PEAR Package for Accessing Ogg Bitstreams |
 6+// | Copyright (c) 2005-2007 |
 7+// | David Grant <david@grant.org.uk> |
 8+// | Tim Starling <tstarling@wikimedia.org> |
 9+// +----------------------------------------------------------------------------+
 10+// | This library is free software; you can redistribute it and/or |
 11+// | modify it under the terms of the GNU Lesser General Public |
 12+// | License as published by the Free Software Foundation; either |
 13+// | version 2.1 of the License, or (at your option) any later version. |
 14+// | |
 15+// | This library is distributed in the hope that it will be useful, |
 16+// | but WITHOUT ANY WARRANTY; without even the implied warranty of |
 17+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
 18+// | Lesser General Public License for more details. |
 19+// | |
 20+// | You should have received a copy of the GNU Lesser General Public |
 21+// | License along with this library; if not, write to the Free Software |
 22+// | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
 23+// +----------------------------------------------------------------------------+
 24+
 25+require_once('File/Ogg/Bitstream.php');
 26+
 27+/**
 28+ * Check number for the first header in a Vorbis stream.
 29+ *
 30+ * @access private
 31+ */
 32+define("OGG_VORBIS_IDENTIFICATION_HEADER", 1);
 33+/**
 34+ * Check number for the second header in a Vorbis stream.
 35+ *
 36+ * @access private
 37+ */
 38+define("OGG_VORBIS_COMMENTS_HEADER", 3);
 39+/**
 40+ * Check number for the third header in a Vorbis stream.
 41+ *
 42+ * @access private
 43+ */
 44+define("OGG_VORBIS_SETUP_HEADER", 5);
 45+/**
 46+ * Error thrown if the stream appears to be corrupted.
 47+ *
 48+ * @access private
 49+ */
 50+define("OGG_VORBIS_ERROR_UNDECODABLE", OGG_ERROR_UNDECODABLE);
 51+/**
 52+ * Error thrown if the user attempts to extract a comment using a comment key
 53+ * that does not exist.
 54+ *
 55+ * @access private
 56+ */
 57+define("OGG_VORBIS_ERROR_INVALID_COMMENT", 2);
 58+
 59+define("OGG_VORBIS_IDENTIFICATION_PAGE_OFFSET", 0);
 60+define("OGG_VORBIS_COMMENTS_PAGE_OFFSET", 1);
 61+
 62+/**
 63+ * Error thrown if the user attempts to write a comment containing an illegal
 64+ * character
 65+ *
 66+ * @access private
 67+ */
 68+define("OGG_VORBIS_ERROR_ILLEGAL_COMMENT", 3);
 69+
 70+/**
 71+ * Extract the contents of a Vorbis logical stream.
 72+ *
 73+ * This class provides an interface to a Vorbis logical stream found within
 74+ * a Ogg stream. A variety of information may be extracted, including comment
 75+ * tags, running time, and bitrate. For more information, please see the following
 76+ * links.
 77+ *
 78+ * @author David Grant <david@grant.org.uk>, Tim Starling <tstarling@wikimedia.org>
 79+ * @category File
 80+ * @copyright David Grant <david@grant.org.uk>, Tim Starling <tstarling@wikimedia.org>
 81+ * @license http://www.gnu.org/copyleft/lesser.html GNU LGPL
 82+ * @link http://pear.php.net/package/File_Ogg
 83+ * @link http://www.xiph.org/vorbis/doc/
 84+ * @package File_Ogg
 85+ * @version CVS: $Id: Vorbis.php,v 1.13 2005/11/19 09:06:32 djg Exp $
 86+ */
 87+class File_Ogg_Vorbis extends File_Ogg_Media
 88+{
 89+
 90+ /**
 91+ * Version of vorbis specification used.
 92+ *
 93+ * @access private
 94+ * @var int
 95+ */
 96+ var $_version;
 97+
 98+ /**
 99+ * Number of channels in the vorbis stream.
 100+ *
 101+ * @access private
 102+ * @var int
 103+ */
 104+ var $_channels;
 105+
 106+ /**
 107+ * Number of samples per second in the vorbis stream.
 108+ *
 109+ * @access private
 110+ * @var int
 111+ */
 112+ var $_sampleRate;
 113+
 114+ /**
 115+ * Minimum bitrate for the vorbis stream.
 116+ *
 117+ * @access private
 118+ * @var int
 119+ */
 120+ var $_minBitrate;
 121+
 122+ /**
 123+ * Maximum bitrate for the vorbis stream.
 124+ *
 125+ * @access private
 126+ * @var int
 127+ */
 128+ var $_maxBitrate;
 129+
 130+ /**
 131+ * Nominal bitrate for the vorbis stream.
 132+ *
 133+ * @access private
 134+ * @var int
 135+ */
 136+ var $_nomBitrate;
 137+
 138+ /**
 139+ * Average bitrate for the vorbis stream.
 140+ *
 141+ * @access private
 142+ * @var float
 143+ */
 144+ var $_avgBitrate;
 145+
 146+ /**
 147+ * The length of this stream in seconds.
 148+ *
 149+ * @access private
 150+ * @var int
 151+ */
 152+ var $_streamLength;
 153+
 154+ /**
 155+ * the start offset of this stream in seconds
 156+ */
 157+ var $_startOffset;
 158+ /**
 159+ * Constructor for accessing a Vorbis logical stream.
 160+ *
 161+ * This method is the constructor for the native-PHP interface to a Vorbis logical
 162+ * stream, embedded within an Ogg physical stream.
 163+ *
 164+ * @param int $streamSerial Serial number of the logical stream.
 165+ * @param array $streamData Data for the requested logical stream.
 166+ * @param string $filePath Location of a file on the filesystem.
 167+ * @param pointer $filePointer File pointer for the current physical stream.
 168+ * @access private
 169+ */
 170+ function __construct($streamSerial, $streamData, $filePointer)
 171+ {
 172+ parent::__construct($streamSerial, $streamData, $filePointer);
 173+ $this->_decodeIdentificationHeader();
 174+ $this->_decodeCommentsHeader(OGG_VORBIS_COMMENTS_HEADER, OGG_VORBIS_COMMENTS_PAGE_OFFSET);
 175+
 176+ $endSec = $this->getSecondsFromGranulePos( $this->_lastGranulePos );
 177+ $startSec = $this->getSecondsFromGranulePos( $this->_firstGranulePos );
 178+
 179+ //make sure the offset is worth taking into account oggz_chop related hack
 180+ if( $startSec > 1){
 181+ $this->_streamLength = $endSec - $startSec;
 182+ $this->_startOffset = $startSec;
 183+ }else{
 184+ $this->_streamLength = $endSec;
 185+ }
 186+
 187+ $this->_avgBitrate = $this->_streamLength ? ($this->_streamSize * 8) / $this->_streamLength : 0;
 188+ }
 189+ function getSecondsFromGranulePos( $granulePos ){
 190+ return (( '0x' . substr( $granulePos, 0, 8 ) ) * pow(2, 32)
 191+ + ( '0x' . substr( $granulePos, 8, 8 ) ))
 192+ / $this->_idHeader['audio_sample_rate'];
 193+ }
 194+ /**
 195+ * Get a short string describing the type of the stream
 196+ */
 197+ function getType()
 198+ {
 199+ return 'Vorbis';
 200+ }
 201+
 202+ /**
 203+ * Parse the identification header (the first of three headers) in a Vorbis stream.
 204+ *
 205+ * This function parses the identification header. The identification header
 206+ * contains simple audio characteristics, such as sample rate and number of
 207+ * channels. There are a number of error-checking provisions laid down in the Vorbis
 208+ * specification to ensure the stream is pure.
 209+ *
 210+ * @access private
 211+ */
 212+ function _decodeIdentificationHeader()
 213+ {
 214+ $this->_decodeCommonHeader(OGG_VORBIS_IDENTIFICATION_HEADER, OGG_VORBIS_IDENTIFICATION_PAGE_OFFSET);
 215+
 216+ $h = File_Ogg::_readLittleEndian($this->_filePointer, array(
 217+ 'vorbis_version' => 32,
 218+ 'audio_channels' => 8,
 219+ 'audio_sample_rate' => 32,
 220+ 'bitrate_maximum' => 32,
 221+ 'bitrate_nominal' => 32,
 222+ 'bitrate_minimum' => 32,
 223+ 'blocksize_0' => 4,
 224+ 'blocksize_1' => 4,
 225+ 'framing_flag' => 1
 226+ ));
 227+
 228+ // The Vorbis stream version must be 0.
 229+ if ($h['vorbis_version'] == 0)
 230+ $this->_version = $h['vorbis_version'];
 231+ else
 232+ throw new PEAR_Exception("Stream is undecodable due to an invalid vorbis stream version.", OGG_VORBIS_ERROR_UNDECODABLE);
 233+
 234+ // The number of channels MUST be greater than 0.
 235+ if ($h['audio_channels'] == 0)
 236+ throw new PEAR_Exception("Stream is undecodable due to zero channels.", OGG_VORBIS_ERROR_UNDECODABLE);
 237+ else
 238+ $this->_channels = $h['audio_channels'];
 239+
 240+ // The sample rate MUST be greater than 0.
 241+ if ($h['audio_sample_rate'] == 0)
 242+ throw new PEAR_Exception("Stream is undecodable due to a zero sample rate.", OGG_VORBIS_ERROR_UNDECODABLE);
 243+ else
 244+ $this->_sampleRate = $h['audio_sample_rate'];
 245+
 246+ // Extract the various bitrates
 247+ $this->_maxBitrate = $h['bitrate_maximum'];
 248+ $this->_nomBitrate = $h['bitrate_nominal'];
 249+ $this->_minBitrate = $h['bitrate_minimum'];
 250+
 251+ // Powers of two between 6 and 13 inclusive.
 252+ $valid_block_sizes = array(64, 128, 256, 512, 1024, 2048, 4096, 8192);
 253+
 254+ // blocksize_0 MUST be a valid blocksize.
 255+ $blocksize_0 = pow(2, $h['blocksize_0']);
 256+ if (FALSE == in_array($blocksize_0, $valid_block_sizes))
 257+ throw new PEAR_Exception("Stream is undecodable because blocksize_0 is $blocksize_0, which is not a valid size.", OGG_VORBIS_ERROR_UNDECODABLE);
 258+
 259+ // Extract bits 5 to 8 from the character data.
 260+ // blocksize_1 MUST be a valid blocksize.
 261+ $blocksize_1 = pow(2, $h['blocksize_1']);
 262+ if (FALSE == in_array($blocksize_1, $valid_block_sizes))
 263+ throw new PEAR_Exception("Stream is undecodable because blocksize_1 is not a valid size.", OGG_VORBIS_ERROR_UNDECODABLE);
 264+
 265+ // blocksize 0 MUST be less than or equal to blocksize 1.
 266+ if ($blocksize_0 > $blocksize_1)
 267+ throw new PEAR_Exception("Stream is undecodable because blocksize_0 is not less than or equal to blocksize_1.", OGG_VORBIS_ERROR_UNDECODABLE);
 268+
 269+ // The framing bit MUST be set to mark the end of the identification header.
 270+ // Some encoders are broken though -- TS
 271+ /*
 272+ if ($h['framing_flag'] == 0)
 273+ throw new PEAR_Exception("Stream in undecodable because the framing bit is not non-zero.", OGG_VORBIS_ERROR_UNDECODABLE);
 274+ */
 275+
 276+ $this->_idHeader = $h;
 277+ }
 278+
 279+ /**
 280+ * Decode the comments header
 281+ * @access private
 282+ * @param int $packetType
 283+ * @param int $pageOffset
 284+ */
 285+ function _decodeCommentsHeader($packetType, $pageOffset)
 286+ {
 287+ $this->_decodeCommonHeader($packetType, $pageOffset);
 288+ $this->_decodeBareCommentsHeader();
 289+ // The framing bit MUST be set to mark the end of the comments header.
 290+ $framing_bit = unpack("Cdata", fread($this->_filePointer, 1));
 291+ if ($framing_bit['data'] != 1)
 292+ throw new PEAR_Exception("Stream Undecodable", OGG_VORBIS_ERROR_UNDECODABLE);
 293+ }
 294+
 295+ /**
 296+ * Get the 6-byte identification string expected in the common header
 297+ */
 298+ function getIdentificationString() {
 299+ return OGG_STREAM_CAPTURE_VORBIS;
 300+ }
 301+
 302+ /**
 303+ * Version of the Vorbis specification referred to in the encoding of this stream.
 304+ *
 305+ * This method returns the version of the Vorbis specification (currently 0 (ZERO))
 306+ * referred to by the encoder of this stream. The Vorbis specification is well-
 307+ * defined, and thus one does not expect this value to change on a frequent basis.
 308+ *
 309+ * @access public
 310+ * @return int
 311+ */
 312+ function getEncoderVersion()
 313+ {
 314+ return ($this->_version);
 315+ }
 316+
 317+ /**
 318+ * Number of channels used in this stream
 319+ *
 320+ * This function returns the number of channels used in this stream. This
 321+ * can range from 1 to 255, but will likely be 2 (stereo) or 1 (mono).
 322+ *
 323+ * @access public
 324+ * @return int
 325+ * @see File_Ogg_Vorbis::isMono()
 326+ * @see File_Ogg_Vorbis::isStereo()
 327+ * @see File_Ogg_Vorbis::isQuadrophonic()
 328+ */
 329+ function getChannels()
 330+ {
 331+ return ($this->_channels);
 332+ }
 333+
 334+ /**
 335+ * Samples per second.
 336+ *
 337+ * This function returns the number of samples used per second in this
 338+ * recording. Probably the most common value here is 44,100.
 339+ *
 340+ * @return int
 341+ * @access public
 342+ */
 343+ function getSampleRate()
 344+ {
 345+ return ($this->_sampleRate);
 346+ }
 347+
 348+ /**
 349+ * Various bitrate measurements
 350+ *
 351+ * Gives an array of the values of four different types of bitrates for this
 352+ * stream. The nominal, maximum and minimum values are found within the file,
 353+ * whereas the average value is computed.
 354+ *
 355+ * @access public
 356+ * @return array
 357+ */
 358+ function getBitrates()
 359+ {
 360+ return (array("nom" => $this->_nomBitrate, "max" => $this->_maxBitrate, "min" => $this->_minBitrate, "avg" => $this->_avgBitrate));
 361+ }
 362+
 363+ /**
 364+ * Gives the most accurate bitrate measurement from this stream.
 365+ *
 366+ * This function returns the most accurate bitrate measurement for this
 367+ * recording, depending on values set in the stream header.
 368+ *
 369+ * @access public
 370+ * @return float
 371+ */
 372+ function getBitrate()
 373+ {
 374+ if ($this->_avgBitrate != 0)
 375+ return ($this->_avgBitrate);
 376+ elseif ($this->_nomBitrate != 0)
 377+ return ($this->_nomBitrate);
 378+ else
 379+ return (($this->_minBitrate + $this->_maxBitrate) / 2);
 380+ }
 381+
 382+ /**
 383+ * Gives the length (in seconds) of this stream.
 384+ *
 385+ * @access public
 386+ * @return int
 387+ */
 388+ function getLength()
 389+ {
 390+ return ($this->_streamLength);
 391+ }
 392+ /**
 393+ * Get the start offset of the stream in seconds
 394+ * @access public
 395+ * @return int
 396+ */
 397+ function getStartOffset(){
 398+ return ($this->_startOffset);
 399+ }
 400+ /**
 401+ * States whether this logical stream was encoded in mono.
 402+ *
 403+ * @access public
 404+ * @return boolean
 405+ */
 406+ function isMono()
 407+ {
 408+ return ($this->_channels == 1);
 409+ }
 410+
 411+ /**
 412+ * States whether this logical stream was encoded in stereo.
 413+ *
 414+ * @access public
 415+ * @return boolean
 416+ */
 417+ function isStereo()
 418+ {
 419+ return ($this->_channels == 2);
 420+ }
 421+
 422+ /**
 423+ * States whether this logical stream was encoded in quadrophonic sound.
 424+ *
 425+ * @access public
 426+ * @return boolean
 427+ */
 428+ function isQuadrophonic()
 429+ {
 430+ return ($this->_channels == 4);
 431+ }
 432+
 433+ /**
 434+ * The title of this track, e.g. "What's Up Pussycat?".
 435+ *
 436+ * @access public
 437+ * @return string
 438+ */
 439+ function getTitle()
 440+ {
 441+ return ($this->getField("TITLE"));
 442+ }
 443+
 444+ /**
 445+ * Set the title of this track.
 446+ *
 447+ * @access public
 448+ * @param string $title
 449+ * @param boolean $replace
 450+ */
 451+ function setTitle($title, $replace = true)
 452+ {
 453+ $this->setField("TITLE", $title, $replace);
 454+ }
 455+
 456+ /**
 457+ * The version of the track, such as a remix.
 458+ *
 459+ * @access public
 460+ * @return string
 461+ */
 462+ function getVersion()
 463+ {
 464+ return $this->getField("VERSION");
 465+ }
 466+
 467+ /**
 468+ * Set the version of this track.
 469+ *
 470+ * @access public
 471+ * @param string $version
 472+ * @param boolean $replace
 473+ */
 474+ function setVersion($version, $replace = true)
 475+ {
 476+ $this->setField("VERSION", $version, $replace);
 477+ }
 478+
 479+ /**
 480+ * The album or collection from which this track comes.
 481+ *
 482+ * @access public
 483+ * @return string
 484+ */
 485+ function getAlbum()
 486+ {
 487+ return ($this->getField("ALBUM"));
 488+ }
 489+
 490+ /**
 491+ * Set the album or collection for this track.
 492+ *
 493+ * @access public
 494+ * @param string $album
 495+ * @param boolean $replace
 496+ */
 497+ function setAlbum($album, $replace = true)
 498+ {
 499+ $this->setField("ALBUM", $album, $replace);
 500+ }
 501+
 502+ /**
 503+ * The number of this track if it is part of a larger collection.
 504+ *
 505+ * @access public
 506+ * @return string
 507+ */
 508+ function getTrackNumber()
 509+ {
 510+ return ($this->getField("TRACKNUMBER"));
 511+ }
 512+
 513+ /**
 514+ * Set the number of this relative to the collection.
 515+ *
 516+ * @access public
 517+ * @param int $number
 518+ * @param boolean $replace
 519+ */
 520+ function setTrackNumber($number, $replace = true)
 521+ {
 522+ $this->setField("TRACKNUMBER", $number, $replace);
 523+ }
 524+
 525+ /**
 526+ * The artist responsible for this track.
 527+ *
 528+ * This function returns the name of the artist responsible for this
 529+ * recording, which may be either a solo-artist, duet or group.
 530+ *
 531+ * @access public
 532+ * @return string
 533+ */
 534+ function getArtist()
 535+ {
 536+ return ($this->getField("ARTIST"));
 537+ }
 538+
 539+ /**
 540+ * Set the artist of this track.
 541+ *
 542+ * @access public
 543+ * @param string $artist
 544+ * @param boolean $replace
 545+ */
 546+ function setArtist($artist, $replace = true)
 547+ {
 548+ $this->setField("ARTIST", $artist, $replace = true);
 549+ }
 550+
 551+ /**
 552+ * The performer of this track, such as an orchestra
 553+ *
 554+ * @access public
 555+ * @return string
 556+ */
 557+ function getPerformer()
 558+ {
 559+ return ($this->getField("PERFORMER"));
 560+ }
 561+
 562+ /**
 563+ * Set the performer of this track.
 564+ *
 565+ * @access public
 566+ * @param string $performer
 567+ * @param boolean $replace
 568+ */
 569+ function setPerformer($performer, $replace = true)
 570+ {
 571+ $this->setField("PERFORMER", $performer, $replace);
 572+ }
 573+
 574+ /**
 575+ * The copyright attribution for this track.
 576+ *
 577+ * @access public
 578+ * @return string
 579+ */
 580+ function getCopyright()
 581+ {
 582+ return ($this->getField("COPYRIGHT"));
 583+ }
 584+
 585+ /**
 586+ * Set the copyright attribution for this track.
 587+ *
 588+ * @access public
 589+ * @param string $copyright
 590+ * @param boolean $replace
 591+ */
 592+ function setCopyright($copyright, $replace = true)
 593+ {
 594+ $this->setField("COPYRIGHT", $copyright, $replace);
 595+ }
 596+
 597+ /**
 598+ * The rights of distribution for this track.
 599+ *
 600+ * This funtion returns the license for this track, and may include
 601+ * copyright information, or a creative commons statement.
 602+ *
 603+ * @access public
 604+ * @return string
 605+ */
 606+ function getLicense()
 607+ {
 608+ return ($this->getField("LICENSE"));
 609+ }
 610+
 611+ /**
 612+ * Set the distribution rights for this track.
 613+ *
 614+ * @access public
 615+ * @param string $license
 616+ * @param boolean $replace
 617+ */
 618+ function setLicense($license, $replace = true)
 619+ {
 620+ $this->setField("LICENSE", $license, $replace);
 621+ }
 622+
 623+ /**
 624+ * The organisation responsible for this track.
 625+ *
 626+ * This function returns the name of the organisation responsible for
 627+ * the production of this track, such as the record label.
 628+ *
 629+ * @access public
 630+ * @return string
 631+ */
 632+ function getOrganization()
 633+ {
 634+ return ($this->getField("ORGANIZATION"));
 635+ }
 636+
 637+ /**
 638+ * Set the organisation responsible for this track.
 639+ *
 640+ * @access public
 641+ * @param string $organization
 642+ * @param boolean $replace
 643+ */
 644+ function setOrganziation($organization, $replace = true)
 645+ {
 646+ $this->setField("ORGANIZATION", $organization, $replace);
 647+ }
 648+
 649+ /**
 650+ * A short description of the contents of this track.
 651+ *
 652+ * This function returns a short description of this track, which might
 653+ * contain extra information that doesn't fit anywhere else.
 654+ *
 655+ * @access public
 656+ * @return string
 657+ */
 658+ function getDescription()
 659+ {
 660+ return ($this->getField("DESCRIPTION"));
 661+ }
 662+
 663+ /**
 664+ * Set the description of this track.
 665+ *
 666+ * @access public
 667+ * @param string $description
 668+ * @param boolean $replace
 669+ */
 670+ function setDescription($description, $replace = true)
 671+ {
 672+ $this->setField("DESCRIPTION", $replace);
 673+ }
 674+
 675+ /**
 676+ * The genre of this recording (e.g. Rock)
 677+ *
 678+ * This function returns the genre of this recording. There are no pre-
 679+ * defined genres, so this is completely up to the tagging software.
 680+ *
 681+ * @access public
 682+ * @return string
 683+ */
 684+ function getGenre()
 685+ {
 686+ return ($this->getField("GENRE"));
 687+ }
 688+
 689+ /**
 690+ * Set the genre of this track.
 691+ *
 692+ * @access public
 693+ * @param string $genre
 694+ * @param boolean $replace
 695+ */
 696+ function setGenre($genre, $replace = true)
 697+ {
 698+ $this->setField("GENRE", $genre, $replace);
 699+ }
 700+
 701+ /**
 702+ * The date of the recording of this track.
 703+ *
 704+ * This function returns the date on which this recording was made. There
 705+ * is no specification for the format of this date.
 706+ *
 707+ * @access public
 708+ * @return string
 709+ */
 710+ function getDate()
 711+ {
 712+ return ($this->getField("DATE"));
 713+ }
 714+
 715+ /**
 716+ * Set the date of recording for this track.
 717+ *
 718+ * @access public
 719+ * @param string $date
 720+ * @param boolean $replace
 721+ */
 722+ function setDate($date, $replace = true)
 723+ {
 724+ $this->setField("DATE", $date, $replace);
 725+ }
 726+
 727+ /**
 728+ * Where this recording was made.
 729+ *
 730+ * This function returns where this recording was made, such as a recording
 731+ * studio, or concert venue.
 732+ *
 733+ * @access public
 734+ * @return string
 735+ */
 736+ function getLocation()
 737+ {
 738+ return ($this->getField("LOCATION"));
 739+ }
 740+
 741+ /**
 742+ * Set the location of the recording of this track.
 743+ *
 744+ * @access public
 745+ * @param string $location
 746+ * @param boolean $replace
 747+ */
 748+ function setLocation($location, $replace = true)
 749+ {
 750+ $this->setField("LOCATION", $location, $replace);
 751+ }
 752+
 753+ /**
 754+ * @access public
 755+ * @return string
 756+ */
 757+ function getContact()
 758+ {
 759+ return ($this->getField("CONTACT"));
 760+ }
 761+
 762+ /**
 763+ * Set the contact information for this track.
 764+ *
 765+ * @access public
 766+ * @param string $contact
 767+ * @param boolean $replace
 768+ */
 769+ function setContact($contact, $replace = true)
 770+ {
 771+ $this->setField("CONTACT", $contact, $replace);
 772+ }
 773+
 774+ /**
 775+ * International Standard Recording Code.
 776+ *
 777+ * Returns the International Standard Recording Code. This code can be
 778+ * validated using the Validate_ISPN package.
 779+ *
 780+ * @access public
 781+ * @return string
 782+ */
 783+ function getIsrc()
 784+ {
 785+ return ($this->getField("ISRC"));
 786+ }
 787+
 788+ /**
 789+ * Set the ISRC for this track.
 790+ *
 791+ * @access public
 792+ * @param string $isrc
 793+ * @param boolean $replace
 794+ */
 795+ function setIsrc($isrc, $replace = true)
 796+ {
 797+ $this->setField("ISRC", $isrc, $replace);
 798+ }
 799+
 800+ /**
 801+ * Get an associative array containing header information about the stream
 802+ * @access public
 803+ * @return array
 804+ */
 805+ function getHeader() {
 806+ return $this->_idHeader;
 807+ }
 808+}
 809+?>
Index: trunk/extensions/MetavidWiki/skins/mv_embed/oggServer/PEAR/File_Ogg/File/Ogg/Flac.php
@@ -0,0 +1,134 @@
 2+<?php
 3+/* vim: set expandtab tabstop=4 shiftwidth=4: */
 4+// +----------------------------------------------------------------------------+
 5+// | File_Ogg PEAR Package for Accessing Ogg Bitstreams |
 6+// | Copyright (c) 2005-2007 |
 7+// | David Grant <david@grant.org.uk> |
 8+// | Tim Starling <tstarling@wikimedia.org> |
 9+// +----------------------------------------------------------------------------+
 10+// | This library is free software; you can redistribute it and/or |
 11+// | modify it under the terms of the GNU Lesser General Public |
 12+// | License as published by the Free Software Foundation; either |
 13+// | version 2.1 of the License, or (at your option) any later version. |
 14+// | |
 15+// | This library is distributed in the hope that it will be useful, |
 16+// | but WITHOUT ANY WARRANTY; without even the implied warranty of |
 17+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
 18+// | Lesser General Public License for more details. |
 19+// | |
 20+// | You should have received a copy of the GNU Lesser General Public |
 21+// | License along with this library; if not, write to the Free Software |
 22+// | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
 23+// +----------------------------------------------------------------------------+
 24+
 25+require_once('File/Ogg/Media.php');
 26+
 27+/**
 28+ * @author David Grant <david@grant.org.uk>, Tim Starling <tstarling@wikimedia.org>
 29+ * @category File
 30+ * @copyright David Grant <david@grant.org.uk>, Tim Starling <tstarling@wikimedia.org>
 31+ * @license http://www.gnu.org/copyleft/lesser.html GNU LGPL
 32+ * @link http://pear.php.net/package/File_Ogg
 33+ * @link http://flac.sourceforge.net/documentation.html
 34+ * @package File_Ogg
 35+ * @version CVS: $Id: Flac.php,v 1.9 2005/11/16 20:43:27 djg Exp $
 36+ */
 37+class File_Ogg_Flac extends File_Ogg_Media
 38+{
 39+ /**
 40+ * @access private
 41+ */
 42+ function __construct($streamSerial, $streamData, $filePointer)
 43+ {
 44+ parent::__construct($streamSerial, $streamData, $filePointer);
 45+ $this->_decodeHeader();
 46+ $this->_decodeCommentsHeader();
 47+ $this->_streamLength = $this->_streamInfo['total_samples']
 48+ / $this->_streamInfo['sample_rate'];
 49+ }
 50+
 51+ /**
 52+ * Get a short string describing the type of the stream
 53+ * @return string
 54+ */
 55+ function getType() {
 56+ return 'FLAC';
 57+ }
 58+
 59+ /**
 60+ * @access private
 61+ * @param int $packetType
 62+ * @param int $pageOffset
 63+ */
 64+ function _decodeHeader()
 65+ {
 66+ fseek($this->_filePointer, $this->_streamList[0]['body_offset'], SEEK_SET);
 67+ // Check if this is the correct header.
 68+ $packet = unpack("Cdata", fread($this->_filePointer, 1));
 69+ if ($packet['data'] != 0x7f)
 70+ throw new PEAR_Exception("Stream Undecodable", OGG_ERROR_UNDECODABLE);
 71+
 72+ // The following four characters should be "FLAC".
 73+ if (fread($this->_filePointer, 4) != 'FLAC')
 74+ throw new PEAR_Exception("Stream is undecodable due to a malformed header.", OGG_ERROR_UNDECODABLE);
 75+
 76+ $version = unpack("Cmajor/Cminor", fread($this->_filePointer, 2));
 77+ $this->_version = "{$version['major']}.{$version['minor']}";
 78+ if ($version['major'] > 1) {
 79+ throw new PEAR_Exception("Cannot decode a version {$version['major']} FLAC stream", OGG_ERROR_UNDECODABLE);
 80+ }
 81+ $h = File_Ogg::_readBigEndian( $this->_filePointer,
 82+ array(
 83+ // Ogg-specific
 84+ 'num_headers' => 16,
 85+ 'flac_native_sig' => 32,
 86+ // METADATA_BLOCK_HEADER
 87+ 'is_last' => 1,
 88+ 'type' => 7,
 89+ 'length' => 24,
 90+ ));
 91+
 92+ // METADATA_BLOCK_STREAMINFO
 93+ // The variable names are canonical, and come from the FLAC source (format.h)
 94+ $this->_streamInfo = File_Ogg::_readBigEndian( $this->_filePointer,
 95+ array(
 96+ 'min_blocksize' => 16,
 97+ 'max_blocksize' => 16,
 98+ 'min_framesize' => 24,
 99+ 'max_framesize' => 24,
 100+ 'sample_rate' => 20,
 101+ 'channels' => 3,
 102+ 'bits_per_sample' => 5,
 103+ 'total_samples' => 36,
 104+ ));
 105+ $this->_streamInfo['md5sum'] = bin2hex(fread($this->_filePointer, 16));
 106+ }
 107+
 108+ /**
 109+ * Get an associative array containing header information about the stream
 110+ * @access public
 111+ * @return array
 112+ */
 113+ function getHeader()
 114+ {
 115+ return $this->_streamInfo;
 116+ }
 117+
 118+ function _decodeCommentsHeader()
 119+ {
 120+ fseek($this->_filePointer, $this->_streamList[1]['body_offset'], SEEK_SET);
 121+ $blockHeader = File_Ogg::_readBigEndian( $this->_filePointer,
 122+ array(
 123+ 'last_block' => 1,
 124+ 'block_type' => 7,
 125+ 'length' => 24
 126+ )
 127+ );
 128+ if ($blockHeader['block_type'] != 4) {
 129+ throw new PEAR_Exception("Stream Undecodable", OGG_ERROR_UNDECODABLE);
 130+ }
 131+
 132+ $this->_decodeBareCommentsHeader();
 133+ }
 134+}
 135+?>
Index: trunk/extensions/MetavidWiki/skins/mv_embed/oggServer/PEAR/File_Ogg/File/Ogg/Bitstream.php
@@ -0,0 +1,141 @@
 2+<?php
 3+/* vim: set expandtab tabstop=4 shiftwidth=4: */
 4+// +----------------------------------------------------------------------------+
 5+// | File_Ogg PEAR Package for Accessing Ogg Bitstreams |
 6+// | Copyright (c) 2005-2007 |
 7+// | David Grant <david@grant.org.uk> |
 8+// | Tim Starling <tstarling@wikimedia.org> |
 9+// +----------------------------------------------------------------------------+
 10+// | This library is free software; you can redistribute it and/or |
 11+// | modify it under the terms of the GNU Lesser General Public |
 12+// | License as published by the Free Software Foundation; either |
 13+// | version 2.1 of the License, or (at your option) any later version. |
 14+// | |
 15+// | This library is distributed in the hope that it will be useful, |
 16+// | but WITHOUT ANY WARRANTY; without even the implied warranty of |
 17+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
 18+// | Lesser General Public License for more details. |
 19+// | |
 20+// | You should have received a copy of the GNU Lesser General Public |
 21+// | License along with this library; if not, write to the Free Software |
 22+// | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
 23+// +----------------------------------------------------------------------------+
 24+
 25+
 26+/**
 27+ * @author David Grant <david@grant.org.uk>, Tim Starling <tstarling@wikimedia.org>
 28+ * @category File
 29+ * @copyright David Grant <david@grant.org.uk>, Tim Starling <tstarling@wikimedia.org>
 30+ * @license http://www.gnu.org/copyleft/lesser.html GNU LGPL
 31+ * @link http://pear.php.net/package/File_Ogg
 32+ * @package File_Ogg
 33+ * @version CVS: $Id: Bitstream.php,v 1.3 2005/11/08 19:36:18 djg Exp $
 34+ */
 35+class File_Ogg_Bitstream
 36+{
 37+ /**
 38+ * The serial number of this logical stream.
 39+ *
 40+ * @var int
 41+ * @access private
 42+ */
 43+ var $_streamSerial;
 44+ /**
 45+ * @access private
 46+ */
 47+ var $_streamList;
 48+ /**
 49+ * @access private
 50+ */
 51+ var $_filePointer;
 52+ /**
 53+ * The number of bits used in this stream.
 54+ *
 55+ * @var int
 56+ * @access private
 57+ */
 58+ var $_streamSize;
 59+
 60+ /**
 61+ * The last granule position in the stream
 62+ * @var int
 63+ * @access private
 64+ */
 65+ var $_lastGranulePos;
 66+
 67+ /**
 68+ * Constructor for a generic logical stream.
 69+ *
 70+ * @param int $streamSerial Serial number of the logical stream.
 71+ * @param array $streamData Data for the requested logical stream.
 72+ * @param string $filePath Location of a file on the filesystem.
 73+ * @param pointer $filePointer File pointer for the current physical stream.
 74+ * @access private
 75+ */
 76+ function __construct($streamSerial, $streamData, $filePointer)
 77+ {
 78+ $this->_streamSerial = $streamSerial;
 79+ $this->_streamList = $streamData;
 80+ $this->_filePointer = $filePointer;
 81+ $this->_lastGranulePos = 0;
 82+ $this->_firstGranulePos = 0;
 83+ // This gives an accuracy of approximately 99.7% to the streamsize of ogginfo.
 84+ foreach ( $streamData as $packet ) {
 85+ # Reject -1 as a granule pos, that means no segment finished in the packet
 86+ if ( $packet['abs_granule_pos'] != 'ffffffffffffffff' ) {
 87+ $this->_streamSize += $packet['data_length'];
 88+ # Reject -1 as a granule pos, that means no segment finished in the packet
 89+ if ( $packet['abs_granule_pos'] != 'ffffffffffffffff' ) {
 90+ $currentPos = $packet['abs_granule_pos'];
 91+ $this->_lastGranulePos = max($this->_lastGranulePos, $currentPos);
 92+ //set the _firstGranulePos
 93+ if( hexdec( $this->_firstGranulePos ) === 0){
 94+ //print "on stream: $streamSerial set first gran:". $currentPos.": ". hexdec( $currentPos ) ."\n";
 95+ $this->_firstGranulePos = $currentPos;
 96+ }
 97+ }
 98+ }
 99+ }
 100+ $this->_group = $streamData[0]['group'];
 101+ }
 102+
 103+ /**
 104+ * Gives the serial number of this stream.
 105+ *
 106+ * The stream serial number is of fairly academic importance, as it makes little
 107+ * difference to the end user. The serial number is used by the Ogg physical
 108+ * stream to distinguish between concurrent logical streams.
 109+ *
 110+ * @return int
 111+ * @access public
 112+ */
 113+ function getSerial()
 114+ {
 115+ return ($this->_streamSerial);
 116+ }
 117+
 118+ /**
 119+ * Gives the size (in bits) of this stream.
 120+ *
 121+ * This function returns the size of the Vorbis stream within the Ogg
 122+ * physical stream.
 123+ *
 124+ * @return int
 125+ * @access public
 126+ */
 127+ function getSize()
 128+ {
 129+ return ($this->_streamSize);
 130+ }
 131+
 132+ /**
 133+ * Get the multiplexed group ID
 134+ */
 135+ function getGroup()
 136+ {
 137+ return $this->_group;
 138+ }
 139+
 140+}
 141+
 142+?>
Index: trunk/extensions/MetavidWiki/skins/mv_embed/oggServer/PEAR/File_Ogg/File/Ogg/Media.php
@@ -0,0 +1,233 @@
 2+<?php
 3+/* vim: set expandtab tabstop=4 shiftwidth=4: */
 4+// +----------------------------------------------------------------------------+
 5+// | File_Ogg PEAR Package for Accessing Ogg Bitstreams |
 6+// | Copyright (c) 2005-2007 |
 7+// | David Grant <david@grant.org.uk> |
 8+// | Tim Starling <tstarling@wikimedia.org> |
 9+// +----------------------------------------------------------------------------+
 10+// | This library is free software; you can redistribute it and/or |
 11+// | modify it under the terms of the GNU Lesser General Public |
 12+// | License as published by the Free Software Foundation; either |
 13+// | version 2.1 of the License, or (at your option) any later version. |
 14+// | |
 15+// | This library is distributed in the hope that it will be useful, |
 16+// | but WITHOUT ANY WARRANTY; without even the implied warranty of |
 17+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
 18+// | Lesser General Public License for more details. |
 19+// | |
 20+// | You should have received a copy of the GNU Lesser General Public |
 21+// | License along with this library; if not, write to the Free Software |
 22+// | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
 23+// +----------------------------------------------------------------------------+
 24+
 25+require_once('File/Ogg/Bitstream.php');
 26+
 27+/**
 28+ * Parent class for media bitstreams
 29+ * Contains some functions common to various media formats
 30+ */
 31+abstract class File_Ogg_Media extends File_Ogg_Bitstream
 32+{
 33+ /**
 34+ * Array to hold each of the comments.
 35+ *
 36+ * @access private
 37+ * @var array
 38+ */
 39+ var $_comments = array();
 40+ /**
 41+ * Vendor string for the stream.
 42+ *
 43+ * @access private
 44+ * @var string
 45+ */
 46+ var $_vendor;
 47+
 48+ /**
 49+ * Length of the stream in seconds
 50+ */
 51+ var $_streamLength;
 52+
 53+ /* Start offset of the stream in seconds */
 54+ var $_startOffset = 0;
 55+
 56+ /**
 57+ * Get a short string describing the type of the stream
 58+ * @return string
 59+ */
 60+ abstract function getType();
 61+
 62+ /**
 63+ * Get the 6-byte identification string expected in the common header
 64+ * @return string
 65+ */
 66+ function getIdentificationString()
 67+ {
 68+ return '';
 69+ }
 70+
 71+ /**
 72+ * @access private
 73+ * @param int $packetType
 74+ * @param int $pageOffset
 75+ */
 76+ function _decodeCommonHeader($packetType, $pageOffset)
 77+ {
 78+ fseek($this->_filePointer, $this->_streamList[$pageOffset]['body_offset'], SEEK_SET);
 79+ if ($packetType !== false) {
 80+ // Check if this is the correct header.
 81+ $packet = unpack("Cdata", fread($this->_filePointer, 1));
 82+ if ($packet['data'] != $packetType)
 83+ throw new PEAR_Exception("Stream Undecodable", OGG_ERROR_UNDECODABLE);
 84+
 85+ // The following six characters should be equal to getIdentificationString()
 86+ $id = $this->getIdentificationString();
 87+ if ($id !== '' && fread($this->_filePointer, strlen($id)) !== $id)
 88+ throw new PEAR_Exception("Stream is undecodable due to a malformed header.", OGG_ERROR_UNDECODABLE);
 89+ } // else seek only, no common header
 90+ }
 91+
 92+ /**
 93+ * Parse a Vorbis-style comments header.
 94+ *
 95+ * This function parses the comments header. The comments header contains a series of
 96+ * UTF-8 comments related to the audio encoded in the stream. This header also contains
 97+ * a string to identify the encoding software. More details on the comments header can
 98+ * be found at the following location: http://xiph.org/vorbis/doc/v-comment.html
 99+ *
 100+ * @access private
 101+ */
 102+ function _decodeBareCommentsHeader()
 103+ {
 104+ // Decode the vendor string length as a 32-bit unsigned integer.
 105+ $vendor_len = unpack("Vdata", fread($this->_filePointer, 4));
 106+ if ( $vendor_len['data'] > 0 ) {
 107+ // Retrieve the vendor string from the stream.
 108+ $this->_vendor = fread($this->_filePointer, $vendor_len['data']);
 109+ } else {
 110+ $this->_vendor = '';
 111+ }
 112+ // Decode the size of the comments list as a 32-bit unsigned integer.
 113+ $comment_list_length = unpack("Vdata", fread($this->_filePointer, 4));
 114+ // Iterate through the comments list.
 115+ for ($i = 0; $i < $comment_list_length['data']; ++$i) {
 116+ // Unpack the length of this comment.
 117+ $comment_length = unpack("Vdata", fread($this->_filePointer, 4));
 118+ // Comments are in the format 'ARTIST=Super Furry Animals', so split it on the equals character.
 119+ // NOTE: Equals characters are strictly prohibited in either the COMMENT or DATA parts.
 120+ $comment = explode("=", fread($this->_filePointer, $comment_length['data']));
 121+ $comment_title = (string) $comment[0];
 122+ $comment_value = (string) utf8_decode($comment[1]);
 123+
 124+ // Check if the comment type (e.g. ARTIST) already exists. If it does,
 125+ // take the new value, and the existing value (or array) and insert it
 126+ // into a new array. This is important, since each comment type may have
 127+ // multiple instances (e.g. ARTIST for a collaboration) and we should not
 128+ // overwrite the previous value.
 129+ if (isset($this->_comments[$comment_title])) {
 130+ if (is_array($this->_comments[$comment_title]))
 131+ $this->_comments[$comment_title][] = $comment_value;
 132+ else
 133+ $this->_comments[$comment_title] = array($this->_comments[$comment_title], $comment_value);
 134+ } else
 135+ $this->_comments[$comment_title] = $comment_value;
 136+ }
 137+ }
 138+
 139+ /**
 140+ * Provides a list of the comments extracted from the Vorbis stream.
 141+ *
 142+ * It is recommended that the user fully inspect the array returned by this function
 143+ * rather than blindly requesting a comment in false belief that it will always
 144+ * be present. Whilst the Vorbis specification dictates a number of popular
 145+ * comments (e.g. TITLE, ARTIST, etc.) for use in Vorbis streams, they are not
 146+ * guaranteed to appear.
 147+ *
 148+ * @access public
 149+ * @return array
 150+ */
 151+ function getCommentList()
 152+ {
 153+ return (array_keys($this->_comments));
 154+ }
 155+
 156+ /**
 157+ * Provides an interface to the numerous comments located with a Vorbis stream.
 158+ *
 159+ * A Vorbis stream may contain one or more instances of each comment, so the user
 160+ * should check the variable type before printing out the result of this method.
 161+ * The situation in which multiple instances of a comment occurring are not as
 162+ * rare as one might think, since they are conceivable at least for ARTIST comments
 163+ * in the situation where a track is a duet.
 164+ *
 165+ * @access public
 166+ * @param string $commentTitle Comment title to search for, e.g. TITLE.
 167+ * @param string $separator String to separate multiple values.
 168+ * @return string
 169+ */
 170+ function getField($commentTitle, $separator = ", ")
 171+ {
 172+ if (isset($this->_comments[$commentTitle])) {
 173+ if (is_array($this->_comments[$commentTitle]))
 174+ return (implode($separator, $this->_comments[$commentTitle]));
 175+ else
 176+ return ($this->_comments[$commentTitle]);
 177+ } else
 178+ // The comment doesn't exist in this file. The user should've called getCommentList first.
 179+ return ("");
 180+ }
 181+
 182+ /**
 183+ * Get the entire comments array.
 184+ * May return an empty array if the bitstream does not support comments.
 185+ *
 186+ * @access public
 187+ * @return array
 188+ */
 189+ function getComments() {
 190+ return $this->_comments;
 191+ }
 192+
 193+ /**
 194+ * Vendor of software used to encode this stream.
 195+ *
 196+ * Gives the vendor string for the software used to encode this stream.
 197+ * It is common to find libVorbis here. The majority of encoders appear
 198+ * to use libvorbis from Xiph.org.
 199+ *
 200+ * @access public
 201+ * @return string
 202+ */
 203+ function getVendor()
 204+ {
 205+ return ($this->_vendor);
 206+ }
 207+
 208+ /**
 209+ * Get an associative array containing header information about the stream
 210+ * @access public
 211+ * @return array
 212+ */
 213+ function getHeader()
 214+ {
 215+ return array();
 216+ }
 217+
 218+ /**
 219+ * Get the length of the stream in seconds
 220+ * @return float
 221+ */
 222+ function getLength()
 223+ {
 224+ return $this->_streamLength;
 225+ }
 226+ /**
 227+ * Get the start offset of the stream in seconds
 228+ *
 229+ * @return float
 230+ */
 231+ function getStartOffset(){
 232+ return $this->_startOffset;
 233+ }
 234+}
Index: trunk/extensions/MetavidWiki/skins/mv_embed/oggServer/PEAR/File_Ogg/File/Ogg/Theora.php
@@ -0,0 +1,267 @@
 2+<?php
 3+/* vim: set expandtab tabstop=4 shiftwidth=4: */
 4+// +----------------------------------------------------------------------------+
 5+// | File_Ogg PEAR Package for Accessing Ogg Bitstreams |
 6+// | Copyright (c) 2005-2007 |
 7+// | David Grant <david@grant.org.uk> |
 8+// | Tim Starling <tstarling@wikimedia.org> |
 9+// +----------------------------------------------------------------------------+
 10+// | This library is free software; you can redistribute it and/or |
 11+// | modify it under the terms of the GNU Lesser General Public |
 12+// | License as published by the Free Software Foundation; either |
 13+// | version 2.1 of the License, or (at your option) any later version. |
 14+// | |
 15+// | This library is distributed in the hope that it will be useful, |
 16+// | but WITHOUT ANY WARRANTY; without even the implied warranty of |
 17+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
 18+// | Lesser General Public License for more details. |
 19+// | |
 20+// | You should have received a copy of the GNU Lesser General Public |
 21+// | License along with this library; if not, write to the Free Software |
 22+// | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
 23+// +----------------------------------------------------------------------------+
 24+
 25+require_once('File/Ogg/Bitstream.php');
 26+
 27+define( 'OGG_THEORA_IDENTIFICATION_HEADER', 0x80 );
 28+define( 'OGG_THEORA_COMMENTS_HEADER', 0x81 );
 29+define( 'OGG_THEORA_IDENTIFICATION_PAGE_OFFSET', 0 );
 30+define( 'OGG_THEORA_COMMENTS_PAGE_OFFSET', 1 );
 31+
 32+
 33+/**
 34+ * @author David Grant <david@grant.org.uk>, Tim Starling <tstarling@wikimedia.org>
 35+ * @category File
 36+ * @copyright David Grant <david@grant.org.uk>, Tim Starling <tstarling@wikimedia.org>
 37+ * @license http://www.gnu.org/copyleft/lesser.html GNU LGPL
 38+ * @link http://pear.php.net/package/File_Ogg
 39+ * @link http://www.xiph.org/theora/
 40+ * @package File_Ogg
 41+ * @version CVS: $Id: Theora.php,v 1.9 2005/11/16 20:43:27 djg Exp $
 42+ */
 43+class File_Ogg_Theora extends File_Ogg_Media
 44+{
 45+ /**
 46+ * @access private
 47+ */
 48+ function __construct($streamSerial, $streamData, $filePointer)
 49+ {
 50+ parent::__construct($streamSerial, $streamData, $filePointer);
 51+ $this->_decodeIdentificationHeader();
 52+ $this->_decodeCommentsHeader();
 53+ $endSec = $this->getSecondsFromGranulePos( $this->_lastGranulePos );
 54+
 55+ $startSec = $this->getSecondsFromGranulePos( $this->_firstGranulePos );
 56+
 57+ //make sure the offset is worth taking into account oggz_chop related hack
 58+ if( $startSec > 1){
 59+ $this->_streamLength = $endSec - $startSec;
 60+ $this->_startOffset = $startSec;
 61+ }else{
 62+ $this->_streamLength = $endSec;
 63+ }
 64+
 65+ $this->_avgBitrate = $this->_streamLength ? ($this->_streamSize * 8) / $this->_streamLength : 0;
 66+ }
 67+ function getKeyFrameIndex(){
 68+ $kAry = array();
 69+ foreach($this->_streamList as & $packet){
 70+ # Reject -1 as a granule pos, that means no segment finished in the packet
 71+ if ( $packet['abs_granule_pos'] != 'ffffffffffffffff' ) {
 72+ //get the top & bottom word:
 73+ $topWord = floatval( base_convert( substr( $packet['abs_granule_pos'], 0, 8 ), 16, 10 ) );
 74+ $bottomWord = floatval( base_convert( substr( $packet['abs_granule_pos'], 8, 8 ), 16, 10 ) );
 75+
 76+ $keyFramePos = $topWord / pow(2, $this->_kfgShift - 32) +
 77+ floor( $bottomWord / pow(2, $this->_kfgShift) );
 78+
 79+ $offset = fmod( $bottomWord, pow(2, $this->_kfgShift) );
 80+
 81+ $kTime = ( $keyFramePos ) / $this->_frameRate;
 82+ $time = ( $keyFramePos + $offset ) / $this->_frameRate;
 83+ /*print "paket:: " . print_r($packet, true) . "
 84+ K:$kTime
 85+ rt:$time ( " . ( $offset / $this->_frameRate ) . " \n\n";*/
 86+ if(!isset($kAry[ (string)$kTime ])){
 87+ $kAry[ (string)$kTime ] = $packet['head_offset'];
 88+ }
 89+ }
 90+ }
 91+ return $kAry;
 92+ }
 93+ function getSecondsFromGranulePos($granulePos){
 94+ // Calculate GranulePos seconds
 95+ // First make some "numeric strings"
 96+ // These might not fit into PHP's integer type, but they will fit into
 97+ // the 53-bit mantissa of a double-precision number
 98+ $topWord = floatval( base_convert( substr( $granulePos, 0, 8 ), 16, 10 ) );
 99+ $bottomWord = floatval( base_convert( substr( $granulePos, 8, 8 ), 16, 10 ) );
 100+ // Calculate the keyframe position by shifting right by KFGSHIFT
 101+ // We don't use PHP's shift operators because they're terribly broken
 102+ // This is made slightly simpler by the fact that KFGSHIFT < 32
 103+ $keyFramePos = $topWord / pow(2, $this->_kfgShift - 32) +
 104+ floor( $bottomWord / pow(2, $this->_kfgShift) );
 105+ // Calculate the frame offset by masking off the top 64-KFGSHIFT bits
 106+ // This requires a bit of floating point trickery
 107+ $offset = fmod( $bottomWord, pow(2, $this->_kfgShift) );
 108+ // They didn't teach you that one at school did they?
 109+ // Now put it together with the frame rate to calculate time in seconds
 110+ return ( $keyFramePos + $offset ) / $this->_frameRate;
 111+ }
 112+ /**
 113+ * Get the 6-byte identification string expected in the common header
 114+ */
 115+ function getIdentificationString()
 116+ {
 117+ return OGG_STREAM_CAPTURE_THEORA;
 118+ }
 119+
 120+ /**
 121+ * Parse the identification header in a Theora stream.
 122+ * @access private
 123+ */
 124+ function _decodeIdentificationHeader()
 125+ {
 126+ $this->_decodeCommonHeader(OGG_THEORA_IDENTIFICATION_HEADER, OGG_THEORA_IDENTIFICATION_PAGE_OFFSET);
 127+ $h = File_Ogg::_readBigEndian( $this->_filePointer, array(
 128+ 'VMAJ' => 8,
 129+ 'VMIN' => 8,
 130+ 'VREV' => 8,
 131+ 'FMBW' => 16,
 132+ 'FMBH' => 16,
 133+ 'PICW' => 24,
 134+ 'PICH' => 24,
 135+ 'PICX' => 8,
 136+ 'PICY' => 8,
 137+ 'FRN' => 32,
 138+ 'FRD' => 32,
 139+ 'PARN' => 24,
 140+ 'PARD' => 24,
 141+ 'CS' => 8,
 142+ 'NOMBR' => 24,
 143+ 'QUAL' => 6,
 144+ 'KFGSHIFT' => 5,
 145+ 'PF' => 2));
 146+ if ( !$h ) {
 147+ throw new PEAR_Exception("Stream is undecodable due to a truncated header.", OGG_ERROR_UNDECODABLE);
 148+ }
 149+
 150+ // Theora version
 151+ // Seems overly strict but this is what the spec says
 152+ // VREV is for backwards-compatible changes, apparently
 153+ if ( $h['VMAJ'] != 3 || $h['VMIN'] != 2 ) {
 154+ throw new PEAR_Exception("Stream is undecodable due to an invalid theora version.", OGG_ERROR_UNDECODABLE);
 155+ }
 156+ $this->_theoraVersion = "{$h['VMAJ']}.{$h['VMIN']}.{$h['VREV']}";
 157+
 158+ // Frame height/width
 159+ if ( !$h['FMBW'] || !$h['FMBH'] ) {
 160+ throw new PEAR_Exception("Stream is undecodable because it has frame size of zero.", OGG_ERROR_UNDECODABLE);
 161+ }
 162+ $this->_frameWidth = $h['FMBW'] * 16;
 163+ $this->_frameHeight = $h['FMBH'] * 16;
 164+
 165+ // Picture height/width
 166+ if ( $h['PICW'] > $this->_frameWidth || $h['PICH'] > $this->_frameHeight ) {
 167+ throw new PEAR_Exception("Stream is undecodable because the picture width is greater than the frame width.", OGG_ERROR_UNDECODABLE);
 168+ }
 169+ $this->_pictureWidth = $h['PICW'];
 170+ $this->_pictureHeight = $h['PICH'];
 171+
 172+ // Picture offset
 173+ $this->_offsetX = $h['PICX'];
 174+ $this->_offsetY = $h['PICY'];
 175+ // Frame rate
 176+ $this->_frameRate = $h['FRD'] == 0 ? 0 : $h['FRN'] / $h['FRD'];
 177+ // Physical aspect ratio
 178+ if ( !$h['PARN'] || !$h['PARD'] ) {
 179+ $this->_physicalAspectRatio = 1;
 180+ } else {
 181+ $this->_physicalAspectRatio = $h['PARN'] / $h['PARD'];
 182+ }
 183+
 184+ // Color space
 185+ $colorSpaces = array(
 186+ 0 => 'Undefined',
 187+ 1 => 'Rec. 470M',
 188+ 2 => 'Rec. 470BG',
 189+ );
 190+ if ( isset( $colorSpaces[$h['CS']] ) ) {
 191+ $this->_colorSpace = $colorSpaces[$h['CS']];
 192+ } else {
 193+ $this->_colorSpace = 'Unknown (reserved)';
 194+ }
 195+
 196+ $this->_nomBitrate = $h['NOMBR'];
 197+
 198+ $this->_quality = $h['QUAL'];
 199+ $this->_kfgShift = $h['KFGSHIFT'];
 200+
 201+ $pixelFormats = array(
 202+ 0 => '4:2:0',
 203+ 1 => 'Unknown (reserved)',
 204+ 2 => '4:2:2',
 205+ 3 => '4:4:4',
 206+ );
 207+ $this->_pixelFormat = $pixelFormats[$h['PF']];
 208+
 209+ switch ( $h['PF'] ) {
 210+ case 0:
 211+ $h['NSBS'] =
 212+ floor( ($h['FMBW'] + 1) / 2 ) *
 213+ floor( ($h['FMBH'] + 1) / 2 ) + 2 *
 214+ floor( ($h['FMBW'] + 3) / 4 ) *
 215+ floor( ($h['FMBH'] + 3) / 4 );
 216+ $h['NBS'] = 6 * $h['FMBW'] * $h['FMBH'];
 217+ break;
 218+ case 2:
 219+ $h['NSBS'] =
 220+ floor( ($h['FMBW'] + 1) / 2 ) *
 221+ floor( ($h['FMBH'] + 1) / 2 ) + 2 *
 222+ floor( ($h['FMBW'] + 3) / 4 ) *
 223+ floor( ($h['FMBH'] + 1) / 2 );
 224+ $h['NBS'] = 8 * $h['FMBW'] * $h['FMBH'];
 225+ break;
 226+ case 3:
 227+ $h['NSBS'] =
 228+ 3 * floor( ($h['FMBW'] + 1) / 2 ) *
 229+ floor( ($h['FMBH'] + 1) / 2 );
 230+ $h['NBS'] = 12 * $h['FMBW'] * $h['FMBH'];
 231+ break;
 232+ default:
 233+ $h['NSBS'] = $h['NBS'] = 0;
 234+ }
 235+ $h['NMBS'] = $h['FMBW'] * $h['FMBH'];
 236+
 237+ $this->_idHeader = $h;
 238+ }
 239+
 240+ /**
 241+ * Get an associative array containing header information about the stream
 242+ * @access public
 243+ * @return array
 244+ */
 245+ function getHeader() {
 246+ return $this->_idHeader;
 247+ }
 248+
 249+ /**
 250+ * Get a short string describing the type of the stream
 251+ * @return string
 252+ */
 253+ function getType() {
 254+ return 'Theora';
 255+ }
 256+
 257+ /**
 258+ * Decode the comments header
 259+ * @access private
 260+ */
 261+ function _decodeCommentsHeader()
 262+ {
 263+ $this->_decodeCommonHeader(OGG_THEORA_COMMENTS_HEADER, OGG_THEORA_COMMENTS_PAGE_OFFSET);
 264+ $this->_decodeBareCommentsHeader();
 265+ }
 266+
 267+}
 268+?>
Index: trunk/extensions/MetavidWiki/skins/mv_embed/oggServer/PEAR/File_Ogg/File/README
@@ -0,0 +1,4 @@
 2+This was originally a fork of the File_Ogg package in PEAR. I (TS) have now taken
 3+over maintainership of that package, and have merged my work back to there,
 4+starting with version 0.3.0.
 5+
Index: trunk/extensions/MetavidWiki/skins/mv_embed/oggServer/PEAR/File_Ogg/File/Ogg.php
@@ -0,0 +1,594 @@
 2+<?php
 3+/* vim: set expandtab tabstop=4 shiftwidth=4: */
 4+// +----------------------------------------------------------------------------+
 5+// | File_Ogg PEAR Package for Accessing Ogg Bitstreams |
 6+// | Copyright (c) 2005-2007 |
 7+// | David Grant <david@grant.org.uk> |
 8+// | Tim Starling <tstarling@wikimedia.org> |
 9+// +----------------------------------------------------------------------------+
 10+// | This library is free software; you can redistribute it and/or |
 11+// | modify it under the terms of the GNU Lesser General Public |
 12+// | License as published by the Free Software Foundation; either |
 13+// | version 2.1 of the License, or (at your option) any later version. |
 14+// | |
 15+// | This library is distributed in the hope that it will be useful, |
 16+// | but WITHOUT ANY WARRANTY; without even the implied warranty of |
 17+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
 18+// | Lesser General Public License for more details. |
 19+// | |
 20+// | You should have received a copy of the GNU Lesser General Public |
 21+// | License along with this library; if not, write to the Free Software |
 22+// | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
 23+// +----------------------------------------------------------------------------+
 24+
 25+/**
 26+ * @author David Grant <david@grant.org.uk>, Tim Starling <tstarling@wikimedia.org>
 27+ * @category File
 28+ * @copyright David Grant <david@grant.org.uk>, Tim Starling <tstarling@wikimedia.org>
 29+ * @license http://www.gnu.org/copyleft/lesser.html GNU LGPL
 30+ * @link http://pear.php.net/package/File_Ogg
 31+ * @package File_Ogg
 32+ * @version CVS: $Id: Ogg.php,v 1.14 2005/11/19 09:06:30 djg Exp $
 33+ */
 34+
 35+/**
 36+ * @access public
 37+ */
 38+define("OGG_STREAM_VORBIS", 1);
 39+/**
 40+ * @access public
 41+ */
 42+define("OGG_STREAM_THEORA", 2);
 43+/**
 44+ * @access public
 45+ */
 46+define("OGG_STREAM_SPEEX", 3);
 47+/**
 48+ * @access public
 49+ */
 50+define("OGG_STREAM_FLAC", 4);
 51+
 52+/**
 53+ * Capture pattern to determine if a file is an Ogg physical stream.
 54+ *
 55+ * @access private
 56+ */
 57+define("OGG_CAPTURE_PATTERN", "OggS");
 58+/**
 59+ * Maximum size of an Ogg stream page plus four. This value is specified to allow
 60+ * efficient parsing of the physical stream. The extra four is a paranoid measure
 61+ * to make sure a capture pattern is not split into two parts accidentally.
 62+ *
 63+ * @access private
 64+ */
 65+define("OGG_MAXIMUM_PAGE_SIZE", 65311);
 66+/**
 67+ * Capture pattern for an Ogg Vorbis logical stream.
 68+ *
 69+ * @access private
 70+ */
 71+define("OGG_STREAM_CAPTURE_VORBIS", "vorbis");
 72+/**
 73+ * Capture pattern for an Ogg Speex logical stream.
 74+ * @access private
 75+ */
 76+define("OGG_STREAM_CAPTURE_SPEEX", "Speex ");
 77+/**
 78+ * Capture pattern for an Ogg FLAC logical stream.
 79+ *
 80+ * @access private
 81+ */
 82+define("OGG_STREAM_CAPTURE_FLAC", "FLAC");
 83+/**
 84+ * Capture pattern for an Ogg Theora logical stream.
 85+ *
 86+ * @access private
 87+ */
 88+define("OGG_STREAM_CAPTURE_THEORA", "theora");
 89+/**
 90+ * Error thrown if the file location passed is nonexistant or unreadable.
 91+ *
 92+ * @access private
 93+ */
 94+define("OGG_ERROR_INVALID_FILE", 1);
 95+/**
 96+ * Error thrown if the user attempts to extract an unsupported logical stream.
 97+ *
 98+ * @access private
 99+ */
 100+define("OGG_ERROR_UNSUPPORTED", 2);
 101+/**
 102+ * Error thrown if the user attempts to extract an logical stream with no
 103+ * corresponding serial number.
 104+ *
 105+ * @access private
 106+ */
 107+define("OGG_ERROR_BAD_SERIAL", 3);
 108+/**
 109+ * Error thrown if the stream appears to be corrupted.
 110+ *
 111+ * @access private
 112+ */
 113+define("OGG_ERROR_UNDECODABLE", 4);
 114+
 115+require_once('PEAR.php');
 116+require_once('PEAR/Exception.php');
 117+require_once('File/Ogg/Bitstream.php');
 118+require_once("File/Ogg/Flac.php");
 119+require_once("File/Ogg/Speex.php");
 120+require_once("File/Ogg/Theora.php");
 121+require_once("File/Ogg/Vorbis.php");
 122+
 123+
 124+/**
 125+ * Class for parsing a ogg bitstream.
 126+ *
 127+ * This class provides a means to access several types of logical bitstreams (e.g. Vorbis)
 128+ * within a Ogg physical bitstream.
 129+ *
 130+ * @link http://www.xiph.org/ogg/doc/
 131+ * @package File_Ogg
 132+ */
 133+class File_Ogg
 134+{
 135+ /**
 136+ * File pointer to Ogg container.
 137+ *
 138+ * This is the file pointer used for extracting data from the Ogg stream. It is
 139+ * the result of a standard fopen call.
 140+ *
 141+ * @var pointer
 142+ * @access private
 143+ */
 144+ var $_filePointer;
 145+
 146+ /**
 147+ * The container for all logical streams.
 148+ *
 149+ * List of all of the unique streams in the Ogg physical stream. The key
 150+ * used is the unique serial number assigned to the logical stream by the
 151+ * encoding application.
 152+ *
 153+ * @var array
 154+ * @access private
 155+ */
 156+ var $_streamList = array();
 157+ var $_streams = array();
 158+
 159+ /**
 160+ * Length in seconds of each stream group
 161+ */
 162+ var $_groupLengths = array();
 163+
 164+ /**
 165+ * Total length in seconds of the entire file
 166+ */
 167+ var $_totalLength;
 168+ var $_startOffset = false;
 169+ /**
 170+ * Returns an interface to an Ogg physical stream.
 171+ *
 172+ * This method takes the path to a local file and examines it for a physical
 173+ * ogg bitsream. After instantiation, the user should query the object for
 174+ * the logical bitstreams held within the ogg container.
 175+ *
 176+ * @access public
 177+ * @param string $fileLocation The path of the file to be examined.
 178+ */
 179+ function __construct($fileLocation)
 180+ {
 181+ clearstatcache();
 182+ if (! file_exists($fileLocation)) {
 183+ throw new PEAR_Exception("Couldn't Open File. Check File Path.", OGG_ERROR_INVALID_FILE);
 184+ }
 185+
 186+ // Open this file as a binary, and split the file into streams.
 187+ $this->_filePointer = fopen($fileLocation, "rb");
 188+ if (!is_resource($this->_filePointer))
 189+ throw new PEAR_Exception("Couldn't Open File. Check File Permissions.", OGG_ERROR_INVALID_FILE);
 190+
 191+ // Check for a stream at the start
 192+ $magic = fread($this->_filePointer, strlen(OGG_CAPTURE_PATTERN));
 193+ if ($magic !== OGG_CAPTURE_PATTERN) {
 194+ throw new PEAR_Exception("Couldn't read file: Incorrect magic number.", OGG_ERROR_UNDECODABLE);
 195+ }
 196+ fseek($this->_filePointer, 0, SEEK_SET);
 197+
 198+ $this->_splitStreams();
 199+ fclose($this->_filePointer);
 200+ }
 201+
 202+ /**
 203+ * Little-endian equivalent for bin2hex
 204+ * @static
 205+ */
 206+ static function _littleEndianBin2Hex( $bin ) {
 207+ $bigEndian = bin2hex( $bin );
 208+ // Reverse entire string
 209+ $reversed = strrev( $bigEndian );
 210+ // Swap nibbles back
 211+ for ( $i = 0; $i < strlen( $bigEndian ); $i += 2 ) {
 212+ $temp = $reversed[$i];
 213+ $reversed[$i] = $reversed[$i+1];
 214+ $reversed[$i+1] = $temp;
 215+ }
 216+ return $reversed;
 217+ }
 218+
 219+
 220+ /**
 221+ * Read a binary structure from a file. An array of unsigned integers are read.
 222+ * Large integers are upgraded to floating point on overflow.
 223+ *
 224+ * Format is big-endian as per Theora bit packing convention, this function
 225+ * won't work for Vorbis.
 226+ *
 227+ * @param resource $file
 228+ * @param array $fields Associative array mapping name to length in bits
 229+ */
 230+ static function _readBigEndian($file, $fields)
 231+ {
 232+ $bufferLength = ceil(array_sum($fields) / 8);
 233+ $buffer = fread($file, $bufferLength);
 234+ if (strlen($buffer) != $bufferLength) {
 235+ throw new PEAR_Exception('Unexpected end of file', OGG_ERROR_UNDECODABLE);
 236+ }
 237+ $bytePos = 0;
 238+ $bitPos = 0;
 239+ $byteValue = ord($buffer[0]);
 240+ $output = array();
 241+ foreach ($fields as $name => $width) {
 242+ if ($width % 8 == 0 && $bitPos == 0) {
 243+ // Byte aligned case
 244+ $bytes = $width / 8;
 245+ $endBytePos = $bytePos + $bytes;
 246+ $value = 0;
 247+ while ($bytePos < $endBytePos) {
 248+ $value = ($value * 256) + ord($buffer[$bytePos]);
 249+ $bytePos++;
 250+ }
 251+ if ($bytePos < strlen($buffer)) {
 252+ $byteValue = ord($buffer[$bytePos]);
 253+ }
 254+ } else {
 255+ // General case
 256+ $bitsRemaining = $width;
 257+ $value = 0;
 258+ while ($bitsRemaining > 0) {
 259+ $bitsToRead = min($bitsRemaining, 8 - $bitPos);
 260+ $byteValue <<= $bitsToRead;
 261+ $overflow = ($byteValue & 0xff00) >> 8;
 262+ $byteValue &= $byteValue & 0xff;
 263+
 264+ $bitPos += $bitsToRead;
 265+ $bitsRemaining -= $bitsToRead;
 266+ $value += $overflow * pow(2, $bitsRemaining);
 267+
 268+ if ($bitPos >= 8) {
 269+ $bitPos = 0;
 270+ $bytePos++;
 271+ if ($bitsRemaining <= 0) {
 272+ break;
 273+ }
 274+ $byteValue = ord($buffer[$bytePos]);
 275+ }
 276+ }
 277+ }
 278+ $output[$name] = $value;
 279+ assert($bytePos <= $bufferLength);
 280+ }
 281+ return $output;
 282+ }
 283+
 284+ /**
 285+ * Read a binary structure from a file. An array of unsigned integers are read.
 286+ * Large integers are upgraded to floating point on overflow.
 287+ *
 288+ * Format is little-endian as per Vorbis bit packing convention.
 289+ *
 290+ * @param resource $file
 291+ * @param array $fields Associative array mapping name to length in bits
 292+ */
 293+ static function _readLittleEndian( $file, $fields ) {
 294+ $bufferLength = ceil(array_sum($fields) / 8);
 295+ $buffer = fread($file, $bufferLength);
 296+ if (strlen($buffer) != $bufferLength) {
 297+ throw new PEAR_Exception('Unexpected end of file', OGG_ERROR_UNDECODABLE);
 298+ }
 299+
 300+ $bytePos = 0;
 301+ $bitPos = 0;
 302+ $byteValue = ord($buffer[0]) << 8;
 303+ $output = array();
 304+ foreach ($fields as $name => $width) {
 305+ if ($width % 8 == 0 && $bitPos == 0) {
 306+ // Byte aligned case
 307+ $bytes = $width / 8;
 308+ $value = 0;
 309+ for ($i = 0; $i < $bytes; $i++, $bytePos++) {
 310+ $value += pow(256, $i) * ord($buffer[$bytePos]);
 311+ }
 312+ if ($bytePos < strlen($buffer)) {
 313+ $byteValue = ord($buffer[$bytePos]) << 8;
 314+ }
 315+ } else {
 316+ // General case
 317+ $bitsRemaining = $width;
 318+ $value = 0;
 319+ while ($bitsRemaining > 0) {
 320+ $bitsToRead = min($bitsRemaining, 8 - $bitPos);
 321+ $byteValue >>= $bitsToRead;
 322+ $overflow = ($byteValue & 0xff) >> (8 - $bitsToRead);
 323+ $byteValue &= 0xff00;
 324+
 325+ $value += $overflow * pow(2, $width - $bitsRemaining);
 326+ $bitPos += $bitsToRead;
 327+ $bitsRemaining -= $bitsToRead;
 328+
 329+ if ($bitPos >= 8) {
 330+ $bitPos = 0;
 331+ $bytePos++;
 332+ if ($bitsRemaining <= 0) {
 333+ break;
 334+ }
 335+ $byteValue = ord($buffer[$bytePos]) << 8;
 336+ }
 337+ }
 338+ }
 339+ $output[$name] = $value;
 340+ assert($bytePos <= $bufferLength);
 341+ }
 342+ return $output;
 343+ }
 344+
 345+
 346+ /**
 347+ * @access private
 348+ */
 349+ function _decodePageHeader($pageData, $pageOffset, $groupId)
 350+ {
 351+ // Extract the various bits and pieces found in each packet header.
 352+ if (substr($pageData, 0, 4) != OGG_CAPTURE_PATTERN)
 353+ return (false);
 354+
 355+ $stream_version = unpack("C1data", substr($pageData, 4, 1));
 356+ if ($stream_version['data'] != 0x00)
 357+ return (false);
 358+
 359+ $header_flag = unpack("Cdata", substr($pageData, 5, 1));
 360+
 361+ // Exact granule position
 362+ $abs_granule_pos = self::_littleEndianBin2Hex( substr($pageData, 6, 8));
 363+ // Approximate (floating point) granule position
 364+ $pos = unpack("Va/Vb", substr($pageData, 6, 8));
 365+ $approx_granule_pos = $pos['a'] + $pos['b'] * pow(2, 32);
 366+
 367+ // Serial number for the current datastream.
 368+ $stream_serial = unpack("Vdata", substr($pageData, 14, 4));
 369+ $page_sequence = unpack("Vdata", substr($pageData, 18, 4));
 370+ $checksum = unpack("Vdata", substr($pageData, 22, 4));
 371+ $page_segments = unpack("Cdata", substr($pageData, 26, 1));
 372+ $segments_total = 0;
 373+ for ($i = 0; $i < $page_segments['data']; ++$i) {
 374+ $segment_length = unpack("Cdata", substr($pageData, 26 + ($i + 1), 1));
 375+ $segments_total += $segment_length['data'];
 376+ }
 377+ $pageFinish = $pageOffset + 27 + $page_segments['data'] + $segments_total;
 378+ $page = array(
 379+ 'stream_version' => $stream_version['data'],
 380+ 'header_flag' => $header_flag['data'],
 381+ 'abs_granule_pos' => $abs_granule_pos,
 382+ 'approx_granule_pos' => $approx_granule_pos,
 383+ 'checksum' => sprintf("%u", $checksum['data']),
 384+ 'segments' => $page_segments['data'],
 385+ 'head_offset' => $pageOffset,
 386+ 'body_offset' => $pageOffset + 27 + $page_segments['data'],
 387+ 'body_finish' => $pageFinish,
 388+ 'data_length' => $pageFinish - $pageOffset,
 389+ 'group' => $groupId,
 390+ );
 391+ $this->_streamList[$stream_serial['data']]['stream_page'][$page_sequence['data']] = $page;
 392+ return $page;
 393+ }
 394+
 395+ /**
 396+ * @access private
 397+ */
 398+ function _splitStreams()
 399+ {
 400+ // Loop through the physical stream until there are no more pages to read.
 401+ $groupId = 0;
 402+ $openStreams = 0;
 403+ $this_page_offset = 0;
 404+ while (!feof($this->_filePointer)) {
 405+ $pageData = fread($this->_filePointer, 282);
 406+ if (strval($pageData) === '') {
 407+ break;
 408+ }
 409+ $page = $this->_decodePageHeader($pageData, $this_page_offset, $groupId);
 410+ if ($page === false) {
 411+ throw new PEAR_Exception("Cannot decode Ogg file: Invalid page at offset $this_page_offset", OGG_ERROR_UNDECODABLE);
 412+ }
 413+
 414+ // Keep track of multiplexed groups
 415+ if ($page['header_flag'] & 2/*bos*/) {
 416+ $openStreams++;
 417+ } elseif ($page['header_flag'] & 4/*eos*/) {
 418+ $openStreams--;
 419+ if (!$openStreams) {
 420+ // End of group
 421+ $groupId++;
 422+ }
 423+ }
 424+ if ($openStreams < 0) {
 425+ throw new PEAR_Exception("Unexpected end of stream", OGG_ERROR_UNDECODABLE);
 426+ }
 427+
 428+ $this_page_offset = $page['body_finish'];
 429+ fseek($this->_filePointer, $this_page_offset, SEEK_SET);
 430+ }
 431+ // Loop through the streams, and find out what type of stream is available.
 432+ $groupLengths = array();
 433+ foreach ($this->_streamList as $stream_serial => $pages) {
 434+ fseek($this->_filePointer, $pages['stream_page'][0]['body_offset'], SEEK_SET);
 435+ $pattern = fread($this->_filePointer, 8);
 436+ if (preg_match("/" . OGG_STREAM_CAPTURE_VORBIS . "/", $pattern)) {
 437+ $this->_streamList[$stream_serial]['stream_type'] = OGG_STREAM_VORBIS;
 438+ $stream = new File_Ogg_Vorbis($stream_serial, $pages['stream_page'], $this->_filePointer);
 439+ } elseif (preg_match("/" . OGG_STREAM_CAPTURE_SPEEX . "/", $pattern)) {
 440+ $this->_streamList[$stream_serial]['stream_type'] = OGG_STREAM_SPEEX;
 441+ $stream = new File_Ogg_Speex($stream_serial, $pages['stream_page'], $this->_filePointer);
 442+ } elseif (preg_match("/" . OGG_STREAM_CAPTURE_FLAC . "/", $pattern)) {
 443+ $this->_streamList[$stream_serial]['stream_type'] = OGG_STREAM_FLAC;
 444+ $stream = new File_Ogg_Flac($stream_serial, $pages['stream_page'], $this->_filePointer);
 445+ } elseif (preg_match("/" . OGG_STREAM_CAPTURE_THEORA . "/", $pattern)) {
 446+ $this->_streamList[$stream_serial]['stream_type'] = OGG_STREAM_THEORA;
 447+ $stream = new File_Ogg_Theora($stream_serial, $pages['stream_page'], $this->_filePointer);
 448+ } else {
 449+ $pages['stream_type'] = "unknown";
 450+ $stream = false;
 451+ }
 452+
 453+ if ($stream) {
 454+ $this->_streams[$stream_serial] = $stream;
 455+ $group = $pages['stream_page'][0]['group'];
 456+ if (isset($groupLengths[$group])) {
 457+ $groupLengths[$group] = max($groupLengths[$group], $stream->getLength());
 458+ } else {
 459+ $groupLengths[$group] = $stream->getLength();
 460+ }
 461+ //just store the startOffset for the first stream:
 462+ if( $this->_startOffset === false ){
 463+ $this->_startOffset = $stream->getStartOffset();
 464+ }
 465+
 466+ }
 467+ }
 468+ $this->_groupLengths = $groupLengths;
 469+ $this->_totalLength = array_sum( $groupLengths );
 470+ unset($this->_streamList);
 471+ }
 472+
 473+ /**
 474+ * Returns the overead percentage used by the Ogg headers.
 475+ *
 476+ * This function returns the percentage of the total stream size
 477+ * used for Ogg headers.
 478+ *
 479+ * @return float
 480+ */
 481+ function getOverhead() {
 482+ $header_size = 0;
 483+ $stream_size = 0;
 484+ foreach ($this->_streams as $serial => $stream) {
 485+ foreach ($stream->_streamList as $offset => $stream_data) {
 486+ $header_size += $stream_data['body_offset'] - $stream_data['head_offset'];
 487+ $stream_size = $stream_data['body_finish'];
 488+ }
 489+ }
 490+ return sprintf("%0.2f", ($header_size / $stream_size) * 100);
 491+ }
 492+
 493+ /**
 494+ * Returns the appropriate logical bitstream that corresponds to the provided serial.
 495+ *
 496+ * This function returns a logical bitstream contained within the Ogg physical
 497+ * stream, corresponding to the serial used as the offset for that bitstream.
 498+ * The returned stream may be Vorbis, Speex, FLAC or Theora, although the only
 499+ * usable bitstream is Vorbis.
 500+ *
 501+ * @return File_Ogg_Bitstream
 502+ */
 503+ function &getStream($streamSerial)
 504+ {
 505+ if (! array_key_exists($streamSerial, $this->_streams))
 506+ throw new PEAR_Exception("The stream number is invalid.", OGG_ERROR_BAD_SERIAL);
 507+
 508+ return $this->_streams[$streamSerial];
 509+ }
 510+
 511+ /**
 512+ * This function returns true if a logical bitstream of the requested type can be found.
 513+ *
 514+ * This function checks the contents of this ogg physical bitstream for of logical
 515+ * bitstream corresponding to the supplied type. If one is found, the function returns
 516+ * true, otherwise it return false.
 517+ *
 518+ * @param int $streamType
 519+ * @return boolean
 520+ */
 521+ function hasStream($streamType)
 522+ {
 523+ foreach ($this->_stream as $stream) {
 524+ if ($stream['stream_type'] == $streamType)
 525+ return (true);
 526+ }
 527+ return (false);
 528+ }
 529+
 530+ /**
 531+ * Returns an array of logical streams inside this physical bitstream.
 532+ *
 533+ * This function returns an array of logical streams found within this physical
 534+ * bitstream. If a filter is provided, only logical streams of the requested type
 535+ * are returned, as an array of serial numbers. If no filter is provided, this
 536+ * function returns a two-dimensional array, with the stream type as the primary key,
 537+ * and a value consisting of an array of stream serial numbers.
 538+ *
 539+ * @param int $filter
 540+ * @return array
 541+ */
 542+ function listStreams($filter = null)
 543+ {
 544+ $streams = array();
 545+ // Loops through the streams and assign them to an appropriate index,
 546+ // ready for filtering the second part of this function.
 547+ foreach ($this->_streams as $serial => $stream) {
 548+ $stream_type = 0;
 549+ switch (get_class($stream)) {
 550+ case "file_ogg_flac":
 551+ $stream_type = OGG_STREAM_FLAC;
 552+ break;
 553+ case "file_ogg_speex":
 554+ $stream_type = OGG_STREAM_SPEEX;
 555+ break;
 556+ case "file_ogg_theora":
 557+ $stream_type = OGG_STREAM_THEORA;
 558+ break;
 559+ case "file_ogg_vorbis":
 560+ $stream_type = OGG_STREAM_VORBIS;
 561+ break;
 562+ }
 563+ if (! isset($streams[$stream_type]))
 564+ // Initialise the result list for this stream type.
 565+ $streams[$stream_type] = array();
 566+
 567+ $streams[$stream_type][] = $serial;
 568+ }
 569+
 570+ // Perform filtering.
 571+ if (is_null($filter))
 572+ return ($streams);
 573+ elseif (isset($streams[$filter]))
 574+ return ($streams[$filter]);
 575+ else
 576+ return array();
 577+ }
 578+ /**
 579+ * getStartOffset
 580+ *
 581+ * @return unknown
 582+ */
 583+ function getStartOffset(){
 584+ if( $this->_startOffset === false)
 585+ return 0;
 586+ return $this->_startOffset;
 587+ }
 588+ /**
 589+ * Get the total length of the group of streams
 590+ */
 591+ function getLength() {
 592+ return $this->_totalLength;
 593+ }
 594+}
 595+?>

Status & tagging log