Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 91
0.00% covered (danger)
0.00%
0 / 31
CRAP
0.00% covered (danger)
0.00%
0 / 1
File_Ogg_Vorbis
0.00% covered (danger)
0.00%
0 / 83
0.00% covered (danger)
0.00%
0 / 31
1806
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 getSecondsFromGranulePos
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 getType
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 _decodeIdentificationHeader
0.00% covered (danger)
0.00%
0 / 34
0.00% covered (danger)
0.00%
0 / 1
56
 _decodeCommentsHeader
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 getIdentificationString
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getEncoderVersion
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSampleRate
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getBitrates
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getBitrate
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 getLength
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getStartOffset
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isMono
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isStereo
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isQuadrophonic
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getTitle
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getVersion
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getAlbum
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getTrackNumber
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getArtist
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getPerformer
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getCopyright
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getLicense
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getOrganization
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDescription
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getGenre
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDate
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getLocation
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getContact
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getIsrc
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getHeader
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/* vim: set expandtab tabstop=4 shiftwidth=4: */
3// +----------------------------------------------------------------------------+
4// | File_Ogg PEAR Package for Accessing Ogg Bitstreams                         |
5// | Copyright (c) 2005-2007                                                    |
6// | David Grant <david@grant.org.uk>                                           |
7// | Tim Starling <tstarling@wikimedia.org>                                     |
8// +----------------------------------------------------------------------------+
9// | This library is free software; you can redistribute it and/or              |
10// | modify it under the terms of the GNU Lesser General Public                 |
11// | License as published by the Free Software Foundation; either               |
12// | version 2.1 of the License, or (at your option) any later version.         |
13// |                                                                            |
14// | This library is distributed in the hope that it will be useful,            |
15// | but WITHOUT ANY WARRANTY; without even the implied warranty of             |
16// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU          |
17// | Lesser General Public License for more details.                            |
18// |                                                                            |
19// | You should have received a copy of the GNU Lesser General Public           |
20// | License along with this library; if not, write to the Free Software        |
21// | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA |
22// +----------------------------------------------------------------------------+
23
24
25/**
26 * Check number for the first header in a Vorbis stream.
27 *
28 * @access  private
29 */
30
31use MediaWiki\TimedMediaHandler\Handlers\OggHandler\OggException;
32
33define("OGG_VORBIS_IDENTIFICATION_HEADER",  1);
34/**
35 * Check number for the second header in a Vorbis stream.
36 *
37 * @access  private
38 */
39define("OGG_VORBIS_COMMENTS_HEADER",        3);
40/**
41 * Check number for the third header in a Vorbis stream.
42 *
43 * @access  private
44 */
45define("OGG_VORBIS_SETUP_HEADER",           5);
46/**
47 * Error thrown if the stream appears to be corrupted.
48 *
49 * @access  private
50 */
51define("OGG_VORBIS_ERROR_UNDECODABLE",      OGG_ERROR_UNDECODABLE);
52/**
53 * Error thrown if the user attempts to extract a comment using a comment key
54 * that does not exist.
55 *
56 * @access  private
57 */
58define("OGG_VORBIS_ERROR_INVALID_COMMENT",  2);
59
60define("OGG_VORBIS_IDENTIFICATION_PAGE_OFFSET", 0);
61define("OGG_VORBIS_COMMENTS_PAGE_OFFSET",       1);
62
63/**
64 * Error thrown if the user attempts to write a comment containing an illegal
65 * character
66 *
67 * @access  private
68 */
69define("OGG_VORBIS_ERROR_ILLEGAL_COMMENT",  3);
70
71/**
72 * Extract the contents of a Vorbis logical stream.
73 *
74 * This class provides an interface to a Vorbis logical stream found within
75 * a Ogg stream.  A variety of information may be extracted, including comment
76 * tags, running time, and bitrate.  For more information, please see the following
77 * links.
78 *
79 * @author      David Grant <david@grant.org.uk>, Tim Starling <tstarling@wikimedia.org>
80 * @category    File
81 * @copyright   David Grant <david@grant.org.uk>, Tim Starling <tstarling@wikimedia.org>
82 * @license     http://www.gnu.org/copyleft/lesser.html GNU LGPL
83 * @link        http://pear.php.net/package/File_Ogg
84 * @link        http://www.xiph.org/vorbis/doc/
85 * @package     File_Ogg
86 * @version     CVS: $Id: Vorbis.php,v 1.13 2005/11/19 09:06:32 djg Exp $
87 */
88class File_Ogg_Vorbis extends File_Ogg_Media
89{
90
91    /**
92     * Version of vorbis specification used.
93     *
94     * @access  private
95     * @var     int
96     */
97    var $_version;
98
99    /**
100     * Number of channels in the vorbis stream.
101     *
102     * @access  private
103     * @var     int
104     */
105    var $_channels;
106
107    /**
108     * Vorbis Identification Header
109     * https://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-610004.2
110     *
111     * @access  private
112     * @var     array
113     */
114    var $_idHeader;
115
116    /**
117     * Number of samples per second in the vorbis stream.
118     *
119     * @access  private
120     * @var     int
121     */
122    var $_sampleRate;
123
124    /**
125     * Minimum bitrate for the vorbis stream.
126     *
127     * @access  private
128     * @var     int
129     */
130    var $_minBitrate;
131
132    /**
133     * Maximum bitrate for the vorbis stream.
134     *
135     * @access  private
136     * @var     int
137     */
138    var $_maxBitrate;
139
140    /**
141     * Nominal bitrate for the vorbis stream.
142     *
143     * @access  private
144     * @var     int
145     */
146    var $_nomBitrate;
147
148    /**
149     * The length of this stream in seconds.
150     *
151     * @access  private
152     * @var     int
153     */
154    var $_streamLength;
155
156    /**
157     * the start offset of this stream in seconds
158     */
159    var $_startOffset;
160    /**
161     * Constructor for accessing a Vorbis logical stream.
162     *
163     * This method is the constructor for the native-PHP interface to a Vorbis logical
164     * stream, embedded within an Ogg physical stream.
165     *
166     * @param   int      $streamSerial   Serial number of the logical stream.
167     * @param   array    $streamData     Data for the requested logical stream.
168     * @param   resource $filePointer    File pointer for the current physical stream.
169     * @access  private
170     */
171    function __construct($streamSerial, $streamData, $filePointer)
172    {
173        parent::__construct($streamSerial, $streamData, $filePointer);
174        $this->_decodeIdentificationHeader();
175        $this->_decodeCommentsHeader(OGG_VORBIS_COMMENTS_HEADER, OGG_VORBIS_COMMENTS_PAGE_OFFSET);
176
177        $endSec =  $this->getSecondsFromGranulePos( $this->_lastGranulePos );
178        $startSec = $this->getSecondsFromGranulePos( $this->_firstGranulePos );
179
180        //make sure the offset is worth taking into account oggz_chop related hack
181        if( $startSec > 1){
182            $this->_streamLength = $endSec - $startSec;
183            $this->_startOffset = $startSec;
184        }else{
185            $this->_streamLength = $endSec;
186        }
187
188        $this->_avgBitrate      = $this->_streamLength ? ($this->_streamSize * 8) / $this->_streamLength : 0;
189    }
190    function getSecondsFromGranulePos( $granulePos ){
191        return (intval(substr( $granulePos, 0, 8 ), 16) * pow(2, 32)
192            + intval( substr( $granulePos, 8, 8 ), 16 ))
193            / $this->_idHeader['audio_sample_rate'];
194    }
195    /**
196     * Get a short string describing the type of the stream
197     */
198    function getType()
199    {
200        return 'Vorbis';
201    }
202
203    /**
204     * Parse the identification header (the first of three headers) in a Vorbis stream.
205     *
206     * This function parses the identification header.  The identification header
207     * contains simple audio characteristics, such as sample rate and number of
208     * channels.  There are a number of error-checking provisions laid down in the Vorbis
209     * specification to ensure the stream is pure.
210     *
211     * @access  private
212     */
213    function _decodeIdentificationHeader()
214    {
215        $this->_decodeCommonHeader(OGG_VORBIS_IDENTIFICATION_HEADER, OGG_VORBIS_IDENTIFICATION_PAGE_OFFSET);
216
217        $h = File_Ogg::_readLittleEndian($this->_filePointer, array(
218            'vorbis_version'        => 32,
219            'audio_channels'        => 8,
220            'audio_sample_rate'     => 32,
221            'bitrate_maximum'       => 32,
222            'bitrate_nominal'       => 32,
223            'bitrate_minimum'       => 32,
224            'blocksize_0'           => 4,
225            'blocksize_1'           => 4,
226            'framing_flag'          => 1
227        ));
228
229        // The Vorbis stream version must be 0.
230        if ($h['vorbis_version'] == 0)
231            $this->_version = $h['vorbis_version'];
232        else
233            throw new OggException("Stream is undecodable due to an invalid vorbis stream version.", OGG_VORBIS_ERROR_UNDECODABLE);
234
235        // The number of channels MUST be greater than 0.
236        if ($h['audio_channels'] == 0)
237            throw new OggException("Stream is undecodable due to zero channels.", OGG_VORBIS_ERROR_UNDECODABLE);
238        else
239            $this->_channels = $h['audio_channels'];
240
241        // The sample rate MUST be greater than 0.
242        if ($h['audio_sample_rate'] == 0)
243            throw new OggException("Stream is undecodable due to a zero sample rate.", OGG_VORBIS_ERROR_UNDECODABLE);
244        else
245            $this->_sampleRate = $h['audio_sample_rate'];
246
247        // Extract the various bitrates
248        $this->_maxBitrate  = $h['bitrate_maximum'];
249        $this->_nomBitrate  = $h['bitrate_nominal'];
250        $this->_minBitrate  = $h['bitrate_minimum'];
251
252        // Powers of two between 6 and 13 inclusive.
253        $valid_block_sizes = array(64, 128, 256, 512, 1024, 2048, 4096, 8192);
254
255        // blocksize_0 MUST be a valid blocksize.
256        $blocksize_0 = pow(2, $h['blocksize_0']);
257        if (!in_array($blocksize_0, $valid_block_sizes))
258            throw new OggException("Stream is undecodable because blocksize_0 is $blocksize_0, which is not a valid size.", OGG_VORBIS_ERROR_UNDECODABLE);
259
260        // Extract bits 5 to 8 from the character data.
261        // blocksize_1 MUST be a valid blocksize.
262        $blocksize_1 = pow(2, $h['blocksize_1']);
263        if (!in_array($blocksize_1, $valid_block_sizes))
264            throw new OggException("Stream is undecodable because blocksize_1 is not a valid size.", OGG_VORBIS_ERROR_UNDECODABLE);
265
266        // blocksize 0 MUST be less than or equal to blocksize 1.
267        if ($blocksize_0 > $blocksize_1)
268            throw new OggException("Stream is undecodable because blocksize_0 is not less than or equal to blocksize_1.", OGG_VORBIS_ERROR_UNDECODABLE);
269
270        // The framing bit MUST be set to mark the end of the identification header.
271        // Some encoders are broken though -- TS
272        /*
273        if ($h['framing_flag'] == 0)
274            throw new OggException("Stream in undecodable because the framing bit is not non-zero.", OGG_VORBIS_ERROR_UNDECODABLE);
275         */
276
277        $this->_idHeader = $h;
278    }
279
280    /**
281     * Decode the comments header
282     * @access  private
283     * @param   int     $packetType
284     * @param   int     $pageOffset
285     */
286    function _decodeCommentsHeader($packetType, $pageOffset)
287    {
288        $this->_decodeCommonHeader($packetType, $pageOffset);
289        $this->_decodeBareCommentsHeader();
290        // The framing bit MUST be set to mark the end of the comments header.
291        $framing_bit = unpack("Cdata", fread($this->_filePointer, 1));
292        if ($framing_bit['data'] != 1)
293            throw new OggException("Stream Undecodable", OGG_VORBIS_ERROR_UNDECODABLE);
294    }
295
296    /**
297     * Get the 6-byte identification string expected in the common header
298     */
299    function getIdentificationString() {
300        return OGG_STREAM_CAPTURE_VORBIS;
301    }
302
303    /**
304     * Version of the Vorbis specification referred to in the encoding of this stream.
305     *
306     * This method returns the version of the Vorbis specification (currently 0 (ZERO))
307     * referred to by the encoder of this stream.  The Vorbis specification is well-
308     * defined, and thus one does not expect this value to change on a frequent basis.
309     *
310     * @access  public
311     * @return  int
312     */
313    function getEncoderVersion()
314    {
315        return ($this->_version);
316    }
317
318    /**
319     * Samples per second.
320     *
321     * This function returns the number of samples used per second in this
322     * recording.  Probably the most common value here is 44,100.
323     *
324     * @return  int
325     * @access  public
326     */
327    function getSampleRate()
328    {
329        return ($this->_sampleRate);
330    }
331
332    /**
333     * Various bitrate measurements
334     *
335     * Gives an array of the values of four different types of bitrates for this
336     * stream. The nominal, maximum and minimum values are found within the file,
337     * whereas the average value is computed.
338     *
339     * @access  public
340     * @return  array
341     */
342    function getBitrates()
343    {
344        return (array("nom" => $this->_nomBitrate, "max" => $this->_maxBitrate, "min" => $this->_minBitrate, "avg" => $this->_avgBitrate));
345    }
346
347    /**
348     * Gives the most accurate bitrate measurement from this stream.
349     *
350     * This function returns the most accurate bitrate measurement for this
351     * recording, depending on values set in the stream header.
352     *
353     * @access  public
354     * @return  float
355     */
356    function getBitrate()
357    {
358        if ($this->_avgBitrate != 0)
359            return ($this->_avgBitrate);
360        elseif ($this->_nomBitrate != 0)
361            return ($this->_nomBitrate);
362        else
363            return (($this->_minBitrate + $this->_maxBitrate) / 2);
364    }
365
366    /**
367     * Gives the length (in seconds) of this stream.
368     *
369     * @access  public
370     * @return  int
371     */
372    function getLength()
373    {
374        return ($this->_streamLength);
375    }
376     /**
377     * Get the start offset of the stream in seconds
378     * @access public
379     * @return int
380     */
381    function getStartOffset(){
382        return ($this->_startOffset);
383    }
384    /**
385     * States whether this logical stream was encoded in mono.
386     *
387     * @access  public
388     * @return  boolean
389     */
390    function isMono()
391    {
392        return ($this->_channels == 1);
393    }
394
395    /**
396     * States whether this logical stream was encoded in stereo.
397     *
398     * @access  public
399     * @return  boolean
400     */
401    function isStereo()
402    {
403        return ($this->_channels == 2);
404    }
405
406    /**
407     * States whether this logical stream was encoded in quadrophonic sound.
408     *
409     * @access  public
410     * @return  boolean
411     */
412    function isQuadrophonic()
413    {
414        return ($this->_channels == 4);
415    }
416
417    /**
418     * The title of this track, e.g. "What's Up Pussycat?".
419     *
420     * @access  public
421     * @return  string
422     */
423    function getTitle()
424    {
425        return ($this->getField("TITLE"));
426    }
427
428    /**
429     * The version of the track, such as a remix.
430     *
431     * @access  public
432     * @return  string
433     */
434    function getVersion()
435    {
436        return $this->getField("VERSION");
437    }
438
439    /**
440     * The album or collection from which this track comes.
441     *
442     * @access  public
443     * @return  string
444     */
445    function getAlbum()
446    {
447        return ($this->getField("ALBUM"));
448    }
449
450    /**
451     * The number of this track if it is part of a larger collection.
452     *
453     * @access  public
454     * @return  string
455     */
456    function getTrackNumber()
457    {
458        return ($this->getField("TRACKNUMBER"));
459    }
460
461    /**
462     * The artist responsible for this track.
463     *
464     * This function returns the name of the artist responsible for this
465     * recording, which may be either a solo-artist, duet or group.
466     *
467     * @access  public
468     * @return  string
469     */
470    function getArtist()
471    {
472        return ($this->getField("ARTIST"));
473    }
474
475    /**
476     * The performer of this track, such as an orchestra
477     *
478     * @access  public
479     * @return  string
480     */
481    function getPerformer()
482    {
483        return ($this->getField("PERFORMER"));
484    }
485
486    /**
487     * The copyright attribution for this track.
488     *
489     * @access  public
490     * @return  string
491     */
492    function getCopyright()
493    {
494        return ($this->getField("COPYRIGHT"));
495    }
496
497    /**
498     * The rights of distribution for this track.
499     *
500     * This funtion returns the license for this track, and may include
501     * copyright information, or a creative commons statement.
502     *
503     * @access  public
504     * @return  string
505     */
506    function getLicense()
507    {
508        return ($this->getField("LICENSE"));
509    }
510
511    /**
512     * The organisation responsible for this track.
513     *
514     * This function returns the name of the organisation responsible for
515     * the production of this track, such as the record label.
516     *
517     * @access  public
518     * @return  string
519     */
520    function getOrganization()
521    {
522        return ($this->getField("ORGANIZATION"));
523    }
524
525    /**
526     * A short description of the contents of this track.
527     *
528     * This function returns a short description of this track, which might
529     * contain extra information that doesn't fit anywhere else.
530     *
531     * @access  public
532     * @return  string
533     */
534    function getDescription()
535    {
536        return ($this->getField("DESCRIPTION"));
537    }
538
539    /**
540     * The genre of this recording (e.g. Rock)
541     *
542     * This function returns the genre of this recording.  There are no pre-
543     * defined genres, so this is completely up to the tagging software.
544     *
545     * @access  public
546     * @return  string
547     */
548    function getGenre()
549    {
550        return ($this->getField("GENRE"));
551    }
552
553    /**
554     * The date of the recording of this track.
555     *
556     * This function returns the date on which this recording was made.  There
557     * is no specification for the format of this date.
558     *
559     * @access  public
560     * @return  string
561     */
562    function getDate()
563    {
564        return ($this->getField("DATE"));
565    }
566
567    /**
568     * Where this recording was made.
569     *
570     * This function returns where this recording was made, such as a recording
571     * studio, or concert venue.
572     *
573     * @access  public
574     * @return  string
575     */
576    function getLocation()
577    {
578        return ($this->getField("LOCATION"));
579    }
580
581    /**
582     * @access  public
583     * @return  string
584     */
585    function getContact()
586    {
587        return ($this->getField("CONTACT"));
588    }
589
590    /**
591     * International Standard Recording Code.
592     *
593     * Returns the International Standard Recording Code.  This code can be
594     * validated using the Validate_ISPN package.
595     *
596     * @access  public
597     * @return  string
598     */
599    function getIsrc()
600    {
601        return ($this->getField("ISRC"));
602    }
603
604    /**
605     * Get an associative array containing header information about the stream
606     * @access  public
607     * @return  array
608     */
609    function getHeader() {
610        return $this->_idHeader;
611    }
612}
613?>