source: extensions/charlies_content/getid3/getid3/module.audio-video.asf.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:eol-style set to LF
  • Property svn:keywords set to Author Date Id Revision
File size: 127.4 KB
RevLine 
[3318]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.php                                               |
18// | Module for analyzing Microsoft ASF, WMA and WMV files.               |
19// | dependencies: module.audio-video.riff.php                            |
20// +----------------------------------------------------------------------+
21//
22// $Id: module.audio-video.asf.php 3318 2009-05-20 21:54:10Z vdigital $
23
24       
25       
26class getid3_asf extends getid3_handler
27{
28
29    const Extended_Stream_Properties_Object   = '14E6A5CB-C672-4332-8399-A96952065B5A';
30    const Padding_Object                      = '1806D474-CADF-4509-A4BA-9AABCB96AAE8';
31    const Payload_Ext_Syst_Pixel_Aspect_Ratio = '1B1EE554-F9EA-4BC8-821A-376B74E4C4B8';
32    const Script_Command_Object               = '1EFB1A30-0B62-11D0-A39B-00A0C90348F6';
33    const No_Error_Correction                 = '20FB5700-5B55-11CF-A8FD-00805F5C442B';
34    const Content_Branding_Object             = '2211B3FA-BD23-11D2-B4B7-00A0C955FC6E';
35    const Content_Encryption_Object           = '2211B3FB-BD23-11D2-B4B7-00A0C955FC6E';
36    const Digital_Signature_Object            = '2211B3FC-BD23-11D2-B4B7-00A0C955FC6E';
37    const Extended_Content_Encryption_Object  = '298AE614-2622-4C17-B935-DAE07EE9289C';
38    const Simple_Index_Object                 = '33000890-E5B1-11CF-89F4-00A0C90349CB';
39    const Degradable_JPEG_Media               = '35907DE0-E415-11CF-A917-00805F5C442B';
40    const Payload_Extension_System_Timecode   = '399595EC-8667-4E2D-8FDB-98814CE76C1E';
41    const Binary_Media                        = '3AFB65E2-47EF-40F2-AC2C-70A90D71D343';
42    const Timecode_Index_Object               = '3CB73FD0-0C4A-4803-953D-EDF7B6228F0C';
43    const Metadata_Library_Object             = '44231C94-9498-49D1-A141-1D134E457054';
44    const Reserved_3                          = '4B1ACBE3-100B-11D0-A39B-00A0C90348F6';
45    const Reserved_4                          = '4CFEDB20-75F6-11CF-9C0F-00A0C90349CB';
46    const Command_Media                       = '59DACFC0-59E6-11D0-A3AC-00A0C90348F6';
47    const Header_Extension_Object             = '5FBF03B5-A92E-11CF-8EE3-00C00C205365';
48    const Media_Object_Index_Parameters_Obj   = '6B203BAD-3F11-4E84-ACA8-D7613DE2CFA7';
49    const Header_Object                       = '75B22630-668E-11CF-A6D9-00AA0062CE6C';
50    const Content_Description_Object          = '75B22633-668E-11CF-A6D9-00AA0062CE6C';
51    const Error_Correction_Object             = '75B22635-668E-11CF-A6D9-00AA0062CE6C';
52    const Data_Object                         = '75B22636-668E-11CF-A6D9-00AA0062CE6C';
53    const Web_Stream_Media_Subtype            = '776257D4-C627-41CB-8F81-7AC7FF1C40CC';
54    const Stream_Bitrate_Properties_Object    = '7BF875CE-468D-11D1-8D82-006097C9A2B2';
55    const Language_List_Object                = '7C4346A9-EFE0-4BFC-B229-393EDE415C85';
56    const Codec_List_Object                   = '86D15240-311D-11D0-A3A4-00A0C90348F6';
57    const Reserved_2                          = '86D15241-311D-11D0-A3A4-00A0C90348F6';
58    const File_Properties_Object              = '8CABDCA1-A947-11CF-8EE4-00C00C205365';
59    const File_Transfer_Media                 = '91BD222C-F21C-497A-8B6D-5AA86BFC0185';
60    const Old_RTP_Extension_Data              = '96800C63-4C94-11D1-837B-0080C7A37F95';
61    const Advanced_Mutual_Exclusion_Object    = 'A08649CF-4775-4670-8A16-6E35357566CD';
62    const Bandwidth_Sharing_Object            = 'A69609E6-517B-11D2-B6AF-00C04FD908E9';
63    const Reserved_1                          = 'ABD3D211-A9BA-11CF-8EE6-00C00C205365';
64    const Bandwidth_Sharing_Exclusive         = 'AF6060AA-5197-11D2-B6AF-00C04FD908E9';
65    const Bandwidth_Sharing_Partial           = 'AF6060AB-5197-11D2-B6AF-00C04FD908E9';
66    const JFIF_Media                          = 'B61BE100-5B4E-11CF-A8FD-00805F5C442B';
67    const Stream_Properties_Object            = 'B7DC0791-A9B7-11CF-8EE6-00C00C205365';
68    const Video_Media                         = 'BC19EFC0-5B4D-11CF-A8FD-00805F5C442B';
69    const Audio_Spread                        = 'BFC3CD50-618F-11CF-8BB2-00AA00B4E220';
70    const Metadata_Object                     = 'C5F8CBEA-5BAF-4877-8467-AA8C44FA4CCA';
71    const Payload_Ext_Syst_Sample_Duration    = 'C6BD9450-867F-4907-83A3-C77921B733AD';
72    const Group_Mutual_Exclusion_Object       = 'D1465A40-5A79-4338-B71B-E36B8FD6C249';
73    const Extended_Content_Description_Object = 'D2D0A440-E307-11D2-97F0-00A0C95EA850';
74    const Stream_Prioritization_Object        = 'D4FED15B-88D3-454F-81F0-ED5C45999E24';
75    const Payload_Ext_System_Content_Type     = 'D590DC20-07BC-436C-9CF7-F3BBFBF1A4DC';
76    const Old_File_Properties_Object          = 'D6E229D0-35DA-11D1-9034-00A0C90349BE';
77    const Old_ASF_Header_Object               = 'D6E229D1-35DA-11D1-9034-00A0C90349BE';
78    const Old_ASF_Data_Object                 = 'D6E229D2-35DA-11D1-9034-00A0C90349BE';
79    const Index_Object                        = 'D6E229D3-35DA-11D1-9034-00A0C90349BE';
80    const Old_Stream_Properties_Object        = 'D6E229D4-35DA-11D1-9034-00A0C90349BE';
81    const Old_Content_Description_Object      = 'D6E229D5-35DA-11D1-9034-00A0C90349BE';
82    const Old_Script_Command_Object           = 'D6E229D6-35DA-11D1-9034-00A0C90349BE';
83    const Old_Marker_Object                   = 'D6E229D7-35DA-11D1-9034-00A0C90349BE';
84    const Old_Component_Download_Object       = 'D6E229D8-35DA-11D1-9034-00A0C90349BE';
85    const Old_Stream_Group_Object             = 'D6E229D9-35DA-11D1-9034-00A0C90349BE';
86    const Old_Scalable_Object                 = 'D6E229DA-35DA-11D1-9034-00A0C90349BE';
87    const Old_Prioritization_Object           = 'D6E229DB-35DA-11D1-9034-00A0C90349BE';
88    const Bitrate_Mutual_Exclusion_Object     = 'D6E229DC-35DA-11D1-9034-00A0C90349BE';
89    const Old_Inter_Media_Dependency_Object   = 'D6E229DD-35DA-11D1-9034-00A0C90349BE';
90    const Old_Rating_Object                   = 'D6E229DE-35DA-11D1-9034-00A0C90349BE';
91    const Index_Parameters_Object             = 'D6E229DF-35DA-11D1-9034-00A0C90349BE';
92    const Old_Color_Table_Object              = 'D6E229E0-35DA-11D1-9034-00A0C90349BE';
93    const Old_Language_List_Object            = 'D6E229E1-35DA-11D1-9034-00A0C90349BE';
94    const Old_Audio_Media                     = 'D6E229E2-35DA-11D1-9034-00A0C90349BE';
95    const Old_Video_Media                     = 'D6E229E3-35DA-11D1-9034-00A0C90349BE';
96    const Old_Image_Media                     = 'D6E229E4-35DA-11D1-9034-00A0C90349BE';
97    const Old_Timecode_Media                  = 'D6E229E5-35DA-11D1-9034-00A0C90349BE';
98    const Old_Text_Media                      = 'D6E229E6-35DA-11D1-9034-00A0C90349BE';
99    const Old_MIDI_Media                      = 'D6E229E7-35DA-11D1-9034-00A0C90349BE';
100    const Old_Command_Media                   = 'D6E229E8-35DA-11D1-9034-00A0C90349BE';
101    const Old_No_Error_Concealment            = 'D6E229EA-35DA-11D1-9034-00A0C90349BE';
102    const Old_Scrambled_Audio                 = 'D6E229EB-35DA-11D1-9034-00A0C90349BE';
103    const Old_No_Color_Table                  = 'D6E229EC-35DA-11D1-9034-00A0C90349BE';
104    const Old_SMPTE_Time                      = 'D6E229ED-35DA-11D1-9034-00A0C90349BE';
105    const Old_ASCII_Text                      = 'D6E229EE-35DA-11D1-9034-00A0C90349BE';
106    const Old_Unicode_Text                    = 'D6E229EF-35DA-11D1-9034-00A0C90349BE';
107    const Old_HTML_Text                       = 'D6E229F0-35DA-11D1-9034-00A0C90349BE';
108    const Old_URL_Command                     = 'D6E229F1-35DA-11D1-9034-00A0C90349BE';
109    const Old_Filename_Command                = 'D6E229F2-35DA-11D1-9034-00A0C90349BE';
110    const Old_ACM_Codec                       = 'D6E229F3-35DA-11D1-9034-00A0C90349BE';
111    const Old_VCM_Codec                       = 'D6E229F4-35DA-11D1-9034-00A0C90349BE';
112    const Old_QuickTime_Codec                 = 'D6E229F5-35DA-11D1-9034-00A0C90349BE';
113    const Old_DirectShow_Transform_Filter     = 'D6E229F6-35DA-11D1-9034-00A0C90349BE';
114    const Old_DirectShow_Rendering_Filter     = 'D6E229F7-35DA-11D1-9034-00A0C90349BE';
115    const Old_No_Enhancement                  = 'D6E229F8-35DA-11D1-9034-00A0C90349BE';
116    const Old_Unknown_Enhancement_Type        = 'D6E229F9-35DA-11D1-9034-00A0C90349BE';
117    const Old_Temporal_Enhancement            = 'D6E229FA-35DA-11D1-9034-00A0C90349BE';
118    const Old_Spatial_Enhancement             = 'D6E229FB-35DA-11D1-9034-00A0C90349BE';
119    const Old_Quality_Enhancement             = 'D6E229FC-35DA-11D1-9034-00A0C90349BE';
120    const Old_Number_of_Channels_Enhancement  = 'D6E229FD-35DA-11D1-9034-00A0C90349BE';
121    const Old_Frequency_Response_Enhancement  = 'D6E229FE-35DA-11D1-9034-00A0C90349BE';
122    const Old_Media_Object                    = 'D6E229FF-35DA-11D1-9034-00A0C90349BE';
123    const Mutex_Language                      = 'D6E22A00-35DA-11D1-9034-00A0C90349BE';
124    const Mutex_Bitrate                       = 'D6E22A01-35DA-11D1-9034-00A0C90349BE';
125    const Mutex_Unknown                       = 'D6E22A02-35DA-11D1-9034-00A0C90349BE';
126    const Old_ASF_Placeholder_Object          = 'D6E22A0E-35DA-11D1-9034-00A0C90349BE';
127    const Old_Data_Unit_Extension_Object      = 'D6E22A0F-35DA-11D1-9034-00A0C90349BE';
128    const Web_Stream_Format                   = 'DA1E6B13-8359-4050-B398-388E965BF00C';
129    const Payload_Ext_System_File_Name        = 'E165EC0E-19ED-45D7-B4A7-25CBD1E28E9B';
130    const Marker_Object                       = 'F487CD01-A951-11CF-8EE6-00C00C205365';
131    const Timecode_Index_Parameters_Object    = 'F55E496D-9797-4B5D-8C8B-604DFE9BFB24';
132    const Audio_Media                         = 'F8699E40-5B4D-11CF-A8FD-00805F5C442B';
133    const Media_Object_Index_Object           = 'FEB103F8-12AD-4C64-840F-2A1D2F7AD48C';
134    const Alt_Extended_Content_Encryption_Obj = 'FF889EF1-ADEE-40DA-9E71-98704BB928CE';
135
136
137
138    public function Analyze() {
139
140        $getid3 = $this->getid3;
141       
142        $getid3->include_module('audio-video.riff');
143
144        !isset($getid3->info['audio']) and $getid3->info['audio'] = array ();
145        !isset($getid3->info['video']) and $getid3->info['video'] = array ();
146        $getid3->info['asf']['comments'] = $getid3->info['asf']['header_object'] = array ();
147           
148        $info_audio             = &$getid3->info['audio'];
149        $info_video             = &$getid3->info['video'];
150        $info_asf               = &$getid3->info['asf'];
151        $info_asf_comments      = &$info_asf['comments'];
152        $info_asf_header_object = &$info_asf['header_object'];
153
154        // ASF structure:
155        // * Header Object [required]
156        //   * File Properties Object [required]   (global file attributes)
157        //   * Stream Properties Object [required] (defines media stream & characteristics)
158        //   * Header Extension Object [required]  (additional functionality)
159        //   * Content Description Object          (bibliographic information)
160        //   * Script Command Object               (commands for during playback)
161        //   * Marker Object                       (named jumped points within the file)
162        // * Data Object [required]
163        //   * Data Packets
164        // * Index Object
165
166        // Header Object: (mandatory, one only)
167        // Field Name                   Field Type   Size (bits)
168        // Object ID                    GUID         128             // GUID for header object - getid3_asf::Header_Object
169        // Object Size                  QWORD        64              // size of header object, including 30 bytes of Header Object header
170        // Number of Header Objects     DWORD        32              // number of objects in header object
171        // Reserved1                    BYTE         8               // hardcoded: 0x01
172        // Reserved2                    BYTE         8               // hardcoded: 0x02
173
174        $getid3->info['fileformat'] = 'asf';
175
176        fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET);
177        $header_object_data = fread($getid3->fp, 30);
178
179        $info_asf_header_object['objectid_guid'] = getid3_asf::BytestringToGUID(substr($header_object_data, 0, 16));
180       
181        if ($info_asf_header_object['objectid_guid'] != getid3_asf::Header_Object) {
182            throw new getid3_exception('ASF header GUID {'.$info_asf_header_object['objectid_guid'].'} does not match expected "getid3_asf::Header_Object" GUID {'.getid3_asf::Header_Object.'}');
183        }
184       
185        getid3_lib::ReadSequence('LittleEndian2Int', $info_asf_header_object, $header_object_data, 16,
186            array (
187                'objectsize'    => 8,
188                'headerobjects' => 4,
189                'reserved1'     => 1,
190                'reserved2'     => 1
191            )
192        );
193
194        $asf_header_data = fread($getid3->fp, $info_asf_header_object['objectsize'] - 30);
195        $offset = 0;
196
197        for ($header_objects_counter = 0; $header_objects_counter < $info_asf_header_object['headerobjects']; $header_objects_counter++) {
198           
199            $next_object_guid = substr($asf_header_data, $offset, 16);
200            $offset += 16;
201           
202            $next_object_size = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 8));
203            $offset += 8;
204           
205            $next_object_guidtext = getid3_asf::BytestringToGUID($next_object_guid);
206           
207            switch ($next_object_guidtext) {
208
209                case getid3_asf::File_Properties_Object:
210               
211                    // File Properties Object: (mandatory, one only)
212                    // Field Name                   Field Type   Size (bits)
213                    // Object ID                    GUID         128             // GUID for file properties object - getid3_asf::File_Properties_Object
214                    // Object Size                  QWORD        64              // size of file properties object, including 104 bytes of File Properties Object header
215                    // File ID                      GUID         128             // unique ID - identical to File ID in Data Object
216                    // File Size                    QWORD        64              // entire file in bytes. Invalid if Broadcast Flag == 1
217                    // Creation Date                QWORD        64              // date & time of file creation. Maybe invalid if Broadcast Flag == 1
218                    // Data Packets Count           QWORD        64              // number of data packets in Data Object. Invalid if Broadcast Flag == 1
219                    // Play Duration                QWORD        64              // playtime, in 100-nanosecond units. Invalid if Broadcast Flag == 1
220                    // Send Duration                QWORD        64              // time needed to send file, in 100-nanosecond units. Players can ignore this value. Invalid if Broadcast Flag == 1
221                    // Preroll                      QWORD        64              // time to buffer data before starting to play file, in 1-millisecond units. If <> 0, PlayDuration and PresentationTime have been offset by this amount
222                    // Flags                        DWORD        32              //
223                    // * Broadcast Flag             bits         1  (0x01)       // file is currently being written, some header values are invalid
224                    // * Seekable Flag              bits         1  (0x02)       // is file seekable
225                    // * Reserved                   bits         30 (0xFFFFFFFC) // reserved - set to zero
226                    // Minimum Data Packet Size     DWORD        32              // in bytes. should be same as Maximum Data Packet Size. Invalid if Broadcast Flag == 1
227                    // Maximum Data Packet Size     DWORD        32              // in bytes. should be same as Minimum Data Packet Size. Invalid if Broadcast Flag == 1
228                    // Maximum Bitrate              DWORD        32              // maximum instantaneous bitrate in bits per second for entire file, including all data streams and ASF overhead
229
230                    $info_asf['file_properties_object'] = array ();
231                    $info_asf_file_properties_object = &$info_asf['file_properties_object'];
232
233                    $info_asf_file_properties_object['objectid_guid']      = $next_object_guidtext;
234                    $info_asf_file_properties_object['objectsize']         = $next_object_size;
235                   
236                    $info_asf_file_properties_object['fileid_guid']        = getid3_asf::BytestringToGUID(substr($asf_header_data, $offset, 16));
237                    $offset += 16;
238
239                    getid3_lib::ReadSequence('LittleEndian2Int', $info_asf_file_properties_object, $asf_header_data, $offset,
240                        array (
241                            'filesize'        => 8,
242                            'creation_date'   => 8,
243                            'data_packets'    => 8,
244                            'play_duration'   => 8,
245                            'send_duration'   => 8,
246                            'preroll'         => 8,
247                            'flags_raw'       => 4,
248                            'min_packet_size' => 4,
249                            'max_packet_size' => 4,
250                            'max_bitrate'     => 4
251                        )
252                    );
253                   
254                    $offset += 64   ;
255                   
256                    $info_asf_file_properties_object['creation_date_unix'] = getid3_asf::FiletimeToUNIXtime($info_asf_file_properties_object['creation_date']);
257                    $info_asf_file_properties_object['flags']['broadcast'] = (bool)($info_asf_file_properties_object['flags_raw'] & 0x0001);
258                    $info_asf_file_properties_object['flags']['seekable']  = (bool)($info_asf_file_properties_object['flags_raw'] & 0x0002);
259
260                    $getid3->info['playtime_seconds'] = ($info_asf_file_properties_object['play_duration'] / 10000000) - ($info_asf_file_properties_object['preroll'] / 1000);
261                    $getid3->info['bitrate']          = ($info_asf_file_properties_object['filesize'] * 8) / $getid3->info['playtime_seconds'];
262                    break;
263
264
265                case getid3_asf::Stream_Properties_Object:
266                   
267                    // Stream Properties Object: (mandatory, one per media stream)
268                    // Field Name                   Field Type   Size (bits)
269                    // Object ID                    GUID         128             // GUID for stream properties object - getid3_asf::Stream_Properties_Object
270                    // Object Size                  QWORD        64              // size of stream properties object, including 78 bytes of Stream Properties Object header
271                    // Stream Type                  GUID         128             // getid3_asf::Audio_Media, getid3_asf::Video_Media or getid3_asf::Command_Media
272                    // Error Correction Type        GUID         128             // getid3_asf::Audio_Spread for audio-only streams, getid3_asf::No_Error_Correction for other stream types
273                    // Time Offset                  QWORD        64              // 100-nanosecond units. typically zero. added to all timestamps of samples in the stream
274                    // Type-Specific Data Length    DWORD        32              // number of bytes for Type-Specific Data field
275                    // Error Correction Data Length DWORD        32              // number of bytes for Error Correction Data field
276                    // Flags                        WORD         16              //
277                    // * Stream Number              bits         7 (0x007F)      // number of this stream.  1 <= valid <= 127
278                    // * Reserved                   bits         8 (0x7F80)      // reserved - set to zero
279                    // * Encrypted Content Flag     bits         1 (0x8000)      // stream contents encrypted if set
280                    // Reserved                     DWORD        32              // reserved - set to zero
281                    // Type-Specific Data           BYTESTREAM   variable        // type-specific format data, depending on value of Stream Type
282                    // Error Correction Data        BYTESTREAM   variable        // error-correction-specific format data, depending on value of Error Correct Type
283
284                    // There is one getid3_asf::Stream_Properties_Object for each stream (audio, video) but the
285                    // stream number isn't known until halfway through decoding the structure, hence it
286                    // it is decoded to a temporary variable and then stuck in the appropriate index later
287
288                    $stream_properties_object_data['objectid_guid']      = $next_object_guidtext;
289                    $stream_properties_object_data['objectsize']         = $next_object_size;
290                   
291                    getid3_lib::ReadSequence('LittleEndian2Int', $stream_properties_object_data, $asf_header_data, $offset,
292                        array (
293                            'stream_type'        => -16,
294                            'error_correct_type' => -16,
295                            'time_offset'        => 8,
296                            'type_data_length'   => 4,
297                            'error_data_length'  => 4,
298                            'flags_raw'          => 2
299                        )
300                    );
301
302                    $stream_properties_stream_number                     =        $stream_properties_object_data['flags_raw'] & 0x007F;
303                    $stream_properties_object_data['flags']['encrypted'] = (bool)($stream_properties_object_data['flags_raw'] & 0x8000);
304
305                    $stream_properties_object_data['stream_type_guid']   = getid3_asf::BytestringToGUID($stream_properties_object_data['stream_type']);
306                    $stream_properties_object_data['error_correct_guid'] = getid3_asf::BytestringToGUID($stream_properties_object_data['error_correct_type']);
307
308                    $offset += 54; // 50 bytes + 4 bytes reserved - DWORD
309                   
310                    $stream_properties_object_data['type_specific_data'] = substr($asf_header_data, $offset, $stream_properties_object_data['type_data_length']);
311                    $offset += $stream_properties_object_data['type_data_length'];
312                   
313                    $stream_properties_object_data['error_correct_data'] = substr($asf_header_data, $offset, $stream_properties_object_data['error_data_length']);
314                    $offset += $stream_properties_object_data['error_data_length'];
315
316                    switch ($stream_properties_object_data['stream_type_guid']) {
317
318                        case getid3_asf::Audio_Media:
319                   
320                            $info_audio['dataformat']   = (@$info_audio['dataformat']   ? $info_audio['dataformat']   : 'asf');
321                            $info_audio['bitrate_mode'] = (@$info_audio['bitrate_mode'] ? $info_audio['bitrate_mode'] : 'cbr');
322
323                            $audiodata = getid3_riff::RIFFparseWAVEFORMATex(substr($stream_properties_object_data['type_specific_data'], 0, 16));
324                            unset($audiodata['raw']);
325                            $info_audio = getid3_riff::array_merge_noclobber($audiodata, $info_audio);
326                            break;
327
328
329                        case getid3_asf::Video_Media:
330
331                            $info_video['dataformat']   = (@$info_video['dataformat']   ? $info_video['dataformat']   : 'asf');
332                            $info_video['bitrate_mode'] = (@$info_video['bitrate_mode'] ? $info_video['bitrate_mode'] : 'cbr');
333                            break;
334
335
336                        /* does nothing but eat memory
337                        case getid3_asf::Command_Media:
338                        default:
339                            // do nothing
340                            break;
341                        */
342                    }
343
344                    $info_asf['stream_properties_object'][$stream_properties_stream_number] = $stream_properties_object_data;
345                    unset($stream_properties_object_data); // clear for next stream, if any
346                    break;
347                   
348
349                case getid3_asf::Header_Extension_Object:
350                   
351                    // Header Extension Object: (mandatory, one only)
352                    // Field Name                   Field Type   Size (bits)
353                    // Object ID                    GUID         128             // GUID for Header Extension object - getid3_asf::Header_Extension_Object
354                    // Object Size                  QWORD        64              // size of Header Extension object, including 46 bytes of Header Extension Object header
355                    // Reserved Field 1             GUID         128             // hardcoded: getid3_asf::Reserved_1
356                    // Reserved Field 2             WORD         16              // hardcoded: 0x00000006
357                    // Header Extension Data Size   DWORD        32              // in bytes. valid: 0, or > 24. equals object size minus 46
358                    // Header Extension Data        BYTESTREAM   variable        // array of zero or more extended header objects
359
360                    $info_asf['header_extension_object'] = array ();
361                    $info_asf_header_extension_object    = &$info_asf['header_extension_object'];
362
363                    $info_asf_header_extension_object['objectid_guid']   = $next_object_guidtext;
364                    $info_asf_header_extension_object['objectsize']      = $next_object_size;
365                    $info_asf_header_extension_object['reserved_1_guid'] = getid3_asf::BytestringToGUID(substr($asf_header_data, $offset, 16));
366                    $offset += 16;
367                   
368                    if ($info_asf_header_extension_object['reserved_1_guid'] != getid3_asf::Reserved_1) {
369                        $getid3->warning('header_extension_object.reserved_1 GUID ('.$info_asf_header_extension_object['reserved_1_guid'].') does not match expected "getid3_asf::Reserved_1" GUID ('.getid3_asf::Reserved_1.')');
370                        break;
371                    }
372                   
373                    $info_asf_header_extension_object['reserved_2'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2));
374                    $offset += 2;
375                   
376                    if ($info_asf_header_extension_object['reserved_2'] != 6) {
377                        $getid3->warning('header_extension_object.reserved_2 ('.getid3_lib::PrintHexBytes($info_asf_header_extension_object['reserved_2']).') does not match expected value of "6"');
378                        break;
379                    }
380                   
381                    $info_asf_header_extension_object['extension_data_size'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 4));
382                    $offset += 4;
383                   
384                    $info_asf_header_extension_object['extension_data'] = substr($asf_header_data, $offset, $info_asf_header_extension_object['extension_data_size']);
385                    $offset += $info_asf_header_extension_object['extension_data_size'];
386                    break;
387                   
388
389                case getid3_asf::Codec_List_Object:
390                   
391                    // Codec List Object: (optional, one only)
392                    // Field Name                   Field Type   Size (bits)
393                    // Object ID                    GUID         128             // GUID for Codec List object - getid3_asf::Codec_List_Object
394                    // Object Size                  QWORD        64              // size of Codec List object, including 44 bytes of Codec List Object header
395                    // Reserved                     GUID         128             // hardcoded: 86D15241-311D-11D0-A3A4-00A0C90348F6
396                    // Codec Entries Count          DWORD        32              // number of entries in Codec Entries array
397                    // Codec Entries                array of:    variable        //
398                    // * Type                       WORD         16              // 0x0001 = Video Codec, 0x0002 = Audio Codec, 0xFFFF = Unknown Codec
399                    // * Codec Name Length          WORD         16              // number of Unicode characters stored in the Codec Name field
400                    // * Codec Name                 WCHAR        variable        // array of Unicode characters - name of codec used to create the content
401                    // * Codec Description Length   WORD         16              // number of Unicode characters stored in the Codec Description field
402                    // * Codec Description          WCHAR        variable        // array of Unicode characters - description of format used to create the content
403                    // * Codec Information Length   WORD         16              // number of Unicode characters stored in the Codec Information field
404                    // * Codec Information          BYTESTREAM   variable        // opaque array of information bytes about the codec used to create the content
405
406                    $info_asf['codec_list_object'] = array ();
407                    $info_asf_codec_list_object      = &$info_asf['codec_list_object'];
408
409                    $info_asf_codec_list_object['objectid_guid'] = $next_object_guidtext;
410                    $info_asf_codec_list_object['objectsize']    = $next_object_size;
411                   
412                    $info_asf_codec_list_object['reserved_guid'] = getid3_asf::BytestringToGUID(substr($asf_header_data, $offset, 16));
413                    $offset += 16;
414                   
415                    if ($info_asf_codec_list_object['reserved_guid'] != '86D15241-311D-11D0-A3A4-00A0C90348F6') {
416                        $getid3->warning('codec_list_object.reserved GUID {'.$info_asf_codec_list_object['reserved_guid'].'} does not match expected "getid3_asf::Reserved_1" GUID {86D15241-311D-11D0-A3A4-00A0C90348F6}');
417                        break;
418                    }
419                   
420                    $info_asf_codec_list_object['codec_entries_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 4));
421                    $offset += 4;
422                   
423                    for ($codec_entry_counter = 0; $codec_entry_counter < $info_asf_codec_list_object['codec_entries_count']; $codec_entry_counter++) {
424                       
425                        $info_asf_codec_list_object['codec_entries'][$codec_entry_counter] = array ();
426                        $info_asf_codec_list_object_codecentries_current = &$info_asf_codec_list_object['codec_entries'][$codec_entry_counter];
427
428                        $info_asf_codec_list_object_codecentries_current['type_raw'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2));
429                        $offset += 2;
430                       
431                        $info_asf_codec_list_object_codecentries_current['type'] = getid3_asf::ASFCodecListObjectTypeLookup($info_asf_codec_list_object_codecentries_current['type_raw']);
432
433                        $codec_name_length = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2)) * 2; // 2 bytes per character
434                        $offset += 2;
435                       
436                        $info_asf_codec_list_object_codecentries_current['name'] = substr($asf_header_data, $offset, $codec_name_length);
437                        $offset += $codec_name_length;
438
439                        $codec_description_length = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2)) * 2; // 2 bytes per character
440                        $offset += 2;
441                       
442                        $info_asf_codec_list_object_codecentries_current['description'] = substr($asf_header_data, $offset, $codec_description_length);
443                        $offset += $codec_description_length;
444
445                        $codec_information_length = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2));
446                        $offset += 2;
447                       
448                        $info_asf_codec_list_object_codecentries_current['information'] = substr($asf_header_data, $offset, $codec_information_length);
449                        $offset += $codec_information_length;
450
451                        if ($info_asf_codec_list_object_codecentries_current['type_raw'] == 2) {
452                           
453                            // audio codec
454                            if (strpos($info_asf_codec_list_object_codecentries_current['description'], ',') === false) {
455                                throw new getid3_exception('[asf][codec_list_object][codec_entries]['.$codec_entry_counter.'][description] expected to contain comma-seperated list of parameters: "'.$info_asf_codec_list_object_codecentries_current['description'].'"');
456                            }
457                            list($audio_codec_bitrate, $audio_codec_frequency, $audio_codec_channels) = explode(',', $this->TrimConvert($info_asf_codec_list_object_codecentries_current['description']));
458                            $info_audio['codec'] = $this->TrimConvert($info_asf_codec_list_object_codecentries_current['name']);
459
460                            if (!isset($info_audio['bitrate']) && strstr($audio_codec_bitrate, 'kbps')) {
461                                $info_audio['bitrate'] = (int)(trim(str_replace('kbps', '', $audio_codec_bitrate)) * 1000);
462                            }
463
464                            if (!isset($info_video['bitrate']) && isset($info_audio['bitrate']) && isset($info_asf['file_properties_object']['max_bitrate']) && ($info_asf_codec_list_object['codec_entries_count'] > 1)) {
465                                $info_video['bitrate'] = $info_asf['file_properties_object']['max_bitrate'] - $info_audio['bitrate'];
466                            }
467                           
468                            if (!@$info_video['bitrate'] && @$info_audio['bitrate'] && @$getid3->info['bitrate']) {
469                                                                $info_video['bitrate'] = $getid3->info['bitrate'] - $info_audio['bitrate'];
470                                                        }
471
472                            $audio_codec_frequency = (int)trim(str_replace('kHz', '', $audio_codec_frequency));
473
474                            static $sample_rate_lookup = array (
475                                8  =>  8000,    8000 =>  8000,
476                                11 => 11025,   11025 => 11025,
477                                12 => 12000,   12000 => 12000,
478                                16 => 16000,   16000 => 16000,
479                                22 => 22050,   22050 => 22050,
480                                24 => 24000,   24000 => 24000,
481                                32 => 32000,   32000 => 32000,
482                                44 => 44100,   44100 => 44100,
483                                48 => 48000,   48000 => 48000,
484                            );
485
486                            $info_audio['sample_rate'] = @$sample_rate_lookup[$audio_codec_frequency];
487
488                            if (!$info_audio['sample_rate']) {
489                                $getid3->warning('unknown frequency: "'.$audio_codec_frequency.'" ('.$this->TrimConvert($info_asf_codec_list_object_codecentries_current['description']).')');
490                                break;
491                            }
492
493                            if (!isset($info_audio['channels'])) {
494                                if (strstr($audio_codec_channels, 'stereo')) {
495                                    $info_audio['channels'] = 2;
496                                } elseif (strstr($audio_codec_channels, 'mono')) {
497                                    $info_audio['channels'] = 1;
498                                }
499                            }
500                        }
501                    }
502                    break;
503
504
505                case getid3_asf::Script_Command_Object:
506
507                    // Script Command Object: (optional, one only)
508                    // Field Name                   Field Type   Size (bits)
509                    // Object ID                    GUID         128             // GUID for Script Command object - getid3_asf::Script_Command_Object
510                    // Object Size                  QWORD        64              // size of Script Command object, including 44 bytes of Script Command Object header
511                    // Reserved                     GUID         128             // hardcoded: 4B1ACBE3-100B-11D0-A39B-00A0C90348F6
512                    // Commands Count               WORD         16              // number of Commands structures in the Script Commands Objects
513                    // Command Types Count          WORD         16              // number of Command Types structures in the Script Commands Objects
514                    // Command Types                array of:    variable        //
515                    // * Command Type Name Length   WORD         16              // number of Unicode characters for Command Type Name
516                    // * Command Type Name          WCHAR        variable        // array of Unicode characters - name of a type of command
517                    // Commands                     array of:    variable        //
518                    // * Presentation Time          DWORD        32              // presentation time of that command, in milliseconds
519                    // * Type Index                 WORD         16              // type of this command, as a zero-based index into the array of Command Types of this object
520                    // * Command Name Length        WORD         16              // number of Unicode characters for Command Name
521                    // * Command Name               WCHAR        variable        // array of Unicode characters - name of this command
522
523                    // shortcut
524                    $info_asf['script_command_object'] = array ();
525                    $info_asf_script_command_object    = &$info_asf['script_command_object'];
526
527                    $info_asf_script_command_object['objectid_guid'] = $next_object_guidtext;
528                    $info_asf_script_command_object['objectsize']    = $next_object_size;
529                    $info_asf_script_command_object['reserved_guid'] = getid3_asf::BytestringToGUID(substr($asf_header_data, $offset, 16));
530                    $offset += 16;
531                   
532                    if ($info_asf_script_command_object['reserved_guid'] != '4B1ACBE3-100B-11D0-A39B-00A0C90348F6') {
533                        $getid3->warning('script_command_object.reserved GUID {'.$info_asf_script_command_object['reserved_guid'].'} does not match expected GUID {4B1ACBE3-100B-11D0-A39B-00A0C90348F6}');
534                        break;
535                    }
536                   
537                    $info_asf_script_command_object['commands_count']       = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2));
538                    $offset += 2;
539                   
540                    $info_asf_script_command_object['command_types_count']  = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2));
541                    $offset += 2;
542                   
543                    for ($command_types_counter = 0; $command_types_counter < $info_asf_script_command_object['command_types_count']; $command_types_counter++) {
544                       
545                        $command_type_name_length = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2)) * 2; // 2 bytes per character
546                        $offset += 2;
547                       
548                        $info_asf_script_command_object['command_types'][$command_types_counter]['name'] = substr($asf_header_data, $offset, $command_type_name_length);
549                        $offset += $command_type_name_length;
550                    }
551                   
552                    for ($commands_counter = 0; $commands_counter < $info_asf_script_command_object['commands_count']; $commands_counter++) {
553                       
554                        $info_asf_script_command_object['commands'][$commands_counter]['presentation_time'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 4));
555                        $offset += 4;
556                       
557                        $info_asf_script_command_object['commands'][$commands_counter]['type_index']        = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2));
558                        $offset += 2;
559
560                        $command_type_name_length                                                           = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2)) * 2; // 2 bytes per character
561                        $offset += 2;
562                       
563                        $info_asf_script_command_object['commands'][$commands_counter]['name']              = substr($asf_header_data, $offset, $command_type_name_length);
564                        $offset += $command_type_name_length;
565                    }
566                    break;
567
568
569                case getid3_asf::Marker_Object:
570
571                    // Marker Object: (optional, one only)
572                    // Field Name                   Field Type   Size (bits)
573                    // Object ID                    GUID         128             // GUID for Marker object - getid3_asf::Marker_Object
574                    // Object Size                  QWORD        64              // size of Marker object, including 48 bytes of Marker Object header
575                    // Reserved                     GUID         128             // hardcoded: 4CFEDB20-75F6-11CF-9C0F-00A0C90349CB
576                    // Markers Count                DWORD        32              // number of Marker structures in Marker Object
577                    // Reserved                     WORD         16              // hardcoded: 0x0000
578                    // Name Length                  WORD         16              // number of bytes in the Name field
579                    // Name                         WCHAR        variable        // name of the Marker Object
580                    // Markers                      array of:    variable        //
581                    // * Offset                     QWORD        64              // byte offset into Data Object
582                    // * Presentation Time          QWORD        64              // in 100-nanosecond units
583                    // * Entry Length               WORD         16              // length in bytes of (Send Time + Flags + Marker Description Length + Marker Description + Padding)
584                    // * Send Time                  DWORD        32              // in milliseconds
585                    // * Flags                      DWORD        32              // hardcoded: 0x00000000
586                    // * Marker Description Length  DWORD        32              // number of bytes in Marker Description field
587                    // * Marker Description         WCHAR        variable        // array of Unicode characters - description of marker entry
588                    // * Padding                    BYTESTREAM   variable        // optional padding bytes
589
590                    $info_asf['marker_object'] = array ();
591                    $info_asf_marker_object    = &$info_asf['marker_object'];
592
593                    $info_asf_marker_object['objectid_guid'] = $next_object_guidtext;
594                    $info_asf_marker_object['objectsize']    = $next_object_size;
595                    $info_asf_marker_object['reserved_guid'] = getid3_asf::BytestringToGUID(substr($asf_header_data, $offset, 16));
596                    $offset += 16;                           
597                   
598                    if ($info_asf_marker_object['reserved_guid'] != '4CFEDB20-75F6-11CF-9C0F-00A0C90349CB') {
599                        $getid3->warning('marker_object.reserved GUID {'.$info_asf_marker_object['reserved_guid'].'} does not match expected GUID {4CFEDB20-75F6-11CF-9C0F-00A0C90349CB}');
600                        break;
601                    }
602                   
603                    $info_asf_marker_object['markers_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 4));
604                    $offset += 4;
605                   
606                    $info_asf_marker_object['reserved_2']    = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2));
607                    $offset += 2;
608                   
609                    if ($info_asf_marker_object['reserved_2'] != 0) {
610                        $getid3->warning('marker_object.reserved_2 ('.getid3_lib::PrintHexBytes($info_asf_marker_object['reserved_2']).') does not match expected value of "0"');
611                        break;
612                    }
613                   
614                    $info_asf_marker_object['name_length']   = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2));
615                    $offset += 2;
616                   
617                    $info_asf_marker_object['name'] = substr($asf_header_data, $offset, $info_asf_marker_object['name_length']);
618                    $offset += $info_asf_marker_object['name_length'];
619                   
620                    for ($markers_counter = 0; $markers_counter < $info_asf_marker_object['markers_count']; $markers_counter++) {
621                       
622                        getid3_lib::ReadSequence('LittleEndian2Int', $info_asf_marker_object['markers'][$markers_counter], $asf_header_data, $offset,
623                            array (
624                                'offset'                    => 8,
625                                'presentation_time'         => 8,
626                                'entry_length'              => 2,
627                                'send_time'                 => 4,
628                                'flags'                     => 4,
629                                'marker_description_length' => 4
630                            )
631                        );
632                        $offset += 30;
633                       
634                        $info_asf_marker_object['markers'][$markers_counter]['marker_description'] = substr($asf_header_data, $offset, $info_asf_marker_object['markers'][$markers_counter]['marker_description_length']);
635                        $offset += $info_asf_marker_object['markers'][$markers_counter]['marker_description_length'];
636                       
637                        $padding_length = $info_asf_marker_object['markers'][$markers_counter]['entry_length'] - 4 -  4 - 4 - $info_asf_marker_object['markers'][$markers_counter]['marker_description_length'];
638                        if ($padding_length > 0) {
639                            $info_asf_marker_object['markers'][$markers_counter]['padding'] = substr($asf_header_data, $offset, $padding_length);
640                            $offset += $padding_length;
641                        }
642                    }
643                    break;
644                   
645
646                case getid3_asf::Bitrate_Mutual_Exclusion_Object:
647                   
648                    // Bitrate Mutual Exclusion Object: (optional)
649                    // Field Name                   Field Type   Size (bits)
650                    // Object ID                    GUID         128             // GUID for Bitrate Mutual Exclusion object - getid3_asf::Bitrate_Mutual_Exclusion_Object
651                    // Object Size                  QWORD        64              // size of Bitrate Mutual Exclusion object, including 42 bytes of Bitrate Mutual Exclusion Object header
652                    // Exlusion Type                GUID         128             // nature of mutual exclusion relationship. one of: (getid3_asf::Mutex_Bitrate, getid3_asf::Mutex_Unknown)
653                    // Stream Numbers Count         WORD         16              // number of video streams
654                    // Stream Numbers               WORD         variable        // array of mutually exclusive video stream numbers. 1 <= valid <= 127
655
656                    // shortcut
657                    $info_asf['bitrate_mutual_exclusion_object'] = array ();
658                    $info_asf_bitrate_mutual_exclusion_object    = &$info_asf['bitrate_mutual_exclusion_object'];
659
660                    $info_asf_bitrate_mutual_exclusion_object['objectid_guid'] = $next_object_guidtext;
661                    $info_asf_bitrate_mutual_exclusion_object['objectsize']    = $next_object_size;
662                    $info_asf_bitrate_mutual_exclusion_object['reserved_guid'] = getid3_asf::BytestringToGUID(substr($asf_header_data, $offset, 16));
663                    $offset += 16;
664                   
665                    if ($info_asf_bitrate_mutual_exclusion_object['reserved_guid'] != getid3_asf::Mutex_Bitrate  &&  $info_asf_bitrate_mutual_exclusion_object['reserved_guid'] != getid3_asf::Mutex_Unknown) {
666                        $getid3->warning('bitrate_mutual_exclusion_object.reserved GUID {'.$info_asf_bitrate_mutual_exclusion_object['reserved_guid'].'} does not match expected "getid3_asf::Mutex_Bitrate" GUID {'.getid3_asf::Mutex_Bitrate.'} or  "getid3_asf::Mutex_Unknown" GUID {'.getid3_asf::Mutex_Unknown.'}');
667                        break;
668                    }
669                   
670                    $info_asf_bitrate_mutual_exclusion_object['stream_numbers_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2));
671                    $offset += 2;
672                   
673                    for ($stream_number_counter = 0; $stream_number_counter < $info_asf_bitrate_mutual_exclusion_object['stream_numbers_count']; $stream_number_counter++) {
674                        $info_asf_bitrate_mutual_exclusion_object['stream_numbers'][$stream_number_counter] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2));
675                        $offset += 2;
676                    }
677                    break;
678
679
680                case getid3_asf::Error_Correction_Object:
681
682                    // Error Correction Object: (optional, one only)
683                    // Field Name                   Field Type   Size (bits)
684                    // Object ID                    GUID         128             // GUID for Error Correction object - getid3_asf::Error_Correction_Object
685                    // Object Size                  QWORD        64              // size of Error Correction object, including 44 bytes of Error Correction Object header
686                    // Error Correction Type        GUID         128             // type of error correction. one of: (getid3_asf::No_Error_Correction, getid3_asf::Audio_Spread)
687                    // Error Correction Data Length DWORD        32              // number of bytes in Error Correction Data field
688                    // Error Correction Data        BYTESTREAM   variable        // structure depends on value of Error Correction Type field
689
690                    $info_asf['error_correction_object'] = array ();
691                    $info_asf_error_correction_object      = &$info_asf['error_correction_object'];
692
693                    $info_asf_error_correction_object['objectid_guid']         = $next_object_guidtext;
694                    $info_asf_error_correction_object['objectsize']            = $next_object_size;
695                    $info_asf_error_correction_object['error_correction_type'] = substr($asf_header_data, $offset, 16);
696                    $offset += 16;
697                   
698                    $info_asf_error_correction_object['error_correction_guid']        = getid3_asf::BytestringToGUID($info_asf_error_correction_object['error_correction_type']);
699                    $info_asf_error_correction_object['error_correction_data_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 4));
700                    $offset += 4;
701                   
702                    switch ($info_asf_error_correction_object['error_correction_type_guid']) {
703                   
704                        case getid3_asf::No_Error_Correction:
705                   
706                            // should be no data, but just in case there is, skip to the end of the field
707                            $offset += $info_asf_error_correction_object['error_correction_data_length'];
708                            break;
709
710
711                        case getid3_asf::Audio_Spread:
712
713                            // Field Name                   Field Type   Size (bits)
714                            // Span                         BYTE         8               // number of packets over which audio will be spread.
715                            // Virtual Packet Length        WORD         16              // size of largest audio payload found in audio stream
716                            // Virtual Chunk Length         WORD         16              // size of largest audio payload found in audio stream
717                            // Silence Data Length          WORD         16              // number of bytes in Silence Data field
718                            // Silence Data                 BYTESTREAM   variable        // hardcoded: 0x00 * (Silence Data Length) bytes
719
720                            getid3_lib::ReadSequence('LittleEndian2Int', $info_asf_error_correction_object, $asf_header_data, $offset, 
721                                array (
722                                    'span'                  => 1,
723                                    'virtual_packet_length' => 2,
724                                    'virtual_chunk_length'  => 2,
725                                    'silence_data_length'   => 2
726                                )
727                            );
728                            $offset += 7;
729                           
730                            $info_asf_error_correction_object['silence_data'] = substr($asf_header_data, $offset, $info_asf_error_correction_object['silence_data_length']);
731                            $offset += $info_asf_error_correction_object['silence_data_length'];
732                            break;
733
734                        default:
735                            $getid3->warning('error_correction_object.error_correction_type GUID {'.$info_asf_error_correction_object['reserved_guid'].'} does not match expected "getid3_asf::No_Error_Correction" GUID {'.getid3_asf::No_Error_Correction.'} or  "getid3_asf::Audio_Spread" GUID {'.getid3_asf::Audio_Spread.'}');
736                            break;
737                    }
738
739                    break;
740
741
742                case getid3_asf::Content_Description_Object:
743
744                    // Content Description Object: (optional, one only)
745                    // Field Name                   Field Type   Size (bits)
746                    // Object ID                    GUID         128             // GUID for Content Description object - getid3_asf::Content_Description_Object
747                    // Object Size                  QWORD        64              // size of Content Description object, including 34 bytes of Content Description Object header
748                    // Title Length                 WORD         16              // number of bytes in Title field
749                    // Author Length                WORD         16              // number of bytes in Author field
750                    // Copyright Length             WORD         16              // number of bytes in Copyright field
751                    // Description Length           WORD         16              // number of bytes in Description field
752                    // Rating Length                WORD         16              // number of bytes in Rating field
753                    // Title                        WCHAR        16              // array of Unicode characters - Title
754                    // Author                       WCHAR        16              // array of Unicode characters - Author
755                    // Copyright                    WCHAR        16              // array of Unicode characters - Copyright
756                    // Description                  WCHAR        16              // array of Unicode characters - Description
757                    // Rating                       WCHAR        16              // array of Unicode characters - Rating
758
759                    $info_asf['content_description_object'] = array ();
760                    $info_asf_content_description_object      = &$info_asf['content_description_object'];
761
762                    $info_asf_content_description_object['objectid_guid'] = $next_object_guidtext;
763                    $info_asf_content_description_object['objectsize']    = $next_object_size;
764                   
765                    getid3_lib::ReadSequence('LittleEndian2Int', $info_asf_content_description_object, $asf_header_data, $offset, 
766                        array (
767                            'title_length'       => 2,
768                            'author_length'      => 2,
769                            'copyright_length'   => 2,
770                            'description_length' => 2,
771                            'rating_length'      => 2
772                        )
773                    );
774                    $offset += 10;
775                   
776                    $info_asf_content_description_object['title']       = substr($asf_header_data, $offset, $info_asf_content_description_object['title_length']);
777                    $offset += $info_asf_content_description_object['title_length'];
778                   
779                    $info_asf_content_description_object['author']      = substr($asf_header_data, $offset, $info_asf_content_description_object['author_length']);
780                    $offset += $info_asf_content_description_object['author_length'];
781                   
782                    $info_asf_content_description_object['copyright']   = substr($asf_header_data, $offset, $info_asf_content_description_object['copyright_length']);
783                    $offset += $info_asf_content_description_object['copyright_length'];
784                   
785                    $info_asf_content_description_object['description'] = substr($asf_header_data, $offset, $info_asf_content_description_object['description_length']);
786                    $offset += $info_asf_content_description_object['description_length'];
787                   
788                    $info_asf_content_description_object['rating']      = substr($asf_header_data, $offset, $info_asf_content_description_object['rating_length']);
789                    $offset += $info_asf_content_description_object['rating_length'];
790
791                    foreach (array ('title'=>'title', 'author'=>'artist', 'copyright'=>'copyright', 'description'=>'comment', 'rating'=>'rating') as $key_to_copy_from => $key_to_copy_to) {
792                        if (!empty($info_asf_content_description_object[$key_to_copy_from])) {
793                            $info_asf_comments[$key_to_copy_to][] = getid3_asf::TrimTerm($info_asf_content_description_object[$key_to_copy_from]);
794                        }
795                    }
796                    break;
797
798
799                case getid3_asf::Extended_Content_Description_Object:
800
801                    // Extended Content Description Object: (optional, one only)
802                    // Field Name                   Field Type   Size (bits)
803                    // Object ID                    GUID         128             // GUID for Extended Content Description object - getid3_asf::Extended_Content_Description_Object
804                    // Object Size                  QWORD        64              // size of ExtendedContent Description object, including 26 bytes of Extended Content Description Object header
805                    // Content Descriptors Count    WORD         16              // number of entries in Content Descriptors list
806                    // Content Descriptors          array of:    variable        //
807                    // * Descriptor Name Length     WORD         16              // size in bytes of Descriptor Name field
808                    // * Descriptor Name            WCHAR        variable        // array of Unicode characters - Descriptor Name
809                    // * Descriptor Value Data Type WORD         16              // Lookup array:
810                                                                                    // 0x0000 = Unicode String (variable length)
811                                                                                    // 0x0001 = BYTE array     (variable length)
812                                                                                    // 0x0002 = BOOL           (DWORD, 32 bits)
813                                                                                    // 0x0003 = DWORD          (DWORD, 32 bits)
814                                                                                    // 0x0004 = QWORD          (QWORD, 64 bits)
815                                                                                    // 0x0005 = WORD           (WORD,  16 bits)
816                    // * Descriptor Value Length    WORD         16              // number of bytes stored in Descriptor Value field
817                    // * Descriptor Value           variable     variable        // value for Content Descriptor
818
819                    $info_asf['extended_content_description_object'] = array ();
820                    $info_asf_extended_content_description_object       = &$info_asf['extended_content_description_object'];
821
822                    $info_asf_extended_content_description_object['objectid_guid']             = $next_object_guidtext;
823                    $info_asf_extended_content_description_object['objectsize']                = $next_object_size;
824                    $info_asf_extended_content_description_object['content_descriptors_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2));
825                    $offset += 2;
826                   
827                    for ($extended_content_descriptors_counter = 0; $extended_content_descriptors_counter < $info_asf_extended_content_description_object['content_descriptors_count']; $extended_content_descriptors_counter++) {
828                       
829                        $info_asf_extended_content_description_object['content_descriptors'][$extended_content_descriptors_counter] = array ();
830                        $info_asf_extended_content_description_object_content_descriptor_current                                  = &$info_asf_extended_content_description_object['content_descriptors'][$extended_content_descriptors_counter];
831
832                        $info_asf_extended_content_description_object_content_descriptor_current['base_offset']  = $offset + 30;
833                        $info_asf_extended_content_description_object_content_descriptor_current['name_length']  = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2));
834                        $offset += 2;
835                       
836                        $info_asf_extended_content_description_object_content_descriptor_current['name']         = substr($asf_header_data, $offset, $info_asf_extended_content_description_object_content_descriptor_current['name_length']);
837                        $offset += $info_asf_extended_content_description_object_content_descriptor_current['name_length'];
838                       
839                        $info_asf_extended_content_description_object_content_descriptor_current['value_type']   = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2));
840                        $offset += 2;
841                       
842                        $info_asf_extended_content_description_object_content_descriptor_current['value_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2));
843                        $offset += 2;
844                       
845                        $info_asf_extended_content_description_object_content_descriptor_current['value']        = substr($asf_header_data, $offset, $info_asf_extended_content_description_object_content_descriptor_current['value_length']);
846                        $offset += $info_asf_extended_content_description_object_content_descriptor_current['value_length'];
847                       
848                        switch ($info_asf_extended_content_description_object_content_descriptor_current['value_type']) {
849                           
850                            case 0x0000: // Unicode string
851                                break;
852
853                            case 0x0001: // BYTE array
854                                // do nothing
855                                break;
856
857                            case 0x0002: // BOOL
858                                $info_asf_extended_content_description_object_content_descriptor_current['value'] = (bool)getid3_lib::LittleEndian2Int($info_asf_extended_content_description_object_content_descriptor_current['value']);
859                                break;
860
861                            case 0x0003: // DWORD
862                            case 0x0004: // QWORD
863                            case 0x0005: // WORD
864                                $info_asf_extended_content_description_object_content_descriptor_current['value'] = getid3_lib::LittleEndian2Int($info_asf_extended_content_description_object_content_descriptor_current['value']);
865                                break;
866
867                            default:
868                                $getid3->warning('extended_content_description.content_descriptors.'.$extended_content_descriptors_counter.'.value_type is invalid ('.$info_asf_extended_content_description_object_content_descriptor_current['value_type'].')');
869                                break;
870                        }
871                       
872                        switch ($this->TrimConvert(strtolower($info_asf_extended_content_description_object_content_descriptor_current['name']))) {
873
874                            case 'wm/albumartist':
875                            case 'artist':
876                                $info_asf_comments['artist'] = array (getid3_asf::TrimTerm($info_asf_extended_content_description_object_content_descriptor_current['value']));
877                                break;
878
879
880                            case 'wm/albumtitle':
881                            case 'album':
882                                $info_asf_comments['album']  = array (getid3_asf::TrimTerm($info_asf_extended_content_description_object_content_descriptor_current['value']));
883                                break;
884
885
886                            case 'wm/genre':
887                            case 'genre':
888                                $genre = getid3_asf::TrimTerm($info_asf_extended_content_description_object_content_descriptor_current['value']);
889                                $info_asf_comments['genre'] = array ($genre);
890                                break;
891
892
893                            case 'wm/tracknumber':
894                            case 'tracknumber':
895                                $info_asf_comments['track'] = array (intval(getid3_asf::TrimTerm($info_asf_extended_content_description_object_content_descriptor_current['value'])));
896                                break;
897
898
899                            case 'wm/track':
900                                if (empty($info_asf_comments['track'])) {
901                                    $info_asf_comments['track'] = array (1 + $this->TrimConvert($info_asf_extended_content_description_object_content_descriptor_current['value']));
902                                }
903                                break;
904
905
906                            case 'wm/year':
907                            case 'year':
908                            case 'date':
909                                $info_asf_comments['year'] = array ( getid3_asf::TrimTerm($info_asf_extended_content_description_object_content_descriptor_current['value']));
910                                break;
911                               
912                               
913                            case 'wm/lyrics':
914                            case 'lyrics':
915                                $info_asf_comments['lyrics'] = array ( getid3_asf::TrimTerm($info_asf_extended_content_description_object_content_descriptor_current['value']));
916                                    break;
917                           
918                           
919                            case 'isvbr':
920                                if ($info_asf_extended_content_description_object_content_descriptor_current['value']) {
921                                    $info_audio['bitrate_mode'] = 'vbr';
922                                    $info_video['bitrate_mode'] = 'vbr';
923                                }
924                                break;
925
926
927                            case 'id3':
928                                                               
929                                                                // id3v2 parsing might not be enabled
930                                                                if (class_exists('getid3_id3v2')) {
931                                                                       
932                                                                        // Clone getid3
933                                    $clone = clone $getid3;
934                                   
935                                    // Analyse clone by string
936                                    $id3v2 = new getid3_id3v2($clone);
937                                    $id3v2->AnalyzeString($info_asf_extended_content_description_object_content_descriptor_current['value']);
938                                   
939                                    // Import from clone and destroy
940                                    $getid3->info['id3v2'] = $clone->info['id3v2'];
941                                    $getid3->warnings($clone->warnings());
942                                    unset($clone);
943                                                                }
944                                                                break;
945
946
947                            case 'wm/encodingtime':
948                                $info_asf_extended_content_description_object_content_descriptor_current['encoding_time_unix'] = getid3_asf::FiletimeToUNIXtime($info_asf_extended_content_description_object_content_descriptor_current['value']);
949                                $info_asf_comments['encoding_time_unix'] = array ($info_asf_extended_content_description_object_content_descriptor_current['encoding_time_unix']);
950                                break;
951
952
953                            case 'wm/picture':
954                               
955                                //typedef struct _WMPicture{
956                                //  LPWSTR  pwszMIMEType;
957                                //  BYTE  bPictureType;
958                                //  LPWSTR  pwszDescription;
959                                //  DWORD  dwDataLen;
960                                //  BYTE*  pbData;
961                                //} WM_PICTURE;
962
963                                $info_asf_extended_content_description_object_content_descriptor_current['image_type_id'] = getid3_lib::LittleEndian2Int($info_asf_extended_content_description_object_content_descriptor_current['value']{0});
964                                $info_asf_extended_content_description_object_content_descriptor_current['image_type']    = getid3_asf::WMpictureTypeLookup($info_asf_extended_content_description_object_content_descriptor_current['image_type_id']);
965                                $info_asf_extended_content_description_object_content_descriptor_current['image_size']    = getid3_lib::LittleEndian2Int(substr($info_asf_extended_content_description_object_content_descriptor_current['value'], 1, 4));
966                                $info_asf_extended_content_description_object_content_descriptor_current['image_mime']   = '';
967                               
968                                $wm_picture_offset = 5;
969                               
970                                do {
971                                    $next_byte_pair = substr($info_asf_extended_content_description_object_content_descriptor_current['value'], $wm_picture_offset, 2);
972                                    $wm_picture_offset += 2;
973                                    $info_asf_extended_content_description_object_content_descriptor_current['image_mime'] .= $next_byte_pair;
974                                } while ($next_byte_pair !== "\x00\x00");
975
976                                $info_asf_extended_content_description_object_content_descriptor_current['image_description'] = '';
977                               
978                                do {
979                                    $next_byte_pair = substr($info_asf_extended_content_description_object_content_descriptor_current['value'], $wm_picture_offset, 2);
980                                    $wm_picture_offset += 2;
981                                    $info_asf_extended_content_description_object_content_descriptor_current['image_description'] .= $next_byte_pair;
982                                } while ($next_byte_pair !== "\x00\x00");
983
984                                $info_asf_extended_content_description_object_content_descriptor_current['dataoffset'] = $wm_picture_offset;
985                                $info_asf_extended_content_description_object_content_descriptor_current['data']       = substr($info_asf_extended_content_description_object_content_descriptor_current['value'], $wm_picture_offset);
986                                unset($info_asf_extended_content_description_object_content_descriptor_current['value']);
987                                break;
988
989                            default:
990                                switch ($info_asf_extended_content_description_object_content_descriptor_current['value_type']) {
991                                    case 0: // Unicode string
992                                        if (substr($this->TrimConvert($info_asf_extended_content_description_object_content_descriptor_current['name']), 0, 3) == 'WM/') {
993                                            $info_asf_comments[str_replace('wm/', '', strtolower($this->TrimConvert($info_asf_extended_content_description_object_content_descriptor_current['name'])))] = array (getid3_asf::TrimTerm($info_asf_extended_content_description_object_content_descriptor_current['value']));
994                                        }
995                                        break;
996
997                                    case 1:
998                                        break;
999                                }
1000                                break;
1001                        }
1002
1003                    }
1004                    break;
1005
1006
1007                case getid3_asf::Stream_Bitrate_Properties_Object:
1008
1009                    // Stream Bitrate Properties Object: (optional, one only)
1010                    // Field Name                   Field Type   Size (bits)
1011                    // Object ID                    GUID         128             // GUID for Stream Bitrate Properties object - getid3_asf::Stream_Bitrate_Properties_Object
1012                    // Object Size                  QWORD        64              // size of Extended Content Description object, including 26 bytes of Stream Bitrate Properties Object header
1013                    // Bitrate Records Count        WORD         16              // number of records in Bitrate Records
1014                    // Bitrate Records              array of:    variable        //
1015                    // * Flags                      WORD         16              //
1016                    // * * Stream Number            bits         7  (0x007F)     // number of this stream
1017                    // * * Reserved                 bits         9  (0xFF80)     // hardcoded: 0
1018                    // * Average Bitrate            DWORD        32              // in bits per second
1019
1020                    // shortcut
1021                    $info_asf['stream_bitrate_properties_object'] = array ();
1022                    $info_asf_stream_bitrate_properties_object = &$info_asf['stream_bitrate_properties_object'];
1023
1024                    $info_asf_stream_bitrate_properties_object['objectid_guid']         = $next_object_guidtext;
1025                    $info_asf_stream_bitrate_properties_object['objectsize']            = $next_object_size;
1026                    $info_asf_stream_bitrate_properties_object['bitrate_records_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2));
1027                    $offset += 2;
1028                   
1029                    for ($bitrate_records_counter = 0; $bitrate_records_counter < $info_asf_stream_bitrate_properties_object['bitrate_records_count']; $bitrate_records_counter++) {
1030                   
1031                        $info_asf_stream_bitrate_properties_object['bitrate_records'][$bitrate_records_counter]['flags_raw'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2));
1032                        $offset += 2;
1033                       
1034                        $info_asf_stream_bitrate_properties_object['bitrate_records'][$bitrate_records_counter]['flags']['stream_number'] = $info_asf_stream_bitrate_properties_object['bitrate_records'][$bitrate_records_counter]['flags_raw'] & 0x007F;
1035                       
1036                        $info_asf_stream_bitrate_properties_object['bitrate_records'][$bitrate_records_counter]['bitrate'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 4));
1037                        $offset += 4;
1038                    }
1039                    break;
1040
1041
1042                case getid3_asf::Padding_Object:
1043
1044                    // Padding Object: (optional)
1045                    // Field Name                   Field Type   Size (bits)
1046                    // Object ID                    GUID         128             // GUID for Padding object - getid3_asf::Padding_Object
1047                    // Object Size                  QWORD        64              // size of Padding object, including 24 bytes of ASF Padding Object header
1048                    // Padding Data                 BYTESTREAM   variable        // ignore
1049
1050                    // shortcut
1051                    $info_asf['padding_object'] = array ();
1052                    $info_asf_paddingobject     = &$info_asf['padding_object'];
1053
1054                    $info_asf_paddingobject['objectid_guid']  = $next_object_guidtext;
1055                    $info_asf_paddingobject['objectsize']     = $next_object_size;
1056                    $info_asf_paddingobject['padding_length'] = $info_asf_paddingobject['objectsize'] - 16 - 8;
1057                    $info_asf_paddingobject['padding']        = substr($asf_header_data, $offset, $info_asf_paddingobject['padding_length']);
1058                    $offset += ($next_object_size - 16 - 8);
1059                    break;
1060
1061
1062                case getid3_asf::Extended_Content_Encryption_Object:
1063                case getid3_asf::Content_Encryption_Object:
1064
1065                    // WMA DRM - just ignore
1066                    $offset += ($next_object_size - 16 - 8);
1067                    break;
1068
1069
1070                default:
1071
1072                    // Implementations shall ignore any standard or non-standard object that they do not know how to handle.
1073                    if (getid3_asf::GUIDname($next_object_guidtext)) {
1074                        $getid3->warning('unhandled GUID "'.getid3_asf::GUIDname($next_object_guidtext).'" {'.$next_object_guidtext.'} in ASF header at offset '.($offset - 16 - 8));
1075                    } else {
1076                        $getid3->warning('unknown GUID {'.$next_object_guidtext.'} in ASF header at offset '.($offset - 16 - 8));
1077                    }
1078                    $offset += ($next_object_size - 16 - 8);
1079                    break;
1080            }
1081        }
1082       
1083        if (isset($info_asf_stream_bitrate_properties['bitrate_records_count'])) {
1084            $asf_bitrate_audio = 0;
1085            $asf_bitrate_video = 0;
1086
1087            for ($bitrate_records_counter = 0; $bitrate_records_counter < $info_asf_stream_bitrate_properties['bitrate_records_count']; $bitrate_records_counter++) {
1088                if (isset($info_asf_codec_list_object['codec_entries'][$bitrate_records_counter])) {
1089                    switch ($info_asf_codec_list_object['codec_entries'][$bitrate_records_counter]['type_raw']) {
1090                       
1091                        case 1:
1092                            $asf_bitrate_video += $info_asf_stream_bitrate_properties['bitrate_records'][$bitrate_records_counter]['bitrate'];
1093                            break;
1094                           
1095                        case 2:
1096                            $asf_bitrate_audio += $info_asf_stream_bitrate_properties['bitrate_records'][$bitrate_records_counter]['bitrate'];
1097                            break;
1098                    }
1099                }
1100            }
1101            if ($asf_bitrate_audio > 0) {
1102                $info_audio['bitrate'] = $asf_bitrate_audio;
1103            }
1104            if ($asf_bitrate_video > 0) {
1105                $info_video['bitrate'] = $asf_bitrate_video;
1106            }
1107        }
1108       
1109        if (isset($info_asf['stream_properties_object']) && is_array($info_asf['stream_properties_object'])) {
1110           
1111            $info_audio['bitrate'] = 0;
1112            $info_video['bitrate'] = 0;
1113
1114            foreach ($info_asf['stream_properties_object'] as $stream_number => $stream_data) {
1115               
1116                switch ($stream_data['stream_type_guid']) {
1117                   
1118                    case getid3_asf::Audio_Media:
1119                   
1120                        // Field Name                   Field Type   Size (bits)
1121                        // Codec ID / Format Tag        WORD         16              // unique ID of audio codec - defined as wFormatTag field of WAVEFORMATEX structure
1122                        // Number of Channels           WORD         16              // number of channels of audio - defined as nChannels field of WAVEFORMATEX structure
1123                        // Samples Per Second           DWORD        32              // in Hertz - defined as nSamplesPerSec field of WAVEFORMATEX structure
1124                        // Average number of Bytes/sec  DWORD        32              // bytes/sec of audio stream  - defined as nAvgBytesPerSec field of WAVEFORMATEX structure
1125                        // Block Alignment              WORD         16              // block size in bytes of audio codec - defined as nBlockAlign field of WAVEFORMATEX structure
1126                        // Bits per sample              WORD         16              // bits per sample of mono data. set to zero for variable bitrate codecs. defined as wBitsPerSample field of WAVEFORMATEX structure
1127                        // Codec Specific Data Size     WORD         16              // size in bytes of Codec Specific Data buffer - defined as cbSize field of WAVEFORMATEX structure
1128                        // Codec Specific Data          BYTESTREAM   variable        // array of codec-specific data bytes
1129
1130                        // shortcut
1131                        $info_asf['audio_media'][$stream_number] = array ();
1132                        $info_asf_audio_media_current_stream     = &$info_asf['audio_media'][$stream_number];
1133
1134                        $audio_media_offset = 0;
1135
1136                        $info_asf_audio_media_current_stream = getid3_riff::RIFFparseWAVEFORMATex(substr($stream_data['type_specific_data'], $audio_media_offset, 16));
1137
1138                        $audio_media_offset += 16;
1139
1140                        $info_audio['lossless'] = false;
1141                        switch ($info_asf_audio_media_current_stream['raw']['wFormatTag']) {
1142                            case 0x0001: // PCM
1143                            case 0x0163: // WMA9 Lossless
1144                                $info_audio['lossless'] = true;
1145                                break;
1146                        }
1147
1148                        if (!empty($info_asf['stream_bitrate_properties_object']['bitrate_records'])) {
1149                                                        foreach ($info_asf['stream_bitrate_properties_object']['bitrate_records'] as $data_array) {
1150                                                                if (@$data_array['flags']['stream_number'] == $stream_number) {
1151                                                                        $info_asf_audio_media_current_stream['bitrate'] = $data_array['bitrate'];
1152                                                                        $info_audio['bitrate'] += $data_array['bitrate'];
1153                                                                        break;
1154                                                                }
1155                                                        }
1156                                                } else {
1157                                                        if (@$info_asf_audio_media_current_stream['bytes_sec']) {
1158                                                                $info_audio['bitrate'] += $info_asf_audio_media_current_stream['bytes_sec'] * 8;
1159                                                        } elseif (@$info_asf_audio_media_current_stream['bitrate']) {
1160                                                                $info_audio['bitrate'] += $info_asf_audio_media_current_stream['bitrate'];
1161                                                        }
1162                                                }
1163                       
1164                        $info_audio['streams'][$stream_number]                  = $info_asf_audio_media_current_stream;
1165                        $info_audio['streams'][$stream_number]['wformattag']    = $info_asf_audio_media_current_stream['raw']['wFormatTag'];
1166                        $info_audio['streams'][$stream_number]['lossless']      = $info_audio['lossless'];
1167                        $info_audio['streams'][$stream_number]['bitrate']       = $info_audio['bitrate'];
1168                        unset($info_audio['streams'][$stream_number]['raw']);
1169
1170                        $info_asf_audio_media_current_stream['codec_data_size'] = getid3_lib::LittleEndian2Int(substr($stream_data['type_specific_data'], $audio_media_offset, 2));
1171                        $audio_media_offset += 2;
1172                       
1173                        $info_asf_audio_media_current_stream['codec_data']      = substr($stream_data['type_specific_data'], $audio_media_offset, $info_asf_audio_media_current_stream['codec_data_size']);
1174                        $audio_media_offset += $info_asf_audio_media_current_stream['codec_data_size'];
1175                        break;
1176
1177
1178                    case getid3_asf::Video_Media:
1179
1180                        // Field Name                   Field Type   Size (bits)
1181                        // Encoded Image Width          DWORD        32              // width of image in pixels
1182                        // Encoded Image Height         DWORD        32              // height of image in pixels
1183                        // Reserved Flags               BYTE         8               // hardcoded: 0x02
1184                        // Format Data Size             WORD         16              // size of Format Data field in bytes
1185                        // Format Data                  array of:    variable        //
1186                        // * Format Data Size           DWORD        32              // number of bytes in Format Data field, in bytes - defined as biSize field of BITMAPINFOHEADER structure
1187                        // * Image Width                LONG         32              // width of encoded image in pixels - defined as biWidth field of BITMAPINFOHEADER structure
1188                        // * Image Height               LONG         32              // height of encoded image in pixels - defined as biHeight field of BITMAPINFOHEADER structure
1189                        // * Reserved                   WORD         16              // hardcoded: 0x0001 - defined as biPlanes field of BITMAPINFOHEADER structure
1190                        // * Bits Per Pixel Count       WORD         16              // bits per pixel - defined as biBitCount field of BITMAPINFOHEADER structure
1191                        // * Compression ID             FOURCC       32              // fourcc of video codec - defined as biCompression field of BITMAPINFOHEADER structure
1192                        // * Image Size                 DWORD        32              // image size in bytes - defined as biSizeImage field of BITMAPINFOHEADER structure
1193                        // * Horizontal Pixels / Meter  DWORD        32              // horizontal resolution of target device in pixels per meter - defined as biXPelsPerMeter field of BITMAPINFOHEADER structure
1194                        // * Vertical Pixels / Meter    DWORD        32              // vertical resolution of target device in pixels per meter - defined as biYPelsPerMeter field of BITMAPINFOHEADER structure
1195                        // * Colors Used Count          DWORD        32              // number of color indexes in the color table that are actually used - defined as biClrUsed field of BITMAPINFOHEADER structure
1196                        // * Important Colors Count     DWORD        32              // number of color index required for displaying bitmap. if zero, all colors are required. defined as biClrImportant field of BITMAPINFOHEADER structure
1197                        // * Codec Specific Data        BYTESTREAM   variable        // array of codec-specific data bytes
1198
1199                        $info_asf['video_media'][$stream_number] = array ();
1200                        $info_asf_video_media_current_stream     = &$info_asf['video_media'][$stream_number];
1201
1202                        getid3_lib::ReadSequence('LittleEndian2Int', $info_asf_video_media_current_stream, $stream_data['type_specific_data'], 0, 
1203                            array (
1204                                'image_width'     => 4,
1205                                'image_height'    => 4,
1206                                'flags'           => 1,
1207                                'format_data_size'=> 2
1208                            )
1209                        );
1210                       
1211                        getid3_lib::ReadSequence('LittleEndian2Int', $info_asf_video_media_current_stream['format_data'], $stream_data['type_specific_data'], 11, 
1212                            array (
1213                                'format_data_size' => 4,
1214                                'image_width'      => 4,
1215                                'image_height'     => 4,
1216                                'reserved'         => 2,
1217                                'bits_per_pixel'   => 2,
1218                                'codec_fourcc'     => -4,
1219                                'image_size'       => 4,
1220                                'horizontal_pels'  => 4,
1221                                'vertical_pels'    => 4,
1222                                'colors_used'      => 4,
1223                                'colors_important' => 4
1224                            )
1225                        );
1226                           
1227                        $info_asf_video_media_current_stream['format_data']['codec_data'] = substr($stream_data['type_specific_data'], 51);
1228                       
1229                        if (!empty($info_asf['stream_bitrate_properties_object']['bitrate_records'])) {
1230                            foreach ($info_asf['stream_bitrate_properties_object']['bitrate_records'] as $data_array) {
1231                                if (@$data_array['flags']['stream_number'] == $stream_number) {
1232                                    $info_asf_video_media_current_stream['bitrate']   = $data_array['bitrate'];
1233                                    $info_video['streams'][$stream_number]['bitrate'] = $data_array['bitrate'];
1234                                    $info_video['bitrate'] += $data_array['bitrate'];
1235                                   
1236                                    break;
1237                                }
1238                            }
1239                        }
1240                       
1241                        $info_asf_video_media_current_stream['format_data']['codec'] = getid3_riff::RIFFfourccLookup($info_asf_video_media_current_stream['format_data']['codec_fourcc']);
1242
1243                        $info_video['streams'][$stream_number]['fourcc']          = $info_asf_video_media_current_stream['format_data']['codec_fourcc'];
1244                        $info_video['streams'][$stream_number]['codec']           = $info_asf_video_media_current_stream['format_data']['codec'];
1245                        $info_video['streams'][$stream_number]['resolution_x']    = $info_asf_video_media_current_stream['image_width'];
1246                        $info_video['streams'][$stream_number]['resolution_y']    = $info_asf_video_media_current_stream['image_height'];
1247                        $info_video['streams'][$stream_number]['bits_per_sample'] = $info_asf_video_media_current_stream['format_data']['bits_per_pixel'];
1248                        break;
1249
1250                    default:
1251                        break;
1252                }
1253            }
1254        }
1255
1256        while (ftell($getid3->fp) < $getid3->info['avdataend']) {
1257           
1258            $next_object_data_header = fread($getid3->fp, 24);
1259            $offset = 0;
1260           
1261            $next_object_guid = substr($next_object_data_header, 0, 16);
1262            $offset += 16;
1263           
1264            $next_object_guidtext = getid3_asf::BytestringToGUID($next_object_guid);
1265            $next_object_size     = getid3_lib::LittleEndian2Int(substr($next_object_data_header, $offset, 8));
1266            $offset += 8;
1267
1268            switch ($next_object_guidtext) {
1269               
1270                case getid3_asf::Data_Object:
1271               
1272                    // Data Object: (mandatory, one only)
1273                    // Field Name                       Field Type   Size (bits)
1274                    // Object ID                        GUID         128             // GUID for Data object - getid3_asf::Data_Object
1275                    // Object Size                      QWORD        64              // size of Data object, including 50 bytes of Data Object header. may be 0 if FilePropertiesObject.BroadcastFlag == 1
1276                    // File ID                          GUID         128             // unique identifier. identical to File ID field in Header Object
1277                    // Total Data Packets               QWORD        64              // number of Data Packet entries in Data Object. invalid if FilePropertiesObject.BroadcastFlag == 1
1278                    // Reserved                         WORD         16              // hardcoded: 0x0101
1279
1280                    // shortcut
1281                    $info_asf['data_object'] = array ();
1282                    $info_asf_data_object    = &$info_asf['data_object'];
1283
1284                    $data_object_data = $next_object_data_header.fread($getid3->fp, 50 - 24);
1285                    $offset = 24;
1286
1287                    $info_asf_data_object['objectid_guid']      = $next_object_guidtext;
1288                    $info_asf_data_object['objectsize']         = $next_object_size;
1289
1290                    $info_asf_data_object['fileid_guid']        = getid3_asf::BytestringToGUID(substr($data_object_data, $offset, 16));
1291                    $offset += 16;
1292                   
1293                    $info_asf_data_object['total_data_packets'] = getid3_lib::LittleEndian2Int(substr($data_object_data, $offset, 8));
1294                    $offset += 8;
1295                   
1296                    $info_asf_data_object['reserved']           = getid3_lib::LittleEndian2Int(substr($data_object_data, $offset, 2));
1297                    $offset += 2;
1298                   
1299                    if ($info_asf_data_object['reserved'] != 0x0101) {
1300                        $getid3->warning('data_object.reserved ('.getid3_lib::PrintHexBytes($info_asf_data_object['reserved']).') does not match expected value of "0x0101"');
1301                        break;
1302                    }
1303
1304                    // Data Packets                     array of:    variable        //
1305                    // * Error Correction Flags         BYTE         8               //
1306                    // * * Error Correction Data Length bits         4               // if Error Correction Length Type == 00, size of Error Correction Data in bytes, else hardcoded: 0000
1307                    // * * Opaque Data Present          bits         1               //
1308                    // * * Error Correction Length Type bits         2               // number of bits for size of the error correction data. hardcoded: 00
1309                    // * * Error Correction Present     bits         1               // If set, use Opaque Data Packet structure, else use Payload structure
1310                    // * Error Correction Data
1311
1312                    $getid3->info['avdataoffset'] = ftell($getid3->fp);
1313                    fseek($getid3->fp, ($info_asf_data_object['objectsize'] - 50), SEEK_CUR); // skip actual audio/video data
1314                    $getid3->info['avdataend'] = ftell($getid3->fp);
1315                    break;
1316
1317
1318                case getid3_asf::Simple_Index_Object:
1319
1320                    // Simple Index Object: (optional, recommended, one per video stream)
1321                    // Field Name                       Field Type   Size (bits)
1322                    // Object ID                        GUID         128             // GUID for Simple Index object - getid3_asf::Data_Object
1323                    // Object Size                      QWORD        64              // size of Simple Index object, including 56 bytes of Simple Index Object header
1324                    // File ID                          GUID         128             // unique identifier. may be zero or identical to File ID field in Data Object and Header Object
1325                    // Index Entry Time Interval        QWORD        64              // interval between index entries in 100-nanosecond units
1326                    // Maximum Packet Count             DWORD        32              // maximum packet count for all index entries
1327                    // Index Entries Count              DWORD        32              // number of Index Entries structures
1328                    // Index Entries                    array of:    variable        //
1329                    // * Packet Number                  DWORD        32              // number of the Data Packet associated with this index entry
1330                    // * Packet Count                   WORD         16              // number of Data Packets to sent at this index entry
1331
1332                    // shortcut
1333                    $info_asf['simple_index_object'] = array ();
1334                    $info_asf_simple_index_object    = &$info_asf['simple_index_object'];
1335
1336                    $info_asf_simple_index_object['objectid_guid'] = $next_object_guidtext;
1337                    $info_asf_simple_index_object['objectsize']    = $next_object_size;
1338
1339                    $simple_index_object_data = $next_object_data_header.fread($getid3->fp, 56 - 24);
1340                   
1341                    $info_asf_simple_index_object['fileid_guid'] = getid3_asf::BytestringToGUID(substr($simple_index_object_data, 24, 16));
1342
1343                    getid3_lib::ReadSequence('LittleEndian2Int', $info_asf_simple_index_object, $simple_index_object_data, 40,
1344                        array (
1345                            'index_entry_time_interval' => 8,
1346                            'maximum_packet_count'      => 4,
1347                            'index_entries_count'       => 4
1348                        )
1349                    );
1350                   
1351                    $offset = 56;
1352
1353                    $index_entries_data = $simple_index_object_data.fread($getid3->fp, 6 * $info_asf_simple_index_object['index_entries_count']);
1354                    for ($index_entries_counter = 0; $index_entries_counter < $info_asf_simple_index_object['index_entries_count']; $index_entries_counter++) {
1355                   
1356                        $info_asf_simple_index_object['index_entries'][$index_entries_counter]['packet_number'] = getid3_lib::LittleEndian2Int(substr($index_entries_data, $offset, 4));
1357                        $offset += 4;
1358                   
1359                        $info_asf_simple_index_object['index_entries'][$index_entries_counter]['packet_count']  = getid3_lib::LittleEndian2Int(substr($index_entries_data, $offset, 4));
1360                        $offset += 2;
1361                    }
1362                    break;
1363
1364
1365                case getid3_asf::Index_Object:
1366
1367                    // 6.2 ASF top-level Index Object (optional but recommended when appropriate, 0 or 1)
1368                    // Field Name                       Field Type   Size (bits)
1369                    // Object ID                        GUID         128             // GUID for the Index Object - getid3_asf::Index_Object
1370                    // Object Size                      QWORD        64              // Specifies the size, in bytes, of the Index Object, including at least 34 bytes of Index Object header
1371                    // Index Entry Time Interval        DWORD        32              // Specifies the time interval between each index entry in ms.
1372                    // Index Specifiers Count           WORD         16              // Specifies the number of Index Specifiers structures in this Index Object.
1373                    // Index Blocks Count               DWORD        32              // Specifies the number of Index Blocks structures in this Index Object.
1374
1375                    // Index Entry Time Interval        DWORD        32              // Specifies the time interval between index entries in milliseconds.  This value cannot be 0.
1376                    // Index Specifiers Count           WORD         16              // Specifies the number of entries in the Index Specifiers list.  Valid values are 1 and greater.
1377                    // Index Specifiers                 array of:    varies          //
1378                    // * Stream Number                  WORD         16              // Specifies the stream number that the Index Specifiers refer to. Valid values are between 1 and 127.
1379                    // * Index Type                     WORD         16              // Specifies Index Type values as follows:
1380                                                                                     //   1 = Nearest Past Data Packet - indexes point to the data packet whose presentation time is closest to the index entry time.
1381                                                                                     //   2 = Nearest Past Media Object - indexes point to the closest data packet containing an entire object or first fragment of an object.
1382                                                                                     //   3 = Nearest Past Cleanpoint. - indexes point to the closest data packet containing an entire object (or first fragment of an object) that has the Cleanpoint Flag set.
1383                                                                                     //   Nearest Past Cleanpoint is the most common type of index.
1384                    // Index Entry Count                DWORD        32              // Specifies the number of Index Entries in the block.
1385                    // * Block Positions                QWORD        varies          // Specifies a list of byte offsets of the beginnings of the blocks relative to the beginning of the first Data Packet (i.e., the beginning of the Data Object + 50 bytes). The number of entries in this list is specified by the value of the Index Specifiers Count field. The order of those byte offsets is tied to the order in which Index Specifiers are listed.
1386                    // * Index Entries                  array of:    varies          //
1387                    // * * Offsets                      DWORD        varies          // An offset value of 0xffffffff indicates an invalid offset value
1388
1389                    // shortcut
1390                    $info_asf['asf_index_object'] = array ();
1391                    $info_asf_asf_index_object      = &$info_asf['asf_index_object'];
1392
1393                    $asf_index_object_data = $next_object_data_header.fread($getid3->fp, 34 - 24);
1394
1395                    $info_asf_asf_index_object['objectid_guid'] = $next_object_guidtext;
1396                    $info_asf_asf_index_object['objectsize']    = $next_object_size;
1397
1398                    getid3_lib::ReadSequence('LittleEndian2Int', $info_asf_asf_index_object, $asf_index_object_data, 24, 
1399                        array (
1400                            'entry_time_interval'    =>4,
1401                            'index_specifiers_count' =>2,
1402                            'index_blocks_count'     =>4
1403                        )
1404                    );
1405
1406                    $offset = 34;
1407
1408                    $asf_index_object_data .= fread($getid3->fp, 4 * $info_asf_asf_index_object['index_specifiers_count']);
1409                   
1410                    for ($index_specifiers_counter = 0; $index_specifiers_counter < $info_asf_asf_index_object['index_specifiers_count']; $index_specifiers_counter++) {
1411                   
1412                        $index_specifier_stream_number = getid3_lib::LittleEndian2Int(substr($asf_index_object_data, $offset, 2));
1413                        $offset += 2;
1414                       
1415                        $info_asf_asf_index_object['index_specifiers'][$index_specifiers_counter]['stream_number']   = $index_specifier_stream_number;
1416                       
1417                        $info_asf_asf_index_object['index_specifiers'][$index_specifiers_counter]['index_type']      = getid3_lib::LittleEndian2Int(substr($asf_index_object_data, $offset, 2));
1418                        $offset += 2;
1419                       
1420                        $info_asf_asf_index_object['index_specifiers'][$index_specifiers_counter]['index_type_text'] = getid3_asf::ASFIndexObjectIndexTypeLookup($info_asf_asf_index_object['index_specifiers'][$index_specifiers_counter]['index_type']);
1421                    }
1422
1423                    $asf_index_object_data .= fread($getid3->fp, 4);
1424                    $info_asf_asf_index_object['index_entry_count'] = getid3_lib::LittleEndian2Int(substr($asf_index_object_data, $offset, 4));
1425                    $offset += 4;
1426
1427                    $asf_index_object_data .= fread($getid3->fp, 8 * $info_asf_asf_index_object['index_specifiers_count']);
1428                   
1429                    for ($index_specifiers_counter = 0; $index_specifiers_counter < $info_asf_asf_index_object['index_specifiers_count']; $index_specifiers_counter++) {
1430                        $info_asf_asf_index_object['block_positions'][$index_specifiers_counter] = getid3_lib::LittleEndian2Int(substr($asf_index_object_data, $offset, 8));
1431                        $offset += 8;
1432                    }
1433
1434                    $asf_index_object_data .= fread($getid3->fp, 4 * $info_asf_asf_index_object['index_specifiers_count'] * $info_asf_asf_index_object['index_entry_count']);
1435                   
1436                    for ($index_entry_counter = 0; $index_entry_counter < $info_asf_asf_index_object['index_entry_count']; $index_entry_counter++) {
1437                        for ($index_specifiers_counter = 0; $index_specifiers_counter < $info_asf_asf_index_object['index_specifiers_count']; $index_specifiers_counter++) {
1438                            $info_asf_asf_index_object['offsets'][$index_specifiers_counter][$index_entry_counter] = getid3_lib::LittleEndian2Int(substr($asf_index_object_data, $offset, 4));
1439                            $offset += 4;
1440                        }
1441                    }
1442                    break;
1443
1444
1445                default:
1446                   
1447                    // Implementations shall ignore any standard or non-standard object that they do not know how to handle.
1448                    if (getid3_asf::GUIDname($next_object_guidtext)) {
1449                        $getid3->warning('unhandled GUID "'.getid3_asf::GUIDname($next_object_guidtext).'" {'.$next_object_guidtext.'} in ASF body at offset '.($offset - 16 - 8));
1450                    } else {
1451                        $getid3->warning('unknown GUID {'.$next_object_guidtext.'} in ASF body at offset '.(ftell($getid3->fp) - 16 - 8));
1452                    }
1453                    fseek($getid3->fp, ($next_object_size - 16 - 8), SEEK_CUR);
1454                    break;
1455            }
1456        }
1457
1458        if (isset($info_asf_codec_list_object['codec_entries']) && is_array($info_asf_codec_list_object['codec_entries'])) {
1459            foreach ($info_asf_codec_list_object['codec_entries'] as $stream_number => $stream_data) {
1460                switch ($stream_data['information']) {
1461                    case 'WMV1':
1462                    case 'WMV2':
1463                    case 'WMV3':
1464                    case 'MSS1':
1465                    case 'MSS2':
1466                    case 'WMVA':
1467                    case 'WVC1':
1468                    case 'WMVP':
1469                    case 'WVP2': 
1470                        $info_video['dataformat'] = 'wmv';
1471                        $getid3->info['mime_type']    = 'video/x-ms-wmv';
1472                        break;
1473
1474                    case 'MP42':
1475                    case 'MP43':
1476                    case 'MP4S':
1477                    case 'mp4s':
1478                        $info_video['dataformat'] = 'asf';
1479                        $getid3->info['mime_type']    = 'video/x-ms-asf';
1480                        break;
1481
1482                    default:
1483                        switch ($stream_data['type_raw']) {
1484                            case 1:
1485                                if (strstr($this->TrimConvert($stream_data['name']), 'Windows Media')) {
1486                                    $info_video['dataformat'] = 'wmv';
1487                                    if ($getid3->info['mime_type'] == 'video/x-ms-asf') {
1488                                        $getid3->info['mime_type'] = 'video/x-ms-wmv';
1489                                    }
1490                                }
1491                                break;
1492
1493                            case 2:
1494                                if (strstr($this->TrimConvert($stream_data['name']), 'Windows Media')) {
1495                                    $info_audio['dataformat'] = 'wma';
1496                                    if ($getid3->info['mime_type'] == 'video/x-ms-asf') {
1497                                        $getid3->info['mime_type'] = 'audio/x-ms-wma';
1498                                    }
1499                                }
1500                                break;
1501
1502                        }
1503                        break;
1504                }
1505            }
1506        }
1507
1508        switch (@$info_audio['codec']) {
1509            case 'MPEG Layer-3':
1510                $info_audio['dataformat'] = 'mp3';
1511                break;
1512
1513            default:
1514                break;
1515        }
1516
1517        if (isset($info_asf_codec_list_object['codec_entries'])) {
1518            foreach ($info_asf_codec_list_object['codec_entries'] as $stream_number => $stream_data) {
1519                switch ($stream_data['type_raw']) {
1520
1521                    case 1: // video
1522                        $info_video['encoder'] = $this->TrimConvert($info_asf_codec_list_object['codec_entries'][$stream_number]['name']);
1523                        break;
1524
1525                    case 2: // audio
1526                        $info_audio['encoder']         = $this->TrimConvert($info_asf_codec_list_object['codec_entries'][$stream_number]['name']);
1527                        $info_audio['encoder_options'] = $this->TrimConvert($info_asf_codec_list_object['codec_entries'][0]['description']);
1528                        $info_audio['codec']           = $info_audio['encoder'];
1529                        break;
1530
1531                    default:
1532                        $getid3->warning('Unknown streamtype: [codec_list_object][codec_entries]['.$stream_number.'][type_raw] == '.$stream_data['type_raw']);
1533                        break;
1534
1535                }
1536            }
1537        }
1538
1539        if (isset($getid3->info['audio'])) {
1540            $info_audio['lossless']           = (isset($info_audio['lossless'])           ? $info_audio['lossless']           : false);
1541            $info_audio['dataformat']         = (!empty($info_audio['dataformat'])        ? $info_audio['dataformat']         : 'asf');
1542        }
1543       
1544        if (!empty($info_video['dataformat'])) {
1545            $info_video['lossless']           = (isset($info_audio['lossless'])           ? $info_audio['lossless']           : false);
1546            $info_video['pixel_aspect_ratio'] = (isset($info_audio['pixel_aspect_ratio']) ? $info_audio['pixel_aspect_ratio'] : (float)1);
1547            $info_video['dataformat']         = (!empty($info_video['dataformat'])        ? $info_video['dataformat']         : 'asf');
1548        }
1549       
1550        $getid3->info['bitrate'] = @$info_audio['bitrate'] + @$info_video['bitrate'];
1551             
1552        if (empty($info_audio)) {
1553            unset($getid3->info['audio']);
1554        }
1555       
1556        if (empty($info_video)) {
1557            unset($getid3->info['video']);
1558        }
1559       
1560        return true;
1561    }
1562
1563
1564 
1565    // Remove terminator 00 00 and convert UNICODE to Latin-1
1566    private function TrimConvert($string) {
1567       
1568        // remove terminator, only if present (it should be, but...)
1569        if (substr($string, strlen($string) - 2, 2) == "\x00\x00") {
1570            $string = substr($string, 0, strlen($string) - 2);
1571        }
1572
1573        // convert
1574        return trim($this->getid3->iconv('UTF-16LE', 'ISO-8859-1', $string), ' ');
1575    }
1576
1577
1578
1579    private function WMpictureTypeLookup($wm_picture_type) {
1580       
1581        static $lookup = array (
1582            0x03 => 'Front Cover',
1583            0x04 => 'Back Cover',
1584            0x00 => 'User Defined',
1585            0x05 => 'Leaflet Page',
1586            0x06 => 'Media Label',
1587            0x07 => 'Lead Artist',
1588            0x08 => 'Artist',
1589            0x09 => 'Conductor',
1590            0x0A => 'Band',
1591            0x0B => 'Composer',
1592            0x0C => 'Lyricist',
1593            0x0D => 'Recording Location',
1594            0x0E => 'During Recording',
1595            0x0F => 'During Performance',
1596            0x10 => 'Video Screen Capture',
1597            0x12 => 'Illustration',
1598            0x13 => 'Band Logotype',
1599            0x14 => 'Publisher Logotype'
1600        );
1601       
1602        return isset($lookup[$wm_picture_type]) ? $this->getid3->iconv('ISO-8859-1', 'UTF-16LE', $lookup[$wm_picture_type]) : '';
1603    }
1604
1605
1606
1607    public static function ASFCodecListObjectTypeLookup($codec_list_type) {
1608       
1609        static $lookup = array (
1610            0x0001 => 'Video Codec',
1611            0x0002 => 'Audio Codec',
1612            0xFFFF => 'Unknown Codec'
1613        );
1614
1615        return (isset($lookup[$codec_list_type]) ? $lookup[$codec_list_type] : 'Invalid Codec Type');
1616    }
1617
1618
1619
1620    public static function GUIDname($guid_string) {
1621       
1622        static $lookup = array (
1623            getid3_asf::Extended_Stream_Properties_Object   => 'Extended_Stream_Properties_Object',   
1624            getid3_asf::Padding_Object                      => 'Padding_Object',                     
1625            getid3_asf::Payload_Ext_Syst_Pixel_Aspect_Ratio => 'Payload_Ext_Syst_Pixel_Aspect_Ratio', 
1626            getid3_asf::Script_Command_Object               => 'Script_Command_Object',               
1627            getid3_asf::No_Error_Correction                 => 'No_Error_Correction',                 
1628            getid3_asf::Content_Branding_Object             => 'Content_Branding_Object',             
1629            getid3_asf::Content_Encryption_Object           => 'Content_Encryption_Object',           
1630            getid3_asf::Digital_Signature_Object            => 'Digital_Signature_Object',           
1631            getid3_asf::Extended_Content_Encryption_Object  => 'Extended_Content_Encryption_Object', 
1632            getid3_asf::Simple_Index_Object                 => 'Simple_Index_Object',                 
1633            getid3_asf::Degradable_JPEG_Media               => 'Degradable_JPEG_Media',               
1634            getid3_asf::Payload_Extension_System_Timecode   => 'Payload_Extension_System_Timecode',   
1635            getid3_asf::Binary_Media                        => 'Binary_Media',                       
1636            getid3_asf::Timecode_Index_Object               => 'Timecode_Index_Object',               
1637            getid3_asf::Metadata_Library_Object             => 'Metadata_Library_Object',             
1638            getid3_asf::Reserved_3                          => 'Reserved_3',                         
1639            getid3_asf::Reserved_4                          => 'Reserved_4',                         
1640            getid3_asf::Command_Media                       => 'Command_Media',                       
1641            getid3_asf::Header_Extension_Object             => 'Header_Extension_Object',             
1642            getid3_asf::Media_Object_Index_Parameters_Obj   => 'Media_Object_Index_Parameters_Obj',   
1643            getid3_asf::Header_Object                       => 'Header_Object',                       
1644            getid3_asf::Content_Description_Object          => 'Content_Description_Object',         
1645            getid3_asf::Error_Correction_Object             => 'Error_Correction_Object',             
1646            getid3_asf::Data_Object                         => 'Data_Object',                         
1647            getid3_asf::Web_Stream_Media_Subtype            => 'Web_Stream_Media_Subtype',           
1648            getid3_asf::Stream_Bitrate_Properties_Object    => 'Stream_Bitrate_Properties_Object',   
1649            getid3_asf::Language_List_Object                => 'Language_List_Object',               
1650            getid3_asf::Codec_List_Object                   => 'Codec_List_Object',                   
1651            getid3_asf::Reserved_2                          => 'Reserved_2',                         
1652            getid3_asf::File_Properties_Object              => 'File_Properties_Object',             
1653            getid3_asf::File_Transfer_Media                 => 'File_Transfer_Media',                 
1654            getid3_asf::Old_RTP_Extension_Data              => 'Old_RTP_Extension_Data',             
1655            getid3_asf::Advanced_Mutual_Exclusion_Object    => 'Advanced_Mutual_Exclusion_Object',   
1656            getid3_asf::Bandwidth_Sharing_Object            => 'Bandwidth_Sharing_Object',           
1657            getid3_asf::Reserved_1                          => 'Reserved_1',                         
1658            getid3_asf::Bandwidth_Sharing_Exclusive         => 'Bandwidth_Sharing_Exclusive',         
1659            getid3_asf::Bandwidth_Sharing_Partial           => 'Bandwidth_Sharing_Partial',           
1660            getid3_asf::JFIF_Media                          => 'JFIF_Media',                         
1661            getid3_asf::Stream_Properties_Object            => 'Stream_Properties_Object',           
1662            getid3_asf::Video_Media                         => 'Video_Media',                         
1663            getid3_asf::Audio_Spread                        => 'Audio_Spread',                       
1664            getid3_asf::Metadata_Object                     => 'Metadata_Object',                     
1665            getid3_asf::Payload_Ext_Syst_Sample_Duration    => 'Payload_Ext_Syst_Sample_Duration',   
1666            getid3_asf::Group_Mutual_Exclusion_Object       => 'Group_Mutual_Exclusion_Object',       
1667            getid3_asf::Extended_Content_Description_Object => 'Extended_Content_Description_Object', 
1668            getid3_asf::Stream_Prioritization_Object        => 'Stream_Prioritization_Object',       
1669            getid3_asf::Payload_Ext_System_Content_Type     => 'Payload_Ext_System_Content_Type',     
1670            getid3_asf::Old_File_Properties_Object          => 'Old_File_Properties_Object',         
1671            getid3_asf::Old_ASF_Header_Object               => 'Old_ASF_Header_Object',               
1672            getid3_asf::Old_ASF_Data_Object                 => 'Old_ASF_Data_Object',                 
1673            getid3_asf::Index_Object                        => 'Index_Object',                       
1674            getid3_asf::Old_Stream_Properties_Object        => 'Old_Stream_Properties_Object',       
1675            getid3_asf::Old_Content_Description_Object      => 'Old_Content_Description_Object',     
1676            getid3_asf::Old_Script_Command_Object           => 'Old_Script_Command_Object',           
1677            getid3_asf::Old_Marker_Object                   => 'Old_Marker_Object',                   
1678            getid3_asf::Old_Component_Download_Object       => 'Old_Component_Download_Object',       
1679            getid3_asf::Old_Stream_Group_Object             => 'Old_Stream_Group_Object',             
1680            getid3_asf::Old_Scalable_Object                 => 'Old_Scalable_Object',                 
1681            getid3_asf::Old_Prioritization_Object           => 'Old_Prioritization_Object',           
1682            getid3_asf::Bitrate_Mutual_Exclusion_Object     => 'Bitrate_Mutual_Exclusion_Object',     
1683            getid3_asf::Old_Inter_Media_Dependency_Object   => 'Old_Inter_Media_Dependency_Object',   
1684            getid3_asf::Old_Rating_Object                   => 'Old_Rating_Object',                   
1685            getid3_asf::Index_Parameters_Object             => 'Index_Parameters_Object',             
1686            getid3_asf::Old_Color_Table_Object              => 'Old_Color_Table_Object',             
1687            getid3_asf::Old_Language_List_Object            => 'Old_Language_List_Object',           
1688            getid3_asf::Old_Audio_Media                     => 'Old_Audio_Media',                     
1689            getid3_asf::Old_Video_Media                     => 'Old_Video_Media',                     
1690            getid3_asf::Old_Image_Media                     => 'Old_Image_Media',                     
1691            getid3_asf::Old_Timecode_Media                  => 'Old_Timecode_Media',                 
1692            getid3_asf::Old_Text_Media                      => 'Old_Text_Media',                     
1693            getid3_asf::Old_MIDI_Media                      => 'Old_MIDI_Media',                     
1694            getid3_asf::Old_Command_Media                   => 'Old_Command_Media',                   
1695            getid3_asf::Old_No_Error_Concealment            => 'Old_No_Error_Concealment',           
1696            getid3_asf::Old_Scrambled_Audio                 => 'Old_Scrambled_Audio',                 
1697            getid3_asf::Old_No_Color_Table                  => 'Old_No_Color_Table',                 
1698            getid3_asf::Old_SMPTE_Time                      => 'Old_SMPTE_Time',                     
1699            getid3_asf::Old_ASCII_Text                      => 'Old_ASCII_Text',                     
1700            getid3_asf::Old_Unicode_Text                    => 'Old_Unicode_Text',                   
1701            getid3_asf::Old_HTML_Text                       => 'Old_HTML_Text',                       
1702            getid3_asf::Old_URL_Command                     => 'Old_URL_Command',                     
1703            getid3_asf::Old_Filename_Command                => 'Old_Filename_Command',               
1704            getid3_asf::Old_ACM_Codec                       => 'Old_ACM_Codec',                       
1705            getid3_asf::Old_VCM_Codec                       => 'Old_VCM_Codec',                       
1706            getid3_asf::Old_QuickTime_Codec                 => 'Old_QuickTime_Codec',                 
1707            getid3_asf::Old_DirectShow_Transform_Filter     => 'Old_DirectShow_Transform_Filter',     
1708            getid3_asf::Old_DirectShow_Rendering_Filter     => 'Old_DirectShow_Rendering_Filter',     
1709            getid3_asf::Old_No_Enhancement                  => 'Old_No_Enhancement',                 
1710            getid3_asf::Old_Unknown_Enhancement_Type        => 'Old_Unknown_Enhancement_Type',       
1711            getid3_asf::Old_Temporal_Enhancement            => 'Old_Temporal_Enhancement',           
1712            getid3_asf::Old_Spatial_Enhancement             => 'Old_Spatial_Enhancement',             
1713            getid3_asf::Old_Quality_Enhancement             => 'Old_Quality_Enhancement',             
1714            getid3_asf::Old_Number_of_Channels_Enhancement  => 'Old_Number_of_Channels_Enhancement', 
1715            getid3_asf::Old_Frequency_Response_Enhancement  => 'Old_Frequency_Response_Enhancement', 
1716            getid3_asf::Old_Media_Object                    => 'Old_Media_Object',                   
1717            getid3_asf::Mutex_Language                      => 'Mutex_Language',                     
1718            getid3_asf::Mutex_Bitrate                       => 'Mutex_Bitrate',                       
1719            getid3_asf::Mutex_Unknown                       => 'Mutex_Unknown',                       
1720            getid3_asf::Old_ASF_Placeholder_Object          => 'Old_ASF_Placeholder_Object',         
1721            getid3_asf::Old_Data_Unit_Extension_Object      => 'Old_Data_Unit_Extension_Object',     
1722            getid3_asf::Web_Stream_Format                   => 'Web_Stream_Format',                   
1723            getid3_asf::Payload_Ext_System_File_Name        => 'Payload_Ext_System_File_Name',       
1724            getid3_asf::Marker_Object                       => 'Marker_Object',                       
1725            getid3_asf::Timecode_Index_Parameters_Object    => 'Timecode_Index_Parameters_Object',   
1726            getid3_asf::Audio_Media                         => 'Audio_Media',                         
1727            getid3_asf::Media_Object_Index_Object           => 'Media_Object_Index_Object',           
1728            getid3_asf::Alt_Extended_Content_Encryption_Obj => 'Alt_Extended_Content_Encryption_Obj' 
1729        );
1730       
1731        return @$lookup[$guid_string];
1732    }
1733
1734
1735
1736    public static function ASFIndexObjectIndexTypeLookup($id) {
1737       
1738        static $lookup = array (
1739            1 => 'Nearest Past Data Packet',
1740            2 => 'Nearest Past Media Object',
1741            3 => 'Nearest Past Cleanpoint'
1742        );
1743
1744        return (isset($lookup[$id]) ? $lookup[$id] : 'invalid');
1745    }
1746
1747
1748
1749    public static function GUIDtoBytestring($guid_string) {
1750       
1751        // Microsoft defines these 16-byte (128-bit) GUIDs in the strangest way:
1752        // first 4 bytes are in little-endian order
1753        // next 2 bytes are appended in little-endian order
1754        // next 2 bytes are appended in little-endian order
1755        // next 2 bytes are appended in big-endian order
1756        // next 6 bytes are appended in big-endian order
1757
1758        // AaBbCcDd-EeFf-GgHh-IiJj-KkLlMmNnOoPp is stored as this 16-byte string:
1759        // $Dd $Cc $Bb $Aa $Ff $Ee $Hh $Gg $Ii $Jj $Kk $Ll $Mm $Nn $Oo $Pp
1760
1761        $hex_byte_char_string  = chr(hexdec(substr($guid_string,  6, 2)));
1762        $hex_byte_char_string .= chr(hexdec(substr($guid_string,  4, 2)));
1763        $hex_byte_char_string .= chr(hexdec(substr($guid_string,  2, 2)));
1764        $hex_byte_char_string .= chr(hexdec(substr($guid_string,  0, 2)));
1765
1766        $hex_byte_char_string .= chr(hexdec(substr($guid_string, 11, 2)));
1767        $hex_byte_char_string .= chr(hexdec(substr($guid_string,  9, 2)));
1768
1769        $hex_byte_char_string .= chr(hexdec(substr($guid_string, 16, 2)));
1770        $hex_byte_char_string .= chr(hexdec(substr($guid_string, 14, 2)));
1771
1772        $hex_byte_char_string .= chr(hexdec(substr($guid_string, 19, 2)));
1773        $hex_byte_char_string .= chr(hexdec(substr($guid_string, 21, 2)));
1774
1775        $hex_byte_char_string .= chr(hexdec(substr($guid_string, 24, 2)));
1776        $hex_byte_char_string .= chr(hexdec(substr($guid_string, 26, 2)));
1777        $hex_byte_char_string .= chr(hexdec(substr($guid_string, 28, 2)));
1778        $hex_byte_char_string .= chr(hexdec(substr($guid_string, 30, 2)));
1779        $hex_byte_char_string .= chr(hexdec(substr($guid_string, 32, 2)));
1780        $hex_byte_char_string .= chr(hexdec(substr($guid_string, 34, 2)));
1781
1782        return $hex_byte_char_string;
1783    }
1784
1785
1786
1787    public static function BytestringToGUID($byte_string) {
1788       
1789        $guid_string  = str_pad(dechex(ord($byte_string{3})),  2, '0', STR_PAD_LEFT);
1790        $guid_string .= str_pad(dechex(ord($byte_string{2})),  2, '0', STR_PAD_LEFT);
1791        $guid_string .= str_pad(dechex(ord($byte_string{1})),  2, '0', STR_PAD_LEFT);
1792        $guid_string .= str_pad(dechex(ord($byte_string{0})),  2, '0', STR_PAD_LEFT);
1793        $guid_string .= '-';
1794        $guid_string .= str_pad(dechex(ord($byte_string{5})),  2, '0', STR_PAD_LEFT);
1795        $guid_string .= str_pad(dechex(ord($byte_string{4})),  2, '0', STR_PAD_LEFT);
1796        $guid_string .= '-';
1797        $guid_string .= str_pad(dechex(ord($byte_string{7})),  2, '0', STR_PAD_LEFT);
1798        $guid_string .= str_pad(dechex(ord($byte_string{6})),  2, '0', STR_PAD_LEFT);
1799        $guid_string .= '-';
1800        $guid_string .= str_pad(dechex(ord($byte_string{8})),  2, '0', STR_PAD_LEFT);
1801        $guid_string .= str_pad(dechex(ord($byte_string{9})),  2, '0', STR_PAD_LEFT);
1802        $guid_string .= '-';
1803        $guid_string .= str_pad(dechex(ord($byte_string{10})), 2, '0', STR_PAD_LEFT);
1804        $guid_string .= str_pad(dechex(ord($byte_string{11})), 2, '0', STR_PAD_LEFT);
1805        $guid_string .= str_pad(dechex(ord($byte_string{12})), 2, '0', STR_PAD_LEFT);
1806        $guid_string .= str_pad(dechex(ord($byte_string{13})), 2, '0', STR_PAD_LEFT);
1807        $guid_string .= str_pad(dechex(ord($byte_string{14})), 2, '0', STR_PAD_LEFT);
1808        $guid_string .= str_pad(dechex(ord($byte_string{15})), 2, '0', STR_PAD_LEFT);
1809
1810        return strtoupper($guid_string);
1811    }
1812
1813
1814
1815    public static function FiletimeToUNIXtime($file_time, $round=true) {
1816       
1817        // FILETIME is a 64-bit unsigned integer representing
1818        // the number of 100-nanosecond intervals since January 1, 1601
1819        // UNIX timestamp is number of seconds since January 1, 1970
1820        // 116444736000000000 = 10000000 * 60 * 60 * 24 * 365 * 369 + 89 leap days
1821       
1822        $time = ($file_time - 116444736000000000) / 10000000;
1823       
1824        if ($round) {
1825            return intval(round($time));
1826        }
1827       
1828        return $time;
1829    }
1830
1831
1832
1833    public static function TrimTerm($string) {
1834
1835        // remove terminator, only if present (it should be, but...)
1836        if (substr($string, -2) == "\x00\x00") {
1837            $string = substr($string, 0, -2);
1838        }
1839        return $string;
1840    }
1841
1842
1843}
1844
1845
1846?>
Note: See TracBrowser for help on using the repository browser.