Add support for resynchronization on stream error

git-svn-id: http://php-reader.googlecode.com/svn/trunk@261 51a70ab9-7547-0410-9469-37e369ee0574
This commit is contained in:
svollbehr
2012-03-05 20:43:15 +00:00
parent e0049fc338
commit 6995f912f3
2 changed files with 69 additions and 52 deletions

View File

@@ -42,7 +42,7 @@ require_once 'Zend/Media/Mpeg/Abs/Frame.php';
* @subpackage MPEG * @subpackage MPEG
* @author Ryan Butterfield <buttza@gmail.com> * @author Ryan Butterfield <buttza@gmail.com>
* @author Sven Vollbehr <sven@vollbehr.eu> * @author Sven Vollbehr <sven@vollbehr.eu>
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @copyright Copyright (c) 2005-2012 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 Implement validation routines * @todo Implement validation routines
@@ -181,15 +181,13 @@ final class Zend_Media_Mpeg_Abs extends Zend_Media_Mpeg_Abs_Object
} }
/* Check for VBR headers */ /* Check for VBR headers */
$offset = $this->_reader->getOffset();
$this->_frames[] = $firstFrame = $this->_frames[] = $firstFrame =
new Zend_Media_Mpeg_Abs_Frame($this->_reader, $options); new Zend_Media_Mpeg_Abs_Frame($this->_reader, $options);
$postoffset = $this->_reader->getOffset(); $offset = $this->_reader->getOffset();
$this->_reader->setOffset $this->_reader->setOffset
($offset + 4 + self::$sidesizes ($firstFrame->getOffset() + 4 + self::$sidesizes
[$firstFrame->getFrequencyType()][$firstFrame->getMode()]); [$firstFrame->getFrequencyType()][$firstFrame->getMode()]);
if (($xing = $this->_reader->readString8(4)) == 'Xing' || if (($xing = $this->_reader->readString8(4)) == 'Xing' ||
$xing == 'Info') { $xing == 'Info') {
@@ -207,7 +205,7 @@ final class Zend_Media_Mpeg_Abs extends Zend_Media_Mpeg_Abs_Object
array_pop($this->_frames); array_pop($this->_frames);
} }
$this->_reader->setOffset($offset + 4 + 32); $this->_reader->setOffset($firstFrame->getOffset() + 4 + 32);
if ($this->_reader->readString8(4) == 'VBRI') { if ($this->_reader->readString8(4) == 'VBRI') {
require_once 'Zend/Media/Mpeg/Abs/VbriHeader.php'; require_once 'Zend/Media/Mpeg/Abs/VbriHeader.php';
$this->_vbriHeader = $this->_vbriHeader =
@@ -217,7 +215,7 @@ final class Zend_Media_Mpeg_Abs extends Zend_Media_Mpeg_Abs_Object
array_pop($this->_frames); array_pop($this->_frames);
} }
$this->_reader->setOffset($postoffset); $this->_reader->setOffset($offset);
// Ensure we always have read at least one frame // Ensure we always have read at least one frame
if (empty($this->_frames)) { if (empty($this->_frames)) {
@@ -242,7 +240,7 @@ final class Zend_Media_Mpeg_Abs extends Zend_Media_Mpeg_Abs_Object
$firstFrame->getSamplingFrequency()) / 1000 * 8); $firstFrame->getSamplingFrequency()) / 1000 * 8);
} }
} else { } else {
$this->_estimatedBitrate = ($this->_bytes - $offset) / $this->_estimatedBitrate = ($this->_bytes - $firstFrame->getOffset()) /
$this->_estimatedPlayDuration / 1000 * 8; $this->_estimatedPlayDuration / 1000 * 8;
} }
} else { } else {
@@ -251,7 +249,7 @@ final class Zend_Media_Mpeg_Abs extends Zend_Media_Mpeg_Abs_Object
$this->_estimatedBitrate = $this->_estimatedBitrate =
$this->_cumulativeBitrate / count($this->_frames); $this->_cumulativeBitrate / count($this->_frames);
$this->_estimatedPlayDuration = $this->_estimatedPlayDuration =
($this->_bytes - $offset) / ($this->_bytes - $firstFrame->getOffset()) /
($this->_estimatedBitrate * 1000 / 8); ($this->_estimatedBitrate * 1000 / 8);
} }
} else { } else {

View File

@@ -38,7 +38,7 @@ require_once 'Zend/Media/Mpeg/Abs/Object.php';
* @subpackage MPEG * @subpackage MPEG
* @author Ryan Butterfield <buttza@gmail.com> * @author Ryan Butterfield <buttza@gmail.com>
* @author Sven Vollbehr <sven@vollbehr.eu> * @author Sven Vollbehr <sven@vollbehr.eu>
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @copyright Copyright (c) 2005-2012 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$
*/ */
@@ -229,12 +229,20 @@ final class Zend_Media_Mpeg_Abs_Frame extends Zend_Media_Mpeg_Abs_Object
$this->_offset = $this->_reader->getOffset(); $this->_offset = $this->_reader->getOffset();
$header = $this->_reader->readUInt32BE(); $header = null;
if (!Zend_Bit_Twiddling::testAllBits(Zend_Bit_Twiddling::getValue($header, 21, 32), 0xffe)) { for ($i = 0; $i < 5775 /* max attempts: max frame size x2 */; $i++) {
require_once 'Zend/Media/Mpeg/Exception.php'; $header = $this->_reader->readUInt32BE();
throw new Zend_Media_Mpeg_Exception if (Zend_Bit_Twiddling::testAllBits(Zend_Bit_Twiddling::getValue($header, 21, 32), 0xffe)) {
('File does not contain a valid MPEG Audio Bit Stream (Invalid frame sync)'); break;
}
$this->_reader->setOffset(++$this->_offset + 1);
if ($this->_offset == $this->_reader->getSize() || $i == (5775 - 1)) {
require_once 'Zend/Media/Mpeg/Exception.php';
throw new Zend_Media_Mpeg_Exception
('File does not contain a valid MPEG Audio Bit Stream (Invalid frame sync and resynchronization failed)');
}
} }
$this->_version = Zend_Bit_Twiddling::getValue($header, 19, 20); $this->_version = Zend_Bit_Twiddling::getValue($header, 19, 20);
$this->_frequencyType = Zend_Bit_Twiddling::testBit($header, 19); $this->_frequencyType = Zend_Bit_Twiddling::testBit($header, 19);
$this->_layer = Zend_Bit_Twiddling::getValue($header, 17, 18); $this->_layer = Zend_Bit_Twiddling::getValue($header, 17, 18);
@@ -268,6 +276,17 @@ final class Zend_Media_Mpeg_Abs_Frame extends Zend_Media_Mpeg_Abs_Object
$this->_reader->skip($this->_length - 4); $this->_reader->skip($this->_length - 4);
} }
/**
* Returns the offset where the frame actually begins (stream error may
* cause resynchronization).
*
* @return integer
*/
public function getOffset()
{
return $this->_offset;
}
/** /**
* Returns the version identifier of the algorithm. * Returns the version identifier of the algorithm.
* *