Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 35 |
|
0.00% |
0 / 7 |
CRAP | |
0.00% |
0 / 1 |
File_Ogg_Opus | |
0.00% |
0 / 34 |
|
0.00% |
0 / 7 |
132 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
12 | |||
getSecondsFromGranulePos | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
getType | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
_decodeHeader | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
6 | |||
getHeader | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getSampleRate | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
_decodeCommentsHeader | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 |
1 | <?php |
2 | /* vim: set expandtab tabstop=4 shiftwidth=4: */ |
3 | // +----------------------------------------------------------------------------+ |
4 | // | File_Ogg PEAR Package for Accessing Ogg Bitstreams | |
5 | // | Copyright (c) 2013 | |
6 | // | Jan Gerber <jgerber@wikimedia.org> | |
7 | // +----------------------------------------------------------------------------+ |
8 | // | This library is free software; you can redistribute it and/or | |
9 | // | modify it under the terms of the GNU Lesser General Public | |
10 | // | License as published by the Free Software Foundation; either | |
11 | // | version 2.1 of the License, or (at your option) any later version. | |
12 | // | | |
13 | // | This library is distributed in the hope that it will be useful, | |
14 | // | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | // | Lesser General Public License for more details. | |
17 | // | | |
18 | // | You should have received a copy of the GNU Lesser General Public | |
19 | // | License along with this library; if not, write to the Free Software | |
20 | // | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
21 | // +----------------------------------------------------------------------------+ |
22 | |
23 | use MediaWiki\TimedMediaHandler\Handlers\OggHandler\OggException; |
24 | |
25 | define( 'OGG_OPUS_COMMENTS_PAGE_OFFSET', 1 ); |
26 | |
27 | /** |
28 | * @author Jan Gerber <jgerber@wikimedia.org> |
29 | * @category File |
30 | * @copyright Jan Gerber <jgerber@wikimedia.org> |
31 | * @license http://www.gnu.org/copyleft/lesser.html GNU LGPL |
32 | * @link http://pear.php.net/package/File_Ogg |
33 | * @link http://www.opus-codec.org/ |
34 | * @package File_Ogg |
35 | * @version 1 |
36 | */ |
37 | class File_Ogg_Opus extends File_Ogg_Media |
38 | { |
39 | /** |
40 | * The Opus audio header |
41 | * https://www.opus-codec.org/docs/opusfile_api-0.7/structOpusHead.html |
42 | * |
43 | * @var array |
44 | * @access private |
45 | */ |
46 | var $_header; |
47 | |
48 | /** |
49 | * Number of audio channels in the stream |
50 | * |
51 | * @var int |
52 | * @access private |
53 | */ |
54 | var $_channels; |
55 | |
56 | /** |
57 | * @access private |
58 | */ |
59 | function __construct($streamSerial, $streamData, $filePointer) |
60 | { |
61 | parent::__construct($streamSerial, $streamData, $filePointer); |
62 | $this->_decodeHeader(); |
63 | $this->_decodeCommentsHeader(); |
64 | |
65 | $endSec = $this->getSecondsFromGranulePos( $this->_lastGranulePos ); |
66 | $startSec = $this->getSecondsFromGranulePos( $this->_firstGranulePos ); |
67 | |
68 | if( $startSec > 1){ |
69 | $this->_streamLength = $endSec - $startSec; |
70 | $this->_startOffset = $startSec; |
71 | }else{ |
72 | $this->_streamLength = $endSec; |
73 | } |
74 | $this->_avgBitrate = $this->_streamLength ? ($this->_streamSize * 8) / $this->_streamLength : 0; |
75 | } |
76 | |
77 | function getSecondsFromGranulePos( $granulePos ){ |
78 | return (intval(substr( $granulePos, 0, 8 ), 16 ) * pow(2, 32) |
79 | + intval(substr( $granulePos, 8, 8 ), 16 ) |
80 | - $this->_header['pre_skip']) |
81 | / 48000; |
82 | } |
83 | |
84 | /** |
85 | * Get a short string describing the type of the stream |
86 | * @return string |
87 | */ |
88 | function getType() |
89 | { |
90 | return 'Opus'; |
91 | } |
92 | |
93 | /** |
94 | * Decode the stream header |
95 | * @access private |
96 | */ |
97 | function _decodeHeader() |
98 | { |
99 | fseek($this->_filePointer, $this->_streamData['pages'][0]['body_offset'], SEEK_SET); |
100 | // The first 8 characters should be "OpusHead". |
101 | if (fread($this->_filePointer, 8) != 'OpusHead') |
102 | throw new OggException("Stream is undecodable due to a malformed header.", OGG_ERROR_UNDECODABLE); |
103 | |
104 | $this->_header = File_Ogg::_readLittleEndian($this->_filePointer, array( |
105 | 'opus_version' => 8, |
106 | 'nb_channels' => 8, |
107 | 'pre_skip' => 16, |
108 | 'audio_sample_rate' => 32, |
109 | 'output_gain' => 16, |
110 | 'channel_mapping_family'=> 8, |
111 | )); |
112 | $this->_channels = $this->_header['nb_channels']; |
113 | } |
114 | |
115 | /** |
116 | * Get an associative array containing header information about the stream |
117 | * @access public |
118 | * @return array |
119 | */ |
120 | function getHeader() { |
121 | return $this->_header; |
122 | } |
123 | |
124 | function getSampleRate() |
125 | { |
126 | //Opus always outputs 48kHz, the header only lists |
127 | //the samplerate of the source as reference |
128 | return 48000; |
129 | } |
130 | |
131 | /** |
132 | * Decode the comments header |
133 | * @access private |
134 | */ |
135 | function _decodeCommentsHeader() |
136 | { |
137 | $id = 'OpusTags'; |
138 | $this->_decodeCommonHeader(false, OGG_OPUS_COMMENTS_PAGE_OFFSET); |
139 | if(fread($this->_filePointer, strlen($id)) !== $id) |
140 | throw new OggException("Stream is undecodable due to a malformed header.", OGG_ERROR_UNDECODABLE); |
141 | $this->_decodeBareCommentsHeader(); |
142 | } |
143 | } |
144 | ?> |