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