Mercurial > judyates
comparison e2gallerypro/e2upload/Backend/Assets/getid3/module.audio-video.quicktime.php @ 3:3f6b44aa6b35 judyates
[svn r4] added ability to buy stuff, from a Prints page, but it doesn't work well with the css, and it also has not been fitted into the perl make system.
author | rlm |
---|---|
date | Mon, 22 Feb 2010 08:02:39 -0500 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
2:670229c4eb4b | 3:3f6b44aa6b35 |
---|---|
1 <?php | |
2 // +----------------------------------------------------------------------+ | |
3 // | PHP version 5 | | |
4 // +----------------------------------------------------------------------+ | |
5 // | Copyright (c) 2002-2006 James Heinrich, Allan Hansen | | |
6 // +----------------------------------------------------------------------+ | |
7 // | This source file is subject to version 2 of the GPL license, | | |
8 // | that is bundled with this package in the file license.txt and is | | |
9 // | available through the world-wide-web at the following url: | | |
10 // | http://www.gnu.org/copyleft/gpl.html | | |
11 // +----------------------------------------------------------------------+ | |
12 // | getID3() - http://getid3.sourceforge.net or http://www.getid3.org | | |
13 // +----------------------------------------------------------------------+ | |
14 // | Authors: James Heinrich <infoØgetid3*org> | | |
15 // | Allan Hansen <ahØartemis*dk> | | |
16 // +----------------------------------------------------------------------+ | |
17 // | module.audio-video.quicktime.php | | |
18 // | Module for analyzing Quicktime, MP3-in-MP4 and Apple Lossless files. | | |
19 // | dependencies: module.audio.mp3.php | | |
20 // | zlib support in PHP (optional) | | |
21 // +----------------------------------------------------------------------+ | |
22 // | |
23 // $Id: module.audio-video.quicktime.php,v 1.7 2006/11/02 16:03:28 ah Exp $ | |
24 | |
25 | |
26 | |
27 class getid3_quicktime extends getid3_handler | |
28 { | |
29 | |
30 public function Analyze() { | |
31 | |
32 $getid3 = $this->getid3; | |
33 | |
34 $info = &$getid3->info; | |
35 | |
36 $getid3->include_module('audio.mp3'); | |
37 | |
38 $info['quicktime'] = array (); | |
39 $info_quicktime = &$info['quicktime']; | |
40 | |
41 $info['fileformat'] = 'quicktime'; | |
42 $info_quicktime['hinting'] = false; | |
43 | |
44 fseek($getid3->fp, $info['avdataoffset'], SEEK_SET); | |
45 | |
46 $offset = $atom_counter = 0; | |
47 | |
48 while ($offset < $info['avdataend']) { | |
49 | |
50 fseek($getid3->fp, $offset, SEEK_SET); | |
51 $atom_header = fread($getid3->fp, 8); | |
52 | |
53 $atom_size = getid3_lib::BigEndian2Int(substr($atom_header, 0, 4)); | |
54 $atom_name = substr($atom_header, 4, 4); | |
55 | |
56 $info_quicktime[$atom_name]['name'] = $atom_name; | |
57 $info_quicktime[$atom_name]['size'] = $atom_size; | |
58 $info_quicktime[$atom_name]['offset'] = $offset; | |
59 | |
60 if (($offset + $atom_size) > $info['avdataend']) { | |
61 throw new getid3_exception('Atom at offset '.$offset.' claims to go beyond end-of-file (length: '.$atom_size.' bytes)'); | |
62 } | |
63 | |
64 if ($atom_size == 0) { | |
65 // Furthermore, for historical reasons the list of atoms is optionally | |
66 // terminated by a 32-bit integer set to 0. If you are writing a program | |
67 // to read user data atoms, you should allow for the terminating 0. | |
68 break; | |
69 } | |
70 | |
71 switch ($atom_name) { | |
72 | |
73 case 'mdat': // Media DATa atom | |
74 // 'mdat' contains the actual data for the audio/video | |
75 if (($atom_size > 8) && (!isset($info['avdataend_tmp']) || ($info_quicktime[$atom_name]['size'] > ($info['avdataend_tmp'] - $info['avdataoffset'])))) { | |
76 | |
77 $info['avdataoffset'] = $info_quicktime[$atom_name]['offset'] + 8; | |
78 $old_av_data_end = $info['avdataend']; | |
79 $info['avdataend'] = $info_quicktime[$atom_name]['offset'] + $info_quicktime[$atom_name]['size']; | |
80 | |
81 | |
82 //// MP3 | |
83 | |
84 if (!$getid3->include_module_optional('audio.mp3')) { | |
85 $getid3->warning('MP3 skipped because mpeg module is missing.'); | |
86 } | |
87 | |
88 else { | |
89 | |
90 // Clone getid3 - messing with offsets - better safe than sorry | |
91 $clone = clone $getid3; | |
92 | |
93 if (getid3_mp3::MPEGaudioHeaderValid(getid3_mp3::MPEGaudioHeaderDecode(fread($clone->fp, 4)))) { | |
94 | |
95 $mp3 = new getid3_mp3($clone); | |
96 $mp3->AnalyzeMPEGaudioInfo(); | |
97 | |
98 // Import from clone and destroy | |
99 if (isset($clone->info['mpeg']['audio'])) { | |
100 | |
101 $info['mpeg']['audio'] = $clone->info['mpeg']['audio']; | |
102 | |
103 $info['audio']['dataformat'] = 'mp3'; | |
104 $info['audio']['codec'] = (!empty($info['mpeg']['audio']['encoder']) ? $info['mpeg']['audio']['encoder'] : (!empty($info['mpeg']['audio']['codec']) ? $info['mpeg']['audio']['codec'] : (!empty($info['mpeg']['audio']['LAME']) ? 'LAME' :'mp3'))); | |
105 $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate']; | |
106 $info['audio']['channels'] = $info['mpeg']['audio']['channels']; | |
107 $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate']; | |
108 $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']); | |
109 $info['bitrate'] = $info['audio']['bitrate']; | |
110 | |
111 $getid3->warning($clone->warnings()); | |
112 unset($clone); | |
113 } | |
114 } | |
115 } | |
116 | |
117 $info['avdataend'] = $old_av_data_end; | |
118 unset($old_av_data_end); | |
119 | |
120 } | |
121 break; | |
122 | |
123 | |
124 case 'free': // FREE space atom | |
125 case 'skip': // SKIP atom | |
126 case 'wide': // 64-bit expansion placeholder atom | |
127 // 'free', 'skip' and 'wide' are just padding, contains no useful data at all | |
128 break; | |
129 | |
130 | |
131 default: | |
132 $atom_hierarchy = array (); | |
133 $info_quicktime[$atom_name] = $this->QuicktimeParseAtom($atom_name, $atom_size, fread($getid3->fp, $atom_size), $offset, $atom_hierarchy); | |
134 break; | |
135 } | |
136 | |
137 $offset += $atom_size; | |
138 $atom_counter++; | |
139 } | |
140 | |
141 if (!empty($info['avdataend_tmp'])) { | |
142 // this value is assigned to a temp value and then erased because | |
143 // otherwise any atoms beyond the 'mdat' atom would not get parsed | |
144 $info['avdataend'] = $info['avdataend_tmp']; | |
145 unset($info['avdataend_tmp']); | |
146 } | |
147 | |
148 if (!isset($info['bitrate']) && isset($info['playtime_seconds'])) { | |
149 $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; | |
150 } | |
151 | |
152 if (isset($info['bitrate']) && !isset($info['audio']['bitrate']) && !isset($info_quicktime['video'])) { | |
153 $info['audio']['bitrate'] = $info['bitrate']; | |
154 } | |
155 | |
156 if ((@$info['audio']['dataformat'] == 'mp4') && empty($info['video']['resolution_x'])) { | |
157 $info['fileformat'] = 'mp4'; | |
158 $info['mime_type'] = 'audio/mp4'; | |
159 unset($info['video']['dataformat']); | |
160 } | |
161 | |
162 if (!$getid3->option_extra_info) { | |
163 unset($info_quicktime['moov']); | |
164 } | |
165 | |
166 if (empty($info['audio']['dataformat']) && !empty($info_quicktime['audio'])) { | |
167 $info['audio']['dataformat'] = 'quicktime'; | |
168 } | |
169 | |
170 if (empty($info['video']['dataformat']) && !empty($info_quicktime['video'])) { | |
171 $info['video']['dataformat'] = 'quicktime'; | |
172 } | |
173 | |
174 return true; | |
175 } | |
176 | |
177 | |
178 | |
179 private function QuicktimeParseAtom($atom_name, $atom_size, $atom_data, $base_offset, &$atom_hierarchy) { | |
180 | |
181 // http://developer.apple.com/techpubs/quicktime/qtdevdocs/APIREF/INDEX/atomalphaindex.htm | |
182 | |
183 $getid3 = $this->getid3; | |
184 | |
185 $info = &$getid3->info; | |
186 $info_quicktime = &$info['quicktime']; | |
187 | |
188 array_push($atom_hierarchy, $atom_name); | |
189 $atom_structure['hierarchy'] = implode(' ', $atom_hierarchy); | |
190 $atom_structure['name'] = $atom_name; | |
191 $atom_structure['size'] = $atom_size; | |
192 $atom_structure['offset'] = $base_offset; | |
193 | |
194 switch ($atom_name) { | |
195 case 'moov': // MOVie container atom | |
196 case 'trak': // TRAcK container atom | |
197 case 'clip': // CLIPping container atom | |
198 case 'matt': // track MATTe container atom | |
199 case 'edts': // EDiTS container atom | |
200 case 'tref': // Track REFerence container atom | |
201 case 'mdia': // MeDIA container atom | |
202 case 'minf': // Media INFormation container atom | |
203 case 'dinf': // Data INFormation container atom | |
204 case 'udta': // User DaTA container atom | |
205 case 'stbl': // Sample TaBLe container atom | |
206 case 'cmov': // Compressed MOVie container atom | |
207 case 'rmra': // Reference Movie Record Atom | |
208 case 'rmda': // Reference Movie Descriptor Atom | |
209 case 'gmhd': // Generic Media info HeaDer atom (seen on QTVR) | |
210 $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $base_offset + 8, $atom_hierarchy); | |
211 break; | |
212 | |
213 | |
214 case '©cpy': | |
215 case '©day': | |
216 case '©dir': | |
217 case '©ed1': | |
218 case '©ed2': | |
219 case '©ed3': | |
220 case '©ed4': | |
221 case '©ed5': | |
222 case '©ed6': | |
223 case '©ed7': | |
224 case '©ed8': | |
225 case '©ed9': | |
226 case '©fmt': | |
227 case '©inf': | |
228 case '©prd': | |
229 case '©prf': | |
230 case '©req': | |
231 case '©src': | |
232 case '©wrt': | |
233 case '©nam': | |
234 case '©cmt': | |
235 case '©wrn': | |
236 case '©hst': | |
237 case '©mak': | |
238 case '©mod': | |
239 case '©PRD': | |
240 case '©swr': | |
241 case '©aut': | |
242 case '©ART': | |
243 case '©trk': | |
244 case '©alb': | |
245 case '©com': | |
246 case '©gen': | |
247 case '©ope': | |
248 case '©url': | |
249 case '©enc': | |
250 $atom_structure['data_length'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2)); | |
251 $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2)); | |
252 $atom_structure['data'] = substr($atom_data, 4); | |
253 | |
254 $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']); | |
255 if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) { | |
256 $info['comments']['language'][] = $atom_structure['language']; | |
257 } | |
258 $this->CopyToAppropriateCommentsSection($atom_name, $atom_structure['data']); | |
259 break; | |
260 | |
261 | |
262 case 'play': // auto-PLAY atom | |
263 $atom_structure['autoplay'] = (bool)getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); | |
264 | |
265 $info_quicktime['autoplay'] = $atom_structure['autoplay']; | |
266 break; | |
267 | |
268 | |
269 case 'WLOC': // Window LOCation atom | |
270 $atom_structure['location_x'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2)); | |
271 $atom_structure['location_y'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2)); | |
272 break; | |
273 | |
274 | |
275 case 'LOOP': // LOOPing atom | |
276 case 'SelO': // play SELection Only atom | |
277 case 'AllF': // play ALL Frames atom | |
278 $atom_structure['data'] = getid3_lib::BigEndian2Int($atom_data); | |
279 break; | |
280 | |
281 | |
282 case 'name': // | |
283 case 'MCPS': // Media Cleaner PRo | |
284 case '@PRM': // adobe PReMiere version | |
285 case '@PRQ': // adobe PRemiere Quicktime version | |
286 $atom_structure['data'] = $atom_data; | |
287 break; | |
288 | |
289 | |
290 case 'cmvd': // Compressed MooV Data atom | |
291 // Code by ubergeekØubergeek*tv based on information from | |
292 // http://developer.apple.com/quicktime/icefloe/dispatch012.html | |
293 $atom_structure['unCompressedSize'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); | |
294 | |
295 $compressed_file_data = substr($atom_data, 4); | |
296 if (!function_exists('gzuncompress')) { | |
297 $getid3->warning('PHP does not have zlib support - cannot decompress MOV atom at offset '.$atom_structure['offset']); | |
298 } | |
299 elseif ($uncompressed_header = @gzuncompress($compressed_file_data)) { | |
300 $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($uncompressed_header, 0, $atom_hierarchy); | |
301 } else { | |
302 $getid3->warning('Error decompressing compressed MOV atom at offset '.$atom_structure['offset']); | |
303 } | |
304 break; | |
305 | |
306 | |
307 case 'dcom': // Data COMpression atom | |
308 $atom_structure['compression_id'] = $atom_data; | |
309 $atom_structure['compression_text'] = getid3_quicktime::QuicktimeDCOMLookup($atom_data); | |
310 break; | |
311 | |
312 | |
313 case 'rdrf': // Reference movie Data ReFerence atom | |
314 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, | |
315 array ( | |
316 'version' => 1, | |
317 'flags_raw' => 3, | |
318 'reference_type_name' => -4, | |
319 'reference_length' => 4, | |
320 ) | |
321 ); | |
322 | |
323 $atom_structure['flags']['internal_data'] = (bool)($atom_structure['flags_raw'] & 0x000001); | |
324 | |
325 switch ($atom_structure['reference_type_name']) { | |
326 case 'url ': | |
327 $atom_structure['url'] = $this->NoNullString(substr($atom_data, 12)); | |
328 break; | |
329 | |
330 case 'alis': | |
331 $atom_structure['file_alias'] = substr($atom_data, 12); | |
332 break; | |
333 | |
334 case 'rsrc': | |
335 $atom_structure['resource_alias'] = substr($atom_data, 12); | |
336 break; | |
337 | |
338 default: | |
339 $atom_structure['data'] = substr($atom_data, 12); | |
340 break; | |
341 } | |
342 break; | |
343 | |
344 | |
345 case 'rmqu': // Reference Movie QUality atom | |
346 $atom_structure['movie_quality'] = getid3_lib::BigEndian2Int($atom_data); | |
347 break; | |
348 | |
349 | |
350 case 'rmcs': // Reference Movie Cpu Speed atom | |
351 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, | |
352 array ( | |
353 'version' => 1, | |
354 'flags_raw' => 3, // hardcoded: 0x0000 | |
355 'cpu_speed_rating' => 2 | |
356 ) | |
357 ); | |
358 break; | |
359 | |
360 | |
361 case 'rmvc': // Reference Movie Version Check atom | |
362 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, | |
363 array ( | |
364 'version' => 1, | |
365 'flags_raw' => 3, // hardcoded: 0x0000 | |
366 'gestalt_selector' => -4, | |
367 'gestalt_value_mask' => 4, | |
368 'gestalt_value' => 4, | |
369 'gestalt_check_type' => 2 | |
370 ) | |
371 ); | |
372 break; | |
373 | |
374 | |
375 case 'rmcd': // Reference Movie Component check atom | |
376 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, | |
377 array ( | |
378 'version' => 1, | |
379 'flags_raw' => 3, // hardcoded: 0x0000 | |
380 'component_type' => -4, | |
381 'component_subtype' => -4, | |
382 'component_manufacturer' => -4, | |
383 'component_flags_raw' => 4, | |
384 'component_flags_mask' => 4, | |
385 'component_min_version' => 4 | |
386 ) | |
387 ); | |
388 break; | |
389 | |
390 | |
391 case 'rmdr': // Reference Movie Data Rate atom | |
392 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, | |
393 array ( | |
394 'version' => 1, | |
395 'flags_raw' => 3, // hardcoded: 0x0000 | |
396 'data_rate' => 4 | |
397 ) | |
398 ); | |
399 | |
400 $atom_structure['data_rate_bps'] = $atom_structure['data_rate'] * 10; | |
401 break; | |
402 | |
403 | |
404 case 'rmla': // Reference Movie Language Atom | |
405 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, | |
406 array ( | |
407 'version' => 1, | |
408 'flags_raw' => 3, // hardcoded: 0x0000 | |
409 'language_id' => 2 | |
410 ) | |
411 ); | |
412 | |
413 $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']); | |
414 if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) { | |
415 $info['comments']['language'][] = $atom_structure['language']; | |
416 } | |
417 break; | |
418 | |
419 | |
420 case 'rmla': // Reference Movie Language Atom | |
421 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, | |
422 array ( | |
423 'version' => 1, | |
424 'flags_raw' => 3, // hardcoded: 0x0000 | |
425 'track_id' => 2 | |
426 ) | |
427 ); | |
428 break; | |
429 | |
430 | |
431 case 'ptv ': // Print To Video - defines a movie's full screen mode | |
432 // http://developer.apple.com/documentation/QuickTime/APIREF/SOURCESIV/at_ptv-_pg.htm | |
433 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, | |
434 array ( | |
435 'display_size_raw' => 2, | |
436 'reserved_1' => 2, // hardcoded: 0x0000 | |
437 'reserved_2' => 2, // hardcoded: 0x0000 | |
438 'slide_show_flag' => 1, | |
439 'play_on_open_flag' => 1 | |
440 ) | |
441 ); | |
442 | |
443 $atom_structure['flags']['play_on_open'] = (bool)$atom_structure['play_on_open_flag']; | |
444 $atom_structure['flags']['slide_show'] = (bool)$atom_structure['slide_show_flag']; | |
445 | |
446 $ptv_lookup[0] = 'normal'; | |
447 $ptv_lookup[1] = 'double'; | |
448 $ptv_lookup[2] = 'half'; | |
449 $ptv_lookup[3] = 'full'; | |
450 $ptv_lookup[4] = 'current'; | |
451 if (isset($ptv_lookup[$atom_structure['display_size_raw']])) { | |
452 $atom_structure['display_size'] = $ptv_lookup[$atom_structure['display_size_raw']]; | |
453 } else { | |
454 $getid3->warning('unknown "ptv " display constant ('.$atom_structure['display_size_raw'].')'); | |
455 } | |
456 break; | |
457 | |
458 | |
459 case 'stsd': // Sample Table Sample Description atom | |
460 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, | |
461 array ( | |
462 'version' => 1, | |
463 'flags_raw' => 3, // hardcoded: 0x0000 | |
464 'number_entries' => 4 | |
465 ) | |
466 ); | |
467 $stsd_entries_data_offset = 8; | |
468 for ($i = 0; $i < $atom_structure['number_entries']; $i++) { | |
469 | |
470 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure['sample_description_table'][$i], $atom_data, $stsd_entries_data_offset, | |
471 array ( | |
472 'size' => 4, | |
473 'data_format' => -4, | |
474 'reserved' => 6, | |
475 'reference_index' => 2 | |
476 ) | |
477 ); | |
478 | |
479 $atom_structure['sample_description_table'][$i]['data'] = substr($atom_data, 16+$stsd_entries_data_offset, ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2)); | |
480 $stsd_entries_data_offset += 16 + ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2); | |
481 | |
482 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure['sample_description_table'][$i], $atom_structure['sample_description_table'][$i]['data'], 0, | |
483 array ( | |
484 'encoder_version' => 2, | |
485 'encoder_revision' => 2, | |
486 'encoder_vendor' => -4 | |
487 ) | |
488 ); | |
489 | |
490 switch ($atom_structure['sample_description_table'][$i]['encoder_vendor']) { | |
491 | |
492 case "\x00\x00\x00\x00": | |
493 // audio atom | |
494 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure['sample_description_table'][$i], $atom_structure['sample_description_table'][$i]['data'], 8, | |
495 array ( | |
496 'audio_channels' => 2, | |
497 'audio_bit_depth' => 2, | |
498 'audio_compression_id' => 2, | |
499 'audio_packet_size' => 2 | |
500 ) | |
501 ); | |
502 | |
503 $atom_structure['sample_description_table'][$i]['audio_sample_rate'] = getid3_quicktime::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 16, 4)); | |
504 | |
505 switch ($atom_structure['sample_description_table'][$i]['data_format']) { | |
506 | |
507 case 'mp4v': | |
508 $info['fileformat'] = 'mp4'; | |
509 throw new getid3_exception('This version of getID3() does not fully support MPEG-4 audio/video streams'); | |
510 | |
511 case 'qtvr': | |
512 $info['video']['dataformat'] = 'quicktimevr'; | |
513 break; | |
514 | |
515 case 'mp4a': | |
516 default: | |
517 $info_quicktime['audio']['codec'] = $this->QuicktimeAudioCodecLookup($atom_structure['sample_description_table'][$i]['data_format']); | |
518 $info_quicktime['audio']['sample_rate'] = $atom_structure['sample_description_table'][$i]['audio_sample_rate']; | |
519 $info_quicktime['audio']['channels'] = $atom_structure['sample_description_table'][$i]['audio_channels']; | |
520 $info_quicktime['audio']['bit_depth'] = $atom_structure['sample_description_table'][$i]['audio_bit_depth']; | |
521 $info['audio']['codec'] = $info_quicktime['audio']['codec']; | |
522 $info['audio']['sample_rate'] = $info_quicktime['audio']['sample_rate']; | |
523 $info['audio']['channels'] = $info_quicktime['audio']['channels']; | |
524 $info['audio']['bits_per_sample'] = $info_quicktime['audio']['bit_depth']; | |
525 switch ($atom_structure['sample_description_table'][$i]['data_format']) { | |
526 case 'raw ': // PCM | |
527 case 'alac': // Apple Lossless Audio Codec | |
528 $info['audio']['lossless'] = true; | |
529 break; | |
530 default: | |
531 $info['audio']['lossless'] = false; | |
532 break; | |
533 } | |
534 break; | |
535 } | |
536 break; | |
537 | |
538 default: | |
539 switch ($atom_structure['sample_description_table'][$i]['data_format']) { | |
540 case 'mp4s': | |
541 $info['fileformat'] = 'mp4'; | |
542 break; | |
543 | |
544 default: | |
545 // video atom | |
546 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure['sample_description_table'][$i], $atom_structure['sample_description_table'][$i]['data'], 8, | |
547 array ( | |
548 'video_temporal_quality' => 4, | |
549 'video_spatial_quality' => 4, | |
550 'video_frame_width' => 2, | |
551 'video_frame_height' => 2 | |
552 ) | |
553 ); | |
554 $atom_structure['sample_description_table'][$i]['video_resolution_x'] = getid3_quicktime::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 20, 4)); | |
555 $atom_structure['sample_description_table'][$i]['video_resolution_y'] = getid3_quicktime::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 24, 4)); | |
556 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure['sample_description_table'][$i], $atom_structure['sample_description_table'][$i]['data'], 28, | |
557 array ( | |
558 'video_data_size' => 4, | |
559 'video_frame_count' => 2, | |
560 'video_encoder_name_len' => 1 | |
561 ) | |
562 ); | |
563 $atom_structure['sample_description_table'][$i]['video_encoder_name'] = substr($atom_structure['sample_description_table'][$i]['data'], 35, $atom_structure['sample_description_table'][$i]['video_encoder_name_len']); | |
564 $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 66, 2)); | |
565 $atom_structure['sample_description_table'][$i]['video_color_table_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 68, 2)); | |
566 | |
567 $atom_structure['sample_description_table'][$i]['video_pixel_color_type'] = (($atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color'); | |
568 $atom_structure['sample_description_table'][$i]['video_pixel_color_name'] = $this->QuicktimeColorNameLookup($atom_structure['sample_description_table'][$i]['video_pixel_color_depth']); | |
569 | |
570 if ($atom_structure['sample_description_table'][$i]['video_pixel_color_name'] != 'invalid') { | |
571 $info_quicktime['video']['codec_fourcc'] = $atom_structure['sample_description_table'][$i]['data_format']; | |
572 $info_quicktime['video']['codec_fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($atom_structure['sample_description_table'][$i]['data_format']); | |
573 $info_quicktime['video']['codec'] = $atom_structure['sample_description_table'][$i]['video_encoder_name']; | |
574 $info_quicktime['video']['color_depth'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_depth']; | |
575 $info_quicktime['video']['color_depth_name'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_name']; | |
576 | |
577 $info['video']['codec'] = $info_quicktime['video']['codec']; | |
578 $info['video']['bits_per_sample'] = $info_quicktime['video']['color_depth']; | |
579 } | |
580 $info['video']['lossless'] = false; | |
581 $info['video']['pixel_aspect_ratio'] = (float)1; | |
582 break; | |
583 } | |
584 break; | |
585 } | |
586 switch (strtolower($atom_structure['sample_description_table'][$i]['data_format'])) { | |
587 case 'mp4a': | |
588 $info['audio']['dataformat'] = $info_quicktime['audio']['codec'] = 'mp4'; | |
589 break; | |
590 | |
591 case '3ivx': | |
592 case '3iv1': | |
593 case '3iv2': | |
594 $info['video']['dataformat'] = '3ivx'; | |
595 break; | |
596 | |
597 case 'xvid': | |
598 $info['video']['dataformat'] = 'xvid'; | |
599 break; | |
600 | |
601 case 'mp4v': | |
602 $info['video']['dataformat'] = 'mpeg4'; | |
603 break; | |
604 | |
605 case 'divx': | |
606 case 'div1': | |
607 case 'div2': | |
608 case 'div3': | |
609 case 'div4': | |
610 case 'div5': | |
611 case 'div6': | |
612 //$TDIVXileInfo['video']['dataformat'] = 'divx'; | |
613 break; | |
614 | |
615 default: | |
616 // do nothing | |
617 break; | |
618 } | |
619 unset($atom_structure['sample_description_table'][$i]['data']); | |
620 } | |
621 break; | |
622 | |
623 | |
624 case 'stts': // Sample Table Time-to-Sample atom | |
625 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, | |
626 array ( | |
627 'version' => 1, | |
628 'flags_raw' => 3, // hardcoded: 0x0000 | |
629 'number_entries' => 4 | |
630 ) | |
631 ); | |
632 | |
633 $stts_entries_data_offset = 8; | |
634 $frame_rate_calculator_array = array (); | |
635 for ($i = 0; $i < $atom_structure['number_entries']; $i++) { | |
636 | |
637 $atom_structure['time_to_sample_table'][$i]['sample_count'] = getid3_lib::BigEndian2Int(substr($atom_data, $stts_entries_data_offset, 4)); | |
638 $stts_entries_data_offset += 4; | |
639 | |
640 $atom_structure['time_to_sample_table'][$i]['sample_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, $stts_entries_data_offset, 4)); | |
641 $stts_entries_data_offset += 4; | |
642 | |
643 if (!empty($info_quicktime['time_scale']) && (@$atoms_structure['time_to_sample_table'][$i]['sample_duration'] > 0)) { | |
644 | |
645 $stts_new_framerate = $info_quicktime['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration']; | |
646 if ($stts_new_framerate <= 60) { | |
647 // some atoms have durations of "1" giving a very large framerate, which probably is not right | |
648 $info['video']['frame_rate'] = max(@$info['video']['frame_rate'], $stts_new_framerate); | |
649 } | |
650 } | |
651 //@$frame_rate_calculator_array[($info_quicktime['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration'])] += $atom_structure['time_to_sample_table'][$i]['sample_count']; | |
652 } | |
653 /* | |
654 $stts_frames_total = 0; | |
655 $stts_seconds_total = 0; | |
656 foreach ($frame_rate_calculator_array as $frames_per_second => $frame_count) { | |
657 if (($frames_per_second > 60) || ($frames_per_second < 1)) { | |
658 // not video FPS information, probably audio information | |
659 $stts_frames_total = 0; | |
660 $stts_seconds_total = 0; | |
661 break; | |
662 } | |
663 $stts_frames_total += $frame_count; | |
664 $stts_seconds_total += $frame_count / $frames_per_second; | |
665 } | |
666 if (($stts_frames_total > 0) && ($stts_seconds_total > 0)) { | |
667 if (($stts_frames_total / $stts_seconds_total) > @$info['video']['frame_rate']) { | |
668 $info['video']['frame_rate'] = $stts_frames_total / $stts_seconds_total; | |
669 } | |
670 } | |
671 */ | |
672 break; | |
673 | |
674 | |
675 case 'stss': // Sample Table Sync Sample (key frames) atom | |
676 /* | |
677 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); | |
678 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 | |
679 $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); | |
680 $stss_entries_data_offset = 8; | |
681 for ($i = 0; $i < $atom_structure['number_entries']; $i++) { | |
682 $atom_structure['time_to_sample_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stss_entries_data_offset, 4)); | |
683 $stss_entries_data_offset += 4; | |
684 } | |
685 */ | |
686 break; | |
687 | |
688 | |
689 case 'stsc': // Sample Table Sample-to-Chunk atom | |
690 /* | |
691 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); | |
692 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 | |
693 $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); | |
694 $stsc_entries_data_offset = 8; | |
695 for ($i = 0; $i < $atom_structure['number_entries']; $i++) { | |
696 $atom_structure['sample_to_chunk_table'][$i]['first_chunk'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsc_entries_data_offset, 4)); | |
697 $stsc_entries_data_offset += 4; | |
698 $atom_structure['sample_to_chunk_table'][$i]['samples_per_chunk'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsc_entries_data_offset, 4)); | |
699 $stsc_entries_data_offset += 4; | |
700 $atom_structure['sample_to_chunk_table'][$i]['sample_description'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsc_entries_data_offset, 4)); | |
701 $stsc_entries_data_offset += 4; | |
702 } | |
703 */ | |
704 break; | |
705 | |
706 | |
707 case 'stsz': // Sample Table SiZe atom | |
708 /* | |
709 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); | |
710 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 | |
711 $atom_structure['sample_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); | |
712 $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4)); | |
713 $stsz_entries_data_offset = 12; | |
714 if ($atom_structure['sample_size'] == 0) { | |
715 for ($i = 0; $i < $atom_structure['number_entries']; $i++) { | |
716 $atom_structure['sample_size_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stsz_entries_data_offset, 4)); | |
717 $stsz_entries_data_offset += 4; | |
718 } | |
719 } | |
720 */ | |
721 break; | |
722 | |
723 | |
724 case 'stco': // Sample Table Chunk Offset atom | |
725 /* | |
726 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); | |
727 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 | |
728 $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); | |
729 $stco_entries_data_offset = 8; | |
730 for ($i = 0; $i < $atom_structure['number_entries']; $i++) { | |
731 $atom_structure['chunk_offset_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stco_entries_data_offset, 4)); | |
732 $stco_entries_data_offset += 4; | |
733 } | |
734 */ | |
735 break; | |
736 | |
737 | |
738 case 'dref': // Data REFerence atom | |
739 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, | |
740 array ( | |
741 'version' => 1, | |
742 'flags_raw' => 3, // hardcoded: 0x0000 | |
743 'number_entries' => 4 | |
744 ) | |
745 ); | |
746 | |
747 $dref_data_offset = 8; | |
748 for ($i = 0; $i < $atom_structure['number_entries']; $i++) { | |
749 | |
750 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure['data_references'][$i], $atom_data, $dref_data_offset, | |
751 array ( | |
752 'size' => 4, | |
753 'type' => -4, | |
754 'version' => 1, | |
755 'flags_raw' => 3 // hardcoded: 0x0000 | |
756 ) | |
757 ); | |
758 $dref_data_offset += 12; | |
759 | |
760 $atom_structure['data_references'][$i]['data'] = substr($atom_data, $dref_data_offset, ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3)); | |
761 $dref_data_offset += ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3); | |
762 | |
763 $atom_structure['data_references'][$i]['flags']['self_reference'] = (bool)($atom_structure['data_references'][$i]['flags_raw'] & 0x001); | |
764 } | |
765 break; | |
766 | |
767 | |
768 case 'gmin': // base Media INformation atom | |
769 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, | |
770 array ( | |
771 'version' => 1, | |
772 'flags_raw' => 3, // hardcoded: 0x0000 | |
773 'graphics_mode' => 2, | |
774 'opcolor_red' => 2, | |
775 'opcolor_green' => 2, | |
776 'opcolor_blue' => 2, | |
777 'balance' => 2, | |
778 'reserved' => 2 | |
779 ) | |
780 ); | |
781 break; | |
782 | |
783 | |
784 case 'smhd': // Sound Media information HeaDer atom | |
785 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, | |
786 array ( | |
787 'version' => 1, | |
788 'flags_raw' => 3, // hardcoded: 0x0000 | |
789 'balance' => 2, | |
790 'reserved' => 2 | |
791 ) | |
792 ); | |
793 break; | |
794 | |
795 | |
796 case 'vmhd': // Video Media information HeaDer atom | |
797 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, | |
798 array ( | |
799 'version' => 1, | |
800 'flags_raw' => 3, | |
801 'graphics_mode' => 2, | |
802 'opcolor_red' => 2, | |
803 'opcolor_green' => 2, | |
804 'opcolor_blue' => 2 | |
805 ) | |
806 ); | |
807 $atom_structure['flags']['no_lean_ahead'] = (bool)($atom_structure['flags_raw'] & 0x001); | |
808 break; | |
809 | |
810 | |
811 case 'hdlr': // HanDLeR reference atom | |
812 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, | |
813 array ( | |
814 'version' => 1, | |
815 'flags_raw' => 3, // hardcoded: 0x0000 | |
816 'component_type' => -4, | |
817 'component_subtype' => -4, | |
818 'component_manufacturer' => -4, | |
819 'component_flags_raw' => 4, | |
820 'component_flags_mask' => 4 | |
821 ) | |
822 ); | |
823 | |
824 $atom_structure['component_name'] = substr(substr($atom_data, 24), 1); /// Pascal2String | |
825 | |
826 if (($atom_structure['component_subtype'] == 'STpn') && ($atom_structure['component_manufacturer'] == 'zzzz')) { | |
827 $info['video']['dataformat'] = 'quicktimevr'; | |
828 } | |
829 break; | |
830 | |
831 | |
832 case 'mdhd': // MeDia HeaDer atom | |
833 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, | |
834 array ( | |
835 'version' => 1, | |
836 'flags_raw' => 3, // hardcoded: 0x0000 | |
837 'creation_time' => 4, | |
838 'modify_time' => 4, | |
839 'time_scale' => 4, | |
840 'duration' => 4, | |
841 'language_id' => 2, | |
842 'quality' => 2 | |
843 ) | |
844 ); | |
845 | |
846 if ($atom_structure['time_scale'] == 0) { | |
847 throw new getid3_exception('Corrupt Quicktime file: mdhd.time_scale == zero'); | |
848 } | |
849 $info_quicktime['time_scale'] = max(@$info['quicktime']['time_scale'], $atom_structure['time_scale']); | |
850 | |
851 $atom_structure['creation_time_unix'] = (int)($atom_structure['creation_time'] - 2082844800); // DateMac2Unix() | |
852 $atom_structure['modify_time_unix'] = (int)($atom_structure['modify_time'] - 2082844800); // DateMac2Unix() | |
853 $atom_structure['playtime_seconds'] = $atom_structure['duration'] / $atom_structure['time_scale']; | |
854 $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']); | |
855 if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) { | |
856 $info['comments']['language'][] = $atom_structure['language']; | |
857 } | |
858 break; | |
859 | |
860 | |
861 case 'pnot': // Preview atom | |
862 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, | |
863 array ( | |
864 'modification_date' => 4, // "standard Macintosh format" | |
865 'version_number' => 2, // hardcoded: 0x00 | |
866 'atom_type' => -4, // usually: 'PICT' | |
867 'atom_index' => 2 // usually: 0x01 | |
868 ) | |
869 ); | |
870 $atom_structure['modification_date_unix'] = (int)($atom_structure['modification_date'] - 2082844800); // DateMac2Unix() | |
871 break; | |
872 | |
873 | |
874 case 'crgn': // Clipping ReGioN atom | |
875 $atom_structure['region_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2)); // The Region size, Region boundary box, | |
876 $atom_structure['boundary_box'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 8)); // and Clipping region data fields | |
877 $atom_structure['clipping_data'] = substr($atom_data, 10); // constitute a QuickDraw region. | |
878 break; | |
879 | |
880 | |
881 case 'load': // track LOAD settings atom | |
882 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, | |
883 array ( | |
884 'preload_start_time' => 4, | |
885 'preload_duration' => 4, | |
886 'preload_flags_raw' => 4, | |
887 'default_hints_raw' => 4 | |
888 ) | |
889 ); | |
890 | |
891 $atom_structure['default_hints']['double_buffer'] = (bool)($atom_structure['default_hints_raw'] & 0x0020); | |
892 $atom_structure['default_hints']['high_quality'] = (bool)($atom_structure['default_hints_raw'] & 0x0100); | |
893 break; | |
894 | |
895 | |
896 case 'tmcd': // TiMe CoDe atom | |
897 case 'chap': // CHAPter list atom | |
898 case 'sync': // SYNChronization atom | |
899 case 'scpt': // tranSCriPT atom | |
900 case 'ssrc': // non-primary SouRCe atom | |
901 for ($i = 0; $i < (strlen($atom_data) % 4); $i++) { | |
902 $atom_structure['track_id'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $i * 4, 4)); | |
903 } | |
904 break; | |
905 | |
906 | |
907 case 'elst': // Edit LiST atom | |
908 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, | |
909 array ( | |
910 'version' => 1, | |
911 'flags_raw' => 3, // hardcoded: 0x0000 | |
912 'number_entries' => 4 | |
913 ) | |
914 ); | |
915 | |
916 for ($i = 0; $i < $atom_structure['number_entries']; $i++ ) { | |
917 $atom_structure['edit_list'][$i]['track_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($i * 12) + 0, 4)); | |
918 $atom_structure['edit_list'][$i]['media_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($i * 12) + 4, 4)); | |
919 $atom_structure['edit_list'][$i]['media_rate'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 8 + ($i * 12) + 8, 4)); | |
920 } | |
921 break; | |
922 | |
923 | |
924 case 'kmat': // compressed MATte atom | |
925 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); | |
926 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 | |
927 $atom_structure['matte_data_raw'] = substr($atom_data, 4); | |
928 break; | |
929 | |
930 | |
931 case 'ctab': // Color TABle atom | |
932 $atom_structure['color_table_seed'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); // hardcoded: 0x00000000 | |
933 $atom_structure['color_table_flags'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x8000 | |
934 $atom_structure['color_table_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2)) + 1; | |
935 for ($colortableentry = 0; $colortableentry < $atom_structure['color_table_size']; $colortableentry++) { | |
936 $atom_structure['color_table'][$colortableentry]['alpha'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 0, 2)); | |
937 $atom_structure['color_table'][$colortableentry]['red'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 2, 2)); | |
938 $atom_structure['color_table'][$colortableentry]['green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 4, 2)); | |
939 $atom_structure['color_table'][$colortableentry]['blue'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 6, 2)); | |
940 } | |
941 break; | |
942 | |
943 | |
944 case 'mvhd': // MoVie HeaDer atom | |
945 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, | |
946 array ( | |
947 'version' => 1, | |
948 'flags_raw' => 3, | |
949 'creation_time' => 4, | |
950 'modify_time' => 4, | |
951 'time_scale' => 4, | |
952 'duration' => 4 | |
953 ) | |
954 ); | |
955 | |
956 $atom_structure['preferred_rate'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 20, 4)); | |
957 $atom_structure['preferred_volume'] = getid3_quicktime::FixedPoint8_8(substr($atom_data, 24, 2)); | |
958 $atom_structure['reserved'] = substr($atom_data, 26, 10); | |
959 $atom_structure['matrix_a'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 36, 4)); | |
960 $atom_structure['matrix_b'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 40, 4)); | |
961 $atom_structure['matrix_u'] = getid3_quicktime::FixedPoint2_30(substr($atom_data, 44, 4)); | |
962 $atom_structure['matrix_c'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 48, 4)); | |
963 $atom_structure['matrix_d'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 52, 4)); | |
964 $atom_structure['matrix_v'] = getid3_quicktime::FixedPoint2_30(substr($atom_data, 56, 4)); | |
965 $atom_structure['matrix_x'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 60, 4)); | |
966 $atom_structure['matrix_y'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 64, 4)); | |
967 $atom_structure['matrix_w'] = getid3_quicktime::FixedPoint2_30(substr($atom_data, 68, 4)); | |
968 | |
969 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 72, | |
970 array ( | |
971 'preview_time' => 4, | |
972 'preview_duration' => 4, | |
973 'poster_time' => 4, | |
974 'selection_time' => 4, | |
975 'selection_duration' => 4, | |
976 'current_time' => 4, | |
977 'next_track_id' => 4 | |
978 ) | |
979 ); | |
980 | |
981 if ($atom_structure['time_scale'] == 0) { | |
982 throw new getid3_exception('Corrupt Quicktime file: mvhd.time_scale == zero'); | |
983 } | |
984 | |
985 $atom_structure['creation_time_unix'] = (int)($atom_structure['creation_time'] - 2082844800); // DateMac2Unix() | |
986 $atom_structure['modify_time_unix'] = (int)($atom_structure['modify_time'] - 2082844800); // DateMac2Unix() | |
987 $info_quicktime['time_scale'] = max(@$info['quicktime']['time_scale'], $atom_structure['time_scale']); | |
988 $info_quicktime['display_scale'] = $atom_structure['matrix_a']; | |
989 $info['playtime_seconds'] = $atom_structure['duration'] / $atom_structure['time_scale']; | |
990 break; | |
991 | |
992 | |
993 case 'tkhd': // TracK HeaDer atom | |
994 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, | |
995 array ( | |
996 'version' => 1, | |
997 'flags_raw' => 3, | |
998 'creation_time' => 4, | |
999 'modify_time' => 4, | |
1000 'trackid' => 4, | |
1001 'reserved1' => 4, | |
1002 'duration' => 4, | |
1003 'reserved2' => 8, | |
1004 'layer' => 2, | |
1005 'alternate_group' => 2 | |
1006 ) | |
1007 ); | |
1008 | |
1009 $atom_structure['volume'] = getid3_quicktime::FixedPoint8_8(substr($atom_data, 36, 2)); | |
1010 $atom_structure['reserved3'] = getid3_lib::BigEndian2Int(substr($atom_data, 38, 2)); | |
1011 $atom_structure['matrix_a'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 40, 4)); | |
1012 $atom_structure['matrix_b'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 44, 4)); | |
1013 $atom_structure['matrix_u'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 48, 4)); | |
1014 $atom_structure['matrix_c'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 52, 4)); | |
1015 $atom_structure['matrix_v'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 56, 4)); | |
1016 $atom_structure['matrix_d'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 60, 4)); | |
1017 $atom_structure['matrix_x'] = getid3_quicktime::FixedPoint2_30(substr($atom_data, 64, 4)); | |
1018 $atom_structure['matrix_y'] = getid3_quicktime::FixedPoint2_30(substr($atom_data, 68, 4)); | |
1019 $atom_structure['matrix_w'] = getid3_quicktime::FixedPoint2_30(substr($atom_data, 72, 4)); | |
1020 $atom_structure['width'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 76, 4)); | |
1021 $atom_structure['height'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 80, 4)); | |
1022 | |
1023 $atom_structure['flags']['enabled'] = (bool)($atom_structure['flags_raw'] & 0x0001); | |
1024 $atom_structure['flags']['in_movie'] = (bool)($atom_structure['flags_raw'] & 0x0002); | |
1025 $atom_structure['flags']['in_preview'] = (bool)($atom_structure['flags_raw'] & 0x0004); | |
1026 $atom_structure['flags']['in_poster'] = (bool)($atom_structure['flags_raw'] & 0x0008); | |
1027 $atom_structure['creation_time_unix'] = (int)($atom_structure['creation_time'] - 2082844800); // DateMac2Unix() | |
1028 $atom_structure['modify_time_unix'] = (int)($atom_structure['modify_time'] - 2082844800); // DateMac2Unix() | |
1029 | |
1030 if (!isset($info['video']['resolution_x']) || !isset($info['video']['resolution_y'])) { | |
1031 $info['video']['resolution_x'] = $atom_structure['width']; | |
1032 $info['video']['resolution_y'] = $atom_structure['height']; | |
1033 } | |
1034 | |
1035 if ($atom_structure['flags']['enabled'] == 1) { | |
1036 $info['video']['resolution_x'] = max($info['video']['resolution_x'], $atom_structure['width']); | |
1037 $info['video']['resolution_y'] = max($info['video']['resolution_y'], $atom_structure['height']); | |
1038 } | |
1039 | |
1040 if (!empty($info['video']['resolution_x']) && !empty($info['video']['resolution_y'])) { | |
1041 $info_quicktime['video']['resolution_x'] = $info['video']['resolution_x']; | |
1042 $info_quicktime['video']['resolution_y'] = $info['video']['resolution_y']; | |
1043 } else { | |
1044 unset($info['video']['resolution_x']); | |
1045 unset($info['video']['resolution_y']); | |
1046 unset($info_quicktime['video']); | |
1047 } | |
1048 break; | |
1049 | |
1050 | |
1051 case 'meta': // METAdata atom | |
1052 // http://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt | |
1053 $next_tag_position = strpos($atom_data, '©'); | |
1054 while ($next_tag_position < strlen($atom_data)) { | |
1055 $meta_item_size = getid3_lib::BigEndian2Int(substr($atom_data, $next_tag_position - 4, 4)) - 4; | |
1056 if ($meta_item_size == -4) { | |
1057 break; | |
1058 } | |
1059 $meta_item_raw = substr($atom_data, $next_tag_position, $meta_item_size); | |
1060 $meta_item_key = substr($meta_item_raw, 0, 4); | |
1061 $meta_item_data = substr($meta_item_raw, 20); | |
1062 $next_tag_position += $meta_item_size + 4; | |
1063 | |
1064 $this->CopyToAppropriateCommentsSection($meta_item_key, $meta_item_data); | |
1065 } | |
1066 break; | |
1067 | |
1068 case 'ftyp': // FileTYPe (?) atom (for MP4 it seems) | |
1069 getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, | |
1070 array ( | |
1071 'signature' => -4, | |
1072 'unknown_1' => 4, | |
1073 'fourcc' => -4, | |
1074 ) | |
1075 ); | |
1076 break; | |
1077 | |
1078 case 'mdat': // Media DATa atom | |
1079 case 'free': // FREE space atom | |
1080 case 'skip': // SKIP atom | |
1081 case 'wide': // 64-bit expansion placeholder atom | |
1082 // 'mdat' data is too big to deal with, contains no useful metadata | |
1083 // 'free', 'skip' and 'wide' are just padding, contains no useful data at all | |
1084 | |
1085 // When writing QuickTime files, it is sometimes necessary to update an atom's size. | |
1086 // It is impossible to update a 32-bit atom to a 64-bit atom since the 32-bit atom | |
1087 // is only 8 bytes in size, and the 64-bit atom requires 16 bytes. Therefore, QuickTime | |
1088 // puts an 8-byte placeholder atom before any atoms it may have to update the size of. | |
1089 // In this way, if the atom needs to be converted from a 32-bit to a 64-bit atom, the | |
1090 // placeholder atom can be overwritten to obtain the necessary 8 extra bytes. | |
1091 // The placeholder atom has a type of kWideAtomPlaceholderType ( 'wide' ). | |
1092 break; | |
1093 | |
1094 | |
1095 case 'nsav': // NoSAVe atom | |
1096 // http://developer.apple.com/technotes/tn/tn2038.html | |
1097 $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); | |
1098 break; | |
1099 | |
1100 case 'ctyp': // Controller TYPe atom (seen on QTVR) | |
1101 // http://homepages.slingshot.co.nz/~helmboy/quicktime/formats/qtm-layout.txt | |
1102 // some controller names are: | |
1103 // 0x00 + 'std' for linear movie | |
1104 // 'none' for no controls | |
1105 $atom_structure['ctyp'] = substr($atom_data, 0, 4); | |
1106 switch ($atom_structure['ctyp']) { | |
1107 case 'qtvr': | |
1108 $info['video']['dataformat'] = 'quicktimevr'; | |
1109 break; | |
1110 } | |
1111 break; | |
1112 | |
1113 case 'pano': // PANOrama track (seen on QTVR) | |
1114 $atom_structure['pano'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); | |
1115 break; | |
1116 | |
1117 case 'hint': // HINT track | |
1118 case 'hinf': // | |
1119 case 'hinv': // | |
1120 case 'hnti': // | |
1121 $info['quicktime']['hinting'] = true; | |
1122 break; | |
1123 | |
1124 case 'imgt': // IMaGe Track reference (kQTVRImageTrackRefType) (seen on QTVR) | |
1125 for ($i = 0; $i < ($atom_structure['size'] - 8); $i += 4) { | |
1126 $atom_structure['imgt'][] = getid3_lib::BigEndian2Int(substr($atom_data, $i, 4)); | |
1127 } | |
1128 break; | |
1129 | |
1130 case 'FXTC': // Something to do with Adobe After Effects (?) | |
1131 case 'PrmA': | |
1132 case 'code': | |
1133 case 'FIEL': // this is NOT "fiel" (Field Ordering) as describe here: http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap3/chapter_4_section_2.html | |
1134 // Observed-but-not-handled atom types are just listed here | |
1135 // to prevent warnings being generated | |
1136 $atom_structure['data'] = $atom_data; | |
1137 break; | |
1138 | |
1139 default: | |
1140 $getid3->warning('Unknown QuickTime atom type: "'.$atom_name.'" at offset '.$base_offset); | |
1141 $atom_structure['data'] = $atom_data; | |
1142 break; | |
1143 } | |
1144 array_pop($atom_hierarchy); | |
1145 return $atom_structure; | |
1146 } | |
1147 | |
1148 | |
1149 | |
1150 private function QuicktimeParseContainerAtom($atom_data, $base_offset, &$atom_hierarchy) { | |
1151 | |
1152 if ((strlen($atom_data) == 4) && (getid3_lib::BigEndian2Int($atom_data) == 0x00000000)) { | |
1153 return false; | |
1154 } | |
1155 | |
1156 $atom_structure = false; | |
1157 $subatom_offset = 0; | |
1158 | |
1159 while ($subatom_offset < strlen($atom_data)) { | |
1160 | |
1161 $subatom_size = getid3_lib::BigEndian2Int(substr($atom_data, $subatom_offset + 0, 4)); | |
1162 $subatom_name = substr($atom_data, $subatom_offset + 4, 4); | |
1163 $subatom_data = substr($atom_data, $subatom_offset + 8, $subatom_size - 8); | |
1164 | |
1165 if ($subatom_size == 0) { | |
1166 // Furthermore, for historical reasons the list of atoms is optionally | |
1167 // terminated by a 32-bit integer set to 0. If you are writing a program | |
1168 // to read user data atoms, you should allow for the terminating 0. | |
1169 return $atom_structure; | |
1170 } | |
1171 | |
1172 $atom_structure[] = $this->QuicktimeParseAtom($subatom_name, $subatom_size, $subatom_data, $base_offset + $subatom_offset, $atom_hierarchy); | |
1173 | |
1174 $subatom_offset += $subatom_size; | |
1175 } | |
1176 return $atom_structure; | |
1177 } | |
1178 | |
1179 | |
1180 | |
1181 private function CopyToAppropriateCommentsSection($key_name, $data) { | |
1182 | |
1183 // http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt | |
1184 | |
1185 static $translator = array ( | |
1186 '©cpy' => 'copyright', | |
1187 '©day' => 'creation_date', | |
1188 '©dir' => 'director', | |
1189 '©ed1' => 'edit1', | |
1190 '©ed2' => 'edit2', | |
1191 '©ed3' => 'edit3', | |
1192 '©ed4' => 'edit4', | |
1193 '©ed5' => 'edit5', | |
1194 '©ed6' => 'edit6', | |
1195 '©ed7' => 'edit7', | |
1196 '©ed8' => 'edit8', | |
1197 '©ed9' => 'edit9', | |
1198 '©fmt' => 'format', | |
1199 '©inf' => 'information', | |
1200 '©prd' => 'producer', | |
1201 '©prf' => 'performers', | |
1202 '©req' => 'system_requirements', | |
1203 '©src' => 'source_credit', | |
1204 '©wrt' => 'writer', | |
1205 '©nam' => 'title', | |
1206 '©cmt' => 'comment', | |
1207 '©wrn' => 'warning', | |
1208 '©hst' => 'host_computer', | |
1209 '©mak' => 'make', | |
1210 '©mod' => 'model', | |
1211 '©PRD' => 'product', | |
1212 '©swr' => 'software', | |
1213 '©aut' => 'author', | |
1214 '©ART' => 'artist', | |
1215 '©trk' => 'track', | |
1216 '©alb' => 'album', | |
1217 '©com' => 'comment', | |
1218 '©gen' => 'genre', | |
1219 '©ope' => 'composer', | |
1220 '©url' => 'url', | |
1221 '©enc' => 'encoder' | |
1222 ); | |
1223 | |
1224 if (isset($translator[$key_name])) { | |
1225 $this->getid3->info['quicktime']['comments'][$translator[$key_name]][] = $data; | |
1226 } | |
1227 | |
1228 return true; | |
1229 } | |
1230 | |
1231 | |
1232 | |
1233 public static function QuicktimeLanguageLookup($language_id) { | |
1234 | |
1235 static $lookup = array ( | |
1236 0 => 'English', | |
1237 1 => 'French', | |
1238 2 => 'German', | |
1239 3 => 'Italian', | |
1240 4 => 'Dutch', | |
1241 5 => 'Swedish', | |
1242 6 => 'Spanish', | |
1243 7 => 'Danish', | |
1244 8 => 'Portuguese', | |
1245 9 => 'Norwegian', | |
1246 10 => 'Hebrew', | |
1247 11 => 'Japanese', | |
1248 12 => 'Arabic', | |
1249 13 => 'Finnish', | |
1250 14 => 'Greek', | |
1251 15 => 'Icelandic', | |
1252 16 => 'Maltese', | |
1253 17 => 'Turkish', | |
1254 18 => 'Croatian', | |
1255 19 => 'Chinese (Traditional)', | |
1256 20 => 'Urdu', | |
1257 21 => 'Hindi', | |
1258 22 => 'Thai', | |
1259 23 => 'Korean', | |
1260 24 => 'Lithuanian', | |
1261 25 => 'Polish', | |
1262 26 => 'Hungarian', | |
1263 27 => 'Estonian', | |
1264 28 => 'Lettish', | |
1265 28 => 'Latvian', | |
1266 29 => 'Saamisk', | |
1267 29 => 'Lappish', | |
1268 30 => 'Faeroese', | |
1269 31 => 'Farsi', | |
1270 31 => 'Persian', | |
1271 32 => 'Russian', | |
1272 33 => 'Chinese (Simplified)', | |
1273 34 => 'Flemish', | |
1274 35 => 'Irish', | |
1275 36 => 'Albanian', | |
1276 37 => 'Romanian', | |
1277 38 => 'Czech', | |
1278 39 => 'Slovak', | |
1279 40 => 'Slovenian', | |
1280 41 => 'Yiddish', | |
1281 42 => 'Serbian', | |
1282 43 => 'Macedonian', | |
1283 44 => 'Bulgarian', | |
1284 45 => 'Ukrainian', | |
1285 46 => 'Byelorussian', | |
1286 47 => 'Uzbek', | |
1287 48 => 'Kazakh', | |
1288 49 => 'Azerbaijani', | |
1289 50 => 'AzerbaijanAr', | |
1290 51 => 'Armenian', | |
1291 52 => 'Georgian', | |
1292 53 => 'Moldavian', | |
1293 54 => 'Kirghiz', | |
1294 55 => 'Tajiki', | |
1295 56 => 'Turkmen', | |
1296 57 => 'Mongolian', | |
1297 58 => 'MongolianCyr', | |
1298 59 => 'Pashto', | |
1299 60 => 'Kurdish', | |
1300 61 => 'Kashmiri', | |
1301 62 => 'Sindhi', | |
1302 63 => 'Tibetan', | |
1303 64 => 'Nepali', | |
1304 65 => 'Sanskrit', | |
1305 66 => 'Marathi', | |
1306 67 => 'Bengali', | |
1307 68 => 'Assamese', | |
1308 69 => 'Gujarati', | |
1309 70 => 'Punjabi', | |
1310 71 => 'Oriya', | |
1311 72 => 'Malayalam', | |
1312 73 => 'Kannada', | |
1313 74 => 'Tamil', | |
1314 75 => 'Telugu', | |
1315 76 => 'Sinhalese', | |
1316 77 => 'Burmese', | |
1317 78 => 'Khmer', | |
1318 79 => 'Lao', | |
1319 80 => 'Vietnamese', | |
1320 81 => 'Indonesian', | |
1321 82 => 'Tagalog', | |
1322 83 => 'MalayRoman', | |
1323 84 => 'MalayArabic', | |
1324 85 => 'Amharic', | |
1325 86 => 'Tigrinya', | |
1326 87 => 'Galla', | |
1327 87 => 'Oromo', | |
1328 88 => 'Somali', | |
1329 89 => 'Swahili', | |
1330 90 => 'Ruanda', | |
1331 91 => 'Rundi', | |
1332 92 => 'Chewa', | |
1333 93 => 'Malagasy', | |
1334 94 => 'Esperanto', | |
1335 128 => 'Welsh', | |
1336 129 => 'Basque', | |
1337 130 => 'Catalan', | |
1338 131 => 'Latin', | |
1339 132 => 'Quechua', | |
1340 133 => 'Guarani', | |
1341 134 => 'Aymara', | |
1342 135 => 'Tatar', | |
1343 136 => 'Uighur', | |
1344 137 => 'Dzongkha', | |
1345 138 => 'JavaneseRom' | |
1346 ); | |
1347 | |
1348 return (isset($lookup[$language_id]) ? $lookup[$language_id] : 'invalid'); | |
1349 } | |
1350 | |
1351 | |
1352 | |
1353 public static function QuicktimeVideoCodecLookup($codec_id) { | |
1354 | |
1355 static $lookup = array ( | |
1356 '3IVX' => '3ivx MPEG-4', | |
1357 '3IV1' => '3ivx MPEG-4 v1', | |
1358 '3IV2' => '3ivx MPEG-4 v2', | |
1359 'avr ' => 'AVR-JPEG', | |
1360 'base' => 'Base', | |
1361 'WRLE' => 'BMP', | |
1362 'cvid' => 'Cinepak', | |
1363 'clou' => 'Cloud', | |
1364 'cmyk' => 'CMYK', | |
1365 'yuv2' => 'ComponentVideo', | |
1366 'yuvu' => 'ComponentVideoSigned', | |
1367 'yuvs' => 'ComponentVideoUnsigned', | |
1368 'dvc ' => 'DVC-NTSC', | |
1369 'dvcp' => 'DVC-PAL', | |
1370 'dvpn' => 'DVCPro-NTSC', | |
1371 'dvpp' => 'DVCPro-PAL', | |
1372 'fire' => 'Fire', | |
1373 'flic' => 'FLC', | |
1374 'b48r' => '48RGB', | |
1375 'gif ' => 'GIF', | |
1376 'smc ' => 'Graphics', | |
1377 'h261' => 'H261', | |
1378 'h263' => 'H263', | |
1379 'IV41' => 'Indeo4', | |
1380 'jpeg' => 'JPEG', | |
1381 'PNTG' => 'MacPaint', | |
1382 'msvc' => 'Microsoft Video1', | |
1383 'mjpa' => 'Motion JPEG-A', | |
1384 'mjpb' => 'Motion JPEG-B', | |
1385 'myuv' => 'MPEG YUV420', | |
1386 'dmb1' => 'OpenDML JPEG', | |
1387 'kpcd' => 'PhotoCD', | |
1388 '8BPS' => 'Planar RGB', | |
1389 'png ' => 'PNG', | |
1390 'qdrw' => 'QuickDraw', | |
1391 'qdgx' => 'QuickDrawGX', | |
1392 'raw ' => 'RAW', | |
1393 '.SGI' => 'SGI', | |
1394 'b16g' => '16Gray', | |
1395 'b64a' => '64ARGB', | |
1396 'SVQ1' => 'Sorenson Video 1', | |
1397 'SVQ1' => 'Sorenson Video 3', | |
1398 'syv9' => 'Sorenson YUV9', | |
1399 'tga ' => 'Targa', | |
1400 'b32a' => '32AlphaGray', | |
1401 'tiff' => 'TIFF', | |
1402 'path' => 'Vector', | |
1403 'rpza' => 'Video', | |
1404 'ripl' => 'WaterRipple', | |
1405 'WRAW' => 'Windows RAW', | |
1406 'y420' => 'YUV420' | |
1407 ); | |
1408 | |
1409 return (isset($lookup[$codec_id]) ? $lookup[$codec_id] : ''); | |
1410 } | |
1411 | |
1412 | |
1413 | |
1414 public static function QuicktimeAudioCodecLookup($codec_id) { | |
1415 | |
1416 static $lookup = array ( | |
1417 '.mp3' => 'Fraunhofer MPEG Layer-III alias', | |
1418 'aac ' => 'ISO/IEC 14496-3 AAC', | |
1419 'agsm' => 'Apple GSM 10:1', | |
1420 'alac' => 'Apple Lossless Audio Codec', | |
1421 'alaw' => 'A-law 2:1', | |
1422 'conv' => 'Sample Format', | |
1423 'dvca' => 'DV', | |
1424 'dvi ' => 'DV 4:1', | |
1425 'eqal' => 'Frequency Equalizer', | |
1426 'fl32' => '32-bit Floating Point', | |
1427 'fl64' => '64-bit Floating Point', | |
1428 'ima4' => 'Interactive Multimedia Association 4:1', | |
1429 'in24' => '24-bit Integer', | |
1430 'in32' => '32-bit Integer', | |
1431 'lpc ' => 'LPC 23:1', | |
1432 'MAC3' => 'Macintosh Audio Compression/Expansion (MACE) 3:1', | |
1433 'MAC6' => 'Macintosh Audio Compression/Expansion (MACE) 6:1', | |
1434 'mixb' => '8-bit Mixer', | |
1435 'mixw' => '16-bit Mixer', | |
1436 'mp4a' => 'ISO/IEC 14496-3 AAC', | |
1437 "MS'\x00\x02" => 'Microsoft ADPCM', | |
1438 "MS'\x00\x11" => 'DV IMA', | |
1439 "MS\x00\x55" => 'Fraunhofer MPEG Layer III', | |
1440 'NONE' => 'No Encoding', | |
1441 'Qclp' => 'Qualcomm PureVoice', | |
1442 'QDM2' => 'QDesign Music 2', | |
1443 'QDMC' => 'QDesign Music 1', | |
1444 'ratb' => '8-bit Rate', | |
1445 'ratw' => '16-bit Rate', | |
1446 'raw ' => 'raw PCM', | |
1447 'sour' => 'Sound Source', | |
1448 'sowt' => 'signed/two\'s complement (Little Endian)', | |
1449 'str1' => 'Iomega MPEG layer II', | |
1450 'str2' => 'Iomega MPEG *layer II', | |
1451 'str3' => 'Iomega MPEG **layer II', | |
1452 'str4' => 'Iomega MPEG ***layer II', | |
1453 'twos' => 'signed/two\'s complement (Big Endian)', | |
1454 'ulaw' => 'mu-law 2:1', | |
1455 ); | |
1456 | |
1457 return (isset($lookup[$codec_id]) ? $lookup[$codec_id] : ''); | |
1458 } | |
1459 | |
1460 | |
1461 | |
1462 public static function QuicktimeDCOMLookup($compression_id) { | |
1463 | |
1464 static $lookup = array ( | |
1465 'zlib' => 'ZLib Deflate', | |
1466 'adec' => 'Apple Compression' | |
1467 ); | |
1468 | |
1469 return (isset($lookup[$compression_id]) ? $lookup[$compression_id] : ''); | |
1470 } | |
1471 | |
1472 | |
1473 | |
1474 public static function QuicktimeColorNameLookup($color_depth_id) { | |
1475 | |
1476 static $lookup = array ( | |
1477 1 => '2-color (monochrome)', | |
1478 2 => '4-color', | |
1479 4 => '16-color', | |
1480 8 => '256-color', | |
1481 16 => 'thousands (16-bit color)', | |
1482 24 => 'millions (24-bit color)', | |
1483 32 => 'millions+ (32-bit color)', | |
1484 33 => 'black & white', | |
1485 34 => '4-gray', | |
1486 36 => '16-gray', | |
1487 40 => '256-gray', | |
1488 ); | |
1489 | |
1490 return (isset($lookup[$color_depth_id]) ? $lookup[$color_depth_id] : 'invalid'); | |
1491 } | |
1492 | |
1493 | |
1494 | |
1495 public static function NoNullString($null_terminated_string) { | |
1496 | |
1497 // remove the single null terminator on null terminated strings | |
1498 if (substr($null_terminated_string, strlen($null_terminated_string) - 1, 1) === "\x00") { | |
1499 return substr($null_terminated_string, 0, strlen($null_terminated_string) - 1); | |
1500 } | |
1501 | |
1502 return $null_terminated_string; | |
1503 } | |
1504 | |
1505 | |
1506 | |
1507 public static function FixedPoint8_8($raw_data) { | |
1508 | |
1509 return getid3_lib::BigEndian2Int($raw_data{0}) + (float)(getid3_lib::BigEndian2Int($raw_data{1}) / 256); | |
1510 } | |
1511 | |
1512 | |
1513 | |
1514 public static function FixedPoint16_16($raw_data) { | |
1515 | |
1516 return getid3_lib::BigEndian2Int(substr($raw_data, 0, 2)) + (float)(getid3_lib::BigEndian2Int(substr($raw_data, 2, 2)) / 65536); | |
1517 } | |
1518 | |
1519 | |
1520 | |
1521 public static function FixedPoint2_30($raw_data) { | |
1522 | |
1523 $binary_string = getid3_lib::BigEndian2Bin($raw_data); | |
1524 return bindec(substr($binary_string, 0, 2)) + (float)(bindec(substr($binary_string, 2, 30)) / 1073741824); | |
1525 } | |
1526 | |
1527 } | |
1528 | |
1529 ?> |