File_Ogg
[ class tree: File_Ogg ] [ index: File_Ogg ] [ all elements ]

Source for file Vorbis.php

Documentation is available at Vorbis.php

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. // +--------------------------------------------------------------------------------+
  4. // | File_Ogg PEAR Package for Accessing Ogg Bitstreams                             |
  5. // | Copyright (c) 2005 David Grant <david@grant.org.uk>                            |
  6. // +--------------------------------------------------------------------------------+
  7. // | This library is free software; you can redistribute it and/or                  |
  8. // | modify it under the terms of the GNU Lesser General Public                     |
  9. // | License as published by the Free Software Foundation; either                   |
  10. // | version 2.1 of the License, or (at your option) any later version.             |
  11. // |                                                                                |
  12. // | This library is distributed in the hope that it will be useful,                |
  13. // | but WITHOUT ANY WARRANTY; without even the implied warranty of                 |
  14. // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU              |
  15. // | Lesser General Public License for more details.                                |
  16. // |                                                                                |
  17. // | You should have received a copy of the GNU Lesser General Public               |
  18. // | License along with this library; if not, write to the Free Software            |
  19. // | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA     |
  20. // +--------------------------------------------------------------------------------+
  21.  
  22. require_once('File/Ogg/Bitstream.php');
  23.  
  24. /**
  25.  *  Check number for the first header in a Vorbis stream.
  26.  */
  27. define("OGG_VORBIS_IDENTIFICATION_HEADER",  1);
  28. /**
  29.  *  Check number for the second header in a Vorbis stream.
  30.  */
  31. define("OGG_VORBIS_COMMENTS_HEADER",        3);
  32. /**
  33.  *  Check number for the third header in a Vorbis stream.
  34.  */
  35. define("OGG_VORBIS_SETUP_HEADER",           5);
  36. /**
  37.  *  Error thrown if the stream appears to be corrupted.
  38.  */
  39. define("OGG_VORBIS_ERROR_UNDECODABLE",      1);
  40. /**
  41.  *  Error thrown if the user attempts to extract a comment using a comment key
  42.  *  that does not exist.
  43.  */
  44. define("OGG_VORBIS_ERROR_INVALID_COMMENT",  2);
  45.  
  46. /**
  47.  * Extract the contents of a Vorbis logical stream.
  48.  *
  49.  * This class provides an interface to a Vorbis logical stream found within
  50.  * a Ogg stream.  A variety of information may be extracted, including comment
  51.  * tags, running time, and bitrate.  For more information, please see the following
  52.  * links.
  53.  *
  54.  * @link    http://www.xiph.org/ogg/vorbis/docs.html
  55.  * @link    http://www.xiph.org/ogg/vorbis/doc/vorbis-ogg.html
  56.  *
  57.  * @author         David Grant <david@grant.org.uk>
  58.  * @category    File
  59.  * @copyright     David Grant <david@grant.org.uk>
  60.  * @license        http://www.gnu.org/copyleft/lesser.html GNU LGPL
  61.  * @link        http://pear.php.net/package/File_Ogg
  62.  * @package     File_Ogg
  63.  * @version     CVS: $Id: Vorbis.php,v 1.6 2005/11/03 14:14:53 djg Exp $
  64.  */
  65. {
  66.     /**
  67.      * Array to hold each of the comments.
  68.      *
  69.      * @var     array 
  70.      * @access  private
  71.      */
  72.     var $_comments = array();
  73.  
  74.     /**
  75.      * Version of vorbis specification used.
  76.      *
  77.      * @var     int 
  78.      * @access  private
  79.      */
  80.     var $_version;
  81.  
  82.     /**
  83.      * Number of channels in the vorbis stream.
  84.      *
  85.      * @var     int 
  86.      * @access  private
  87.      */
  88.     var $_channels;
  89.  
  90.     /**
  91.      * Number of samples per second in the vorbis stream.
  92.      *
  93.      * @var     int 
  94.      * @access  private
  95.      */
  96.     var $_sampleRate;
  97.  
  98.     /**
  99.      * Minimum bitrate for the vorbis stream.
  100.      *
  101.      * @var     int 
  102.      * @access  private
  103.      */
  104.     var $_minBitrate;
  105.  
  106.     /**
  107.      * Maximum bitrate for the vorbis stream.
  108.      *
  109.      * @var     int 
  110.      * @access  private
  111.      */
  112.     var $_maxBitrate;
  113.  
  114.     /**
  115.      * Nominal bitrate for the vorbis stream.
  116.      *
  117.      * @var     int 
  118.      * @access  private
  119.      */
  120.     var $_nomBitrate;
  121.  
  122.     /**
  123.      * Average bitrate for the vorbis stream.
  124.      *
  125.      * @var     float 
  126.      * @access  private
  127.      */
  128.     var $_avgBitrate;
  129.  
  130.     /**
  131.      * Vendor string for the vorbis stream.
  132.      *
  133.      * @var     string 
  134.      * @access  private
  135.      */
  136.     var $_vendor;
  137.  
  138.     /**
  139.      * The length of this stream in seconds.
  140.      *
  141.      * @var     int 
  142.      * @access  private
  143.      */
  144.     var $_streamLength;
  145.  
  146.     /**
  147.      * The number of bits used in this stream.
  148.      *
  149.      * @var     int 
  150.      * @access  private
  151.      */
  152.     var $_streamSize;
  153.  
  154.     /**
  155.      * Constructor for accessing a Vorbis logical stream.
  156.      *
  157.      * This method is the constructor for the native-PHP interface to a Vorbis logical
  158.      * stream, embedded within an Ogg physical stream.
  159.      *
  160.      * @param   int     $streamSerial   Serial number of the logical stream.
  161.      * @param   array   $streamData     Data for the requested logical stream.
  162.      * @param   string  $filePath       Location of a file on the filesystem.
  163.      * @param   pointer $filePointer    File pointer for the current physical stream.
  164.      * @access  public
  165.      */
  166.     function File_Ogg_Vorbis($streamSerial$streamData$filePointer)
  167.     {
  168.         $this->_streamSerial     $streamSerial;
  169.         $this->_streamList         $streamData;
  170.         $this->_filePointer     $filePointer;
  171.         $this->_parseIdentificationHeader();
  172.         $this->_parseCommentsHeader();
  173.         $this->_streamLength     round($streamData['stream_page'][count($streamData['stream_page']- 1]['abs_granual_pos'$this->_sampleRate);
  174.         // This gives an accuracy of approximately 99.7% to the streamsize of ogginfo.
  175.         for ($i = 0; $i count($streamData['stream_page']); ++$i)
  176.             $this->_streamSize += $streamData['stream_page'][$i]['data_length'];
  177.  
  178.         $this->_avgBitrate         round(($this->_streamSize * 8$this->_streamLength);
  179.     }
  180.     
  181.     /**
  182.      * Parse the identification header (the first of three headers) in a Vorbis stream.
  183.      *
  184.      * This function parses the identification header.  The identification header
  185.      * contains simple audio characteristics, such as sample rate and number of
  186.      * channels.  There are a number of error-checking provisions laid down in the Vorbis
  187.      * specification to ensure the stream is pure.
  188.      *
  189.      * @access  private
  190.       
  191.      */
  192.     function _parseIdentificationHeader()
  193.     {
  194.         fseek($this->_filePointer$this->_streamList['stream_page'][0]['body_offset']SEEK_SET);
  195.         // Check if this is the correct header.
  196.         $packet unpack("Cdata"fread($this->_filePointer1));
  197.         if ($packet['data'!= OGG_VORBIS_IDENTIFICATION_HEADER)
  198.             PEAR::raiseError("Stream Undecodable"OGG_VORBIS_ERROR_UNDECODABLE);
  199.  
  200.         // The following six characters should be the characters 'v', 'o', 'r', 'b', 'i', 's'.
  201.         if (fread($this->_filePointer6!= "vorbis")
  202.             PEAR::raiseError("Stream is undecodable due to a malformed header."OGG_VORBIS_ERROR_UNDECODABLE);
  203.  
  204.         $version unpack("Vdata"fread($this->_filePointer4));
  205.  
  206.         // The Vorbis stream version must be 0.
  207.         if ($version['data'== 0)
  208.             $this->_version $version['data'];
  209.         else
  210.             PEAR::raiseError("Stream is undecodable due to an invalid vorbis stream version."OGG_VORBIS_ERROR_UNDECODABLE);
  211.  
  212.         // The number of channels is stored in an 8 bit unsigned integer,
  213.         // with a maximum of 255 channels.
  214.         $channels unpack("Cdata"fread($this->_filePointer1));
  215.         // The number of channels MUST be greater than 0.
  216.         if ($channels['data'== 0)
  217.             PEAR::raiseError("Stream is undecodable due to zero channels."OGG_VORBIS_ERROR_UNDECODABLE);
  218.         else
  219.             $this->_channels $channels['data'];
  220.  
  221.         // The sample rate is a 32 bit unsigned integer.
  222.         $sample_rate unpack("Vdata"fread($this->_filePointer4));
  223.         // The sample rate MUST be greater than 0.
  224.         if ($sample_rate['data'== 0)
  225.             PEAR::raiseError("Stream is undecodable due to a zero sample rate."OGG_VORBIS_ERROR_UNDECODABLE);
  226.         else
  227.             $this->_sampleRate $sample_rate['data'];
  228.  
  229.         // Extract the various bitrates from the vorbis stream.
  230.         $bitrate['max']     unpack("Vdata"fread($this->_filePointer4));
  231.         $this->_maxBitrate     $bitrate['max']['data'];
  232.         $bitrate['nom']     unpack("Vdata"fread($this->_filePointer4));
  233.         $this->_nomBitrate     $bitrate['nom']['data'];
  234.         $bitrate['min']     unpack("Vdata"fread($this->_filePointer4));
  235.         $this->_minBitrate     $bitrate['min']['data'];
  236.  
  237.         $blocksizes unpack("Cdata"fread($this->_filePointer1));
  238.  
  239.         // Powers of two between 6 and 13 inclusive.
  240.         $valid_block_sizes = array(641282565121024204840968192);
  241.  
  242.         // Extract bits 1 to 4 from the character data.
  243.         // blocksize_0 MUST be a valid blocksize.
  244.         $blocksize_0 pow(2($blocksizes['data'0x0F));
  245.         if (FALSE == in_array($blocksize_0$valid_block_sizes))
  246.             PEAR::raiseError("Stream is undecodable because blocksize_0 is not a valid size."OGG_VORBIS_ERROR_UNDECODABLE);
  247.  
  248.         // Extract bits 5 to 8 from the character data.
  249.         // blocksize_1 MUST be a valid blocksize.
  250.         $blocksize_1 pow(2($blocksizes['data'0xF0>> 4);
  251.         if (FALSE == in_array($blocksize_1$valid_block_sizes))
  252.             PEAR::raiseError("Stream is undecodable because blocksize_1 is not a valid size."OGG_VORBIS_ERROR_UNDECODABLE);
  253.  
  254.         // blocksize 0 MUST be less than or equal to blocksize 1.
  255.         if ($blocksize_0 $blocksize_1)
  256.             PEAR::raiseError("Stream is undecodable because blocksize_0 is not less than or equal to blocksize_1."OGG_VORBIS_ERROR_UNDECODABLE);
  257.  
  258.         // The framing bit MUST be set to mark the end of the identification header.
  259.         $framing_bit unpack("Cdata"fread($this->_filePointer1));
  260.         if ($framing_bit['data'== 0)
  261.             PEAR::raiseError("Stream in undecodable because the framing bit is not non-zero."OGG_VORBIS_ERROR_UNDECODABLE);
  262.     }
  263.     
  264.     /**
  265.      * Parse the comments header (the second of three headers) of a Vorbis stream.
  266.      *
  267.      * This function parses the comments header.  The comments header contains a series of
  268.      * UTF-8 comments related to the audio encoded in the stream.  This header also contains
  269.      * a string to identify the encoding software.  More details on the comments header can
  270.      * be found at the following location.
  271.      *
  272.      * @link    http://www.xiph.org/ogg/vorbis/doc/v-comment.html
  273.      * @access  private
  274.      */
  275.     function _parseCommentsHeader()
  276.     {
  277.         fseek($this->_filePointer$this->_streamList['stream_page'][1]['body_offset']SEEK_SET);
  278.         // Check if this is the correct header.
  279.         $packet unpack("Cdata"fread($this->_filePointer1));
  280.         if ($packet['data'!= OGG_VORBIS_COMMENTS_HEADER{
  281.             PEAR::raiseError("Stream Undecodable"OGG_VORBIS_ERROR_UNDECODABLE);
  282.             exit ("ERROR");
  283.         }
  284.  
  285.         // Check that this stream is a Vorbis stream.
  286.         if (fread($this->_filePointer6!= "vorbis")
  287.             PEAR::raiseError("Stream Undecodable"OGG_VORBIS_ERROR_UNDECODABLE);
  288.  
  289.         // Decode the vendor string length.
  290.         $vendor_len     unpack("Vdata"fread($this->_filePointer4));
  291.         $this->_vendor     fread($this->_filePointer$vendor_len['data']);
  292.         // Decode the size of the comments list.
  293.         $comment_list_length unpack("Vdata"fread($this->_filePointer4));
  294.         for ($i = 0; $i $comment_list_length['data']$i++{
  295.             $comment_length unpack("Vdata"fread($this->_filePointer4));
  296.             // Comments are in the format 'ARTIST=Super Furry Animals', so split it on the equals character.
  297.             // NOTE: Equals characters are strictly prohibited in either the COMMENT or DATA parts.
  298.             $comment         explode("="fread($this->_filePointer$comment_length['data']));
  299.             $comment_title     = (string) $comment[0];
  300.             $comment_value     = (string) utf8_decode($comment[1]);
  301.  
  302.             // Check if the comment type (e.g. ARTIST) already exists.  If it does,
  303.             // take the new value, and the existing value (or array) and insert it
  304.             // into a new array.  This is important, since each comment type may have
  305.             // multiple instances (e.g. ARTIST for a collaboration) and we should not
  306.             // overwrite the previous value.
  307.             if (isset($this->_comments[$comment_title])) {
  308.                 if (is_array($this->_comments[$comment_title]))
  309.                     $this->_comments[$comment_title][$comment_value;
  310.                 else
  311.                     $this->_comments[$comment_title= array($this->_comments[$comment_title]$comment_value);
  312.             else
  313.                 $this->_comments[$comment_title$comment_value;
  314.         }
  315.  
  316.         // The framing bit MUST be set to mark the end of the comments header.
  317.         $framing_bit unpack("Cdata"fread($this->_filePointer1));
  318.         if ($framing_bit['data'!= 1)
  319.             PEAR::raiseError("Stream Undecodable"OGG_VORBIS_ERROR_UNDECODABLE);
  320.     }
  321.     
  322.     /**
  323.      * Provides a list of the comments extracted from the Vorbis stream.
  324.      *
  325.      * It is recommended that the user fully inspect the array returned by this function
  326.      * rather than blindly requesting a comment in false belief that it will always
  327.      * be present.  Whilst the Vorbis specification dictates a number of popular
  328.      * comments (e.g. TITLE, ARTIST, etc.) for use in Vorbis streams, they are not
  329.      * guaranteed to appear.
  330.      *
  331.      * @return  array 
  332.      * @access  public
  333.      */
  334.     function getCommentList()
  335.     {
  336.           return (array_keys($this->_comments));
  337.     }
  338.  
  339.     /**
  340.      * Provides an interface to the numerous comments located with a Vorbis stream.
  341.      *
  342.      * A Vorbis stream may contain one or more instances of each comment, so the user
  343.      * should check the variable type before printing out the result of this method.
  344.      * The situation in which multiple instances of a comment occurring are not as
  345.      * rare as one might think, since they are conceivable at least for ARTIST comments
  346.      * in the situation where a track is a duet.
  347.      *
  348.      * @param   string  $commentTitle   Comment title to search for, e.g. TITLE.
  349.      * @return  string 
  350.      * @access  public
  351.      */
  352.     function getComment($commentTitle)
  353.     {
  354.         if (isset($this->_comments[$commentTitle])) {
  355.             if (is_array($this->_comments[$commentTitle]))
  356.                 return (implode(", "$this->_comments[$commentTitle]));
  357.             else
  358.                 return ($this->_comments[$commentTitle]);
  359.         else
  360.             // The comment doesn't exist in this file.  The user should've called getCommentList first.
  361.             return "";
  362.     }
  363.  
  364.     /**
  365.      * Version of the Vorbis specification referred to in the encoding of this stream.
  366.      *
  367.      * This method returns the version of the Vorbis specification (currently 0 (ZERO))
  368.      * referred to by the encoder of this stream.  The Vorbis specification is well-
  369.      * defined, and thus one does not expect this value to change on a frequent basis.
  370.      *
  371.      * @return  int 
  372.      * @access  public
  373.      */
  374.     function getVersion()
  375.     {
  376.         return ($this->_version);
  377.     }
  378.  
  379.     /**
  380.      * Gives the vendor string for the software used to encode this stream.
  381.      * It is common to find libVorbis here.  A previous version of this package
  382.      * compared this vendor string against a release table, but this has been
  383.      * removed, as encoding software is not limited to libvorbis.
  384.      *
  385.      * @return  string 
  386.      * @access  public
  387.      */
  388.     function getVendor()
  389.     {
  390.         return ($this->_vendor);
  391.     }
  392.  
  393.     /**
  394.      * Gives the number of channels used in this stream.
  395.      *
  396.      * @return  int 
  397.      * @access  public
  398.      */
  399.     function getChannels()
  400.     {
  401.         return ($this->_channels);
  402.     }
  403.  
  404.     /**
  405.      * Gives the number of samples per second used in this stream.
  406.      *
  407.      * @return  int 
  408.      * @access  public
  409.      */
  410.     function getSampleRate()
  411.     {
  412.         return ($this->_sampleRate);
  413.     }
  414.  
  415.     /**
  416.      * Gives an array of the values of four different types of bitrates for this
  417.      * stream. The nominal, maximum and minimum values are found within the file,
  418.      * whereas the average value is computed.
  419.      *
  420.      * @return  array 
  421.      * @access  public
  422.      */
  423.     function getBitrates()
  424.     {
  425.         return (array("nom" => $this->_nomBitrate"max" => $this->_maxBitrate"min" => $this->_minBitrate"avg" => $this->_avgBitrate));
  426.     }
  427.  
  428.     /**
  429.      * Gives the most accurate bitrate measurement from this stream.
  430.      *
  431.      * @return  float 
  432.      * @access  public
  433.      */
  434.     function getBitrate()
  435.     {
  436.         if ($this->_avgBitrate != 0)
  437.             return ($this->_avgBitrate);
  438.         elseif ($this->_nomBitrate != 0)
  439.             return ($this->_nomBitrate);
  440.         else
  441.             return (($this->_minBitrate $this->_maxBitrate/ 2);
  442.     }
  443.  
  444.     /**
  445.      * Gives the size (in bits) of this stream.
  446.      *
  447.      * @return  int 
  448.      * @access  public
  449.      */
  450.     function getSize()
  451.     {
  452.         return ($this->_streamSize);
  453.     }
  454.  
  455.     /**
  456.      * Gives the length (in seconds) of this stream.
  457.      *
  458.      * @return  int 
  459.      * @access  public
  460.      */
  461.     function getLength()
  462.     {
  463.         return ($this->_streamLength);
  464.     }
  465.     
  466.     /**
  467.      * States whether this logical stream was encoded in mono.
  468.      *
  469.      * @return    boolean 
  470.      */
  471.     function isMono()
  472.     {
  473.         return $this->_channels == 1;
  474.     }
  475.     
  476.     /**
  477.      * States whether this logical stream was encoded in stereo.
  478.      *
  479.      * @return    boolean 
  480.      */
  481.     function isStereo()
  482.     {
  483.         return $this->_channels == 2;
  484.     }
  485. }
  486. ?>

Documentation generated on Mon, 11 Mar 2019 14:10:45 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.