From 9e17c9931838f49bb7c7c80035152d602b7f9d00 Mon Sep 17 00:00:00 2001 From: svollbehr Date: Sat, 4 Jun 2011 09:35:48 +0000 Subject: [PATCH] Add support for Vorbis setup header git-svn-id: http://php-reader.googlecode.com/svn/trunk@239 51a70ab9-7547-0410-9469-37e369ee0574 --- src/Zend/Media/Ogg/Reader.php | 59 +++++++++++++++++++----- src/Zend/Media/Vorbis.php | 12 ++--- src/Zend/Media/Vorbis/Header.php | 26 ++++++++++- src/Zend/Media/Vorbis/Header/Comment.php | 1 + src/Zend/Media/Vorbis/Header/Setup.php | 55 ++++++++++++++++++++++ 5 files changed, 133 insertions(+), 20 deletions(-) create mode 100644 src/Zend/Media/Vorbis/Header/Setup.php diff --git a/src/Zend/Media/Ogg/Reader.php b/src/Zend/Media/Ogg/Reader.php index 2d050fc..1c791a1 100644 --- a/src/Zend/Media/Ogg/Reader.php +++ b/src/Zend/Media/Ogg/Reader.php @@ -47,7 +47,7 @@ final class Zend_Media_Ogg_Reader extends Zend_Io_Reader private $_pages = array(); /** @var integer */ - private $_currentPage = 0; + private $_currentPageNumber = 0; /** @var integer */ private $_currentPagePosition = 0; @@ -65,13 +65,15 @@ final class Zend_Media_Ogg_Reader extends Zend_Io_Reader $fileSize = $reader->getSize(); while ($reader->getOffset() < $fileSize) { $this->_pages[] = array( - 'page' => $page = new Zend_Media_Ogg_Page($reader), - 'offset' => $reader->getOffset() + 'offset' => $reader->getOffset(), + 'page' => $page = new Zend_Media_Ogg_Page($reader) ); $this->_size += $page->getPageSize(); $reader->skip($page->getPageSize()); } - $reader->setOffset($this->_pages[$this->_currentPage]['offset']); + $reader->setOffset + ($this->_pages[$this->_currentPageNumber]['offset'] + + $this->_pages[$this->_currentPageNumber]['page']->getHeaderSize()); $this->_fd = $reader->getFileDescriptor(); } @@ -84,7 +86,7 @@ final class Zend_Media_Ogg_Reader extends Zend_Io_Reader public function getOffset() { $offset = 0; - for ($i = 0; $i < $this->_currentPage; $i++) { + for ($i = 0; $i < $this->_currentPageNumber; $i++) { $offset += $this->_pages[$i]['page']->getPageSize(); } return $offset += $this->_currentPagePosition; @@ -102,9 +104,11 @@ final class Zend_Media_Ogg_Reader extends Zend_Io_Reader $streamSize = 0; for ($i = 0, $pageCount = count($this->_pages); $i < $pageCount; $i++) { if (($streamSize + $this->_pages[$i]['page']->getPageSize()) >= $offset) { - $this->_currentPage = $i; + $this->_currentPageNumber = $i; $this->_currentPagePosition = $offset - $streamSize; - parent::setOffset($this->_pages[$i]['offset'] + $this->_currentPagePosition); + parent::setOffset + ($this->_pages[$i]['offset'] + $this->_pages[$i]['page']->getHeaderSize() + + $this->_currentPagePosition); break; } $streamSize += $this->_pages[$i]['page']->getPageSize(); @@ -120,12 +124,12 @@ final class Zend_Media_Ogg_Reader extends Zend_Io_Reader */ public function skip($size) { - $currentPageSize = $this->_pages[$this->_currentPage]['page']->getPageSize(); + $currentPageSize = $this->_pages[$this->_currentPageNumber]['page']->getPageSize(); if (($this->_currentPagePosition + $size) >= $currentPageSize) { parent::skip (($currentPageSize - $this->_currentPagePosition) + - $this->_pages[++$this->_currentPage]['page']->getHeaderSize() + - ($this->_currentPagePosition = ($size - $currentPageSize - $this->_currentPagePosition))); + $this->_pages[++$this->_currentPageNumber]['page']->getHeaderSize() + + ($this->_currentPagePosition = ($size - ($currentPageSize - $this->_currentPagePosition)))); } else { $this->_currentPagePosition += $size; parent::skip($size); @@ -141,10 +145,10 @@ final class Zend_Media_Ogg_Reader extends Zend_Io_Reader */ public function read($length) { - $currentPageSize = $this->_pages[$this->_currentPage]['page']->getPageSize(); + $currentPageSize = $this->_pages[$this->_currentPageNumber]['page']->getPageSize(); if (($this->_currentPagePosition + $length) >= $currentPageSize) { $buffer = parent::read($currentPageSize - $this->_currentPagePosition); - parent::skip($this->_pages[++$this->_currentPage]['page']->getHeaderSize()); + parent::skip($this->_pages[++$this->_currentPageNumber]['page']->getHeaderSize()); return $buffer . parent::read ($this->_currentPagePosition = ($length - ($currentPageSize - $this->_currentPagePosition))); } else { @@ -153,4 +157,35 @@ final class Zend_Media_Ogg_Reader extends Zend_Io_Reader return $buffer; } } + + /** + * Returns the underlying Ogg page at given number. + * + * @param integer $pageNumber The number of the page to return. + * @return Zend_Media_Ogg_Page + */ + public function getPage($pageNumber) + { + return $this->_pages[$pageNumber]['page']; + } + + /** + * Returns the underlying Ogg page number. + * + * @return integer + */ + public function getCurrentPageNumber() + { + return $this->_currentPageNumber; + } + + /** + * Returns the underlying Ogg page position, in bytes. + * + * @return integer + */ + public function getCurrentPagePosition() + { + return $this->_currentPagePosition; + } } diff --git a/src/Zend/Media/Vorbis.php b/src/Zend/Media/Vorbis.php index 28aa779..3adb171 100644 --- a/src/Zend/Media/Vorbis.php +++ b/src/Zend/Media/Vorbis.php @@ -61,11 +61,11 @@ final class Zend_Media_Vorbis /** @var Zend_Media_Vorbis_Header_Comment */ private $_commentHeader; -// /** @var Zend_Media_Vorbis_Header_Setup */ -// private $_setupHeader; + /** @var Zend_Media_Vorbis_Header_Setup */ + private $_setupHeader; /** - * Constructs the . + * Constructs the Zend_Media_Vorbis class with given file. * * @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. @@ -90,7 +90,7 @@ final class Zend_Media_Vorbis $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); + $this->_setupHeader = new Zend_Media_Vorbis_Header_Setup($this->_reader); } /** @@ -120,9 +120,7 @@ final class Zend_Media_Vorbis */ public function getSetupHeader() { - require_once 'Zend/Media/Vorbis/Exception.php'; - throw new Zend_Media_Vorbis_Exception('Not yet supported'); -// return $this->_setupHeader; + return $this->_setupHeader; } /** diff --git a/src/Zend/Media/Vorbis/Header.php b/src/Zend/Media/Vorbis/Header.php index b07c9bf..e56a9f5 100644 --- a/src/Zend/Media/Vorbis/Header.php +++ b/src/Zend/Media/Vorbis/Header.php @@ -53,6 +53,9 @@ abstract class Zend_Media_Vorbis_Header */ protected $_packetType; + /** $var integer */ + protected $_packetSize = 0; + /** * Constructs the class with given parameters. * @@ -62,7 +65,6 @@ abstract class Zend_Media_Vorbis_Header public function __construct($reader) { $this->_reader = $reader; - if (!in_array($this->_packetType = $this->_reader->readUInt8(), array(1, 3, 5))) { require_once 'Zend/Media/Vorbis/Exception.php'; throw new Zend_Media_Vorbis_Exception('Unknown header packet type: ' . $this->_packetType); @@ -71,6 +73,28 @@ abstract class Zend_Media_Vorbis_Header require_once 'Zend/Media/Vorbis/Exception.php'; throw new Zend_Media_Vorbis_Exception('Unknown header packet: ' . $vorbis); } + + $skipBytes = $this->_reader->getCurrentPagePosition(); + for ($page = $this->_reader->getCurrentPageNumber(); /* goes on until we find packet end */; $page++) { + $segments = $this->_reader->getPage($page)->getSegmentTable(); + for ($i = 0, $skippedSegments = 0; $i < count($segments); $i++) { + // Skip page segments that are already read in + if ($skipBytes > $segments[$i]) { + $skipBytes -= $segments[$i]; + continue; + } + + // Skip segments that are full + if ($segments[$i] == 255 && ++$skippedSegments) { + continue; + } + + // Record packet size from the first non-255 segment + $this->_packetSize += $i * 255 + $segments[$i]; + break 2; + } + $this->_packetSize += $skippedSegments * 255; + } } /** diff --git a/src/Zend/Media/Vorbis/Header/Comment.php b/src/Zend/Media/Vorbis/Header/Comment.php index 75aa16a..ca153a0 100644 --- a/src/Zend/Media/Vorbis/Header/Comment.php +++ b/src/Zend/Media/Vorbis/Header/Comment.php @@ -87,6 +87,7 @@ final class Zend_Media_Vorbis_Header_Comment extends Zend_Media_Vorbis_Header 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 */); } /** diff --git a/src/Zend/Media/Vorbis/Header/Setup.php b/src/Zend/Media/Vorbis/Header/Setup.php new file mode 100644 index 0000000..56a850b --- /dev/null +++ b/src/Zend/Media/Vorbis/Header/Setup.php @@ -0,0 +1,55 @@ + + * @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 Implementation + */ +final class Zend_Media_Vorbis_Header_Setup extends Zend_Media_Vorbis_Header +{ + /** + * Constructs the class with given parameters. + * + * @param Zend_Io_Reader $reader The reader object. + */ + public function __construct($reader) + { + parent::__construct($reader); + + $this->_reader->skip($this->_packetSize - 7 /* header */); + } +}