Passed
Branch ticket-41057 (c4f931)
by Stephen
24:38
created

CopyToAppropriateCommentsSection()   D

Complexity

Conditions 13
Paths 64

Size

Total Lines 121
Code Lines 86

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 86
nc 64
nop 3
dl 0
loc 121
rs 4.9922
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/////////////////////////////////////////////////////////////////
3
/// getID3() by James Heinrich <[email protected]>               //
4
//  available at http://getid3.sourceforge.net                 //
5
//            or http://www.getid3.org                         //
6
//          also https://github.com/JamesHeinrich/getID3       //
7
/////////////////////////////////////////////////////////////////
8
// See readme.txt for more details                             //
9
/////////////////////////////////////////////////////////////////
10
//                                                             //
11
// module.audio-video.quicktime.php                            //
12
// module for analyzing Quicktime and MP3-in-MP4 files         //
13
// dependencies: module.audio.mp3.php                          //
14
// dependencies: module.tag.id3v2.php                          //
15
//                                                            ///
16
/////////////////////////////////////////////////////////////////
17
18
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true);
19
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true); // needed for ISO 639-2 language code lookup
20
21
class getid3_quicktime extends getid3_handler
22
{
23
24
	public $ReturnAtomData        = true;
25
	public $ParseAllPossibleAtoms = false;
26
27
	public function Analyze() {
28
		$info = &$this->getid3->info;
29
30
		$info['fileformat'] = 'quicktime';
31
		$info['quicktime']['hinting']    = false;
32
		$info['quicktime']['controller'] = 'standard'; // may be overridden if 'ctyp' atom is present
33
34
		$this->fseek($info['avdataoffset']);
35
36
		$offset      = 0;
37
		$atomcounter = 0;
38
		$atom_data_read_buffer_size = ($info['php_memory_limit'] ? round($info['php_memory_limit'] / 2) : $this->getid3->option_fread_buffer_size * 1024); // allow [default: 32MB] if PHP configured with no memory_limit
39
		while ($offset < $info['avdataend']) {
40
			if (!getid3_lib::intValueSupported($offset)) {
41
				$info['error'][] = 'Unable to parse atom at offset '.$offset.' because beyond '.round(PHP_INT_MAX / 1073741824).'GB limit of PHP filesystem functions';
42
				break;
43
			}
44
			$this->fseek($offset);
45
			$AtomHeader = $this->fread(8);
46
47
			$atomsize = getid3_lib::BigEndian2Int(substr($AtomHeader, 0, 4));
48
			$atomname = substr($AtomHeader, 4, 4);
49
50
			// 64-bit MOV patch by jlegateØktnc*com
51
			if ($atomsize == 1) {
52
				$atomsize = getid3_lib::BigEndian2Int($this->fread(8));
53
			}
54
55
			$info['quicktime'][$atomname]['name']   = $atomname;
56
			$info['quicktime'][$atomname]['size']   = $atomsize;
57
			$info['quicktime'][$atomname]['offset'] = $offset;
58
59
			if (($offset + $atomsize) > $info['avdataend']) {
60
				$info['error'][] = 'Atom at offset '.$offset.' claims to go beyond end-of-file (length: '.$atomsize.' bytes)';
61
				return false;
62
			}
63
64
			if ($atomsize == 0) {
65
				// Furthermore, for historical reasons the list of atoms is optionally
66
				// terminated by a 32-bit integer set to 0. If you are writing a program
67
				// to read user data atoms, you should allow for the terminating 0.
68
				break;
69
			}
70
			$atomHierarchy = array();
71
			$info['quicktime'][$atomname] = $this->QuicktimeParseAtom($atomname, $atomsize, $this->fread(min($atomsize, $atom_data_read_buffer_size)), $offset, $atomHierarchy, $this->ParseAllPossibleAtoms);
72
73
			$offset += $atomsize;
74
			$atomcounter++;
75
		}
76
77
		if (!empty($info['avdataend_tmp'])) {
78
			// this value is assigned to a temp value and then erased because
79
			// otherwise any atoms beyond the 'mdat' atom would not get parsed
80
			$info['avdataend'] = $info['avdataend_tmp'];
81
			unset($info['avdataend_tmp']);
82
		}
83
84 View Code Duplication
		if (!isset($info['bitrate']) && isset($info['playtime_seconds'])) {
85
			$info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
86
		}
87
		if (isset($info['bitrate']) && !isset($info['audio']['bitrate']) && !isset($info['quicktime']['video'])) {
88
			$info['audio']['bitrate'] = $info['bitrate'];
89
		}
90
		if (!empty($info['playtime_seconds']) && !isset($info['video']['frame_rate']) && !empty($info['quicktime']['stts_framecount'])) {
91
			foreach ($info['quicktime']['stts_framecount'] as $key => $samples_count) {
92
				$samples_per_second = $samples_count / $info['playtime_seconds'];
93
				if ($samples_per_second > 240) {
94
					// has to be audio samples
95
				} else {
96
					$info['video']['frame_rate'] = $samples_per_second;
97
					break;
98
				}
99
			}
100
		}
101
		if (($info['audio']['dataformat'] == 'mp4') && empty($info['video']['resolution_x'])) {
102
			$info['fileformat'] = 'mp4';
103
			$info['mime_type']  = 'audio/mp4';
104
			unset($info['video']['dataformat']);
105
		}
106
107
		if (!$this->ReturnAtomData) {
108
			unset($info['quicktime']['moov']);
109
		}
110
111 View Code Duplication
		if (empty($info['audio']['dataformat']) && !empty($info['quicktime']['audio'])) {
112
			$info['audio']['dataformat'] = 'quicktime';
113
		}
114 View Code Duplication
		if (empty($info['video']['dataformat']) && !empty($info['quicktime']['video'])) {
115
			$info['video']['dataformat'] = 'quicktime';
116
		}
117
118
		return true;
119
	}
120
121
	public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
122
		// http://developer.apple.com/techpubs/quicktime/qtdevdocs/APIREF/INDEX/atomalphaindex.htm
123
124
		$info = &$this->getid3->info;
125
126
		$atom_parent = end($atomHierarchy); // not array_pop($atomHierarchy); see http://www.getid3.org/phpBB3/viewtopic.php?t=1717
127
		array_push($atomHierarchy, $atomname);
128
		$atom_structure['hierarchy'] = implode(' ', $atomHierarchy);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$atom_structure was never initialized. Although not strictly required by PHP, it is generally a good practice to add $atom_structure = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
129
		$atom_structure['name']      = $atomname;
130
		$atom_structure['size']      = $atomsize;
131
		$atom_structure['offset']    = $baseoffset;
132
		switch ($atomname) {
133
			case 'moov': // MOVie container atom
134
			case 'trak': // TRAcK container atom
135
			case 'clip': // CLIPping container atom
136
			case 'matt': // track MATTe container atom
137
			case 'edts': // EDiTS container atom
138
			case 'tref': // Track REFerence container atom
139
			case 'mdia': // MeDIA container atom
140
			case 'minf': // Media INFormation container atom
141
			case 'dinf': // Data INFormation container atom
142
			case 'udta': // User DaTA container atom
143
			case 'cmov': // Compressed MOVie container atom
144
			case 'rmra': // Reference Movie Record Atom
145
			case 'rmda': // Reference Movie Descriptor Atom
146
			case 'gmhd': // Generic Media info HeaDer atom (seen on QTVR)
147
				$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
148
				break;
149
150
			case 'ilst': // Item LiST container atom
151
				if ($atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms)) {
152
					// some "ilst" atoms contain data atoms that have a numeric name, and the data is far more accessible if the returned array is compacted
153
					$allnumericnames = true;
154
					foreach ($atom_structure['subatoms'] as $subatomarray) {
0 ignored issues
show
Bug introduced by
The expression $atom_structure['subatoms'] of type boolean is not traversable.
Loading history...
155
						if (!is_integer($subatomarray['name']) || (count($subatomarray['subatoms']) != 1)) {
156
							$allnumericnames = false;
157
							break;
158
						}
159
					}
160
					if ($allnumericnames) {
161
						$newData = array();
162
						foreach ($atom_structure['subatoms'] as $subatomarray) {
0 ignored issues
show
Bug introduced by
The expression $atom_structure['subatoms'] of type boolean is not traversable.
Loading history...
163
							foreach ($subatomarray['subatoms'] as $newData_subatomarray) {
164
								unset($newData_subatomarray['hierarchy'], $newData_subatomarray['name']);
165
								$newData[$subatomarray['name']] = $newData_subatomarray;
166
								break;
167
							}
168
						}
169
						$atom_structure['data'] = $newData;
170
						unset($atom_structure['subatoms']);
171
					}
172
				}
173
				break;
174
175
			case "\x00\x00\x00\x01":
176
			case "\x00\x00\x00\x02":
177
			case "\x00\x00\x00\x03":
178
			case "\x00\x00\x00\x04":
179
			case "\x00\x00\x00\x05":
180
				$atomname = getid3_lib::BigEndian2Int($atomname);
181
				$atom_structure['name'] = $atomname;
182
				$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
183
				break;
184
185
			case 'stbl': // Sample TaBLe container atom
186
				$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
187
				$isVideo = false;
188
				$framerate  = 0;
189
				$framecount = 0;
190
				foreach ($atom_structure['subatoms'] as $key => $value_array) {
0 ignored issues
show
Bug introduced by
The expression $atom_structure['subatoms'] of type boolean is not traversable.
Loading history...
191
					if (isset($value_array['sample_description_table'])) {
192
						foreach ($value_array['sample_description_table'] as $key2 => $value_array2) {
193
							if (isset($value_array2['data_format'])) {
194
								switch ($value_array2['data_format']) {
195
									case 'avc1':
196
									case 'mp4v':
197
										// video data
198
										$isVideo = true;
199
										break;
200
									case 'mp4a':
201
										// audio data
202
										break;
203
								}
204
							}
205
						}
206
					} elseif (isset($value_array['time_to_sample_table'])) {
207
						foreach ($value_array['time_to_sample_table'] as $key2 => $value_array2) {
208
							if (isset($value_array2['sample_count']) && isset($value_array2['sample_duration']) && ($value_array2['sample_duration'] > 0)) {
209
								$framerate  = round($info['quicktime']['time_scale'] / $value_array2['sample_duration'], 3);
210
								$framecount = $value_array2['sample_count'];
211
							}
212
						}
213
					}
214
				}
215
				if ($isVideo && $framerate) {
216
					$info['quicktime']['video']['frame_rate'] = $framerate;
217
					$info['video']['frame_rate'] = $info['quicktime']['video']['frame_rate'];
218
				}
219
				if ($isVideo && $framecount) {
220
					$info['quicktime']['video']['frame_count'] = $framecount;
221
				}
222
				break;
223
224
225
			case 'aART': // Album ARTist
226
			case 'catg': // CaTeGory
227
			case 'covr': // COVeR artwork
228
			case 'cpil': // ComPILation
229
			case 'cprt': // CoPyRighT
230
			case 'desc': // DESCription
231
			case 'disk': // DISK number
232
			case 'egid': // Episode Global ID
233
			case 'gnre': // GeNRE
234
			case 'keyw': // KEYWord
235
			case 'ldes':
236
			case 'pcst': // PodCaST
237
			case 'pgap': // GAPless Playback
238
			case 'purd': // PURchase Date
239
			case 'purl': // Podcast URL
240
			case 'rati':
241
			case 'rndu':
242
			case 'rpdu':
243
			case 'rtng': // RaTiNG
244
			case 'stik':
245
			case 'tmpo': // TeMPO (BPM)
246
			case 'trkn': // TRacK Number
247
			case 'tves': // TV EpiSode
248
			case 'tvnn': // TV Network Name
249
			case 'tvsh': // TV SHow Name
250
			case 'tvsn': // TV SeasoN
251
			case 'akID': // iTunes store account type
252
			case 'apID':
253
			case 'atID':
254
			case 'cmID':
255
			case 'cnID':
256
			case 'geID':
257
			case 'plID':
258
			case 'sfID': // iTunes store country
259
			case "\xA9".'alb': // ALBum
260
			case "\xA9".'art': // ARTist
261
			case "\xA9".'ART':
262
			case "\xA9".'aut':
263
			case "\xA9".'cmt': // CoMmenT
264
			case "\xA9".'com': // COMposer
265
			case "\xA9".'cpy':
266
			case "\xA9".'day': // content created year
267
			case "\xA9".'dir':
268
			case "\xA9".'ed1':
269
			case "\xA9".'ed2':
270
			case "\xA9".'ed3':
271
			case "\xA9".'ed4':
272
			case "\xA9".'ed5':
273
			case "\xA9".'ed6':
274
			case "\xA9".'ed7':
275
			case "\xA9".'ed8':
276
			case "\xA9".'ed9':
277
			case "\xA9".'enc':
278
			case "\xA9".'fmt':
279
			case "\xA9".'gen': // GENre
280
			case "\xA9".'grp': // GRouPing
281
			case "\xA9".'hst':
282
			case "\xA9".'inf':
283
			case "\xA9".'lyr': // LYRics
284
			case "\xA9".'mak':
285
			case "\xA9".'mod':
286
			case "\xA9".'nam': // full NAMe
287
			case "\xA9".'ope':
288
			case "\xA9".'PRD':
289
			case "\xA9".'prd':
290
			case "\xA9".'prf':
291
			case "\xA9".'req':
292
			case "\xA9".'src':
293
			case "\xA9".'swr':
294
			case "\xA9".'too': // encoder
295
			case "\xA9".'trk': // TRacK
296
			case "\xA9".'url':
297
			case "\xA9".'wrn':
298
			case "\xA9".'wrt': // WRiTer
299
			case '----': // itunes specific
300
				if ($atom_parent == 'udta') {
301
					// User data atom handler
302
					$atom_structure['data_length'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2));
303
					$atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2));
304
					$atom_structure['data']        =                           substr($atom_data, 4);
305
306
					$atom_structure['language']    = $this->QuicktimeLanguageLookup($atom_structure['language_id']);
307 View Code Duplication
					if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) {
308
						$info['comments']['language'][] = $atom_structure['language'];
309
					}
310
				} else {
311
					// Apple item list box atom handler
312
					$atomoffset = 0;
313
					if (substr($atom_data, 2, 2) == "\x10\xB5") {
314
						// not sure what it means, but observed on iPhone4 data.
315
						// Each $atom_data has 2 bytes of datasize, plus 0x10B5, then data
316
						while ($atomoffset < strlen($atom_data)) {
317
							$boxsmallsize = getid3_lib::BigEndian2Int(substr($atom_data, $atomoffset,     2));
318
							$boxsmalltype =                           substr($atom_data, $atomoffset + 2, 2);
319
							$boxsmalldata =                           substr($atom_data, $atomoffset + 4, $boxsmallsize);
320 View Code Duplication
							if ($boxsmallsize <= 1) {
321
								$info['warning'][] = 'Invalid QuickTime atom smallbox size "'.$boxsmallsize.'" in atom "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" at offset: '.($atom_structure['offset'] + $atomoffset);
322
								$atom_structure['data'] = null;
323
								$atomoffset = strlen($atom_data);
324
								break;
325
							}
326
							switch ($boxsmalltype) {
327
								case "\x10\xB5":
328
									$atom_structure['data'] = $boxsmalldata;
329
									break;
330 View Code Duplication
								default:
331
									$info['warning'][] = 'Unknown QuickTime smallbox type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $boxsmalltype).'" ('.trim(getid3_lib::PrintHexBytes($boxsmalltype)).') at offset '.$baseoffset;
332
									$atom_structure['data'] = $atom_data;
333
									break;
334
							}
335
							$atomoffset += (4 + $boxsmallsize);
336
						}
337
					} else {
338
						while ($atomoffset < strlen($atom_data)) {
339
							$boxsize = getid3_lib::BigEndian2Int(substr($atom_data, $atomoffset, 4));
340
							$boxtype =                           substr($atom_data, $atomoffset + 4, 4);
341
							$boxdata =                           substr($atom_data, $atomoffset + 8, $boxsize - 8);
342 View Code Duplication
							if ($boxsize <= 1) {
343
								$info['warning'][] = 'Invalid QuickTime atom box size "'.$boxsize.'" in atom "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" at offset: '.($atom_structure['offset'] + $atomoffset);
344
								$atom_structure['data'] = null;
345
								$atomoffset = strlen($atom_data);
346
								break;
347
							}
348
							$atomoffset += $boxsize;
349
350
							switch ($boxtype) {
351
								case 'mean':
352
								case 'name':
353
									$atom_structure[$boxtype] = substr($boxdata, 4);
354
									break;
355
356
								case 'data':
357
									$atom_structure['version']   = getid3_lib::BigEndian2Int(substr($boxdata,  0, 1));
358
									$atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($boxdata,  1, 3));
359
									switch ($atom_structure['flags_raw']) {
360
										case  0: // data flag
361
										case 21: // tmpo/cpil flag
362
											switch ($atomname) {
363
												case 'cpil':
364
												case 'pcst':
365
												case 'pgap':
366
													$atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
367
													break;
368
369
												case 'tmpo':
370
													$atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 2));
371
													break;
372
373
												case 'disk':
374
												case 'trkn':
375
													$num       = getid3_lib::BigEndian2Int(substr($boxdata, 10, 2));
376
													$num_total = getid3_lib::BigEndian2Int(substr($boxdata, 12, 2));
377
													$atom_structure['data']  = empty($num) ? '' : $num;
378
													$atom_structure['data'] .= empty($num_total) ? '' : '/'.$num_total;
379
													break;
380
381 View Code Duplication
												case 'gnre':
382
													$GenreID = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
383
													$atom_structure['data']    = getid3_id3v1::LookupGenreName($GenreID - 1);
384
													break;
385
386 View Code Duplication
												case 'rtng':
387
													$atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
388
													$atom_structure['data']    = $this->QuicktimeContentRatingLookup($atom_structure[$atomname]);
389
													break;
390
391 View Code Duplication
												case 'stik':
392
													$atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
393
													$atom_structure['data']    = $this->QuicktimeSTIKLookup($atom_structure[$atomname]);
394
													break;
395
396 View Code Duplication
												case 'sfID':
397
													$atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
398
													$atom_structure['data']    = $this->QuicktimeStoreFrontCodeLookup($atom_structure[$atomname]);
399
													break;
400
401
												case 'egid':
402
												case 'purl':
403
													$atom_structure['data'] = substr($boxdata, 8);
404
													break;
405
406
												default:
407
													$atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
408
											}
409
											break;
410
411
										case  1: // text flag
412
										case 13: // image flag
413
										default:
414
											$atom_structure['data'] = substr($boxdata, 8);
415
											if ($atomname == 'covr') {
416
												// not a foolproof check, but better than nothing
417
												if (preg_match('#^\xFF\xD8\xFF#', $atom_structure['data'])) {
418
													$atom_structure['image_mime'] = 'image/jpeg';
419
												} elseif (preg_match('#^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A#', $atom_structure['data'])) {
420
													$atom_structure['image_mime'] = 'image/png';
421
												} elseif (preg_match('#^GIF#', $atom_structure['data'])) {
422
													$atom_structure['image_mime'] = 'image/gif';
423
												}
424
											}
425
											break;
426
427
									}
428
									break;
429
430
								default:
431
									$info['warning'][] = 'Unknown QuickTime box type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $boxtype).'" ('.trim(getid3_lib::PrintHexBytes($boxtype)).') at offset '.$baseoffset;
432
									$atom_structure['data'] = $atom_data;
433
434
							}
435
						}
436
					}
437
				}
438
				$this->CopyToAppropriateCommentsSection($atomname, $atom_structure['data'], $atom_structure['name']);
439
				break;
440
441
442
			case 'play': // auto-PLAY atom
443
				$atom_structure['autoplay'] = (bool) getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
444
445
				$info['quicktime']['autoplay'] = $atom_structure['autoplay'];
446
				break;
447
448
449 View Code Duplication
			case 'WLOC': // Window LOCation atom
450
				$atom_structure['location_x']  = getid3_lib::BigEndian2Int(substr($atom_data,  0, 2));
451
				$atom_structure['location_y']  = getid3_lib::BigEndian2Int(substr($atom_data,  2, 2));
452
				break;
453
454
455
			case 'LOOP': // LOOPing atom
456
			case 'SelO': // play SELection Only atom
457
			case 'AllF': // play ALL Frames atom
458
				$atom_structure['data'] = getid3_lib::BigEndian2Int($atom_data);
459
				break;
460
461
462
			case 'name': //
463
			case 'MCPS': // Media Cleaner PRo
464
			case '@PRM': // adobe PReMiere version
465
			case '@PRQ': // adobe PRemiere Quicktime version
466
				$atom_structure['data'] = $atom_data;
467
				break;
468
469
470
			case 'cmvd': // Compressed MooV Data atom
471
				// Code by ubergeekØubergeek*tv based on information from
472
				// http://developer.apple.com/quicktime/icefloe/dispatch012.html
473
				$atom_structure['unCompressedSize'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4));
474
475
				$CompressedFileData = substr($atom_data, 4);
476
				if ($UncompressedHeader = @gzuncompress($CompressedFileData)) {
477
					$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($UncompressedHeader, 0, $atomHierarchy, $ParseAllPossibleAtoms);
478
				} else {
479
					$info['warning'][] = 'Error decompressing compressed MOV atom at offset '.$atom_structure['offset'];
480
				}
481
				break;
482
483
484
			case 'dcom': // Data COMpression atom
485
				$atom_structure['compression_id']   = $atom_data;
486
				$atom_structure['compression_text'] = $this->QuicktimeDCOMLookup($atom_data);
487
				break;
488
489
490
			case 'rdrf': // Reference movie Data ReFerence atom
491
				$atom_structure['version']                = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
492
				$atom_structure['flags_raw']              = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3));
493
				$atom_structure['flags']['internal_data'] = (bool) ($atom_structure['flags_raw'] & 0x000001);
494
495
				$atom_structure['reference_type_name']    =                           substr($atom_data,  4, 4);
496
				$atom_structure['reference_length']       = getid3_lib::BigEndian2Int(substr($atom_data,  8, 4));
497
				switch ($atom_structure['reference_type_name']) {
498
					case 'url ':
499
						$atom_structure['url']            =       $this->NoNullString(substr($atom_data, 12));
500
						break;
501
502
					case 'alis':
503
						$atom_structure['file_alias']     =                           substr($atom_data, 12);
504
						break;
505
506
					case 'rsrc':
507
						$atom_structure['resource_alias'] =                           substr($atom_data, 12);
508
						break;
509
510
					default:
511
						$atom_structure['data']           =                           substr($atom_data, 12);
512
						break;
513
				}
514
				break;
515
516
517
			case 'rmqu': // Reference Movie QUality atom
518
				$atom_structure['movie_quality'] = getid3_lib::BigEndian2Int($atom_data);
519
				break;
520
521
522 View Code Duplication
			case 'rmcs': // Reference Movie Cpu Speed atom
523
				$atom_structure['version']          = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
524
				$atom_structure['flags_raw']        = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
525
				$atom_structure['cpu_speed_rating'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 2));
526
				break;
527
528
529
			case 'rmvc': // Reference Movie Version Check atom
530
				$atom_structure['version']            = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
531
				$atom_structure['flags_raw']          = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
532
				$atom_structure['gestalt_selector']   =                           substr($atom_data,  4, 4);
533
				$atom_structure['gestalt_value_mask'] = getid3_lib::BigEndian2Int(substr($atom_data,  8, 4));
534
				$atom_structure['gestalt_value']      = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
535
				$atom_structure['gestalt_check_type'] = getid3_lib::BigEndian2Int(substr($atom_data, 14, 2));
536
				break;
537
538
539
			case 'rmcd': // Reference Movie Component check atom
540
				$atom_structure['version']                = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
541
				$atom_structure['flags_raw']              = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
542
				$atom_structure['component_type']         =                           substr($atom_data,  4, 4);
543
				$atom_structure['component_subtype']      =                           substr($atom_data,  8, 4);
544
				$atom_structure['component_manufacturer'] =                           substr($atom_data, 12, 4);
545
				$atom_structure['component_flags_raw']    = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
546
				$atom_structure['component_flags_mask']   = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4));
547
				$atom_structure['component_min_version']  = getid3_lib::BigEndian2Int(substr($atom_data, 24, 4));
548
				break;
549
550
551 View Code Duplication
			case 'rmdr': // Reference Movie Data Rate atom
552
				$atom_structure['version']       = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
553
				$atom_structure['flags_raw']     = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
554
				$atom_structure['data_rate']     = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
555
556
				$atom_structure['data_rate_bps'] = $atom_structure['data_rate'] * 10;
557
				break;
558
559
560
			case 'rmla': // Reference Movie Language Atom
561
				$atom_structure['version']     = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
562
				$atom_structure['flags_raw']   = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
563
				$atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 2));
564
565
				$atom_structure['language']    = $this->QuicktimeLanguageLookup($atom_structure['language_id']);
566 View Code Duplication
				if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) {
567
					$info['comments']['language'][] = $atom_structure['language'];
568
				}
569
				break;
570
571
572 View Code Duplication
			case 'rmla': // Reference Movie Language Atom
573
				$atom_structure['version']   = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
574
				$atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
575
				$atom_structure['track_id']  = getid3_lib::BigEndian2Int(substr($atom_data,  4, 2));
576
				break;
577
578
579
			case 'ptv ': // Print To Video - defines a movie's full screen mode
580
				// http://developer.apple.com/documentation/QuickTime/APIREF/SOURCESIV/at_ptv-_pg.htm
581
				$atom_structure['display_size_raw']  = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2));
582
				$atom_structure['reserved_1']        = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2)); // hardcoded: 0x0000
583
				$atom_structure['reserved_2']        = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x0000
584
				$atom_structure['slide_show_flag']   = getid3_lib::BigEndian2Int(substr($atom_data, 6, 1));
585
				$atom_structure['play_on_open_flag'] = getid3_lib::BigEndian2Int(substr($atom_data, 7, 1));
586
587
				$atom_structure['flags']['play_on_open'] = (bool) $atom_structure['play_on_open_flag'];
588
				$atom_structure['flags']['slide_show']   = (bool) $atom_structure['slide_show_flag'];
589
590
				$ptv_lookup[0] = 'normal';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$ptv_lookup was never initialized. Although not strictly required by PHP, it is generally a good practice to add $ptv_lookup = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
591
				$ptv_lookup[1] = 'double';
592
				$ptv_lookup[2] = 'half';
593
				$ptv_lookup[3] = 'full';
594
				$ptv_lookup[4] = 'current';
595
				if (isset($ptv_lookup[$atom_structure['display_size_raw']])) {
596
					$atom_structure['display_size'] = $ptv_lookup[$atom_structure['display_size_raw']];
597
				} else {
598
					$info['warning'][] = 'unknown "ptv " display constant ('.$atom_structure['display_size_raw'].')';
599
				}
600
				break;
601
602
603
			case 'stsd': // Sample Table Sample Description atom
604
				$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
605
				$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
606
				$atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
607
				$stsdEntriesDataOffset = 8;
608
				for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
609
					$atom_structure['sample_description_table'][$i]['size']             = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 4));
610
					$stsdEntriesDataOffset += 4;
611
					$atom_structure['sample_description_table'][$i]['data_format']      =                           substr($atom_data, $stsdEntriesDataOffset, 4);
612
					$stsdEntriesDataOffset += 4;
613
					$atom_structure['sample_description_table'][$i]['reserved']         = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 6));
614
					$stsdEntriesDataOffset += 6;
615
					$atom_structure['sample_description_table'][$i]['reference_index']  = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 2));
616
					$stsdEntriesDataOffset += 2;
617
					$atom_structure['sample_description_table'][$i]['data']             =                           substr($atom_data, $stsdEntriesDataOffset, ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2));
618
					$stsdEntriesDataOffset += ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2);
619
620
					$atom_structure['sample_description_table'][$i]['encoder_version']  = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'],  0, 2));
621
					$atom_structure['sample_description_table'][$i]['encoder_revision'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'],  2, 2));
622
					$atom_structure['sample_description_table'][$i]['encoder_vendor']   =                           substr($atom_structure['sample_description_table'][$i]['data'],  4, 4);
623
624
					switch ($atom_structure['sample_description_table'][$i]['encoder_vendor']) {
625
626
						case "\x00\x00\x00\x00":
627
							// audio tracks
628
							$atom_structure['sample_description_table'][$i]['audio_channels']       =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'],  8,  2));
629
							$atom_structure['sample_description_table'][$i]['audio_bit_depth']      =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 10,  2));
630
							$atom_structure['sample_description_table'][$i]['audio_compression_id'] =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12,  2));
631
							$atom_structure['sample_description_table'][$i]['audio_packet_size']    =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 14,  2));
632
							$atom_structure['sample_description_table'][$i]['audio_sample_rate']    = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 16,  4));
633
634
							// video tracks
635
							// http://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap3/qtff3.html
636
							$atom_structure['sample_description_table'][$i]['temporal_quality'] =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'],  8,  4));
637
							$atom_structure['sample_description_table'][$i]['spatial_quality']  =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12,  4));
638
							$atom_structure['sample_description_table'][$i]['width']            =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 16,  2));
639
							$atom_structure['sample_description_table'][$i]['height']           =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 18,  2));
640
							$atom_structure['sample_description_table'][$i]['resolution_x']     = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 24,  4));
641
							$atom_structure['sample_description_table'][$i]['resolution_y']     = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 28,  4));
642
							$atom_structure['sample_description_table'][$i]['data_size']        =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 32,  4));
643
							$atom_structure['sample_description_table'][$i]['frame_count']      =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 36,  2));
644
							$atom_structure['sample_description_table'][$i]['compressor_name']  =                             substr($atom_structure['sample_description_table'][$i]['data'], 38,  4);
645
							$atom_structure['sample_description_table'][$i]['pixel_depth']      =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 42,  2));
646
							$atom_structure['sample_description_table'][$i]['color_table_id']   =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 44,  2));
647
648
							switch ($atom_structure['sample_description_table'][$i]['data_format']) {
649
								case '2vuY':
650
								case 'avc1':
651
								case 'cvid':
652
								case 'dvc ':
653
								case 'dvcp':
654
								case 'gif ':
655
								case 'h263':
656
								case 'jpeg':
657
								case 'kpcd':
658
								case 'mjpa':
659
								case 'mjpb':
660
								case 'mp4v':
661
								case 'png ':
662
								case 'raw ':
663
								case 'rle ':
664
								case 'rpza':
665
								case 'smc ':
666
								case 'SVQ1':
667
								case 'SVQ3':
668
								case 'tiff':
669
								case 'v210':
670
								case 'v216':
671
								case 'v308':
672
								case 'v408':
673
								case 'v410':
674
								case 'yuv2':
675
									$info['fileformat'] = 'mp4';
676
									$info['video']['fourcc'] = $atom_structure['sample_description_table'][$i]['data_format'];
677
// http://www.getid3.org/phpBB3/viewtopic.php?t=1550
678
//if ((!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($atom_structure['sample_description_table'][$i]['width'])) && (empty($info['video']['resolution_x']) || empty($info['video']['resolution_y']) || (number_format($info['video']['resolution_x'], 6) != number_format(round($info['video']['resolution_x']), 6)) || (number_format($info['video']['resolution_y'], 6) != number_format(round($info['video']['resolution_y']), 6)))) { // ugly check for floating point numbers
679
if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($atom_structure['sample_description_table'][$i]['height'])) {
680
	// assume that values stored here are more important than values stored in [tkhd] atom
681
	$info['video']['resolution_x'] = $atom_structure['sample_description_table'][$i]['width'];
682
	$info['video']['resolution_y'] = $atom_structure['sample_description_table'][$i]['height'];
683
	$info['quicktime']['video']['resolution_x'] = $info['video']['resolution_x'];
684
	$info['quicktime']['video']['resolution_y'] = $info['video']['resolution_y'];
685
}
686
									break;
687
688
								case 'qtvr':
689
									$info['video']['dataformat'] = 'quicktimevr';
690
									break;
691
692
								case 'mp4a':
693
								default:
694
									$info['quicktime']['audio']['codec']       = $this->QuicktimeAudioCodecLookup($atom_structure['sample_description_table'][$i]['data_format']);
695
									$info['quicktime']['audio']['sample_rate'] = $atom_structure['sample_description_table'][$i]['audio_sample_rate'];
696
									$info['quicktime']['audio']['channels']    = $atom_structure['sample_description_table'][$i]['audio_channels'];
697
									$info['quicktime']['audio']['bit_depth']   = $atom_structure['sample_description_table'][$i]['audio_bit_depth'];
698
									$info['audio']['codec']                    = $info['quicktime']['audio']['codec'];
699
									$info['audio']['sample_rate']              = $info['quicktime']['audio']['sample_rate'];
700
									$info['audio']['channels']                 = $info['quicktime']['audio']['channels'];
701
									$info['audio']['bits_per_sample']          = $info['quicktime']['audio']['bit_depth'];
702
									switch ($atom_structure['sample_description_table'][$i]['data_format']) {
703
										case 'raw ': // PCM
704
										case 'alac': // Apple Lossless Audio Codec
705
											$info['audio']['lossless'] = true;
706
											break;
707
										default:
708
											$info['audio']['lossless'] = false;
709
											break;
710
									}
711
									break;
712
							}
713
							break;
714
715
						default:
716
							switch ($atom_structure['sample_description_table'][$i]['data_format']) {
717
								case 'mp4s':
718
									$info['fileformat'] = 'mp4';
719
									break;
720
721
								default:
722
									// video atom
723
									$atom_structure['sample_description_table'][$i]['video_temporal_quality']  =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'],  8,  4));
724
									$atom_structure['sample_description_table'][$i]['video_spatial_quality']   =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12,  4));
725
									$atom_structure['sample_description_table'][$i]['video_frame_width']       =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 16,  2));
726
									$atom_structure['sample_description_table'][$i]['video_frame_height']      =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 18,  2));
727
									$atom_structure['sample_description_table'][$i]['video_resolution_x']      = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 20,  4));
728
									$atom_structure['sample_description_table'][$i]['video_resolution_y']      = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 24,  4));
729
									$atom_structure['sample_description_table'][$i]['video_data_size']         =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 28,  4));
730
									$atom_structure['sample_description_table'][$i]['video_frame_count']       =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 32,  2));
731
									$atom_structure['sample_description_table'][$i]['video_encoder_name_len']  =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 34,  1));
732
									$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']);
733
									$atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 66,  2));
734
									$atom_structure['sample_description_table'][$i]['video_color_table_id']    =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 68,  2));
735
736
									$atom_structure['sample_description_table'][$i]['video_pixel_color_type']  = (($atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color');
737
									$atom_structure['sample_description_table'][$i]['video_pixel_color_name']  = $this->QuicktimeColorNameLookup($atom_structure['sample_description_table'][$i]['video_pixel_color_depth']);
738
739
									if ($atom_structure['sample_description_table'][$i]['video_pixel_color_name'] != 'invalid') {
740
										$info['quicktime']['video']['codec_fourcc']        = $atom_structure['sample_description_table'][$i]['data_format'];
741
										$info['quicktime']['video']['codec_fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($atom_structure['sample_description_table'][$i]['data_format']);
742
										$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']);
743
										$info['quicktime']['video']['color_depth']         = $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'];
744
										$info['quicktime']['video']['color_depth_name']    = $atom_structure['sample_description_table'][$i]['video_pixel_color_name'];
745
746
										$info['video']['codec']           = $info['quicktime']['video']['codec'];
747
										$info['video']['bits_per_sample'] = $info['quicktime']['video']['color_depth'];
748
									}
749
									$info['video']['lossless']           = false;
750
									$info['video']['pixel_aspect_ratio'] = (float) 1;
751
									break;
752
							}
753
							break;
754
					}
755
					switch (strtolower($atom_structure['sample_description_table'][$i]['data_format'])) {
756
						case 'mp4a':
757
							$info['audio']['dataformat']         = 'mp4';
758
							$info['quicktime']['audio']['codec'] = 'mp4';
759
							break;
760
761
						case '3ivx':
762
						case '3iv1':
763
						case '3iv2':
764
							$info['video']['dataformat'] = '3ivx';
765
							break;
766
767
						case 'xvid':
768
							$info['video']['dataformat'] = 'xvid';
769
							break;
770
771
						case 'mp4v':
772
							$info['video']['dataformat'] = 'mpeg4';
773
							break;
774
775
						case 'divx':
776
						case 'div1':
777
						case 'div2':
778
						case 'div3':
779
						case 'div4':
780
						case 'div5':
781
						case 'div6':
782
							$info['video']['dataformat'] = 'divx';
783
							break;
784
785
						default:
786
							// do nothing
787
							break;
788
					}
789
					unset($atom_structure['sample_description_table'][$i]['data']);
790
				}
791
				break;
792
793
794
			case 'stts': // Sample Table Time-to-Sample atom
795
				$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
796
				$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
797
				$atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
798
				$sttsEntriesDataOffset = 8;
799
				//$FrameRateCalculatorArray = array();
800
				$frames_count = 0;
801
802
				$max_stts_entries_to_scan = ($info['php_memory_limit'] ? min(floor($this->getid3->memory_limit / 10000), $atom_structure['number_entries']) : $atom_structure['number_entries']);
803
				if ($max_stts_entries_to_scan < $atom_structure['number_entries']) {
804
					$info['warning'][] = 'QuickTime atom "stts" has '.$atom_structure['number_entries'].' but only scanning the first '.$max_stts_entries_to_scan.' entries due to limited PHP memory available ('.floor($atom_structure['number_entries'] / 1048576).'MB).';
805
				}
806 View Code Duplication
				for ($i = 0; $i < $max_stts_entries_to_scan; $i++) {
807
					$atom_structure['time_to_sample_table'][$i]['sample_count']    = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4));
808
					$sttsEntriesDataOffset += 4;
809
					$atom_structure['time_to_sample_table'][$i]['sample_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4));
810
					$sttsEntriesDataOffset += 4;
811
812
					$frames_count += $atom_structure['time_to_sample_table'][$i]['sample_count'];
813
814
					// THIS SECTION REPLACED WITH CODE IN "stbl" ATOM
815
					//if (!empty($info['quicktime']['time_scale']) && ($atom_structure['time_to_sample_table'][$i]['sample_duration'] > 0)) {
816
					//	$stts_new_framerate = $info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration'];
817
					//	if ($stts_new_framerate <= 60) {
818
					//		// some atoms have durations of "1" giving a very large framerate, which probably is not right
819
					//		$info['video']['frame_rate'] = max($info['video']['frame_rate'], $stts_new_framerate);
820
					//	}
821
					//}
822
					//
823
					//$FrameRateCalculatorArray[($info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration'])] += $atom_structure['time_to_sample_table'][$i]['sample_count'];
824
				}
825
				$info['quicktime']['stts_framecount'][] = $frames_count;
826
				//$sttsFramesTotal  = 0;
827
				//$sttsSecondsTotal = 0;
828
				//foreach ($FrameRateCalculatorArray as $frames_per_second => $frame_count) {
829
				//	if (($frames_per_second > 60) || ($frames_per_second < 1)) {
830
				//		// not video FPS information, probably audio information
831
				//		$sttsFramesTotal  = 0;
832
				//		$sttsSecondsTotal = 0;
833
				//		break;
834
				//	}
835
				//	$sttsFramesTotal  += $frame_count;
836
				//	$sttsSecondsTotal += $frame_count / $frames_per_second;
837
				//}
838
				//if (($sttsFramesTotal > 0) && ($sttsSecondsTotal > 0)) {
839
				//	if (($sttsFramesTotal / $sttsSecondsTotal) > $info['video']['frame_rate']) {
840
				//		$info['video']['frame_rate'] = $sttsFramesTotal / $sttsSecondsTotal;
841
				//	}
842
				//}
843
				break;
844
845
846 View Code Duplication
			case 'stss': // Sample Table Sync Sample (key frames) atom
847
				if ($ParseAllPossibleAtoms) {
848
					$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
849
					$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
850
					$atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
851
					$stssEntriesDataOffset = 8;
852
					for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
853
						$atom_structure['time_to_sample_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stssEntriesDataOffset, 4));
854
						$stssEntriesDataOffset += 4;
855
					}
856
				}
857
				break;
858
859
860
			case 'stsc': // Sample Table Sample-to-Chunk atom
861
				if ($ParseAllPossibleAtoms) {
862
					$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
863
					$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
864
					$atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
865
					$stscEntriesDataOffset = 8;
866 View Code Duplication
					for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
867
						$atom_structure['sample_to_chunk_table'][$i]['first_chunk']        = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4));
868
						$stscEntriesDataOffset += 4;
869
						$atom_structure['sample_to_chunk_table'][$i]['samples_per_chunk']  = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4));
870
						$stscEntriesDataOffset += 4;
871
						$atom_structure['sample_to_chunk_table'][$i]['sample_description'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4));
872
						$stscEntriesDataOffset += 4;
873
					}
874
				}
875
				break;
876
877
878
			case 'stsz': // Sample Table SiZe atom
879
				if ($ParseAllPossibleAtoms) {
880
					$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
881
					$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
882
					$atom_structure['sample_size']    = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
883
					$atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data,  8, 4));
884
					$stszEntriesDataOffset = 12;
885
					if ($atom_structure['sample_size'] == 0) {
886
						for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
887
							$atom_structure['sample_size_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stszEntriesDataOffset, 4));
888
							$stszEntriesDataOffset += 4;
889
						}
890
					}
891
				}
892
				break;
893
894
895 View Code Duplication
			case 'stco': // Sample Table Chunk Offset atom
896
				if ($ParseAllPossibleAtoms) {
897
					$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
898
					$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
899
					$atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
900
					$stcoEntriesDataOffset = 8;
901
					for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
902
						$atom_structure['chunk_offset_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stcoEntriesDataOffset, 4));
903
						$stcoEntriesDataOffset += 4;
904
					}
905
				}
906
				break;
907
908
909 View Code Duplication
			case 'co64': // Chunk Offset 64-bit (version of "stco" that supports > 2GB files)
910
				if ($ParseAllPossibleAtoms) {
911
					$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
912
					$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
913
					$atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
914
					$stcoEntriesDataOffset = 8;
915
					for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
916
						$atom_structure['chunk_offset_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stcoEntriesDataOffset, 8));
917
						$stcoEntriesDataOffset += 8;
918
					}
919
				}
920
				break;
921
922
923
			case 'dref': // Data REFerence atom
924
				$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
925
				$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
926
				$atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
927
				$drefDataOffset = 8;
928
				for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
929
					$atom_structure['data_references'][$i]['size']                    = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 4));
930
					$drefDataOffset += 4;
931
					$atom_structure['data_references'][$i]['type']                    =               substr($atom_data, $drefDataOffset, 4);
932
					$drefDataOffset += 4;
933
					$atom_structure['data_references'][$i]['version']                 = getid3_lib::BigEndian2Int(substr($atom_data,  $drefDataOffset, 1));
934
					$drefDataOffset += 1;
935
					$atom_structure['data_references'][$i]['flags_raw']               = getid3_lib::BigEndian2Int(substr($atom_data,  $drefDataOffset, 3)); // hardcoded: 0x0000
936
					$drefDataOffset += 3;
937
					$atom_structure['data_references'][$i]['data']                    =               substr($atom_data, $drefDataOffset, ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3));
938
					$drefDataOffset += ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3);
939
940
					$atom_structure['data_references'][$i]['flags']['self_reference'] = (bool) ($atom_structure['data_references'][$i]['flags_raw'] & 0x001);
941
				}
942
				break;
943
944
945
			case 'gmin': // base Media INformation atom
946
				$atom_structure['version']                = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
947
				$atom_structure['flags_raw']              = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
948
				$atom_structure['graphics_mode']          = getid3_lib::BigEndian2Int(substr($atom_data,  4, 2));
949
				$atom_structure['opcolor_red']            = getid3_lib::BigEndian2Int(substr($atom_data,  6, 2));
950
				$atom_structure['opcolor_green']          = getid3_lib::BigEndian2Int(substr($atom_data,  8, 2));
951
				$atom_structure['opcolor_blue']           = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2));
952
				$atom_structure['balance']                = getid3_lib::BigEndian2Int(substr($atom_data, 12, 2));
953
				$atom_structure['reserved']               = getid3_lib::BigEndian2Int(substr($atom_data, 14, 2));
954
				break;
955
956
957 View Code Duplication
			case 'smhd': // Sound Media information HeaDer atom
958
				$atom_structure['version']                = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
959
				$atom_structure['flags_raw']              = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
960
				$atom_structure['balance']                = getid3_lib::BigEndian2Int(substr($atom_data,  4, 2));
961
				$atom_structure['reserved']               = getid3_lib::BigEndian2Int(substr($atom_data,  6, 2));
962
				break;
963
964
965
			case 'vmhd': // Video Media information HeaDer atom
966
				$atom_structure['version']                = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
967
				$atom_structure['flags_raw']              = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3));
968
				$atom_structure['graphics_mode']          = getid3_lib::BigEndian2Int(substr($atom_data,  4, 2));
969
				$atom_structure['opcolor_red']            = getid3_lib::BigEndian2Int(substr($atom_data,  6, 2));
970
				$atom_structure['opcolor_green']          = getid3_lib::BigEndian2Int(substr($atom_data,  8, 2));
971
				$atom_structure['opcolor_blue']           = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2));
972
973
				$atom_structure['flags']['no_lean_ahead'] = (bool) ($atom_structure['flags_raw'] & 0x001);
974
				break;
975
976
977
			case 'hdlr': // HanDLeR reference atom
978
				$atom_structure['version']                = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
979
				$atom_structure['flags_raw']              = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
980
				$atom_structure['component_type']         =                           substr($atom_data,  4, 4);
981
				$atom_structure['component_subtype']      =                           substr($atom_data,  8, 4);
982
				$atom_structure['component_manufacturer'] =                           substr($atom_data, 12, 4);
983
				$atom_structure['component_flags_raw']    = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
984
				$atom_structure['component_flags_mask']   = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4));
985
				$atom_structure['component_name']         =      $this->Pascal2String(substr($atom_data, 24));
986
987
				if (($atom_structure['component_subtype'] == 'STpn') && ($atom_structure['component_manufacturer'] == 'zzzz')) {
988
					$info['video']['dataformat'] = 'quicktimevr';
989
				}
990
				break;
991
992
993
			case 'mdhd': // MeDia HeaDer atom
994
				$atom_structure['version']               = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
995
				$atom_structure['flags_raw']             = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
996
				$atom_structure['creation_time']         = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
997
				$atom_structure['modify_time']           = getid3_lib::BigEndian2Int(substr($atom_data,  8, 4));
998
				$atom_structure['time_scale']            = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
999
				$atom_structure['duration']              = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
1000
				$atom_structure['language_id']           = getid3_lib::BigEndian2Int(substr($atom_data, 20, 2));
1001
				$atom_structure['quality']               = getid3_lib::BigEndian2Int(substr($atom_data, 22, 2));
1002
1003
				if ($atom_structure['time_scale'] == 0) {
1004
					$info['error'][] = 'Corrupt Quicktime file: mdhd.time_scale == zero';
1005
					return false;
1006
				}
1007
				$info['quicktime']['time_scale'] = (isset($info['quicktime']['time_scale']) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']);
1008
1009
				$atom_structure['creation_time_unix']    = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
1010
				$atom_structure['modify_time_unix']      = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
1011
				$atom_structure['playtime_seconds']      = $atom_structure['duration'] / $atom_structure['time_scale'];
1012
				$atom_structure['language']              = $this->QuicktimeLanguageLookup($atom_structure['language_id']);
1013 View Code Duplication
				if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) {
1014
					$info['comments']['language'][] = $atom_structure['language'];
1015
				}
1016
				break;
1017
1018
1019
			case 'pnot': // Preview atom
1020
				$atom_structure['modification_date']      = getid3_lib::BigEndian2Int(substr($atom_data,  0, 4)); // "standard Macintosh format"
1021
				$atom_structure['version_number']         = getid3_lib::BigEndian2Int(substr($atom_data,  4, 2)); // hardcoded: 0x00
1022
				$atom_structure['atom_type']              =               substr($atom_data,  6, 4);        // usually: 'PICT'
1023
				$atom_structure['atom_index']             = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2)); // usually: 0x01
1024
1025
				$atom_structure['modification_date_unix'] = getid3_lib::DateMac2Unix($atom_structure['modification_date']);
1026
				break;
1027
1028
1029 View Code Duplication
			case 'crgn': // Clipping ReGioN atom
1030
				$atom_structure['region_size']   = getid3_lib::BigEndian2Int(substr($atom_data,  0, 2)); // The Region size, Region boundary box,
1031
				$atom_structure['boundary_box']  = getid3_lib::BigEndian2Int(substr($atom_data,  2, 8)); // and Clipping region data fields
1032
				$atom_structure['clipping_data'] =               substr($atom_data, 10);           // constitute a QuickDraw region.
1033
				break;
1034
1035
1036
			case 'load': // track LOAD settings atom
1037
				$atom_structure['preload_start_time'] = getid3_lib::BigEndian2Int(substr($atom_data,  0, 4));
1038
				$atom_structure['preload_duration']   = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1039
				$atom_structure['preload_flags_raw']  = getid3_lib::BigEndian2Int(substr($atom_data,  8, 4));
1040
				$atom_structure['default_hints_raw']  = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
1041
1042
				$atom_structure['default_hints']['double_buffer'] = (bool) ($atom_structure['default_hints_raw'] & 0x0020);
1043
				$atom_structure['default_hints']['high_quality']  = (bool) ($atom_structure['default_hints_raw'] & 0x0100);
1044
				break;
1045
1046
1047
			case 'tmcd': // TiMe CoDe atom
1048
			case 'chap': // CHAPter list atom
1049
			case 'sync': // SYNChronization atom
1050
			case 'scpt': // tranSCriPT atom
1051
			case 'ssrc': // non-primary SouRCe atom
1052
				for ($i = 0; $i < strlen($atom_data); $i += 4) {
1053
					@$atom_structure['track_id'][] = getid3_lib::BigEndian2Int(substr($atom_data, $i, 4));
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1054
				}
1055
				break;
1056
1057
1058
			case 'elst': // Edit LiST atom
1059
				$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1060
				$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
1061
				$atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1062
				for ($i = 0; $i < $atom_structure['number_entries']; $i++ ) {
1063
					$atom_structure['edit_list'][$i]['track_duration'] =   getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($i * 12) + 0, 4));
1064
					$atom_structure['edit_list'][$i]['media_time']     =   getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($i * 12) + 4, 4));
1065
					$atom_structure['edit_list'][$i]['media_rate']     = getid3_lib::FixedPoint16_16(substr($atom_data, 8 + ($i * 12) + 8, 4));
1066
				}
1067
				break;
1068
1069
1070 View Code Duplication
			case 'kmat': // compressed MATte atom
1071
				$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1072
				$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
1073
				$atom_structure['matte_data_raw'] =               substr($atom_data,  4);
1074
				break;
1075
1076
1077
			case 'ctab': // Color TABle atom
1078
				$atom_structure['color_table_seed']   = getid3_lib::BigEndian2Int(substr($atom_data,  0, 4)); // hardcoded: 0x00000000
1079
				$atom_structure['color_table_flags']  = getid3_lib::BigEndian2Int(substr($atom_data,  4, 2)); // hardcoded: 0x8000
1080
				$atom_structure['color_table_size']   = getid3_lib::BigEndian2Int(substr($atom_data,  6, 2)) + 1;
1081
				for ($colortableentry = 0; $colortableentry < $atom_structure['color_table_size']; $colortableentry++) {
1082
					$atom_structure['color_table'][$colortableentry]['alpha'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 0, 2));
1083
					$atom_structure['color_table'][$colortableentry]['red']   = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 2, 2));
1084
					$atom_structure['color_table'][$colortableentry]['green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 4, 2));
1085
					$atom_structure['color_table'][$colortableentry]['blue']  = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 6, 2));
1086
				}
1087
				break;
1088
1089
1090
			case 'mvhd': // MoVie HeaDer atom
1091
				$atom_structure['version']            =   getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1092
				$atom_structure['flags_raw']          =   getid3_lib::BigEndian2Int(substr($atom_data,  1, 3));
1093
				$atom_structure['creation_time']      =   getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1094
				$atom_structure['modify_time']        =   getid3_lib::BigEndian2Int(substr($atom_data,  8, 4));
1095
				$atom_structure['time_scale']         =   getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
1096
				$atom_structure['duration']           =   getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
1097
				$atom_structure['preferred_rate']     = getid3_lib::FixedPoint16_16(substr($atom_data, 20, 4));
1098
				$atom_structure['preferred_volume']   =   getid3_lib::FixedPoint8_8(substr($atom_data, 24, 2));
1099
				$atom_structure['reserved']           =                             substr($atom_data, 26, 10);
1100
				$atom_structure['matrix_a']           = getid3_lib::FixedPoint16_16(substr($atom_data, 36, 4));
1101
				$atom_structure['matrix_b']           = getid3_lib::FixedPoint16_16(substr($atom_data, 40, 4));
1102
				$atom_structure['matrix_u']           =  getid3_lib::FixedPoint2_30(substr($atom_data, 44, 4));
1103
				$atom_structure['matrix_c']           = getid3_lib::FixedPoint16_16(substr($atom_data, 48, 4));
1104
				$atom_structure['matrix_d']           = getid3_lib::FixedPoint16_16(substr($atom_data, 52, 4));
1105
				$atom_structure['matrix_v']           =  getid3_lib::FixedPoint2_30(substr($atom_data, 56, 4));
1106
				$atom_structure['matrix_x']           = getid3_lib::FixedPoint16_16(substr($atom_data, 60, 4));
1107
				$atom_structure['matrix_y']           = getid3_lib::FixedPoint16_16(substr($atom_data, 64, 4));
1108
				$atom_structure['matrix_w']           =  getid3_lib::FixedPoint2_30(substr($atom_data, 68, 4));
1109
				$atom_structure['preview_time']       =   getid3_lib::BigEndian2Int(substr($atom_data, 72, 4));
1110
				$atom_structure['preview_duration']   =   getid3_lib::BigEndian2Int(substr($atom_data, 76, 4));
1111
				$atom_structure['poster_time']        =   getid3_lib::BigEndian2Int(substr($atom_data, 80, 4));
1112
				$atom_structure['selection_time']     =   getid3_lib::BigEndian2Int(substr($atom_data, 84, 4));
1113
				$atom_structure['selection_duration'] =   getid3_lib::BigEndian2Int(substr($atom_data, 88, 4));
1114
				$atom_structure['current_time']       =   getid3_lib::BigEndian2Int(substr($atom_data, 92, 4));
1115
				$atom_structure['next_track_id']      =   getid3_lib::BigEndian2Int(substr($atom_data, 96, 4));
1116
1117
				if ($atom_structure['time_scale'] == 0) {
1118
					$info['error'][] = 'Corrupt Quicktime file: mvhd.time_scale == zero';
1119
					return false;
1120
				}
1121
				$atom_structure['creation_time_unix']        = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
1122
				$atom_structure['modify_time_unix']          = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
1123
				$info['quicktime']['time_scale']    = (isset($info['quicktime']['time_scale']) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']);
1124
				$info['quicktime']['display_scale'] = $atom_structure['matrix_a'];
1125
				$info['playtime_seconds']           = $atom_structure['duration'] / $atom_structure['time_scale'];
1126
				break;
1127
1128
1129
			case 'tkhd': // TracK HeaDer atom
1130
				$atom_structure['version']             =   getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1131
				$atom_structure['flags_raw']           =   getid3_lib::BigEndian2Int(substr($atom_data,  1, 3));
1132
				$atom_structure['creation_time']       =   getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1133
				$atom_structure['modify_time']         =   getid3_lib::BigEndian2Int(substr($atom_data,  8, 4));
1134
				$atom_structure['trackid']             =   getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
1135
				$atom_structure['reserved1']           =   getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
1136
				$atom_structure['duration']            =   getid3_lib::BigEndian2Int(substr($atom_data, 20, 4));
1137
				$atom_structure['reserved2']           =   getid3_lib::BigEndian2Int(substr($atom_data, 24, 8));
1138
				$atom_structure['layer']               =   getid3_lib::BigEndian2Int(substr($atom_data, 32, 2));
1139
				$atom_structure['alternate_group']     =   getid3_lib::BigEndian2Int(substr($atom_data, 34, 2));
1140
				$atom_structure['volume']              =   getid3_lib::FixedPoint8_8(substr($atom_data, 36, 2));
1141
				$atom_structure['reserved3']           =   getid3_lib::BigEndian2Int(substr($atom_data, 38, 2));
1142
// http://developer.apple.com/library/mac/#documentation/QuickTime/RM/MovieBasics/MTEditing/K-Chapter/11MatrixFunctions.html
1143
// http://developer.apple.com/library/mac/#documentation/QuickTime/qtff/QTFFChap4/qtff4.html#//apple_ref/doc/uid/TP40000939-CH206-18737
1144
				$atom_structure['matrix_a']            = getid3_lib::FixedPoint16_16(substr($atom_data, 40, 4));
1145
				$atom_structure['matrix_b']            = getid3_lib::FixedPoint16_16(substr($atom_data, 44, 4));
1146
				$atom_structure['matrix_u']            =  getid3_lib::FixedPoint2_30(substr($atom_data, 48, 4));
1147
				$atom_structure['matrix_c']            = getid3_lib::FixedPoint16_16(substr($atom_data, 52, 4));
1148
				$atom_structure['matrix_d']            = getid3_lib::FixedPoint16_16(substr($atom_data, 56, 4));
1149
				$atom_structure['matrix_v']            =  getid3_lib::FixedPoint2_30(substr($atom_data, 60, 4));
1150
				$atom_structure['matrix_x']            = getid3_lib::FixedPoint16_16(substr($atom_data, 64, 4));
1151
				$atom_structure['matrix_y']            = getid3_lib::FixedPoint16_16(substr($atom_data, 68, 4));
1152
				$atom_structure['matrix_w']            =  getid3_lib::FixedPoint2_30(substr($atom_data, 72, 4));
1153
				$atom_structure['width']               = getid3_lib::FixedPoint16_16(substr($atom_data, 76, 4));
1154
				$atom_structure['height']              = getid3_lib::FixedPoint16_16(substr($atom_data, 80, 4));
1155
				$atom_structure['flags']['enabled']    = (bool) ($atom_structure['flags_raw'] & 0x0001);
1156
				$atom_structure['flags']['in_movie']   = (bool) ($atom_structure['flags_raw'] & 0x0002);
1157
				$atom_structure['flags']['in_preview'] = (bool) ($atom_structure['flags_raw'] & 0x0004);
1158
				$atom_structure['flags']['in_poster']  = (bool) ($atom_structure['flags_raw'] & 0x0008);
1159
				$atom_structure['creation_time_unix']  = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
1160
				$atom_structure['modify_time_unix']    = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
1161
1162
				if ($atom_structure['flags']['enabled'] == 1) {
1163 View Code Duplication
					if (!isset($info['video']['resolution_x']) || !isset($info['video']['resolution_y'])) {
1164
						$info['video']['resolution_x'] = $atom_structure['width'];
1165
						$info['video']['resolution_y'] = $atom_structure['height'];
1166
					}
1167
					$info['video']['resolution_x'] = max($info['video']['resolution_x'], $atom_structure['width']);
1168
					$info['video']['resolution_y'] = max($info['video']['resolution_y'], $atom_structure['height']);
1169
					$info['quicktime']['video']['resolution_x'] = $info['video']['resolution_x'];
1170
					$info['quicktime']['video']['resolution_y'] = $info['video']['resolution_y'];
1171
				} else {
1172
					// see: http://www.getid3.org/phpBB3/viewtopic.php?t=1295
1173
					//if (isset($info['video']['resolution_x'])) { unset($info['video']['resolution_x']); }
1174
					//if (isset($info['video']['resolution_y'])) { unset($info['video']['resolution_y']); }
1175
					//if (isset($info['quicktime']['video']))    { unset($info['quicktime']['video']);    }
1176
				}
1177
				break;
1178
1179
1180
			case 'iods': // Initial Object DeScriptor atom
1181
				// http://www.koders.com/c/fid1FAB3E762903DC482D8A246D4A4BF9F28E049594.aspx?s=windows.h
1182
				// http://libquicktime.sourcearchive.com/documentation/1.0.2plus-pdebian/iods_8c-source.html
1183
				$offset = 0;
1184
				$atom_structure['version']                =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1185
				$offset += 1;
1186
				$atom_structure['flags_raw']              =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 3));
1187
				$offset += 3;
1188
				$atom_structure['mp4_iod_tag']            =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1189
				$offset += 1;
1190
				$atom_structure['length']                 = $this->quicktime_read_mp4_descr_length($atom_data, $offset);
1191
				//$offset already adjusted by quicktime_read_mp4_descr_length()
1192
				$atom_structure['object_descriptor_id']   =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2));
1193
				$offset += 2;
1194
				$atom_structure['od_profile_level']       =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1195
				$offset += 1;
1196
				$atom_structure['scene_profile_level']    =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1197
				$offset += 1;
1198
				$atom_structure['audio_profile_id']       =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1199
				$offset += 1;
1200
				$atom_structure['video_profile_id']       =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1201
				$offset += 1;
1202
				$atom_structure['graphics_profile_level'] =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1203
				$offset += 1;
1204
1205
				$atom_structure['num_iods_tracks'] = ($atom_structure['length'] - 7) / 6; // 6 bytes would only be right if all tracks use 1-byte length fields
1206 View Code Duplication
				for ($i = 0; $i < $atom_structure['num_iods_tracks']; $i++) {
1207
					$atom_structure['track'][$i]['ES_ID_IncTag'] =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1208
					$offset += 1;
1209
					$atom_structure['track'][$i]['length']       = $this->quicktime_read_mp4_descr_length($atom_data, $offset);
1210
					//$offset already adjusted by quicktime_read_mp4_descr_length()
1211
					$atom_structure['track'][$i]['track_id']     =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4));
1212
					$offset += 4;
1213
				}
1214
1215
				$atom_structure['audio_profile_name'] = $this->QuicktimeIODSaudioProfileName($atom_structure['audio_profile_id']);
1216
				$atom_structure['video_profile_name'] = $this->QuicktimeIODSvideoProfileName($atom_structure['video_profile_id']);
1217
				break;
1218
1219 View Code Duplication
			case 'ftyp': // FileTYPe (?) atom (for MP4 it seems)
1220
				$atom_structure['signature'] =                           substr($atom_data,  0, 4);
1221
				$atom_structure['unknown_1'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1222
				$atom_structure['fourcc']    =                           substr($atom_data,  8, 4);
1223
				break;
1224
1225
			case 'mdat': // Media DATa atom
1226
				// 'mdat' contains the actual data for the audio/video, possibly also subtitles
1227
1228
/* due to lack of known documentation, this is a kludge implementation. If you know of documentation on how mdat is properly structed, please send it to [email protected] */
1229
1230
				// first, skip any 'wide' padding, and second 'mdat' header (with specified size of zero?)
1231
				$mdat_offset = 0;
1232
				while (true) {
1233
					if (substr($atom_data, $mdat_offset, 8) == "\x00\x00\x00\x08".'wide') {
1234
						$mdat_offset += 8;
1235
					} elseif (substr($atom_data, $mdat_offset, 8) == "\x00\x00\x00\x00".'mdat') {
1236
						$mdat_offset += 8;
1237
					} else {
1238
						break;
1239
					}
1240
				}
1241
1242
				// check to see if it looks like chapter titles, in the form of unterminated strings with a leading 16-bit size field
1243
				while  (($chapter_string_length = getid3_lib::BigEndian2Int(substr($atom_data, $mdat_offset, 2)))
1244
					&& ($chapter_string_length < 1000)
1245
					&& ($chapter_string_length <= (strlen($atom_data) - $mdat_offset - 2))
1246
					&& preg_match('#^[\x20-\xFF]+$#', substr($atom_data, $mdat_offset + 2, $chapter_string_length), $chapter_matches)) {
1247
						$mdat_offset += (2 + $chapter_string_length);
1248
						@$info['quicktime']['comments']['chapters'][] = $chapter_matches[0];
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1249
				}
1250
1251
1252
1253
				if (($atomsize > 8) && (!isset($info['avdataend_tmp']) || ($info['quicktime'][$atomname]['size'] > ($info['avdataend_tmp'] - $info['avdataoffset'])))) {
1254
1255
					$info['avdataoffset'] = $atom_structure['offset'] + 8;                       // $info['quicktime'][$atomname]['offset'] + 8;
1256
					$OldAVDataEnd         = $info['avdataend'];
1257
					$info['avdataend']    = $atom_structure['offset'] + $atom_structure['size']; // $info['quicktime'][$atomname]['offset'] + $info['quicktime'][$atomname]['size'];
1258
1259
					$getid3_temp = new getID3();
1260
					$getid3_temp->openfile($this->getid3->filename);
1261
					$getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
1262
					$getid3_temp->info['avdataend']    = $info['avdataend'];
1263
					$getid3_mp3 = new getid3_mp3($getid3_temp);
1264
					if ($getid3_mp3->MPEGaudioHeaderValid($getid3_mp3->MPEGaudioHeaderDecode($this->fread(4)))) {
1265
						$getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info['avdataoffset'], false);
1266 View Code Duplication
						if (!empty($getid3_temp->info['warning'])) {
1267
							foreach ($getid3_temp->info['warning'] as $value) {
1268
								$info['warning'][] = $value;
1269
							}
1270
						}
1271
						if (!empty($getid3_temp->info['mpeg'])) {
1272
							$info['mpeg'] = $getid3_temp->info['mpeg'];
1273
							if (isset($info['mpeg']['audio'])) {
1274
								$info['audio']['dataformat']   = 'mp3';
1275
								$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')));
1276
								$info['audio']['sample_rate']  = $info['mpeg']['audio']['sample_rate'];
1277
								$info['audio']['channels']     = $info['mpeg']['audio']['channels'];
1278
								$info['audio']['bitrate']      = $info['mpeg']['audio']['bitrate'];
1279
								$info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
1280
								$info['bitrate']               = $info['audio']['bitrate'];
1281
							}
1282
						}
1283
					}
1284
					unset($getid3_mp3, $getid3_temp);
1285
					$info['avdataend'] = $OldAVDataEnd;
1286
					unset($OldAVDataEnd);
1287
1288
				}
1289
1290
				unset($mdat_offset, $chapter_string_length, $chapter_matches);
1291
				break;
1292
1293
			case 'free': // FREE space atom
1294
			case 'skip': // SKIP atom
1295
			case 'wide': // 64-bit expansion placeholder atom
1296
				// 'free', 'skip' and 'wide' are just padding, contains no useful data at all
1297
1298
				// When writing QuickTime files, it is sometimes necessary to update an atom's size.
1299
				// It is impossible to update a 32-bit atom to a 64-bit atom since the 32-bit atom
1300
				// is only 8 bytes in size, and the 64-bit atom requires 16 bytes. Therefore, QuickTime
1301
				// puts an 8-byte placeholder atom before any atoms it may have to update the size of.
1302
				// In this way, if the atom needs to be converted from a 32-bit to a 64-bit atom, the
1303
				// placeholder atom can be overwritten to obtain the necessary 8 extra bytes.
1304
				// The placeholder atom has a type of kWideAtomPlaceholderType ( 'wide' ).
1305
				break;
1306
1307
1308
			case 'nsav': // NoSAVe atom
1309
				// http://developer.apple.com/technotes/tn/tn2038.html
1310
				$atom_structure['data'] = getid3_lib::BigEndian2Int(substr($atom_data,  0, 4));
1311
				break;
1312
1313
			case 'ctyp': // Controller TYPe atom (seen on QTVR)
1314
				// http://homepages.slingshot.co.nz/~helmboy/quicktime/formats/qtm-layout.txt
1315
				// some controller names are:
1316
				//   0x00 + 'std' for linear movie
1317
				//   'none' for no controls
1318
				$atom_structure['ctyp'] = substr($atom_data, 0, 4);
1319
				$info['quicktime']['controller'] = $atom_structure['ctyp'];
1320
				switch ($atom_structure['ctyp']) {
1321
					case 'qtvr':
1322
						$info['video']['dataformat'] = 'quicktimevr';
1323
						break;
1324
				}
1325
				break;
1326
1327
			case 'pano': // PANOrama track (seen on QTVR)
1328
				$atom_structure['pano'] = getid3_lib::BigEndian2Int(substr($atom_data,  0, 4));
1329
				break;
1330
1331
			case 'hint': // HINT track
1332
			case 'hinf': //
1333
			case 'hinv': //
1334
			case 'hnti': //
1335
				$info['quicktime']['hinting'] = true;
1336
				break;
1337
1338
			case 'imgt': // IMaGe Track reference (kQTVRImageTrackRefType) (seen on QTVR)
1339
				for ($i = 0; $i < ($atom_structure['size'] - 8); $i += 4) {
1340
					$atom_structure['imgt'][] = getid3_lib::BigEndian2Int(substr($atom_data, $i, 4));
1341
				}
1342
				break;
1343
1344
1345
			// Observed-but-not-handled atom types are just listed here to prevent warnings being generated
1346
			case 'FXTC': // Something to do with Adobe After Effects (?)
1347
			case 'PrmA':
1348
			case 'code':
1349
			case 'FIEL': // this is NOT "fiel" (Field Ordering) as describe here: http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap3/chapter_4_section_2.html
1350
			case 'tapt': // TrackApertureModeDimensionsAID - http://developer.apple.com/documentation/QuickTime/Reference/QT7-1_Update_Reference/Constants/Constants.html
1351
						// tapt seems to be used to compute the video size [http://www.getid3.org/phpBB3/viewtopic.php?t=838]
1352
						// * http://lists.apple.com/archives/quicktime-api/2006/Aug/msg00014.html
1353
						// * http://handbrake.fr/irclogs/handbrake-dev/handbrake-dev20080128_pg2.html
1354
			case 'ctts'://  STCompositionOffsetAID             - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
1355
			case 'cslg'://  STCompositionShiftLeastGreatestAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
1356
			case 'sdtp'://  STSampleDependencyAID              - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
1357
			case 'stps'://  STPartialSyncSampleAID             - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
1358
				//$atom_structure['data'] = $atom_data;
1359
				break;
1360
1361
			case "\xA9".'xyz':  // GPS latitude+longitude+altitude
1362
				$atom_structure['data'] = $atom_data;
1363
				if (preg_match('#([\\+\\-][0-9\\.]+)([\\+\\-][0-9\\.]+)([\\+\\-][0-9\\.]+)?/$#i', $atom_data, $matches)) {
1364
					@list($all, $latitude, $longitude, $altitude) = $matches;
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1365
					$info['quicktime']['comments']['gps_latitude'][]  = floatval($latitude);
1366
					$info['quicktime']['comments']['gps_longitude'][] = floatval($longitude);
1367
					if (!empty($altitude)) {
1368
						$info['quicktime']['comments']['gps_altitude'][] = floatval($altitude);
1369
					}
1370
				} else {
1371
					$info['warning'][] = 'QuickTime atom "©xyz" data does not match expected data pattern at offset '.$baseoffset.'. Please report as getID3() bug.';
1372
				}
1373
				break;
1374
1375
			case 'NCDT':
1376
				// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
1377
				// Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100
1378
				$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 4, $atomHierarchy, $ParseAllPossibleAtoms);
1379
				break;
1380
			case 'NCTH': // Nikon Camera THumbnail image
1381
			case 'NCVW': // Nikon Camera preVieW image
1382
				// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
1383
				if (preg_match('/^\xFF\xD8\xFF/', $atom_data)) {
1384
					$atom_structure['data'] = $atom_data;
1385
					$atom_structure['image_mime'] = 'image/jpeg';
1386
					$atom_structure['description'] = (($atomname == 'NCTH') ? 'Nikon Camera Thumbnail Image' : (($atomname == 'NCVW') ? 'Nikon Camera Preview Image' : 'Nikon preview image'));
1387
					$info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_data, 'description'=>$atom_structure['description']);
1388
				}
1389
				break;
1390
			case 'NCTG': // Nikon - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
1391
				$atom_structure['data'] = $this->QuicktimeParseNikonNCTG($atom_data);
1392
				break;
1393
			case 'NCHD': // Nikon:MakerNoteVersion  - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
1394
			case 'NCDB': // Nikon                   - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
1395
			case 'CNCV': // Canon:CompressorVersion - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Canon.html
1396
				$atom_structure['data'] = $atom_data;
1397
				break;
1398
1399
			case "\x00\x00\x00\x00":
1400
			case 'meta': // METAdata atom
1401
				// some kind of metacontainer, may contain a big data dump such as:
1402
				// mdta keys \005 mdtacom.apple.quicktime.make (mdtacom.apple.quicktime.creationdate ,mdtacom.apple.quicktime.location.ISO6709 $mdtacom.apple.quicktime.software !mdtacom.apple.quicktime.model ilst \01D \001 \015data \001DE\010Apple 0 \002 (data \001DE\0102011-05-11T17:54:04+0200 2 \003 *data \001DE\010+52.4936+013.3897+040.247/ \01D \004 \015data \001DE\0104.3.1 \005 \018data \001DE\010iPhone 4
1403
				// http://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt
1404
1405
	            $atom_structure['version']   =          getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1406
	            $atom_structure['flags_raw'] =          getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
1407
	            $atom_structure['subatoms']  = $this->QuicktimeParseContainerAtom(substr($atom_data, 4), $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
1408
				//$atom_structure['subatoms']  = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
1409
				break;
1410
1411
			case 'data': // metaDATA atom
1412
				// seems to be 2 bytes language code (ASCII), 2 bytes unknown (set to 0x10B5 in sample I have), remainder is useful data
1413
				$atom_structure['language'] =                           substr($atom_data, 4 + 0, 2);
1414
				$atom_structure['unknown']  = getid3_lib::BigEndian2Int(substr($atom_data, 4 + 2, 2));
1415
				$atom_structure['data']     =                           substr($atom_data, 4 + 4);
1416
				break;
1417
1418 View Code Duplication
			default:
1419
				$info['warning'][] = 'Unknown QuickTime atom type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" ('.trim(getid3_lib::PrintHexBytes($atomname)).') at offset '.$baseoffset;
1420
				$atom_structure['data'] = $atom_data;
1421
				break;
1422
		}
1423
		array_pop($atomHierarchy);
1424
		return $atom_structure;
1425
	}
1426
1427
	public function QuicktimeParseContainerAtom($atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
1428
//echo 'QuicktimeParseContainerAtom('.substr($atom_data, 4, 4).') @ '.$baseoffset.'<br><br>';
1429
		$atom_structure  = false;
1430
		$subatomoffset  = 0;
1431
		$subatomcounter = 0;
1432
		if ((strlen($atom_data) == 4) && (getid3_lib::BigEndian2Int($atom_data) == 0x00000000)) {
1433
			return false;
1434
		}
1435
		while ($subatomoffset < strlen($atom_data)) {
1436
			$subatomsize = getid3_lib::BigEndian2Int(substr($atom_data, $subatomoffset + 0, 4));
1437
			$subatomname =                           substr($atom_data, $subatomoffset + 4, 4);
1438
			$subatomdata =                           substr($atom_data, $subatomoffset + 8, $subatomsize - 8);
1439
			if ($subatomsize == 0) {
1440
				// Furthermore, for historical reasons the list of atoms is optionally
1441
				// terminated by a 32-bit integer set to 0. If you are writing a program
1442
				// to read user data atoms, you should allow for the terminating 0.
1443
				return $atom_structure;
1444
			}
1445
1446
			$atom_structure[$subatomcounter] = $this->QuicktimeParseAtom($subatomname, $subatomsize, $subatomdata, $baseoffset + $subatomoffset, $atomHierarchy, $ParseAllPossibleAtoms);
1447
1448
			$subatomoffset += $subatomsize;
1449
			$subatomcounter++;
1450
		}
1451
		return $atom_structure;
1452
	}
1453
1454
1455
	public function quicktime_read_mp4_descr_length($data, &$offset) {
1456
		// http://libquicktime.sourcearchive.com/documentation/2:1.0.2plus-pdebian-2build1/esds_8c-source.html
1457
		$num_bytes = 0;
1458
		$length    = 0;
1459
		do {
1460
			$b = ord(substr($data, $offset++, 1));
1461
			$length = ($length << 7) | ($b & 0x7F);
1462
		} while (($b & 0x80) && ($num_bytes++ < 4));
1463
		return $length;
1464
	}
1465
1466
1467
	public function QuicktimeLanguageLookup($languageid) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
1468
		// http://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap4/qtff4.html#//apple_ref/doc/uid/TP40000939-CH206-34353
1469
		static $QuicktimeLanguageLookup = array();
1470
		if (empty($QuicktimeLanguageLookup)) {
1471
			$QuicktimeLanguageLookup[0]     = 'English';
1472
			$QuicktimeLanguageLookup[1]     = 'French';
1473
			$QuicktimeLanguageLookup[2]     = 'German';
1474
			$QuicktimeLanguageLookup[3]     = 'Italian';
1475
			$QuicktimeLanguageLookup[4]     = 'Dutch';
1476
			$QuicktimeLanguageLookup[5]     = 'Swedish';
1477
			$QuicktimeLanguageLookup[6]     = 'Spanish';
1478
			$QuicktimeLanguageLookup[7]     = 'Danish';
1479
			$QuicktimeLanguageLookup[8]     = 'Portuguese';
1480
			$QuicktimeLanguageLookup[9]     = 'Norwegian';
1481
			$QuicktimeLanguageLookup[10]    = 'Hebrew';
1482
			$QuicktimeLanguageLookup[11]    = 'Japanese';
1483
			$QuicktimeLanguageLookup[12]    = 'Arabic';
1484
			$QuicktimeLanguageLookup[13]    = 'Finnish';
1485
			$QuicktimeLanguageLookup[14]    = 'Greek';
1486
			$QuicktimeLanguageLookup[15]    = 'Icelandic';
1487
			$QuicktimeLanguageLookup[16]    = 'Maltese';
1488
			$QuicktimeLanguageLookup[17]    = 'Turkish';
1489
			$QuicktimeLanguageLookup[18]    = 'Croatian';
1490
			$QuicktimeLanguageLookup[19]    = 'Chinese (Traditional)';
1491
			$QuicktimeLanguageLookup[20]    = 'Urdu';
1492
			$QuicktimeLanguageLookup[21]    = 'Hindi';
1493
			$QuicktimeLanguageLookup[22]    = 'Thai';
1494
			$QuicktimeLanguageLookup[23]    = 'Korean';
1495
			$QuicktimeLanguageLookup[24]    = 'Lithuanian';
1496
			$QuicktimeLanguageLookup[25]    = 'Polish';
1497
			$QuicktimeLanguageLookup[26]    = 'Hungarian';
1498
			$QuicktimeLanguageLookup[27]    = 'Estonian';
1499
			$QuicktimeLanguageLookup[28]    = 'Lettish';
1500
			$QuicktimeLanguageLookup[28]    = 'Latvian';
1501
			$QuicktimeLanguageLookup[29]    = 'Saamisk';
1502
			$QuicktimeLanguageLookup[29]    = 'Lappish';
1503
			$QuicktimeLanguageLookup[30]    = 'Faeroese';
1504
			$QuicktimeLanguageLookup[31]    = 'Farsi';
1505
			$QuicktimeLanguageLookup[31]    = 'Persian';
1506
			$QuicktimeLanguageLookup[32]    = 'Russian';
1507
			$QuicktimeLanguageLookup[33]    = 'Chinese (Simplified)';
1508
			$QuicktimeLanguageLookup[34]    = 'Flemish';
1509
			$QuicktimeLanguageLookup[35]    = 'Irish';
1510
			$QuicktimeLanguageLookup[36]    = 'Albanian';
1511
			$QuicktimeLanguageLookup[37]    = 'Romanian';
1512
			$QuicktimeLanguageLookup[38]    = 'Czech';
1513
			$QuicktimeLanguageLookup[39]    = 'Slovak';
1514
			$QuicktimeLanguageLookup[40]    = 'Slovenian';
1515
			$QuicktimeLanguageLookup[41]    = 'Yiddish';
1516
			$QuicktimeLanguageLookup[42]    = 'Serbian';
1517
			$QuicktimeLanguageLookup[43]    = 'Macedonian';
1518
			$QuicktimeLanguageLookup[44]    = 'Bulgarian';
1519
			$QuicktimeLanguageLookup[45]    = 'Ukrainian';
1520
			$QuicktimeLanguageLookup[46]    = 'Byelorussian';
1521
			$QuicktimeLanguageLookup[47]    = 'Uzbek';
1522
			$QuicktimeLanguageLookup[48]    = 'Kazakh';
1523
			$QuicktimeLanguageLookup[49]    = 'Azerbaijani';
1524
			$QuicktimeLanguageLookup[50]    = 'AzerbaijanAr';
1525
			$QuicktimeLanguageLookup[51]    = 'Armenian';
1526
			$QuicktimeLanguageLookup[52]    = 'Georgian';
1527
			$QuicktimeLanguageLookup[53]    = 'Moldavian';
1528
			$QuicktimeLanguageLookup[54]    = 'Kirghiz';
1529
			$QuicktimeLanguageLookup[55]    = 'Tajiki';
1530
			$QuicktimeLanguageLookup[56]    = 'Turkmen';
1531
			$QuicktimeLanguageLookup[57]    = 'Mongolian';
1532
			$QuicktimeLanguageLookup[58]    = 'MongolianCyr';
1533
			$QuicktimeLanguageLookup[59]    = 'Pashto';
1534
			$QuicktimeLanguageLookup[60]    = 'Kurdish';
1535
			$QuicktimeLanguageLookup[61]    = 'Kashmiri';
1536
			$QuicktimeLanguageLookup[62]    = 'Sindhi';
1537
			$QuicktimeLanguageLookup[63]    = 'Tibetan';
1538
			$QuicktimeLanguageLookup[64]    = 'Nepali';
1539
			$QuicktimeLanguageLookup[65]    = 'Sanskrit';
1540
			$QuicktimeLanguageLookup[66]    = 'Marathi';
1541
			$QuicktimeLanguageLookup[67]    = 'Bengali';
1542
			$QuicktimeLanguageLookup[68]    = 'Assamese';
1543
			$QuicktimeLanguageLookup[69]    = 'Gujarati';
1544
			$QuicktimeLanguageLookup[70]    = 'Punjabi';
1545
			$QuicktimeLanguageLookup[71]    = 'Oriya';
1546
			$QuicktimeLanguageLookup[72]    = 'Malayalam';
1547
			$QuicktimeLanguageLookup[73]    = 'Kannada';
1548
			$QuicktimeLanguageLookup[74]    = 'Tamil';
1549
			$QuicktimeLanguageLookup[75]    = 'Telugu';
1550
			$QuicktimeLanguageLookup[76]    = 'Sinhalese';
1551
			$QuicktimeLanguageLookup[77]    = 'Burmese';
1552
			$QuicktimeLanguageLookup[78]    = 'Khmer';
1553
			$QuicktimeLanguageLookup[79]    = 'Lao';
1554
			$QuicktimeLanguageLookup[80]    = 'Vietnamese';
1555
			$QuicktimeLanguageLookup[81]    = 'Indonesian';
1556
			$QuicktimeLanguageLookup[82]    = 'Tagalog';
1557
			$QuicktimeLanguageLookup[83]    = 'MalayRoman';
1558
			$QuicktimeLanguageLookup[84]    = 'MalayArabic';
1559
			$QuicktimeLanguageLookup[85]    = 'Amharic';
1560
			$QuicktimeLanguageLookup[86]    = 'Tigrinya';
1561
			$QuicktimeLanguageLookup[87]    = 'Galla';
1562
			$QuicktimeLanguageLookup[87]    = 'Oromo';
1563
			$QuicktimeLanguageLookup[88]    = 'Somali';
1564
			$QuicktimeLanguageLookup[89]    = 'Swahili';
1565
			$QuicktimeLanguageLookup[90]    = 'Ruanda';
1566
			$QuicktimeLanguageLookup[91]    = 'Rundi';
1567
			$QuicktimeLanguageLookup[92]    = 'Chewa';
1568
			$QuicktimeLanguageLookup[93]    = 'Malagasy';
1569
			$QuicktimeLanguageLookup[94]    = 'Esperanto';
1570
			$QuicktimeLanguageLookup[128]   = 'Welsh';
1571
			$QuicktimeLanguageLookup[129]   = 'Basque';
1572
			$QuicktimeLanguageLookup[130]   = 'Catalan';
1573
			$QuicktimeLanguageLookup[131]   = 'Latin';
1574
			$QuicktimeLanguageLookup[132]   = 'Quechua';
1575
			$QuicktimeLanguageLookup[133]   = 'Guarani';
1576
			$QuicktimeLanguageLookup[134]   = 'Aymara';
1577
			$QuicktimeLanguageLookup[135]   = 'Tatar';
1578
			$QuicktimeLanguageLookup[136]   = 'Uighur';
1579
			$QuicktimeLanguageLookup[137]   = 'Dzongkha';
1580
			$QuicktimeLanguageLookup[138]   = 'JavaneseRom';
1581
			$QuicktimeLanguageLookup[32767] = 'Unspecified';
1582
		}
1583
		if (($languageid > 138) && ($languageid < 32767)) {
1584
			/*
1585
			ISO Language Codes - http://www.loc.gov/standards/iso639-2/php/code_list.php
1586
			Because the language codes specified by ISO 639-2/T are three characters long, they must be packed to fit into a 16-bit field.
1587
			The packing algorithm must map each of the three characters, which are always lowercase, into a 5-bit integer and then concatenate
1588
			these integers into the least significant 15 bits of a 16-bit integer, leaving the 16-bit integer's most significant bit set to zero.
1589
1590
			One algorithm for performing this packing is to treat each ISO character as a 16-bit integer. Subtract 0x60 from the first character
1591
			and multiply by 2^10 (0x400), subtract 0x60 from the second character and multiply by 2^5 (0x20), subtract 0x60 from the third character,
1592
			and add the three 16-bit values. This will result in a single 16-bit value with the three codes correctly packed into the 15 least
1593
			significant bits and the most significant bit set to zero.
1594
			*/
1595
			$iso_language_id  = '';
1596
			$iso_language_id .= chr((($languageid & 0x7C00) >> 10) + 0x60);
1597
			$iso_language_id .= chr((($languageid & 0x03E0) >>  5) + 0x60);
1598
			$iso_language_id .= chr((($languageid & 0x001F) >>  0) + 0x60);
1599
			$QuicktimeLanguageLookup[$languageid] = getid3_id3v2::LanguageLookup($iso_language_id);
1600
		}
1601
		return (isset($QuicktimeLanguageLookup[$languageid]) ? $QuicktimeLanguageLookup[$languageid] : 'invalid');
1602
	}
1603
1604
	public function QuicktimeVideoCodecLookup($codecid) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
1605
		static $QuicktimeVideoCodecLookup = array();
1606
		if (empty($QuicktimeVideoCodecLookup)) {
1607
			$QuicktimeVideoCodecLookup['.SGI'] = 'SGI';
1608
			$QuicktimeVideoCodecLookup['3IV1'] = '3ivx MPEG-4 v1';
1609
			$QuicktimeVideoCodecLookup['3IV2'] = '3ivx MPEG-4 v2';
1610
			$QuicktimeVideoCodecLookup['3IVX'] = '3ivx MPEG-4';
1611
			$QuicktimeVideoCodecLookup['8BPS'] = 'Planar RGB';
1612
			$QuicktimeVideoCodecLookup['avc1'] = 'H.264/MPEG-4 AVC';
1613
			$QuicktimeVideoCodecLookup['avr '] = 'AVR-JPEG';
1614
			$QuicktimeVideoCodecLookup['b16g'] = '16Gray';
1615
			$QuicktimeVideoCodecLookup['b32a'] = '32AlphaGray';
1616
			$QuicktimeVideoCodecLookup['b48r'] = '48RGB';
1617
			$QuicktimeVideoCodecLookup['b64a'] = '64ARGB';
1618
			$QuicktimeVideoCodecLookup['base'] = 'Base';
1619
			$QuicktimeVideoCodecLookup['clou'] = 'Cloud';
1620
			$QuicktimeVideoCodecLookup['cmyk'] = 'CMYK';
1621
			$QuicktimeVideoCodecLookup['cvid'] = 'Cinepak';
1622
			$QuicktimeVideoCodecLookup['dmb1'] = 'OpenDML JPEG';
1623
			$QuicktimeVideoCodecLookup['dvc '] = 'DVC-NTSC';
1624
			$QuicktimeVideoCodecLookup['dvcp'] = 'DVC-PAL';
1625
			$QuicktimeVideoCodecLookup['dvpn'] = 'DVCPro-NTSC';
1626
			$QuicktimeVideoCodecLookup['dvpp'] = 'DVCPro-PAL';
1627
			$QuicktimeVideoCodecLookup['fire'] = 'Fire';
1628
			$QuicktimeVideoCodecLookup['flic'] = 'FLC';
1629
			$QuicktimeVideoCodecLookup['gif '] = 'GIF';
1630
			$QuicktimeVideoCodecLookup['h261'] = 'H261';
1631
			$QuicktimeVideoCodecLookup['h263'] = 'H263';
1632
			$QuicktimeVideoCodecLookup['IV41'] = 'Indeo4';
1633
			$QuicktimeVideoCodecLookup['jpeg'] = 'JPEG';
1634
			$QuicktimeVideoCodecLookup['kpcd'] = 'PhotoCD';
1635
			$QuicktimeVideoCodecLookup['mjpa'] = 'Motion JPEG-A';
1636
			$QuicktimeVideoCodecLookup['mjpb'] = 'Motion JPEG-B';
1637
			$QuicktimeVideoCodecLookup['msvc'] = 'Microsoft Video1';
1638
			$QuicktimeVideoCodecLookup['myuv'] = 'MPEG YUV420';
1639
			$QuicktimeVideoCodecLookup['path'] = 'Vector';
1640
			$QuicktimeVideoCodecLookup['png '] = 'PNG';
1641
			$QuicktimeVideoCodecLookup['PNTG'] = 'MacPaint';
1642
			$QuicktimeVideoCodecLookup['qdgx'] = 'QuickDrawGX';
1643
			$QuicktimeVideoCodecLookup['qdrw'] = 'QuickDraw';
1644
			$QuicktimeVideoCodecLookup['raw '] = 'RAW';
1645
			$QuicktimeVideoCodecLookup['ripl'] = 'WaterRipple';
1646
			$QuicktimeVideoCodecLookup['rpza'] = 'Video';
1647
			$QuicktimeVideoCodecLookup['smc '] = 'Graphics';
1648
			$QuicktimeVideoCodecLookup['SVQ1'] = 'Sorenson Video 1';
1649
			$QuicktimeVideoCodecLookup['SVQ1'] = 'Sorenson Video 3';
1650
			$QuicktimeVideoCodecLookup['syv9'] = 'Sorenson YUV9';
1651
			$QuicktimeVideoCodecLookup['tga '] = 'Targa';
1652
			$QuicktimeVideoCodecLookup['tiff'] = 'TIFF';
1653
			$QuicktimeVideoCodecLookup['WRAW'] = 'Windows RAW';
1654
			$QuicktimeVideoCodecLookup['WRLE'] = 'BMP';
1655
			$QuicktimeVideoCodecLookup['y420'] = 'YUV420';
1656
			$QuicktimeVideoCodecLookup['yuv2'] = 'ComponentVideo';
1657
			$QuicktimeVideoCodecLookup['yuvs'] = 'ComponentVideoUnsigned';
1658
			$QuicktimeVideoCodecLookup['yuvu'] = 'ComponentVideoSigned';
1659
		}
1660
		return (isset($QuicktimeVideoCodecLookup[$codecid]) ? $QuicktimeVideoCodecLookup[$codecid] : '');
1661
	}
1662
1663
	public function QuicktimeAudioCodecLookup($codecid) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
1664
		static $QuicktimeAudioCodecLookup = array();
1665
		if (empty($QuicktimeAudioCodecLookup)) {
1666
			$QuicktimeAudioCodecLookup['.mp3']          = 'Fraunhofer MPEG Layer-III alias';
1667
			$QuicktimeAudioCodecLookup['aac ']          = 'ISO/IEC 14496-3 AAC';
1668
			$QuicktimeAudioCodecLookup['agsm']          = 'Apple GSM 10:1';
1669
			$QuicktimeAudioCodecLookup['alac']          = 'Apple Lossless Audio Codec';
1670
			$QuicktimeAudioCodecLookup['alaw']          = 'A-law 2:1';
1671
			$QuicktimeAudioCodecLookup['conv']          = 'Sample Format';
1672
			$QuicktimeAudioCodecLookup['dvca']          = 'DV';
1673
			$QuicktimeAudioCodecLookup['dvi ']          = 'DV 4:1';
1674
			$QuicktimeAudioCodecLookup['eqal']          = 'Frequency Equalizer';
1675
			$QuicktimeAudioCodecLookup['fl32']          = '32-bit Floating Point';
1676
			$QuicktimeAudioCodecLookup['fl64']          = '64-bit Floating Point';
1677
			$QuicktimeAudioCodecLookup['ima4']          = 'Interactive Multimedia Association 4:1';
1678
			$QuicktimeAudioCodecLookup['in24']          = '24-bit Integer';
1679
			$QuicktimeAudioCodecLookup['in32']          = '32-bit Integer';
1680
			$QuicktimeAudioCodecLookup['lpc ']          = 'LPC 23:1';
1681
			$QuicktimeAudioCodecLookup['MAC3']          = 'Macintosh Audio Compression/Expansion (MACE) 3:1';
1682
			$QuicktimeAudioCodecLookup['MAC6']          = 'Macintosh Audio Compression/Expansion (MACE) 6:1';
1683
			$QuicktimeAudioCodecLookup['mixb']          = '8-bit Mixer';
1684
			$QuicktimeAudioCodecLookup['mixw']          = '16-bit Mixer';
1685
			$QuicktimeAudioCodecLookup['mp4a']          = 'ISO/IEC 14496-3 AAC';
1686
			$QuicktimeAudioCodecLookup['MS'."\x00\x02"] = 'Microsoft ADPCM';
1687
			$QuicktimeAudioCodecLookup['MS'."\x00\x11"] = 'DV IMA';
1688
			$QuicktimeAudioCodecLookup['MS'."\x00\x55"] = 'Fraunhofer MPEG Layer III';
1689
			$QuicktimeAudioCodecLookup['NONE']          = 'No Encoding';
1690
			$QuicktimeAudioCodecLookup['Qclp']          = 'Qualcomm PureVoice';
1691
			$QuicktimeAudioCodecLookup['QDM2']          = 'QDesign Music 2';
1692
			$QuicktimeAudioCodecLookup['QDMC']          = 'QDesign Music 1';
1693
			$QuicktimeAudioCodecLookup['ratb']          = '8-bit Rate';
1694
			$QuicktimeAudioCodecLookup['ratw']          = '16-bit Rate';
1695
			$QuicktimeAudioCodecLookup['raw ']          = 'raw PCM';
1696
			$QuicktimeAudioCodecLookup['sour']          = 'Sound Source';
1697
			$QuicktimeAudioCodecLookup['sowt']          = 'signed/two\'s complement (Little Endian)';
1698
			$QuicktimeAudioCodecLookup['str1']          = 'Iomega MPEG layer II';
1699
			$QuicktimeAudioCodecLookup['str2']          = 'Iomega MPEG *layer II';
1700
			$QuicktimeAudioCodecLookup['str3']          = 'Iomega MPEG **layer II';
1701
			$QuicktimeAudioCodecLookup['str4']          = 'Iomega MPEG ***layer II';
1702
			$QuicktimeAudioCodecLookup['twos']          = 'signed/two\'s complement (Big Endian)';
1703
			$QuicktimeAudioCodecLookup['ulaw']          = 'mu-law 2:1';
1704
		}
1705
		return (isset($QuicktimeAudioCodecLookup[$codecid]) ? $QuicktimeAudioCodecLookup[$codecid] : '');
1706
	}
1707
1708
	public function QuicktimeDCOMLookup($compressionid) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
1709
		static $QuicktimeDCOMLookup = array();
1710
		if (empty($QuicktimeDCOMLookup)) {
1711
			$QuicktimeDCOMLookup['zlib'] = 'ZLib Deflate';
1712
			$QuicktimeDCOMLookup['adec'] = 'Apple Compression';
1713
		}
1714
		return (isset($QuicktimeDCOMLookup[$compressionid]) ? $QuicktimeDCOMLookup[$compressionid] : '');
1715
	}
1716
1717
	public function QuicktimeColorNameLookup($colordepthid) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
1718
		static $QuicktimeColorNameLookup = array();
1719
		if (empty($QuicktimeColorNameLookup)) {
1720
			$QuicktimeColorNameLookup[1]  = '2-color (monochrome)';
1721
			$QuicktimeColorNameLookup[2]  = '4-color';
1722
			$QuicktimeColorNameLookup[4]  = '16-color';
1723
			$QuicktimeColorNameLookup[8]  = '256-color';
1724
			$QuicktimeColorNameLookup[16] = 'thousands (16-bit color)';
1725
			$QuicktimeColorNameLookup[24] = 'millions (24-bit color)';
1726
			$QuicktimeColorNameLookup[32] = 'millions+ (32-bit color)';
1727
			$QuicktimeColorNameLookup[33] = 'black & white';
1728
			$QuicktimeColorNameLookup[34] = '4-gray';
1729
			$QuicktimeColorNameLookup[36] = '16-gray';
1730
			$QuicktimeColorNameLookup[40] = '256-gray';
1731
		}
1732
		return (isset($QuicktimeColorNameLookup[$colordepthid]) ? $QuicktimeColorNameLookup[$colordepthid] : 'invalid');
1733
	}
1734
1735
	public function QuicktimeSTIKLookup($stik) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
1736
		static $QuicktimeSTIKLookup = array();
1737
		if (empty($QuicktimeSTIKLookup)) {
1738
			$QuicktimeSTIKLookup[0]  = 'Movie';
1739
			$QuicktimeSTIKLookup[1]  = 'Normal';
1740
			$QuicktimeSTIKLookup[2]  = 'Audiobook';
1741
			$QuicktimeSTIKLookup[5]  = 'Whacked Bookmark';
1742
			$QuicktimeSTIKLookup[6]  = 'Music Video';
1743
			$QuicktimeSTIKLookup[9]  = 'Short Film';
1744
			$QuicktimeSTIKLookup[10] = 'TV Show';
1745
			$QuicktimeSTIKLookup[11] = 'Booklet';
1746
			$QuicktimeSTIKLookup[14] = 'Ringtone';
1747
			$QuicktimeSTIKLookup[21] = 'Podcast';
1748
		}
1749
		return (isset($QuicktimeSTIKLookup[$stik]) ? $QuicktimeSTIKLookup[$stik] : 'invalid');
1750
	}
1751
1752
	public function QuicktimeIODSaudioProfileName($audio_profile_id) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
1753
		static $QuicktimeIODSaudioProfileNameLookup = array();
1754
		if (empty($QuicktimeIODSaudioProfileNameLookup)) {
1755
			$QuicktimeIODSaudioProfileNameLookup = array(
1756
			    0x00 => 'ISO Reserved (0x00)',
1757
			    0x01 => 'Main Audio Profile @ Level 1',
1758
			    0x02 => 'Main Audio Profile @ Level 2',
1759
			    0x03 => 'Main Audio Profile @ Level 3',
1760
			    0x04 => 'Main Audio Profile @ Level 4',
1761
			    0x05 => 'Scalable Audio Profile @ Level 1',
1762
			    0x06 => 'Scalable Audio Profile @ Level 2',
1763
			    0x07 => 'Scalable Audio Profile @ Level 3',
1764
			    0x08 => 'Scalable Audio Profile @ Level 4',
1765
			    0x09 => 'Speech Audio Profile @ Level 1',
1766
			    0x0A => 'Speech Audio Profile @ Level 2',
1767
			    0x0B => 'Synthetic Audio Profile @ Level 1',
1768
			    0x0C => 'Synthetic Audio Profile @ Level 2',
1769
			    0x0D => 'Synthetic Audio Profile @ Level 3',
1770
			    0x0E => 'High Quality Audio Profile @ Level 1',
1771
			    0x0F => 'High Quality Audio Profile @ Level 2',
1772
			    0x10 => 'High Quality Audio Profile @ Level 3',
1773
			    0x11 => 'High Quality Audio Profile @ Level 4',
1774
			    0x12 => 'High Quality Audio Profile @ Level 5',
1775
			    0x13 => 'High Quality Audio Profile @ Level 6',
1776
			    0x14 => 'High Quality Audio Profile @ Level 7',
1777
			    0x15 => 'High Quality Audio Profile @ Level 8',
1778
			    0x16 => 'Low Delay Audio Profile @ Level 1',
1779
			    0x17 => 'Low Delay Audio Profile @ Level 2',
1780
			    0x18 => 'Low Delay Audio Profile @ Level 3',
1781
			    0x19 => 'Low Delay Audio Profile @ Level 4',
1782
			    0x1A => 'Low Delay Audio Profile @ Level 5',
1783
			    0x1B => 'Low Delay Audio Profile @ Level 6',
1784
			    0x1C => 'Low Delay Audio Profile @ Level 7',
1785
			    0x1D => 'Low Delay Audio Profile @ Level 8',
1786
			    0x1E => 'Natural Audio Profile @ Level 1',
1787
			    0x1F => 'Natural Audio Profile @ Level 2',
1788
			    0x20 => 'Natural Audio Profile @ Level 3',
1789
			    0x21 => 'Natural Audio Profile @ Level 4',
1790
			    0x22 => 'Mobile Audio Internetworking Profile @ Level 1',
1791
			    0x23 => 'Mobile Audio Internetworking Profile @ Level 2',
1792
			    0x24 => 'Mobile Audio Internetworking Profile @ Level 3',
1793
			    0x25 => 'Mobile Audio Internetworking Profile @ Level 4',
1794
			    0x26 => 'Mobile Audio Internetworking Profile @ Level 5',
1795
			    0x27 => 'Mobile Audio Internetworking Profile @ Level 6',
1796
			    0x28 => 'AAC Profile @ Level 1',
1797
			    0x29 => 'AAC Profile @ Level 2',
1798
			    0x2A => 'AAC Profile @ Level 4',
1799
			    0x2B => 'AAC Profile @ Level 5',
1800
			    0x2C => 'High Efficiency AAC Profile @ Level 2',
1801
			    0x2D => 'High Efficiency AAC Profile @ Level 3',
1802
			    0x2E => 'High Efficiency AAC Profile @ Level 4',
1803
			    0x2F => 'High Efficiency AAC Profile @ Level 5',
1804
			    0xFE => 'Not part of MPEG-4 audio profiles',
1805
			    0xFF => 'No audio capability required',
1806
			);
1807
		}
1808
		return (isset($QuicktimeIODSaudioProfileNameLookup[$audio_profile_id]) ? $QuicktimeIODSaudioProfileNameLookup[$audio_profile_id] : 'ISO Reserved / User Private');
1809
	}
1810
1811
1812
	public function QuicktimeIODSvideoProfileName($video_profile_id) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
1813
		static $QuicktimeIODSvideoProfileNameLookup = array();
1814
		if (empty($QuicktimeIODSvideoProfileNameLookup)) {
1815
			$QuicktimeIODSvideoProfileNameLookup = array(
1816
				0x00 => 'Reserved (0x00) Profile',
1817
				0x01 => 'Simple Profile @ Level 1',
1818
				0x02 => 'Simple Profile @ Level 2',
1819
				0x03 => 'Simple Profile @ Level 3',
1820
				0x08 => 'Simple Profile @ Level 0',
1821
				0x10 => 'Simple Scalable Profile @ Level 0',
1822
				0x11 => 'Simple Scalable Profile @ Level 1',
1823
				0x12 => 'Simple Scalable Profile @ Level 2',
1824
				0x15 => 'AVC/H264 Profile',
1825
				0x21 => 'Core Profile @ Level 1',
1826
				0x22 => 'Core Profile @ Level 2',
1827
				0x32 => 'Main Profile @ Level 2',
1828
				0x33 => 'Main Profile @ Level 3',
1829
				0x34 => 'Main Profile @ Level 4',
1830
				0x42 => 'N-bit Profile @ Level 2',
1831
				0x51 => 'Scalable Texture Profile @ Level 1',
1832
				0x61 => 'Simple Face Animation Profile @ Level 1',
1833
				0x62 => 'Simple Face Animation Profile @ Level 2',
1834
				0x63 => 'Simple FBA Profile @ Level 1',
1835
				0x64 => 'Simple FBA Profile @ Level 2',
1836
				0x71 => 'Basic Animated Texture Profile @ Level 1',
1837
				0x72 => 'Basic Animated Texture Profile @ Level 2',
1838
				0x81 => 'Hybrid Profile @ Level 1',
1839
				0x82 => 'Hybrid Profile @ Level 2',
1840
				0x91 => 'Advanced Real Time Simple Profile @ Level 1',
1841
				0x92 => 'Advanced Real Time Simple Profile @ Level 2',
1842
				0x93 => 'Advanced Real Time Simple Profile @ Level 3',
1843
				0x94 => 'Advanced Real Time Simple Profile @ Level 4',
1844
				0xA1 => 'Core Scalable Profile @ Level1',
1845
				0xA2 => 'Core Scalable Profile @ Level2',
1846
				0xA3 => 'Core Scalable Profile @ Level3',
1847
				0xB1 => 'Advanced Coding Efficiency Profile @ Level 1',
1848
				0xB2 => 'Advanced Coding Efficiency Profile @ Level 2',
1849
				0xB3 => 'Advanced Coding Efficiency Profile @ Level 3',
1850
				0xB4 => 'Advanced Coding Efficiency Profile @ Level 4',
1851
				0xC1 => 'Advanced Core Profile @ Level 1',
1852
				0xC2 => 'Advanced Core Profile @ Level 2',
1853
				0xD1 => 'Advanced Scalable Texture @ Level1',
1854
				0xD2 => 'Advanced Scalable Texture @ Level2',
1855
				0xE1 => 'Simple Studio Profile @ Level 1',
1856
				0xE2 => 'Simple Studio Profile @ Level 2',
1857
				0xE3 => 'Simple Studio Profile @ Level 3',
1858
				0xE4 => 'Simple Studio Profile @ Level 4',
1859
				0xE5 => 'Core Studio Profile @ Level 1',
1860
				0xE6 => 'Core Studio Profile @ Level 2',
1861
				0xE7 => 'Core Studio Profile @ Level 3',
1862
				0xE8 => 'Core Studio Profile @ Level 4',
1863
				0xF0 => 'Advanced Simple Profile @ Level 0',
1864
				0xF1 => 'Advanced Simple Profile @ Level 1',
1865
				0xF2 => 'Advanced Simple Profile @ Level 2',
1866
				0xF3 => 'Advanced Simple Profile @ Level 3',
1867
				0xF4 => 'Advanced Simple Profile @ Level 4',
1868
				0xF5 => 'Advanced Simple Profile @ Level 5',
1869
				0xF7 => 'Advanced Simple Profile @ Level 3b',
1870
				0xF8 => 'Fine Granularity Scalable Profile @ Level 0',
1871
				0xF9 => 'Fine Granularity Scalable Profile @ Level 1',
1872
				0xFA => 'Fine Granularity Scalable Profile @ Level 2',
1873
				0xFB => 'Fine Granularity Scalable Profile @ Level 3',
1874
				0xFC => 'Fine Granularity Scalable Profile @ Level 4',
1875
				0xFD => 'Fine Granularity Scalable Profile @ Level 5',
1876
				0xFE => 'Not part of MPEG-4 Visual profiles',
1877
				0xFF => 'No visual capability required',
1878
			);
1879
		}
1880
		return (isset($QuicktimeIODSvideoProfileNameLookup[$video_profile_id]) ? $QuicktimeIODSvideoProfileNameLookup[$video_profile_id] : 'ISO Reserved Profile');
1881
	}
1882
1883
1884 View Code Duplication
	public function QuicktimeContentRatingLookup($rtng) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
1885
		static $QuicktimeContentRatingLookup = array();
1886
		if (empty($QuicktimeContentRatingLookup)) {
1887
			$QuicktimeContentRatingLookup[0]  = 'None';
1888
			$QuicktimeContentRatingLookup[2]  = 'Clean';
1889
			$QuicktimeContentRatingLookup[4]  = 'Explicit';
1890
		}
1891
		return (isset($QuicktimeContentRatingLookup[$rtng]) ? $QuicktimeContentRatingLookup[$rtng] : 'invalid');
1892
	}
1893
1894
	public function QuicktimeStoreAccountTypeLookup($akid) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
1895
		static $QuicktimeStoreAccountTypeLookup = array();
1896
		if (empty($QuicktimeStoreAccountTypeLookup)) {
1897
			$QuicktimeStoreAccountTypeLookup[0] = 'iTunes';
1898
			$QuicktimeStoreAccountTypeLookup[1] = 'AOL';
1899
		}
1900
		return (isset($QuicktimeStoreAccountTypeLookup[$akid]) ? $QuicktimeStoreAccountTypeLookup[$akid] : 'invalid');
1901
	}
1902
1903
	public function QuicktimeStoreFrontCodeLookup($sfid) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
1904
		static $QuicktimeStoreFrontCodeLookup = array();
1905
		if (empty($QuicktimeStoreFrontCodeLookup)) {
1906
			$QuicktimeStoreFrontCodeLookup[143460] = 'Australia';
1907
			$QuicktimeStoreFrontCodeLookup[143445] = 'Austria';
1908
			$QuicktimeStoreFrontCodeLookup[143446] = 'Belgium';
1909
			$QuicktimeStoreFrontCodeLookup[143455] = 'Canada';
1910
			$QuicktimeStoreFrontCodeLookup[143458] = 'Denmark';
1911
			$QuicktimeStoreFrontCodeLookup[143447] = 'Finland';
1912
			$QuicktimeStoreFrontCodeLookup[143442] = 'France';
1913
			$QuicktimeStoreFrontCodeLookup[143443] = 'Germany';
1914
			$QuicktimeStoreFrontCodeLookup[143448] = 'Greece';
1915
			$QuicktimeStoreFrontCodeLookup[143449] = 'Ireland';
1916
			$QuicktimeStoreFrontCodeLookup[143450] = 'Italy';
1917
			$QuicktimeStoreFrontCodeLookup[143462] = 'Japan';
1918
			$QuicktimeStoreFrontCodeLookup[143451] = 'Luxembourg';
1919
			$QuicktimeStoreFrontCodeLookup[143452] = 'Netherlands';
1920
			$QuicktimeStoreFrontCodeLookup[143461] = 'New Zealand';
1921
			$QuicktimeStoreFrontCodeLookup[143457] = 'Norway';
1922
			$QuicktimeStoreFrontCodeLookup[143453] = 'Portugal';
1923
			$QuicktimeStoreFrontCodeLookup[143454] = 'Spain';
1924
			$QuicktimeStoreFrontCodeLookup[143456] = 'Sweden';
1925
			$QuicktimeStoreFrontCodeLookup[143459] = 'Switzerland';
1926
			$QuicktimeStoreFrontCodeLookup[143444] = 'United Kingdom';
1927
			$QuicktimeStoreFrontCodeLookup[143441] = 'United States';
1928
		}
1929
		return (isset($QuicktimeStoreFrontCodeLookup[$sfid]) ? $QuicktimeStoreFrontCodeLookup[$sfid] : 'invalid');
1930
	}
1931
1932
	public function QuicktimeParseNikonNCTG($atom_data) {
1933
		// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
1934
		// Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100
1935
		// Data is stored as records of:
1936
		// * 4 bytes record type
1937
		// * 2 bytes size of data field type:
1938
		//     0x0001 = flag   (size field *= 1-byte)
1939
		//     0x0002 = char   (size field *= 1-byte)
1940
		//     0x0003 = DWORD+ (size field *= 2-byte), values are stored CDAB
1941
		//     0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD
1942
		//     0x0005 = float  (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together
1943
		//     0x0007 = bytes  (size field *= 1-byte), values are stored as ??????
1944
		//     0x0008 = ?????  (size field *= 2-byte), values are stored as ??????
1945
		// * 2 bytes data size field
1946
		// * ? bytes data (string data may be null-padded; datestamp fields are in the format "2011:05:25 20:24:15")
1947
		// all integers are stored BigEndian
1948
1949
		$NCTGtagName = array(
1950
			0x00000001 => 'Make',
1951
			0x00000002 => 'Model',
1952
			0x00000003 => 'Software',
1953
			0x00000011 => 'CreateDate',
1954
			0x00000012 => 'DateTimeOriginal',
1955
			0x00000013 => 'FrameCount',
1956
			0x00000016 => 'FrameRate',
1957
			0x00000022 => 'FrameWidth',
1958
			0x00000023 => 'FrameHeight',
1959
			0x00000032 => 'AudioChannels',
1960
			0x00000033 => 'AudioBitsPerSample',
1961
			0x00000034 => 'AudioSampleRate',
1962
			0x02000001 => 'MakerNoteVersion',
1963
			0x02000005 => 'WhiteBalance',
1964
			0x0200000b => 'WhiteBalanceFineTune',
1965
			0x0200001e => 'ColorSpace',
1966
			0x02000023 => 'PictureControlData',
1967
			0x02000024 => 'WorldTime',
1968
			0x02000032 => 'UnknownInfo',
1969
			0x02000083 => 'LensType',
1970
			0x02000084 => 'Lens',
1971
		);
1972
1973
		$offset = 0;
1974
		$datalength = strlen($atom_data);
1975
		$parsed = array();
1976
		while ($offset < $datalength) {
1977
//echo getid3_lib::PrintHexBytes(substr($atom_data, $offset, 4)).'<br>';
1978
			$record_type       = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4));  $offset += 4;
1979
			$data_size_type    = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2));  $offset += 2;
1980
			$data_size         = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2));  $offset += 2;
1981
			switch ($data_size_type) {
1982
				case 0x0001: // 0x0001 = flag   (size field *= 1-byte)
1983
					$data = getid3_lib::BigEndian2Int(substr($atom_data, $offset, $data_size * 1));
1984
					$offset += ($data_size * 1);
1985
					break;
1986 View Code Duplication
				case 0x0002: // 0x0002 = char   (size field *= 1-byte)
1987
					$data = substr($atom_data, $offset, $data_size * 1);
1988
					$offset += ($data_size * 1);
1989
					$data = rtrim($data, "\x00");
1990
					break;
1991 View Code Duplication
				case 0x0003: // 0x0003 = DWORD+ (size field *= 2-byte), values are stored CDAB
1992
					$data = '';
1993
					for ($i = $data_size - 1; $i >= 0; $i--) {
1994
						$data .= substr($atom_data, $offset + ($i * 2), 2);
1995
					}
1996
					$data = getid3_lib::BigEndian2Int($data);
1997
					$offset += ($data_size * 2);
1998
					break;
1999 View Code Duplication
				case 0x0004: // 0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD
2000
					$data = '';
2001
					for ($i = $data_size - 1; $i >= 0; $i--) {
2002
						$data .= substr($atom_data, $offset + ($i * 4), 4);
2003
					}
2004
					$data = getid3_lib::BigEndian2Int($data);
2005
					$offset += ($data_size * 4);
2006
					break;
2007
				case 0x0005: // 0x0005 = float  (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together
2008
					$data = array();
2009
					for ($i = 0; $i < $data_size; $i++) {
2010
						$numerator    = getid3_lib::BigEndian2Int(substr($atom_data, $offset + ($i * 8) + 0, 4));
2011
						$denomninator = getid3_lib::BigEndian2Int(substr($atom_data, $offset + ($i * 8) + 4, 4));
2012
						if ($denomninator == 0) {
2013
							$data[$i] = false;
2014
						} else {
2015
							$data[$i] = (double) $numerator / $denomninator;
2016
						}
2017
					}
2018
					$offset += (8 * $data_size);
2019
					if (count($data) == 1) {
2020
						$data = $data[0];
2021
					}
2022
					break;
2023 View Code Duplication
				case 0x0007: // 0x0007 = bytes  (size field *= 1-byte), values are stored as ??????
2024
					$data = substr($atom_data, $offset, $data_size * 1);
2025
					$offset += ($data_size * 1);
2026
					break;
2027 View Code Duplication
				case 0x0008: // 0x0008 = ?????  (size field *= 2-byte), values are stored as ??????
2028
					$data = substr($atom_data, $offset, $data_size * 2);
2029
					$offset += ($data_size * 2);
2030
					break;
2031
				default:
2032
echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br>';
2033
					break 2;
2034
			}
2035
2036
			switch ($record_type) {
2037
				case 0x00000011: // CreateDate
2038
				case 0x00000012: // DateTimeOriginal
2039
					$data = strtotime($data);
2040
					break;
2041
				case 0x0200001e: // ColorSpace
2042
					switch ($data) {
2043
						case 1:
2044
							$data = 'sRGB';
2045
							break;
2046
						case 2:
2047
							$data = 'Adobe RGB';
2048
							break;
2049
					}
2050
					break;
2051
				case 0x02000023: // PictureControlData
2052
					$PictureControlAdjust = array(0=>'default', 1=>'quick', 2=>'full');
2053
					$FilterEffect = array(0x80=>'off', 0x81=>'yellow', 0x82=>'orange',    0x83=>'red', 0x84=>'green',  0xff=>'n/a');
2054
					$ToningEffect = array(0x80=>'b&w', 0x81=>'sepia',  0x82=>'cyanotype', 0x83=>'red', 0x84=>'yellow', 0x85=>'green', 0x86=>'blue-green', 0x87=>'blue', 0x88=>'purple-blue', 0x89=>'red-purple', 0xff=>'n/a');
2055
					$data = array(
2056
						'PictureControlVersion'     =>                           substr($data,  0,  4),
2057
						'PictureControlName'        =>                     rtrim(substr($data,  4, 20), "\x00"),
2058
						'PictureControlBase'        =>                     rtrim(substr($data, 24, 20), "\x00"),
2059
						//'?'                       =>                           substr($data, 44,  4),
2060
						'PictureControlAdjust'      => $PictureControlAdjust[ord(substr($data, 48,  1))],
2061
						'PictureControlQuickAdjust' =>                       ord(substr($data, 49,  1)),
2062
						'Sharpness'                 =>                       ord(substr($data, 50,  1)),
2063
						'Contrast'                  =>                       ord(substr($data, 51,  1)),
2064
						'Brightness'                =>                       ord(substr($data, 52,  1)),
2065
						'Saturation'                =>                       ord(substr($data, 53,  1)),
2066
						'HueAdjustment'             =>                       ord(substr($data, 54,  1)),
2067
						'FilterEffect'              =>         $FilterEffect[ord(substr($data, 55,  1))],
2068
						'ToningEffect'              =>         $ToningEffect[ord(substr($data, 56,  1))],
2069
						'ToningSaturation'          =>                       ord(substr($data, 57,  1)),
2070
					);
2071
					break;
2072
				case 0x02000024: // WorldTime
2073
					// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#WorldTime
2074
					// timezone is stored as offset from GMT in minutes
2075
					$timezone = getid3_lib::BigEndian2Int(substr($data, 0, 2));
2076
					if ($timezone & 0x8000) {
2077
						$timezone = 0 - (0x10000 - $timezone);
2078
					}
2079
					$timezone /= 60;
2080
2081
					$dst = (bool) getid3_lib::BigEndian2Int(substr($data, 2, 1));
2082
					switch (getid3_lib::BigEndian2Int(substr($data, 3, 1))) {
2083
						case 2:
2084
							$datedisplayformat = 'D/M/Y'; break;
2085
						case 1:
2086
							$datedisplayformat = 'M/D/Y'; break;
2087
						case 0:
2088
						default:
2089
							$datedisplayformat = 'Y/M/D'; break;
2090
					}
2091
2092
					$data = array('timezone'=>floatval($timezone), 'dst'=>$dst, 'display'=>$datedisplayformat);
2093
					break;
2094
				case 0x02000083: // LensType
2095
					$data = array(
2096
						//'_'  => $data,
2097
						'mf' => (bool) ($data & 0x01),
2098
						'd'  => (bool) ($data & 0x02),
2099
						'g'  => (bool) ($data & 0x04),
2100
						'vr' => (bool) ($data & 0x08),
2101
					);
2102
					break;
2103
			}
2104
			$tag_name = (isset($NCTGtagName[$record_type]) ? $NCTGtagName[$record_type] : '0x'.str_pad(dechex($record_type), 8, '0', STR_PAD_LEFT));
2105
			$parsed[$tag_name] = $data;
2106
		}
2107
		return $parsed;
2108
	}
2109
2110
2111
	public function CopyToAppropriateCommentsSection($keyname, $data, $boxname='') {
2112
		static $handyatomtranslatorarray = array();
2113
		if (empty($handyatomtranslatorarray)) {
2114
			$handyatomtranslatorarray["\xA9".'cpy'] = 'copyright';
2115
			$handyatomtranslatorarray["\xA9".'day'] = 'creation_date';    // iTunes 4.0
2116
			$handyatomtranslatorarray["\xA9".'dir'] = 'director';
2117
			$handyatomtranslatorarray["\xA9".'ed1'] = 'edit1';
2118
			$handyatomtranslatorarray["\xA9".'ed2'] = 'edit2';
2119
			$handyatomtranslatorarray["\xA9".'ed3'] = 'edit3';
2120
			$handyatomtranslatorarray["\xA9".'ed4'] = 'edit4';
2121
			$handyatomtranslatorarray["\xA9".'ed5'] = 'edit5';
2122
			$handyatomtranslatorarray["\xA9".'ed6'] = 'edit6';
2123
			$handyatomtranslatorarray["\xA9".'ed7'] = 'edit7';
2124
			$handyatomtranslatorarray["\xA9".'ed8'] = 'edit8';
2125
			$handyatomtranslatorarray["\xA9".'ed9'] = 'edit9';
2126
			$handyatomtranslatorarray["\xA9".'fmt'] = 'format';
2127
			$handyatomtranslatorarray["\xA9".'inf'] = 'information';
2128
			$handyatomtranslatorarray["\xA9".'prd'] = 'producer';
2129
			$handyatomtranslatorarray["\xA9".'prf'] = 'performers';
2130
			$handyatomtranslatorarray["\xA9".'req'] = 'system_requirements';
2131
			$handyatomtranslatorarray["\xA9".'src'] = 'source_credit';
2132
			$handyatomtranslatorarray["\xA9".'wrt'] = 'writer';
2133
2134
			// http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt
2135
			$handyatomtranslatorarray["\xA9".'nam'] = 'title';           // iTunes 4.0
2136
			$handyatomtranslatorarray["\xA9".'cmt'] = 'comment';         // iTunes 4.0
2137
			$handyatomtranslatorarray["\xA9".'wrn'] = 'warning';
2138
			$handyatomtranslatorarray["\xA9".'hst'] = 'host_computer';
2139
			$handyatomtranslatorarray["\xA9".'mak'] = 'make';
2140
			$handyatomtranslatorarray["\xA9".'mod'] = 'model';
2141
			$handyatomtranslatorarray["\xA9".'PRD'] = 'product';
2142
			$handyatomtranslatorarray["\xA9".'swr'] = 'software';
2143
			$handyatomtranslatorarray["\xA9".'aut'] = 'author';
2144
			$handyatomtranslatorarray["\xA9".'ART'] = 'artist';
2145
			$handyatomtranslatorarray["\xA9".'trk'] = 'track';
2146
			$handyatomtranslatorarray["\xA9".'alb'] = 'album';           // iTunes 4.0
2147
			$handyatomtranslatorarray["\xA9".'com'] = 'comment';
2148
			$handyatomtranslatorarray["\xA9".'gen'] = 'genre';           // iTunes 4.0
2149
			$handyatomtranslatorarray["\xA9".'ope'] = 'composer';
2150
			$handyatomtranslatorarray["\xA9".'url'] = 'url';
2151
			$handyatomtranslatorarray["\xA9".'enc'] = 'encoder';
2152
2153
			// http://atomicparsley.sourceforge.net/mpeg-4files.html
2154
			$handyatomtranslatorarray["\xA9".'art'] = 'artist';           // iTunes 4.0
2155
			$handyatomtranslatorarray['aART'] = 'album_artist';
2156
			$handyatomtranslatorarray['trkn'] = 'track_number';     // iTunes 4.0
2157
			$handyatomtranslatorarray['disk'] = 'disc_number';      // iTunes 4.0
2158
			$handyatomtranslatorarray['gnre'] = 'genre';            // iTunes 4.0
2159
			$handyatomtranslatorarray["\xA9".'too'] = 'encoder';          // iTunes 4.0
2160
			$handyatomtranslatorarray['tmpo'] = 'bpm';              // iTunes 4.0
2161
			$handyatomtranslatorarray['cprt'] = 'copyright';        // iTunes 4.0?
2162
			$handyatomtranslatorarray['cpil'] = 'compilation';      // iTunes 4.0
2163
			$handyatomtranslatorarray['covr'] = 'picture';          // iTunes 4.0
2164
			$handyatomtranslatorarray['rtng'] = 'rating';           // iTunes 4.0
2165
			$handyatomtranslatorarray["\xA9".'grp'] = 'grouping';         // iTunes 4.2
2166
			$handyatomtranslatorarray['stik'] = 'stik';             // iTunes 4.9
2167
			$handyatomtranslatorarray['pcst'] = 'podcast';          // iTunes 4.9
2168
			$handyatomtranslatorarray['catg'] = 'category';         // iTunes 4.9
2169
			$handyatomtranslatorarray['keyw'] = 'keyword';          // iTunes 4.9
2170
			$handyatomtranslatorarray['purl'] = 'podcast_url';      // iTunes 4.9
2171
			$handyatomtranslatorarray['egid'] = 'episode_guid';     // iTunes 4.9
2172
			$handyatomtranslatorarray['desc'] = 'description';      // iTunes 5.0
2173
			$handyatomtranslatorarray["\xA9".'lyr'] = 'lyrics';           // iTunes 5.0
2174
			$handyatomtranslatorarray['tvnn'] = 'tv_network_name';  // iTunes 6.0
2175
			$handyatomtranslatorarray['tvsh'] = 'tv_show_name';     // iTunes 6.0
2176
			$handyatomtranslatorarray['tvsn'] = 'tv_season';        // iTunes 6.0
2177
			$handyatomtranslatorarray['tves'] = 'tv_episode';       // iTunes 6.0
2178
			$handyatomtranslatorarray['purd'] = 'purchase_date';    // iTunes 6.0.2
2179
			$handyatomtranslatorarray['pgap'] = 'gapless_playback'; // iTunes 7.0
2180
2181
			// http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt
2182
2183
2184
2185
			// boxnames:
2186
			/*
2187
			$handyatomtranslatorarray['iTunSMPB']                    = 'iTunSMPB';
2188
			$handyatomtranslatorarray['iTunNORM']                    = 'iTunNORM';
2189
			$handyatomtranslatorarray['Encoding Params']             = 'Encoding Params';
2190
			$handyatomtranslatorarray['replaygain_track_gain']       = 'replaygain_track_gain';
2191
			$handyatomtranslatorarray['replaygain_track_peak']       = 'replaygain_track_peak';
2192
			$handyatomtranslatorarray['replaygain_track_minmax']     = 'replaygain_track_minmax';
2193
			$handyatomtranslatorarray['MusicIP PUID']                = 'MusicIP PUID';
2194
			$handyatomtranslatorarray['MusicBrainz Artist Id']       = 'MusicBrainz Artist Id';
2195
			$handyatomtranslatorarray['MusicBrainz Album Id']        = 'MusicBrainz Album Id';
2196
			$handyatomtranslatorarray['MusicBrainz Album Artist Id'] = 'MusicBrainz Album Artist Id';
2197
			$handyatomtranslatorarray['MusicBrainz Track Id']        = 'MusicBrainz Track Id';
2198
			$handyatomtranslatorarray['MusicBrainz Disc Id']         = 'MusicBrainz Disc Id';
2199
2200
			// http://age.hobba.nl/audio/tag_frame_reference.html
2201
			$handyatomtranslatorarray['PLAY_COUNTER']                = 'play_counter'; // Foobar2000 - http://www.getid3.org/phpBB3/viewtopic.php?t=1355
2202
			$handyatomtranslatorarray['MEDIATYPE']                   = 'mediatype';    // Foobar2000 - http://www.getid3.org/phpBB3/viewtopic.php?t=1355
2203
			*/
2204
		}
2205
		$info = &$this->getid3->info;
2206
		$comment_key = '';
2207
		if ($boxname && ($boxname != $keyname)) {
2208
			$comment_key = (isset($handyatomtranslatorarray[$boxname]) ? $handyatomtranslatorarray[$boxname] : $boxname);
2209
		} elseif (isset($handyatomtranslatorarray[$keyname])) {
2210
			$comment_key = $handyatomtranslatorarray[$keyname];
2211
		}
2212
		if ($comment_key) {
2213
			if ($comment_key == 'picture') {
2214
				if (!is_array($data)) {
2215
					$image_mime = '';
2216
					if (preg_match('#^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A#', $data)) {
2217
						$image_mime = 'image/png';
2218
					} elseif (preg_match('#^\xFF\xD8\xFF#', $data)) {
2219
						$image_mime = 'image/jpeg';
2220
					} elseif (preg_match('#^GIF#', $data)) {
2221
						$image_mime = 'image/gif';
2222
					} elseif (preg_match('#^BM#', $data)) {
2223
						$image_mime = 'image/bmp';
2224
					}
2225
					$data = array('data'=>$data, 'image_mime'=>$image_mime);
2226
				}
2227
			}
2228
			$info['quicktime']['comments'][$comment_key][] = $data;
2229
		}
2230
		return true;
2231
	}
2232
2233
	public function NoNullString($nullterminatedstring) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
2234
		// remove the single null terminator on null terminated strings
2235
		if (substr($nullterminatedstring, strlen($nullterminatedstring) - 1, 1) === "\x00") {
2236
			return substr($nullterminatedstring, 0, strlen($nullterminatedstring) - 1);
2237
		}
2238
		return $nullterminatedstring;
2239
	}
2240
2241
	public function Pascal2String($pascalstring) {
2242
		// Pascal strings have 1 unsigned byte at the beginning saying how many chars (1-255) are in the string
2243
		return substr($pascalstring, 1);
2244
	}
2245
2246
}
2247