source: spip-zone/_core_/plugins/medias/lib/getid3/module.audio.aac.php @ 113161

Last change on this file since 113161 was 113161, checked in by spip.franck@…, 5 months ago

Mise à jour de la lib getid en 1.9.16, nous étions en 1.9.14
https://github.com/JamesHeinrich/getID3/blob/master/changelog.txt

File size: 24.5 KB
Line 
1<?php
2
3/////////////////////////////////////////////////////////////////
4/// getID3() by James Heinrich <info@getid3.org>               //
5//  available at https://github.com/JamesHeinrich/getID3       //
6//            or https://www.getid3.org                        //
7//            or http://getid3.sourceforge.net                 //
8//  see readme.txt for more details                            //
9/////////////////////////////////////////////////////////////////
10//                                                             //
11// module.audio.aac.php                                        //
12// module for analyzing AAC Audio files                        //
13// dependencies: NONE                                          //
14//                                                            ///
15/////////////////////////////////////////////////////////////////
16
17
18class getid3_aac extends getid3_handler
19{
20        /**
21         * @return bool
22         */
23        public function Analyze() {
24                $info = &$this->getid3->info;
25                $this->fseek($info['avdataoffset']);
26                if ($this->fread(4) == 'ADIF') {
27                        $this->getAACADIFheaderFilepointer();
28                } else {
29                        $this->getAACADTSheaderFilepointer();
30                }
31                return true;
32        }
33
34        /**
35         * @return bool
36         */
37        public function getAACADIFheaderFilepointer() {
38                $info = &$this->getid3->info;
39                $info['fileformat']          = 'aac';
40                $info['audio']['dataformat'] = 'aac';
41                $info['audio']['lossless']   = false;
42
43                $this->fseek($info['avdataoffset']);
44                $AACheader = $this->fread(1024);
45                $offset    = 0;
46
47                if (substr($AACheader, 0, 4) == 'ADIF') {
48
49                        // http://faac.sourceforge.net/wiki/index.php?page=ADIF
50
51                        // http://libmpeg.org/mpeg4/doc/w2203tfs.pdf
52                        // adif_header() {
53                        //     adif_id                                32
54                        //     copyright_id_present                    1
55                        //     if( copyright_id_present )
56                        //         copyright_id                       72
57                        //     original_copy                           1
58                        //     home                                    1
59                        //     bitstream_type                          1
60                        //     bitrate                                23
61                        //     num_program_config_elements             4
62                        //     for (i = 0; i < num_program_config_elements + 1; i++ ) {
63                        //         if( bitstream_type == '0' )
64                        //             adif_buffer_fullness           20
65                        //         program_config_element()
66                        //     }
67                        // }
68
69                        $AACheaderBitstream = getid3_lib::BigEndian2Bin($AACheader);
70                        $bitoffset          = 0;
71
72                        $info['aac']['header_type']                   = 'ADIF';
73                        $bitoffset += 32;
74                        $info['aac']['header']['mpeg_version']        = 4;
75
76                        $info['aac']['header']['copyright']           = substr($AACheaderBitstream, $bitoffset, 1) == '1';
77                        $bitoffset += 1;
78                        if ($info['aac']['header']['copyright']) {
79                                $info['aac']['header']['copyright_id']    = getid3_lib::Bin2String(substr($AACheaderBitstream, $bitoffset, 72));
80                                $bitoffset += 72;
81                        }
82                        $info['aac']['header']['original_copy']       = substr($AACheaderBitstream, $bitoffset, 1) == '1';
83                        $bitoffset += 1;
84                        $info['aac']['header']['home']                = substr($AACheaderBitstream, $bitoffset, 1) == '1';
85                        $bitoffset += 1;
86                        $info['aac']['header']['is_vbr']              = substr($AACheaderBitstream, $bitoffset, 1) == '1';
87                        $bitoffset += 1;
88                        if ($info['aac']['header']['is_vbr']) {
89                                $info['audio']['bitrate_mode']            = 'vbr';
90                                $info['aac']['header']['bitrate_max']     = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 23));
91                                $bitoffset += 23;
92                        } else {
93                                $info['audio']['bitrate_mode']            = 'cbr';
94                                $info['aac']['header']['bitrate']         = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 23));
95                                $bitoffset += 23;
96                                $info['audio']['bitrate']                 = $info['aac']['header']['bitrate'];
97                        }
98                        if ($info['audio']['bitrate'] == 0) {
99                                $this->error('Corrupt AAC file: bitrate_audio == zero');
100                                return false;
101                        }
102                        $info['aac']['header']['num_program_configs'] = 1 + getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
103                        $bitoffset += 4;
104
105                        for ($i = 0; $i < $info['aac']['header']['num_program_configs']; $i++) {
106                                // http://www.audiocoding.com/wiki/index.php?page=program_config_element
107
108                                // buffer_fullness                       20
109
110                                // element_instance_tag                   4
111                                // object_type                            2
112                                // sampling_frequency_index               4
113                                // num_front_channel_elements             4
114                                // num_side_channel_elements              4
115                                // num_back_channel_elements              4
116                                // num_lfe_channel_elements               2
117                                // num_assoc_data_elements                3
118                                // num_valid_cc_elements                  4
119                                // mono_mixdown_present                   1
120                                // mono_mixdown_element_number            4   if mono_mixdown_present == 1
121                                // stereo_mixdown_present                 1
122                                // stereo_mixdown_element_number          4   if stereo_mixdown_present == 1
123                                // matrix_mixdown_idx_present             1
124                                // matrix_mixdown_idx                     2   if matrix_mixdown_idx_present == 1
125                                // pseudo_surround_enable                 1   if matrix_mixdown_idx_present == 1
126                                // for (i = 0; i < num_front_channel_elements; i++) {
127                                //     front_element_is_cpe[i]            1
128                                //     front_element_tag_select[i]        4
129                                // }
130                                // for (i = 0; i < num_side_channel_elements; i++) {
131                                //     side_element_is_cpe[i]             1
132                                //     side_element_tag_select[i]         4
133                                // }
134                                // for (i = 0; i < num_back_channel_elements; i++) {
135                                //     back_element_is_cpe[i]             1
136                                //     back_element_tag_select[i]         4
137                                // }
138                                // for (i = 0; i < num_lfe_channel_elements; i++) {
139                                //     lfe_element_tag_select[i]          4
140                                // }
141                                // for (i = 0; i < num_assoc_data_elements; i++) {
142                                //     assoc_data_element_tag_select[i]   4
143                                // }
144                                // for (i = 0; i < num_valid_cc_elements; i++) {
145                                //     cc_element_is_ind_sw[i]            1
146                                //     valid_cc_element_tag_select[i]     4
147                                // }
148                                // byte_alignment()                       VAR
149                                // comment_field_bytes                    8
150                                // for (i = 0; i < comment_field_bytes; i++) {
151                                //     comment_field_data[i]              8
152                                // }
153
154                                if (!$info['aac']['header']['is_vbr']) {
155                                        $info['aac']['program_configs'][$i]['buffer_fullness']        = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 20));
156                                        $bitoffset += 20;
157                                }
158                                $info['aac']['program_configs'][$i]['element_instance_tag']       = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
159                                $bitoffset += 4;
160                                $info['aac']['program_configs'][$i]['object_type']                = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2));
161                                $bitoffset += 2;
162                                $info['aac']['program_configs'][$i]['sampling_frequency_index']   = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
163                                $bitoffset += 4;
164                                $info['aac']['program_configs'][$i]['num_front_channel_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
165                                $bitoffset += 4;
166                                $info['aac']['program_configs'][$i]['num_side_channel_elements']  = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
167                                $bitoffset += 4;
168                                $info['aac']['program_configs'][$i]['num_back_channel_elements']  = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
169                                $bitoffset += 4;
170                                $info['aac']['program_configs'][$i]['num_lfe_channel_elements']   = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2));
171                                $bitoffset += 2;
172                                $info['aac']['program_configs'][$i]['num_assoc_data_elements']    = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 3));
173                                $bitoffset += 3;
174                                $info['aac']['program_configs'][$i]['num_valid_cc_elements']      = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
175                                $bitoffset += 4;
176                                $info['aac']['program_configs'][$i]['mono_mixdown_present']       = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
177                                $bitoffset += 1;
178                                if ($info['aac']['program_configs'][$i]['mono_mixdown_present']) {
179                                        $info['aac']['program_configs'][$i]['mono_mixdown_element_number']    = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
180                                        $bitoffset += 4;
181                                }
182                                $info['aac']['program_configs'][$i]['stereo_mixdown_present']             = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
183                                $bitoffset += 1;
184                                if ($info['aac']['program_configs'][$i]['stereo_mixdown_present']) {
185                                        $info['aac']['program_configs'][$i]['stereo_mixdown_element_number']  = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
186                                        $bitoffset += 4;
187                                }
188                                $info['aac']['program_configs'][$i]['matrix_mixdown_idx_present']         = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
189                                $bitoffset += 1;
190                                if ($info['aac']['program_configs'][$i]['matrix_mixdown_idx_present']) {
191                                        $info['aac']['program_configs'][$i]['matrix_mixdown_idx']             = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2));
192                                        $bitoffset += 2;
193                                        $info['aac']['program_configs'][$i]['pseudo_surround_enable']         = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
194                                        $bitoffset += 1;
195                                }
196                                for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_front_channel_elements']; $j++) {
197                                        $info['aac']['program_configs'][$i]['front_element_is_cpe'][$j]     = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
198                                        $bitoffset += 1;
199                                        $info['aac']['program_configs'][$i]['front_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
200                                        $bitoffset += 4;
201                                }
202                                for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_side_channel_elements']; $j++) {
203                                        $info['aac']['program_configs'][$i]['side_element_is_cpe'][$j]     = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
204                                        $bitoffset += 1;
205                                        $info['aac']['program_configs'][$i]['side_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
206                                        $bitoffset += 4;
207                                }
208                                for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_back_channel_elements']; $j++) {
209                                        $info['aac']['program_configs'][$i]['back_element_is_cpe'][$j]     = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
210                                        $bitoffset += 1;
211                                        $info['aac']['program_configs'][$i]['back_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
212                                        $bitoffset += 4;
213                                }
214                                for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_lfe_channel_elements']; $j++) {
215                                        $info['aac']['program_configs'][$i]['lfe_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
216                                        $bitoffset += 4;
217                                }
218                                for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_assoc_data_elements']; $j++) {
219                                        $info['aac']['program_configs'][$i]['assoc_data_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
220                                        $bitoffset += 4;
221                                }
222                                for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_valid_cc_elements']; $j++) {
223                                        $info['aac']['program_configs'][$i]['cc_element_is_ind_sw'][$j]          = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
224                                        $bitoffset += 1;
225                                        $info['aac']['program_configs'][$i]['valid_cc_element_tag_select'][$j]   = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
226                                        $bitoffset += 4;
227                                }
228
229                                $bitoffset = ceil($bitoffset / 8) * 8;
230
231                                $info['aac']['program_configs'][$i]['comment_field_bytes'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 8));
232                                $bitoffset += 8;
233                                $info['aac']['program_configs'][$i]['comment_field']       = getid3_lib::Bin2String(substr($AACheaderBitstream, $bitoffset, 8 * $info['aac']['program_configs'][$i]['comment_field_bytes']));
234                                $bitoffset += 8 * $info['aac']['program_configs'][$i]['comment_field_bytes'];
235
236
237                                $info['aac']['header']['profile']                           = self::AACprofileLookup($info['aac']['program_configs'][$i]['object_type'], $info['aac']['header']['mpeg_version']);
238                                $info['aac']['program_configs'][$i]['sampling_frequency']   = self::AACsampleRateLookup($info['aac']['program_configs'][$i]['sampling_frequency_index']);
239                                $info['audio']['sample_rate']                               = $info['aac']['program_configs'][$i]['sampling_frequency'];
240                                $info['audio']['channels']                                  = self::AACchannelCountCalculate($info['aac']['program_configs'][$i]);
241                                if ($info['aac']['program_configs'][$i]['comment_field']) {
242                                        $info['aac']['comments'][]                          = $info['aac']['program_configs'][$i]['comment_field'];
243                                }
244                        }
245                        $info['playtime_seconds'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['audio']['bitrate'];
246
247                        $info['audio']['encoder_options'] = $info['aac']['header_type'].' '.$info['aac']['header']['profile'];
248
249
250
251                        return true;
252
253                } else {
254
255                        unset($info['fileformat']);
256                        unset($info['aac']);
257                        $this->error('AAC-ADIF synch not found at offset '.$info['avdataoffset'].' (expected "ADIF", found "'.substr($AACheader, 0, 4).'" instead)');
258                        return false;
259
260                }
261
262        }
263
264        /**
265         * @param int  $MaxFramesToScan
266         * @param bool $ReturnExtendedInfo
267         *
268         * @return bool
269         */
270        public function getAACADTSheaderFilepointer($MaxFramesToScan=1000000, $ReturnExtendedInfo=false) {
271                $info = &$this->getid3->info;
272
273                // based loosely on code from AACfile by Jurgen Faul  <jfaulØgmx.de>
274                // http://jfaul.de/atl  or  http://j-faul.virtualave.net/atl/atl.html
275
276
277                // http://faac.sourceforge.net/wiki/index.php?page=ADTS // dead link
278                // http://wiki.multimedia.cx/index.php?title=ADTS
279
280                // * ADTS Fixed Header: these don't change from frame to frame
281                // syncword                                       12    always: '111111111111'
282                // ID                                              1    0: MPEG-4, 1: MPEG-2
283                // MPEG layer                                      2    If you send AAC in MPEG-TS, set to 0
284                // protection_absent                               1    0: CRC present; 1: no CRC
285                // profile                                         2    0: AAC Main; 1: AAC LC (Low Complexity); 2: AAC SSR (Scalable Sample Rate); 3: AAC LTP (Long Term Prediction)
286                // sampling_frequency_index                        4    15 not allowed
287                // private_bit                                     1    usually 0
288                // channel_configuration                           3
289                // original/copy                                   1    0: original; 1: copy
290                // home                                            1    usually 0
291                // emphasis                                        2    only if ID == 0 (ie MPEG-4)  // not present in some documentation?
292
293                // * ADTS Variable Header: these can change from frame to frame
294                // copyright_identification_bit                    1
295                // copyright_identification_start                  1
296                // aac_frame_length                               13    length of the frame including header (in bytes)
297                // adts_buffer_fullness                           11    0x7FF indicates VBR
298                // no_raw_data_blocks_in_frame                     2
299
300                // * ADTS Error check
301                // crc_check                                      16    only if protection_absent == 0
302
303                $byteoffset  = $info['avdataoffset'];
304                $framenumber = 0;
305
306                // Init bit pattern array
307                static $decbin = array();
308
309                // Populate $bindec
310                for ($i = 0; $i < 256; $i++) {
311                        $decbin[chr($i)] = str_pad(decbin($i), 8, '0', STR_PAD_LEFT);
312                }
313
314                // used to calculate bitrate below
315                $BitrateCache = array();
316
317
318                while (true) {
319                        // breaks out when end-of-file encountered, or invalid data found,
320                        // or MaxFramesToScan frames have been scanned
321
322                        if (!getid3_lib::intValueSupported($byteoffset)) {
323                                $this->warning('Unable to parse AAC file beyond '.$this->ftell().' (PHP does not support file operations beyond '.round(PHP_INT_MAX / 1073741824).'GB)');
324                                return false;
325                        }
326                        $this->fseek($byteoffset);
327
328                        // First get substring
329                        $substring = $this->fread(9); // header is 7 bytes (or 9 if CRC is present)
330                        $substringlength = strlen($substring);
331                        if ($substringlength != 9) {
332                                $this->error('Failed to read 7 bytes at offset '.($this->ftell() - $substringlength).' (only read '.$substringlength.' bytes)');
333                                return false;
334                        }
335                        // this would be easier with 64-bit math, but split it up to allow for 32-bit:
336                        $header1 = getid3_lib::BigEndian2Int(substr($substring, 0, 2));
337                        $header2 = getid3_lib::BigEndian2Int(substr($substring, 2, 4));
338                        $header3 = getid3_lib::BigEndian2Int(substr($substring, 6, 1));
339
340                        $info['aac']['header']['raw']['syncword']          = ($header1 & 0xFFF0) >> 4;
341                        if ($info['aac']['header']['raw']['syncword'] != 0x0FFF) {
342                                $this->error('Synch pattern (0x0FFF) not found at offset '.($this->ftell() - $substringlength).' (found 0x0'.strtoupper(dechex($info['aac']['header']['raw']['syncword'])).' instead)');
343                                //if ($info['fileformat'] == 'aac') {
344                                //      return true;
345                                //}
346                                unset($info['aac']);
347                                return false;
348                        }
349
350                        // Gather info for first frame only - this takes time to do 1000 times!
351                        if ($framenumber == 0) {
352                                $info['aac']['header_type']                      = 'ADTS';
353                                $info['fileformat']                              = 'aac';
354                                $info['audio']['dataformat']                     = 'aac';
355
356                                $info['aac']['header']['raw']['mpeg_version']      = ($header1 & 0x0008) >> 3;
357                                $info['aac']['header']['raw']['mpeg_layer']        = ($header1 & 0x0006) >> 1;
358                                $info['aac']['header']['raw']['protection_absent'] = ($header1 & 0x0001) >> 0;
359
360                                $info['aac']['header']['raw']['profile_code']      = ($header2 & 0xC0000000) >> 30;
361                                $info['aac']['header']['raw']['sample_rate_code']  = ($header2 & 0x3C000000) >> 26;
362                                $info['aac']['header']['raw']['private_stream']    = ($header2 & 0x02000000) >> 25;
363                                $info['aac']['header']['raw']['channels_code']     = ($header2 & 0x01C00000) >> 22;
364                                $info['aac']['header']['raw']['original']          = ($header2 & 0x00200000) >> 21;
365                                $info['aac']['header']['raw']['home']              = ($header2 & 0x00100000) >> 20;
366                                $info['aac']['header']['raw']['copyright_stream']  = ($header2 & 0x00080000) >> 19;
367                                $info['aac']['header']['raw']['copyright_start']   = ($header2 & 0x00040000) >> 18;
368                                $info['aac']['header']['raw']['frame_length']      = ($header2 & 0x0003FFE0) >>  5;
369
370                                $info['aac']['header']['mpeg_version']     = ($info['aac']['header']['raw']['mpeg_version']      ? 2    : 4);
371                                $info['aac']['header']['crc_present']      = ($info['aac']['header']['raw']['protection_absent'] ? false: true);
372                                $info['aac']['header']['profile']          = self::AACprofileLookup($info['aac']['header']['raw']['profile_code'], $info['aac']['header']['mpeg_version']);
373                                $info['aac']['header']['sample_frequency'] = self::AACsampleRateLookup($info['aac']['header']['raw']['sample_rate_code']);
374                                $info['aac']['header']['private']          = (bool) $info['aac']['header']['raw']['private_stream'];
375                                $info['aac']['header']['original']         = (bool) $info['aac']['header']['raw']['original'];
376                                $info['aac']['header']['home']             = (bool) $info['aac']['header']['raw']['home'];
377                                $info['aac']['header']['channels']         = (($info['aac']['header']['raw']['channels_code'] == 7) ? 8 : $info['aac']['header']['raw']['channels_code']);
378                                if ($ReturnExtendedInfo) {
379                                        $info['aac'][$framenumber]['copyright_id_bit']   = (bool) $info['aac']['header']['raw']['copyright_stream'];
380                                        $info['aac'][$framenumber]['copyright_id_start'] = (bool) $info['aac']['header']['raw']['copyright_start'];
381                                }
382
383                                if ($info['aac']['header']['raw']['mpeg_layer'] != 0) {
384                                        $this->warning('Layer error - expected "0", found "'.$info['aac']['header']['raw']['mpeg_layer'].'" instead');
385                                }
386                                if ($info['aac']['header']['sample_frequency'] == 0) {
387                                        $this->error('Corrupt AAC file: sample_frequency == zero');
388                                        return false;
389                                }
390
391                                $info['audio']['sample_rate'] = $info['aac']['header']['sample_frequency'];
392                                $info['audio']['channels']    = $info['aac']['header']['channels'];
393                        }
394
395                        $FrameLength = ($header2 & 0x0003FFE0) >>  5;
396
397                        if (!isset($BitrateCache[$FrameLength])) {
398                                $BitrateCache[$FrameLength] = ($info['aac']['header']['sample_frequency'] / 1024) * $FrameLength * 8;
399                        }
400                        getid3_lib::safe_inc($info['aac']['bitrate_distribution'][$BitrateCache[$FrameLength]], 1);
401
402                        $info['aac'][$framenumber]['aac_frame_length']     = $FrameLength;
403
404                        $info['aac'][$framenumber]['adts_buffer_fullness'] = (($header2 & 0x0000001F) << 6) & (($header3 & 0xFC) >> 2);
405                        if ($info['aac'][$framenumber]['adts_buffer_fullness'] == 0x07FF) {
406                                $info['audio']['bitrate_mode'] = 'vbr';
407                        } else {
408                                $info['audio']['bitrate_mode'] = 'cbr';
409                        }
410                        $info['aac'][$framenumber]['num_raw_data_blocks']  = (($header3 & 0x03) >> 0);
411
412                        if ($info['aac']['header']['crc_present']) {
413                                //$info['aac'][$framenumber]['crc'] = getid3_lib::BigEndian2Int(substr($substring, 7, 2);
414                        }
415
416                        if (!$ReturnExtendedInfo) {
417                                unset($info['aac'][$framenumber]);
418                        }
419
420                        /*
421                        $rounded_precision = 5000;
422                        $info['aac']['bitrate_distribution_rounded'] = array();
423                        foreach ($info['aac']['bitrate_distribution'] as $bitrate => $count) {
424                                $rounded_bitrate = round($bitrate / $rounded_precision) * $rounded_precision;
425                                getid3_lib::safe_inc($info['aac']['bitrate_distribution_rounded'][$rounded_bitrate], $count);
426                        }
427                        ksort($info['aac']['bitrate_distribution_rounded']);
428                        */
429
430                        $byteoffset += $FrameLength;
431                        if ((++$framenumber < $MaxFramesToScan) && (($byteoffset + 10) < $info['avdataend'])) {
432
433                                // keep scanning
434
435                        } else {
436
437                                $info['aac']['frames']    = $framenumber;
438                                $info['playtime_seconds'] = ($info['avdataend'] / $byteoffset) * (($framenumber * 1024) / $info['aac']['header']['sample_frequency']);  // (1 / % of file scanned) * (samples / (samples/sec)) = seconds
439                                if ($info['playtime_seconds'] == 0) {
440                                        $this->error('Corrupt AAC file: playtime_seconds == zero');
441                                        return false;
442                                }
443                                $info['audio']['bitrate']    = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
444                                ksort($info['aac']['bitrate_distribution']);
445
446                                $info['audio']['encoder_options'] = $info['aac']['header_type'].' '.$info['aac']['header']['profile'];
447
448                                return true;
449
450                        }
451                }
452                // should never get here.
453        }
454
455        /**
456         * @param int $samplerateid
457         *
458         * @return int|string
459         */
460        public static function AACsampleRateLookup($samplerateid) {
461                static $AACsampleRateLookup = array();
462                if (empty($AACsampleRateLookup)) {
463                        $AACsampleRateLookup[0]  = 96000;
464                        $AACsampleRateLookup[1]  = 88200;
465                        $AACsampleRateLookup[2]  = 64000;
466                        $AACsampleRateLookup[3]  = 48000;
467                        $AACsampleRateLookup[4]  = 44100;
468                        $AACsampleRateLookup[5]  = 32000;
469                        $AACsampleRateLookup[6]  = 24000;
470                        $AACsampleRateLookup[7]  = 22050;
471                        $AACsampleRateLookup[8]  = 16000;
472                        $AACsampleRateLookup[9]  = 12000;
473                        $AACsampleRateLookup[10] = 11025;
474                        $AACsampleRateLookup[11] = 8000;
475                        $AACsampleRateLookup[12] = 0;
476                        $AACsampleRateLookup[13] = 0;
477                        $AACsampleRateLookup[14] = 0;
478                        $AACsampleRateLookup[15] = 0;
479                }
480                return (isset($AACsampleRateLookup[$samplerateid]) ? $AACsampleRateLookup[$samplerateid] : 'invalid');
481        }
482
483        /**
484         * @param int $profileid
485         * @param int $mpegversion
486         *
487         * @return string
488         */
489        public static function AACprofileLookup($profileid, $mpegversion) {
490                static $AACprofileLookup = array();
491                if (empty($AACprofileLookup)) {
492                        $AACprofileLookup[2][0]  = 'Main profile';
493                        $AACprofileLookup[2][1]  = 'Low Complexity profile (LC)';
494                        $AACprofileLookup[2][2]  = 'Scalable Sample Rate profile (SSR)';
495                        $AACprofileLookup[2][3]  = '(reserved)';
496                        $AACprofileLookup[4][0]  = 'AAC_MAIN';
497                        $AACprofileLookup[4][1]  = 'AAC_LC';
498                        $AACprofileLookup[4][2]  = 'AAC_SSR';
499                        $AACprofileLookup[4][3]  = 'AAC_LTP';
500                }
501                return (isset($AACprofileLookup[$mpegversion][$profileid]) ? $AACprofileLookup[$mpegversion][$profileid] : 'invalid');
502        }
503
504        /**
505         * @param array $program_configs
506         *
507         * @return int
508         */
509        public static function AACchannelCountCalculate($program_configs) {
510                $channels = 0;
511                for ($i = 0; $i < $program_configs['num_front_channel_elements']; $i++) {
512                        $channels++;
513                        if ($program_configs['front_element_is_cpe'][$i]) {
514                                // each front element is channel pair (CPE = Channel Pair Element)
515                                $channels++;
516                        }
517                }
518                for ($i = 0; $i < $program_configs['num_side_channel_elements']; $i++) {
519                        $channels++;
520                        if ($program_configs['side_element_is_cpe'][$i]) {
521                                // each side element is channel pair (CPE = Channel Pair Element)
522                                $channels++;
523                        }
524                }
525                for ($i = 0; $i < $program_configs['num_back_channel_elements']; $i++) {
526                        $channels++;
527                        if ($program_configs['back_element_is_cpe'][$i]) {
528                                // each back element is channel pair (CPE = Channel Pair Element)
529                                $channels++;
530                        }
531                }
532                for ($i = 0; $i < $program_configs['num_lfe_channel_elements']; $i++) {
533                        $channels++;
534                }
535                return $channels;
536        }
537
538}
Note: See TracBrowser for help on using the repository browser.