PageRenderTime 372ms CodeModel.GetById 154ms app.highlight 125ms RepoModel.GetById 53ms app.codeStats 2ms

/getid3/module.audio-video.quicktime.php

https://bitbucket.org/holyfield/getid3
PHP | 2128 lines | 1817 code | 179 blank | 132 comment | 168 complexity | 39948e0652f76cc9045d7e55f51e9452 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1<?php
  2/////////////////////////////////////////////////////////////////
  3/// getID3() by James Heinrich <info@getid3.org>               //
  4//  available at http://getid3.sourceforge.net                 //
  5//            or http://www.getid3.org                         //
  6/////////////////////////////////////////////////////////////////
  7// See readme.txt for more details                             //
  8/////////////////////////////////////////////////////////////////
  9//                                                             //
 10// module.audio-video.quicktime.php                            //
 11// module for analyzing Quicktime and MP3-in-MP4 files         //
 12// dependencies: module.audio.mp3.php                          //
 13//                                                            ///
 14/////////////////////////////////////////////////////////////////
 15
 16
 17getid3_lib::IncludeDependency ( GETID3_INCLUDEPATH . 'module.audio.mp3.php', __FILE__, true );
 18
 19class getid3_quicktime extends getid3_handler {
 20	
 21	var $ReturnAtomData = true;
 22	var $ParseAllPossibleAtoms = false;
 23	
 24	function Analyze() {
 25		$info = &$this->getid3->info;
 26		
 27		$info ['fileformat'] = 'quicktime';
 28		$info ['quicktime'] ['hinting'] = false;
 29		$info ['quicktime'] ['controller'] = 'standard'; // may be overridden if 'ctyp' atom is present
 30		
 31
 32		fseek ( $this->getid3->fp, $info ['avdataoffset'], SEEK_SET );
 33		
 34		$offset = 0;
 35		$atomcounter = 0;
 36		
 37		while ( $offset < $info ['avdataend'] ) {
 38			if (! getid3_lib::intValueSupported ( $offset )) {
 39				$info ['error'] [] = 'Unable to parse atom at offset ' . $offset . ' because beyond ' . round ( PHP_INT_MAX / 1073741824 ) . 'GB limit of PHP filesystem functions';
 40				break;
 41			}
 42			fseek ( $this->getid3->fp, $offset, SEEK_SET );
 43			$AtomHeader = fread ( $this->getid3->fp, 8 );
 44			
 45			$atomsize = getid3_lib::BigEndian2Int ( substr ( $AtomHeader, 0, 4 ) );
 46			$atomname = substr ( $AtomHeader, 4, 4 );
 47			
 48			// 64-bit MOV patch by jlegateØktnc*com
 49			if ($atomsize == 1) {
 50				$atomsize = getid3_lib::BigEndian2Int ( fread ( $this->getid3->fp, 8 ) );
 51			}
 52			
 53			$info ['quicktime'] [$atomname] ['name'] = $atomname;
 54			$info ['quicktime'] [$atomname] ['size'] = $atomsize;
 55			$info ['quicktime'] [$atomname] ['offset'] = $offset;
 56			
 57			if (($offset + $atomsize) > $info ['avdataend']) {
 58				$info ['error'] [] = 'Atom at offset ' . $offset . ' claims to go beyond end-of-file (length: ' . $atomsize . ' bytes)';
 59				return false;
 60			}
 61			
 62			if ($atomsize == 0) {
 63				// Furthermore, for historical reasons the list of atoms is optionally
 64				// terminated by a 32-bit integer set to 0. If you are writing a program
 65				// to read user data atoms, you should allow for the terminating 0.
 66				break;
 67			}
 68			switch ($atomname) {
 69				case 'mdat' : // Media DATa atom
 70					// 'mdat' contains the actual data for the audio/video
 71					if (($atomsize > 8) && (! isset ( $info ['avdataend_tmp'] ) || ($info ['quicktime'] [$atomname] ['size'] > ($info ['avdataend_tmp'] - $info ['avdataoffset'])))) {
 72						
 73						$info ['avdataoffset'] = $info ['quicktime'] [$atomname] ['offset'] + 8;
 74						$OldAVDataEnd = $info ['avdataend'];
 75						$info ['avdataend'] = $info ['quicktime'] [$atomname] ['offset'] + $info ['quicktime'] [$atomname] ['size'];
 76						
 77						$getid3_temp = new getID3 ();
 78						$getid3_temp->openfile ( $this->getid3->filename );
 79						$getid3_temp->info ['avdataoffset'] = $info ['avdataoffset'];
 80						$getid3_temp->info ['avdataend'] = $info ['avdataend'];
 81						$getid3_mp3 = new getid3_mp3 ( $getid3_temp );
 82						if ($getid3_mp3->MPEGaudioHeaderValid ( $getid3_mp3->MPEGaudioHeaderDecode ( fread ( $this->getid3->fp, 4 ) ) )) {
 83							$getid3_mp3->getOnlyMPEGaudioInfo ( $getid3_temp->info ['avdataoffset'], false );
 84							if (! empty ( $getid3_temp->info ['warning'] )) {
 85								foreach ( $getid3_temp->info ['warning'] as $value ) {
 86									$info ['warning'] [] = $value;
 87								}
 88							}
 89							if (! empty ( $getid3_temp->info ['mpeg'] )) {
 90								$info ['mpeg'] = $getid3_temp->info ['mpeg'];
 91								if (isset ( $info ['mpeg'] ['audio'] )) {
 92									$info ['audio'] ['dataformat'] = 'mp3';
 93									$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')));
 94									$info ['audio'] ['sample_rate'] = $info ['mpeg'] ['audio'] ['sample_rate'];
 95									$info ['audio'] ['channels'] = $info ['mpeg'] ['audio'] ['channels'];
 96									$info ['audio'] ['bitrate'] = $info ['mpeg'] ['audio'] ['bitrate'];
 97									$info ['audio'] ['bitrate_mode'] = strtolower ( $info ['mpeg'] ['audio'] ['bitrate_mode'] );
 98									$info ['bitrate'] = $info ['audio'] ['bitrate'];
 99								}
100							}
101						}
102						unset ( $getid3_mp3, $getid3_temp );
103						$info ['avdataend'] = $OldAVDataEnd;
104						unset ( $OldAVDataEnd );
105					
106					}
107					break;
108				
109				case 'free' : // FREE space atom
110				case 'skip' : // SKIP atom
111				case 'wide' : // 64-bit expansion placeholder atom
112					// 'free', 'skip' and 'wide' are just padding, contains no useful data at all
113					break;
114				
115				default :
116					$atomHierarchy = array ();
117					$info ['quicktime'] [$atomname] = $this->QuicktimeParseAtom ( $atomname, $atomsize, fread ( $this->getid3->fp, $atomsize ), $offset, $atomHierarchy, $this->ParseAllPossibleAtoms );
118					break;
119			}
120			
121			$offset += $atomsize;
122			$atomcounter ++;
123		}
124		
125		if (! empty ( $info ['avdataend_tmp'] )) {
126			// this value is assigned to a temp value and then erased because
127			// otherwise any atoms beyond the 'mdat' atom would not get parsed
128			$info ['avdataend'] = $info ['avdataend_tmp'];
129			unset ( $info ['avdataend_tmp'] );
130		}
131		
132		if (! isset ( $info ['bitrate'] ) && isset ( $info ['playtime_seconds'] )) {
133			$info ['bitrate'] = (($info ['avdataend'] - $info ['avdataoffset']) * 8) / $info ['playtime_seconds'];
134		}
135		if (isset ( $info ['bitrate'] ) && ! isset ( $info ['audio'] ['bitrate'] ) && ! isset ( $info ['quicktime'] ['video'] )) {
136			$info ['audio'] ['bitrate'] = $info ['bitrate'];
137		}
138		if (! empty ( $info ['playtime_seconds'] ) && ! isset ( $info ['video'] ['frame_rate'] ) && ! empty ( $info ['quicktime'] ['stts_framecount'] )) {
139			foreach ( $info ['quicktime'] ['stts_framecount'] as $key => $samples_count ) {
140				$samples_per_second = $samples_count / $info ['playtime_seconds'];
141				if ($samples_per_second > 240) {
142					// has to be audio samples
143				} else {
144					$info ['video'] ['frame_rate'] = $samples_per_second;
145					break;
146				}
147			}
148		}
149		if (($info ['audio'] ['dataformat'] == 'mp4') && empty ( $info ['video'] ['resolution_x'] )) {
150			$info ['fileformat'] = 'mp4';
151			$info ['mime_type'] = 'audio/mp4';
152			unset ( $info ['video'] ['dataformat'] );
153		}
154		
155		if (! $this->ReturnAtomData) {
156			unset ( $info ['quicktime'] ['moov'] );
157		}
158		
159		if (empty ( $info ['audio'] ['dataformat'] ) && ! empty ( $info ['quicktime'] ['audio'] )) {
160			$info ['audio'] ['dataformat'] = 'quicktime';
161		}
162		if (empty ( $info ['video'] ['dataformat'] ) && ! empty ( $info ['quicktime'] ['video'] )) {
163			$info ['video'] ['dataformat'] = 'quicktime';
164		}
165		
166		return true;
167	}
168	
169	function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
170		// http://developer.apple.com/techpubs/quicktime/qtdevdocs/APIREF/INDEX/atomalphaindex.htm
171		
172
173		$info = &$this->getid3->info;
174		
175		$atom_parent = array_pop ( $atomHierarchy );
176		array_push ( $atomHierarchy, $atomname );
177		$atom_structure ['hierarchy'] = implode ( ' ', $atomHierarchy );
178		$atom_structure ['name'] = $atomname;
179		$atom_structure ['size'] = $atomsize;
180		$atom_structure ['offset'] = $baseoffset;
181		//echo getid3_lib::PrintHexBytes(substr($atom_data, 0, 8)).'<br>';
182		//echo getid3_lib::PrintHexBytes(substr($atom_data, 0, 8), false).'<br><br>';
183		switch ($atomname) {
184			case 'moov' : // MOVie container atom
185			case 'trak' : // TRAcK container atom
186			case 'clip' : // CLIPping container atom
187			case 'matt' : // track MATTe container atom
188			case 'edts' : // EDiTS container atom
189			case 'tref' : // Track REFerence container atom
190			case 'mdia' : // MeDIA container atom
191			case 'minf' : // Media INFormation container atom
192			case 'dinf' : // Data INFormation container atom
193			case 'udta' : // User DaTA container atom
194			case 'cmov' : // Compressed MOVie container atom
195			case 'rmra' : // Reference Movie Record Atom
196			case 'rmda' : // Reference Movie Descriptor Atom
197			case 'gmhd' : // Generic Media info HeaDer atom (seen on QTVR)
198				$atom_structure ['subatoms'] = $this->QuicktimeParseContainerAtom ( $atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms );
199				break;
200			
201			case 'ilst' : // Item LiST container atom
202				$atom_structure ['subatoms'] = $this->QuicktimeParseContainerAtom ( $atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms );
203				
204				// some "ilst" atoms contain data atoms that have a numeric name, and the data is far more accessible if the returned array is compacted
205				$allnumericnames = true;
206				foreach ( $atom_structure ['subatoms'] as $subatomarray ) {
207					if (! is_integer ( $subatomarray ['name'] ) || (count ( $subatomarray ['subatoms'] ) != 1)) {
208						$allnumericnames = false;
209						break;
210					}
211				}
212				if ($allnumericnames) {
213					$newData = array ();
214					foreach ( $atom_structure ['subatoms'] as $subatomarray ) {
215						foreach ( $subatomarray ['subatoms'] as $newData_subatomarray ) {
216							unset ( $newData_subatomarray ['hierarchy'], $newData_subatomarray ['name'] );
217							$newData [$subatomarray ['name']] = $newData_subatomarray;
218							break;
219						}
220					}
221					$atom_structure ['data'] = $newData;
222					unset ( $atom_structure ['subatoms'] );
223				}
224				break;
225			
226			case "\x00\x00\x00\x01" :
227			case "\x00\x00\x00\x02" :
228			case "\x00\x00\x00\x03" :
229			case "\x00\x00\x00\x04" :
230			case "\x00\x00\x00\x05" :
231				$atomname = getid3_lib::BigEndian2Int ( $atomname );
232				$atom_structure ['name'] = $atomname;
233				$atom_structure ['subatoms'] = $this->QuicktimeParseContainerAtom ( $atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms );
234				break;
235			
236			case 'stbl' : // Sample TaBLe container atom
237				$atom_structure ['subatoms'] = $this->QuicktimeParseContainerAtom ( $atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms );
238				$isVideo = false;
239				$framerate = 0;
240				$framecount = 0;
241				foreach ( $atom_structure ['subatoms'] as $key => $value_array ) {
242					if (isset ( $value_array ['sample_description_table'] )) {
243						foreach ( $value_array ['sample_description_table'] as $key2 => $value_array2 ) {
244							if (isset ( $value_array2 ['data_format'] )) {
245								switch ($value_array2 ['data_format']) {
246									case 'avc1' :
247									case 'mp4v' :
248										// video data
249										$isVideo = true;
250										break;
251									case 'mp4a' :
252										// audio data
253										break;
254								}
255							}
256						}
257					} elseif (isset ( $value_array ['time_to_sample_table'] )) {
258						foreach ( $value_array ['time_to_sample_table'] as $key2 => $value_array2 ) {
259							if (isset ( $value_array2 ['sample_count'] ) && isset ( $value_array2 ['sample_duration'] ) && ($value_array2 ['sample_duration'] > 0)) {
260								$framerate = round ( $info ['quicktime'] ['time_scale'] / $value_array2 ['sample_duration'], 3 );
261								$framecount = $value_array2 ['sample_count'];
262							}
263						}
264					}
265				}
266				if ($isVideo && $framerate) {
267					$info ['quicktime'] ['video'] ['frame_rate'] = $framerate;
268					$info ['video'] ['frame_rate'] = $info ['quicktime'] ['video'] ['frame_rate'];
269				}
270				if ($isVideo && $framecount) {
271					$info ['quicktime'] ['video'] ['frame_count'] = $framecount;
272				}
273				break;
274			
275			case 'aART' : // Album ARTist
276			case 'catg' : // CaTeGory
277			case 'covr' : // COVeR artwork
278			case 'cpil' : // ComPILation
279			case 'cprt' : // CoPyRighT
280			case 'desc' : // DESCription
281			case 'disk' : // DISK number
282			case 'egid' : // Episode Global ID
283			case 'gnre' : // GeNRE
284			case 'keyw' : // KEYWord
285			case 'ldes' :
286			case 'pcst' : // PodCaST
287			case 'pgap' : // GAPless Playback
288			case 'purd' : // PURchase Date
289			case 'purl' : // Podcast URL
290			case 'rati' :
291			case 'rndu' :
292			case 'rpdu' :
293			case 'rtng' : // RaTiNG
294			case 'stik' :
295			case 'tmpo' : // TeMPO (BPM)
296			case 'trkn' : // TRacK Number
297			case 'tves' : // TV EpiSode
298			case 'tvnn' : // TV Network Name
299			case 'tvsh' : // TV SHow Name
300			case 'tvsn' : // TV SeasoN
301			case 'akID' : // iTunes store account type
302			case 'apID' :
303			case 'atID' :
304			case 'cmID' :
305			case 'cnID' :
306			case 'geID' :
307			case 'plID' :
308			case 'sfID' : // iTunes store country
309			case '©alb' : // ALBum
310			case '©art' : // ARTist
311			case '©ART' :
312			case '©aut' :
313			case '©cmt' : // CoMmenT
314			case '©com' : // COMposer
315			case '©cpy' :
316			case '©day' : // content created year
317			case '©dir' :
318			case '©ed1' :
319			case '©ed2' :
320			case '©ed3' :
321			case '©ed4' :
322			case '©ed5' :
323			case '©ed6' :
324			case '©ed7' :
325			case '©ed8' :
326			case '©ed9' :
327			case '©enc' :
328			case '©fmt' :
329			case '©gen' : // GENre
330			case '©grp' : // GRouPing
331			case '©hst' :
332			case '©inf' :
333			case '©lyr' : // LYRics
334			case '©mak' :
335			case '©mod' :
336			case '©nam' : // full NAMe
337			case '©ope' :
338			case '©PRD' :
339			case '©prd' :
340			case '©prf' :
341			case '©req' :
342			case '©src' :
343			case '©swr' :
344			case '©too' : // encoder
345			case '©trk' : // TRacK
346			case '©url' :
347			case '©wrn' :
348			case '©wrt' : // WRiTer
349			case '----' : // itunes specific
350				if ($atom_parent == 'udta') {
351					// User data atom handler
352					$atom_structure ['data_length'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 2 ) );
353					$atom_structure ['language_id'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 2, 2 ) );
354					$atom_structure ['data'] = substr ( $atom_data, 4 );
355					
356					$atom_structure ['language'] = $this->QuicktimeLanguageLookup ( $atom_structure ['language_id'] );
357					if (empty ( $info ['comments'] ['language'] ) || (! in_array ( $atom_structure ['language'], $info ['comments'] ['language'] ))) {
358						$info ['comments'] ['language'] [] = $atom_structure ['language'];
359					}
360				} else {
361					// Apple item list box atom handler
362					$atomoffset = 0;
363					if (substr ( $atom_data, 2, 2 ) == "\x10\xB5") {
364						// not sure what it means, but observed on iPhone4 data.
365						// Each $atom_data has 2 bytes of datasize, plus 0x10B5, then data
366						while ( $atomoffset < strlen ( $atom_data ) ) {
367							$boxsmallsize = getid3_lib::BigEndian2Int ( substr ( $atom_data, $atomoffset, 2 ) );
368							$boxsmalltype = substr ( $atom_data, $atomoffset + 2, 2 );
369							$boxsmalldata = substr ( $atom_data, $atomoffset + 4, $boxsmallsize );
370							switch ($boxsmalltype) {
371								case "\x10\xB5" :
372									$atom_structure ['data'] = $boxsmalldata;
373									break;
374								default :
375									$info ['warning'] [] = 'Unknown QuickTime smallbox type: "' . getid3_lib::PrintHexBytes ( $boxsmalltype ) . '" at offset ' . $baseoffset;
376									$atom_structure ['data'] = $atom_data;
377									break;
378							}
379							$atomoffset += (4 + $boxsmallsize);
380						}
381					} else {
382						while ( $atomoffset < strlen ( $atom_data ) ) {
383							$boxsize = getid3_lib::BigEndian2Int ( substr ( $atom_data, $atomoffset, 4 ) );
384							$boxtype = substr ( $atom_data, $atomoffset + 4, 4 );
385							$boxdata = substr ( $atom_data, $atomoffset + 8, $boxsize - 8 );
386							
387							switch ($boxtype) {
388								case 'mean' :
389								case 'name' :
390									$atom_structure [$boxtype] = substr ( $boxdata, 4 );
391									break;
392								
393								case 'data' :
394									$atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $boxdata, 0, 1 ) );
395									$atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $boxdata, 1, 3 ) );
396									switch ($atom_structure ['flags_raw']) {
397										case 0 : // data flag
398										case 21 : // tmpo/cpil flag
399											switch ($atomname) {
400												case 'cpil' :
401												case 'pcst' :
402												case 'pgap' :
403													$atom_structure ['data'] = getid3_lib::BigEndian2Int ( substr ( $boxdata, 8, 1 ) );
404													break;
405												
406												case 'tmpo' :
407													$atom_structure ['data'] = getid3_lib::BigEndian2Int ( substr ( $boxdata, 8, 2 ) );
408													break;
409												
410												case 'disk' :
411												case 'trkn' :
412													$num = getid3_lib::BigEndian2Int ( substr ( $boxdata, 10, 2 ) );
413													$num_total = getid3_lib::BigEndian2Int ( substr ( $boxdata, 12, 2 ) );
414													$atom_structure ['data'] = empty ( $num ) ? '' : $num;
415													$atom_structure ['data'] .= empty ( $num_total ) ? '' : '/' . $num_total;
416													break;
417												
418												case 'gnre' :
419													$GenreID = getid3_lib::BigEndian2Int ( substr ( $boxdata, 8, 4 ) );
420													$atom_structure ['data'] = getid3_id3v1::LookupGenreName ( $GenreID - 1 );
421													break;
422												
423												case 'rtng' :
424													$atom_structure [$atomname] = getid3_lib::BigEndian2Int ( substr ( $boxdata, 8, 1 ) );
425													$atom_structure ['data'] = $this->QuicktimeContentRatingLookup ( $atom_structure [$atomname] );
426													break;
427												
428												case 'stik' :
429													$atom_structure [$atomname] = getid3_lib::BigEndian2Int ( substr ( $boxdata, 8, 1 ) );
430													$atom_structure ['data'] = $this->QuicktimeSTIKLookup ( $atom_structure [$atomname] );
431													break;
432												
433												case 'sfID' :
434													$atom_structure [$atomname] = getid3_lib::BigEndian2Int ( substr ( $boxdata, 8, 4 ) );
435													$atom_structure ['data'] = $this->QuicktimeStoreFrontCodeLookup ( $atom_structure [$atomname] );
436													break;
437												
438												case 'egid' :
439												case 'purl' :
440													$atom_structure ['data'] = substr ( $boxdata, 8 );
441													break;
442												
443												default :
444													$atom_structure ['data'] = getid3_lib::BigEndian2Int ( substr ( $boxdata, 8, 4 ) );
445											}
446											break;
447										
448										case 1 : // text flag
449										case 13 : // image flag
450										default :
451											$atom_structure ['data'] = substr ( $boxdata, 8 );
452											break;
453									
454									}
455									break;
456								
457								default :
458									$info ['warning'] [] = 'Unknown QuickTime box type: "' . getid3_lib::PrintHexBytes ( $boxtype ) . '" at offset ' . $baseoffset;
459									$atom_structure ['data'] = $atom_data;
460							
461							}
462							$atomoffset += $boxsize;
463						}
464					}
465				}
466				$this->CopyToAppropriateCommentsSection ( $atomname, $atom_structure ['data'], $atom_structure ['name'] );
467				break;
468			
469			case 'play' : // auto-PLAY atom
470				$atom_structure ['autoplay'] = ( bool ) getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
471				
472				$info ['quicktime'] ['autoplay'] = $atom_structure ['autoplay'];
473				break;
474			
475			case 'WLOC' : // Window LOCation atom
476				$atom_structure ['location_x'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 2 ) );
477				$atom_structure ['location_y'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 2, 2 ) );
478				break;
479			
480			case 'LOOP' : // LOOPing atom
481			case 'SelO' : // play SELection Only atom
482			case 'AllF' : // play ALL Frames atom
483				$atom_structure ['data'] = getid3_lib::BigEndian2Int ( $atom_data );
484				break;
485			
486			case 'name' : //
487			case 'MCPS' : // Media Cleaner PRo
488			case '@PRM' : // adobe PReMiere version
489			case '@PRQ' : // adobe PRemiere Quicktime version
490				$atom_structure ['data'] = $atom_data;
491				break;
492			
493			case 'cmvd' : // Compressed MooV Data atom
494				// Code by ubergeekØubergeek*tv based on information from
495				// http://developer.apple.com/quicktime/icefloe/dispatch012.html
496				$atom_structure ['unCompressedSize'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 4 ) );
497				
498				$CompressedFileData = substr ( $atom_data, 4 );
499				if (($UncompressedHeader = @gzuncompress ( $CompressedFileData )) != false) {
500					$atom_structure ['subatoms'] = $this->QuicktimeParseContainerAtom ( $UncompressedHeader, 0, $atomHierarchy, $ParseAllPossibleAtoms );
501				} else {
502					$info ['warning'] [] = 'Error decompressing compressed MOV atom at offset ' . $atom_structure ['offset'];
503				}
504				break;
505			
506			case 'dcom' : // Data COMpression atom
507				$atom_structure ['compression_id'] = $atom_data;
508				$atom_structure ['compression_text'] = $this->QuicktimeDCOMLookup ( $atom_data );
509				break;
510			
511			case 'rdrf' : // Reference movie Data ReFerence atom
512				$atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
513				$atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) );
514				$atom_structure ['flags'] ['internal_data'] = ( bool ) ($atom_structure ['flags_raw'] & 0x000001);
515				
516				$atom_structure ['reference_type_name'] = substr ( $atom_data, 4, 4 );
517				$atom_structure ['reference_length'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 8, 4 ) );
518				switch ($atom_structure ['reference_type_name']) {
519					case 'url ' :
520						$atom_structure ['url'] = $this->NoNullString ( substr ( $atom_data, 12 ) );
521						break;
522					
523					case 'alis' :
524						$atom_structure ['file_alias'] = substr ( $atom_data, 12 );
525						break;
526					
527					case 'rsrc' :
528						$atom_structure ['resource_alias'] = substr ( $atom_data, 12 );
529						break;
530					
531					default :
532						$atom_structure ['data'] = substr ( $atom_data, 12 );
533						break;
534				}
535				break;
536			
537			case 'rmqu' : // Reference Movie QUality atom
538				$atom_structure ['movie_quality'] = getid3_lib::BigEndian2Int ( $atom_data );
539				break;
540			
541			case 'rmcs' : // Reference Movie Cpu Speed atom
542				$atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
543				$atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
544				$atom_structure ['cpu_speed_rating'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 2 ) );
545				break;
546			
547			case 'rmvc' : // Reference Movie Version Check atom
548				$atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
549				$atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
550				$atom_structure ['gestalt_selector'] = substr ( $atom_data, 4, 4 );
551				$atom_structure ['gestalt_value_mask'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 8, 4 ) );
552				$atom_structure ['gestalt_value'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 12, 4 ) );
553				$atom_structure ['gestalt_check_type'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 14, 2 ) );
554				break;
555			
556			case 'rmcd' : // Reference Movie Component check atom
557				$atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
558				$atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
559				$atom_structure ['component_type'] = substr ( $atom_data, 4, 4 );
560				$atom_structure ['component_subtype'] = substr ( $atom_data, 8, 4 );
561				$atom_structure ['component_manufacturer'] = substr ( $atom_data, 12, 4 );
562				$atom_structure ['component_flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 16, 4 ) );
563				$atom_structure ['component_flags_mask'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 20, 4 ) );
564				$atom_structure ['component_min_version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 24, 4 ) );
565				break;
566			
567			case 'rmdr' : // Reference Movie Data Rate atom
568				$atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
569				$atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
570				$atom_structure ['data_rate'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 4 ) );
571				
572				$atom_structure ['data_rate_bps'] = $atom_structure ['data_rate'] * 10;
573				break;
574			
575			case 'rmla' : // Reference Movie Language Atom
576				$atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
577				$atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
578				$atom_structure ['language_id'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 2 ) );
579				
580				$atom_structure ['language'] = $this->QuicktimeLanguageLookup ( $atom_structure ['language_id'] );
581				if (empty ( $info ['comments'] ['language'] ) || (! in_array ( $atom_structure ['language'], $info ['comments'] ['language'] ))) {
582					$info ['comments'] ['language'] [] = $atom_structure ['language'];
583				}
584				break;
585			
586			case 'rmla' : // Reference Movie Language Atom
587				$atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
588				$atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
589				$atom_structure ['track_id'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 2 ) );
590				break;
591			
592			case 'ptv ' : // Print To Video - defines a movie's full screen mode
593				// http://developer.apple.com/documentation/QuickTime/APIREF/SOURCESIV/at_ptv-_pg.htm
594				$atom_structure ['display_size_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 2 ) );
595				$atom_structure ['reserved_1'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 2, 2 ) ); // hardcoded: 0x0000
596				$atom_structure ['reserved_2'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 2 ) ); // hardcoded: 0x0000
597				$atom_structure ['slide_show_flag'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 6, 1 ) );
598				$atom_structure ['play_on_open_flag'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 7, 1 ) );
599				
600				$atom_structure ['flags'] ['play_on_open'] = ( bool ) $atom_structure ['play_on_open_flag'];
601				$atom_structure ['flags'] ['slide_show'] = ( bool ) $atom_structure ['slide_show_flag'];
602				
603				$ptv_lookup [0] = 'normal';
604				$ptv_lookup [1] = 'double';
605				$ptv_lookup [2] = 'half';
606				$ptv_lookup [3] = 'full';
607				$ptv_lookup [4] = 'current';
608				if (isset ( $ptv_lookup [$atom_structure ['display_size_raw']] )) {
609					$atom_structure ['display_size'] = $ptv_lookup [$atom_structure ['display_size_raw']];
610				} else {
611					$info ['warning'] [] = 'unknown "ptv " display constant (' . $atom_structure ['display_size_raw'] . ')';
612				}
613				break;
614			
615			case 'stsd' : // Sample Table Sample Description atom
616				$atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
617				$atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
618				$atom_structure ['number_entries'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 4 ) );
619				$stsdEntriesDataOffset = 8;
620				for($i = 0; $i < $atom_structure ['number_entries']; $i ++) {
621					$atom_structure ['sample_description_table'] [$i] ['size'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $stsdEntriesDataOffset, 4 ) );
622					$stsdEntriesDataOffset += 4;
623					$atom_structure ['sample_description_table'] [$i] ['data_format'] = substr ( $atom_data, $stsdEntriesDataOffset, 4 );
624					$stsdEntriesDataOffset += 4;
625					$atom_structure ['sample_description_table'] [$i] ['reserved'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $stsdEntriesDataOffset, 6 ) );
626					$stsdEntriesDataOffset += 6;
627					$atom_structure ['sample_description_table'] [$i] ['reference_index'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $stsdEntriesDataOffset, 2 ) );
628					$stsdEntriesDataOffset += 2;
629					$atom_structure ['sample_description_table'] [$i] ['data'] = substr ( $atom_data, $stsdEntriesDataOffset, ($atom_structure ['sample_description_table'] [$i] ['size'] - 4 - 4 - 6 - 2) );
630					$stsdEntriesDataOffset += ($atom_structure ['sample_description_table'] [$i] ['size'] - 4 - 4 - 6 - 2);
631					
632					$atom_structure ['sample_description_table'] [$i] ['encoder_version'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 0, 2 ) );
633					$atom_structure ['sample_description_table'] [$i] ['encoder_revision'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 2, 2 ) );
634					$atom_structure ['sample_description_table'] [$i] ['encoder_vendor'] = substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 4, 4 );
635					
636					switch ($atom_structure ['sample_description_table'] [$i] ['encoder_vendor']) {
637						
638						case "\x00\x00\x00\x00" :
639							// audio atom
640							$atom_structure ['sample_description_table'] [$i] ['audio_channels'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 8, 2 ) );
641							$atom_structure ['sample_description_table'] [$i] ['audio_bit_depth'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 10, 2 ) );
642							$atom_structure ['sample_description_table'] [$i] ['audio_compression_id'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 12, 2 ) );
643							$atom_structure ['sample_description_table'] [$i] ['audio_packet_size'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 14, 2 ) );
644							$atom_structure ['sample_description_table'] [$i] ['audio_sample_rate'] = getid3_lib::FixedPoint16_16 ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 16, 4 ) );
645							
646							switch ($atom_structure ['sample_description_table'] [$i] ['data_format']) {
647								case 'avc1' :
648								case 'mp4v' :
649									$info ['fileformat'] = 'mp4';
650									$info ['video'] ['fourcc'] = $atom_structure ['sample_description_table'] [$i] ['data_format'];
651									//$info['warning'][] = 'This version of getID3() ['.$this->getid3->version().'] does not fully support MPEG-4 audio/video streams'; // 2011-02-18: why am I warning about this again? What's not supported?
652									break;
653								
654								case 'qtvr' :
655									$info ['video'] ['dataformat'] = 'quicktimevr';
656									break;
657								
658								case 'mp4a' :
659								default :
660									$info ['quicktime'] ['audio'] ['codec'] = $this->QuicktimeAudioCodecLookup ( $atom_structure ['sample_description_table'] [$i] ['data_format'] );
661									$info ['quicktime'] ['audio'] ['sample_rate'] = $atom_structure ['sample_description_table'] [$i] ['audio_sample_rate'];
662									$info ['quicktime'] ['audio'] ['channels'] = $atom_structure ['sample_description_table'] [$i] ['audio_channels'];
663									$info ['quicktime'] ['audio'] ['bit_depth'] = $atom_structure ['sample_description_table'] [$i] ['audio_bit_depth'];
664									$info ['audio'] ['codec'] = $info ['quicktime'] ['audio'] ['codec'];
665									$info ['audio'] ['sample_rate'] = $info ['quicktime'] ['audio'] ['sample_rate'];
666									$info ['audio'] ['channels'] = $info ['quicktime'] ['audio'] ['channels'];
667									$info ['audio'] ['bits_per_sample'] = $info ['quicktime'] ['audio'] ['bit_depth'];
668									switch ($atom_structure ['sample_description_table'] [$i] ['data_format']) {
669										case 'raw ' : // PCM
670										case 'alac' : // Apple Lossless Audio Codec
671											$info ['audio'] ['lossless'] = true;
672											break;
673										default :
674											$info ['audio'] ['lossless'] = false;
675											break;
676									}
677									break;
678							}
679							break;
680						
681						default :
682							switch ($atom_structure ['sample_description_table'] [$i] ['data_format']) {
683								case 'mp4s' :
684									$info ['fileformat'] = 'mp4';
685									break;
686								
687								default :
688									// video atom
689									$atom_structure ['sample_description_table'] [$i] ['video_temporal_quality'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 8, 4 ) );
690									$atom_structure ['sample_description_table'] [$i] ['video_spatial_quality'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 12, 4 ) );
691									$atom_structure ['sample_description_table'] [$i] ['video_frame_width'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 16, 2 ) );
692									$atom_structure ['sample_description_table'] [$i] ['video_frame_height'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 18, 2 ) );
693									$atom_structure ['sample_description_table'] [$i] ['video_resolution_x'] = getid3_lib::FixedPoint16_16 ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 20, 4 ) );
694									$atom_structure ['sample_description_table'] [$i] ['video_resolution_y'] = getid3_lib::FixedPoint16_16 ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 24, 4 ) );
695									$atom_structure ['sample_description_table'] [$i] ['video_data_size'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 28, 4 ) );
696									$atom_structure ['sample_description_table'] [$i] ['video_frame_count'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 32, 2 ) );
697									$atom_structure ['sample_description_table'] [$i] ['video_encoder_name_len'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 34, 1 ) );
698									$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'] );
699									$atom_structure ['sample_description_table'] [$i] ['video_pixel_color_depth'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 66, 2 ) );
700									$atom_structure ['sample_description_table'] [$i] ['video_color_table_id'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 68, 2 ) );
701									
702									$atom_structure ['sample_description_table'] [$i] ['video_pixel_color_type'] = (($atom_structure ['sample_description_table'] [$i] ['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color');
703									$atom_structure ['sample_description_table'] [$i] ['video_pixel_color_name'] = $this->QuicktimeColorNameLookup ( $atom_structure ['sample_description_table'] [$i] ['video_pixel_color_depth'] );
704									
705									if ($atom_structure ['sample_description_table'] [$i] ['video_pixel_color_name'] != 'invalid') {
706										$info ['quicktime'] ['video'] ['codec_fourcc'] = $atom_structure ['sample_description_table'] [$i] ['data_format'];
707										$info ['quicktime'] ['video'] ['codec_fourcc_lookup'] = $this->QuicktimeVideoCodecLookup ( $atom_structure ['sample_description_table'] [$i] ['data_format'] );
708										$info ['quicktime'] ['video'] ['codec'] = (($atom_structure ['sample_description_table'] [$i] ['video_encoder_name_len'] > 0) ? $atom_structure ['sample_description_table'] [$i] ['video_encoder_name'] : $atom_structure ['sample_description_table'] [$i] ['data_format']);
709										$info ['quicktime'] ['video'] ['color_depth'] = $atom_structure ['sample_description_table'] [$i] ['video_pixel_color_depth'];
710										$info ['quicktime'] ['video'] ['color_depth_name'] = $atom_structure ['sample_description_table'] [$i] ['video_pixel_color_name'];
711										
712										$info ['video'] ['codec'] = $info ['quicktime'] ['video'] ['codec'];
713										$info ['video'] ['bits_per_sample'] = $info ['quicktime'] ['video'] ['color_depth'];
714									}
715									$info ['video'] ['lossless'] = false;
716									$info ['video'] ['pixel_aspect_ratio'] = ( float ) 1;
717									break;
718							}
719							break;
720					}
721					switch (strtolower ( $atom_structure ['sample_description_table'] [$i] ['data_format'] )) {
722						case 'mp4a' :
723							$info ['audio'] ['dataformat'] = 'mp4';
724							$info ['quicktime'] ['audio'] ['codec'] = 'mp4';
725							break;
726						
727						case '3ivx' :
728						case '3iv1' :
729						case '3iv2' :
730							$info ['video'] ['dataformat'] = '3ivx';
731							break;
732						
733						case 'xvid' :
734							$info ['video'] ['dataformat'] = 'xvid';
735							break;
736						
737						case 'mp4v' :
738							$info ['video'] ['dataformat'] = 'mpeg4';
739							break;
740						
741						case 'divx' :
742						case 'div1' :
743						case 'div2' :
744						case 'div3' :
745						case 'div4' :
746						case 'div5' :
747						case 'div6' :
748							$info ['video'] ['dataformat'] = 'divx';
749							break;
750						
751						default :
752							// do nothing
753							break;
754					}
755					unset ( $atom_structure ['sample_description_table'] [$i] ['data'] );
756				}
757				break;
758			
759			case 'stts' : // Sample Table Time-to-Sample atom
760				$atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
761				$atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
762				$atom_structure ['number_entries'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 4 ) );
763				$sttsEntriesDataOffset = 8;
764				//$FrameRateCalculatorArray = array();
765				$frames_count = 0;
766				for($i = 0; $i < $atom_structure ['number_entries']; $i ++) {
767					$atom_structure ['time_to_sample_table'] [$i] ['sample_count'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $sttsEntriesDataOffset, 4 ) );
768					$sttsEntriesDataOffset += 4;
769					$atom_structure ['time_to_sample_table'] [$i] ['sample_duration'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $sttsEntriesDataOffset, 4 ) );
770					$sttsEntriesDataOffset += 4;
771					
772					$frames_count += $atom_structure ['time_to_sample_table'] [$i] ['sample_count'];
773					
774					// THIS SECTION REPLACED WITH CODE IN "stbl" ATOM
775					//if (!empty($info['quicktime']['time_scale']) && ($atom_structure['time_to_sample_table'][$i]['sample_duration'] > 0)) {
776					//	$stts_new_framerate = $info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration'];
777					//	if ($stts_new_framerate <= 60) {
778					//		// some atoms have durations of "1" giving a very large framerate, which probably is not right
779					//		$info['video']['frame_rate'] = max($info['video']['frame_rate'], $stts_new_framerate);
780					//	}
781					//}
782					//
783					//$FrameRateCalculatorArray[($info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration'])] += $atom_structure['time_to_sample_table'][$i]['sample_count'];
784				}
785				$info ['quicktime'] ['stts_framecount'] [] = $frames_count;
786				//$sttsFramesTotal  = 0;
787				//$sttsSecondsTotal = 0;
788				//foreach ($FrameRateCalculatorArray as $frames_per_second => $frame_count) {
789				//	if (($frames_per_second > 60) || ($frames_per_second < 1)) {
790				//		// not video FPS information, probably audio information
791				//		$sttsFramesTotal  = 0;
792				//		$sttsSecondsTotal = 0;
793				//		break;
794				//	}
795				//	$sttsFramesTotal  += $frame_count;
796				//	$sttsSecondsTotal += $frame_count / $frames_per_second;
797				//}
798				//if (($sttsFramesTotal > 0) && ($sttsSecondsTotal > 0)) {
799				//	if (($sttsFramesTotal / $sttsSecondsTotal) > $info['video']['frame_rate']) {
800				//		$info['video']['frame_rate'] = $sttsFramesTotal / $sttsSecondsTotal;
801				//	}
802				//}
803				break;
804			
805			case 'stss' : // Sample Table Sync Sample (key frames) atom
806				if ($ParseAllPossibleAtoms) {
807					$atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
808					$atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
809					$atom_structure ['number_entries'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 4 ) );
810					$stssEntriesDataOffset = 8;
811					for($i = 0; $i < $atom_structure ['number_entries']; $i ++) {
812						$atom_structure ['time_to_sample_table'] [$i] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $stssEntriesDataOffset, 4 ) );
813						$stssEntriesDataOffset += 4;
814					}
815				}
816				break;
817			
818			case 'stsc' : // Sample Table Sample-to-Chunk atom
819				if ($ParseAllPossibleAtoms) {
820					$atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
821					$atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
822					$atom_structure ['number_entries'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 4 ) );
823					$stscEntriesDataOffset = 8;
824					for($i = 0; $i < $atom_structure ['number_entries']; $i ++) {
825						$atom_structure ['sample_to_chunk_table'] [$i] ['first_chunk'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $stscEntriesDataOffset, 4 ) );
826						$stscEntriesDataOffset += 4;
827						$atom_structure ['sample_to_chunk_table'] [$i] ['samples_per_chunk'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $stscEntriesDataOffset, 4 ) );
828						$stscEntriesDataOffset += 4;
829						$atom_structure ['sample_to_chunk_table'] [$i] ['sample_description'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $stscEntriesDataOffset, 4 ) );
830						$stscEntriesDataOffset += 4;
831					}
832				}
833				break;
834			
835			case 'stsz' : // Sample Table SiZe atom
836				if ($ParseAllPossibleAtoms) {
837					$atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
838					$atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
839					$atom_structure ['sample_size'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 4 ) );
840					$atom_structure ['number_entries'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 8, 4 ) );
841					$stszEntriesDataOffset = 12;
842					if ($atom_structure ['sample_size'] == 0) {
843						for($i = 0; $i < $atom_structure ['number_entries']; $i ++) {
844							$atom_structure ['sample_size_table'] [$i] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $stszEntriesDataOffset, 4 ) );
845							$stszEntriesDataOffset += 4;
846						}
847					}
848				}
849				break;
850			
851			case 'stco' : // Sample Table Chunk Offset atom
852				if ($ParseAllPossibleAtoms) {
853					$atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
854					$atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
855					$atom_structure ['number_entries'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 4 ) );
856					$stcoEntriesDataOffset = 8;
857					for($i = 0; $i < $atom_structure ['number_entries']; $i ++) {
858						$atom_structure ['chunk_offset_table'] [$i] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $stcoEntriesDataOffset, 4 ) );
859						$stcoEntriesDataOffset += 4;
860					}
861				}
862				break;
863			
864			case 'co64' : // Chunk Offset 64-bit (version of "stco" that supports > 2GB files)
865				if ($ParseAllPossibleAtoms) {
866					$atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
867					$atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
868					$atom_structure ['number_entries'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 4 ) );
869					$stcoEntriesDataOffset = 8;
870					for($i = 0; $i < $atom_structure ['number_entries']; $i ++) {
871						$atom_structure ['chunk_offset_table'] [$i] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $stcoEntriesDataOffset, 8 ) );
872						$stcoEntriesDataOffset += 8;
873					}
874				}
875				break;
876			
877			case 'dref' : // Data REFerence atom
878				$atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
879				$atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
880				$atom_structure ['number_entries'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 4 ) );
881				$drefDataOffset = 8;
882				for($i = 0; $i < $atom_structure ['number_entries']; $i ++) {
883					$atom_structure ['data_references'] [$i] ['size'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $drefDataOffset, 4 ) );
884					$drefDataOffset += 4;
885					$atom_structure ['data_references'] [$i] ['type'] = substr ( $atom_data, $drefDataOffset, 4 );
886					$drefDataOffset += 4;
887					$atom_structure ['data_references'] [$i] ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $drefDataOffset, 1 ) );
888					$drefDataOffset += 1;
889					$atom_structure ['data_references'] [$i] ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $drefDataOffset, 3 ) ); // hardcoded: 0x0000
890					$drefDataOffset += 3;
891					$atom_structure ['data_references'] [$i] ['data'] = substr ( $atom_data, $drefDataOffset, ($atom_structure ['data_references'] [$i] ['size'] - 4 - 4 - 1 - 3) );
892					$drefDataOffset += ($atom_structure ['data_references'] [$i] ['size'] - 4 - 4 - 1 - 3);
893					
894					$atom_structure ['data_references'] [$i] ['flags'] ['self_reference'] = ( bool ) ($atom_structure ['data_references'] [$i] ['flags_raw'] & 0x001);
895				}
896				break;
897			
898			case 'gmin' : // base Media INformation atom
899				$atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
900				$atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
901				$atom_structure ['graphics_mode'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 2 ) );
902				$atom_structure ['opcolor_red'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 6, 2 ) );
903				$atom_structure ['opcolor_green'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 8, 2 ) );
904				$atom_structure ['opcolor_blue'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 10, 2 ) );
905				$atom_structure ['balance'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 12, 2 ) );
906				$atom_structure ['reserved'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 14, 2 ) );
907				break;
908			
909			case 'smhd' : // Sound Media information HeaDer atom
910				$atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
911				$atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
912				$atom_structure ['balance'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 2 ) );
913				$atom_structure ['reserved'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 6, 2 ) );
914				break;
915			
916			case 'vmhd' : // Video Media information HeaDer atom
917				$atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
918				$atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) );
919				$atom_structure ['graphics_mode'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 2 ) );
920				$atom_structure ['opcolor_red'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 6, 2 ) );
921				$atom_structure ['opcolor_green'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 8, 2 ) );
922				$atom_structure ['opcolor_blue'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 10, 2 ) );
923				
924				$atom_structure ['flags'] ['no_lean_ahead'] = ( bool ) ($atom_structure ['flags_raw'] & 0x001);
925				break;
926			
927			case 'hdlr' : // HanDLeR reference atom
928				$atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
929				$atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
930				$atom_structure ['component_type'] = substr ( $atom_data, 4, 4 );
931				$atom_structure ['component_subtype'] = substr ( $atom_data, 8, 4 );
932				$atom_structure ['component_manufacturer'] = substr ( $atom_data, 12, 4 );
933				$atom_structure ['component_flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 16, 4 ) );
934				$atom_structure ['component_flags_mask'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 20, 4 ) );
935				$atom_structure ['component_name'] = $this->Pascal2String ( substr ( $atom_data, 24 ) );
936				
937				if (($atom_structure ['component_subtype'] == 'STpn') && ($atom_structure ['component_manufacturer'] == 'zzzz')) {
938					$info ['video'] ['dataformat'] = 'quicktimevr';
939				}
940				break;
941			
942			case 'mdhd' : // MeDia HeaDer atom
943				$atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
944				$atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
945				$atom_structure ['creation_time'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 4 ) );
946				$atom_structure ['modify_time'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 8, 4 ) );
947				$atom_structure ['time_scale'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 12, 4 ) );
948				$atom_structure ['duration'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 16, 4 ) );
949				$atom_structure ['language_id'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 20, 2 ) );
950				$atom_structure ['quality'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 22, 2 ) );
951				
952				if ($atom_structure ['time_scale'] == 0) {
953					$info ['error'] [] = 'Corrupt Quicktime file: mdhd.time_scale == zero';
954					return false;
955				}
956				$info ['quicktime'] ['time_scale'] = (isset ( $info ['quicktime'] ['time_scale'] ) ? max ( $info ['quicktime'] ['time_scale'], $atom_structure ['time_scale'] ) : $atom_structure ['time_scale']);
957				
958				$atom_structure ['creation_time_unix'] = getid3_lib::DateMac2Unix ( $atom_structure ['creation_time'] );
959				$atom_structure ['modify_time_unix'] = getid3_lib::DateMac2Unix ( $atom_structure ['modify_time'] );
960				$atom_structure ['playtime_seconds'] = $atom_structure ['duration'] / $atom_structure ['time_scale'];
961				$atom_structure ['language'] = $this->QuicktimeLanguageLookup ( $atom_structure ['language_id'] );
962				if (empty ( $info ['comments'] ['language'] ) || (! in_array ( $atom_structure ['language'], $info ['comments'] ['language'] ))) {
963					$info ['comments'] ['language'] [] = $atom_structure ['language'];
964				}
965				break;
966			
967			case 'pnot' : // Preview atom
968				$atom_structure ['modification_date'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 4 ) ); // "standard Mac…

Large files files are truncated, but you can click here to view the full file