source: extensions/charlies_content/getid3/getid3/module.audio.aac_adif.php @ 3318

Last change on this file since 3318 was 3318, checked in by vdigital, 15 years ago

+ Add Charlies' content to depository

  • Property svn:keywords set to Author Date Id Revision
File size: 15.3 KB
Line 
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.aac_adif.php                                            |
18// | Module for analyzing AAC files with ADIF header.                     |
19// | dependencies: NONE                                                   |
20// +----------------------------------------------------------------------+
21//
22// $Id: module.audio.aac_adif.php 3318 2009-05-20 21:54:10Z vdigital $
23
24       
25       
26class getid3_aac_adif extends getid3_handler
27{
28
29    public function Analyze() {
30
31        $getid3 = $this->getid3;   
32
33        // http://faac.sourceforge.net/wiki/index.php?page=ADIF
34        // http://libmpeg.org/mpeg4/doc/w2203tfs.pdf
35        // adif_header() {
36        //     adif_id                                32
37        //     copyright_id_present                    1
38        //     if( copyright_id_present )
39        //         copyright_id                       72
40        //     original_copy                           1
41        //     home                                    1
42        //     bitstream_type                          1
43        //     bitrate                                23
44        //     num_program_config_elements             4
45        //     for (i = 0; i < num_program_config_elements + 1; i++ ) {
46        //         if( bitstream_type == '0' )
47        //             adif_buffer_fullness           20
48        //         program_config_element()
49        //     }
50        // }
51       
52
53        $getid3->info['fileformat']          = 'aac';
54        $getid3->info['audio']['dataformat'] = 'aac';
55        $getid3->info['audio']['lossless']   = false;
56       
57        $getid3->info['aac']['header'] = array () ;
58        $info_aac        = &$getid3->info['aac'];
59        $info_aac_header = & $info_aac['header'];
60
61        fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET);
62        $aac_header_bitstream = getid3_lib::BigEndian2Bin(fread($getid3->fp, 1024));
63       
64        $info_aac['header_type']            = 'ADIF';
65        $info_aac_header['mpeg_version'] = 4;
66        $bit_offset = 32;
67
68        $info_aac_header['copyright'] = $aac_header_bitstream{$bit_offset++} == '1';
69        if ($info_aac_header['copyright']) {
70            $info_aac_header['copyright_id'] = getid3_aac_adif::Bin2String(substr($aac_header_bitstream, $bit_offset, 72));
71            $bit_offset += 72;
72        }
73       
74        $info_aac_header['original_copy'] = $aac_header_bitstream{$bit_offset++} == '1';
75        $info_aac_header['home']          = $aac_header_bitstream{$bit_offset++} == '1';
76        $info_aac_header['is_vbr']        = $aac_header_bitstream{$bit_offset++} == '1';
77
78        if ($info_aac_header['is_vbr']) {
79            $getid3->info['audio']['bitrate_mode'] = 'vbr';
80            $info_aac_header['bitrate_max']     = bindec(substr($aac_header_bitstream, $bit_offset, 23));
81            $bit_offset += 23;
82        } 
83        else {
84            $getid3->info['audio']['bitrate_mode'] = 'cbr';
85            $info_aac_header['bitrate']         = bindec(substr($aac_header_bitstream, $bit_offset, 23));
86            $bit_offset += 23;
87            $getid3->info['audio']['bitrate']      = $info_aac_header['bitrate'];
88        }
89       
90        $info_aac_header['num_program_configs'] = 1 + bindec(substr($aac_header_bitstream, $bit_offset, 4));
91        $bit_offset += 4;
92
93        for ($i = 0; $i < $info_aac_header['num_program_configs']; $i++) {
94
95            // http://www.audiocoding.com/wiki/index.php?page=program_config_element
96
97            // buffer_fullness                       20
98
99            // element_instance_tag                   4
100            // object_type                            2
101            // sampling_frequency_index               4
102            // num_front_channel_elements             4
103            // num_side_channel_elements              4
104            // num_back_channel_elements              4
105            // num_lfe_channel_elements               2
106            // num_assoc_data_elements                3
107            // num_valid_cc_elements                  4
108            // mono_mixdown_present                   1
109            // mono_mixdown_element_number            4   if mono_mixdown_present == 1
110            // stereo_mixdown_present                 1
111            // stereo_mixdown_element_number          4   if stereo_mixdown_present == 1
112            // matrix_mixdown_idx_present             1
113            // matrix_mixdown_idx                     2   if matrix_mixdown_idx_present == 1
114            // pseudo_surround_enable                 1   if matrix_mixdown_idx_present == 1
115            // for (i = 0; i < num_front_channel_elements; i++) {
116            //     front_element_is_cpe[i]            1
117            //     front_element_tag_select[i]        4
118            // }
119            // for (i = 0; i < num_side_channel_elements; i++) {
120            //     side_element_is_cpe[i]             1
121            //     side_element_tag_select[i]         4
122            // }
123            // for (i = 0; i < num_back_channel_elements; i++) {
124            //     back_element_is_cpe[i]             1
125            //     back_element_tag_select[i]         4
126            // }
127            // for (i = 0; i < num_lfe_channel_elements; i++) {
128            //     lfe_element_tag_select[i]          4
129            // }
130            // for (i = 0; i < num_assoc_data_elements; i++) {
131            //     assoc_data_element_tag_select[i]   4
132            // }
133            // for (i = 0; i < num_valid_cc_elements; i++) {
134            //     cc_element_is_ind_sw[i]            1
135            //     valid_cc_element_tag_select[i]     4
136            // }
137            // byte_alignment()                       VAR
138            // comment_field_bytes                    8
139            // for (i = 0; i < comment_field_bytes; i++) {
140            //     comment_field_data[i]              8
141            // }
142           
143            $info_aac['program_configs'][$i] = array ();
144            $info_aac_program_configs_i = &$info_aac['program_configs'][$i];
145
146            if (!$info_aac_header['is_vbr']) {
147                $info_aac_program_configs_i['buffer_fullness']        = bindec(substr($aac_header_bitstream, $bit_offset, 20));
148                $bit_offset += 20;
149            }
150               
151            $info_aac_program_configs_i['element_instance_tag']       = bindec(substr($aac_header_bitstream, $bit_offset,      4));
152            $info_aac_program_configs_i['object_type']                = bindec(substr($aac_header_bitstream, $bit_offset +  4, 2));
153            $info_aac_program_configs_i['sampling_frequency_index']   = bindec(substr($aac_header_bitstream, $bit_offset +  6, 4));
154            $info_aac_program_configs_i['num_front_channel_elements'] = bindec(substr($aac_header_bitstream, $bit_offset + 10, 4));
155            $info_aac_program_configs_i['num_side_channel_elements']  = bindec(substr($aac_header_bitstream, $bit_offset + 14, 4));
156            $info_aac_program_configs_i['num_back_channel_elements']  = bindec(substr($aac_header_bitstream, $bit_offset + 18, 4));
157            $info_aac_program_configs_i['num_lfe_channel_elements']   = bindec(substr($aac_header_bitstream, $bit_offset + 22, 2));
158            $info_aac_program_configs_i['num_assoc_data_elements']    = bindec(substr($aac_header_bitstream, $bit_offset + 24, 3));
159            $info_aac_program_configs_i['num_valid_cc_elements']      = bindec(substr($aac_header_bitstream, $bit_offset + 27, 4));
160            $bit_offset += 31;
161           
162            $info_aac_program_configs_i['mono_mixdown_present'] = $aac_header_bitstream{$bit_offset++} == 1;
163            if ($info_aac_program_configs_i['mono_mixdown_present']) {
164                $info_aac_program_configs_i['mono_mixdown_element_number'] = bindec(substr($aac_header_bitstream, $bit_offset, 4));
165                $bit_offset += 4;
166            }
167           
168            $info_aac_program_configs_i['stereo_mixdown_present'] = $aac_header_bitstream{$bit_offset++} == 1;
169            if ($info_aac_program_configs_i['stereo_mixdown_present']) {
170                $info_aac_program_configs_i['stereo_mixdown_element_number'] = bindec(substr($aac_header_bitstream, $bit_offset, 4));
171                $bit_offset += 4;
172            }
173           
174            $info_aac_program_configs_i['matrix_mixdown_idx_present'] = $aac_header_bitstream{$bit_offset++} == 1;
175            if ($info_aac_program_configs_i['matrix_mixdown_idx_present']) {
176                $info_aac_program_configs_i['matrix_mixdown_idx']     = bindec(substr($aac_header_bitstream, $bit_offset, 2));
177                $bit_offset += 2;
178                $info_aac_program_configs_i['pseudo_surround_enable'] = $aac_header_bitstream{$bit_offset++} == 1;
179            }
180           
181            for ($j = 0; $j < $info_aac_program_configs_i['num_front_channel_elements']; $j++) {
182                $info_aac_program_configs_i['front_element_is_cpe'][$j]     = $aac_header_bitstream{$bit_offset++} == 1;
183                $info_aac_program_configs_i['front_element_tag_select'][$j] = bindec(substr($aac_header_bitstream, $bit_offset, 4));
184                $bit_offset += 4;
185            }
186            for ($j = 0; $j < $info_aac_program_configs_i['num_side_channel_elements']; $j++) {
187                $info_aac_program_configs_i['side_element_is_cpe'][$j]     = $aac_header_bitstream{$bit_offset++} == 1;
188                $info_aac_program_configs_i['side_element_tag_select'][$j] = bindec(substr($aac_header_bitstream, $bit_offset, 4));
189                $bit_offset += 4;
190            }
191            for ($j = 0; $j < $info_aac_program_configs_i['num_back_channel_elements']; $j++) {
192                $info_aac_program_configs_i['back_element_is_cpe'][$j]     = $aac_header_bitstream{$bit_offset++} == 1;
193                $info_aac_program_configs_i['back_element_tag_select'][$j] = bindec(substr($aac_header_bitstream, $bit_offset, 4));
194                $bit_offset += 4;
195            }
196            for ($j = 0; $j < $info_aac_program_configs_i['num_lfe_channel_elements']; $j++) {
197                $info_aac_program_configs_i['lfe_element_tag_select'][$j] = bindec(substr($aac_header_bitstream, $bit_offset, 4));
198                $bit_offset += 4;
199            }
200            for ($j = 0; $j < $info_aac_program_configs_i['num_assoc_data_elements']; $j++) {
201                $info_aac_program_configs_i['assoc_data_element_tag_select'][$j] = bindec(substr($aac_header_bitstream, $bit_offset, 4));
202                $bit_offset += 4;
203            }
204            for ($j = 0; $j < $info_aac_program_configs_i['num_valid_cc_elements']; $j++) {
205                $info_aac_program_configs_i['cc_element_is_ind_sw'][$j]          = $aac_header_bitstream{$bit_offset++} == 1;
206                $info_aac_program_configs_i['valid_cc_element_tag_select'][$j]   = bindec(substr($aac_header_bitstream, $bit_offset, 4));
207                $bit_offset += 4;
208            }
209
210            $bit_offset = ceil($bit_offset / 8) * 8;
211
212            $info_aac_program_configs_i['comment_field_bytes'] = bindec(substr($aac_header_bitstream, $bit_offset, 8));
213            $bit_offset += 8;
214           
215            $info_aac_program_configs_i['comment_field'] = getid3_aac_adif::Bin2String(substr($aac_header_bitstream, $bit_offset, 8 * $info_aac_program_configs_i['comment_field_bytes']));
216            $bit_offset += 8 * $info_aac_program_configs_i['comment_field_bytes'];
217
218            $info_aac_header['profile_text']                  = getid3_aac_adif::AACprofileLookup($info_aac_program_configs_i['object_type'], $info_aac_header['mpeg_version']);
219            $info_aac_program_configs_i['sampling_frequency'] = $getid3->info['audio']['sample_rate'] = getid3_aac_adif::AACsampleRateLookup($info_aac_program_configs_i['sampling_frequency_index']);
220            $getid3->info['audio']['channels']                = getid3_aac_adif::AACchannelCountCalculate($info_aac_program_configs_i);
221           
222            if ($info_aac_program_configs_i['comment_field']) {
223                $info_aac['comments'][] = $info_aac_program_configs_i['comment_field'];
224            }
225        }
226       
227        $getid3->info['playtime_seconds'] = (($getid3->info['avdataend'] - $getid3->info['avdataoffset']) * 8) / $getid3->info['audio']['bitrate'];
228        $getid3->info['audio']['encoder_options'] = $info_aac['header_type'].' '.$info_aac_header['profile_text'];
229
230        return true;
231    }
232
233
234
235    public static function Bin2String($bin_string) {
236        // return 'hi' for input of '0110100001101001'
237        $string = '';
238        $bin_string_reversed = strrev($bin_string);
239        for ($i = 0; $i < strlen($bin_string_reversed); $i += 8) {
240            $string = chr(bindec(strrev(substr($bin_string_reversed, $i, 8)))).$string;
241        }
242        return $string;
243    }
244   
245   
246   
247    public static function AACsampleRateLookup($samplerate_id) {
248       
249        static $lookup = array (
250            0  => 96000,
251            1  => 88200,
252            2  => 64000,
253            3  => 48000,
254            4  => 44100,
255            5  => 32000,
256            6  => 24000,
257            7  => 22050,
258            8  => 16000,
259            9  => 12000,
260            10 => 11025,
261            11 => 8000,
262            12 => 0,
263            13 => 0,
264            14 => 0,
265            15 => 0
266        );
267        return (isset($lookup[$samplerate_id]) ? $lookup[$samplerate_id] : 'invalid');
268    }
269
270
271
272    public static function AACprofileLookup($profile_id, $mpeg_version) {
273       
274        static $lookup = array (
275            2 => array ( 
276                0 => 'Main profile',
277                1 => 'Low Complexity profile (LC)',
278                2 => 'Scalable Sample Rate profile (SSR)',
279                3 => '(reserved)'
280            ),           
281            4 => array (
282                0 => 'AAC_MAIN',
283                1 => 'AAC_LC',
284                2 => 'AAC_SSR',
285                3 => 'AAC_LTP'
286            )
287        );
288        return (isset($lookup[$mpeg_version][$profile_id]) ? $lookup[$mpeg_version][$profile_id] : 'invalid');
289    }
290
291
292
293    public static function AACchannelCountCalculate($program_configs) {
294       
295        $channels = 0;
296       
297        foreach (array ('front', 'side', 'back') as $placement) {
298            for ($i = 0; $i < $program_configs['num_'.$placement.'_channel_elements']; $i++) {
299               
300                // Each element is channel pair (CPE = Channel Pair Element)
301                $channels += 1 + ($program_configs[$placement.'_element_is_cpe'][$i] ? 1 : 0);
302            }
303        }
304       
305        return $channels + $program_configs['num_lfe_channel_elements'];
306    }
307
308}
309
310
311?>
Note: See TracBrowser for help on using the repository browser.