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