Add support for Vorbis I

git-svn-id: http://php-reader.googlecode.com/svn/trunk@233 51a70ab9-7547-0410-9469-37e369ee0574
This commit is contained in:
svollbehr
2011-05-14 16:00:55 +00:00
parent acce677af2
commit 1ac772d14c
5 changed files with 455 additions and 98 deletions

View File

@@ -39,6 +39,7 @@ require_once 'Zend/Media/Ogg/Page.php';
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License * @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$ * @version $Id$
* @todo Currently supports only one logical bitstream
*/ */
final class Zend_Media_Ogg_Reader extends Zend_Io_Reader final class Zend_Media_Ogg_Reader extends Zend_Io_Reader
{ {
@@ -51,9 +52,6 @@ final class Zend_Media_Ogg_Reader extends Zend_Io_Reader
/** @var integer */ /** @var integer */
private $_currentPagePosition = 0; private $_currentPagePosition = 0;
/** @var integer */
private $_streamSize = 0;
/** /**
* Constructs the Ogg class with given file. * Constructs the Ogg class with given file.
* *
@@ -70,7 +68,7 @@ final class Zend_Media_Ogg_Reader extends Zend_Io_Reader
'page' => $page = new Zend_Media_Ogg_Page($reader), 'page' => $page = new Zend_Media_Ogg_Page($reader),
'offset' => $reader->getOffset() 'offset' => $reader->getOffset()
); );
$this->_streamSize += $page->getPageSize(); $this->_size += $page->getPageSize();
$reader->skip($page->getPageSize()); $reader->skip($page->getPageSize());
} }
$reader->setOffset($this->_pages[$this->_currentPage]['offset']); $reader->setOffset($this->_pages[$this->_currentPage]['offset']);
@@ -113,17 +111,6 @@ final class Zend_Media_Ogg_Reader extends Zend_Io_Reader
} }
} }
/**
* Overwrite the method to return the Ogg bitstream size in bytes.
*
* @return integer
*/
public function getSize()
{
echo "getSize\n";
return $this->_streamSize;
}
/** /**
* Overwrite the method to jump <var>size</var> amount of bytes in the Ogg bitstream. * Overwrite the method to jump <var>size</var> amount of bytes in the Ogg bitstream.
* *

143
src/Zend/Media/Vorbis.php Normal file
View File

@@ -0,0 +1,143 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Media
* @subpackage Vorbis
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
/**#@+ @ignore */
require_once 'Zend/Io/Reader.php';
require_once 'Zend/Media/Vorbis/Header/Identification.php';
require_once 'Zend/Media/Vorbis/Header/Comment.php';
require_once 'Zend/Media/Vorbis/Header/Setup.php';
/**#@-*/
/**
* This class represents a file containing Vorbis bitstream as described in
* {@link http://xiph.org/vorbis/doc/Vorbis_I_spec.pdf Vorbis I specification}.
*
* Vorbis is a general purpose perceptual audio CODEC intended to allow maximum encoder exibility, thus allowing it to
* scale competitively over an exceptionally wide range of bitrates. At the high quality/bitrate end of the scale (CD
* or DAT rate stereo, 16/24 bits) it is in the same league as MPEG-2 and MPC. Similarly, the 1.0 encoder can encode
* high-quality CD and DAT rate stereo at below 48kbps without resampling to a lower rate. Vorbis is also intended for
* lower and higher sample rates (from 8kHz telephony to 192kHz digital masters) and a range of channel representations
* (monaural, polyphonic, stereo, quadraphonic, 5.1, ambisonic, or up to 255 discrete channels).
*
* @category Zend
* @package Zend_Media
* @subpackage Vorbis
* @author Sven Vollbehr <sven@vollbehr.eu>
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
* @todo Setup header is not yet supported
*/
final class Zend_Media_Vorbis
{
/** @var Zend_Io_Reader */
private $_reader;
/** @var string */
private $_filename = null;
/** @var Zend_Media_Vorbis_Header_Identification */
private $_identificationHeader;
/** @var Zend_Media_Vorbis_Header_Comment */
private $_commentHeader;
// /** @var Zend_Media_Vorbis_Header_Setup */
// private $_setupHeader;
/**
* Constructs the .
*
* @param string|resource|Zend_Io_Reader $filename The path to the file,
* file descriptor of an opened file, or a {@link Zend_Io_Reader} instance.
* @throws Zend_Io_Exception if an error occur in stream handling.
* @throws Zend_Media_Vorbis_Exception if an error occurs in vorbis bitstream reading.
*/
public function __construct($filename)
{
if ($filename instanceof Zend_Io_Reader) {
$this->_reader = &$filename;
} else {
$this->_filename = $filename;
require_once('Zend/Io/FileReader.php');
try {
$this->_reader = new Zend_Io_FileReader($filename);
} catch (Zend_Io_Exception $e) {
$this->_reader = null;
require_once 'Zend/Media/Vorbis/Exception.php';
throw new Zend_Media_Vorbis_Exception($e->getMessage());
}
}
$this->_identificationHeader = new Zend_Media_Vorbis_Header_Identification($this->_reader);
$this->_commentHeader = new Zend_Media_Vorbis_Header_Comment($this->_reader);
// $this->_setupHeader = new Zend_Media_Vorbis_Header_Setup($this->_reader);
}
/**
* Returns the identification header.
*
* @return Zend_Media_Vorbis_Header_Identification
*/
public function getIdentificationHeader()
{
return $this->_identificationHeader;
}
/**
* Returns the comment header.
*
* @return Zend_Media_Vorbis_Header_Comment
*/
public function getCommentHeader()
{
return $this->_commentHeader;
}
/**
* Returns the setup header.
*
* @return Zend_Media_Vorbis_Header_Setup
*/
public function getSetupHeader()
{
require_once 'Zend/Media/Vorbis/Exception.php';
throw new Zend_Media_Vorbis_Exception('Not yet supported');
// return $this->_setupHeader;
}
/**
* Magic function so that $obj->value will work.
*
* @param string $name The field name.
* @return mixed
*/
public function __get($name)
{
if (method_exists($this, 'get' . ucfirst($name))) {
return call_user_func(array($this, 'get' . ucfirst($name)));
} else {
require_once('Zend/Media/Vorbis/Exception.php');
throw new Zend_Media_Vorbis_Exception('Unknown field: ' . $name);
}
}
}

View File

@@ -46,13 +46,6 @@ abstract class Zend_Media_Vorbis_Header
*/ */
protected $_reader; protected $_reader;
/**
* The options array.
*
* @var Array
*/
private $_options;
/** /**
* The packet type; the identication header is type 1, the comment header type 3 and the setup header type 5. * The packet type; the identication header is type 1, the comment header type 3 and the setup header type 5.
* *
@@ -66,10 +59,9 @@ abstract class Zend_Media_Vorbis_Header
* @param Zend_Io_Reader $reader The reader object. * @param Zend_Io_Reader $reader The reader object.
* @param Array $options The options array. * @param Array $options The options array.
*/ */
public function __construct($reader, &$options = array()) public function __construct($reader)
{ {
$this->_reader = $reader; $this->_reader = $reader;
$this->_options = &$options;
if (!in_array($this->_packetType = $this->_reader->readUInt8(), array(1, 3, 5))) { if (!in_array($this->_packetType = $this->_reader->readUInt8(), array(1, 3, 5))) {
require_once 'Zend/Media/Vorbis/Exception.php'; require_once 'Zend/Media/Vorbis/Exception.php';
@@ -81,62 +73,6 @@ abstract class Zend_Media_Vorbis_Header
} }
} }
/**
* Returns the options array.
*
* @return Array
*/
public final function &getOptions()
{
return $this->_options;
}
/**
* Returns the given option value, or the default value if the option is not
* defined.
*
* @param string $option The name of the option.
* @param mixed $defaultValue The default value to be returned.
*/
public final function getOption($option, $defaultValue = null)
{
if (isset($this->_options[$option])) {
return $this->_options[$option];
}
return $defaultValue;
}
/**
* Sets the options array. See main class for available options.
*
* @param Array $options The options array.
*/
public final function setOptions(&$options)
{
$this->_options = &$options;
}
/**
* Sets the given option the given value.
*
* @param string $option The name of the option.
* @param mixed $value The value to set for the option.
*/
public final function setOption($option, $value)
{
$this->_options[$option] = $value;
}
/**
* Clears the given option value.
*
* @param string $option The name of the option.
*/
public final function clearOption($option)
{
unset($this->_options[$option]);
}
/** /**
* Magic function so that $obj->value will work. * Magic function so that $obj->value will work.
* *
@@ -152,22 +88,4 @@ abstract class Zend_Media_Vorbis_Header
throw new Zend_Media_Vorbis_Exception('Unknown field: ' . $name); throw new Zend_Media_Vorbis_Exception('Unknown field: ' . $name);
} }
} }
/**
* Magic function so that assignments with $obj->value will work.
*
* @param string $name The field name.
* @param string $value The field value.
* @return mixed
*/
public function __set($name, $value)
{
if (method_exists($this, 'set' . ucfirst($name))) {
call_user_func
(array($this, 'set' . ucfirst($name)), $value);
} else {
require_once 'Zend/Media/Vorbis/Exception.php';
throw new Zend_Media_Vorbis_Exception('Unknown field: ' . $name);
}
}
} }

View File

@@ -0,0 +1,139 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled with this package in the file LICENSE.txt. It is
* also available through the world-wide-web at this URL: http://framework.zend.com/license/new-bsd. If you did not
* receive a copy of the license and are unable to obtain it through the world-wide-web, please send an email to
* license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Media
* @subpackage Vorbis
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
/**#@+ @ignore */
require_once 'Zend/Media/Vorbis/Header.php';
/**#@-*/
/**
* The Vorbis text comment header is the second (of three) header packets that begin a Vorbis bitstream. It is meant
* for short text comments, not arbitrary metadata; arbitrary metadata belongs in a separate logical bitstream (usually
* an XML stream type) that provides greater structure and machine parseability.
*
* The comment field is meant to be used much like someone jotting a quick note on the bottom of a CDR. It should be a
* little information to remember the disc by and explain it to others; a short, to-the-point text note that need not
* only be a couple words, but isn't going to be more than a short paragraph. The essentials, in other words, whatever
* they turn out to be, eg:
*
* Honest Bob and the Factory-to-Dealer-Incentives, \I'm Still Around", opening for Moxy Fruvous, 1997.
*
* The following web pages will guide you with applicaple field names and values:
*
* o Recommended set of 15 field names
* http://xiph.org/vorbis/doc/v-comment.html
*
* o Proposed update to the minimal list of 15 standard field names
* http://wiki.xiph.org/Field_names
*
* o Other proposals for additional field names
* http://age.hobba.nl/audio/mirroredpages/ogg-tagging.html
* http://reallylongword.org/vorbiscomment/
*
* @category Zend
* @package Zend_Media
* @subpackage Vorbis
* @author Sven Vollbehr <sven@vollbehr.eu>
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
final class Zend_Media_Vorbis_Header_Comment extends Zend_Media_Vorbis_Header
{
/** @var string */
private $_vendor;
/** @var Array */
private $_comments;
/** @var integer */
private $_framingFlag;
/**
* Constructs the class with given parameters.
*
* @param Zend_Io_Reader $reader The reader object.
*/
public function __construct($reader)
{
parent::__construct($reader);
$this->_vendor = $this->_reader->read($this->_reader->readUInt32LE());
$userCommentListLength = $this->_reader->readUInt32LE();
for ($i = 0; $i < $userCommentListLength; $i++) {
list ($name, $value) = preg_split('/=/', $this->_reader->read($this->_reader->readUInt32LE()), 2);
if (!isset($this->_comments[strtoupper($name)])) {
$this->_comments[strtoupper($name)] = array();
}
$this->_comments[strtoupper($name)][] = $value;
}
$this->_framingFlag = $this->_reader->readUInt8() & 0x1;
if ($this->_framingFlag == 0) {
require_once 'Zend/Media/Vorbis/Exception.php';
throw new Zend_Media_Vorbis_Exception('Undecodable Vorbis stream');
}
}
/**
* Returns an array of comments having the field names as keys and an array of values as a value.
*
* @return Array
*/
public function getComments()
{
return $this->_comments;
}
/**
* Magic function so that $obj->value will work. The method will attempt to return the first field by the given
* name from the comment. If there is no field with given name, functionality of the parent method is executed.
*
* @param string $name The field name.
* @return mixed
*/
public function __get($name)
{
if (!empty($this->_comments[strtoupper($name)])) {
return $this->_comments[strtoupper($name)][0];
}
parent::__get($name);
}
/**
* Magic function so that isset($obj->value) will work. This method checks whether the comment contains a field by
* the given name.
*
* @param string $name The field name.
* @return boolean
*/
public function __isset($name)
{
return empty($this->_comments[strtoupper($name)]);
}
/**
* Magic function so that unset($obj->value) will work. This method removes all the comments matching the field
* name.
*
* @param string $name The field name.
*/
public function __unset($name)
{
unset($this->_comments[strtoupper($name)]);
}
}

View File

@@ -0,0 +1,170 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Media
* @subpackage Vorbis
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
/**#@+ @ignore */
require_once 'Zend/Media/Vorbis/Header.php';
/**#@-*/
/**
* The identication header is a short header of only a few fields used to declare the stream definitively as Vorbis,
* and provide a few externally relevant pieces of information about the audio stream.
*
* @category Zend
* @package Zend_Media
* @subpackage Vorbis
* @author Sven Vollbehr <sven@vollbehr.eu>
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
final class Zend_Media_Vorbis_Header_Identification extends Zend_Media_Vorbis_Header
{
/** @var integer */
private $_vorbisVersion;
/** @var integer */
private $_audioChannels;
/** @var integer */
private $_audioSampleRate;
/** @var integer */
private $_bitrateMaximum;
/** @var integer */
private $_bitrateNominal;
/** @var integer */
private $_bitrateMinimum;
/** @var integer */
private $_blocksize0;
/** @var integer */
private $_blocksize1;
/**
* Constructs the class with given parameters.
*
* @param Zend_Io_Reader $reader The reader object.
*/
public function __construct($reader)
{
parent::__construct($reader);
$this->_vorbisVersion = $this->_reader->readUInt32LE();
$this->_audioChannels = $this->_reader->readUInt8();
$this->_audioSampleRate = $this->_reader->readUInt32LE();
$this->_bitrateMaximum = $this->_reader->readInt32LE();
$this->_bitrateNominal = $this->_reader->readInt32LE();
$this->_bitrateMinimum = $this->_reader->readInt32LE();
$this->_blocksize0 = pow(2, ($tmp = $this->_reader->readUInt8()) & 0xf);
$this->_blocksize1 = pow(2, ($tmp >> 4) & 0xf);
$framingFlag = $this->_reader->readUInt8() & 0x1;
if ($this->_blocksize0 > $this->_blocksize1 || $framingFlag == 0) {
require_once 'Zend/Media/Vorbis/Exception.php';
throw new Zend_Media_Vorbis_Exception('Undecodable Vorbis stream');
}
}
/**
* Returns the vorbis version.
*
* @return integer
*/
public function getVorbisVersion()
{
return $this->_vorbisVersion;
}
/**
* Returns the number of audio channels.
*
* @return integer
*/
public function getAudioChannels()
{
return $this->_audioChannels;
}
/**
* Returns the audio sample rate.
*
* @return integer
*/
public function getAudioSampleRate()
{
return $this->_audioSampleRate;
}
/**
* Returns the maximum bitrate.
*
* @return integer
*/
public function getBitrateMaximum()
{
return $this->_bitrateMaximum;
}
/**
* Returns the nominal bitrate.
*
* @return integer
*/
public function getBitrateNominal()
{
return $this->_bitrateNominal;
}
/**
* Returns the minimum bitrate.
*
* @return integer
*/
public function getBitrateMinimum()
{
return $this->_bitrateMinimum;
}
/**
* Returns the first block size. Allowed final blocksize values are 64, 128, 256, 512, 1024, 2048, 4096 and 8192 in
* Vorbis I.
*
* @return integer
*/
public function getBlocksize1()
{
return $this->_blocksize1;
}
/**
* Returns the second block size. Allowed final blocksize values are 64, 128, 256, 512, 1024, 2048, 4096 and 8192 in
* Vorbis I.
*
* @return integer
*/
public function getBlocksize2()
{
return $this->_blocksize2;
}
}