summaryrefslogtreecommitdiff
path: root/extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Media.php
blob: 67ddaeceb7269c8feddd4d05d4eb957a29fc397f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------------+
// | File_Ogg PEAR Package for Accessing Ogg Bitstreams                         |
// | Copyright (c) 2005-2007                                                    |
// | David Grant <david@grant.org.uk>                                           |
// | Tim Starling <tstarling@wikimedia.org>                                     |
// +----------------------------------------------------------------------------+
// | This library is free software; you can redistribute it and/or              |
// | modify it under the terms of the GNU Lesser General Public                 |
// | License as published by the Free Software Foundation; either               |
// | version 2.1 of the License, or (at your option) any later version.         |
// |                                                                            |
// | This library is distributed in the hope that it will be useful,            |
// | but WITHOUT ANY WARRANTY; without even the implied warranty of             |
// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU          |
// | Lesser General Public License for more details.                            |
// |                                                                            |
// | You should have received a copy of the GNU Lesser General Public           |
// | License along with this library; if not, write to the Free Software        |
// | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA |
// +----------------------------------------------------------------------------+


/**
 * Parent class for media bitstreams
 * Contains some functions common to various media formats
 */
abstract class File_Ogg_Media extends File_Ogg_Bitstream
{
    /**
     * Maximum size of header comment to parse.
     * Set to 1 MB by default. Make sure this is less than your PHP memory_limit.
     */
    const COMMENT_MAX_SIZE = 1000000;

    /**
     * Array to hold each of the comments.
     *
     * @access  private
     * @var     array
     */
    var $_comments = array();

    /**
     * Vendor string for the stream.
     *
     * @access  private
     * @var     string
     */
    var $_vendor;

    /**
     * Length of the stream in seconds
     */
    var $_streamLength;

    /* Start offset of the stream in seconds */
    var $_startOffset = 0;

    /**
     * Get a short string describing the type of the stream
     * @return string
     */
    abstract function getType();

    /**
     * Get the 6-byte identification string expected in the common header
     * @return string
     */
    function getIdentificationString()
    {
        return '';
    }

    /**
     * @access  private
     * @param   int     $packetType
     * @param   int     $pageOffset
     */
    function _decodeCommonHeader($packetType, $pageOffset)
    {
        fseek($this->_filePointer, $this->_streamData['pages'][$pageOffset]['body_offset'], SEEK_SET);
        if ($packetType !== false) {
            // Check if this is the correct header.
            $packet = unpack("Cdata", fread($this->_filePointer, 1));
            if ($packet['data'] != $packetType)
                throw new OggException("Stream Undecodable", OGG_ERROR_UNDECODABLE);

            // The following six characters should be equal to getIdentificationString()
            $id = $this->getIdentificationString();
            if ($id !== '' && fread($this->_filePointer, strlen($id)) !== $id)
                throw new OggException("Stream is undecodable due to a malformed header.", OGG_ERROR_UNDECODABLE);
        } // else seek only, no common header
    }

    /**
     * Parse a Vorbis-style comments header.
     *
     * This function parses the comments header.  The comments header contains a series of
     * UTF-8 comments related to the audio encoded in the stream.  This header also contains
     * a string to identify the encoding software.  More details on the comments header can
     * be found at the following location: http://xiph.org/vorbis/doc/v-comment.html
     *
     * @access  private
     */
    function _decodeBareCommentsHeader()
    {
        // Decode the vendor string length as a 32-bit unsigned integer.
        $vendor_len = unpack("Vdata", fread($this->_filePointer, 4));
        if ( $vendor_len['data'] > 0 ) {
            // Retrieve the vendor string from the stream.
            $this->_vendor  = fread($this->_filePointer, $vendor_len['data']);
        } else {
            $this->_vendor = '';
        }
        // Decode the size of the comments list as a 32-bit unsigned integer.
        $comment_list_length = unpack("Vdata", fread($this->_filePointer, 4));
        // Iterate through the comments list.
        for ($i = 0; $i < $comment_list_length['data']; ++$i) {
            // Unpack the length of this comment.
            $comment_length = unpack("Vdata", fread($this->_filePointer, 4));

            // If the comment length is greater than specified limit, skip it.
            if ( $comment_length['data'] > self::COMMENT_MAX_SIZE ) {
                continue;
            }

            // Comments are in the format 'ARTIST=Super Furry Animals', so split it on the equals character.
            // NOTE: Equals characters are strictly prohibited in either the COMMENT or DATA parts.
            $comment        = explode("=", fread($this->_filePointer, $comment_length['data']));
            $comment_title  = (string) $comment[0];
            $comment_value  = (string) $comment[1];

            // Check if the comment type (e.g. ARTIST) already exists.  If it does,
            // take the new value, and the existing value (or array) and insert it
            // into a new array.  This is important, since each comment type may have
            // multiple instances (e.g. ARTIST for a collaboration) and we should not
            // overwrite the previous value.
            if (isset($this->_comments[$comment_title])) {
                if (is_array($this->_comments[$comment_title]))
                    $this->_comments[$comment_title][] = $comment_value;
                else
                    $this->_comments[$comment_title] = array($this->_comments[$comment_title], $comment_value);
            } else
                $this->_comments[$comment_title] = $comment_value;
        }
    }

    /**
     * Number of channels used in this stream
     *
     * This function returns the number of channels used in this stream.  This
     * can range from 1 to 255, but will likely be 2 (stereo) or 1 (mono).
     *
     * @access  public
     * @return  int
     * @see     File_Ogg_Vorbis::isMono()
     * @see     File_Ogg_Vorbis::isStereo()
     * @see     File_Ogg_Vorbis::isQuadrophonic()
     */
    function getChannels()
    {
        return ($this->_channels);
    }

    /**
     * Provides a list of the comments extracted from the Vorbis stream.
     *
     * It is recommended that the user fully inspect the array returned by this function
     * rather than blindly requesting a comment in false belief that it will always
     * be present.  Whilst the Vorbis specification dictates a number of popular
     * comments (e.g. TITLE, ARTIST, etc.) for use in Vorbis streams, they are not
     * guaranteed to appear.
     *
     * @access  public
     * @return  array
     */
    function getCommentList()
    {
        return (array_keys($this->_comments));
    }

    /**
     * Provides an interface to the numerous comments located with a Vorbis stream.
     *
     * A Vorbis stream may contain one or more instances of each comment, so the user
     * should check the variable type before printing out the result of this method.
     * The situation in which multiple instances of a comment occurring are not as
     * rare as one might think, since they are conceivable at least for ARTIST comments
     * in the situation where a track is a duet.
     *
     * @access  public
     * @param   string  $commentTitle   Comment title to search for, e.g. TITLE.
     * @param   string  $separator      String to separate multiple values.
     * @return  string
     */
    function getField($commentTitle, $separator = ", ")
    {
    if (isset($this->_comments[$commentTitle])) {
        if (is_array($this->_comments[$commentTitle]))
            return (implode($separator, $this->_comments[$commentTitle]));
        else
            return ($this->_comments[$commentTitle]);
    } else
        // The comment doesn't exist in this file.  The user should've called getCommentList first.
        return ("");
    }

    /**
     * Get the entire comments array.
     * May return an empty array if the bitstream does not support comments.
     *
     * @access  public
     * @return  array
     */
    function getComments() {
        return $this->_comments;
    }

    /**
     * Vendor of software used to encode this stream.
     *
     * Gives the vendor string for the software used to encode this stream.
     * It is common to find libVorbis here.  The majority of encoders appear
     * to use libvorbis from Xiph.org.
     *
     * @access  public
     * @return  string
     */
    function getVendor()
    {
        return ($this->_vendor);
    }

    /**
     * Get an associative array containing header information about the stream
     * @access  public
     * @return  array
     */
    function getHeader()
    {
        return array();
    }

    /**
     * Get the length of the stream in seconds
     * @return float
     */
    function getLength()
    {
        return $this->_streamLength;
    }
    /**
     * Get the start offset of the stream in seconds
     *
     * @return float
     */
    function getStartOffset(){
    	return $this->_startOffset;
    }
}