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