Add support for reading Ogg format
git-svn-id: http://php-reader.googlecode.com/svn/trunk@231 51a70ab9-7547-0410-9469-37e369ee0574
This commit is contained in:
39
src/Zend/Media/Ogg/Exception.php
Normal file
39
src/Zend/Media/Ogg/Exception.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?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 Ogg
|
||||
* @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_Ogg_Exception is thrown whenever an error occurs within the Ogg family of classes.
|
||||
*
|
||||
* @category Zend
|
||||
* @package Zend_Media
|
||||
* @subpackage Ogg
|
||||
* @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_Ogg_Exception extends Zend_Media_Exception
|
||||
{}
|
||||
235
src/Zend/Media/Ogg/Page.php
Normal file
235
src/Zend/Media/Ogg/Page.php
Normal file
@@ -0,0 +1,235 @@
|
||||
<?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 Ogg
|
||||
* @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 an Ogg page. A physical bitstream consists of a sequence of Ogg pages containing data of one
|
||||
* logical bitstream only. It usually contains a group of contiguous segments of one packet only, but sometimes packets
|
||||
* are too large and need to be split over several pages.
|
||||
*
|
||||
* @category Zend
|
||||
* @package Zend_Media
|
||||
* @subpackage Ogg
|
||||
* @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_Ogg_Page
|
||||
{
|
||||
/**
|
||||
* The reader object.
|
||||
*
|
||||
* @var Zend_Io_Reader
|
||||
*/
|
||||
private $_reader;
|
||||
|
||||
/** @var string */
|
||||
private $_capturePattern;
|
||||
|
||||
/** @var integer */
|
||||
private $_streamStructureVersion;
|
||||
|
||||
/** @var integer */
|
||||
private $_headerTypeFlag;
|
||||
|
||||
/** @var integer */
|
||||
private $_granulePosition;
|
||||
|
||||
/** @var integer */
|
||||
private $_bitstreamSerialNumber;
|
||||
|
||||
/** @var integer */
|
||||
private $_pageSequenceNumber;
|
||||
|
||||
/** @var integer */
|
||||
private $_crcChecksum;
|
||||
|
||||
/** @var integer */
|
||||
private $_numberPageSegments;
|
||||
|
||||
/** @var Array */
|
||||
private $_segmentTable = array();
|
||||
|
||||
/** @var integer */
|
||||
private $_size;
|
||||
|
||||
/** @var integer */
|
||||
private $_headerSize;
|
||||
|
||||
/** @var integer */
|
||||
private $_pageSize;
|
||||
|
||||
/**
|
||||
* Constructs the class with given parameters and reads object related data
|
||||
* from the Ogg bitstream.
|
||||
*
|
||||
* @param Zend_Io_Reader $reader The reader object.
|
||||
*/
|
||||
public function __construct($reader)
|
||||
{
|
||||
$this->_reader = $reader;
|
||||
|
||||
$this->_capturePattern = $this->_reader->read(4);
|
||||
if ($this->_capturePattern != 'OggS') {
|
||||
require_once 'Zend/Media/Ogg/Exception.php';
|
||||
throw new Zend_Media_Ogg_Exception('Not a valid Ogg bitstream');
|
||||
}
|
||||
$this->_streamStructureVersion = $this->_reader->readUInt8();
|
||||
if ($this->_streamStructureVersion != 0) {
|
||||
require_once 'Zend/Media/Ogg/Exception.php';
|
||||
throw new Zend_Media_Ogg_Exception('Unsupported Ogg stream structure version');
|
||||
}
|
||||
$this->_headerTypeFlag = $this->_reader->readUInt8();
|
||||
$this->_granulePosition = $this->_reader->readInt64LE();
|
||||
$this->_bitstreamSerialNumber = $this->_reader->readUInt32LE();
|
||||
$this->_pageSequenceNumber = $this->_reader->readUInt32LE();
|
||||
$this->_crcChecksum = $this->_reader->readUInt32LE();
|
||||
$this->_numberPageSegments = $this->_reader->readUInt8();
|
||||
$this->_segmentTable = array();
|
||||
for ($i = 0; $i < $this->_numberPageSegments; $i++) {
|
||||
$this->_segmentTable[] = $this->_reader->readUInt8();
|
||||
}
|
||||
$this->_headerSize = $this->_numberPageSegments + 27;
|
||||
$this->_pageSize = array_sum($this->_segmentTable);
|
||||
$this->_size = $this->_headerSize + $this->_pageSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this page's context identifier in the bitstream.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public final function getHeaderTypeFlag()
|
||||
{
|
||||
return $this->_headerTypeFlag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns total samples encoded after including all packets finished on this page (packets begun on this page but
|
||||
* continuing on to the next page do not count).
|
||||
*
|
||||
* The rationale here is that the position specified in the frame header of the last page tells how long the data
|
||||
* coded by the bitstream is. A truncated stream will still return the proper number of samples that can be decoded
|
||||
* fully.
|
||||
*
|
||||
* A special value of '-1' (in two's complement) indicates that no packets finish on this page.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public final function getGranulePosition()
|
||||
{
|
||||
return $this->_granulePosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the logical bitstream serial number.
|
||||
*
|
||||
* Ogg allows for separate logical bitstreams to be mixed at page granularity in a physical bitstream. The most
|
||||
* common case would be sequential arrangement, but it is possible to interleave pages for two separate bitstreams
|
||||
* to be decoded concurrently. The serial number is the means by which pages physical pages are associated with a
|
||||
* particular logical stream. Each logical stream must have a unique serial number within a physical stream.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public final function getBitstreamSerialNumber()
|
||||
{
|
||||
return $this->_bitstreamSerialNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the page counter; lets us know if a page is lost (useful where packets span page boundaries).
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public final function getPageSequenceNumber()
|
||||
{
|
||||
return $this->_pageSequenceNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the 32 bit CRC value (direct algorithm, initial val and final XOR = 0, generator polynomial=0x04c11db7).
|
||||
* The value is computed over the entire header (with the CRC field in the header set to zero) and then continued
|
||||
* over the page. The CRC field is then filled with the computed value.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public final function getCrcChecksum()
|
||||
{
|
||||
return $this->_crcChecksum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of segment entries to appear in the segment table. The maximum number of 255 segments (255
|
||||
* bytes each) sets the maximum possible physical page size at 65307 bytes or just under 64kB (thus we know that a
|
||||
* header corrupted so as destroy sizing/alignment information will not cause a runaway bitstream. We'll read in the
|
||||
* page according to the corrupted size information that's guaranteed to be a reasonable size regardless, notice the
|
||||
* checksum mismatch, drop sync and then look for recapture).
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public final function getNumberPageSegments()
|
||||
{
|
||||
return $this->_numberPageSegments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the lacing values for each packet segment physically appearing in this page are listed in contiguous
|
||||
* order.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public final function getSegmentTable()
|
||||
{
|
||||
return $this->_segmentTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total page size with the header in bytes.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public final function getSize()
|
||||
{
|
||||
return $this->_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total header size in bytes.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public final function getHeaderSize()
|
||||
{
|
||||
return $this->_headerSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total page size without the header in bytes. The page size is calculated directly from the known
|
||||
* lacing values in the segment table.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public final function getPageSize()
|
||||
{
|
||||
return $this->_pageSize;
|
||||
}
|
||||
}
|
||||
169
src/Zend/Media/Ogg/Reader.php
Normal file
169
src/Zend/Media/Ogg/Reader.php
Normal file
@@ -0,0 +1,169 @@
|
||||
<?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 Ogg
|
||||
* @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/Io/FileReader.php';
|
||||
require_once 'Zend/Media/Ogg/Page.php';
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* This class is a Zend_Io_Reader specialization that can read a file containing the Ogg bitstream format version 0 as
|
||||
* described in {@link http://tools.ietf.org/html/rfc3533 RFC3533}. It is a general, freely-available encapsulation
|
||||
* format for media streams. It is able to encapsulate any kind and number of video and audio encoding formats as well
|
||||
* as other data streams in a single bitstream.
|
||||
*
|
||||
* @category Zend
|
||||
* @package Zend_Media
|
||||
* @subpackage Ogg
|
||||
* @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_Ogg_Reader extends Zend_Io_Reader
|
||||
{
|
||||
/** @var Array */
|
||||
private $_pages = array();
|
||||
|
||||
/** @var integer */
|
||||
private $_currentPage = 0;
|
||||
|
||||
/** @var integer */
|
||||
private $_currentPagePosition = 0;
|
||||
|
||||
/** @var integer */
|
||||
private $_streamSize = 0;
|
||||
|
||||
/**
|
||||
* Constructs the Ogg class with given file.
|
||||
*
|
||||
* @param string $filename The path to the file.
|
||||
* @throws Zend_Io_Exception if an error occur in stream handling.
|
||||
* @throws Zend_Media_Ogg_Exception if an error occurs in Ogg bitstream reading.
|
||||
*/
|
||||
public function __construct($filename)
|
||||
{
|
||||
$reader = new Zend_Io_FileReader($filename);
|
||||
$fileSize = $reader->getSize();
|
||||
while ($reader->getOffset() < $fileSize) {
|
||||
$this->_pages[] = array(
|
||||
'page' => $page = new Zend_Media_Ogg_Page($reader),
|
||||
'offset' => $reader->getOffset()
|
||||
);
|
||||
$this->_streamSize += $page->getPageSize();
|
||||
$reader->skip($page->getPageSize());
|
||||
}
|
||||
$reader->setOffset($this->_pages[$this->_currentPage]['offset']);
|
||||
$this->_fd = $reader->getFileDescriptor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrite the method to return the current point of operation within the Ogg bitstream.
|
||||
*
|
||||
* @return integer
|
||||
* @throws Zend_Io_Exception if an I/O error occurs
|
||||
*/
|
||||
public function getOffset()
|
||||
{
|
||||
$offset = 0;
|
||||
for ($i = 0; $i < $this->_currentPage; $i++) {
|
||||
$offset += $this->_pages[$i]['page']->getPageSize();
|
||||
}
|
||||
return $offset += $this->_currentPagePosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrite the method to set the point of operation within the Ogg bitstream.
|
||||
*
|
||||
* @param integer $offset The new point of operation.
|
||||
* @return void
|
||||
* @throws Zend_Io_Exception if an I/O error occurs
|
||||
*/
|
||||
public function setOffset($offset)
|
||||
{
|
||||
$streamSize = 0;
|
||||
for ($i = 0, $pageCount = count($this->_pages); $i < $pageCount; $i++) {
|
||||
if (($streamSize + $this->_pages[$i]['page']->getPageSize()) >= $offset) {
|
||||
$this->_currentPage = $i;
|
||||
$this->_currentPagePosition = $offset - $streamSize;
|
||||
parent::setOffset($this->_pages[$i]['offset'] + $this->_currentPagePosition);
|
||||
break;
|
||||
}
|
||||
$streamSize += $this->_pages[$i]['page']->getPageSize();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param integer $size The amount of bytes to jump within the Ogg bitstream.
|
||||
* @return void
|
||||
* @throws Zend_Io_Exception if an I/O error occurs
|
||||
*/
|
||||
public function skip($size)
|
||||
{
|
||||
$currentPageSize = $this->_pages[$this->_currentPage]['page']->getPageSize();
|
||||
if (($this->_currentPagePosition + $size) >= $currentPageSize) {
|
||||
parent::skip
|
||||
(($currentPageSize - $this->_currentPagePosition) +
|
||||
$this->_pages[++$this->_currentPage]['page']->getHeaderSize() +
|
||||
($this->_currentPagePosition = ($size - $currentPageSize - $this->_currentPagePosition)));
|
||||
} else {
|
||||
$this->_currentPagePosition += $size;
|
||||
parent::skip($size);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrite the method to read bytes within the Ogg bitstream.
|
||||
*
|
||||
* @param integer $length The amount of bytes to read within the Ogg bitstream.
|
||||
* @return string
|
||||
* @throws Zend_Io_Exception if an I/O error occurs
|
||||
*/
|
||||
public function read($length)
|
||||
{
|
||||
$currentPageSize = $this->_pages[$this->_currentPage]['page']->getPageSize();
|
||||
if (($this->_currentPagePosition + $length) >= $currentPageSize) {
|
||||
$buffer = parent::read($currentPageSize - $this->_currentPagePosition);
|
||||
parent::skip($this->_pages[++$this->_currentPage]['page']->getHeaderSize());
|
||||
return $buffer . parent::read
|
||||
($this->_currentPagePosition = ($length - ($currentPageSize - $this->_currentPagePosition)));
|
||||
} else {
|
||||
$buffer = parent::read($length);
|
||||
$this->_currentPagePosition += $length;
|
||||
return $buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user