/** * 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 <var>estimatePrecision</var> 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 { try { $this->_reader = new Zend_Io_FileReader($filename); } catch (Zend_Io_Exception $e) { $this->_reader = null; 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 tags (some files errorneusly contain multiple tags) */ while ($this->_reader->readString8(3) == 'ID3') { $header = new Zend_Media_Id3_Header($this->_reader); $this->_reader->skip($header->getSize() + ($header->hasFlag(Zend_Media_Id3_Header::FOOTER) ? 10 : 0)); $offset = $this->_reader->getOffset(); } $this->_reader->setOffset($offset); /* Check whether the ABS is contained within a RIFF chunk */ $offset = $this->_reader->getOffset(); if ($this->_reader->readString8(4) == 'RIFF') { $riffSize = $this->_reader->readUInt32LE(); $riffType = $this->_reader->read(4); // WAVE while ($this->_reader->getOffset() < $offset + 8 + $riffSize - 1) { $chunkId = $this->_reader->read(4); $chunkSize = $this->_reader->readUInt32LE(); if ($chunkId == 'fmt ') { if ($this->_reader->readInt16LE() != 85) { // 85: MPEG-1 Layer 3 Codec throw new Zend_Media_Mpeg_Exception('File does not contain a valid MPEG Audio Bit Stream (Contains RIFF with no MPEG ABS)'); } else { $this->_reader->skip($chunkSize - 2); } } else { if ($chunkId == 'data') { $offset = $this->_reader->getOffset(); break; } else { $this->_reader->skip($chunkSize); } } } } else { $this->_reader->setOffset($offset); } /* Check for VBR headers */ $this->_frames[] = $firstFrame = new Zend_Media_Mpeg_Abs_Frame($this->_reader, $options); $offset = $this->_reader->getOffset(); $this->_reader->setOffset($firstFrame->getOffset() + 4 + self::$sidesizes[$firstFrame->getFrequencyType()][$firstFrame->getMode()]); if (($xing = $this->_reader->readString8(4)) == 'Xing' || $xing == 'Info') { $this->_xingHeader = new Zend_Media_Mpeg_Abs_XingHeader($this->_reader, $options); if ($this->_reader->readString8(4) == 'LAME') { $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($firstFrame->getOffset() + 4 + 32); if ($this->_reader->readString8(4) == 'VBRI') { $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($offset); // 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) && $header->getFrames() != 0) { $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 - $firstFrame->getOffset()) / $this->_estimatedPlayDuration / 1000 * 8; } } else { $this->_readFrames($this->getOption('estimatePrecision', 1000)); $this->_estimatedBitrate = $this->_cumulativeBitrate / count($this->_frames); $this->_estimatedPlayDuration = ($this->_bytes - $firstFrame->getOffset()) / ($this->_estimatedBitrate * 1000 / 8); } } else { $this->_readFrames(); $this->_estimatedBitrate = $this->_cumulativeBitrate / count($this->_frames); $this->_estimatedPlayDuration = $this->_cumulativePlayDuration; } }
/** * 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 <var>estimatePrecision</var> 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; } }