1 | <?php |
---|
2 | ///////////////////////////////////////////////////////////////// |
---|
3 | /// getID3() by James Heinrich <info@getid3.org> // |
---|
4 | // available at http://getid3.sourceforge.net // |
---|
5 | // or http://www.getid3.org // |
---|
6 | ///////////////////////////////////////////////////////////////// |
---|
7 | // See readme.txt for more details // |
---|
8 | ///////////////////////////////////////////////////////////////// |
---|
9 | // // |
---|
10 | // module.audio-video.real.php // |
---|
11 | // module for analyzing Real Audio/Video files // |
---|
12 | // dependencies: module.audio-video.riff.php // |
---|
13 | // /// |
---|
14 | ///////////////////////////////////////////////////////////////// |
---|
15 | |
---|
16 | getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true); |
---|
17 | |
---|
18 | class getid3_real |
---|
19 | { |
---|
20 | |
---|
21 | function getid3_real(&$fd, &$ThisFileInfo) { |
---|
22 | $ThisFileInfo['fileformat'] = 'real'; |
---|
23 | $ThisFileInfo['bitrate'] = 0; |
---|
24 | $ThisFileInfo['playtime_seconds'] = 0; |
---|
25 | |
---|
26 | fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET); |
---|
27 | $ChunkCounter = 0; |
---|
28 | while (ftell($fd) < $ThisFileInfo['avdataend']) { |
---|
29 | $ChunkData = fread($fd, 8); |
---|
30 | $ChunkName = substr($ChunkData, 0, 4); |
---|
31 | $ChunkSize = getid3_lib::BigEndian2Int(substr($ChunkData, 4, 4)); |
---|
32 | |
---|
33 | if ($ChunkName == '.ra'."\xFD") { |
---|
34 | $ChunkData .= fread($fd, $ChunkSize - 8); |
---|
35 | if ($this->ParseOldRAheader(substr($ChunkData, 0, 128), $ThisFileInfo['real']['old_ra_header'])) { |
---|
36 | $ThisFileInfo['audio']['dataformat'] = 'real'; |
---|
37 | $ThisFileInfo['audio']['lossless'] = false; |
---|
38 | $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['real']['old_ra_header']['sample_rate']; |
---|
39 | $ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['real']['old_ra_header']['bits_per_sample']; |
---|
40 | $ThisFileInfo['audio']['channels'] = $ThisFileInfo['real']['old_ra_header']['channels']; |
---|
41 | |
---|
42 | $ThisFileInfo['playtime_seconds'] = 60 * ($ThisFileInfo['real']['old_ra_header']['audio_bytes'] / $ThisFileInfo['real']['old_ra_header']['bytes_per_minute']); |
---|
43 | $ThisFileInfo['audio']['bitrate'] = 8 * ($ThisFileInfo['real']['old_ra_header']['audio_bytes'] / $ThisFileInfo['playtime_seconds']); |
---|
44 | $ThisFileInfo['audio']['codec'] = $this->RealAudioCodecFourCClookup($ThisFileInfo['real']['old_ra_header']['fourcc'], $ThisFileInfo['audio']['bitrate']); |
---|
45 | |
---|
46 | foreach ($ThisFileInfo['real']['old_ra_header']['comments'] as $key => $valuearray) { |
---|
47 | if (strlen(trim($valuearray[0])) > 0) { |
---|
48 | $ThisFileInfo['real']['comments'][$key][] = trim($valuearray[0]); |
---|
49 | } |
---|
50 | } |
---|
51 | return true; |
---|
52 | } |
---|
53 | $ThisFileInfo['error'][] = 'There was a problem parsing this RealAudio file. Please submit it for analysis to http://www.getid3.org/upload/ or info@getid3.org'; |
---|
54 | unset($ThisFileInfo['bitrate']); |
---|
55 | unset($ThisFileInfo['playtime_seconds']); |
---|
56 | return false; |
---|
57 | } |
---|
58 | |
---|
59 | // shortcut |
---|
60 | $ThisFileInfo['real']['chunks'][$ChunkCounter] = array(); |
---|
61 | $thisfile_real_chunks_currentchunk = &$ThisFileInfo['real']['chunks'][$ChunkCounter]; |
---|
62 | |
---|
63 | $thisfile_real_chunks_currentchunk['name'] = $ChunkName; |
---|
64 | $thisfile_real_chunks_currentchunk['offset'] = ftell($fd) - 8; |
---|
65 | $thisfile_real_chunks_currentchunk['length'] = $ChunkSize; |
---|
66 | if (($thisfile_real_chunks_currentchunk['offset'] + $thisfile_real_chunks_currentchunk['length']) > $ThisFileInfo['avdataend']) { |
---|
67 | $ThisFileInfo['warning'][] = 'Chunk "'.$thisfile_real_chunks_currentchunk['name'].'" at offset '.$thisfile_real_chunks_currentchunk['offset'].' claims to be '.$thisfile_real_chunks_currentchunk['length'].' bytes long, which is beyond end of file'; |
---|
68 | return false; |
---|
69 | } |
---|
70 | |
---|
71 | if ($ChunkSize > (GETID3_FREAD_BUFFER_SIZE + 8)) { |
---|
72 | |
---|
73 | $ChunkData .= fread($fd, GETID3_FREAD_BUFFER_SIZE - 8); |
---|
74 | fseek($fd, $thisfile_real_chunks_currentchunk['offset'] + $ChunkSize, SEEK_SET); |
---|
75 | |
---|
76 | } elseif(($ChunkSize - 8) > 0) { |
---|
77 | |
---|
78 | $ChunkData .= fread($fd, $ChunkSize - 8); |
---|
79 | |
---|
80 | } |
---|
81 | $offset = 8; |
---|
82 | |
---|
83 | switch ($ChunkName) { |
---|
84 | |
---|
85 | case '.RMF': // RealMedia File Header |
---|
86 | $thisfile_real_chunks_currentchunk['object_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); |
---|
87 | $offset += 2; |
---|
88 | switch ($thisfile_real_chunks_currentchunk['object_version']) { |
---|
89 | |
---|
90 | case 0: |
---|
91 | $thisfile_real_chunks_currentchunk['file_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); |
---|
92 | $offset += 4; |
---|
93 | $thisfile_real_chunks_currentchunk['headers_count'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); |
---|
94 | $offset += 4; |
---|
95 | break; |
---|
96 | |
---|
97 | default: |
---|
98 | //$ThisFileInfo['warning'][] = 'Expected .RMF-object_version to be "0", actual value is "'.$thisfile_real_chunks_currentchunk['object_version'].'" (should not be a problem)'; |
---|
99 | break; |
---|
100 | |
---|
101 | } |
---|
102 | break; |
---|
103 | |
---|
104 | |
---|
105 | case 'PROP': // Properties Header |
---|
106 | $thisfile_real_chunks_currentchunk['object_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); |
---|
107 | $offset += 2; |
---|
108 | if ($thisfile_real_chunks_currentchunk['object_version'] == 0) { |
---|
109 | $thisfile_real_chunks_currentchunk['max_bit_rate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); |
---|
110 | $offset += 4; |
---|
111 | $thisfile_real_chunks_currentchunk['avg_bit_rate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); |
---|
112 | $offset += 4; |
---|
113 | $thisfile_real_chunks_currentchunk['max_packet_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); |
---|
114 | $offset += 4; |
---|
115 | $thisfile_real_chunks_currentchunk['avg_packet_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); |
---|
116 | $offset += 4; |
---|
117 | $thisfile_real_chunks_currentchunk['num_packets'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); |
---|
118 | $offset += 4; |
---|
119 | $thisfile_real_chunks_currentchunk['duration'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); |
---|
120 | $offset += 4; |
---|
121 | $thisfile_real_chunks_currentchunk['preroll'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); |
---|
122 | $offset += 4; |
---|
123 | $thisfile_real_chunks_currentchunk['index_offset'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); |
---|
124 | $offset += 4; |
---|
125 | $thisfile_real_chunks_currentchunk['data_offset'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); |
---|
126 | $offset += 4; |
---|
127 | $thisfile_real_chunks_currentchunk['num_streams'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); |
---|
128 | $offset += 2; |
---|
129 | $thisfile_real_chunks_currentchunk['flags_raw'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); |
---|
130 | $offset += 2; |
---|
131 | $ThisFileInfo['playtime_seconds'] = $thisfile_real_chunks_currentchunk['duration'] / 1000; |
---|
132 | if ($thisfile_real_chunks_currentchunk['duration'] > 0) { |
---|
133 | $ThisFileInfo['bitrate'] += $thisfile_real_chunks_currentchunk['avg_bit_rate']; |
---|
134 | } |
---|
135 | $thisfile_real_chunks_currentchunk['flags']['save_enabled'] = (bool) ($thisfile_real_chunks_currentchunk['flags_raw'] & 0x0001); |
---|
136 | $thisfile_real_chunks_currentchunk['flags']['perfect_play'] = (bool) ($thisfile_real_chunks_currentchunk['flags_raw'] & 0x0002); |
---|
137 | $thisfile_real_chunks_currentchunk['flags']['live_broadcast'] = (bool) ($thisfile_real_chunks_currentchunk['flags_raw'] & 0x0004); |
---|
138 | } |
---|
139 | break; |
---|
140 | |
---|
141 | case 'MDPR': // Media Properties Header |
---|
142 | $thisfile_real_chunks_currentchunk['object_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); |
---|
143 | $offset += 2; |
---|
144 | if ($thisfile_real_chunks_currentchunk['object_version'] == 0) { |
---|
145 | $thisfile_real_chunks_currentchunk['stream_number'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); |
---|
146 | $offset += 2; |
---|
147 | $thisfile_real_chunks_currentchunk['max_bit_rate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); |
---|
148 | $offset += 4; |
---|
149 | $thisfile_real_chunks_currentchunk['avg_bit_rate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); |
---|
150 | $offset += 4; |
---|
151 | $thisfile_real_chunks_currentchunk['max_packet_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); |
---|
152 | $offset += 4; |
---|
153 | $thisfile_real_chunks_currentchunk['avg_packet_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); |
---|
154 | $offset += 4; |
---|
155 | $thisfile_real_chunks_currentchunk['start_time'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); |
---|
156 | $offset += 4; |
---|
157 | $thisfile_real_chunks_currentchunk['preroll'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); |
---|
158 | $offset += 4; |
---|
159 | $thisfile_real_chunks_currentchunk['duration'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); |
---|
160 | $offset += 4; |
---|
161 | $thisfile_real_chunks_currentchunk['stream_name_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 1)); |
---|
162 | $offset += 1; |
---|
163 | $thisfile_real_chunks_currentchunk['stream_name'] = substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['stream_name_size']); |
---|
164 | $offset += $thisfile_real_chunks_currentchunk['stream_name_size']; |
---|
165 | $thisfile_real_chunks_currentchunk['mime_type_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 1)); |
---|
166 | $offset += 1; |
---|
167 | $thisfile_real_chunks_currentchunk['mime_type'] = substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['mime_type_size']); |
---|
168 | $offset += $thisfile_real_chunks_currentchunk['mime_type_size']; |
---|
169 | $thisfile_real_chunks_currentchunk['type_specific_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); |
---|
170 | $offset += 4; |
---|
171 | $thisfile_real_chunks_currentchunk['type_specific_data'] = substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['type_specific_len']); |
---|
172 | $offset += $thisfile_real_chunks_currentchunk['type_specific_len']; |
---|
173 | |
---|
174 | // shortcut |
---|
175 | $thisfile_real_chunks_currentchunk_typespecificdata = &$thisfile_real_chunks_currentchunk['type_specific_data']; |
---|
176 | |
---|
177 | switch ($thisfile_real_chunks_currentchunk['mime_type']) { |
---|
178 | case 'video/x-pn-realvideo': |
---|
179 | case 'video/x-pn-multirate-realvideo': |
---|
180 | // http://www.freelists.org/archives/matroska-devel/07-2003/msg00010.html |
---|
181 | |
---|
182 | // shortcut |
---|
183 | $thisfile_real_chunks_currentchunk['video_info'] = array(); |
---|
184 | $thisfile_real_chunks_currentchunk_videoinfo = &$thisfile_real_chunks_currentchunk['video_info']; |
---|
185 | |
---|
186 | $thisfile_real_chunks_currentchunk_videoinfo['dwSize'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 0, 4)); |
---|
187 | $thisfile_real_chunks_currentchunk_videoinfo['fourcc1'] = substr($thisfile_real_chunks_currentchunk_typespecificdata, 4, 4); |
---|
188 | $thisfile_real_chunks_currentchunk_videoinfo['fourcc2'] = substr($thisfile_real_chunks_currentchunk_typespecificdata, 8, 4); |
---|
189 | $thisfile_real_chunks_currentchunk_videoinfo['width'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 12, 2)); |
---|
190 | $thisfile_real_chunks_currentchunk_videoinfo['height'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 14, 2)); |
---|
191 | $thisfile_real_chunks_currentchunk_videoinfo['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 16, 2)); |
---|
192 | //$thisfile_real_chunks_currentchunk_videoinfo['unknown1'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 18, 2)); |
---|
193 | //$thisfile_real_chunks_currentchunk_videoinfo['unknown2'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 20, 2)); |
---|
194 | $thisfile_real_chunks_currentchunk_videoinfo['frames_per_second'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 22, 2)); |
---|
195 | //$thisfile_real_chunks_currentchunk_videoinfo['unknown3'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 24, 2)); |
---|
196 | //$thisfile_real_chunks_currentchunk_videoinfo['unknown4'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 26, 2)); |
---|
197 | //$thisfile_real_chunks_currentchunk_videoinfo['unknown5'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 28, 2)); |
---|
198 | //$thisfile_real_chunks_currentchunk_videoinfo['unknown6'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 30, 2)); |
---|
199 | //$thisfile_real_chunks_currentchunk_videoinfo['unknown7'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 32, 2)); |
---|
200 | //$thisfile_real_chunks_currentchunk_videoinfo['unknown8'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 34, 2)); |
---|
201 | //$thisfile_real_chunks_currentchunk_videoinfo['unknown9'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 36, 2)); |
---|
202 | |
---|
203 | $thisfile_real_chunks_currentchunk_videoinfo['codec'] = getid3_riff::RIFFfourccLookup($thisfile_real_chunks_currentchunk_videoinfo['fourcc2']); |
---|
204 | |
---|
205 | $ThisFileInfo['video']['resolution_x'] = $thisfile_real_chunks_currentchunk_videoinfo['width']; |
---|
206 | $ThisFileInfo['video']['resolution_y'] = $thisfile_real_chunks_currentchunk_videoinfo['height']; |
---|
207 | $ThisFileInfo['video']['frame_rate'] = (float) $thisfile_real_chunks_currentchunk_videoinfo['frames_per_second']; |
---|
208 | $ThisFileInfo['video']['codec'] = $thisfile_real_chunks_currentchunk_videoinfo['codec']; |
---|
209 | $ThisFileInfo['video']['bits_per_sample'] = $thisfile_real_chunks_currentchunk_videoinfo['bits_per_sample']; |
---|
210 | break; |
---|
211 | |
---|
212 | case 'audio/x-pn-realaudio': |
---|
213 | case 'audio/x-pn-multirate-realaudio': |
---|
214 | $this->ParseOldRAheader($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk['parsed_audio_data']); |
---|
215 | |
---|
216 | $ThisFileInfo['audio']['sample_rate'] = $thisfile_real_chunks_currentchunk['parsed_audio_data']['sample_rate']; |
---|
217 | $ThisFileInfo['audio']['bits_per_sample'] = $thisfile_real_chunks_currentchunk['parsed_audio_data']['bits_per_sample']; |
---|
218 | $ThisFileInfo['audio']['channels'] = $thisfile_real_chunks_currentchunk['parsed_audio_data']['channels']; |
---|
219 | if (!empty($ThisFileInfo['audio']['dataformat'])) { |
---|
220 | foreach ($ThisFileInfo['audio'] as $key => $value) { |
---|
221 | if ($key != 'streams') { |
---|
222 | $ThisFileInfo['audio']['streams'][$thisfile_real_chunks_currentchunk['stream_number']][$key] = $value; |
---|
223 | } |
---|
224 | } |
---|
225 | } |
---|
226 | break; |
---|
227 | |
---|
228 | case 'logical-fileinfo': |
---|
229 | // shortcut |
---|
230 | $thisfile_real_chunks_currentchunk['logical_fileinfo'] = array(); |
---|
231 | $thisfile_real_chunks_currentchunk_logicalfileinfo = &$thisfile_real_chunks_currentchunk['logical_fileinfo']; |
---|
232 | |
---|
233 | $thisfile_real_chunks_currentchunk_logicalfileinfo_offset = 0; |
---|
234 | $thisfile_real_chunks_currentchunk_logicalfileinfo['logical_fileinfo_length'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4)); |
---|
235 | $thisfile_real_chunks_currentchunk_logicalfileinfo_offset += 4; |
---|
236 | |
---|
237 | //$thisfile_real_chunks_currentchunk_logicalfileinfo['unknown1'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4)); |
---|
238 | $thisfile_real_chunks_currentchunk_logicalfileinfo_offset += 4; |
---|
239 | |
---|
240 | $thisfile_real_chunks_currentchunk_logicalfileinfo['num_tags'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4)); |
---|
241 | $thisfile_real_chunks_currentchunk_logicalfileinfo_offset += 4; |
---|
242 | |
---|
243 | //$thisfile_real_chunks_currentchunk_logicalfileinfo['unknown2'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4)); |
---|
244 | $thisfile_real_chunks_currentchunk_logicalfileinfo_offset += 4; |
---|
245 | |
---|
246 | //$thisfile_real_chunks_currentchunk_logicalfileinfo['d'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 1)); |
---|
247 | |
---|
248 | //$thisfile_real_chunks_currentchunk_logicalfileinfo['one_type'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4)); |
---|
249 | //$thisfile_real_chunks_currentchunk_logicalfileinfo_thislength = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 4 + $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 2)); |
---|
250 | //$thisfile_real_chunks_currentchunk_logicalfileinfo['one'] = substr($thisfile_real_chunks_currentchunk_typespecificdata, 6 + $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, $thisfile_real_chunks_currentchunk_logicalfileinfo_thislength); |
---|
251 | //$thisfile_real_chunks_currentchunk_logicalfileinfo_offset += (6 + $thisfile_real_chunks_currentchunk_logicalfileinfo_thislength); |
---|
252 | |
---|
253 | break; |
---|
254 | |
---|
255 | } |
---|
256 | |
---|
257 | |
---|
258 | if (empty($ThisFileInfo['playtime_seconds'])) { |
---|
259 | $ThisFileInfo['playtime_seconds'] = max($ThisFileInfo['playtime_seconds'], ($thisfile_real_chunks_currentchunk['duration'] + $thisfile_real_chunks_currentchunk['start_time']) / 1000); |
---|
260 | } |
---|
261 | if ($thisfile_real_chunks_currentchunk['duration'] > 0) { |
---|
262 | switch ($thisfile_real_chunks_currentchunk['mime_type']) { |
---|
263 | case 'audio/x-pn-realaudio': |
---|
264 | case 'audio/x-pn-multirate-realaudio': |
---|
265 | $ThisFileInfo['audio']['bitrate'] = (isset($ThisFileInfo['audio']['bitrate']) ? $ThisFileInfo['audio']['bitrate'] : 0) + $thisfile_real_chunks_currentchunk['avg_bit_rate']; |
---|
266 | $ThisFileInfo['audio']['codec'] = $this->RealAudioCodecFourCClookup($thisfile_real_chunks_currentchunk['parsed_audio_data']['fourcc'], $ThisFileInfo['audio']['bitrate']); |
---|
267 | $ThisFileInfo['audio']['dataformat'] = 'real'; |
---|
268 | $ThisFileInfo['audio']['lossless'] = false; |
---|
269 | break; |
---|
270 | |
---|
271 | case 'video/x-pn-realvideo': |
---|
272 | case 'video/x-pn-multirate-realvideo': |
---|
273 | $ThisFileInfo['video']['bitrate'] = (isset($ThisFileInfo['video']['bitrate']) ? $ThisFileInfo['video']['bitrate'] : 0) + $thisfile_real_chunks_currentchunk['avg_bit_rate']; |
---|
274 | $ThisFileInfo['video']['bitrate_mode'] = 'cbr'; |
---|
275 | $ThisFileInfo['video']['dataformat'] = 'real'; |
---|
276 | $ThisFileInfo['video']['lossless'] = false; |
---|
277 | $ThisFileInfo['video']['pixel_aspect_ratio'] = (float) 1; |
---|
278 | break; |
---|
279 | |
---|
280 | case 'audio/x-ralf-mpeg4-generic': |
---|
281 | $ThisFileInfo['audio']['bitrate'] = (isset($ThisFileInfo['audio']['bitrate']) ? $ThisFileInfo['audio']['bitrate'] : 0) + $thisfile_real_chunks_currentchunk['avg_bit_rate']; |
---|
282 | $ThisFileInfo['audio']['codec'] = 'RealAudio Lossless'; |
---|
283 | $ThisFileInfo['audio']['dataformat'] = 'real'; |
---|
284 | $ThisFileInfo['audio']['lossless'] = true; |
---|
285 | break; |
---|
286 | } |
---|
287 | $ThisFileInfo['bitrate'] = (isset($ThisFileInfo['video']['bitrate']) ? $ThisFileInfo['video']['bitrate'] : 0) + (isset($ThisFileInfo['audio']['bitrate']) ? $ThisFileInfo['audio']['bitrate'] : 0); |
---|
288 | } |
---|
289 | } |
---|
290 | break; |
---|
291 | |
---|
292 | case 'CONT': // Content Description Header (text comments) |
---|
293 | $thisfile_real_chunks_currentchunk['object_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); |
---|
294 | $offset += 2; |
---|
295 | if ($thisfile_real_chunks_currentchunk['object_version'] == 0) { |
---|
296 | $thisfile_real_chunks_currentchunk['title_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); |
---|
297 | $offset += 2; |
---|
298 | $thisfile_real_chunks_currentchunk['title'] = (string) substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['title_len']); |
---|
299 | $offset += $thisfile_real_chunks_currentchunk['title_len']; |
---|
300 | |
---|
301 | $thisfile_real_chunks_currentchunk['artist_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); |
---|
302 | $offset += 2; |
---|
303 | $thisfile_real_chunks_currentchunk['artist'] = (string) substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['artist_len']); |
---|
304 | $offset += $thisfile_real_chunks_currentchunk['artist_len']; |
---|
305 | |
---|
306 | $thisfile_real_chunks_currentchunk['copyright_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); |
---|
307 | $offset += 2; |
---|
308 | $thisfile_real_chunks_currentchunk['copyright'] = (string) substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['copyright_len']); |
---|
309 | $offset += $thisfile_real_chunks_currentchunk['copyright_len']; |
---|
310 | |
---|
311 | $thisfile_real_chunks_currentchunk['comment_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); |
---|
312 | $offset += 2; |
---|
313 | $thisfile_real_chunks_currentchunk['comment'] = (string) substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['comment_len']); |
---|
314 | $offset += $thisfile_real_chunks_currentchunk['comment_len']; |
---|
315 | |
---|
316 | |
---|
317 | $commentkeystocopy = array('title'=>'title', 'artist'=>'artist', 'copyright'=>'copyright', 'comment'=>'comment'); |
---|
318 | foreach ($commentkeystocopy as $key => $val) { |
---|
319 | if ($thisfile_real_chunks_currentchunk[$key]) { |
---|
320 | $ThisFileInfo['real']['comments'][$val][] = trim($thisfile_real_chunks_currentchunk[$key]); |
---|
321 | } |
---|
322 | } |
---|
323 | |
---|
324 | } |
---|
325 | break; |
---|
326 | |
---|
327 | |
---|
328 | case 'DATA': // Data Chunk Header |
---|
329 | // do nothing |
---|
330 | break; |
---|
331 | |
---|
332 | case 'INDX': // Index Section Header |
---|
333 | $thisfile_real_chunks_currentchunk['object_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); |
---|
334 | $offset += 2; |
---|
335 | if ($thisfile_real_chunks_currentchunk['object_version'] == 0) { |
---|
336 | $thisfile_real_chunks_currentchunk['num_indices'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); |
---|
337 | $offset += 4; |
---|
338 | $thisfile_real_chunks_currentchunk['stream_number'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); |
---|
339 | $offset += 2; |
---|
340 | $thisfile_real_chunks_currentchunk['next_index_header'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); |
---|
341 | $offset += 4; |
---|
342 | |
---|
343 | if ($thisfile_real_chunks_currentchunk['next_index_header'] == 0) { |
---|
344 | // last index chunk found, ignore rest of file |
---|
345 | break 2; |
---|
346 | } else { |
---|
347 | // non-last index chunk, seek to next index chunk (skipping actual index data) |
---|
348 | fseek($fd, $thisfile_real_chunks_currentchunk['next_index_header'], SEEK_SET); |
---|
349 | } |
---|
350 | } |
---|
351 | break; |
---|
352 | |
---|
353 | default: |
---|
354 | $ThisFileInfo['warning'][] = 'Unhandled RealMedia chunk "'.$ChunkName.'" at offset '.$thisfile_real_chunks_currentchunk['offset']; |
---|
355 | break; |
---|
356 | } |
---|
357 | $ChunkCounter++; |
---|
358 | } |
---|
359 | |
---|
360 | if (!empty($ThisFileInfo['audio']['streams'])) { |
---|
361 | $ThisFileInfo['audio']['bitrate'] = 0; |
---|
362 | foreach ($ThisFileInfo['audio']['streams'] as $key => $valuearray) { |
---|
363 | $ThisFileInfo['audio']['bitrate'] += $valuearray['bitrate']; |
---|
364 | } |
---|
365 | } |
---|
366 | |
---|
367 | return true; |
---|
368 | } |
---|
369 | |
---|
370 | |
---|
371 | function ParseOldRAheader($OldRAheaderData, &$ParsedArray) { |
---|
372 | // http://www.freelists.org/archives/matroska-devel/07-2003/msg00010.html |
---|
373 | |
---|
374 | $ParsedArray = array(); |
---|
375 | $ParsedArray['magic'] = substr($OldRAheaderData, 0, 4); |
---|
376 | if ($ParsedArray['magic'] != '.ra'."\xFD") { |
---|
377 | return false; |
---|
378 | } |
---|
379 | $ParsedArray['version1'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 4, 2)); |
---|
380 | |
---|
381 | if ($ParsedArray['version1'] < 3) { |
---|
382 | |
---|
383 | return false; |
---|
384 | |
---|
385 | } elseif ($ParsedArray['version1'] == 3) { |
---|
386 | |
---|
387 | $ParsedArray['fourcc1'] = '.ra3'; |
---|
388 | $ParsedArray['bits_per_sample'] = 16; // hard-coded for old versions? |
---|
389 | $ParsedArray['sample_rate'] = 8000; // hard-coded for old versions? |
---|
390 | |
---|
391 | $ParsedArray['header_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 6, 2)); |
---|
392 | $ParsedArray['channels'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 8, 2)); // always 1 (?) |
---|
393 | //$ParsedArray['unknown1'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 10, 2)); |
---|
394 | //$ParsedArray['unknown2'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 12, 2)); |
---|
395 | //$ParsedArray['unknown3'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 14, 2)); |
---|
396 | $ParsedArray['bytes_per_minute'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 16, 2)); |
---|
397 | $ParsedArray['audio_bytes'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 18, 4)); |
---|
398 | $ParsedArray['comments_raw'] = substr($OldRAheaderData, 22, $ParsedArray['header_size'] - 22 + 1); // not including null terminator |
---|
399 | |
---|
400 | $commentoffset = 0; |
---|
401 | $commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1)); |
---|
402 | $ParsedArray['comments']['title'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength); |
---|
403 | $commentoffset += $commentlength; |
---|
404 | |
---|
405 | $commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1)); |
---|
406 | $ParsedArray['comments']['artist'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength); |
---|
407 | $commentoffset += $commentlength; |
---|
408 | |
---|
409 | $commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1)); |
---|
410 | $ParsedArray['comments']['copyright'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength); |
---|
411 | $commentoffset += $commentlength; |
---|
412 | |
---|
413 | $commentoffset++; // final null terminator (?) |
---|
414 | $commentoffset++; // fourcc length (?) should be 4 |
---|
415 | $ParsedArray['fourcc'] = substr($OldRAheaderData, 23 + $commentoffset, 4); |
---|
416 | |
---|
417 | } elseif ($ParsedArray['version1'] <= 5) { |
---|
418 | |
---|
419 | //$ParsedArray['unknown1'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 6, 2)); |
---|
420 | $ParsedArray['fourcc1'] = substr($OldRAheaderData, 8, 4); |
---|
421 | $ParsedArray['file_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 12, 4)); |
---|
422 | $ParsedArray['version2'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 16, 2)); |
---|
423 | $ParsedArray['header_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 18, 4)); |
---|
424 | $ParsedArray['codec_flavor_id'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 22, 2)); |
---|
425 | $ParsedArray['coded_frame_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 24, 4)); |
---|
426 | $ParsedArray['audio_bytes'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 28, 4)); |
---|
427 | $ParsedArray['bytes_per_minute'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 32, 4)); |
---|
428 | //$ParsedArray['unknown5'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 36, 4)); |
---|
429 | $ParsedArray['sub_packet_h'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 40, 2)); |
---|
430 | $ParsedArray['frame_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 42, 2)); |
---|
431 | $ParsedArray['sub_packet_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 44, 2)); |
---|
432 | //$ParsedArray['unknown6'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 46, 2)); |
---|
433 | |
---|
434 | switch ($ParsedArray['version1']) { |
---|
435 | |
---|
436 | case 4: |
---|
437 | $ParsedArray['sample_rate'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 48, 2)); |
---|
438 | //$ParsedArray['unknown8'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 50, 2)); |
---|
439 | $ParsedArray['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 52, 2)); |
---|
440 | $ParsedArray['channels'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 54, 2)); |
---|
441 | $ParsedArray['length_fourcc2'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 56, 1)); |
---|
442 | $ParsedArray['fourcc2'] = substr($OldRAheaderData, 57, 4); |
---|
443 | $ParsedArray['length_fourcc3'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 61, 1)); |
---|
444 | $ParsedArray['fourcc3'] = substr($OldRAheaderData, 62, 4); |
---|
445 | //$ParsedArray['unknown9'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 66, 1)); |
---|
446 | //$ParsedArray['unknown10'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 67, 2)); |
---|
447 | $ParsedArray['comments_raw'] = substr($OldRAheaderData, 69, $ParsedArray['header_size'] - 69 + 16); |
---|
448 | |
---|
449 | $commentoffset = 0; |
---|
450 | $commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1)); |
---|
451 | $ParsedArray['comments']['title'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength); |
---|
452 | $commentoffset += $commentlength; |
---|
453 | |
---|
454 | $commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1)); |
---|
455 | $ParsedArray['comments']['artist'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength); |
---|
456 | $commentoffset += $commentlength; |
---|
457 | |
---|
458 | $commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1)); |
---|
459 | $ParsedArray['comments']['copyright'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength); |
---|
460 | $commentoffset += $commentlength; |
---|
461 | break; |
---|
462 | |
---|
463 | case 5: |
---|
464 | $ParsedArray['sample_rate'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 48, 4)); |
---|
465 | $ParsedArray['sample_rate2'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 52, 4)); |
---|
466 | $ParsedArray['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 56, 4)); |
---|
467 | $ParsedArray['channels'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 60, 2)); |
---|
468 | $ParsedArray['genr'] = substr($OldRAheaderData, 62, 4); |
---|
469 | $ParsedArray['fourcc3'] = substr($OldRAheaderData, 66, 4); |
---|
470 | $ParsedArray['comments'] = array(); |
---|
471 | break; |
---|
472 | } |
---|
473 | $ParsedArray['fourcc'] = $ParsedArray['fourcc3']; |
---|
474 | |
---|
475 | } |
---|
476 | foreach ($ParsedArray['comments'] as $key => $value) { |
---|
477 | if ($ParsedArray['comments'][$key][0] === false) { |
---|
478 | $ParsedArray['comments'][$key][0] = ''; |
---|
479 | } |
---|
480 | } |
---|
481 | |
---|
482 | return true; |
---|
483 | } |
---|
484 | |
---|
485 | function RealAudioCodecFourCClookup($fourcc, $bitrate) { |
---|
486 | static $RealAudioCodecFourCClookup = array(); |
---|
487 | if (empty($RealAudioCodecFourCClookup)) { |
---|
488 | // http://www.its.msstate.edu/net/real/reports/config/tags.stats |
---|
489 | // http://www.freelists.org/archives/matroska-devel/06-2003/fullthread18.html |
---|
490 | |
---|
491 | $RealAudioCodecFourCClookup['14_4'][8000] = 'RealAudio v2 (14.4kbps)'; |
---|
492 | $RealAudioCodecFourCClookup['14.4'][8000] = 'RealAudio v2 (14.4kbps)'; |
---|
493 | $RealAudioCodecFourCClookup['lpcJ'][8000] = 'RealAudio v2 (14.4kbps)'; |
---|
494 | $RealAudioCodecFourCClookup['28_8'][15200] = 'RealAudio v2 (28.8kbps)'; |
---|
495 | $RealAudioCodecFourCClookup['28.8'][15200] = 'RealAudio v2 (28.8kbps)'; |
---|
496 | $RealAudioCodecFourCClookup['sipr'][4933] = 'RealAudio v4 (5kbps Voice)'; |
---|
497 | $RealAudioCodecFourCClookup['sipr'][6444] = 'RealAudio v4 (6.5kbps Voice)'; |
---|
498 | $RealAudioCodecFourCClookup['sipr'][8444] = 'RealAudio v4 (8.5kbps Voice)'; |
---|
499 | $RealAudioCodecFourCClookup['sipr'][16000] = 'RealAudio v4 (16kbps Wideband)'; |
---|
500 | $RealAudioCodecFourCClookup['dnet'][8000] = 'RealAudio v3 (8kbps Music)'; |
---|
501 | $RealAudioCodecFourCClookup['dnet'][16000] = 'RealAudio v3 (16kbps Music Low Response)'; |
---|
502 | $RealAudioCodecFourCClookup['dnet'][15963] = 'RealAudio v3 (16kbps Music Mid/High Response)'; |
---|
503 | $RealAudioCodecFourCClookup['dnet'][20000] = 'RealAudio v3 (20kbps Music Stereo)'; |
---|
504 | $RealAudioCodecFourCClookup['dnet'][32000] = 'RealAudio v3 (32kbps Music Mono)'; |
---|
505 | $RealAudioCodecFourCClookup['dnet'][31951] = 'RealAudio v3 (32kbps Music Stereo)'; |
---|
506 | $RealAudioCodecFourCClookup['dnet'][39965] = 'RealAudio v3 (40kbps Music Mono)'; |
---|
507 | $RealAudioCodecFourCClookup['dnet'][40000] = 'RealAudio v3 (40kbps Music Stereo)'; |
---|
508 | $RealAudioCodecFourCClookup['dnet'][79947] = 'RealAudio v3 (80kbps Music Mono)'; |
---|
509 | $RealAudioCodecFourCClookup['dnet'][80000] = 'RealAudio v3 (80kbps Music Stereo)'; |
---|
510 | |
---|
511 | $RealAudioCodecFourCClookup['dnet'][0] = 'RealAudio v3'; |
---|
512 | $RealAudioCodecFourCClookup['sipr'][0] = 'RealAudio v4'; |
---|
513 | $RealAudioCodecFourCClookup['cook'][0] = 'RealAudio G2'; |
---|
514 | $RealAudioCodecFourCClookup['atrc'][0] = 'RealAudio 8'; |
---|
515 | } |
---|
516 | $roundbitrate = intval(round($bitrate)); |
---|
517 | if (isset($RealAudioCodecFourCClookup[$fourcc][$roundbitrate])) { |
---|
518 | return $RealAudioCodecFourCClookup[$fourcc][$roundbitrate]; |
---|
519 | } elseif (isset($RealAudioCodecFourCClookup[$fourcc][0])) { |
---|
520 | return $RealAudioCodecFourCClookup[$fourcc][0]; |
---|
521 | } |
---|
522 | return $fourcc; |
---|
523 | } |
---|
524 | |
---|
525 | } |
---|
526 | |
---|
527 | |
---|
528 | ?> |
---|