diff --git a/src/MPEG/ABS.php b/src/MPEG/ABS.php deleted file mode 100644 index 6061a18..0000000 --- a/src/MPEG/ABS.php +++ /dev/null @@ -1,395 +0,0 @@ - - * @author Sven Vollbehr - * @copyright Copyright (c) 2008 The PHP Reader Project Workgroup - * @license http://code.google.com/p/php-reader/wiki/License New BSD License - * @version $Rev$ - * @todo Implement validation routines - */ -final class MPEG_ABS extends MPEG_ABS_Object -{ - /** @var integer */ - private $_bytes; - - /** @var Array */ - private $_frames = array(); - - /** @var MPEG_ABS_XINGHeader */ - private $_xingHeader = null; - - /** @var MPEG_ABS_LAMEHeader */ - private $_lameHeader = null; - - /** @var MPEG_ABS_VBRIHeader */ - private $_vbriHeader = null; - - /** @var integer */ - private $_cumulativeBitrate = 0; - - /** @var integer */ - private $_cumulativePlayDuration = 0; - - /** @var integer */ - private $_estimatedBitrate = 0; - - /** @var integer */ - private $_estimatedPlayDuration = 0; - - /** @var integer */ - private $_lastFrameOffset = false; - - - /** - * Constructs the MPEG_ABS class with given file and options. - * - * The following options are currently recognized: - * o readmode -- Can be one of full or lazy and determines when the read of - * frames and their data happens. When in full mode the data is read - * automatically during the instantiation of the frame and all the frames - * are read during the instantiation of this class. While this allows - * faster validation and data fetching, it is unnecessary in terms of - * determining just the play duration of the file. Defaults to lazy. - * - * o estimatePrecision -- Only applicaple with lazy read mode to determine - * the precision of play duration estimate. This precision is equal to how - * many frames are read before fixing the average bitrate that is used to - * calculate the play duration estimate of the whole file. Each frame adds - * about 0.1-0.2ms to the processing of the file. Defaults to 1000. - * - * When in lazy data reading mode it is first checked whether a VBR header is - * found in a file. If so, the play duration is calculated based no its data - * and no further frames are read from the file. If no VBR header is found, - * frames up to estimatePrecision are read to calculate an average bitrate. - * - * Hence, only zero or estimatePrecision number of frames are read - * in lazy data reading mode. The rest of the frames are read automatically - * when directly referenced, ie the data is read when it is needed. - * - * @param string|Reader $filename The path to the file, file descriptor of an - * opened file, or {@link Reader} instance. - * @param Array $options The options array. - */ - public function __construct($filename, $options = array()) - { - if ($filename instanceof Reader) - $reader = &$filename; - else - $reader = new Reader($filename); - - parent::__construct($reader, $options); - - $offset = $this->_reader->getOffset(); - $this->_bytes = $this->_reader->getSize(); - - /* Skip ID3v1 tag */ - $this->_reader->setOffset(-128); - if ($this->_reader->read(3) == "TAG") - $this->_bytes -= 128; - $this->_reader->setOffset($offset); - - /* Skip ID3v2 tag */ - if ($this->_reader->readString8(3) == "ID3") { - require_once("ID3/Header.php"); - $header = new ID3_Header($this->_reader); - $this->_reader->skip - ($header->getSize() + ($header->hasFlag(ID3_Header::FOOTER) ? 10 : 0)); - } - else - $this->_reader->setOffset($offset); - - /* Check for VBR headers */ - $offset = $this->_reader->getOffset(); - - $this->_frames[] = - $firstFrame = new MPEG_ABS_Frame($this->_reader, $options); - - $postoffset = $this->_reader->getOffset(); - - $this->_reader->setOffset - ($offset + 4 + self::$sidesizes - [$firstFrame->getFrequencyType()][$firstFrame->getMode()]); - if (($xing = $this->_reader->readString8(4)) == "Xing" || $xing == "Info") { - require_once("MPEG/ABS/XINGHeader.php"); - $this->_xingHeader = new MPEG_ABS_XINGHeader($this->_reader, $options); - if ($this->_reader->readString8(4) == "LAME") { - require_once("MPEG/ABS/LAMEHeader.php"); - $this->_lameHeader = - new MPEG_ABS_LAMEHeader($this->_reader, $options); - } - - // A header frame is not counted as an audio frame - array_pop($this->_frames); - } - - $this->_reader->setOffset($offset + 4 + 32); - if ($this->_reader->readString8(4) == "VBRI") { - require_once("MPEG/ABS/VBRIHeader.php"); - $this->_vbriHeader = new MPEG_ABS_VBRIHeader($this->_reader, $options); - - // A header frame is not counted as an audio frame - array_pop($this->_frames); - } - - $this->_reader->setOffset($postoffset); - - // Ensure we always have read at least one frame - if (empty($this->_frames)) - $this->_readFrames(1); - - /* Read necessary frames */ - if ($this->getOption("readmode", "lazy") == "lazy") { - if (($header = $this->_xingHeader) !== null || - ($header = $this->_vbriHeader) !== null) { - $this->_estimatedPlayDuration = $header->getFrames() * - $firstFrame->getSamples() / $firstFrame->getSamplingFrequency(); - if ($this->_lameHeader !== null) { - $this->_estimatedBitrate = $this->_lameHeader->getBitrate(); - if ($this->_estimatedBitrate == 255) - $this->_estimatedBitrate = round - (($this->_lameHeader->getMusicLength()) / - (($header->getFrames() * $firstFrame->getSamples()) / - $firstFrame->getSamplingFrequency()) / 1000 * 8); - } - else - $this->_estimatedBitrate = ($this->_bytes - $offset) / - $this->_estimatedPlayDuration / 1000 * 8; - } - else { - $this->_readFrames($this->getOption("estimatePrecision", 1000)); - - $this->_estimatedBitrate = - $this->_cumulativeBitrate / count($this->_frames); - $this->_estimatedPlayDuration = - ($this->_bytes - $offset) / ($this->_estimatedBitrate * 1000 / 8); - } - } - else { - $this->_readFrames(); - - $this->_estimatedBitrate = - $this->_cumulativeBitrate / count($this->_frames); - $this->_estimatedPlayDuration = $this->_cumulativePlayDuration; - } - } - - /** - * Returns true if the audio bitstream contains the Xing VBR - * header, or false otherwise. - * - * @return boolean - */ - public function hasXingHeader() { return $this->_xingHeader === null; } - - /** - * Returns the Xing VBR header, or null if not found in the audio - * bitstream. - * - * @return MPEG_ABS_XINGHeader - */ - public function getXingHeader() { return $this->_xingHeader; } - - /** - * Returns true if the audio bitstream contains the LAME VBR - * header, or false otherwise. - * - * @return boolean - */ - public function hasLameHeader() { return $this->_lameHeader === null; } - - /** - * Returns the LAME VBR header, or null if not found in the audio - * bitstream. - * - * @return MPEG_ABS_LAMEHeader - */ - public function getLameHeader() { return $this->_lameHeader; } - - /** - * Returns true if the audio bitstream contains the Fraunhofer IIS - * VBR header, or false otherwise. - * - * @return boolean - */ - public function hasVbriHeader() { return $this->_vbriHeader === null; } - - /** - * Returns the Fraunhofer IIS VBR header, or null if not found in - * the audio bitstream. - * - * @return MPEG_ABS_VBRIHeader - */ - public function getVbriHeader() { return $this->_vbriHeader; } - - /** - * Returns the bitrate estimate. This value is either fetched from one of the - * headers or calculated based on the read frames. - * - * @return integer - */ - public function getBitrateEstimate() - { - return $this->_estimatedBitrate; - } - - /** - * For variable bitrate files this method returns the exact average bitrate of - * the whole file. - * - * @return integer - */ - public function getBitrate() - { - if ($this->getOption("readmode", "lazy") == "lazy") - $this->_readFrames(); - return $this->_cumulativeBitrate / count($this->_frames); - } - - /** - * Returns the playtime estimate, in seconds. - * - * @return integer - */ - public function getLengthEstimate() - { - return $this->_estimatedPlayDuration; - } - - /** - * Returns the exact playtime in seconds. In lazy reading mode the frames are - * read from the file the first time you call this method to get the exact - * playtime of the file. - * - * @return integer - */ - public function getLength() - { - if ($this->getOption("readmode", "lazy") == "lazy") - $this->_readFrames(); - return $this->_cumulativePlayDuration; - } - - /** - * Returns the playtime estimate as a string in the form of - * [hours:]minutes:seconds.milliseconds. - * - * @param integer $seconds The playtime in seconds. - * @return string - */ - public function getFormattedLengthEstimate() - { - return $this->formatTime($this->getLengthEstimate()); - } - - /** - * Returns the exact playtime given in seconds as a string in the form of - * [hours:]minutes:seconds.milliseconds. In lazy reading mode the frames are - * read from the file the first time you call this method to get the exact - * playtime of the file. - * - * @param integer $seconds The playtime in seconds. - * @return string - */ - public function getFormattedLength() - { - return $this->formatTime($this->getLength()); - } - - /** - * Returns all the frames of the audio bitstream as an array. In lazy reading - * mode the frames are read from the file the first time you call this method. - * - * @return Array - */ - public function getFrames() - { - if ($this->getOption("readmode", "lazy") == "lazy") { - $this->_readFrames(); - } - return $this->_frames; - } - - /** - * Reads frames up to given limit. If called subsequently the method continues - * after the last frame read in the last call, again to read up to the limit - * or just the rest of the frames. - * - * @param integer $limit The maximum number of frames read from the bitstream - */ - private function _readFrames($limit = false) - { - if ($this->_lastFrameOffset !== false) - $this->_reader->setOffset($this->_lastFrameOffset); - - for ($i = 0; $this->_reader->getOffset() < $this->_bytes; $i++) { - $options = $this->getOptions(); - $frame = new MPEG_ABS_Frame($this->_reader, $options); - - $this->_cumulativePlayDuration += - (double)($frame->getLength() / ($frame->getBitrate() * 1000 / 8)); - $this->_cumulativeBitrate += $frame->getBitrate(); - $this->_frames[] = $frame; - - if ($limit === false) - $this->_lastFrameOffset = $this->_reader->getOffset(); - if ($limit !== false && ($i + 1) == $limit) { - $this->_lastFrameOffset = $this->_reader->getOffset(); - break; - } - } - } -} diff --git a/src/MPEG/ABS/Frame.php b/src/MPEG/ABS/Frame.php deleted file mode 100644 index 55ce81e..0000000 --- a/src/MPEG/ABS/Frame.php +++ /dev/null @@ -1,507 +0,0 @@ - - * @author Sven Vollbehr - * @copyright Copyright (c) 2008-2009 The PHP Reader Project Workgroup - * @license http://code.google.com/p/php-reader/wiki/License New BSD License - * @version $Rev$ - */ -final class MPEG_ABS_Frame extends MPEG_ABS_Object -{ - /** - * The bitrate lookup table. The table has the following format. - * - * - * array ( - * SAMPLING_FREQUENCY_HIGH | SAMPLING_FREQUENCY_LOW => array ( - * LAYER_ONE | LAYER_TWO | LAYER_TREE => array ( ) - * ) - * ) - * - * - * @var Array - */ - private static $bitrates = array ( - self::SAMPLING_FREQUENCY_HIGH => array ( - self::LAYER_ONE => array ( - 1 => 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448 - ), - self::LAYER_TWO => array ( - 1 => 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384 - ), - self::LAYER_THREE => array ( - 1 => 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 - ) - ), - self::SAMPLING_FREQUENCY_LOW => array ( - self::LAYER_ONE => array ( - 1 => 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256 - ), - self::LAYER_TWO => array ( - 1 => 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 - ), - self::LAYER_THREE => array ( - 1 => 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 - ) - ) - ); - - /** - * Sample rate lookup table. The table has the following format. - * - * - * array ( - * LAYER_ONE | LAYER_TWO | LAYER_TREE => array ( ) - * ) - * - * - * @var Array - */ - private static $samplingFrequencies = array ( - self::VERSION_ONE => array (44100, 48000, 32000), - self::VERSION_TWO => array (22050, 24000, 16000), - self::VERSION_TWO_FIVE => array (11025, 12000, 8000) - ); - - /** - * Samples per frame lookup table. The table has the following format. - * - * - * array ( - * SAMPLING_FREQUENCY_HIGH | SAMPLING_FREQUENCY_LOW => array ( - * LAYER_ONE | LAYER_TWO | LAYER_TREE => - * ) - * ) - * - * - * @var Array - */ - private static $samples = array ( - self::SAMPLING_FREQUENCY_HIGH => array ( - self::LAYER_ONE => 384, - self::LAYER_TWO => 1152, - self::LAYER_THREE => 1152), - self::SAMPLING_FREQUENCY_LOW => array ( - self::LAYER_ONE => 384, - self::LAYER_TWO => 1152, - self::LAYER_THREE => 576)); - - /** - * Coefficient lookup table. The table has the following format. - * - * - * array ( - * SAMPLING_FREQUENCY_HIGH | SAMPLING_FREQUENCY_LOW => array ( - * LAYER_ONE | LAYER_TWO | LAYER_TREE => array ( ) - * ) - * ) - * - * - * @var Array - */ - private static $coefficients = array ( - self::SAMPLING_FREQUENCY_HIGH => array ( - self::LAYER_ONE => 12, self::LAYER_TWO => 144, self::LAYER_THREE => 144 - ), - self::SAMPLING_FREQUENCY_LOW => array ( - self::LAYER_ONE => 12, self::LAYER_TWO => 144, self::LAYER_THREE => 72 - ) - ); - - /** - * Slot size per layer lookup table. The table has the following format. - * - * - * array ( - * LAYER_ONE | LAYER_TWO | LAYER_TREE => - * ) - * - * - * - * @var Array - */ - private static $slotsizes = array ( - self::LAYER_ONE => 4, self::LAYER_TWO => 1, self::LAYER_THREE => 1 - ); - - - /** @var integer */ - private $_offset; - - /** @var integer */ - private $_version; - - /** @var integer */ - private $_frequencyType; - - /** @var integer */ - private $_layer; - - /** @var integer */ - private $_redundancy; - - /** @var integer */ - private $_bitrate; - - /** @var integer */ - private $_samplingFrequency; - - /** @var integer */ - private $_padding; - - /** @var integer */ - private $_mode; - - /** @var integer */ - private $_modeExtension; - - /** @var integer */ - private $_copyright; - - /** @var integer */ - private $_original; - - /** @var integer */ - private $_emphasis; - - /** @var integer */ - private $_length; - - /** @var integer */ - private $_samples; - - /** @var integer */ - private $_crc = false; - - /** @var string */ - private $_data = false; - - /** - * Constructs the class with given parameters and reads object related data - * from the frame. - * - * @param Reader $reader The reader object. - * @param Array $options Array of options. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_offset = $this->_reader->getOffset(); - - $header = Transform::fromUInt32BE($this->_reader->read(4)); - $this->_version = Twiddling::getValue($header, 19, 20); - $this->_frequencyType = Twiddling::testBit($header, 19); - $this->_layer = Twiddling::getValue($header, 17, 18); - $this->_redundancy = !Twiddling::testBit($header, 16); - $this->_bitrate = isset - (self::$bitrates[$this->_frequencyType][$this->_layer] - [$index = Twiddling::getValue($header, 12, 15)]) ? - self::$bitrates[$this->_frequencyType][$this->_layer][$index] : false; - $this->_samplingFrequency = isset - (self::$samplingFrequencies[$this->_version] - [$index = Twiddling::getValue($header, 10, 11)]) ? - self::$samplingFrequencies[$this->_version][$index] : false; - $this->_padding = Twiddling::testBit($header, 9); - $this->_mode = Twiddling::getValue($header, 6, 7); - $this->_modeExtension = Twiddling::getValue($header, 4, 5); - $this->_copyright = Twiddling::testBit($header, 3); - $this->_original = Twiddling::testBit($header, 2); - $this->_emphasis = Twiddling::getValue($header, 0, 1); - - $this->_length = (int) - ((self::$coefficients[$this->_frequencyType][$this->_layer] * - ($this->_bitrate * 1000) / $this->_samplingFrequency) + - ($this->_padding ? 1 : 0)) * self::$slotsizes[$this->_layer]; - $this->_samples = self::$samples[$this->_frequencyType][$this->_layer]; - - if ($this->getOption("readmode", "lazy") == "full") { - $this->_readCrc(); - $this->_readData(); - } - $this->_reader->skip($this->_length - 4); - } - - /** - * Returns the version identifier of the algorithm. - * - * @see VERSION_ONE, VERSION_TWO, VERSION_TWO_FIVE - * @return integer - */ - public function getVersion() { return $this->_version; } - - /** - * Returns the sampling frequency type. This can be one of the following - * values. - * - * o {@link SAMPLING_FREQUENCY_HIGH} -- Higher Sampling Frequency - * (Version 1) - * o {@link SAMPLING_FREQUENCY_LOW} -- Lower Sampling Frequency - * (Version 2 and 2.5) - * - * @see SAMPLING_FREQUENCY_LOW, SAMPLING_FREQUENCY_HIGH - * @return integer - */ - public function getFrequencyType() { return $this->_frequencyType; } - - /** - * Returns the type of layer used. - * - * @see LAYER_ONE, LAYER_TWO, LAYER_THREE - * @return integer - */ - public function getLayer() { return $this->_layer; } - - /** - * An alias to getRedundancy(). - * - * @see getRedundancy - * @return boolean - */ - public function hasRedundancy() { return $this->getRedundancy(); } - - /** - * Returns boolean corresponding to whether redundancy has been added in the - * audio bitstream to facilitate error detection and concealment. Equals - * false if no redundancy has been added, true if - * redundancy has been added. - * - * @return boolean - */ - public function getRedundancy() { return $this->_redundancy; } - - /** - * Returns the bitrate in kbps. The returned value indicates the total bitrate - * irrespective of the mode (stereo, joint_stereo, dual_channel, - * single_channel). - * - * @return integer - */ - public function getBitrate() { return $this->_bitrate; } - - /** - * Returns the sampling frequency in Hz. - * - * @return integer - */ - public function getSamplingFrequency() { return $this->_samplingFrequency; } - - /** - * An alias to getPadding(). - * - * @see getPadding - * @return boolean - */ - public function hasPadding() { return $this->getPadding(); } - - /** - * Returns boolean corresponding the frame contains an additional slot to - * adjust the mean bitrate to the sampling frequency. Equals to - * true if padding has been added, false otherwise. - * - * Padding is only necessary with a sampling frequency of 44.1kHz. - * - * @return boolean - */ - public function getPadding() { return $this->_padding; } - - /** - * Returns the mode. In Layer I and II the CHANNEL_JOINT_STEREO mode is - * intensity_stereo, in Layer III it is intensity_stereo and/or ms_stereo. - * - * @see CHANNEL_STEREO, CHANNEL_JOINT_STEREO, CHANNEL_DUAL_CHANNEL, - * CHANNEL_SINGLE_CHANNEL - * @return integer - */ - public function getMode() { return $this->_mode; } - - /** - * Returns the mode extension used in CHANNEL_JOINT_STEREO mode. - * - * In Layer I and II the return type indicates which subbands are in - * intensity_stereo. All other subbands are coded in stereo. - * - * o {@link MODE_SUBBAND_4_TO_31} -- subbands 4-31 in - * intensity_stereo, bound==4 - * o {@link MODE_SUBBAND_8_TO_31} -- subbands 8-31 in - * intensity_stereo, bound==8 - * o {@link MODE_SUBBAND_12_TO_31} -- subbands 12-31 in - * intensity_stereo, bound==12 - * o {@link MODE_SUBBAND_16_TO_31} -- subbands 16-31 in - * intensity_stereo, bound==16 - * - * In Layer III they indicate which type of joint stereo coding method is - * applied. The frequency ranges over which the intensity_stereo and ms_stereo - * modes are applied are implicit in the algorithm. Please see - * {@link MODE_ISOFF_MSSOFF}, {@link MODE_ISON_MSSOFF}, - * {@link MODE_ISOFF_MSSON}, and {@link MODE_ISON_MSSON}. - * - * @return integer - */ - public function getModeExtension() { return $this->_modeExtension; } - - /** - * An alias to getCopyright(). - * - * @see getCopyright - * @return boolean - */ - public function hasCopyright() { return $this->getCopyright(); } - - /** - * Returns true if the coded bitstream is copyright protected, - * false otherwise. - * - * @return boolean - */ - public function getCopyright() { return $this->_copyright; } - - /** - * An alias to getOriginal(). - * - * @see getOriginal - * @return boolean - */ - public function isOriginal() { return $this->getOriginal(); } - - /** - * Returns whether the bitstream is original or home made. - * - * @return boolean - */ - public function getOriginal() { return $this->_original; } - - /** - * Returns the type of de-emphasis that shall be used. The value is one of the - * following. - * - * o {@link EMPHASIS_NONE} -- No emphasis - * o {@link EMPHASIS_50_15} -- 50/15 microsec. emphasis - * o {@link EMPHASIS_CCIT_J17} -- CCITT J.17 - * - * @see EMPHASIS_NONE, EMPHASIS_50_15, EMPHASIS_CCIT_J17 - * @return integer - */ - public function getEmphasis() { return $this->_emphasis; } - - /** - * Returns the length of the frame based on the current layer, bit rate, - * sampling frequency and padding, in bytes. - * - * @return integer - */ - public function getLength() { return $this->_length; } - - /** - * Returns the number of samples contained in the frame. - * - * @return integer - */ - public function getSamples() { return $this->_samples; } - - /** - * Returns the 16-bit CRC of the frame or false if not present. - * - * @return integer - */ - public function getCrc() - { - if ($this->getOption("readmode", "lazy") == "lazy" && - $this->hasRedundancy() && $this->_crc === false) { - $this->_readCrc(); - } - return $this->_crc; - } - - /** - * Reads the CRC data. - */ - private function _readCrc() - { - if ($this->hasRedundancy()) { - $offset = $this->_reader->getOffset(); - $this->_reader->setOffset($this->_offset + 4); - $this->_crc = $this->_reader->readUInt16BE(); - $this->_reader->setOffset($offset); - } - } - - /** - * Returns the audio data. - * - * @return string - */ - public function getData() - { - if ($this->getOption("readmode", "lazy") == "lazy" && - $this->_data === false) { - $this->_readData(); - } - return $this->_data; - } - - /** - * Reads the frame data. - */ - private function _readData() - { - $offset = $this->_reader->getOffset(); - $this->_reader->setOffset - ($this->_offset + 4 + ($this->hasRedundancy() ? 2 : 0)); - $this->_data = $this->_reader->read - ($this->getLength() - 4 - ($this->hasRedundancy() ? 2 : 0)); - $this->_reader->setOffset($offset); - } -} diff --git a/src/MPEG/ABS/LAMEHeader.php b/src/MPEG/ABS/LAMEHeader.php deleted file mode 100644 index 035d8fd..0000000 --- a/src/MPEG/ABS/LAMEHeader.php +++ /dev/null @@ -1,481 +0,0 @@ - - * @copyright Copyright (c) 2008 The PHP Reader Project Workgroup - * @license http://code.google.com/p/php-reader/wiki/License New BSD License - * @version $Rev$ - */ -class MPEG_ABS_LAMEHeader extends MPEG_ABS_Object -{ - - /** @var integer */ - const VBR_METHOD_CONSTANT = 1; - - /** @var integer */ - const VBR_METHOD_ABR = 2; - - /** @var integer */ - const VBR_METHOD_RH = 3; - - /** @var integer */ - const VBR_METHOD_MTRH = 4; - - /** @var integer */ - const VBR_METHOD_MT = 5; - - /** @var integer */ - const ENCODING_FLAG_NSPSYTUNE = 1; - - /** @var integer */ - const ENCODING_FLAG_NSSAFEJOINT = 2; - - /** @var integer */ - const ENCODING_FLAG_NOGAP_CONTINUED = 4; - - /** @var integer */ - const ENCODING_FLAG_NOGAP_CONTINUATION = 8; - - /** @var integer */ - const MODE_MONO = 0; - - /** @var integer */ - const MODE_STEREO = 1; - - /** @var integer */ - const MODE_DUAL = 2; - - /** @var integer */ - const MODE_JOINT = 3; - - /** @var integer */ - const MODE_FORCE = 4; - - /** @var integer */ - const MODE_AUTO = 5; - - /** @var integer */ - const MODE_INTENSITY = 6; - - /** @var integer */ - const MODE_UNDEFINED = 7; - - /** @var integer */ - const SOURCE_FREQUENCY_32000_OR_LOWER = 0; - - /** @var integer */ - const SOURCE_FREQUENCY_44100 = 1; - - /** @var integer */ - const SOURCE_FREQUENCY_48000 = 2; - - /** @var integer */ - const SOURCE_FREQUENCY_HIGHER = 3; - - /** @var integer */ - const SURROUND_NONE = 0; - - /** @var integer */ - const SURROUND_DPL = 1; - - /** @var integer */ - const SURROUND_DPL2 = 2; - - /** @var integer */ - const SURROUND_AMBISONIC = 3; - - /** @var string */ - private $_version; - - /** @var integer */ - private $_revision; - - /** @var integer */ - private $_vbrMethod; - - /** @var integer */ - private $_lowpass; - - /** @var integer */ - private $_peakSignalAmplitude; - - /** @var integer */ - private $_radioReplayGain; - - /** @var integer */ - private $_audiophileReplayGain; - - /** @var integer */ - private $_encodingFlags; - - /** @var integer */ - private $_athType; - - /** @var integer */ - private $_bitrate; - - /** @var integer */ - private $_encoderDelaySamples; - - /** @var integer */ - private $_paddedSamples; - - /** @var integer */ - private $_sourceSampleFrequency; - - /** @var boolean */ - private $_unwiseSettingsUsed; - - /** @var integer */ - private $_mode; - - /** @var integer */ - private $_noiseShaping; - - /** @var integer */ - private $_mp3Gain; - - /** @var integer */ - private $_surroundInfo; - - /** @var integer */ - private $_presetUsed; - - /** @var integer */ - private $_musicLength; - - /** @var integer */ - private $_musicCrc; - - /** @var integer */ - private $_crc; - - /** - * Constructs the class with given parameters and reads object related data - * from the bitstream. - * - * @param Reader $reader The reader object. - * @param Array $options Array of options. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_version = $this->_reader->readString8(5); - - $tmp = $this->_reader->readUInt8(); - $this->_revision = Twiddling::getValue($tmp, 4, 8); - $this->_vbrMethod = Twiddling::getValue($tmp, 0, 3); - - $this->_lowpass = $this->_reader->readUInt8() * 100; - - $this->_peakSignalAmplitude = $this->_reader->readUInt32BE(); - - $tmp = $this->_reader->readUInt16BE(); - $this->_radioReplayGain = array( - "name" => Twiddling::getValue($tmp, 0, 2), - "originator" => Twiddling::getValue($tmp, 3, 5), - "absoluteGainAdjustment" => Twiddling::getValue($tmp, 7, 15) / 10 - ); - - $tmp = $this->_reader->readUInt16BE(); - $this->_audiophileReplayGain = array( - "name" => Twiddling::getValue($tmp, 0, 2), - "originator" => Twiddling::getValue($tmp, 3, 5), - "absoluteGainAdjustment" => Twiddling::getValue($tmp, 7, 15) / 10 - ); - - $tmp = $this->_reader->readUInt8(); - $this->_encodingFlags = Twiddling::getValue($tmp, 4, 8); - $this->_athType = Twiddling::getValue($tmp, 0, 3); - - $this->_bitrate = $this->_reader->readUInt8(); - - $tmp = $this->_reader->readUInt32BE(); - // Encoder delay fields - $this->_encoderDelaySamples = Twiddling::getValue($tmp, 20, 31); - $this->_paddedSamples = Twiddling::getValue($tmp, 8, 19); - // Misc field - $this->_sourceSampleFrequency = Twiddling::getValue($tmp, 6, 7); - $this->_unwiseSettingsUsed = Twiddling::testBit($tmp, 5); - $this->_mode = Twiddling::getValue($tmp, 2, 4); - $this->_noiseShaping = Twiddling::getValue($tmp, 0, 1); - - $this->_mp3Gain = pow(2, $this->_reader->readInt8() / 4); - - $tmp = $this->_reader->readUInt16BE(); - $this->_surroundInfo = Twiddling::getValue($tmp, 11, 14); - $this->_presetUsed = Twiddling::getValue($tmp, 0, 10); - - $this->_musicLength = $this->_reader->readUInt32BE(); - - $this->_musicCrc = $this->_reader->readUInt16BE(); - $this->_crc = $this->_reader->readUInt16BE(); - } - - /** - * Returns the version string of the header. - * - * @return string - */ - public function getVersion() { return $this->_version; } - - /** - * Returns the info tag revision. - * - * @return integer - */ - public function getRevision() { return $this->_revision; } - - /** - * Returns the VBR method used for encoding. See the corresponding constants - * for possible return values. - * - * @return integer - */ - public function getVbrMethod() { return $this->_vbrMethod; } - - /** - * Returns the lowpass filter value. - * - * @return integer - */ - public function getLowpass() { return $this->_lowpass; } - - /** - * Returns the peak signal amplitude field of replay gain. The value of 1.0 - * (ie 100%) represents maximal signal amplitude storeable in decoding format. - * - * @return integer - */ - public function getPeakSignalAmplitude() - { - return $this->_peakSignalAmplitude; - } - - /** - * Returns the radio replay gain field of replay gain, required to make all - * tracks equal loudness, as an array that consists of the following keys. - * - * o name -- Specifies the name of the gain adjustment. Can be one of the - * following values: 0 = not set, 1 = radio, or 2 = audiophile. - * - * o originator -- Specifies the originator of the gain adjustment. Can be - * one of the following values: 0 = not set, 1 = set by artist, 2 = set - * by user, 3 = set by my model, 4 = set by simple RMS average. - * - * o absoluteGainAdjustment -- Speficies the absolute gain adjustment. - * - * @return Array - */ - public function getRadioReplayGain() { return $this->_radioReplayGain; } - - /** - * Returns the audiophile replay gain field of replay gain, required to give - * ideal listening loudness, as an array that consists of the following keys. - * - * o name -- Specifies the name of the gain adjustment. Can be one of the - * following values: 0 = not set, 1 = radio, or 2 = audiophile. - * - * o originator -- Specifies the originator of the gain adjustment. Can be - * one of the following values: 0 = not set, 1 = set by artist, 2 = set - * by user, 3 = set by my model, 4 = set by simple RMS average. - * - * o absoluteGainAdjustment -- Speficies the absolute gain adjustment. - * - * @return Array - */ - public function getAudiophileReplayGain() - { - return $this->_audiophileReplayGain; - } - - /** - * Returns the encoding flags. See the corresponding flag constants for - * possible values. - * - * @return integer - */ - public function getEncodingFlags() { return $this->_encodingFlags; } - - /** - * Returns the ATH type. - * - * @return integer - */ - public function getAthType() { return $this->_athType; } - - /** - * Returns the bitrate for CBR encoded files and the minimal birate for - * VBR encoded file. The maximum value of this field is 255 even with higher - * actual bitrates. - * - * @return integer - */ - public function getBitrate() { return $this->_bitrate; } - - /** - * Returns the encoder delay or number of samples added at start. - * - * @return integer - */ - public function getEncoderDelaySamples() - { - return $this->_encoderDelaySamples; - } - - /** - * Returns the number of padded samples to complete the last frame. - * - * @return integer - */ - public function getPaddedSamples() { return $this->_paddedSamples; } - - /** - * Returns the source sample frequency. See corresponding constants for - * possible values. - * - * @return integer - */ - public function getSourceSampleFrequency() - { - return $this->_sourceSampleFrequency; - } - - /** - * An alias to getUnwiseSettingsUsed(). - * - * @see getUnwiseSettingsUsed - * @return boolean - */ - public function areUnwiseSettingsUsed() - { - return $this->getUnwiseSettingsUsed(); - } - - /** - * Returns whether unwise settings were used to encode the file. - * - * @return boolean - */ - public function getUnwiseSettingsUsed() { return $this->_unwiseSettingsUsed; } - - /** - * Returns the stereo mode. See corresponding constants for possible values. - * - * @return integer - */ - public function getMode() { return $this->_mode; } - - /** - * Returns the noise shaping. - * - * @return integer - */ - public function getNoiseShaping() { return $this->_noiseShaping; } - - /** - * Returns the MP3 gain change. Any MP3 can be amplified in a lossless manner. - * If done so, this field can be used to log such transformation happened so - * that any given time it can be undone. - * - * @return integer - */ - public function getMp3Gain() { return $this->_mp3Gain; } - - /** - * Returns the surround info. See corresponding contants for possible values. - * - * @return integer - */ - public function getSurroundInfo() { return $this->_surroundInfo; } - - /** - * Returns the preset used in encoding. - * - * @return integer - */ - public function getPresetUsed() { return $this->_presetUsed; } - - /** - * Returns the exact length in bytes of the MP3 file originally made by LAME - * excluded ID3 tag info at the end. - * - * The first byte it counts is the first byte of this LAME header and the last - * byte it counts is the last byte of the last MP3 frame containing music. - * The value should be equal to file length at the time of LAME encoding, - * except when using ID3 tags. - * - * @return integer - */ - public function getMusicLength() { return $this->_musicLength; } - - /** - * Returns the CRC-16 of the complete MP3 music data as made originally by - * LAME. - * - * @return integer - */ - public function getMusicCrc() { return $this->_musicCrc; } - - /** - * Returns the CRC-16 of the first 190 bytes of the header frame. - * - * @return integer - */ - public function getCrc() { return $this->_crc; } -} diff --git a/src/MPEG/ABS/Object.php b/src/MPEG/ABS/Object.php deleted file mode 100644 index b05588a..0000000 --- a/src/MPEG/ABS/Object.php +++ /dev/null @@ -1,167 +0,0 @@ - - * @author Sven Vollbehr - * @copyright Copyright (c) 2008 The PHP Reader Project Workgroup - * @license http://code.google.com/p/php-reader/wiki/License New BSD License - * @version $Rev$ - */ -abstract class MPEG_ABS_Object extends MPEG_Object -{ - /** @var integer */ - const VERSION_ONE = 3; - - /** @var integer */ - const VERSION_TWO = 2; - - /** @var integer */ - const VERSION_TWO_FIVE = 0; - - /** @var integer */ - const SAMPLING_FREQUENCY_LOW = 0; - - /** @var integer */ - const SAMPLING_FREQUENCY_HIGH = 1; - - /** @var integer */ - const LAYER_ONE = 3; - - /** @var integer */ - const LAYER_TWO = 2; - - /** @var integer */ - const LAYER_THREE = 1; - - /** @var integer */ - const CHANNEL_STEREO = 0; - - /** @var integer */ - const CHANNEL_JOINT_STEREO = 1; - - /** @var integer */ - const CHANNEL_DUAL_CHANNEL = 2; - - /** @var integer */ - const CHANNEL_SINGLE_CHANNEL = 3; - - /** @var integer */ - const MODE_SUBBAND_4_TO_31 = 0; - - /** @var integer */ - const MODE_SUBBAND_8_TO_31 = 1; - - /** @var integer */ - const MODE_SUBBAND_12_TO_31 = 2; - - /** @var integer */ - const MODE_SUBBAND_16_TO_31 = 3; - - /** @var integer */ - const MODE_ISOFF_MSSOFF = 0; - - /** @var integer */ - const MODE_ISON_MSSOFF = 1; - - /** @var integer */ - const MODE_ISOFF_MSSON = 2; - - /** @var integer */ - const MODE_ISON_MSSON = 3; - - /** @var integer */ - const EMPHASIS_NONE = 0; - - /** @var integer */ - const EMPHASIS_50_15 = 1; - - /** @var integer */ - const EMPHASIS_CCIT_J17 = 3; - - - /** - * Layer III side information size lookup table. The table has the following - * format. - * - * - * array ( - * SAMPLING_FREQUENCY_HIGH | SAMPLING_FREQUENCY_LOW => array ( - * CHANNEL_STEREO | CHANNEL_JOINT_STEREO | CHANNEL_DUAL_CHANNEL | - * CHANNEL_SINGLE_CHANNEL => - * ) - * ) - * - * - * - * @var Array - */ - protected static $sidesizes = array( - self::SAMPLING_FREQUENCY_HIGH => array( - self::CHANNEL_STEREO => 32, - self::CHANNEL_JOINT_STEREO => 32, - self::CHANNEL_DUAL_CHANNEL => 32, - self::CHANNEL_SINGLE_CHANNEL => 17 - ), - self::SAMPLING_FREQUENCY_LOW => array( - self::CHANNEL_STEREO => 17, - self::CHANNEL_JOINT_STEREO => 17, - self::CHANNEL_DUAL_CHANNEL => 17, - self::CHANNEL_SINGLE_CHANNEL => 9 - ) - ); - - - /** - * Constructs the class with given parameters. - * - * @param Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - } -} diff --git a/src/MPEG/ABS/VBRIHeader.php b/src/MPEG/ABS/VBRIHeader.php deleted file mode 100644 index f874e93..0000000 --- a/src/MPEG/ABS/VBRIHeader.php +++ /dev/null @@ -1,165 +0,0 @@ - - * @author Sven Vollbehr - * @copyright Copyright (c) 2008 The PHP Reader Project Workgroup - * @license http://code.google.com/p/php-reader/wiki/License New BSD License - * @version $Rev$ - */ -class MPEG_ABS_VBRIHeader extends MPEG_ABS_Object -{ - /** @var integer */ - private $_version; - - /** @var integer */ - private $_delay; - - /** @var integer */ - private $_qualityIndicator; - - /** @var integer */ - private $_bytes; - - /** @var integer */ - private $_frames; - - /** @var Array */ - private $_toc = array(); - - /** @var integer */ - private $_tocFramesPerEntry; - - /** @var integer */ - private $_length; - - /** - * Constructs the class with given parameters and reads object related data - * from the bitstream. - * - * @param Reader $reader The reader object. - * @param Array $options Array of options. - */ - public function __construct($reader, &$options = array()) - { - $offset = $this->_reader->getOffset(); - $this->_version = $this->_reader->readUInt16BE(); - $this->_delay = $this->_reader->readUInt16BE(); - $this->_qualityIndicator = $this->_reader->readUInt16BE(); - $this->_bytes = $this->_reader->readUInt32BE(); - $this->_frames = $this->_reader->readUInt32BE(); - $tocEntries = $this->_reader->readUInt16BE(); - $tocEntryScale = $this->_reader->readUInt16BE(); - $tocEntrySize = $this->_reader->readUInt16BE(); - $this->_tocFramesPerEntry = $this->_reader->readUInt16BE(); - $this->_toc = array_merge(unpack(($tocEntrySize == 1) ? "C*" : - ($tocEntrySize == 2) ? "n*" : "N*", - $this->_reader->read($tocCount * $tocEntrySize))); - foreach ($this->_toc as $key => $value) - $this->_toc[$key] = $tocEntryScale * $value; - $this->_length = $this->_reader->getOffset() - $offset; - } - - /** - * Returns the header version. - * - * @return integer - */ - public function getVersion() { return $this->_version; } - - /** - * Returns the delay. - * - * @return integer - */ - public function getDelay() { return $this->_delay; } - - /** - * Returns the quality indicator. Return value varies from 0 (best quality) to - * 100 (worst quality). - * - * @return integer - */ - public function getQualityIndicator() { return $this->_qualityIndicator; } - - /** - * Returns the number of bytes in the file. - * - * @return integer - */ - public function getBytes() { return $this->_bytes; } - - /** - * Returns the number of frames in the file. - * - * @return integer - */ - public function getFrames() { return $this->_frames; } - - /** - * Returns the table of contents array. - * - * @return Array - */ - public function getToc() { return $this->_toc; } - - /** - * Returns the number of frames per TOC entry. - * - * @return integer - */ - public function getTocFramesPerEntry() { return $this->_tocFramesPerEntry; } - - /** - * Returns the length of the header in bytes. - * - * @return integer - */ - public function getLength() { return $this->_length; } -} diff --git a/src/MPEG/ABS/XINGHeader.php b/src/MPEG/ABS/XINGHeader.php deleted file mode 100644 index d7ce7a7..0000000 --- a/src/MPEG/ABS/XINGHeader.php +++ /dev/null @@ -1,136 +0,0 @@ - - * @author Sven Vollbehr - * @copyright Copyright (c) 2008 The PHP Reader Project Workgroup - * @license http://code.google.com/p/php-reader/wiki/License New BSD License - * @version $Rev$ - */ -class MPEG_ABS_XINGHeader extends MPEG_ABS_Object -{ - /** @var integer */ - private $_frames = false; - - /** @var integer */ - private $_bytes = false; - - /** @var Array */ - private $_toc = array(); - - /** @var integer */ - private $_qualityIndicator = false; - - /** - * Constructs the class with given parameters and reads object related data - * from the bitstream. - * - * @param Reader $reader The reader object. - * @param Array $options Array of options. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $flags = $reader->readUInt32BE(); - - if (Twiddling::testAnyBits($flags, 0x1)) - $this->_frames = $this->_reader->readUInt32BE(); - if (Twiddling::testAnyBits($flags, 0x2)) - $this->_bytes = $this->_reader->readUInt32BE(); - if (Twiddling::testAnyBits($flags, 0x4)) - $this->_toc = array_merge(unpack("C*", $this->_reader->read(100))); - if (Twiddling::testAnyBits($flags, 0x8)) - $this->_qualityIndicator = $this->_reader->readUInt32BE(); - } - - /** - * Returns the number of frames in the file. - * - * @return integer - */ - public function getFrames() { return $this->_frames; } - - /** - * Returns the number of bytes in the file. - * - * @return integer - */ - public function getBytes() { return $this->_bytes; } - - /** - * Returns the table of contents array. The returned array has a fixed amount - * of 100 seek points to the file. - * - * @return Array - */ - public function getToc() { return $this->_toc; } - - /** - * Returns the quality indicator. The indicator is from 0 (best quality) to - * 100 (worst quality). - * - * @return integer - */ - public function getQualityIndicator() { return $this->_qualityIndicator; } - - /** - * Returns the length of the header in bytes. - * - * @return integer - */ - public function getLength() - { - return 4 + - ($this->_frames !== false ? 4 : 0) + - ($this->_bytes !== false ? 4 : 0) + - (empty($this->_toc) ? 0 : 100) + - ($this->_qualityIndicator !== false ? 4 : 0); - } -} diff --git a/src/MPEG/Exception.php b/src/MPEG/Exception.php deleted file mode 100644 index 6f24368..0000000 --- a/src/MPEG/Exception.php +++ /dev/null @@ -1,51 +0,0 @@ - - * @copyright Copyright (c) 2008 The PHP Reader Project Workgroup - * @license http://code.google.com/p/php-reader/wiki/License New BSD License - * @version $Rev$ - */ -class MPEG_Exception extends Exception -{ -} diff --git a/src/MPEG/Object.php b/src/MPEG/Object.php deleted file mode 100644 index d772e4d..0000000 --- a/src/MPEG/Object.php +++ /dev/null @@ -1,258 +0,0 @@ - - * @copyright Copyright (c) 2008-2009 The PHP Reader Project Workgroup - * @license http://code.google.com/p/php-reader/wiki/License New BSD License - * @version $Rev$ - */ -abstract class MPEG_Object -{ - /** - * The reader object. - * - * @var Reader - */ - protected $_reader; - - /** - * The options array. - * - * @var Array - */ - private $_options; - - /** - * Constructs the class with given parameters. - * - * @param Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - $this->_reader = $reader; - $this->_options = &$options; - } - - /** - * 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 = false) - { - if (isset($this->_options[$option])) - return $this->_options[$option]; - return $defaultValue; - } - - /** - * Sets the options array. See {@link MPEG} 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; - } - - /** - * Finds and returns the next start code. Start codes are reserved bit - * patterns in the video file that do not otherwise occur in the video stream. - * - * All start codes are byte aligned and start with the following byte - * sequence: 0x00 0x00 0x01. - * - * @return integer - */ - protected final function nextStartCode() - { - $buffer = " "; - for ($i = 0; $i < 4; $i++) { - $start = $this->_reader->getOffset(); - if (($buffer = substr($buffer, -4) . - $this->_reader->read(512)) === false) { - require_once("MPEG/Exception.php"); - throw new MPEG_Exception("Invalid data"); - } - $limit = strlen($buffer); - $pos = 0; - while ($pos < $limit - 3) { - if (Transform::fromUInt8($buffer{$pos++}) == 0 && - Transform::fromUInt16BE(substr($buffer, $pos, 2)) == 1) { - if (($pos += 2) < $limit - 2) - if (Transform::fromUInt16BE(substr($buffer, $pos, 2)) == 0 && - Transform::fromUInt8($buffer{$pos + 2}) == 1) - continue; - $this->_reader->setOffset($start + $pos - 3); - return Transform::fromUInt8($buffer{$pos++}) & 0xff | 0x100; - } - } - $this->_reader->setOffset($start + $limit); - } - - /* No start code found within 2048 bytes, the maximum size of a pack */ - require_once("MPEG/Exception.php"); - throw new MPEG_Exception("Invalid data"); - } - - /** - * Finds and returns the previous start code. Start codes are reserved bit - * patterns in the video file that do not otherwise occur in the video stream. - * - * All start codes are byte aligned and start with the following byte - * sequence: 0x00 0x00 0x01. - * - * @return integer - */ - protected final function prevStartCode() - { - $buffer = " "; - $start; - $position = $this->_reader->getOffset(); - while ($position > 0) { - $start = 0; - $position = $position - 512; - if ($position < 0) { - require_once("MPEG/Exception.php"); - throw new MPEG_Exception("Invalid data"); - } - $this->_reader->setOffset($position); - $buffer = $this->_reader->read(512) . substr($buffer, 0, 4); - $pos = 512 - 8; - while ($pos > 3) { - if (Transform::fromUInt8($buffer{$pos}) == 0 && - Transform::fromUInt16BE(substr($buffer, $pos + 1, 2)) == 1) { - - if ($pos + 2 < 512 && - Transform::fromUInt16BE(substr($buffer, $pos + 3, 2)) == 0 && - Transform::fromUInt8($buffer{$pos + 5}) == 1) { - $pos --; - continue; - } - $this->_reader->setOffset($position + $pos); - return Transform::fromUInt8($buffer{$pos + 3}) & 0xff | 0x100; - } - $pos--; - } - $this->_reader->setOffset($position = $position + 3); - } - return 0; - } - - /** - * Formats given time in seconds into the form of - * [hours:]minutes:seconds.milliseconds. - * - * @param integer $seconds The time to format, in seconds - * @return string - */ - protected final function formatTime($seconds) - { - $milliseconds = round(($seconds - floor($seconds)) * 1000); - $seconds = floor($seconds); - $minutes = floor($seconds / 60); - $hours = floor($minutes / 60); - return - ($minutes > 0 ? - ($hours > 0 ? $hours . ":" . - str_pad($minutes % 60, 2, "0", STR_PAD_LEFT) : $minutes % 60) . ":" . - str_pad($seconds % 60, 2, "0", STR_PAD_LEFT) : $seconds % 60) . "." . - str_pad($milliseconds, 3, "0", STR_PAD_LEFT); - } - - /** - * 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("MPEG/Exception.php"); - throw new MPEG_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("MPEG/Exception.php"); - throw new MPEG_Exception("Unknown field: " . $name); - } - } -} diff --git a/src/MPEG/PS.php b/src/MPEG/PS.php deleted file mode 100644 index e867fad..0000000 --- a/src/MPEG/PS.php +++ /dev/null @@ -1,146 +0,0 @@ - - * @copyright Copyright (c) 2008 The PHP Reader Project Workgroup - * @license http://code.google.com/p/php-reader/wiki/License New BSD License - * @version $Rev$ - * @todo Full implementation - */ -final class MPEG_PS extends MPEG_Object -{ - /** @var integer */ - private $_length; - - /** - * Constructs the class with given file and options. - * - * @param string|Reader $filename The path to the file, file descriptor of an - * opened file, or {@link Reader} instance. - * @param Array $options The options array. - */ - public function __construct($filename, $options = array()) - { - if ($filename instanceof Reader) - $reader = &$filename; - else - $reader = new Reader($filename); - - parent::__construct($reader, $options); - - $startCode = 0; $startTime = 0; - $pictureCount = 0; $pictureRate = 0; - $rates = array ( 0, 23.976, 24, 25, 29.97, 30, 50, 59.94, 60 ); - $foundSeqHdr = false; $foundGOP = false; - - do { - do { - $startCode = $this->nextStartCode(); - } while ($startCode != 0x1b3 && $startCode != 0x1b8); - if ($startCode == 0x1b3 /* sequence_header_code */ && $pictureRate == 0) { - $i1 = $this->_reader->readUInt32BE(); - $i2 = $this->_reader->readUInt32BE(); - if (!Twiddling::testAllBits($i2, 0x2000)) - throw new RuntimeException("Invalid mark"); - $pictureRate = $rates[Twiddling::getValue($i1, 4, 8)]; - $foundSeqHdr = true; - } - if ($startCode == 0x1b8 /* group_start_code */) { - $tmp = $this->_reader->readUInt32BE(); - $startTime = (($tmp >> 26) & 0x1f) * 60 * 60 * 1000 /* hours */ + - (($tmp >> 20) & 0x3f) * 60 * 1000 /* minutes */ + - (($tmp >> 13) & 0x3f) * 1000 /* seconds */ + - (int)(1 / $pictureRate * (($tmp >> 7) & 0x3f) * 1000); - $foundGOP = true; - } - } while (!$foundSeqHdr || !$foundGOP); - - $this->_reader->setOffset($this->_reader->getSize()); - - do { - if (($startCode = $this->prevStartCode()) == 0x100) - $pictureCount++; - } while ($startCode != 0x1b8); - - $this->_reader->skip(4); - $tmp = $this->_reader->readUInt32BE(); - $this->_length = - (((($tmp >> 26) & 0x1f) * 60 * 60 * 1000 /* hours */ + - (($tmp >> 20) & 0x3f) * 60 * 1000 /* minutes */ + - (($tmp >> 13) & 0x3f) * 1000 /* seconds */ + - (int)(1 / $pictureRate * (($tmp >> 7) & 0x3f) * 1000)) - $startTime + - (int)(1 / $pictureRate * $pictureCount * 1000)) / 1000; - } - - /** - * Returns the exact playtime in seconds. - * - * @return integer - */ - public function getLength() { return $this->_length; } - - /** - * Returns the exact playtime given in seconds as a string in the form of - * [hours:]minutes:seconds.milliseconds. - * - * @param integer $seconds The playtime in seconds. - * @return string - */ - public function getFormattedLength() - { - return $this->formatTime($this->getLength()); - } -} diff --git a/src/Transform.php b/src/Transform.php deleted file mode 100644 index 339af14..0000000 --- a/src/Transform.php +++ /dev/null @@ -1,711 +0,0 @@ - - * @author Ryan Butterfield - * @copyright Copyright (c) 2006-2009 The PHP Reader Project Workgroup - * @license http://code.google.com/p/php-reader/wiki/License New BSD License - * @version $Rev$ - * @static - */ -final class Transform -{ - const MACHINE_ENDIAN_ORDER = 0; - const LITTLE_ENDIAN_ORDER = 1; - const BIG_ENDIAN_ORDER = 2; - - /** - * Default private constructor for a static class. - */ - private function __construct() {} - - /** - * Returns whether the current machine endian order is little endian. - * - * @return boolean - */ - public static function isLittleEndian() - { - return self::fromInt32("\x01\x00\x00\x00") == 1; - } - - /** - * Returns whether the current machine endian order is big endian. - * - * @return boolean - */ - public static function isBigEndian() - { - return self::fromInt32("\x00\x00\x00\x01") == 1; - } - - /** - * Returns 64-bit float as little-endian ordered binary data string. - * - * @param integer $value The input value. - * @return string - */ - public static function toInt64LE($value) - { - return pack("V*", $value & 0xffffffff, $value / (0xffffffff+1)); - } - - /** - * Returns little-endian ordered binary data as 64-bit float. PHP does not - * support 64-bit integers as the long integer is of 32-bits but using - * aritmetic operations it is implicitly converted into floating point which - * is of 64-bits long. - * - * @param string $value The binary data string. - * @return integer - */ - public static function fromInt64LE($value) - { - list(, $lolo, $lohi, $hilo, $hihi) = unpack("v*", $value); - return ($hihi * (0xffff+1) + $hilo) * (0xffffffff+1) + - ($lohi * (0xffff+1) + $lolo); - } - - /** - * Returns 64-bit float as big-endian ordered binary data string. - * - * @param integer $value The input value. - * @return string - */ - public static function toInt64BE($value) - { - return pack("N*", $value / (0xffffffff+1), $value & 0xffffffff); - } - - /** - * Returns big-endian ordered binary data as 64-bit float. PHP does not - * support 64-bit integers as the long integer is of 32-bits but using - * aritmetic operations it is implicitly converted into floating point which - * is of 64-bits long. - * - * @param string $value The binary data string. - * @return integer - */ - public static function fromInt64BE($value) - { - list(, $hihi, $hilo, $lohi, $lolo) = unpack("n*", $value); - return ($hihi * (0xffff+1) + $hilo) * (0xffffffff+1) + - ($lohi * (0xffff+1) + $lolo); - } - - /** - * Returns signed 32-bit integer as machine-endian ordered binary data. - * - * @param integer $value The input value. - * @return string - */ - public static function toInt32($value) - { - return pack("l*", $value); - } - - /** - * Returns machine-endian ordered binary data as signed 32-bit integer. - * - * @param string $value The binary data string. - * @return integer - */ - public static function fromInt32($value) - { - list(, $int) = unpack("l*", $value); - return $int; - } - - /** - * Returns signed 32-bit integer as little-endian ordered binary data. - * - * @param integer $value The input value. - * @return string - */ - public static function toInt32LE($value) - { - if (self::isBigEndian()) - return strrev(self::toInt32($value)); - else - return self::toInt32($value); - } - - /** - * Returns little-endian ordered binary data as signed 32-bit integer. - * - * @param string $value The binary data string. - * @return integer - */ - public static function fromInt32LE($value) - { - if (self::isBigEndian()) - return self::fromInt32(strrev($value)); - else - return self::fromInt32($value); - } - - /** - * Returns signed 32-bit integer as big-endian ordered binary data. - * - * @param integer $value The input value. - * @return string - */ - public static function toInt32BE($value) - { - if (self::isBigEndian()) - return self::toInt32($value); - else - return strrev(self::toInt32($value)); - } - - /** - * Returns big-endian ordered binary data as signed 32-bit integer. - * - * @param string $value The binary data string. - * @return integer - */ - public static function fromInt32BE($value) - { - if (self::isBigEndian()) - return self::fromInt32($value); - else - return self::fromInt32(strrev($value)); - } - - /** - * Returns unsigned 32-bit integer as little-endian ordered binary data. - * - * @param integer $value The input value. - * @return string - */ - public static function toUInt32LE($value) - { - return pack("V*", $value); - } - - /** - * Returns little-endian ordered binary data as unsigned 32-bit integer. - * - * @param string $value The binary data string. - * @return integer - */ - public static function fromUInt32LE($value) - { - if (PHP_INT_SIZE < 8) { - list(, $lo, $hi) = unpack("v*", $value); - return $hi * (0xffff+1) + $lo; // eq $hi << 16 | $lo - } else { - list(, $int) = unpack("V*", $value); - return $int; - } - } - - /** - * Returns unsigned 32-bit integer as big-endian ordered binary data. - * - * @param integer $value The input value. - * @return string - */ - public static function toUInt32BE($value) - { - return pack("N*", $value); - } - - /** - * Returns big-endian ordered binary data as unsigned 32-bit integer. - * - * @param string $value The binary data string. - * @return integer - */ - public static function fromUInt32BE($value) - { - if (PHP_INT_SIZE < 8) { - list(, $hi, $lo) = unpack("n*", $value); - return $hi * (0xffff+1) + $lo; // eq $hi << 16 | $lo - } else { - list(, $int) = unpack("N*", $value); - return $int; - } - } - - /** - * Returns signed 16-bit integer as machine endian ordered binary data. - * - * @param integer $value The input value. - * @return string - */ - public static function toInt16($value) - { - return pack("s*", $value); - } - - /** - * Returns machine endian ordered binary data as signed 16-bit integer. - * - * @param string $value The binary data string. - * @return integer - */ - public static function fromInt16($value) - { - list(, $int) = unpack("s*", $value); - return $int; - } - - /** - * Returns signed 16-bit integer as little-endian ordered binary data. - * - * @param integer $value The input value. - * @return string - */ - public static function toInt16LE($value) - { - if (self::isBigEndian()) - return strrev(self::toInt16($value)); - else - return self::toInt16($value); - } - - /** - * Returns little-endian ordered binary data as signed 16-bit integer. - * - * @param string $value The binary data string. - * @return integer - */ - public static function fromInt16LE($value) - { - if (self::isBigEndian()) - return self::fromInt16(strrev($value)); - else - return self::fromInt16($value); - } - - /** - * Returns signed 16-bit integer as big-endian ordered binary data. - * - * @param integer $value The input value. - * @return string - */ - public static function toInt16BE($value) - { - if (self::isBigEndian()) - return self::toInt16($value); - else - return strrev(self::toInt16($value)); - } - - /** - * Returns big-endian ordered binary data as signed 16-bit integer. - * - * @param string $value The binary data string. - * @return integer - */ - public static function fromInt16BE($value) - { - if (self::isBigEndian()) - return self::fromInt16($value); - else - return self::fromInt16(strrev($value)); - } - - /** - * Returns machine endian ordered binary data as unsigned 16-bit integer. - * - * @param string $value The binary data string. - * @param integer $order The byte order of the binary data string. - * @return integer - */ - private static function fromUInt16($value, $order = self::MACHINE_ENDIAN_ORDER) - { - list(, $int) = unpack - (($order == self::BIG_ENDIAN_ORDER ? "n" : - ($order == self::LITTLE_ENDIAN_ORDER ? "v" : "S")) . "*", $value); - return $int; - } - - /** - * Returns unsigned 16-bit integer as little-endian ordered binary data. - * - * @param integer $value The input value. - * @return string - */ - public static function toUInt16LE($value) - { - return pack("v*", $value); - } - - /** - * Returns little-endian ordered binary data as unsigned 16-bit integer. - * - * @param string $value The binary data string. - * @return integer - */ - public static function fromUInt16LE($value) - { - return self::fromUInt16($value, self::LITTLE_ENDIAN_ORDER); - } - - /** - * Returns unsigned 16-bit integer as big-endian ordered binary data. - * - * @param integer $value The input value. - * @return string - */ - public static function toUInt16BE($value) - { - return pack("n*", $value); - } - - /** - * Returns big-endian ordered binary data as unsigned 16-bit integer. - * - * @param string $value The binary data string. - * @return integer - */ - public static function fromUInt16BE($value) - { - return self::fromUInt16($value, self::BIG_ENDIAN_ORDER); - } - - /** - * Returns an 8-bit integer as binary data. - * - * @param integer $value The input value. - * @return integer - */ - public static function toInt8($value) - { - return pack("c*", $value); - } - - /** - * Returns binary data as 8-bit integer. - * - * @param string $value The binary data string. - * @return integer - */ - public static function fromInt8($value) - { - list(, $int) = unpack("c*", $value); - return $int; - } - - /** - * Returns an unsigned 8-bit integer as binary data. - * - * @param integer $value The input value. - * @return integer - */ - public static function toUInt8($value) - { - return pack("C*", $value); - } - - /** - * Returns binary data as an unsigned 8-bit integer. - * - * @param string $value The binary data string. - * @return integer - */ - public static function fromUInt8($value) - { - list(, $int) = unpack("C*", $value); - return $int; - } - - /** - * Returns a floating point number as machine endian ordered binary data. - * - * @param float $value The input value. - * @return string - */ - public static function toFloat($value) - { - return pack("f*", $value); - } - - /** - * Returns machine endian ordered binary data as a floating point number. - * - * @param string $value The binary data string. - * @return float - */ - public static function fromFloat($value) - { - list(, $float) = unpack("f*", $value); - return $float; - } - - /** - * Returns a floating point number as little-endian ordered binary data. - * - * @param float $value The input value. - * @return string - */ - public static function toFloatLE($value) - { - if (self::isBigEndian()) - return strrev(self::toFloat($value)); - else - return self::toFloat($value); - } - - /** - * Returns little-endian ordered binary data as a floating point number. - * - * @param string $value The binary data string. - * @return float - */ - public static function fromFloatLE($value) - { - if (self::isBigEndian()) - return self::fromFloat(strrev($value)); - else - return self::fromFloat($value); - } - - /** - * Returns a floating point number as big-endian ordered binary data. - * - * @param float $value The input value. - * @return string - */ - public static function toFloatBE($value) - { - if (self::isBigEndian()) - return self::toFloat($value); - else - return strrev(self::toFloat($value)); - } - - /** - * Returns big-endian ordered binary data as a float point number. - * - * @param string $value The binary data string. - * @return float - */ - public static function fromFloatBE($value) - { - if (self::isBigEndian()) - return self::fromFloat($value); - else - return self::fromFloat(strrev($value)); - } - - /** - * Returns string as binary data padded to given length with zeros. If length - * is smaller than the length of the string, it is considered as the length of - * the padding. - * - * @param string $value The input value. - * @param integer $length The length to which to pad the value. - * @param string $padding The padding character. - * @return string - */ - public static function toString8($value, $length = false, $padding = "\0") - { - if ($length === false) - $length = strlen($value); - if ($length < ($tmp = strlen($value))) - $length = $tmp + $length; - return str_pad($value, $length, $padding); - } - - /** - * Returns binary data as string. Removes terminating zero. - * - * @param string $value The binary data string. - * @return string - */ - public static function fromString8($value) - { - return rtrim($value, "\0"); - } - - /** - * Returns the multibyte string as binary data with given byte order mark - * (BOM) and padded to given length with zeros. Length is given in unicode - * characters so each character adds two zeros to the string. If length is - * smaller than the length of the string, it is considered as the length of - * the padding. - * - * If byte order mark is false no mark is inserted to the binary - * data. - * - * @param string $value The input value. - * @param integer $order The byte order of the binary data string. - * @param integer $length The length to which to pad the value. - * @param string $padding The padding character. - * @return string - */ - public static function toString16 - ($value, $order = false, $length = false, $padding = "\0") - { - if ($length === false) - $length = (int)(strlen($value) / 2); - if ($length < ($tmp = strlen($value) / 2)) - $length = $tmp + $length; - if ($order == self::BIG_ENDIAN_ORDER && - !(ord($value[0]) == 0xfe && ord($value[1]) == 0xff)) { - $value = 0xfeff . $value; - $length++; - } - if ($order == self::LITTLE_ENDIAN_ORDER && - !(ord($value[0]) == 0xff && ord($value[1]) == 0xfe)) { - $value = 0xfffe . $value; - $length++; - } - return str_pad($value, $length * 2, $padding); - } - - /** - * Returns binary data as multibyte Unicode string. Removes terminating zero. - * - * The byte order is possibly determined from the byte order mark included in - * the binary data string. The order parameter is updated if the BOM is found. - * - * @param string $value The binary data string. - * @param integer $order The endianess of the string. - * @param integer $trimOrder Whether to remove the byte order mark from the - * string. - * @return string - */ - public static function fromString16 - ($value, &$order = false, $trimOrder = false) - { - if (strlen($value) < 2) - return ""; - - if (ord($value[0]) == 0xfe && ord($value[1]) == 0xff) { - $order = self::BIG_ENDIAN_ORDER; - if ($trimOrder) - $value = substr($value, 2); - } - if (ord($value[0]) == 0xff && ord($value[1]) == 0xfe) { - $order = self::LITTLE_ENDIAN_ORDER; - if ($trimOrder) - $value = substr($value, 2); - } - - return substr($value, -2) == "\0\0" ? substr($value, 0, -2) : $value; - } - - /** - * Returns hexadecimal string having high nibble first as binary data. - * - * @param string $value The input value. - * @return string - */ - public static function toHHex($value) - { - return pack("H*", $value); - } - - /** - * Returns binary data as hexadecimal string having high nibble first. - * - * @param string $value The binary data string. - * @return string - */ - public static function fromHHex($value) - { - list($hex) = unpack("H*0", $value); - return $hex; - } - - /** - * Returns hexadecimal string having low nibble first as binary data. - * - * @param string $value The input value. - * @return string - */ - public static function toLHex($value) - { - return pack("h*", $value); - } - - /** - * Returns binary data as hexadecimal string having low nibble first. - * - * @param string $value The binary data string. - * @return string - */ - public static function fromLHex($value) - { - list($hex) = unpack("h*0", $value); - return $hex; - } - - /** - * Returns big-endian ordered hexadecimal GUID string as little-endian ordered - * binary data string. - * - * @param string $value The input value. - * @return string - */ - public static function toGUID($value) - { - $string = ""; $C = preg_split("/-/", $value); - return pack - ("V1v2N2", hexdec($C[0]), hexdec($C[1]), hexdec($C[2]), - hexdec($C[3] . substr($C[4], 0, 4)), hexdec(substr($C[4], 4))); - } - - /** - * Returns the little-endian ordered binary data as big-endian ordered - * hexadecimal GUID string. - * - * @param string $value The binary data string. - * @return string - */ - public static function fromGUID($value) - { - $C = @unpack("V1V/v2v/N2N", $value); - list($hex) = @unpack("H*0", pack - ("NnnNN", $C["V"], $C["v1"], $C["v2"], $C["N1"], $C["N2"])); - - /* Fixes a bug in PHP versions earlier than Jan 25 2006 */ - if (implode("", unpack("H*", pack("H*", "a"))) == "a00") - $hex = substr($hex, 0, -1); - - return preg_replace - ("/^(.{8})(.{4})(.{4})(.{4})/", "\\1-\\2-\\3-\\4-", $hex); - } -} diff --git a/src/Twiddling.php b/src/Twiddling.php deleted file mode 100644 index f48ef0a..0000000 --- a/src/Twiddling.php +++ /dev/null @@ -1,233 +0,0 @@ - - * @author Sven Vollbehr - * @copyright Copyright (c) 2008 The PHP Reader Project Workgroup - * @license http://code.google.com/p/php-reader/wiki/License New BSD License - * @version $Rev$ - * @static - */ -final class Twiddling -{ - /** - * Default private constructor for a static class. - */ - private function __construct() {} - - /** - * Sets a bit at a given position in an integer. - * - * @param integer $integer The value to manipulate. - * @param integer $position The position of the bit to set. - * @param boolean $on Whether to enable or clear the bit. - * @return integer - */ - public static function setBit($integer, $position, $on) - { - return $on ? self::enableBit($integer, $position) : - self::clearBit($integer, $position); - } - - /** - * Enables a bit at a given position in an integer. - * - * @param integer $integer The value to manipulate. - * @param integer $position The position of the bit to enable. - * @return integer - */ - public static function enableBit($integer, $position) - { - return $integer | (1 << $position); - } - - /** - * Clears a bit at a given position in an integer. - * - * @param integer $integer The value to manipulate. - * @param integer $position The position of the bit to clear. - * @return integer - */ - public static function clearBit($integer, $position) - { - return $integer & ~(1 << $position); - } - - /** - * Toggles a bit at a given position in an integer. - * - * @param integer $integer The value to manipulate. - * @param integer $position The position of the bit to toggle. - * @return integer - */ - public static function toggleBit($integer, $position) - { - return $integer ^ (1 << $position); - } - - /** - * Tests a bit at a given position in an integer. - * - * @param integer $integer The value to test. - * @param integer $position The position of the bit to test. - * @return boolean - */ - public static function testBit($integer, $position) - { - return ($integer & (1 << $position)) != 0; - } - - /** - * Sets a given set of bits in an integer. - * - * @param integer $integer The value to manipulate. - * @param integer $bits The bits to set. - * @param boolean $on Whether to enable or clear the bits. - * @return integer - */ - public static function setBits($integer, $bits, $on) - { - return $on ? self::enableBits($integer, $bits) : - self::clearBits($integer, $bits); - } - - /** - * Enables a given set of bits in an integer. - * - * @param integer $integer The value to manipulate. - * @param integer $bits The bits to enable. - * @return integer - */ - public static function enableBits($integer, $bits) - { - return $integer | $bits; - } - - /** - * Clears a given set of bits in an integer. - * - * @param integer $integer The value to manipulate. - * @param integer $bits The bits to clear. - * @return integer - */ - public static function clearBits($integer, $bits) - { - return $integer & ~$bits; - } - - /** - * Toggles a given set of bits in an integer. - * - * @param integer $integer The value to manipulate. - * @param integer $bits The bits to toggle. - * @return integer - */ - public static function toggleBits($integer, $bits) - { - return $integer ^ $bits; - } - - /** - * Tests a given set of bits in an integer - * returning whether all bits are set. - * - * @param integer $integer The value to test. - * @param integer $bits The bits to test. - * @return boolean - */ - public static function testAllBits($integer, $bits) - { - return ($integer & $bits) == $bits; - } - - /** - * Tests a given set of bits in an integer - * returning whether any bits are set. - * - * @param integer $integer The value to test. - * @param integer $bits The bits to test. - * @return boolean - */ - public static function testAnyBits($integer, $bits) - { - return ($integer & $bits) != 0; - } - - /** - * Stores a value in a given range in an integer. - * - * @param integer $integer The value to store into. - * @param integer $start The position to store from. Must be <= $end. - * @param integer $end The position to store to. Must be >= $start. - * @param integer $value The value to store. - * @return integer - */ - public static function setValue($integer, $start, $end, $value) - { - return self::clearBits - ($integer, self::getMask($start, $end) << $start) | ($value << $start); - } - - /** - * Retrieves a value from a given range in an integer, inclusive. - * - * @param integer $integer The value to read from. - * @param integer $start The position to read from. Must be <= $end. - * @param integer $end The position to read to. Must be >= $start. - * @return integer - */ - public static function getValue($integer, $start, $end) - { - return ($integer & self::getMask($start, $end)) >> $start; - } - - /** - * Returns an integer with all bits set from start to end. - * - * @param integer $start The position to start setting bits from. Must - * be <= $end. - * @param integer $end The position to stop setting bits. Must be >= $start. - * @return integer - */ - public static function getMask($start, $end) - { - return ($tmp = (1 << $end)) + $tmp - (1 << $start); - } -} diff --git a/src/Zend/Bit/Twiddling.php b/src/Zend/Bit/Twiddling.php index ad88049..d34c4a1 100644 --- a/src/Zend/Bit/Twiddling.php +++ b/src/Zend/Bit/Twiddling.php @@ -1,223 +1,223 @@ - - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id$ - * @static - */ -final class Zend_Bit_Twiddling -{ - /** - * Default private constructor for a static class. - */ - private function __construct() - { - } - - /** - * Sets a bit at a given position in an integer. - * - * @param integer $integer The value to manipulate. - * @param integer $position The position of the bit to set. - * @param boolean $on Whether to enable or clear the bit. - * @return integer - */ - public static function setBit($integer, $position, $on) - { - return $on ? self::enableBit($integer, $position) : - self::clearBit($integer, $position); - } - - /** - * Enables a bit at a given position in an integer. - * - * @param integer $integer The value to manipulate. - * @param integer $position The position of the bit to enable. - * @return integer - */ - public static function enableBit($integer, $position) - { - return $integer | (1 << $position); - } - - /** - * Clears a bit at a given position in an integer. - * - * @param integer $integer The value to manipulate. - * @param integer $position The position of the bit to clear. - * @return integer - */ - public static function clearBit($integer, $position) - { - return $integer & ~(1 << $position); - } - - /** - * Toggles a bit at a given position in an integer. - * - * @param integer $integer The value to manipulate. - * @param integer $position The position of the bit to toggle. - * @return integer - */ - public static function toggleBit($integer, $position) - { - return $integer ^ (1 << $position); - } - - /** - * Tests a bit at a given position in an integer. - * - * @param integer $integer The value to test. - * @param integer $position The position of the bit to test. - * @return boolean - */ - public static function testBit($integer, $position) - { - return ($integer & (1 << $position)) != 0; - } - - /** - * Sets a given set of bits in an integer. - * - * @param integer $integer The value to manipulate. - * @param integer $bits The bits to set. - * @param boolean $on Whether to enable or clear the bits. - * @return integer - */ - public static function setBits($integer, $bits, $on) - { - return $on ? self::enableBits($integer, $bits) : - self::clearBits($integer, $bits); - } - - /** - * Enables a given set of bits in an integer. - * - * @param integer $integer The value to manipulate. - * @param integer $bits The bits to enable. - * @return integer - */ - public static function enableBits($integer, $bits) - { - return $integer | $bits; - } - - /** - * Clears a given set of bits in an integer. - * - * @param integer $integer The value to manipulate. - * @param integer $bits The bits to clear. - * @return integer - */ - public static function clearBits($integer, $bits) - { - return $integer & ~$bits; - } - - /** - * Toggles a given set of bits in an integer. - * - * @param integer $integer The value to manipulate. - * @param integer $bits The bits to toggle. - * @return integer - */ - public static function toggleBits($integer, $bits) - { - return $integer ^ $bits; - } - - /** - * Tests a given set of bits in an integer - * returning whether all bits are set. - * - * @param integer $integer The value to test. - * @param integer $bits The bits to test. - * @return boolean - */ - public static function testAllBits($integer, $bits) - { - return ($integer & $bits) == $bits; - } - - /** - * Tests a given set of bits in an integer - * returning whether any bits are set. - * - * @param integer $integer The value to test. - * @param integer $bits The bits to test. - * @return boolean - */ - public static function testAnyBits($integer, $bits) - { - return ($integer & $bits) != 0; - } - - /** - * Stores a value in a given range in an integer. - * - * @param integer $integer The value to store into. - * @param integer $start The position to store from. Must be <= $end. - * @param integer $end The position to store to. Must be >= $start. - * @param integer $value The value to store. - * @return integer - */ - public static function setValue($integer, $start, $end, $value) - { - return self::clearBits - ($integer, self::getMask - ($start, $end) << $start) | ($value << $start); - } - - /** - * Retrieves a value from a given range in an integer, inclusive. - * - * @param integer $integer The value to read from. - * @param integer $start The position to read from. Must be <= $end. - * @param integer $end The position to read to. Must be >= $start. - * @return integer - */ - public static function getValue($integer, $start, $end) - { - return ($integer & self::getMask($start, $end)) >> $start; - } - - /** - * Returns an integer with all bits set from start to end. - * - * @param integer $start The position to start setting bits from. Must - * be <= $end. - * @param integer $end The position to stop setting bits. Must - * be >= $start. - * @return integer - */ - public static function getMask($start, $end) - { - return ($tmp = (1 << $end)) + $tmp - (1 << $start); - } -} + + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + * @static + */ +final class Zend_Bit_Twiddling +{ + /** + * Default private constructor for a static class. + */ + private function __construct() + { + } + + /** + * Sets a bit at a given position in an integer. + * + * @param integer $integer The value to manipulate. + * @param integer $position The position of the bit to set. + * @param boolean $on Whether to enable or clear the bit. + * @return integer + */ + public static function setBit($integer, $position, $on) + { + return $on ? self::enableBit($integer, $position) : + self::clearBit($integer, $position); + } + + /** + * Enables a bit at a given position in an integer. + * + * @param integer $integer The value to manipulate. + * @param integer $position The position of the bit to enable. + * @return integer + */ + public static function enableBit($integer, $position) + { + return $integer | (1 << $position); + } + + /** + * Clears a bit at a given position in an integer. + * + * @param integer $integer The value to manipulate. + * @param integer $position The position of the bit to clear. + * @return integer + */ + public static function clearBit($integer, $position) + { + return $integer & ~(1 << $position); + } + + /** + * Toggles a bit at a given position in an integer. + * + * @param integer $integer The value to manipulate. + * @param integer $position The position of the bit to toggle. + * @return integer + */ + public static function toggleBit($integer, $position) + { + return $integer ^ (1 << $position); + } + + /** + * Tests a bit at a given position in an integer. + * + * @param integer $integer The value to test. + * @param integer $position The position of the bit to test. + * @return boolean + */ + public static function testBit($integer, $position) + { + return ($integer & (1 << $position)) != 0; + } + + /** + * Sets a given set of bits in an integer. + * + * @param integer $integer The value to manipulate. + * @param integer $bits The bits to set. + * @param boolean $on Whether to enable or clear the bits. + * @return integer + */ + public static function setBits($integer, $bits, $on) + { + return $on ? self::enableBits($integer, $bits) : + self::clearBits($integer, $bits); + } + + /** + * Enables a given set of bits in an integer. + * + * @param integer $integer The value to manipulate. + * @param integer $bits The bits to enable. + * @return integer + */ + public static function enableBits($integer, $bits) + { + return $integer | $bits; + } + + /** + * Clears a given set of bits in an integer. + * + * @param integer $integer The value to manipulate. + * @param integer $bits The bits to clear. + * @return integer + */ + public static function clearBits($integer, $bits) + { + return $integer & ~$bits; + } + + /** + * Toggles a given set of bits in an integer. + * + * @param integer $integer The value to manipulate. + * @param integer $bits The bits to toggle. + * @return integer + */ + public static function toggleBits($integer, $bits) + { + return $integer ^ $bits; + } + + /** + * Tests a given set of bits in an integer + * returning whether all bits are set. + * + * @param integer $integer The value to test. + * @param integer $bits The bits to test. + * @return boolean + */ + public static function testAllBits($integer, $bits) + { + return ($integer & $bits) == $bits; + } + + /** + * Tests a given set of bits in an integer + * returning whether any bits are set. + * + * @param integer $integer The value to test. + * @param integer $bits The bits to test. + * @return boolean + */ + public static function testAnyBits($integer, $bits) + { + return ($integer & $bits) != 0; + } + + /** + * Stores a value in a given range in an integer. + * + * @param integer $integer The value to store into. + * @param integer $start The position to store from. Must be <= $end. + * @param integer $end The position to store to. Must be >= $start. + * @param integer $value The value to store. + * @return integer + */ + public static function setValue($integer, $start, $end, $value) + { + return self::clearBits + ($integer, self::getMask + ($start, $end) << $start) | ($value << $start); + } + + /** + * Retrieves a value from a given range in an integer, inclusive. + * + * @param integer $integer The value to read from. + * @param integer $start The position to read from. Must be <= $end. + * @param integer $end The position to read to. Must be >= $start. + * @return integer + */ + public static function getValue($integer, $start, $end) + { + return ($integer & self::getMask($start, $end)) >> $start; + } + + /** + * Returns an integer with all bits set from start to end. + * + * @param integer $start The position to start setting bits from. Must + * be <= $end. + * @param integer $end The position to stop setting bits. Must + * be >= $start. + * @return integer + */ + public static function getMask($start, $end) + { + return ($tmp = (1 << $end)) + $tmp - (1 << $start); + } +} diff --git a/src/Zend/Media/Id3v2.php b/src/Zend/Media/Id3v2.php index bdec4a7..5cfa5a1 100644 --- a/src/Zend/Media/Id3v2.php +++ b/src/Zend/Media/Id3v2.php @@ -442,7 +442,7 @@ final class Zend_Media_Id3v2 extends Zend_Media_Id3_Object if ($filename === null && ($filename = $this->_filename) === null) { require_once 'Zend/Media/Id3/Exception.php'; throw new Zend_Media_Id3_Exception - ('No file given to write the tag to'); + ('No file given to write to'); } else if ($filename !== null && $filename instanceof Zend_Io_Writer) { require_once 'Zend/Io/Writer.php'; $this->_writeData($filename); diff --git a/src/Zend/Media/Iso14496.php b/src/Zend/Media/Iso14496.php index 141e731..290d744 100644 --- a/src/Zend/Media/Iso14496.php +++ b/src/Zend/Media/Iso14496.php @@ -301,14 +301,13 @@ final class Zend_Media_Iso14496 extends Zend_Media_Iso14496_Box } /** - * Writes the changes back to the original media file. If the class was - * constructed without a file name, one can be provided here as an argument. + * Writes the changes back to given media file. * * The write operation commits only changes made to the Movie Box. It * further changes the order of the Movie Box and Media Data Box in a way * compatible for progressive download from a web page. * - * All file offsets must be assumed to be invalid after the write operation. + * All box offsets must be assumed to be invalid after the write operation. * * @param string $filename The optional path to the file, use null to save * to the same file. @@ -318,7 +317,7 @@ final class Zend_Media_Iso14496 extends Zend_Media_Iso14496_Box if ($filename === null && ($filename = $this->_filename) === null) { require_once 'Zend/Media/Iso14496/Exception.php'; throw new Zend_Media_Iso14496_Exception - ('No file given to write the tag to'); + ('No file given to write to'); } else if ($filename !== null && $this->_filename !== null && realpath($filename) != realpath($this->_filename) && !copy($this->_filename, $filename)) { diff --git a/src/Zend/Media/Iso14496/Box.php b/src/Zend/Media/Iso14496/Box.php index 8582465..4a9efd5 100644 --- a/src/Zend/Media/Iso14496/Box.php +++ b/src/Zend/Media/Iso14496/Box.php @@ -56,10 +56,10 @@ class Zend_Media_Iso14496_Box private $_options; /** @var integer */ - private $_offset = -1; + private $_offset = false; /** @var integer */ - private $_size = -1; + private $_size = false; /** @var string */ private $_type; @@ -168,7 +168,8 @@ class Zend_Media_Iso14496_Box } /** - * Returns the file offset to box start, or -1 if the box was created on heap. + * Returns the file offset to box start, or false if the box was + * created on heap. * * @return integer */ @@ -189,8 +190,8 @@ class Zend_Media_Iso14496_Box /** * Returns the box size in bytes read from the file, including the size and - * type header, fields, and all contained boxes, or -1 if the box was - * created on heap. + * type header, fields, and all contained boxes, or false if the + * box was created on heap. * * @return integer */ diff --git a/src/Zend/Media/Mpeg/Abs.php b/src/Zend/Media/Mpeg/Abs.php new file mode 100644 index 0000000..c8600e5 --- /dev/null +++ b/src/Zend/Media/Mpeg/Abs.php @@ -0,0 +1,425 @@ + + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + * @todo Implement validation routines + */ +final class Zend_Media_Mpeg_Abs extends Zend_Media_Mpeg_Abs_Object +{ + /** @var integer */ + private $_bytes; + + /** @var Array */ + private $_frames = array(); + + /** @var Zend_Media_Mpeg_Abs_XingHeader */ + private $_xingHeader = null; + + /** @var Zend_Media_Mpeg_Abs_LameHeader */ + private $_lameHeader = null; + + /** @var Zend_Media_Mpeg_Abs_VbriHeader */ + private $_vbriHeader = null; + + /** @var integer */ + private $_cumulativeBitrate = 0; + + /** @var integer */ + private $_cumulativePlayDuration = 0; + + /** @var integer */ + private $_estimatedBitrate = 0; + + /** @var integer */ + private $_estimatedPlayDuration = 0; + + /** @var integer */ + private $_lastFrameOffset = false; + + /** + * Constructs the Zend_Media_Mpeg_ABS class with given file and options. + * + * The following options are currently recognized: + * o readmode -- Can be one of full or lazy and determines when the read + * of frames and their data happens. When in full mode the data is read + * automatically during the instantiation of the frame and all the + * frames are read during the instantiation of this class. While this + * allows faster validation and data fetching, it is unnecessary in + * terms of determining just the play duration of the file. Defaults to + * lazy. + * + * o estimatePrecision -- Only applicaple with lazy read mode to determine + * the precision of play duration estimate. This precision is equal to + * how many frames are read before fixing the average bitrate that is + * used to calculate the play duration estimate of the whole file. Each + * frame adds about 0.1-0.2ms to the processing of the file. Defaults to + * 1000. + * + * When in lazy data reading mode it is first checked whether a VBR header + * is found in a file. If so, the play duration is calculated based no its + * data and no further frames are read from the file. If no VBR header is + * found, frames up to estimatePrecision are read to calculate an average + * bitrate. + * + * Hence, only zero or estimatePrecision number of frames are + * read in lazy data reading mode. The rest of the frames are read + * automatically when directly referenced, ie the data is read when it is + * needed. + * + * @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. + * @param Array $options The options array. + */ + public function __construct($filename, $options = array()) + { + if ($filename instanceof Zend_Io_Reader) { + $this->_reader = &$filename; + } else { + 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/Mpeg/Exception.php'; + throw new Zend_Media_Mpeg_Exception($e->getMessage()); + } + } + $this->setOptions($options); + + $offset = $this->_reader->getOffset(); + $this->_bytes = $this->_reader->getSize(); + + /* Skip ID3v1 tag */ + $this->_reader->setOffset(-128); + if ($this->_reader->read(3) == 'TAG') { + $this->_bytes -= 128; + } + $this->_reader->setOffset($offset); + + /* Skip ID3v2 tag */ + if ($this->_reader->readString8(3) == 'ID3') { + require_once 'Zend/Media/Id3/Header.php'; + $header = new Zend_Media_Id3_Header($this->_reader); + $this->_reader->skip + ($header->getSize() + + ($header->hasFlag(Zend_Media_Id3_Header::FOOTER) ? 10 : 0)); + } else { + $this->_reader->setOffset($offset); + } + + /* Check for VBR headers */ + $offset = $this->_reader->getOffset(); + + $this->_frames[] = $firstFrame = + new Zend_Media_Mpeg_Abs_Frame($this->_reader, $options); + + $postoffset = $this->_reader->getOffset(); + + $this->_reader->setOffset + ($offset + 4 + self::$sidesizes + [$firstFrame->getFrequencyType()][$firstFrame->getMode()]); + if (($xing = $this->_reader->readString8(4)) == 'Xing' || + $xing == 'Info') { + require_once 'Zend/Media/Mpeg/Abs/XingHeader.php'; + $this->_xingHeader = + new Zend_Media_Mpeg_Abs_XingHeader($this->_reader, $options); + if ($this->_reader->readString8(4) == 'LAME') { + require_once 'Zend/Media/Mpeg/Abs/LameHeader.php'; + $this->_lameHeader = + new Zend_Media_Mpeg_Abs_LameHeader + ($this->_reader, $options); + } + + // A header frame is not counted as an audio frame + array_pop($this->_frames); + } + + $this->_reader->setOffset($offset + 4 + 32); + if ($this->_reader->readString8(4) == 'VBRI') { + require_once 'Zend/Media/Mpeg/Abs/VbriHeader.php'; + $this->_vbriHeader = + new Zend_Media_Mpeg_Abs_VbriHeader($this->_reader, $options); + + // A header frame is not counted as an audio frame + array_pop($this->_frames); + } + + $this->_reader->setOffset($postoffset); + + // Ensure we always have read at least one frame + if (empty($this->_frames)) { + $this->_readFrames(1); + } + + /* Read necessary frames */ + if ($this->getOption('readmode', 'lazy') == 'lazy') { + if (($header = $this->_xingHeader) !== null || + ($header = $this->_vbriHeader) !== null) { + $this->_estimatedPlayDuration = $header->getFrames() * + $firstFrame->getSamples() / + $firstFrame->getSamplingFrequency(); + if ($this->_lameHeader !== null) { + $this->_estimatedBitrate = $this->_lameHeader->getBitrate(); + if ($this->_estimatedBitrate == 255) { + $this->_estimatedBitrate = round + (($this->_lameHeader->getMusicLength()) / + (($header->getFrames() * + $firstFrame->getSamples()) / + $firstFrame->getSamplingFrequency()) / 1000 * 8); + } + } else { + $this->_estimatedBitrate = ($this->_bytes - $offset) / + $this->_estimatedPlayDuration / 1000 * 8; + } + } else { + $this->_readFrames($this->getOption('estimatePrecision', 1000)); + + $this->_estimatedBitrate = + $this->_cumulativeBitrate / count($this->_frames); + $this->_estimatedPlayDuration = + ($this->_bytes - $offset) / + ($this->_estimatedBitrate * 1000 / 8); + } + } else { + $this->_readFrames(); + + $this->_estimatedBitrate = + $this->_cumulativeBitrate / count($this->_frames); + $this->_estimatedPlayDuration = $this->_cumulativePlayDuration; + } + } + + /** + * Returns true if the audio bitstream contains the Xing VBR + * header, or false otherwise. + * + * @return boolean + */ + public function hasXingHeader() + { + return $this->_xingHeader === null; + } + + /** + * Returns the Xing VBR header, or null if not found in the audio + * bitstream. + * + * @return Zend_Media_Mpeg_Abs_XingHeader + */ + public function getXingHeader() + { + return $this->_xingHeader; + } + + /** + * Returns true if the audio bitstream contains the LAME VBR + * header, or false otherwise. + * + * @return boolean + */ + public function hasLameHeader() + { + return $this->_lameHeader === null; + } + + /** + * Returns the LAME VBR header, or null if not found in the audio + * bitstream. + * + * @return Zend_Media_Mpeg_Abs_LameHeader + */ + public function getLameHeader() + { + return $this->_lameHeader; + } + + /** + * Returns true if the audio bitstream contains the Fraunhofer IIS + * VBR header, or false otherwise. + * + * @return boolean + */ + public function hasVbriHeader() + { + return $this->_vbriHeader === null; + } + + /** + * Returns the Fraunhofer IIS VBR header, or null if not found in + * the audio bitstream. + * + * @return Zend_Media_Mpeg_Abs_VbriHeader + */ + public function getVbriHeader() + { + return $this->_vbriHeader; + } + + /** + * Returns the bitrate estimate. This value is either fetched from one of the + * headers or calculated based on the read frames. + * + * @return integer + */ + public function getBitrateEstimate() + { + return $this->_estimatedBitrate; + } + + /** + * For variable bitrate files this method returns the exact average bitrate of + * the whole file. + * + * @return integer + */ + public function getBitrate() + { + if ($this->getOption('readmode', 'lazy') == 'lazy') { + $this->_readFrames(); + } + return $this->_cumulativeBitrate / count($this->_frames); + } + + /** + * Returns the playtime estimate, in seconds. + * + * @return integer + */ + public function getLengthEstimate() + { + return $this->_estimatedPlayDuration; + } + + /** + * Returns the exact playtime in seconds. In lazy reading mode the frames + * are read from the file the first time you call this method to get the + * exact playtime of the file. + * + * @return integer + */ + public function getLength() + { + if ($this->getOption('readmode', 'lazy') == 'lazy') { + $this->_readFrames(); + } + return $this->_cumulativePlayDuration; + } + + /** + * Returns the playtime estimate as a string in the form of + * [hours:]minutes:seconds.milliseconds. + * + * @param integer $seconds The playtime in seconds. + * @return string + */ + public function getFormattedLengthEstimate() + { + return $this->formatTime($this->getLengthEstimate()); + } + + /** + * Returns the exact playtime given in seconds as a string in the form of + * [hours:]minutes:seconds.milliseconds. In lazy reading mode the frames are + * read from the file the first time you call this method to get the exact + * playtime of the file. + * + * @param integer $seconds The playtime in seconds. + * @return string + */ + public function getFormattedLength() + { + return $this->formatTime($this->getLength()); + } + + /** + * Returns all the frames of the audio bitstream as an array. In lazy + * reading mode the frames are read from the file the first time you call + * this method. + * + * @return Array + */ + public function getFrames() + { + if ($this->getOption('readmode', 'lazy') == 'lazy') { + $this->_readFrames(); + } + return $this->_frames; + } + + /** + * Reads frames up to given limit. If called subsequently the method + * continues after the last frame read in the last call, again to read up + * to the limit or just the rest of the frames. + * + * @param integer $limit The maximum number of frames read from the + * bitstream + */ + private function _readFrames($limit = null) + { + if ($this->_lastFrameOffset !== false) { + $this->_reader->setOffset($this->_lastFrameOffset); + } + + for ($i = 0; $this->_reader->getOffset() < $this->_bytes; $i++) { + $options = $this->getOptions(); + $frame = new Zend_Media_Mpeg_Abs_Frame($this->_reader, $options); + + $this->_cumulativePlayDuration += + (double)($frame->getLength() / + ($frame->getBitrate() * 1000 / 8)); + $this->_cumulativeBitrate += $frame->getBitrate(); + $this->_frames[] = $frame; + + if ($limit === null) { + $this->_lastFrameOffset = $this->_reader->getOffset(); + } + if ($limit !== null && ($i + 1) == $limit) { + $this->_lastFrameOffset = $this->_reader->getOffset(); + break; + } + } + } +} diff --git a/src/Zend/Media/Mpeg/Abs/Frame.php b/src/Zend/Media/Mpeg/Abs/Frame.php new file mode 100644 index 0000000..ea1d2fa --- /dev/null +++ b/src/Zend/Media/Mpeg/Abs/Frame.php @@ -0,0 +1,550 @@ + + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 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_Mpeg_Abs_Frame extends Zend_Media_Mpeg_Abs_Object +{ + /** + * The bitrate lookup table. The table has the following format. + * + * + * array ( + * SAMPLING_FREQUENCY_HIGH | SAMPLING_FREQUENCY_LOW => array ( + * LAYER_ONE | LAYER_TWO | LAYER_TREE => array ( ) + * ) + * ) + * + * + * @var Array + */ + private static $bitrates = array ( + self::SAMPLING_FREQUENCY_HIGH => array ( + self::LAYER_ONE => array ( + 1 => 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, + 416, 448 + ), + self::LAYER_TWO => array ( + 1 => 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, + 384 + ), + self::LAYER_THREE => array ( + 1 => 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, + 320 + ) + ), + self::SAMPLING_FREQUENCY_LOW => array ( + self::LAYER_ONE => array ( + 1 => 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, + 256 + ), + self::LAYER_TWO => array ( + 1 => 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 + ), + self::LAYER_THREE => array ( + 1 => 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 + ) + ) + ); + + /** + * Sample rate lookup table. The table has the following format. + * + * + * array ( + * LAYER_ONE | LAYER_TWO | LAYER_TREE => array ( ) + * ) + * + * + * @var Array + */ + private static $samplingFrequencies = array ( + self::VERSION_ONE => array (44100, 48000, 32000), + self::VERSION_TWO => array (22050, 24000, 16000), + self::VERSION_TWO_FIVE => array (11025, 12000, 8000) + ); + + /** + * Samples per frame lookup table. The table has the following format. + * + * + * array ( + * SAMPLING_FREQUENCY_HIGH | SAMPLING_FREQUENCY_LOW => array ( + * LAYER_ONE | LAYER_TWO | LAYER_TREE => + * ) + * ) + * + * + * @var Array + */ + private static $samples = array ( + self::SAMPLING_FREQUENCY_HIGH => array ( + self::LAYER_ONE => 384, + self::LAYER_TWO => 1152, + self::LAYER_THREE => 1152), + self::SAMPLING_FREQUENCY_LOW => array ( + self::LAYER_ONE => 384, + self::LAYER_TWO => 1152, + self::LAYER_THREE => 576)); + + /** + * Coefficient lookup table. The table has the following format. + * + * + * array ( + * SAMPLING_FREQUENCY_HIGH | SAMPLING_FREQUENCY_LOW => array ( + * LAYER_ONE | LAYER_TWO | LAYER_TREE => array ( ) + * ) + * ) + * + * + * @var Array + */ + private static $coefficients = array ( + self::SAMPLING_FREQUENCY_HIGH => array ( + self::LAYER_ONE => 12, self::LAYER_TWO => 144, + self::LAYER_THREE => 144 + ), + self::SAMPLING_FREQUENCY_LOW => array ( + self::LAYER_ONE => 12, self::LAYER_TWO => 144, + self::LAYER_THREE => 72 + ) + ); + + /** + * Slot size per layer lookup table. The table has the following format. + * + * + * array ( + * LAYER_ONE | LAYER_TWO | LAYER_TREE => + * ) + * + * + * @var Array + */ + private static $slotsizes = array ( + self::LAYER_ONE => 4, self::LAYER_TWO => 1, self::LAYER_THREE => 1 + ); + + /** @var integer */ + private $_offset; + + /** @var integer */ + private $_version; + + /** @var integer */ + private $_frequencyType; + + /** @var integer */ + private $_layer; + + /** @var integer */ + private $_redundancy; + + /** @var integer */ + private $_bitrate; + + /** @var integer */ + private $_samplingFrequency; + + /** @var integer */ + private $_padding; + + /** @var integer */ + private $_mode; + + /** @var integer */ + private $_modeExtension; + + /** @var integer */ + private $_copyright; + + /** @var integer */ + private $_original; + + /** @var integer */ + private $_emphasis; + + /** @var integer */ + private $_length; + + /** @var integer */ + private $_samples; + + /** @var integer */ + private $_crc = false; + + /** @var string */ + private $_data = false; + + /** + * Constructs the class with given parameters and reads object related data + * from the frame. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options Array of options. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_offset = $this->_reader->getOffset(); + + $header = $this->_reader->readUInt32BE(); + $this->_version = Zend_Bit_Twiddling::getValue($header, 19, 20); + $this->_frequencyType = Zend_Bit_Twiddling::testBit($header, 19); + $this->_layer = Zend_Bit_Twiddling::getValue($header, 17, 18); + $this->_redundancy = !Zend_Bit_Twiddling::testBit($header, 16); + $this->_bitrate = isset + (self::$bitrates[$this->_frequencyType][$this->_layer] + [$index = Zend_Bit_Twiddling::getValue($header, 12, 15)]) ? + self::$bitrates[$this->_frequencyType][$this->_layer][$index] : + false; + $this->_samplingFrequency = isset + (self::$samplingFrequencies[$this->_version] + [$index = Zend_Bit_Twiddling::getValue($header, 10, 11)]) ? + self::$samplingFrequencies[$this->_version][$index] : false; + $this->_padding = Zend_Bit_Twiddling::testBit($header, 9); + $this->_mode = Zend_Bit_Twiddling::getValue($header, 6, 7); + $this->_modeExtension = Zend_Bit_Twiddling::getValue($header, 4, 5); + $this->_copyright = Zend_Bit_Twiddling::testBit($header, 3); + $this->_original = Zend_Bit_Twiddling::testBit($header, 2); + $this->_emphasis = Zend_Bit_Twiddling::getValue($header, 0, 1); + + $this->_length = (int) + ((self::$coefficients[$this->_frequencyType][$this->_layer] * + ($this->_bitrate * 1000) / $this->_samplingFrequency) + + ($this->_padding ? 1 : 0)) * self::$slotsizes[$this->_layer]; + $this->_samples = self::$samples[$this->_frequencyType][$this->_layer]; + + if ($this->getOption('readmode', 'lazy') == 'full') { + $this->_readCrc(); + $this->_readData(); + } + $this->_reader->skip($this->_length - 4); + } + + /** + * Returns the version identifier of the algorithm. + * + * @see VERSION_ONE, VERSION_TWO, VERSION_TWO_FIVE + * @return integer + */ + public function getVersion() + { + return $this->_version; + } + + /** + * Returns the sampling frequency type. This can be one of the following + * values. + * + * o {@link SAMPLING_FREQUENCY_HIGH} -- Higher Sampling Frequency + * (Version 1) + * o {@link SAMPLING_FREQUENCY_LOW} -- Lower Sampling Frequency + * (Version 2 and 2.5) + * + * @see SAMPLING_FREQUENCY_LOW, SAMPLING_FREQUENCY_HIGH + * @return integer + */ + public function getFrequencyType() + { + return $this->_frequencyType; + } + + /** + * Returns the type of layer used. + * + * @see LAYER_ONE, LAYER_TWO, LAYER_THREE + * @return integer + */ + public function getLayer() + { + return $this->_layer; + } + + /** + * An alias to getRedundancy(). + * + * @see getRedundancy + * @return boolean + */ + public function hasRedundancy() + { + return $this->getRedundancy(); + } + + /** + * Returns boolean corresponding to whether redundancy has been added in the + * audio bitstream to facilitate error detection and concealment. Equals + * false if no redundancy has been added, true if + * redundancy has been added. + * + * @return boolean + */ + public function getRedundancy() + { + return $this->_redundancy; + } + + /** + * Returns the bitrate in kbps. The returned value indicates the total bitrate + * irrespective of the mode (stereo, joint_stereo, dual_channel, + * single_channel). + * + * @return integer + */ + public function getBitrate() + { + return $this->_bitrate; + } + + /** + * Returns the sampling frequency in Hz. + * + * @return integer + */ + public function getSamplingFrequency() + { + return $this->_samplingFrequency; + } + + /** + * An alias to getPadding(). + * + * @see getPadding + * @return boolean + */ + public function hasPadding() + { + return $this->getPadding(); + } + + /** + * Returns boolean corresponding the frame contains an additional slot to + * adjust the mean bitrate to the sampling frequency. Equals to + * true if padding has been added, false otherwise. + * + * Padding is only necessary with a sampling frequency of 44.1kHz. + * + * @return boolean + */ + public function getPadding() + { + return $this->_padding; + } + + /** + * Returns the mode. In Layer I and II the CHANNEL_JOINT_STEREO mode is + * intensity_stereo, in Layer III it is intensity_stereo and/or ms_stereo. + * + * @see CHANNEL_STEREO, CHANNEL_JOINT_STEREO, CHANNEL_DUAL_CHANNEL, + * CHANNEL_SINGLE_CHANNEL + * @return integer + */ + public function getMode() + { + return $this->_mode; + } + + /** + * Returns the mode extension used in CHANNEL_JOINT_STEREO mode. + * + * In Layer I and II the return type indicates which subbands are in + * intensity_stereo. All other subbands are coded in stereo. + * + * o {@link MODE_SUBBAND_4_TO_31} -- subbands 4-31 in + * intensity_stereo, bound==4 + * o {@link MODE_SUBBAND_8_TO_31} -- subbands 8-31 in + * intensity_stereo, bound==8 + * o {@link MODE_SUBBAND_12_TO_31} -- subbands 12-31 in + * intensity_stereo, bound==12 + * o {@link MODE_SUBBAND_16_TO_31} -- subbands 16-31 in + * intensity_stereo, bound==16 + * + * In Layer III they indicate which type of joint stereo coding method is + * applied. The frequency ranges over which the intensity_stereo and + * ms_stereo modes are applied are implicit in the algorithm. Please see + * {@link MODE_ISOFF_MSSOFF}, {@link MODE_ISON_MSSOFF}, + * {@link MODE_ISOFF_MSSON}, and {@link MODE_ISON_MSSON}. + * + * @return integer + */ + public function getModeExtension() + { + return $this->_modeExtension; + } + + /** + * An alias to getCopyright(). + * + * @see getCopyright + * @return boolean + */ + public function hasCopyright() + { + return $this->getCopyright(); + } + + /** + * Returns true if the coded bitstream is copyright protected, + * false otherwise. + * + * @return boolean + */ + public function getCopyright() + { + return $this->_copyright; + } + + /** + * An alias to getOriginal(). + * + * @see getOriginal + * @return boolean + */ + public function isOriginal() + { + return $this->getOriginal(); + } + + /** + * Returns whether the bitstream is original or home made. + * + * @return boolean + */ + public function getOriginal() + { + return $this->_original; + } + + /** + * Returns the type of de-emphasis that shall be used. The value is one of + * the following. + * + * o {@link EMPHASIS_NONE} -- No emphasis + * o {@link EMPHASIS_50_15} -- 50/15 microsec. emphasis + * o {@link EMPHASIS_CCIT_J17} -- CCITT J.17 + * + * @see EMPHASIS_NONE, EMPHASIS_50_15, EMPHASIS_CCIT_J17 + * @return integer + */ + public function getEmphasis() + { + return $this->_emphasis; + } + + /** + * Returns the length of the frame based on the current layer, bit rate, + * sampling frequency and padding, in bytes. + * + * @return integer + */ + public function getLength() + { + return $this->_length; + } + + /** + * Returns the number of samples contained in the frame. + * + * @return integer + */ + public function getSamples() + { + return $this->_samples; + } + + /** + * Returns the 16-bit CRC of the frame or false if not present. + * + * @return integer + */ + public function getCrc() + { + if ($this->getOption('readmode', 'lazy') == 'lazy' && + $this->hasRedundancy() && $this->_crc === false) { + $this->_readCrc(); + } + return $this->_crc; + } + + /** + * Reads the CRC data. + */ + private function _readCrc() + { + if ($this->hasRedundancy()) { + $offset = $this->_reader->getOffset(); + $this->_reader->setOffset($this->_offset + 4); + $this->_crc = $this->_reader->readUInt16BE(); + $this->_reader->setOffset($offset); + } + } + + /** + * Returns the audio data. + * + * @return string + */ + public function getData() + { + if ($this->getOption('readmode', 'lazy') == 'lazy' && + $this->_data === false) { + $this->_readData(); + } + return $this->_data; + } + + /** + * Reads the frame data. + */ + private function _readData() + { + $offset = $this->_reader->getOffset(); + $this->_reader->setOffset + ($this->_offset + 4 + ($this->hasRedundancy() ? 2 : 0)); + $this->_data = $this->_reader->read + ($this->getLength() - 4 - ($this->hasRedundancy() ? 2 : 0)); + $this->_reader->setOffset($offset); + } +} diff --git a/src/Zend/Media/Mpeg/Abs/LameHeader.php b/src/Zend/Media/Mpeg/Abs/LameHeader.php new file mode 100644 index 0000000..b075404 --- /dev/null +++ b/src/Zend/Media/Mpeg/Abs/LameHeader.php @@ -0,0 +1,528 @@ + + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ +class Zend_Media_Mpeg_Abs_LameHeader extends Zend_Media_Mpeg_Abs_Object +{ + /** @var integer */ + const VBR_METHOD_CONSTANT = 1; + + /** @var integer */ + const VBR_METHOD_ABR = 2; + + /** @var integer */ + const VBR_METHOD_RH = 3; + + /** @var integer */ + const VBR_METHOD_MTRH = 4; + + /** @var integer */ + const VBR_METHOD_MT = 5; + + /** @var integer */ + const ENCODING_FLAG_NSPSYTUNE = 1; + + /** @var integer */ + const ENCODING_FLAG_NSSAFEJOINT = 2; + + /** @var integer */ + const ENCODING_FLAG_NOGAP_CONTINUED = 4; + + /** @var integer */ + const ENCODING_FLAG_NOGAP_CONTINUATION = 8; + + /** @var integer */ + const MODE_MONO = 0; + + /** @var integer */ + const MODE_STEREO = 1; + + /** @var integer */ + const MODE_DUAL = 2; + + /** @var integer */ + const MODE_JOINT = 3; + + /** @var integer */ + const MODE_FORCE = 4; + + /** @var integer */ + const MODE_AUTO = 5; + + /** @var integer */ + const MODE_INTENSITY = 6; + + /** @var integer */ + const MODE_UNDEFINED = 7; + + /** @var integer */ + const SOURCE_FREQUENCY_32000_OR_LOWER = 0; + + /** @var integer */ + const SOURCE_FREQUENCY_44100 = 1; + + /** @var integer */ + const SOURCE_FREQUENCY_48000 = 2; + + /** @var integer */ + const SOURCE_FREQUENCY_HIGHER = 3; + + /** @var integer */ + const SURROUND_NONE = 0; + + /** @var integer */ + const SURROUND_DPL = 1; + + /** @var integer */ + const SURROUND_DPL2 = 2; + + /** @var integer */ + const SURROUND_AMBISONIC = 3; + + /** @var string */ + private $_version; + + /** @var integer */ + private $_revision; + + /** @var integer */ + private $_vbrMethod; + + /** @var integer */ + private $_lowpass; + + /** @var integer */ + private $_peakSignalAmplitude; + + /** @var integer */ + private $_radioReplayGain; + + /** @var integer */ + private $_audiophileReplayGain; + + /** @var integer */ + private $_encodingFlags; + + /** @var integer */ + private $_athType; + + /** @var integer */ + private $_bitrate; + + /** @var integer */ + private $_encoderDelaySamples; + + /** @var integer */ + private $_paddedSamples; + + /** @var integer */ + private $_sourceSampleFrequency; + + /** @var boolean */ + private $_unwiseSettingsUsed; + + /** @var integer */ + private $_mode; + + /** @var integer */ + private $_noiseShaping; + + /** @var integer */ + private $_mp3Gain; + + /** @var integer */ + private $_surroundInfo; + + /** @var integer */ + private $_presetUsed; + + /** @var integer */ + private $_musicLength; + + /** @var integer */ + private $_musicCrc; + + /** @var integer */ + private $_crc; + + /** + * Constructs the class with given parameters and reads object related data + * from the bitstream. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options Array of options. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_version = $this->_reader->readString8(5); + + $tmp = $this->_reader->readUInt8(); + $this->_revision = Zend_Bit_Twiddling::getValue($tmp, 4, 8); + $this->_vbrMethod = Zend_Bit_Twiddling::getValue($tmp, 0, 3); + + $this->_lowpass = $this->_reader->readUInt8() * 100; + + $this->_peakSignalAmplitude = $this->_reader->readUInt32BE(); + + $tmp = $this->_reader->readUInt16BE(); + $this->_radioReplayGain = array( + 'name' => Zend_Bit_Twiddling::getValue($tmp, 0, 2), + 'originator' => Zend_Bit_Twiddling::getValue($tmp, 3, 5), + 'absoluteGainAdjustment' => + Zend_Bit_Twiddling::getValue($tmp, 7, 15) / 10 + ); + + $tmp = $this->_reader->readUInt16BE(); + $this->_audiophileReplayGain = array( + 'name' => Zend_Bit_Twiddling::getValue($tmp, 0, 2), + 'originator' => Zend_Bit_Twiddling::getValue($tmp, 3, 5), + 'absoluteGainAdjustment' => + Zend_Bit_Twiddling::getValue($tmp, 7, 15) / 10 + ); + + $tmp = $this->_reader->readUInt8(); + $this->_encodingFlags = Zend_Bit_Twiddling::getValue($tmp, 4, 8); + $this->_athType = Zend_Bit_Twiddling::getValue($tmp, 0, 3); + + $this->_bitrate = $this->_reader->readUInt8(); + + $tmp = $this->_reader->readUInt32BE(); + // Encoder delay fields + $this->_encoderDelaySamples = + Zend_Bit_Twiddling::getValue($tmp, 20, 31); + $this->_paddedSamples = Zend_Bit_Twiddling::getValue($tmp, 8, 19); + // Misc field + $this->_sourceSampleFrequency = + Zend_Bit_Twiddling::getValue($tmp, 6, 7); + $this->_unwiseSettingsUsed = Zend_Bit_Twiddling::testBit($tmp, 5); + $this->_mode = Zend_Bit_Twiddling::getValue($tmp, 2, 4); + $this->_noiseShaping = Zend_Bit_Twiddling::getValue($tmp, 0, 1); + + $this->_mp3Gain = pow(2, $this->_reader->readInt8() / 4); + + $tmp = $this->_reader->readUInt16BE(); + $this->_surroundInfo = Zend_Bit_Twiddling::getValue($tmp, 11, 14); + $this->_presetUsed = Zend_Bit_Twiddling::getValue($tmp, 0, 10); + + $this->_musicLength = $this->_reader->readUInt32BE(); + + $this->_musicCrc = $this->_reader->readUInt16BE(); + $this->_crc = $this->_reader->readUInt16BE(); + } + + /** + * Returns the version string of the header. + * + * @return string + */ + public function getVersion() + { + return $this->_version; + } + + /** + * Returns the info tag revision. + * + * @return integer + */ + public function getRevision() + { + return $this->_revision; + } + + /** + * Returns the VBR method used for encoding. See the corresponding constants + * for possible return values. + * + * @return integer + */ + public function getVbrMethod() + { + return $this->_vbrMethod; + } + + /** + * Returns the lowpass filter value. + * + * @return integer + */ + public function getLowpass() + { + return $this->_lowpass; + } + + /** + * Returns the peak signal amplitude field of replay gain. The value of 1.0 + * (ie 100%) represents maximal signal amplitude storeable in decoding + * format. + * + * @return integer + */ + public function getPeakSignalAmplitude() + { + return $this->_peakSignalAmplitude; + } + + /** + * Returns the radio replay gain field of replay gain, required to make all + * tracks equal loudness, as an array that consists of the following keys. + * + * o name -- Specifies the name of the gain adjustment. Can be one of the + * following values: 0 = not set, 1 = radio, or 2 = audiophile. + * + * o originator -- Specifies the originator of the gain adjustment. Can be + * one of the following values: 0 = not set, 1 = set by artist, 2 = set + * by user, 3 = set by my model, 4 = set by simple RMS average. + * + * o absoluteGainAdjustment -- Speficies the absolute gain adjustment. + * + * @return Array + */ + public function getRadioReplayGain() + { + return $this->_radioReplayGain; + } + + /** + * Returns the audiophile replay gain field of replay gain, required to give + * ideal listening loudness, as an array that consists of the following + * keys. + * + * o name -- Specifies the name of the gain adjustment. Can be one of the + * following values: 0 = not set, 1 = radio, or 2 = audiophile. + * + * o originator -- Specifies the originator of the gain adjustment. Can be + * one of the following values: 0 = not set, 1 = set by artist, 2 = set + * by user, 3 = set by my model, 4 = set by simple RMS average. + * + * o absoluteGainAdjustment -- Speficies the absolute gain adjustment. + * + * @return Array + */ + public function getAudiophileReplayGain() + { + return $this->_audiophileReplayGain; + } + + /** + * Returns the encoding flags. See the corresponding flag constants for + * possible values. + * + * @return integer + */ + public function getEncodingFlags() + { + return $this->_encodingFlags; + } + + /** + * Returns the ATH type. + * + * @return integer + */ + public function getAthType() + { + return $this->_athType; + } + + /** + * Returns the bitrate for CBR encoded files and the minimal birate for + * VBR encoded file. The maximum value of this field is 255 even with higher + * actual bitrates. + * + * @return integer + */ + public function getBitrate() + { + return $this->_bitrate; + } + + /** + * Returns the encoder delay or number of samples added at start. + * + * @return integer + */ + public function getEncoderDelaySamples() + { + return $this->_encoderDelaySamples; + } + + /** + * Returns the number of padded samples to complete the last frame. + * + * @return integer + */ + public function getPaddedSamples() + { + return $this->_paddedSamples; + } + + /** + * Returns the source sample frequency. See corresponding constants for + * possible values. + * + * @return integer + */ + public function getSourceSampleFrequency() + { + return $this->_sourceSampleFrequency; + } + + /** + * An alias to getUnwiseSettingsUsed(). + * + * @see getUnwiseSettingsUsed + * @return boolean + */ + public function areUnwiseSettingsUsed() + { + return $this->getUnwiseSettingsUsed(); + } + + /** + * Returns whether unwise settings were used to encode the file. + * + * @return boolean + */ + public function getUnwiseSettingsUsed() + { + return $this->_unwiseSettingsUsed; + } + + /** + * Returns the stereo mode. See corresponding constants for possible values. + * + * @return integer + */ + public function getMode() + { + return $this->_mode; + } + + /** + * Returns the noise shaping. + * + * @return integer + */ + public function getNoiseShaping() + { + return $this->_noiseShaping; + } + + /** + * Returns the MP3 gain change. Any MP3 can be amplified in a lossless + * manner. If done so, this field can be used to log such transformation + * happened so that any given time it can be undone. + * + * @return integer + */ + public function getMp3Gain() + { + return $this->_mp3Gain; + } + + /** + * Returns the surround info. See corresponding contants for possible + * values. + * + * @return integer + */ + public function getSurroundInfo() + { + return $this->_surroundInfo; + } + + /** + * Returns the preset used in encoding. + * + * @return integer + */ + public function getPresetUsed() + { + return $this->_presetUsed; + } + + /** + * Returns the exact length in bytes of the MP3 file originally made by LAME + * excluded ID3 tag info at the end. + * + * The first byte it counts is the first byte of this LAME header and the + * last byte it counts is the last byte of the last MP3 frame containing + * music. The value should be equal to file length at the time of LAME + * encoding, except when using ID3 tags. + * + * @return integer + */ + public function getMusicLength() + { + return $this->_musicLength; + } + + /** + * Returns the CRC-16 of the complete MP3 music data as made originally by + * LAME. + * + * @return integer + */ + public function getMusicCrc() + { + return $this->_musicCrc; + } + + /** + * Returns the CRC-16 of the first 190 bytes of the header frame. + * + * @return integer + */ + public function getCrc() + { + return $this->_crc; + } +} diff --git a/src/Zend/Media/Mpeg/Abs/Object.php b/src/Zend/Media/Mpeg/Abs/Object.php new file mode 100644 index 0000000..b4550f8 --- /dev/null +++ b/src/Zend/Media/Mpeg/Abs/Object.php @@ -0,0 +1,150 @@ + + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 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_Mpeg_Abs_Object extends Zend_Media_Mpeg_Object +{ + /** @var integer */ + const VERSION_ONE = 3; + + /** @var integer */ + const VERSION_TWO = 2; + + /** @var integer */ + const VERSION_TWO_FIVE = 0; + + /** @var integer */ + const SAMPLING_FREQUENCY_LOW = 0; + + /** @var integer */ + const SAMPLING_FREQUENCY_HIGH = 1; + + /** @var integer */ + const LAYER_ONE = 3; + + /** @var integer */ + const LAYER_TWO = 2; + + /** @var integer */ + const LAYER_THREE = 1; + + /** @var integer */ + const CHANNEL_STEREO = 0; + + /** @var integer */ + const CHANNEL_JOINT_STEREO = 1; + + /** @var integer */ + const CHANNEL_DUAL_CHANNEL = 2; + + /** @var integer */ + const CHANNEL_SINGLE_CHANNEL = 3; + + /** @var integer */ + const MODE_SUBBAND_4_TO_31 = 0; + + /** @var integer */ + const MODE_SUBBAND_8_TO_31 = 1; + + /** @var integer */ + const MODE_SUBBAND_12_TO_31 = 2; + + /** @var integer */ + const MODE_SUBBAND_16_TO_31 = 3; + + /** @var integer */ + const MODE_ISOFF_MSSOFF = 0; + + /** @var integer */ + const MODE_ISON_MSSOFF = 1; + + /** @var integer */ + const MODE_ISOFF_MSSON = 2; + + /** @var integer */ + const MODE_ISON_MSSON = 3; + + /** @var integer */ + const EMPHASIS_NONE = 0; + + /** @var integer */ + const EMPHASIS_50_15 = 1; + + /** @var integer */ + const EMPHASIS_CCIT_J17 = 3; + + /** + * Layer III side information size lookup table. The table has the + * following format. + * + * + * array ( + * SAMPLING_FREQUENCY_HIGH | SAMPLING_FREQUENCY_LOW => array ( + * CHANNEL_STEREO | CHANNEL_JOINT_STEREO | CHANNEL_DUAL_CHANNEL | + * CHANNEL_SINGLE_CHANNEL => + * ) + * ) + * + * + * @var Array + */ + protected static $sidesizes = array( + self::SAMPLING_FREQUENCY_HIGH => array( + self::CHANNEL_STEREO => 32, + self::CHANNEL_JOINT_STEREO => 32, + self::CHANNEL_DUAL_CHANNEL => 32, + self::CHANNEL_SINGLE_CHANNEL => 17 + ), + self::SAMPLING_FREQUENCY_LOW => array( + self::CHANNEL_STEREO => 17, + self::CHANNEL_JOINT_STEREO => 17, + self::CHANNEL_DUAL_CHANNEL => 17, + self::CHANNEL_SINGLE_CHANNEL => 9 + ) + ); + + /** + * Constructs the class with given parameters. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + } +} diff --git a/src/Zend/Media/Mpeg/Abs/VbriHeader.php b/src/Zend/Media/Mpeg/Abs/VbriHeader.php new file mode 100644 index 0000000..e4927c0 --- /dev/null +++ b/src/Zend/Media/Mpeg/Abs/VbriHeader.php @@ -0,0 +1,176 @@ + + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ +class Zend_Media_Mpeg_Abs_VbriHeader extends Zend_Media_Mpeg_Abs_Object +{ + /** @var integer */ + private $_version; + + /** @var integer */ + private $_delay; + + /** @var integer */ + private $_qualityIndicator; + + /** @var integer */ + private $_bytes; + + /** @var integer */ + private $_frames; + + /** @var Array */ + private $_toc = array(); + + /** @var integer */ + private $_tocFramesPerEntry; + + /** @var integer */ + private $_length; + + /** + * Constructs the class with given parameters and reads object related data + * from the bitstream. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options Array of options. + */ + public function __construct($reader, &$options = array()) + { + $offset = $this->_reader->getOffset(); + $this->_version = $this->_reader->readUInt16BE(); + $this->_delay = $this->_reader->readUInt16BE(); + $this->_qualityIndicator = $this->_reader->readUInt16BE(); + $this->_bytes = $this->_reader->readUInt32BE(); + $this->_frames = $this->_reader->readUInt32BE(); + $tocEntries = $this->_reader->readUInt16BE(); + $tocEntryScale = $this->_reader->readUInt16BE(); + $tocEntrySize = $this->_reader->readUInt16BE(); + $this->_tocFramesPerEntry = $this->_reader->readUInt16BE(); + $this->_toc = array_merge(unpack(($tocEntrySize == 1) ? 'C*' : + ($tocEntrySize == 2) ? 'n*' : 'N*', + $this->_reader->read($tocCount * $tocEntrySize))); + foreach ($this->_toc as $key => $value) { + $this->_toc[$key] = $tocEntryScale * $value; + } + $this->_length = $this->_reader->getOffset() - $offset; + } + + /** + * Returns the header version. + * + * @return integer + */ + public function getVersion() + { + return $this->_version; + } + + /** + * Returns the delay. + * + * @return integer + */ + public function getDelay() + { + return $this->_delay; + } + + /** + * Returns the quality indicator. Return value varies from 0 (best quality) + * to 100 (worst quality). + * + * @return integer + */ + public function getQualityIndicator() + { + return $this->_qualityIndicator; + } + + /** + * Returns the number of bytes in the file. + * + * @return integer + */ + public function getBytes() + { + return $this->_bytes; + } + + /** + * Returns the number of frames in the file. + * + * @return integer + */ + public function getFrames() + { + return $this->_frames; + } + + /** + * Returns the table of contents array. + * + * @return Array + */ + public function getToc() + { + return $this->_toc; + } + + /** + * Returns the number of frames per TOC entry. + * + * @return integer + */ + public function getTocFramesPerEntry() + { + return $this->_tocFramesPerEntry; + } + + /** + * Returns the length of the header in bytes. + * + * @return integer + */ + public function getLength() + { + return $this->_length; + } +} diff --git a/src/Zend/Media/Mpeg/Abs/XingHeader.php b/src/Zend/Media/Mpeg/Abs/XingHeader.php new file mode 100644 index 0000000..8a886de --- /dev/null +++ b/src/Zend/Media/Mpeg/Abs/XingHeader.php @@ -0,0 +1,138 @@ + + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ +class Zend_Media_Mpeg_Abs_XingHeader extends Zend_Media_Mpeg_Abs_Object +{ + /** @var integer */ + private $_frames = false; + + /** @var integer */ + private $_bytes = false; + + /** @var Array */ + private $_toc = array(); + + /** @var integer */ + private $_qualityIndicator = false; + + /** + * Constructs the class with given parameters and reads object related data + * from the bitstream. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options Array of options. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $flags = $reader->readUInt32BE(); + + if (Zend_Bit_Twiddling::testAnyBits($flags, 0x1)) { + $this->_frames = $this->_reader->readUInt32BE(); + } + if (Zend_Bit_Twiddling::testAnyBits($flags, 0x2)) { + $this->_bytes = $this->_reader->readUInt32BE(); + } + if (Zend_Bit_Twiddling::testAnyBits($flags, 0x4)) { + $this->_toc = array_merge(unpack('C*', $this->_reader->read(100))); + } + if (Zend_Bit_Twiddling::testAnyBits($flags, 0x8)) { + $this->_qualityIndicator = $this->_reader->readUInt32BE(); + } + } + + /** + * Returns the number of frames in the file. + * + * @return integer + */ + public function getFrames() + { + return $this->_frames; + } + + /** + * Returns the number of bytes in the file. + * + * @return integer + */ + public function getBytes() + { + return $this->_bytes; + } + + /** + * Returns the table of contents array. The returned array has a fixed + * amount of 100 seek points to the file. + * + * @return Array + */ + public function getToc() + { + return $this->_toc; + } + + /** + * Returns the quality indicator. The indicator is from 0 (best quality) to + * 100 (worst quality). + * + * @return integer + */ + public function getQualityIndicator() + { + return $this->_qualityIndicator; + } + + /** + * Returns the length of the header in bytes. + * + * @return integer + */ + public function getLength() + { + return 4 + + ($this->_frames !== false ? 4 : 0) + + ($this->_bytes !== false ? 4 : 0) + + (empty($this->_toc) ? 0 : 100) + + ($this->_qualityIndicator !== false ? 4 : 0); + } +} diff --git a/src/Zend/Media/Mpeg/Exception.php b/src/Zend/Media/Mpeg/Exception.php new file mode 100644 index 0000000..77307d5 --- /dev/null +++ b/src/Zend/Media/Mpeg/Exception.php @@ -0,0 +1,37 @@ + + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ +class Zend_Media_Mpeg_Exception extends Exception +{ +} diff --git a/src/Zend/Media/Mpeg/Object.php b/src/Zend/Media/Mpeg/Object.php new file mode 100644 index 0000000..925c256 --- /dev/null +++ b/src/Zend/Media/Mpeg/Object.php @@ -0,0 +1,267 @@ + + * @copyright Copyright (c) 2005-2010 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_Mpeg_Object +{ + /** + * The reader object. + * + * @var Reader + */ + protected $_reader; + + /** + * The options array. + * + * @var Array + */ + private $_options; + + /** + * Constructs the class with given parameters. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + $this->_reader = $reader; + $this->_options = &$options; + } + + /** + * 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]); + } + + /** + * Finds and returns the next start code. Start codes are reserved bit + * patterns in the video file that do not otherwise occur in the video stream. + * + * All start codes are byte aligned and start with the following byte + * sequence: 0x00 0x00 0x01. + * + * @return integer + */ + protected final function nextStartCode() + { + $buffer = ' '; + for ($i = 0; $i < 4; $i++) { + $start = $this->_reader->getOffset(); + if (($buffer = substr($buffer, -4) . + $this->_reader->read(512)) === false) { + require_once 'Zend/Media/Mpeg/Exception.php'; + throw new Zend_Media_Mpeg_Exception('Invalid data'); + } + $limit = strlen($buffer); + $pos = 0; + while ($pos < $limit - 3) { + if (ord($buffer{$pos++}) == 0) { + list(, $int) = unpack('n*', substr($buffer, $pos, 2)); + if ($int == 1) { + if (($pos += 2) < $limit - 2) { + list(, $int) = + unpack('n*', substr($buffer, $pos, 2)); + if ($int == 0 && ord($buffer{$pos + 2}) == 1) { + continue; + } + } + $this->_reader->setOffset($start + $pos - 3); + return ord($buffer{$pos++}) & 0xff | 0x100; + } + } + } + $this->_reader->setOffset($start + $limit); + } + + /* No start code found within 2048 bytes, the maximum size of a pack */ + require_once 'Zend/Media/Mpeg/Exception.php'; + throw new Zend_Media_Mpeg_Exception('Invalid data'); + } + + /** + * Finds and returns the previous start code. Start codes are reserved bit + * patterns in the video file that do not otherwise occur in the video + * stream. + * + * All start codes are byte aligned and start with the following byte + * sequence: 0x00 0x00 0x01. + * + * @return integer + */ + protected final function prevStartCode() + { + $buffer = ' '; + $start; + $position = $this->_reader->getOffset(); + while ($position > 0) { + $start = 0; + $position = $position - 512; + if ($position < 0) { + require_once 'Zend/Media/Mpeg/Exception.php'; + throw new Zend_Media_Mpeg_Exception('Invalid data'); + } + $this->_reader->setOffset($position); + $buffer = $this->_reader->read(512) . substr($buffer, 0, 4); + $pos = 512 - 8; + while ($pos > 3) { + list(, $int) = unpack('n*', substr($buffer, $pos + 1, 2)); + if (ord($buffer{$pos}) == 0 && $int == 1) { + list(, $int) = unpack('n*', substr($buffer, $pos + 3, 2)); + if ($pos + 2 < 512 && $int == 0 && + ord($buffer{$pos + 5}) == 1) { + $pos--; + continue; + } + $this->_reader->setOffset($position + $pos); + return ord($buffer{$pos + 3}) & 0xff | 0x100; + } + $pos--; + } + $this->_reader->setOffset($position = $position + 3); + } + return 0; + } + + /** + * Formats given time in seconds into the form of + * [hours:]minutes:seconds.milliseconds. + * + * @param integer $seconds The time to format, in seconds + * @return string + */ + protected final function formatTime($seconds) + { + $milliseconds = round(($seconds - floor($seconds)) * 1000); + $seconds = floor($seconds); + $minutes = floor($seconds / 60); + $hours = floor($minutes / 60); + return + ($minutes > 0 ? + ($hours > 0 ? $hours . ':' . + str_pad($minutes % 60, 2, '0', STR_PAD_LEFT) : $minutes % 60) . + ':' . + str_pad($seconds % 60, 2, '0', STR_PAD_LEFT) : $seconds % 60) . + '.' . + str_pad($milliseconds, 3, '0', STR_PAD_LEFT); + } + + /** + * 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/Mpeg/Exception.php'; + throw new Zend_Media_Mpeg_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/Mpeg/Exception.php'; + throw new Zend_Media_Mpeg_Exception('Unknown field: ' . $name); + } + } +} diff --git a/src/Zend/Media/Mpeg/Ps.php b/src/Zend/Media/Mpeg/Ps.php new file mode 100644 index 0000000..5e4e870 --- /dev/null +++ b/src/Zend/Media/Mpeg/Ps.php @@ -0,0 +1,152 @@ + + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + * @todo Full implementation + */ +final class Zend_Media_Mpeg_Ps extends Zend_Media_Mpeg_Object +{ + /** @var integer */ + private $_length; + + /** + * Constructs the class with given file and options. + * + * @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. + * @param Array $options The options array. + */ + public function __construct($filename, $options = array()) + { + if ($filename instanceof Zend_Io_Reader) { + $this->_reader = &$filename; + } else { + 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/Mpeg/Exception.php'; + throw new Zend_Media_Mpeg_Exception($e->getMessage()); + } + } + $this->setOptions($options); + + $startCode = 0; + $startTime = 0; + $pictureCount = 0; + $pictureRate = 0; + $rates = array ( 0, 23.976, 24, 25, 29.97, 30, 50, 59.94, 60 ); + $foundSeqHdr = false; + $foundGOP = false; + + do { + do { + $startCode = $this->nextStartCode(); + echo "STARTCODE: $startCode\n"; + } while ($startCode != 0x1b3 && $startCode != 0x1b8); + + if ($startCode == 0x1b3 /* sequence_header_code */ && + $pictureRate == 0) { + $i1 = $this->_reader->readUInt32BE(); + $i2 = $this->_reader->readUInt32BE(); + if (!Zend_Bit_Twiddling::testAllBits($i2, 0x2000)) { + throw new RuntimeException('Invalid mark'); + } + $pictureRate = $rates[Zend_Bit_Twiddling::getValue($i1, 4, 8)]; + $foundSeqHdr = true; + } + if ($startCode == 0x1b8 /* group_start_code */) { + $tmp = $this->_reader->readUInt32BE(); + $startTime = + (($tmp >> 26) & 0x1f) * 60 * 60 * 1000 /* hours */ + + (($tmp >> 20) & 0x3f) * 60 * 1000 /* minutes */ + + (($tmp >> 13) & 0x3f) * 1000 /* seconds */ + + (int)(1 / $pictureRate * (($tmp >> 7) & 0x3f) * 1000); + $foundGOP = true; + } + } while (!$foundSeqHdr || !$foundGOP); + + $this->_reader->setOffset($this->_reader->getSize()); + + do { + if (($startCode = $this->prevStartCode()) == 0x100) { + $pictureCount++; + } + } while ($startCode != 0x1b8); + + $this->_reader->skip(4); + $tmp = $this->_reader->readUInt32BE(); + $this->_length = + (((($tmp >> 26) & 0x1f) * 60 * 60 * 1000 /* hours */ + + (($tmp >> 20) & 0x3f) * 60 * 1000 /* minutes */ + + (($tmp >> 13) & 0x3f) * 1000 /* seconds */ + + (int)(1 / $pictureRate * (($tmp >> 7) & 0x3f) * 1000)) - + $startTime + + (int)(1 / $pictureRate * $pictureCount * 1000)) / 1000; + } + + /** + * Returns the exact playtime in seconds. + * + * @return integer + */ + public function getLength() + { + return $this->_length; + } + + /** + * Returns the exact playtime given in seconds as a string in the form of + * [hours:]minutes:seconds.milliseconds. + * + * @param integer $seconds The playtime in seconds. + * @return string + */ + public function getFormattedLength() + { + return $this->formatTime($this->getLength()); + } +}