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.7 2005/11/03 22:20:10 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->_decodeIdentificationHeader();
  172.         $this->_decodeCommentsHeader();
  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 _decodeIdentificationHeader()
  193.     {
  194.         $this->_decodeCommonHeader(OGG_VORBIS_IDENTIFICATION_HEADER0);
  195.  
  196.         $version unpack("Vdata"fread($this->_filePointer4));
  197.  
  198.         // The Vorbis stream version must be 0.
  199.         if ($version['data'== 0)
  200.             $this->_version $version['data'];
  201.         else
  202.             PEAR::raiseError("Stream is undecodable due to an invalid vorbis stream version."OGG_VORBIS_ERROR_UNDECODABLE);
  203.  
  204.         // The number of channels is stored in an 8 bit unsigned integer,
  205.         // with a maximum of 255 channels.
  206.         $channels unpack("Cdata"fread($this->_filePointer1));
  207.         // The number of channels MUST be greater than 0.
  208.         if ($channels['data'== 0)
  209.             PEAR::raiseError("Stream is undecodable due to zero channels."OGG_VORBIS_ERROR_UNDECODABLE);
  210.         else
  211.             $this->_channels $channels['data'];
  212.  
  213.         // The sample rate is a 32 bit unsigned integer.
  214.         $sample_rate unpack("Vdata"fread($this->_filePointer4));
  215.         // The sample rate MUST be greater than 0.
  216.         if ($sample_rate['data'== 0)
  217.             PEAR::raiseError("Stream is undecodable due to a zero sample rate."OGG_VORBIS_ERROR_UNDECODABLE);
  218.         else
  219.             $this->_sampleRate $sample_rate['data'];
  220.  
  221.         // Extract the various bitrates from the vorbis stream.
  222.         $bitrate['max']     unpack("Vdata"fread($this->_filePointer4));
  223.         $this->_maxBitrate     $bitrate['max']['data'];
  224.         $bitrate['nom']     unpack("Vdata"fread($this->_filePointer4));
  225.         $this->_nomBitrate     $bitrate['nom']['data'];
  226.         $bitrate['min']     unpack("Vdata"fread($this->_filePointer4));
  227.         $this->_minBitrate     $bitrate['min']['data'];
  228.  
  229.         $blocksizes unpack("Cdata"fread($this->_filePointer1));
  230.  
  231.         // Powers of two between 6 and 13 inclusive.
  232.         $valid_block_sizes = array(641282565121024204840968192);
  233.  
  234.         // Extract bits 1 to 4 from the character data.
  235.         // blocksize_0 MUST be a valid blocksize.
  236.         $blocksize_0 pow(2($blocksizes['data'0x0F));
  237.         if (FALSE == in_array($blocksize_0$valid_block_sizes))
  238.             PEAR::raiseError("Stream is undecodable because blocksize_0 is not a valid size."OGG_VORBIS_ERROR_UNDECODABLE);
  239.  
  240.         // Extract bits 5 to 8 from the character data.
  241.         // blocksize_1 MUST be a valid blocksize.
  242.         $blocksize_1 pow(2($blocksizes['data'0xF0>> 4);
  243.         if (FALSE == in_array($blocksize_1$valid_block_sizes))
  244.             PEAR::raiseError("Stream is undecodable because blocksize_1 is not a valid size."OGG_VORBIS_ERROR_UNDECODABLE);
  245.  
  246.         // blocksize 0 MUST be less than or equal to blocksize 1.
  247.         if ($blocksize_0 $blocksize_1)
  248.             PEAR::raiseError("Stream is undecodable because blocksize_0 is not less than or equal to blocksize_1."OGG_VORBIS_ERROR_UNDECODABLE);
  249.  
  250.         // The framing bit MUST be set to mark the end of the identification header.
  251.         $framing_bit unpack("Cdata"fread($this->_filePointer1));
  252.         if ($framing_bit['data'== 0)
  253.             PEAR::raiseError("Stream in undecodable because the framing bit is not non-zero."OGG_VORBIS_ERROR_UNDECODABLE);
  254.     }
  255.     
  256.     function _decodeCommonHeader($packetType$pageOffset)
  257.     {
  258.         fseek($this->_filePointer$this->_streamList['stream_page'][$pageOffset]['body_offset']SEEK_SET);
  259.         // Check if this is the correct header.
  260.         $packet unpack("Cdata"fread($this->_filePointer1));
  261.         if ($packet['data'!= $packetType)
  262.             PEAR::raiseError("Stream Undecodable"OGG_VORBIS_ERROR_UNDECODABLE);
  263.  
  264.         // The following six characters should be the characters 'v', 'o', 'r', 'b', 'i', 's'.
  265.         if (fread($this->_filePointer6!= "vorbis")
  266.             PEAR::raiseError("Stream is undecodable due to a malformed header."OGG_VORBIS_ERROR_UNDECODABLE);
  267.     }
  268.     
  269.     /**
  270.      * Parse the comments header (the second of three headers) of a Vorbis stream.
  271.      *
  272.      * This function parses the comments header.  The comments header contains a series of
  273.      * UTF-8 comments related to the audio encoded in the stream.  This header also contains
  274.      * a string to identify the encoding software.  More details on the comments header can
  275.      * be found at the following location.
  276.      *
  277.      * @link    http://www.xiph.org/ogg/vorbis/doc/v-comment.html
  278.      * @access  private
  279.      */
  280.     function _decodeCommentsHeader()
  281.     {
  282.         $this->_decodeCommonHeader(OGG_VORBIS_COMMENTS_HEADER1);
  283.             
  284.         // Decode the vendor string length.
  285.         $vendor_len     unpack("Vdata"fread($this->_filePointer4));
  286.         $this->_vendor     fread($this->_filePointer$vendor_len['data']);
  287.         // Decode the size of the comments list.
  288.         $comment_list_length unpack("Vdata"fread($this->_filePointer4));
  289.         for ($i = 0; $i $comment_list_length['data']$i++{
  290.             $comment_length unpack("Vdata"fread($this->_filePointer4));
  291.             // Comments are in the format 'ARTIST=Super Furry Animals', so split it on the equals character.
  292.             // NOTE: Equals characters are strictly prohibited in either the COMMENT or DATA parts.
  293.             $comment         explode("="fread($this->_filePointer$comment_length['data']));
  294.             $comment_title     = (string) $comment[0];
  295.             $comment_value     = (string) utf8_decode($comment[1]);
  296.  
  297.             // Check if the comment type (e.g. ARTIST) already exists.  If it does,
  298.             // take the new value, and the existing value (or array) and insert it
  299.             // into a new array.  This is important, since each comment type may have
  300.             // multiple instances (e.g. ARTIST for a collaboration) and we should not
  301.             // overwrite the previous value.
  302.             if (isset($this->_comments[$comment_title])) {
  303.                 if (is_array($this->_comments[$comment_title]))
  304.                     $this->_comments[$comment_title][$comment_value;
  305.                 else
  306.                     $this->_comments[$comment_title= array($this->_comments[$comment_title]$comment_value);
  307.             else
  308.                 $this->_comments[$comment_title$comment_value;
  309.         }
  310.  
  311.         // The framing bit MUST be set to mark the end of the comments header.
  312.         $framing_bit unpack("Cdata"fread($this->_filePointer1));
  313.         if ($framing_bit['data'!= 1)
  314.             PEAR::raiseError("Stream Undecodable"OGG_VORBIS_ERROR_UNDECODABLE);
  315.     }
  316.     
  317.     /**
  318.      * Provides a list of the comments extracted from the Vorbis stream.
  319.      *
  320.      * It is recommended that the user fully inspect the array returned by this function
  321.      * rather than blindly requesting a comment in false belief that it will always
  322.      * be present.  Whilst the Vorbis specification dictates a number of popular
  323.      * comments (e.g. TITLE, ARTIST, etc.) for use in Vorbis streams, they are not
  324.      * guaranteed to appear.
  325.      *
  326.      * @return  array 
  327.      * @access  public
  328.      */
  329.     function getCommentList()
  330.     {
  331.           return (array_keys($this->_comments));
  332.     }
  333.  
  334.     /**
  335.      * Provides an interface to the numerous comments located with a Vorbis stream.
  336.      *
  337.      * A Vorbis stream may contain one or more instances of each comment, so the user
  338.      * should check the variable type before printing out the result of this method.
  339.      * The situation in which multiple instances of a comment occurring are not as
  340.      * rare as one might think, since they are conceivable at least for ARTIST comments
  341.      * in the situation where a track is a duet.
  342.      *
  343.      * @param   string  $commentTitle   Comment title to search for, e.g. TITLE.
  344.      * @return  string 
  345.      * @access  public
  346.      */
  347.     function getField($commentTitle)
  348.     {
  349.         if (isset($this->_comments[$commentTitle])) {
  350.             if (is_array($this->_comments[$commentTitle]))
  351.                 return (implode(", "$this->_comments[$commentTitle]));
  352.             else
  353.                 return ($this->_comments[$commentTitle]);
  354.         else
  355.             // The comment doesn't exist in this file.  The user should've called getCommentList first.
  356.             return "";
  357.     }
  358.  
  359.     /**
  360.      * Version of the Vorbis specification referred to in the encoding of this stream.
  361.      *
  362.      * This method returns the version of the Vorbis specification (currently 0 (ZERO))
  363.      * referred to by the encoder of this stream.  The Vorbis specification is well-
  364.      * defined, and thus one does not expect this value to change on a frequent basis.
  365.      *
  366.      * @return  int 
  367.      * @access  public
  368.      */
  369.     function getEncoderVersion()
  370.     {
  371.         return ($this->_version);
  372.     }
  373.  
  374.     /**
  375.      * Gives the vendor string for the software used to encode this stream.
  376.      * It is common to find libVorbis here.  A previous version of this package
  377.      * compared this vendor string against a release table, but this has been
  378.      * removed, as encoding software is not limited to libvorbis.
  379.      *
  380.      * @return  string 
  381.      * @access  public
  382.      */
  383.     function getVendor()
  384.     {
  385.         return ($this->_vendor);
  386.     }
  387.  
  388.     /**
  389.      * Gives the number of channels used in this stream.
  390.      *
  391.      * @return  int 
  392.      * @access  public
  393.      */
  394.     function getChannels()
  395.     {
  396.         return ($this->_channels);
  397.     }
  398.  
  399.     /**
  400.      * Gives the number of samples per second used in this stream.
  401.      *
  402.      * @return  int 
  403.      * @access  public
  404.      */
  405.     function getSampleRate()
  406.     {
  407.         return ($this->_sampleRate);
  408.     }
  409.  
  410.     /**
  411.      * Gives an array of the values of four different types of bitrates for this
  412.      * stream. The nominal, maximum and minimum values are found within the file,
  413.      * whereas the average value is computed.
  414.      *
  415.      * @return  array 
  416.      * @access  public
  417.      */
  418.     function getBitrates()
  419.     {
  420.         return (array("nom" => $this->_nomBitrate"max" => $this->_maxBitrate"min" => $this->_minBitrate"avg" => $this->_avgBitrate));
  421.     }
  422.  
  423.     /**
  424.      * Gives the most accurate bitrate measurement from this stream.
  425.      *
  426.      * @return  float 
  427.      * @access  public
  428.      */
  429.     function getBitrate()
  430.     {
  431.         if ($this->_avgBitrate != 0)
  432.             return ($this->_avgBitrate);
  433.         elseif ($this->_nomBitrate != 0)
  434.             return ($this->_nomBitrate);
  435.         else
  436.             return (($this->_minBitrate $this->_maxBitrate/ 2);
  437.     }
  438.  
  439.     /**
  440.      * Gives the size (in bits) of this stream.
  441.      *
  442.      * @return  int 
  443.      * @access  public
  444.      */
  445.     function getSize()
  446.     {
  447.         return ($this->_streamSize);
  448.     }
  449.  
  450.     /**
  451.      * Gives the length (in seconds) of this stream.
  452.      *
  453.      * @return  int 
  454.      * @access  public
  455.      */
  456.     function getLength()
  457.     {
  458.         return ($this->_streamLength);
  459.     }
  460.     
  461.     /**
  462.      * States whether this logical stream was encoded in mono.
  463.      *
  464.      * @return    boolean 
  465.      */
  466.     function isMono()
  467.     {
  468.         return $this->_channels == 1;
  469.     }
  470.     
  471.     /**
  472.      * States whether this logical stream was encoded in stereo.
  473.      *
  474.      * @return    boolean 
  475.      */
  476.     function isStereo()
  477.     {
  478.         return $this->_channels == 2;
  479.     }
  480.     
  481.     /**
  482.      * The title of this track, e.g. "What's Up Pussycat?".
  483.      *
  484.      * @return string 
  485.      */
  486.     function getTitle()
  487.     {
  488.         return $this->getField("TITLE");
  489.     }
  490.     
  491.     /**
  492.      * The version of the track, such as a remix.
  493.      *
  494.      * @return     string 
  495.      */
  496.     function getVersion()
  497.     {
  498.         return $this->getField("VERSION");
  499.     }
  500.     
  501.     /**
  502.      * The album from which this track comes.
  503.      *
  504.      * @return     string 
  505.      */
  506.     function getAlbum()
  507.     {
  508.         return $this->getField("ALBUM");
  509.     }
  510.     
  511.     /**
  512.      * The number of this track if it is part of a larger collection.
  513.      */
  514.     function getTrackNumber()
  515.     {
  516.         return $this->getField("TRACKNUMBER");
  517.     }
  518.     
  519.     /**
  520.      * The artist responsible for this track.
  521.      *
  522.      * @return    string 
  523.      */
  524.     function getArtist()
  525.     {
  526.         return $this->getField("ARTIST");
  527.     }
  528.     
  529.     /**
  530.      * The performer of this track, such as an orchestra
  531.      *
  532.      * @return     string 
  533.      */
  534.     function getPerformer()
  535.     {
  536.         return $this->getField("PERFORMER");
  537.     }
  538.     
  539.     /**
  540.      * The copyright attribution for this track.
  541.      *
  542.      * @return    string 
  543.      */
  544.     function getCopyright()
  545.     {
  546.         return $this->getField("COPYRIGHT");
  547.     }
  548.     
  549.     /**
  550.      * The rights of distribution for this track.
  551.      *
  552.      * @return     string 
  553.      */
  554.     function getLicense()
  555.     {
  556.         return $this->getField("LICENSE");
  557.     }
  558.     
  559.     /**
  560.      * The name of the organisation producing this track, such
  561.      * as a record label.
  562.      *
  563.      * @return     string 
  564.      */
  565.     function getOrganization()
  566.     {
  567.         return $this->getField("ORGANIZATION");
  568.     }
  569.     
  570.     /**
  571.      * A short description of the contents of this track.
  572.      *
  573.      * @return    string 
  574.      */
  575.     function getDescription()
  576.     {
  577.         return $this->getField("DESCRIPTION");
  578.     }
  579.     
  580.     /**
  581.      *
  582.      */
  583.     function getGenre()
  584.     {
  585.         return $this->getField("GENRE");
  586.     }
  587.     
  588.     function getDate()
  589.     {
  590.         return $this->getField("DATE");
  591.     }
  592.     
  593.     function getLocation()
  594.     {
  595.         return $this->getField("LOCATION");
  596.     }
  597.     
  598.     function getContact()
  599.     {
  600.         return $this->getField("CONTACT");
  601.     }
  602.     
  603.     function getIsrc()
  604.     {
  605.         return $this->getField("ISRC");
  606.     }
  607. }
  608. ?>

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