Passed
Branch master (f2d2e3)
by Michael
18:45
created

getid3_quicktime   F

Complexity

Total Complexity 223

Size/Duplication

Total Lines 1501
Duplicated Lines 4.93 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 0
Metric Value
dl 74
loc 1501
rs 0.8
c 0
b 0
f 0
wmc 223
lcom 1
cbo 5

13 Methods

Rating   Name   Duplication   Size   Complexity  
B QuicktimeLanguageLookup() 0 116 2
A NoNullString() 0 8 2
F Analyze() 0 145 30
A QuicktimeAudioCodecLookup() 0 44 2
A FixedPoint8_8() 0 3 1
A QuicktimeDCOMLookup() 0 8 2
F QuicktimeParseAtom() 0 967 171
B QuicktimeVideoCodecLookup() 0 57 2
A FixedPoint16_16() 0 3 1
A QuicktimeParseContainerAtom() 0 27 5
A CopyToAppropriateCommentsSection() 0 48 2
A QuicktimeColorNameLookup() 0 17 2
A FixedPoint2_30() 0 4 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like getid3_quicktime often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use getid3_quicktime, and based on these observations, apply Extract Interface, too.

1
<?php
2
// +----------------------------------------------------------------------+
3
// | PHP version 5                                                        |
4
// +----------------------------------------------------------------------+
5
// | Copyright (c) 2002-2006 James Heinrich, Allan Hansen                 |
6
// +----------------------------------------------------------------------+
7
// | This source file is subject to version 2 of the GPL license,         |
8
// | that is bundled with this package in the file license.txt and is     |
9
// | available through the world-wide-web at the following url:           |
10
// | http://www.gnu.org/copyleft/gpl.html                                 |
11
// +----------------------------------------------------------------------+
12
// | getID3() - http://getid3.sourceforge.net or http://www.getid3.org    |
13
// +----------------------------------------------------------------------+
14
// | Authors: James Heinrich <info�getid3*org>                            |
15
// |          Allan Hansen <ah�artemis*dk>                                |
16
// +----------------------------------------------------------------------+
17
// | module.audio-video.quicktime.php                                     |
18
// | Module for analyzing Quicktime, MP3-in-MP4 and Apple Lossless files. |
19
// | dependencies: module.audio.mp3.php                                   |
20
// |               zlib support in PHP (optional)                         |
21
// +----------------------------------------------------------------------+
22
//
23
// $Id: module.audio-video.quicktime.php,v 1.7 2006/11/02 16:03:28 ah Exp $
24
25
        
26
        
27
class getid3_quicktime extends getid3_handler
28
{
29
30
    public function Analyze() {
31
        
32
        $getid3 = $this->getid3;
33
34
        $info   = &$getid3->info;
35
        
36
        $getid3->include_module('audio.mp3');
37
        
38
        $info['quicktime'] = array ();
39
        $info_quicktime = &$info['quicktime'];
40
41
        $info['fileformat'] = 'quicktime';
42
        $info_quicktime['hinting'] = false;
43
44
        fseek($getid3->fp, $info['avdataoffset'], SEEK_SET);
45
46
        $offset = $atom_counter = 0;
47
48
        while ($offset < $info['avdataend']) {
49
50
            fseek($getid3->fp, $offset, SEEK_SET);
51
            $atom_header = fread($getid3->fp, 8);
52
53
            $atom_size = getid3_lib::BigEndian2Int(substr($atom_header, 0, 4));
54
            $atom_name =               substr($atom_header, 4, 4);
55
            
56
            $info_quicktime[$atom_name]['name']   = $atom_name;
57
            $info_quicktime[$atom_name]['size']   = $atom_size;
58
            $info_quicktime[$atom_name]['offset'] = $offset;
59
60
            if (($offset + $atom_size) > $info['avdataend']) {
61
                throw new getid3_exception('Atom at offset '.$offset.' claims to go beyond end-of-file (length: '.$atom_size.' bytes)');
62
            }
63
64
            if ($atom_size == 0) {
65
                // Furthermore, for historical reasons the list of atoms is optionally
66
                // terminated by a 32-bit integer set to 0. If you are writing a program
67
                // to read user data atoms, you should allow for the terminating 0.
68
                break;
69
            }
70
            
71
            switch ($atom_name) {
72
            
73
                case 'mdat': // Media DATa atom
74
                    // 'mdat' contains the actual data for the audio/video
75
                    if (($atom_size > 8) && (!isset($info['avdataend_tmp']) || ($info_quicktime[$atom_name]['size'] > ($info['avdataend_tmp'] - $info['avdataoffset'])))) {
76
77
                        $info['avdataoffset'] = $info_quicktime[$atom_name]['offset'] + 8;
78
                        $old_av_data_end      = $info['avdataend'];
79
                        $info['avdataend']    = $info_quicktime[$atom_name]['offset'] + $info_quicktime[$atom_name]['size'];
80
81
                        
82
                        //// MP3
83
                        
84
                        if (!$getid3->include_module_optional('audio.mp3')) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $getid3->include_module_optional('audio.mp3') of type null|true is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

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

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...