Add read support for FLAC metadata blocks

git-svn-id: http://php-reader.googlecode.com/svn/trunk@241 51a70ab9-7547-0410-9469-37e369ee0574
This commit is contained in:
svollbehr
2011-06-11 16:46:52 +00:00
parent 0d792cf221
commit 8bdcf4209a
12 changed files with 1431 additions and 12 deletions

245
src/Zend/Media/Flac.php Normal file
View File

@@ -0,0 +1,245 @@
<?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 FLAC
* @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';
/**#@-*/
/**
* This class represents a file FLAC file format as described in {@link http://flac.sourceforge.net/format.html}. FLAC
* stands for Free Lossless Audio Codec, an audio format similar to MP3, but lossless, meaning that audio is compressed
* in FLAC without any loss in quality. This is similar to how Zip works, except with FLAC you will get much better
* compression because it is designed specifically for audio, and you can play back compressed FLAC files in your
* favorite player (or your car or home stereo, see supported devices) just like you would an MP3 file.
*
* FLAC stands out as the fastest and most widely supported lossless audio codec, and the only one that at once is
* non-proprietary, is unencumbered by patents, has an open-source reference implementation, has a well documented
* format and API, and has several other independent implementations.
*
* @category Zend
* @package Zend_Media
* @subpackage FLAC
* @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_Flac
{
/** The streaminfo metadata block */
const STREAMINFO = 0;
/** The padding metadata block */
const PADDING = 1;
/** The application metadata block */
const APPLICATION = 2;
/** The seektable metadata block */
const SEEKTABLE = 3;
/** The vorbis comment metadata block */
const VORBIS_COMMENT = 4;
/** The cuesheet metadata block */
const CUESHEET = 5;
/** The picture metadata block */
const PICTURE = 6;
/** @var Zend_Io_Reader */
private $_reader;
/** @var Array */
private $_metadataBlocks = array();
/** @var string */
private $_filename = null;
/**
* Constructs the class with given filename.
*
* @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_Flac_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/Flac/Exception.php';
throw new Zend_Media_Flac_Exception($e->getMessage());
}
}
$capturePattern = $this->_reader->read(4);
if ($capturePattern != 'fLaC') {
require_once 'Zend/Media/Flac/Exception.php';
throw new Zend_Media_Flac_Exception('Not a valid FLAC bitstream');
}
while (true) {
$offset = $this->_reader->getOffset();
$last = ($tmp = $this->_reader->readUInt8()) >> 7 & 0x1;
$type = $tmp & 0x7f;
$size = $this->_reader->readUInt24BE();
$this->_reader->setOffset($offset);
switch ($type) {
case self::STREAMINFO: // 0
require_once 'Zend/Media/Flac/MetadataBlock/Streaminfo.php';
$this->_metadataBlocks[] = new Zend_Media_Flac_MetadataBlock_Streaminfo($this->_reader);
break;
case self::PADDING: // 1
require_once 'Zend/Media/Flac/MetadataBlock/Padding.php';
$this->_metadataBlocks[] = new Zend_Media_Flac_MetadataBlock_Padding($this->_reader);
break;
case self::APPLICATION: // 2
require_once 'Zend/Media/Flac/MetadataBlock/Application.php';
$this->_metadataBlocks[] = new Zend_Media_Flac_MetadataBlock_Application($this->_reader);
break;
case self::SEEKTABLE: // 3
require_once 'Zend/Media/Flac/MetadataBlock/Seektable.php';
$this->_metadataBlocks[] = new Zend_Media_Flac_MetadataBlock_Seektable($this->_reader);
break;
case self::VORBIS_COMMENT: // 4
require_once 'Zend/Media/Flac/MetadataBlock/VorbisComment.php';
$this->_metadataBlocks[] = new Zend_Media_Flac_MetadataBlock_VorbisComment($this->_reader);
break;
case self::CUESHEET: // 5
require_once 'Zend/Media/Flac/MetadataBlock/Cuesheet.php';
$this->_metadataBlocks[] = new Zend_Media_Flac_MetadataBlock_Cuesheet($this->_reader);
break;
case self::PICTURE: // 6
require_once 'Zend/Media/Flac/MetadataBlock/Picture.php';
$this->_metadataBlocks[] = new Zend_Media_Flac_MetadataBlock_Picture($this->_reader);
break;
default:
// break intentionally omitted
}
$this->_reader->setOffset($offset + 4 /* header */ + $size);
// Jump off the loop if we reached the end of metadata blocks
if ($last === 1) {
break;
}
}
}
/**
* Checks whether the given metadata block is there. Returns <var>true</var> if one ore more frames are present,
* <var>false</var> otherwise.
*
* @param string $type The metadata block type.
* @return boolean
*/
public function hasMetadataBlock($type)
{
$metadataBlockCount = count($this->_metadataBlocks);
for ($i = 0; $i < $metadataBlockCount; $i++) {
if ($this->_metadataBlocks[$i]->getType() === $type) {
return true;
}
}
return false;
}
/**
* Returns all the metadata blocks as an associate array.
*
* @return Array
*/
public function getMetadataBlocks()
{
return $this->_metadataBlocks;
}
/**
* Returns an array of metadata blocks frames matching the given type or an empty array if no metadata blocks
* matched the type.
*
* Please note that one may also use the shorthand $obj->type to access the first metadata block with the given
* type.
*
* @param string $type The metadata block type.
* @return Array
*/
public function getMetadataBlocksByType($type)
{
$matches = array();
$metadataBlockCount = count($this->_metadataBlocks);
for ($i = 0; $i < $metadataBlockCount; $i++) {
if ($this->_metadataBlocks[$i]->getType() === $type) {
$matches[] = $this->_metadataBlocks[$i];
}
}
return $matches;
}
/**
* 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)));
}
if (defined($constant = 'self::' . strtoupper(preg_replace('/(?<=[a-z])[A-Z]/', '_$0', $name)))) {
$metadataBlocks = $this->getMetadataBlocksByType(constant($constant));
if (isset($metadataBlocks[0])) {
return $metadataBlocks[0];
}
}
require_once 'Zend/Media/Flac/Exception.php';
throw new Zend_Media_Flac_Exception('Unknown metadata block or 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(strtolower($name)))) {
call_user_func
(array($this, 'set' . ucfirst(strtolower($name))), $value);
} else {
require_once('Zend/Media/Flac/Exception.php');
throw new Zend_Media_Flac_Exception('Unknown field: ' . $name);
}
}
}

View File

@@ -0,0 +1,40 @@
<?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 FLAC
* @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/Exception.php';
/**#@-*/
/**
* The Zend_Media_Flac_Exception is thrown whenever an error occurs within the {@link Zend_Media_Flac} family of
* classes.
*
* @category Zend
* @package Zend_Media
* @subpackage FLAC
* @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$
*/
class Zend_Media_Flac_Exception extends Zend_Media_Exception
{}

View File

@@ -0,0 +1,173 @@
<?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 FLAC
* @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$
*/
/**
* This class represents a FLAC metadata block. FLAC specifies a metadata system, which allows arbitrary information
* about the stream to be included at the beginning of the stream. FLAC contains a mandatory metadata block (called the
* STREAMINFO block), and any number of other metadata blocks, listed below. After metadata blocks follows the audio
* frames.
*
* FLAC supports up to 128 kinds of metadata blocks; currently the following are defined:
* o STREAMINFO
* This block has information about the whole stream, like sample rate, number of channels, total number of samples,
* etc. It must be present as the first metadata block in the stream. Other metadata blocks may follow, and ones
* that the decoder doesn't understand, it will skip.
* o APPLICATION
* This block is for use by third-party applications. The only mandatory field is a 32-bit identifier. This ID is
* granted upon request to an application by the FLAC maintainers. The remainder is of the block is defined by the
* registered application. Visit the registration page if you would like to register an ID for your application with
* FLAC.
* o PADDING
* This block allows for an arbitrary amount of padding. The contents of a PADDING block have no meaning. This block
* is useful when it is known that metadata will be edited after encoding; the user can instruct the encoder to
* reserve a PADDING block of sufficient size so that when metadata is added, it will simply overwrite the padding
* (which is relatively quick) instead of having to insert it into the right place in the existing file (which would
* normally require rewriting the entire file).
* o SEEKTABLE
* This is an optional block for storing seek points. It is possible to seek to any given sample in a FLAC stream
* without a seek table, but the delay can be unpredictable since the bitrate may vary widely within a stream. By
* adding seek points to a stream, this delay can be significantly reduced. Each seek point takes 18 bytes, so 1%
* resolution within a stream adds less than 2k. There can be only one SEEKTABLE in a stream, but the table can have
* any number of seek points. There is also a special 'placeholder' seekpoint which will be ignored by decoders but
* which can be used to reserve space for future seek point insertion.
* o VORBIS_COMMENT
* This block is for storing a list of human-readable name/value pairs. Values are encoded using UTF-8. It is an
* implementation of the Vorbis comment specification (without the framing bit). This is the only officially
* supported tagging mechanism in FLAC. There may be only one VORBIS_COMMENT block in a stream. In some external
* documentation, Vorbis comments are called FLAC tags to lessen confusion.
* o CUESHEET
* This block is for storing various information that can be used in a cue sheet. It supports track and index points,
* compatible with Red Book CD digital audio discs, as well as other CD-DA metadata such as media catalog number and
* track ISRCs. The CUESHEET block is especially useful for backing up CD-DA discs, but it can be used as a general
* purpose cueing mechanism for playback.
* o PICTURE
* This block is for storing pictures associated with the file, most commonly cover art from CDs. There may be more
* than one PICTURE block in a file. The picture format is similar to the APIC frame in ID3v2. The PICTURE block has
* a type, MIME type, and UTF-8 description like ID3v2, and supports external linking via URL (though this is
* discouraged). The differences are that there is no uniqueness constraint on the description field, and the MIME
* type is mandatory. The FLAC PICTURE block also includes the resolution, color depth, and palette size so that the
* client can search for a suitable picture without having to scan them all.
*
* @category Zend
* @package Zend_Media
* @subpackage FLAC
* @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$
*/
abstract class Zend_Media_Flac_MetadataBlock
{
/**
* The reader object.
*
* @var Zend_Io_Reader
*/
protected $_reader;
/** @var integer */
private $_last;
/** @var integer */
private $_type;
/** @var integer */
private $_size;
/**
* Constructs the class with given parameters and reads object related data
* from the Flac bitstream.
*
* @param Zend_Io_Reader $reader The reader object.
*/
public function __construct($reader)
{
$this->_reader = $reader;
$this->_last = ($tmp = $this->_reader->readUInt8()) >> 7 & 0x1;
$this->_type = $tmp & 0x7f;
$this->_size = $this->_reader->readUInt24BE();
}
/**
* Returns the metadata block type. The type is one of the following.
*
* o 0: STREAMINFO
* o 1: PADDING
* o 2: APPLICATION
* o 3: SEEKTABLE
* o 4: VORBIS_COMMENT
* o 5: CUESHEET
* o 6: PICTURE
* o 7-126: reserved
* o 127: invalid, to avoid confusion with a frame sync code
*
* @return integer
*/
public function getType()
{
return $this->_type;
}
/**
* Returns the metadata block length without the header, in bytes.
*
* @return integer
*/
public function getSize()
{
return $this->_size;
}
/**
* 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/Flac/Exception.php';
throw new Zend_Media_Flac_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/Flac/Exception.php';
throw new Zend_Media_Flac_Exception('Unknown field: ' . $name);
}
}
}

View File

@@ -0,0 +1,77 @@
<?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 FLAC
* @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/Flac/MetadataBlock.php';
/**#@-*/
/**
* This class represents the application metadata block. This block is for use by third-party applications. The only
* mandatory field is a 32-bit identifier. This ID is granted upon request to an application by the FLAC maintainers.
* The remainder is of the block is defined by the registered application. Visit the registration page if you would like
* to register an ID for your application with FLAC.
*
* Applications can be registered at {@link http://flac.sourceforge.net/id.html}.
*
* @category Zend
* @package Zend_Media
* @subpackage FLAC
* @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_Flac_MetadataBlock_Application extends Zend_Media_Flac_MetadataBlock
{
/**
* Constructs the class with given parameters and parses object related data.
*
* @param Zend_Io_Reader $reader The reader object.
*/
public function __construct($reader)
{
parent::__construct($reader);
$this->_identifier = $this->_reader->readUInt32BE();
$this->_data = $this->_reader->read($this->getSize() - 4);
}
/**
* Returns the application identifier.
*
* @return integer
*/
public function getIdentifier()
{
return $this->_identifier;
}
/**
* Returns the application data.
*
* @return string
*/
public function getData()
{
return $this->_data;
}
}

View File

@@ -0,0 +1,189 @@
<?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 FLAC
* @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/Flac/MetadataBlock.php';
/**#@-*/
/**
* This class represents the cuesheet metadata block. This block is for storing various information that can be used in
* a cue sheet. It supports track and index points, compatible with Red Book CD digital audio discs, as well as other
* CD-DA metadata such as media catalog number and track ISRCs. The CUESHEET block is especially useful for backing up
* CD-DA discs, but it can be used as a general purpose cueing mechanism for playback.
*
* @category Zend
* @package Zend_Media
* @subpackage FLAC
* @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_Flac_MetadataBlock_Cuesheet extends Zend_Media_Flac_MetadataBlock
{
/** @var string */
private $_catalogNumber;
/** @var integer */
private $_leadinSamples;
/** @var boolean */
private $_compactDisc;
/** @var Array */
private $_tracks;
/**
* Constructs the class with given parameters and parses object related data.
*
* @param Zend_Io_Reader $reader The reader object.
*/
public function __construct($reader)
{
parent::__construct($reader);
$this->_catalogNumber = rtrim($this->_reader->read(128), "\x00");
$this->_leadinSamples = $this->_reader->readInt64BE();
$this->_compactDisc = ($this->_reader->readUInt8() >> 7) & 0x1;
$this->_reader->skip(258);
$tracksLength = $this->_reader->readUInt8();
for ($i = 0; $i < $tracksLength; $i++) {
$this->_tracks[$i] = array(
'offset' => $this->_reader->readInt64BE(),
'number' => $this->_reader->readUInt8(),
'isrc' => rtrim($this->_reader->read(12), "\x00"),
'type' => (($tmp = $this->_reader->readUInt8()) >> 7 ) & 0x1,
'pre-emphasis' => (($tmp) >> 6 ) & 0x1,
'index' => array());
$this->_reader->skip(13);
$indexPointsLength = $this->_reader->readUInt8();
for ($j = 0; $j < $indexPointsLength; $j++) {
$this->_tracks[$i]['index'][$j] = array(
'offset' => $this->_reader->readInt64BE(),
'number' => $this->_reader->readUInt8()
);
$this->_reader->skip(3);
}
}
}
/**
* Returns the media catalog number, in ASCII printable characters 0x20-0x7e. In general, the media catalog number
* may be 0 to 128 bytes long; any unused characters should be right-padded with NUL characters. For CD-DA, this is
* a thirteen digit number, followed by 115 NUL bytes.minimum block size (in samples) used in the stream.
*
* @return string
*/
public function getCatalogNumber()
{
return $this->_catalogNumber;
}
/**
* Returns the number of lead-in samples. This field has meaning only for CD-DA cuesheets; for other uses it should
* be 0. For CD-DA, the lead-in is the TRACK 00 area where the table of contents is stored; more precisely, it is
* the number of samples from the first sample of the media to the first sample of the first index point of the
* first track. According to the Red Book, the lead-in must be silence and CD grabbing software does not usually
* store it; additionally, the lead-in must be at least two seconds but may be longer. For these reasons the
* lead-in length is stored here so that the absolute position of the first track can be computed. Note that the
* lead-in stored here is the number of samples up to the first index point of the first track, not necessarily to
* INDEX 01 of the first track; even the first track may have INDEX 00 data.
*
* @return integer
*/
public function getLeadinSamples()
{
return $this->_leadinSamples;
}
/**
* Returns the minimum frame size (in bytes) used in the stream. May be 0 to imply the value is not known.
*
* @return integer
*/
public function getMinimumFrameSize()
{
return $this->_minimumFrameSize;
}
/**
* Returns the maximum frame size (in bytes) used in the stream. May be 0 to imply the value is not known.
*
* @return integer
*/
public function getMaximumFrameSize()
{
return $this->_maximumFrameSize;
}
/**
* Returns sample rate in Hz. The maximum sample rate is limited by the structure of frame headers to 655350Hz.
* Also, a value of 0 is invalid.
*
* @return integer
*/
public function getSampleRate()
{
return $this->_sampleRate;
}
/**
* Returns whether the CUESHEET corresponds to a Compact Disc or not.
*
* @return boolean
*/
public function getCompactDisk()
{
return $this->_compactDisk == 1;
}
/**
* Returns an array of values. Each entry is an array containing the following keys.
* o offset -- Track offset in samples, relative to the beginning of the FLAC audio stream. It is the offset to
* the first index point of the track. (Note how this differs from CD-DA, where the track's offset in the TOC
* is that of the track's INDEX 01 even if there is an INDEX 00.) For CD-DA, the offset must be evenly divisible
* by 588 samples (588 samples = 44100 samples/sec * 1/75th of a sec).
* o number -- Track number. A track number of 0 is not allowed to avoid conflicting with the CD-DA spec, which
* reserves this for the lead-in. For CD-DA the number must be 1-99, or 170 for the lead-out; for non-CD-DA,
* the track number must for 255 for the lead-out. It is not required but encouraged to start with track 1 and
* increase sequentially. Track numbers must be unique within a CUESHEET.
* o isrc -- Track ISRC. This is a 12-digit alphanumeric code or an empty string to denote absence of an ISRC.
* o type -- The track type: 0 for audio, 1 for non-audio. This corresponds to the CD-DA Q-channel control bit 3.
* o pre-emphasis -- The pre-emphasis flag: 0 for no pre-emphasis, 1 for pre-emphasis. This corresponds to the
* CD-DA Q-channel control bit 5.
* o index -- An array of track index points. There must be at least one index in every track in a CUESHEET except
* for the lead-out track, which must have zero. For CD-DA, this number may be no more than 100. Each entry is
* an array containing the following keys.
* o offset -- Offset in samples, relative to the track offset, of the index point. For CD-DA, the offset must
* be evenly divisible by 588 samples (588 samples = 44100 samples/sec * 1/75th of a sec). Note that the
* offset is from the beginning of the track, not the beginning of the audio data.
* o number -- The index point number. For CD-DA, an index number of 0 corresponds to the track pre-gap. The
* first index in a track must have a number of 0 or 1, and subsequently, index numbers must increase by 1.
* Index numbers must be unique within a track.
*
* @return Array
*/
public function getTracks()
{
return $this->_tracks;
}
}

View File

@@ -0,0 +1,53 @@
<?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 FLAC
* @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/Flac/MetadataBlock.php';
/**#@-*/
/**
* This class represents the padding metadata block. This block allows for an arbitrary amount of padding. The contents
* of a PADDING block have no meaning. This block is useful when it is known that metadata will be edited after
* encoding; the user can instruct the encoder to reserve a PADDING block of sufficient size so that when metadata is
* added, it will simply overwrite the padding (which is relatively quick) instead of having to insert it into the right
* place in the existing file (which would normally require rewriting the entire file).
*
* @category Zend
* @package Zend_Media
* @subpackage FLAC
* @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_Flac_MetadataBlock_Padding extends Zend_Media_Flac_MetadataBlock
{
/**
* Constructs the class with given parameters and parses object related data.
*
* @param Zend_Io_Reader $reader The reader object.
*/
public function __construct($reader)
{
parent::__construct($reader);
}
}

View File

@@ -0,0 +1,199 @@
<?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 FLAC
* @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/Flac/MetadataBlock.php';
/**#@-*/
/**
* This class represents the picture metadata block. This block is for storing pictures associated with the file, most
* commonly cover art from CDs. There may be more than one PICTURE block in a file. The picture format is similar to the
* {@link Zend_Media_Id3v2_Frame_Apic APIC} frame in {@link Zend_Media_Id3v2 ID3v2}. The PICTURE block has a type,
* MIME type, and UTF-8 description like {@link Zend_Media_Id3v2 ID3v2}, and supports external linking via URL (though
* this is discouraged). The differences are that there is no uniqueness constraint on the description field, and the
* MIME type is mandatory. The FLAC PICTURE block also includes the resolution, color depth, and palette size so that
* the client can search for a suitable picture without having to scan them all.
*
* @category Zend
* @package Zend_Media
* @subpackage FLAC
* @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_Flac_MetadataBlock_Picture extends Zend_Media_Flac_MetadataBlock
{
/**
* The list of picture types.
*
* @var Array
*/
public static $types = array
('Other', '32x32 pixels file icon (PNG only)', 'Other file icon',
'Cover (front)', 'Cover (back)', 'Leaflet page',
'Media (e.g. label side of CD)', 'Lead artist/lead performer/soloist',
'Artist/performer', 'Conductor', 'Band/Orchestra', 'Composer',
'Lyricist/text writer', 'Recording Location', 'During recording',
'During performance', 'Movie/video screen capture',
'A bright coloured fish', 'Illustration', 'Band/artist logotype',
'Publisher/Studio logotype');
/** @var integer */
private $_type;
/** @var string */
private $_mimeType;
/** @var string */
private $_description;
/** @var integer */
private $_width;
/** @var integer */
private $_height;
/** @var integer */
private $_colorDepth;
/** @var integer */
private $_numberOfColors;
/** @var integer */
private $_dataSize;
/** @var string */
private $_data;
/**
* Constructs the class with given parameters and parses object related data.
*
* @todo There is the possibility to put only a link to the picture file by
* using the MIME type '-->' and having a complete URL instead of picture
* data. Support for such needs design considerations.
* @param Zend_Io_Reader $reader The reader object.
*/
public function __construct($reader)
{
parent::__construct($reader);
$this->_type = $this->_reader->readUInt32BE();
$this->_mimeType = $this->_reader->read($this->_reader->readUInt32BE());
$this->_description = $this->_reader->read($this->_reader->readUInt32BE());
$this->_width = $this->_reader->readUInt32BE();
$this->_height = $this->_reader->readUInt32BE();
$this->_colorDepth = $this->_reader->readUInt32BE();
$this->_numberOfColors = $this->_reader->readUInt32BE();
$this->_data = $this->_reader->read($this->_dataSize = $this->_reader->readUInt32BE());
}
/**
* Returns the picture type.
*
* @return integer
*/
public function getPictureType()
{
return $this->_pictureType;
}
/**
* Returns the MIME type.
*
* @return string
*/
public function getMimeType()
{
return $this->_mimeType;
}
/**
* Returns the picture description.
*
* @return string
*/
public function getDescription()
{
return $this->_description;
}
/**
* Returns the picture width.
*
* @return integer
*/
public function getWidth()
{
return $this->_width;
}
/**
* Returns the picture height.
*
* @return integer
*/
public function getHeight()
{
return $this->_height;
}
/**
* Returns the color depth of the picture in bits-per-pixel.
*
* @return integer
*/
public function getColorDepth()
{
return $this->_colorDepth;
}
/**
* Returns the number of colors used for indexed-color pictures, or 0 for non-indexed pictures.
*
* @return integer
*/
public function getNumberOfColors()
{
return $this->_numberOfColors;
}
/**
* Returns the picture data size.
*
* @return integer
*/
public function getDataSize()
{
return $this->_dataSize;
}
/**
* Returns the picture data.
*
* @return string
*/
public function getData()
{
return $this->_data;
}
}

View File

@@ -0,0 +1,82 @@
<?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 FLAC
* @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/Flac/MetadataBlock.php';
/**#@-*/
/**
* This class represents the seektable metadata block. This is an optional block for storing seek points. It is possible
* to seek to any given sample in a FLAC stream without a seek table, but the delay can be unpredictable since the
* bitrate may vary widely within a stream. By adding seek points to a stream, this delay can be significantly reduced.
* Each seek point takes 18 bytes, so 1% resolution within a stream adds less than 2k. There can be only one SEEKTABLE
* in a stream, but the table can have any number of seek points. There is also a special 'placeholder' seekpoint which
* will be ignored by decoders but which can be used to reserve space for future seek point insertion.
*
* @category Zend
* @package Zend_Media
* @subpackage FLAC
* @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_Flac_MetadataBlock_Seektable extends Zend_Media_Flac_MetadataBlock
{
/** @var Array */
private $_seekpoints = array();
/**
* Constructs the class with given parameters and parses object related data.
*
* @param Zend_Io_Reader $reader The reader object.
*/
public function __construct($reader)
{
parent::__construct($reader);
$seekpointCount = $this->getSize() / 18;
for ($i = 0; $i < $seekpointCount; $i++) {
$this->_seekpoints[] = array(
'sampleNumber' => $this->_reader->readInt64BE(),
'offset' => $this->_reader->readInt64BE(),
'numberOfSamples' => $this->_reader->readUInt16BE()
);
}
}
/**
* Returns the seekpoint table. The array consists of items having three keys.
*
* o sampleNumber -- Sample number of first sample in the target frame, or 0xFFFFFFFFFFFFFFFF for a
* placeholder point.
* o offset -- Offset (in bytes) from the first byte of the first frame header to the first byte of the
* target frame's header.
* o numberOfSamples -- Number of samples in the target frame.
*
* @return Array
*/
public function getSeekpoints()
{
return $this->_seekpoints;
}
}

View File

@@ -0,0 +1,185 @@
<?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 FLAC
* @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/Flac/MetadataBlock.php';
require_once 'Zend/Bit/Twiddling.php';
/**#@-*/
/**
* This class represents the streaminfo metadata block. This block has information about the whole stream, like sample
* rate, number of channels, total number of samples, etc. It must be present as the first metadata block in the stream.
* Other metadata blocks may follow, and ones that the decoder doesn't understand, it will skip.
*
* @category Zend
* @package Zend_Media
* @subpackage FLAC
* @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_Flac_MetadataBlock_Streaminfo extends Zend_Media_Flac_MetadataBlock
{
/** @var integer */
private $_minimumBlockSize;
/** @var integer */
private $_maximumBlockSize;
/** @var integer */
private $_minimumFrameSize;
/** @var integer */
private $_maximumFrameSize;
/** @var integer */
private $_sampleRate;
/** @var integer */
private $_numberOfChannels;
/** @var integer */
private $_bitsPerSample;
/** @var integer */
private $_numberOfSamples;
/** @var string */
private $_md5Signature;
/**
* Constructs the class with given parameters and parses object related data.
*
* @param Zend_Io_Reader $reader The reader object.
*/
public function __construct($reader)
{
parent::__construct($reader);
$this->_minimumBlockSize = $this->_reader->readUInt16BE();
$this->_maximumBlockSize = $this->_reader->readUInt16BE();
$this->_minimumFrameSize = $this->_reader->readUInt24BE();
$this->_maximumFrameSize = $this->_reader->readUInt24BE();
$this->_sampleRate = Zend_Bit_Twiddling::getValue(($tmp = $this->_reader->readUInt32BE()), 12, 31);
$this->_numberOfChannels = Zend_Bit_Twiddling::getValue($tmp, 9, 11) + 1;
$this->_bitsPerSample = Zend_Bit_Twiddling::getValue($tmp, 4, 8) + 1;
$this->_numberOfSamples = (Zend_Bit_Twiddling::getValue($tmp, 0, 3) << 32) | $this->_reader->readUInt32BE();
$this->_md5Signature = bin2hex($this->_reader->read(16));
}
/**
* Returns the minimum block size (in samples) used in the stream.
*
* @return integer
*/
public function getMinimumBlockSize()
{
return $this->_minimumBlockSize;
}
/**
* Returns the maximum block size (in samples) used in the stream. (Minimum blocksize == maximum blocksize) implies
* a fixed-blocksize stream.
*
* @return integer
*/
public function getMaximumBlockSize()
{
return $this->_maximumBlockSize;
}
/**
* Returns the minimum frame size (in bytes) used in the stream. May be 0 to imply the value is not known.
*
* @return integer
*/
public function getMinimumFrameSize()
{
return $this->_minimumFrameSize;
}
/**
* Returns the maximum frame size (in bytes) used in the stream. May be 0 to imply the value is not known.
*
* @return integer
*/
public function getMaximumFrameSize()
{
return $this->_maximumFrameSize;
}
/**
* Returns sample rate in Hz. The maximum sample rate is limited by the structure of frame headers to 655350Hz.
* Also, a value of 0 is invalid.
*
* @return integer
*/
public function getSampleRate()
{
return $this->_sampleRate;
}
/**
* Returns number of channels. FLAC supports from 1 to 8 channels.
*
* @return integer
*/
public function getNumberOfChannels()
{
return $this->_numberOfChannels;
}
/**
* Returns bits per sample. FLAC supports from 4 to 32 bits per sample. Currently the reference encoder and
* decoders only support up to 24 bits per sample.
*
* @return integer
*/
public function getBitsPerSample()
{
return $this->_bitsPerSample;
}
/**
* Returns total samples in stream. 'Samples' means inter-channel sample, i.e. one second of 44.1Khz audio will
* have 44100 samples regardless of the number of channels. A value of zero here means the number of total samples
* is unknown.
*
* @return integer
*/
public function getNumberOfSamples()
{
return $this->_numberOfSamples;
}
/**
* Returns MD5 signature of the unencoded audio data. This allows the decoder to determine if an error exists in
* the audio data even when the error does not result in an invalid bitstream.
*
* @return integer
*/
public function getMd5Signature()
{
return $this->_md5Signature;
}
}

View File

@@ -0,0 +1,155 @@
<?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 FLAC
* @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/Flac/MetadataBlock.php';
require_once 'Zend/Media/Vorbis/Header/Comment.php';
/**#@-*/
/**
* This class represents the vorbis comments metadata block. This block is for storing a list of human-readable
* name/value pairs. This is the only officially supported tagging mechanism in FLAC. There may be only one
* VORBIS_COMMENT block in a stream. In some external documentation, Vorbis comments are called FLAC tags to lessen
* confusion.
*
* This class parses the vorbis comments using the {@link Zend_Media_Vorbis_Header_Comment} class. Any of its method
* or fields can be used in the context of this class.
*
* @category Zend
* @package Zend_Media
* @subpackage FLAC
* @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_Flac_MetadataBlock_VorbisComment extends Zend_Media_Flac_MetadataBlock
{
/** @var Zend_Media_Vorbis_Header_Comment */
private $_impl;
/**
* Constructs the class with given parameters and parses object related data using the vorbis comment implementation
* class {@link Zend_Media_Vorbis_Header_Comment}.
*
* @param Zend_Io_Reader $reader The reader object.
*/
public function __construct($reader)
{
parent::__construct($reader);
$this->_impl = new Zend_Media_Vorbis_Header_Comment($this->_reader, array('vorbisContext' => false));
}
/**
* Forward all calls to the vorbis comment implementation class {@link Zend_Media_Vorbis_Header_Comment}.
*
* @param string $name The method name.
* @param Array $arguments The method arguments.
* @return mixed
*/
public function __call($name, $arguments)
{
if (method_exists($this, $name)) {
return $this->$name($arguments);
}
try {
return $this->_impl->$name($arguments);
} catch (Zend_Media_Vorbis_Exception $e) {
require_once 'Zend/Media/Flac/Exception.php';
throw new Zend_Media_Flac_Exception($e->getMessage());
}
}
/**
* Forward all calls to the vorbis comment implementation class {@link Zend_Media_Vorbis_Header_Comment}.
*
* @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)));
}
if (method_exists($this->_impl, 'get' . ucfirst($name))) {
return call_user_func(array($this->_impl, 'get' . ucfirst($name)));
}
try {
return $this->_impl->__get($name);
} catch (Zend_Media_Vorbis_Exception $e) {
require_once 'Zend/Media/Flac/Exception.php';
throw new Zend_Media_Flac_Exception($e->getMessage());
}
}
/**
* Forward all calls to the vorbis comment implementation class {@link Zend_Media_Vorbis_Header_Comment}.
*
* @param string $name The field name.
* @param string $name 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 {
try {
return $this->_impl->__set($name, $value);
} catch (Zend_Media_Vorbis_Exception $e) {
require_once 'Zend/Media/Flac/Exception.php';
throw new Zend_Media_Flac_Exception($e->getMessage());
}
}
}
/**
* Forward all calls to the vorbis comment implementation class {@link Zend_Media_Vorbis_Header_Comment}.
*
* @param string $name The field name.
* @return boolean
*/
public function __isset($name)
{
try {
return $this->_impl->__isset($name);
} catch (Zend_Media_Vorbis_Exception $e) {
require_once 'Zend/Media/Flac/Exception.php';
throw new Zend_Media_Flac_Exception($e->getMessage());
}
}
/**
* Forward all calls to the vorbis comment implementation class {@link Zend_Media_Vorbis_Header_Comment}.
*
* @param string $name The field name.
*/
public function __unset($name)
{
try {
$this->_impl->__unset($name);
} catch (Zend_Media_Vorbis_Exception $e) {
require_once 'Zend/Media/Flac/Exception.php';
throw new Zend_Media_Flac_Exception($e->getMessage());
}
}
}

View File

@@ -84,7 +84,7 @@ final class Zend_Media_Id3_Frame_Apic extends Zend_Media_Id3_Frame
*
* @todo There is the possibility to put only a link to the image file by
* using the MIME type '-->' and having a complete URL instead of picture
* data. Support for such needs design considerations.
* data. Support for such needs further design considerations.
* @param Zend_Io_Reader $reader The reader object.
* @param Array $options The options array.
*/

View File

@@ -62,17 +62,26 @@ final class Zend_Media_Vorbis_Header_Comment extends Zend_Media_Vorbis_Header
private $_comments;
/** @var integer */
private $_framingFlag;
private $_framingFlag = 1;
/**
* Constructs the class with given parameters.
* Constructs the class with given parameters and reads object related data from the bitstream.
*
* The following options are currently recognized:
* o vorbisContext -- Indicates whether to expect comments to be in the context of a vorbis bitstream or not. This
* option can be used to parse vorbis comments in another formats, eg FLAC, that do not use for example the
* framing flags. Defaults to true.
*
* @param Zend_Io_Reader $reader The reader object.
* @param Array $options Array of options.
*/
public function __construct($reader)
public function __construct($reader, $options = array())
{
parent::__construct($reader);
if (!isset($options['vorbisContext']) || $options['vorbisContext']) {
parent::__construct($reader);
} else {
$this->_reader = $reader;
}
$this->_vendor = $this->_reader->read($this->_reader->readUInt32LE());
$userCommentListLength = $this->_reader->readUInt32LE();
for ($i = 0; $i < $userCommentListLength; $i++) {
@@ -82,12 +91,24 @@ final class Zend_Media_Vorbis_Header_Comment extends Zend_Media_Vorbis_Header
}
$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');
if (!isset($options['vorbisContext']) || $options['vorbisContext']) {
$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');
}
$this->_reader->skip($this->_packetSize - $this->_reader->getOffset() + 30 /* header */);
}
$this->_reader->skip($this->_packetSize - $this->_reader->getOffset() + 30 /* header */);
}
/**
* Returns the vendor string.
*
* @return string
*/
public function getVendor()
{
return $this->_vendor;
}
/**
@@ -124,7 +145,7 @@ final class Zend_Media_Vorbis_Header_Comment extends Zend_Media_Vorbis_Header
*/
public function __isset($name)
{
return empty($this->_comments[strtoupper($name)]);
return count($this->_comments[strtoupper($name)]) > 0;
}
/**