wp/wp-includes/ID3/module.audio-video.asf.php
changeset 0 d970ebf37754
child 5 5e2f62d02dcd
equal deleted inserted replaced
-1:000000000000 0:d970ebf37754
       
     1 <?php
       
     2 /////////////////////////////////////////////////////////////////
       
     3 /// getID3() by James Heinrich <info@getid3.org>               //
       
     4 //  available at http://getid3.sourceforge.net                 //
       
     5 //            or http://www.getid3.org                         //
       
     6 /////////////////////////////////////////////////////////////////
       
     7 // See readme.txt for more details                             //
       
     8 /////////////////////////////////////////////////////////////////
       
     9 //                                                             //
       
    10 // module.audio-video.asf.php                                  //
       
    11 // module for analyzing ASF, WMA and WMV files                 //
       
    12 // dependencies: module.audio-video.riff.php                   //
       
    13 //                                                            ///
       
    14 /////////////////////////////////////////////////////////////////
       
    15 
       
    16 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
       
    17 
       
    18 class getid3_asf extends getid3_handler
       
    19 {
       
    20 
       
    21 	public function __construct(getID3 $getid3) {
       
    22 		parent::__construct($getid3);  // extends getid3_handler::__construct()
       
    23 
       
    24 		// initialize all GUID constants
       
    25 		$GUIDarray = $this->KnownGUIDs();
       
    26 		foreach ($GUIDarray as $GUIDname => $hexstringvalue) {
       
    27 			if (!defined($GUIDname)) {
       
    28 				define($GUIDname, $this->GUIDtoBytestring($hexstringvalue));
       
    29 			}
       
    30 		}
       
    31 	}
       
    32 
       
    33 	public function Analyze() {
       
    34 		$info = &$this->getid3->info;
       
    35 
       
    36 		// Shortcuts
       
    37 		$thisfile_audio = &$info['audio'];
       
    38 		$thisfile_video = &$info['video'];
       
    39 		$info['asf']  = array();
       
    40 		$thisfile_asf = &$info['asf'];
       
    41 		$thisfile_asf['comments'] = array();
       
    42 		$thisfile_asf_comments    = &$thisfile_asf['comments'];
       
    43 		$thisfile_asf['header_object'] = array();
       
    44 		$thisfile_asf_headerobject     = &$thisfile_asf['header_object'];
       
    45 
       
    46 
       
    47 		// ASF structure:
       
    48 		// * Header Object [required]
       
    49 		//   * File Properties Object [required]   (global file attributes)
       
    50 		//   * Stream Properties Object [required] (defines media stream & characteristics)
       
    51 		//   * Header Extension Object [required]  (additional functionality)
       
    52 		//   * Content Description Object          (bibliographic information)
       
    53 		//   * Script Command Object               (commands for during playback)
       
    54 		//   * Marker Object                       (named jumped points within the file)
       
    55 		// * Data Object [required]
       
    56 		//   * Data Packets
       
    57 		// * Index Object
       
    58 
       
    59 		// Header Object: (mandatory, one only)
       
    60 		// Field Name                   Field Type   Size (bits)
       
    61 		// Object ID                    GUID         128             // GUID for header object - GETID3_ASF_Header_Object
       
    62 		// Object Size                  QWORD        64              // size of header object, including 30 bytes of Header Object header
       
    63 		// Number of Header Objects     DWORD        32              // number of objects in header object
       
    64 		// Reserved1                    BYTE         8               // hardcoded: 0x01
       
    65 		// Reserved2                    BYTE         8               // hardcoded: 0x02
       
    66 
       
    67 		$info['fileformat'] = 'asf';
       
    68 
       
    69 		fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
       
    70 		$HeaderObjectData = fread($this->getid3->fp, 30);
       
    71 
       
    72 		$thisfile_asf_headerobject['objectid']      = substr($HeaderObjectData, 0, 16);
       
    73 		$thisfile_asf_headerobject['objectid_guid'] = $this->BytestringToGUID($thisfile_asf_headerobject['objectid']);
       
    74 		if ($thisfile_asf_headerobject['objectid'] != GETID3_ASF_Header_Object) {
       
    75 			$info['warning'][] = 'ASF header GUID {'.$this->BytestringToGUID($thisfile_asf_headerobject['objectid']).'} does not match expected "GETID3_ASF_Header_Object" GUID {'.$this->BytestringToGUID(GETID3_ASF_Header_Object).'}';
       
    76 			unset($info['fileformat']);
       
    77 			unset($info['asf']);
       
    78 			return false;
       
    79 			break;
       
    80 		}
       
    81 		$thisfile_asf_headerobject['objectsize']    = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 16, 8));
       
    82 		$thisfile_asf_headerobject['headerobjects'] = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 24, 4));
       
    83 		$thisfile_asf_headerobject['reserved1']     = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 28, 1));
       
    84 		$thisfile_asf_headerobject['reserved2']     = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 29, 1));
       
    85 
       
    86 		$NextObjectOffset = ftell($this->getid3->fp);
       
    87 		$ASFHeaderData = fread($this->getid3->fp, $thisfile_asf_headerobject['objectsize'] - 30);
       
    88 		$offset = 0;
       
    89 
       
    90 		for ($HeaderObjectsCounter = 0; $HeaderObjectsCounter < $thisfile_asf_headerobject['headerobjects']; $HeaderObjectsCounter++) {
       
    91 			$NextObjectGUID = substr($ASFHeaderData, $offset, 16);
       
    92 			$offset += 16;
       
    93 			$NextObjectGUIDtext = $this->BytestringToGUID($NextObjectGUID);
       
    94 			$NextObjectSize = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
       
    95 			$offset += 8;
       
    96 			switch ($NextObjectGUID) {
       
    97 
       
    98 				case GETID3_ASF_File_Properties_Object:
       
    99 					// File Properties Object: (mandatory, one only)
       
   100 					// Field Name                   Field Type   Size (bits)
       
   101 					// Object ID                    GUID         128             // GUID for file properties object - GETID3_ASF_File_Properties_Object
       
   102 					// Object Size                  QWORD        64              // size of file properties object, including 104 bytes of File Properties Object header
       
   103 					// File ID                      GUID         128             // unique ID - identical to File ID in Data Object
       
   104 					// File Size                    QWORD        64              // entire file in bytes. Invalid if Broadcast Flag == 1
       
   105 					// Creation Date                QWORD        64              // date & time of file creation. Maybe invalid if Broadcast Flag == 1
       
   106 					// Data Packets Count           QWORD        64              // number of data packets in Data Object. Invalid if Broadcast Flag == 1
       
   107 					// Play Duration                QWORD        64              // playtime, in 100-nanosecond units. Invalid if Broadcast Flag == 1
       
   108 					// Send Duration                QWORD        64              // time needed to send file, in 100-nanosecond units. Players can ignore this value. Invalid if Broadcast Flag == 1
       
   109 					// 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
       
   110 					// Flags                        DWORD        32              //
       
   111 					// * Broadcast Flag             bits         1  (0x01)       // file is currently being written, some header values are invalid
       
   112 					// * Seekable Flag              bits         1  (0x02)       // is file seekable
       
   113 					// * Reserved                   bits         30 (0xFFFFFFFC) // reserved - set to zero
       
   114 					// Minimum Data Packet Size     DWORD        32              // in bytes. should be same as Maximum Data Packet Size. Invalid if Broadcast Flag == 1
       
   115 					// Maximum Data Packet Size     DWORD        32              // in bytes. should be same as Minimum Data Packet Size. Invalid if Broadcast Flag == 1
       
   116 					// Maximum Bitrate              DWORD        32              // maximum instantaneous bitrate in bits per second for entire file, including all data streams and ASF overhead
       
   117 
       
   118 					// shortcut
       
   119 					$thisfile_asf['file_properties_object'] = array();
       
   120 					$thisfile_asf_filepropertiesobject      = &$thisfile_asf['file_properties_object'];
       
   121 
       
   122 					$thisfile_asf_filepropertiesobject['offset']             = $NextObjectOffset + $offset;
       
   123 					$thisfile_asf_filepropertiesobject['objectid']           = $NextObjectGUID;
       
   124 					$thisfile_asf_filepropertiesobject['objectid_guid']      = $NextObjectGUIDtext;
       
   125 					$thisfile_asf_filepropertiesobject['objectsize']         = $NextObjectSize;
       
   126 					$thisfile_asf_filepropertiesobject['fileid']             = substr($ASFHeaderData, $offset, 16);
       
   127 					$offset += 16;
       
   128 					$thisfile_asf_filepropertiesobject['fileid_guid']        = $this->BytestringToGUID($thisfile_asf_filepropertiesobject['fileid']);
       
   129 					$thisfile_asf_filepropertiesobject['filesize']           = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
       
   130 					$offset += 8;
       
   131 					$thisfile_asf_filepropertiesobject['creation_date']      = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
       
   132 					$thisfile_asf_filepropertiesobject['creation_date_unix'] = $this->FILETIMEtoUNIXtime($thisfile_asf_filepropertiesobject['creation_date']);
       
   133 					$offset += 8;
       
   134 					$thisfile_asf_filepropertiesobject['data_packets']       = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
       
   135 					$offset += 8;
       
   136 					$thisfile_asf_filepropertiesobject['play_duration']      = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
       
   137 					$offset += 8;
       
   138 					$thisfile_asf_filepropertiesobject['send_duration']      = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
       
   139 					$offset += 8;
       
   140 					$thisfile_asf_filepropertiesobject['preroll']            = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
       
   141 					$offset += 8;
       
   142 					$thisfile_asf_filepropertiesobject['flags_raw']          = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
       
   143 					$offset += 4;
       
   144 					$thisfile_asf_filepropertiesobject['flags']['broadcast'] = (bool) ($thisfile_asf_filepropertiesobject['flags_raw'] & 0x0001);
       
   145 					$thisfile_asf_filepropertiesobject['flags']['seekable']  = (bool) ($thisfile_asf_filepropertiesobject['flags_raw'] & 0x0002);
       
   146 
       
   147 					$thisfile_asf_filepropertiesobject['min_packet_size']    = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
       
   148 					$offset += 4;
       
   149 					$thisfile_asf_filepropertiesobject['max_packet_size']    = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
       
   150 					$offset += 4;
       
   151 					$thisfile_asf_filepropertiesobject['max_bitrate']        = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
       
   152 					$offset += 4;
       
   153 
       
   154 					if ($thisfile_asf_filepropertiesobject['flags']['broadcast']) {
       
   155 
       
   156 						// broadcast flag is set, some values invalid
       
   157 						unset($thisfile_asf_filepropertiesobject['filesize']);
       
   158 						unset($thisfile_asf_filepropertiesobject['data_packets']);
       
   159 						unset($thisfile_asf_filepropertiesobject['play_duration']);
       
   160 						unset($thisfile_asf_filepropertiesobject['send_duration']);
       
   161 						unset($thisfile_asf_filepropertiesobject['min_packet_size']);
       
   162 						unset($thisfile_asf_filepropertiesobject['max_packet_size']);
       
   163 
       
   164 					} else {
       
   165 
       
   166 						// broadcast flag NOT set, perform calculations
       
   167 						$info['playtime_seconds'] = ($thisfile_asf_filepropertiesobject['play_duration'] / 10000000) - ($thisfile_asf_filepropertiesobject['preroll'] / 1000);
       
   168 
       
   169 						//$info['bitrate'] = $thisfile_asf_filepropertiesobject['max_bitrate'];
       
   170 						$info['bitrate'] = ((isset($thisfile_asf_filepropertiesobject['filesize']) ? $thisfile_asf_filepropertiesobject['filesize'] : $info['filesize']) * 8) / $info['playtime_seconds'];
       
   171 					}
       
   172 					break;
       
   173 
       
   174 				case GETID3_ASF_Stream_Properties_Object:
       
   175 					// Stream Properties Object: (mandatory, one per media stream)
       
   176 					// Field Name                   Field Type   Size (bits)
       
   177 					// Object ID                    GUID         128             // GUID for stream properties object - GETID3_ASF_Stream_Properties_Object
       
   178 					// Object Size                  QWORD        64              // size of stream properties object, including 78 bytes of Stream Properties Object header
       
   179 					// Stream Type                  GUID         128             // GETID3_ASF_Audio_Media, GETID3_ASF_Video_Media or GETID3_ASF_Command_Media
       
   180 					// Error Correction Type        GUID         128             // GETID3_ASF_Audio_Spread for audio-only streams, GETID3_ASF_No_Error_Correction for other stream types
       
   181 					// Time Offset                  QWORD        64              // 100-nanosecond units. typically zero. added to all timestamps of samples in the stream
       
   182 					// Type-Specific Data Length    DWORD        32              // number of bytes for Type-Specific Data field
       
   183 					// Error Correction Data Length DWORD        32              // number of bytes for Error Correction Data field
       
   184 					// Flags                        WORD         16              //
       
   185 					// * Stream Number              bits         7 (0x007F)      // number of this stream.  1 <= valid <= 127
       
   186 					// * Reserved                   bits         8 (0x7F80)      // reserved - set to zero
       
   187 					// * Encrypted Content Flag     bits         1 (0x8000)      // stream contents encrypted if set
       
   188 					// Reserved                     DWORD        32              // reserved - set to zero
       
   189 					// Type-Specific Data           BYTESTREAM   variable        // type-specific format data, depending on value of Stream Type
       
   190 					// Error Correction Data        BYTESTREAM   variable        // error-correction-specific format data, depending on value of Error Correct Type
       
   191 
       
   192 					// There is one GETID3_ASF_Stream_Properties_Object for each stream (audio, video) but the
       
   193 					// stream number isn't known until halfway through decoding the structure, hence it
       
   194 					// it is decoded to a temporary variable and then stuck in the appropriate index later
       
   195 
       
   196 					$StreamPropertiesObjectData['offset']             = $NextObjectOffset + $offset;
       
   197 					$StreamPropertiesObjectData['objectid']           = $NextObjectGUID;
       
   198 					$StreamPropertiesObjectData['objectid_guid']      = $NextObjectGUIDtext;
       
   199 					$StreamPropertiesObjectData['objectsize']         = $NextObjectSize;
       
   200 					$StreamPropertiesObjectData['stream_type']        = substr($ASFHeaderData, $offset, 16);
       
   201 					$offset += 16;
       
   202 					$StreamPropertiesObjectData['stream_type_guid']   = $this->BytestringToGUID($StreamPropertiesObjectData['stream_type']);
       
   203 					$StreamPropertiesObjectData['error_correct_type'] = substr($ASFHeaderData, $offset, 16);
       
   204 					$offset += 16;
       
   205 					$StreamPropertiesObjectData['error_correct_guid'] = $this->BytestringToGUID($StreamPropertiesObjectData['error_correct_type']);
       
   206 					$StreamPropertiesObjectData['time_offset']        = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
       
   207 					$offset += 8;
       
   208 					$StreamPropertiesObjectData['type_data_length']   = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
       
   209 					$offset += 4;
       
   210 					$StreamPropertiesObjectData['error_data_length']  = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
       
   211 					$offset += 4;
       
   212 					$StreamPropertiesObjectData['flags_raw']          = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
       
   213 					$offset += 2;
       
   214 					$StreamPropertiesObjectStreamNumber               = $StreamPropertiesObjectData['flags_raw'] & 0x007F;
       
   215 					$StreamPropertiesObjectData['flags']['encrypted'] = (bool) ($StreamPropertiesObjectData['flags_raw'] & 0x8000);
       
   216 
       
   217 					$offset += 4; // reserved - DWORD
       
   218 					$StreamPropertiesObjectData['type_specific_data'] = substr($ASFHeaderData, $offset, $StreamPropertiesObjectData['type_data_length']);
       
   219 					$offset += $StreamPropertiesObjectData['type_data_length'];
       
   220 					$StreamPropertiesObjectData['error_correct_data'] = substr($ASFHeaderData, $offset, $StreamPropertiesObjectData['error_data_length']);
       
   221 					$offset += $StreamPropertiesObjectData['error_data_length'];
       
   222 
       
   223 					switch ($StreamPropertiesObjectData['stream_type']) {
       
   224 
       
   225 						case GETID3_ASF_Audio_Media:
       
   226 							$thisfile_audio['dataformat']   = (!empty($thisfile_audio['dataformat'])   ? $thisfile_audio['dataformat']   : 'asf');
       
   227 							$thisfile_audio['bitrate_mode'] = (!empty($thisfile_audio['bitrate_mode']) ? $thisfile_audio['bitrate_mode'] : 'cbr');
       
   228 
       
   229 							$audiodata = getid3_riff::parseWAVEFORMATex(substr($StreamPropertiesObjectData['type_specific_data'], 0, 16));
       
   230 							unset($audiodata['raw']);
       
   231 							$thisfile_audio = getid3_lib::array_merge_noclobber($audiodata, $thisfile_audio);
       
   232 							break;
       
   233 
       
   234 						case GETID3_ASF_Video_Media:
       
   235 							$thisfile_video['dataformat']   = (!empty($thisfile_video['dataformat'])   ? $thisfile_video['dataformat']   : 'asf');
       
   236 							$thisfile_video['bitrate_mode'] = (!empty($thisfile_video['bitrate_mode']) ? $thisfile_video['bitrate_mode'] : 'cbr');
       
   237 							break;
       
   238 
       
   239 						case GETID3_ASF_Command_Media:
       
   240 						default:
       
   241 							// do nothing
       
   242 							break;
       
   243 
       
   244 					}
       
   245 
       
   246 					$thisfile_asf['stream_properties_object'][$StreamPropertiesObjectStreamNumber] = $StreamPropertiesObjectData;
       
   247 					unset($StreamPropertiesObjectData); // clear for next stream, if any
       
   248 					break;
       
   249 
       
   250 				case GETID3_ASF_Header_Extension_Object:
       
   251 					// Header Extension Object: (mandatory, one only)
       
   252 					// Field Name                   Field Type   Size (bits)
       
   253 					// Object ID                    GUID         128             // GUID for Header Extension object - GETID3_ASF_Header_Extension_Object
       
   254 					// Object Size                  QWORD        64              // size of Header Extension object, including 46 bytes of Header Extension Object header
       
   255 					// Reserved Field 1             GUID         128             // hardcoded: GETID3_ASF_Reserved_1
       
   256 					// Reserved Field 2             WORD         16              // hardcoded: 0x00000006
       
   257 					// Header Extension Data Size   DWORD        32              // in bytes. valid: 0, or > 24. equals object size minus 46
       
   258 					// Header Extension Data        BYTESTREAM   variable        // array of zero or more extended header objects
       
   259 
       
   260 					// shortcut
       
   261 					$thisfile_asf['header_extension_object'] = array();
       
   262 					$thisfile_asf_headerextensionobject      = &$thisfile_asf['header_extension_object'];
       
   263 
       
   264 					$thisfile_asf_headerextensionobject['offset']              = $NextObjectOffset + $offset;
       
   265 					$thisfile_asf_headerextensionobject['objectid']            = $NextObjectGUID;
       
   266 					$thisfile_asf_headerextensionobject['objectid_guid']       = $NextObjectGUIDtext;
       
   267 					$thisfile_asf_headerextensionobject['objectsize']          = $NextObjectSize;
       
   268 					$thisfile_asf_headerextensionobject['reserved_1']          = substr($ASFHeaderData, $offset, 16);
       
   269 					$offset += 16;
       
   270 					$thisfile_asf_headerextensionobject['reserved_1_guid']     = $this->BytestringToGUID($thisfile_asf_headerextensionobject['reserved_1']);
       
   271 					if ($thisfile_asf_headerextensionobject['reserved_1'] != GETID3_ASF_Reserved_1) {
       
   272 						$info['warning'][] = 'header_extension_object.reserved_1 GUID ('.$this->BytestringToGUID($thisfile_asf_headerextensionobject['reserved_1']).') does not match expected "GETID3_ASF_Reserved_1" GUID ('.$this->BytestringToGUID(GETID3_ASF_Reserved_1).')';
       
   273 						//return false;
       
   274 						break;
       
   275 					}
       
   276 					$thisfile_asf_headerextensionobject['reserved_2']          = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
       
   277 					$offset += 2;
       
   278 					if ($thisfile_asf_headerextensionobject['reserved_2'] != 6) {
       
   279 						$info['warning'][] = 'header_extension_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_headerextensionobject['reserved_2']).') does not match expected value of "6"';
       
   280 						//return false;
       
   281 						break;
       
   282 					}
       
   283 					$thisfile_asf_headerextensionobject['extension_data_size'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
       
   284 					$offset += 4;
       
   285 					$thisfile_asf_headerextensionobject['extension_data']      =                              substr($ASFHeaderData, $offset, $thisfile_asf_headerextensionobject['extension_data_size']);
       
   286 					$unhandled_sections = 0;
       
   287 					$thisfile_asf_headerextensionobject['extension_data_parsed'] = $this->ASF_HeaderExtensionObjectDataParse($thisfile_asf_headerextensionobject['extension_data'], $unhandled_sections);
       
   288 					if ($unhandled_sections === 0) {
       
   289 						unset($thisfile_asf_headerextensionobject['extension_data']);
       
   290 					}
       
   291 					$offset += $thisfile_asf_headerextensionobject['extension_data_size'];
       
   292 					break;
       
   293 
       
   294 				case GETID3_ASF_Codec_List_Object:
       
   295 					// Codec List Object: (optional, one only)
       
   296 					// Field Name                   Field Type   Size (bits)
       
   297 					// Object ID                    GUID         128             // GUID for Codec List object - GETID3_ASF_Codec_List_Object
       
   298 					// Object Size                  QWORD        64              // size of Codec List object, including 44 bytes of Codec List Object header
       
   299 					// Reserved                     GUID         128             // hardcoded: 86D15241-311D-11D0-A3A4-00A0C90348F6
       
   300 					// Codec Entries Count          DWORD        32              // number of entries in Codec Entries array
       
   301 					// Codec Entries                array of:    variable        //
       
   302 					// * Type                       WORD         16              // 0x0001 = Video Codec, 0x0002 = Audio Codec, 0xFFFF = Unknown Codec
       
   303 					// * Codec Name Length          WORD         16              // number of Unicode characters stored in the Codec Name field
       
   304 					// * Codec Name                 WCHAR        variable        // array of Unicode characters - name of codec used to create the content
       
   305 					// * Codec Description Length   WORD         16              // number of Unicode characters stored in the Codec Description field
       
   306 					// * Codec Description          WCHAR        variable        // array of Unicode characters - description of format used to create the content
       
   307 					// * Codec Information Length   WORD         16              // number of Unicode characters stored in the Codec Information field
       
   308 					// * Codec Information          BYTESTREAM   variable        // opaque array of information bytes about the codec used to create the content
       
   309 
       
   310 					// shortcut
       
   311 					$thisfile_asf['codec_list_object'] = array();
       
   312 					$thisfile_asf_codeclistobject      = &$thisfile_asf['codec_list_object'];
       
   313 
       
   314 					$thisfile_asf_codeclistobject['offset']                    = $NextObjectOffset + $offset;
       
   315 					$thisfile_asf_codeclistobject['objectid']                  = $NextObjectGUID;
       
   316 					$thisfile_asf_codeclistobject['objectid_guid']             = $NextObjectGUIDtext;
       
   317 					$thisfile_asf_codeclistobject['objectsize']                = $NextObjectSize;
       
   318 					$thisfile_asf_codeclistobject['reserved']                  = substr($ASFHeaderData, $offset, 16);
       
   319 					$offset += 16;
       
   320 					$thisfile_asf_codeclistobject['reserved_guid']             = $this->BytestringToGUID($thisfile_asf_codeclistobject['reserved']);
       
   321 					if ($thisfile_asf_codeclistobject['reserved'] != $this->GUIDtoBytestring('86D15241-311D-11D0-A3A4-00A0C90348F6')) {
       
   322 						$info['warning'][] = 'codec_list_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_codeclistobject['reserved']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {86D15241-311D-11D0-A3A4-00A0C90348F6}';
       
   323 						//return false;
       
   324 						break;
       
   325 					}
       
   326 					$thisfile_asf_codeclistobject['codec_entries_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
       
   327 					$offset += 4;
       
   328 					for ($CodecEntryCounter = 0; $CodecEntryCounter < $thisfile_asf_codeclistobject['codec_entries_count']; $CodecEntryCounter++) {
       
   329 						// shortcut
       
   330 						$thisfile_asf_codeclistobject['codec_entries'][$CodecEntryCounter] = array();
       
   331 						$thisfile_asf_codeclistobject_codecentries_current = &$thisfile_asf_codeclistobject['codec_entries'][$CodecEntryCounter];
       
   332 
       
   333 						$thisfile_asf_codeclistobject_codecentries_current['type_raw'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
       
   334 						$offset += 2;
       
   335 						$thisfile_asf_codeclistobject_codecentries_current['type'] = $this->ASFCodecListObjectTypeLookup($thisfile_asf_codeclistobject_codecentries_current['type_raw']);
       
   336 
       
   337 						$CodecNameLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character
       
   338 						$offset += 2;
       
   339 						$thisfile_asf_codeclistobject_codecentries_current['name'] = substr($ASFHeaderData, $offset, $CodecNameLength);
       
   340 						$offset += $CodecNameLength;
       
   341 
       
   342 						$CodecDescriptionLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character
       
   343 						$offset += 2;
       
   344 						$thisfile_asf_codeclistobject_codecentries_current['description'] = substr($ASFHeaderData, $offset, $CodecDescriptionLength);
       
   345 						$offset += $CodecDescriptionLength;
       
   346 
       
   347 						$CodecInformationLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
       
   348 						$offset += 2;
       
   349 						$thisfile_asf_codeclistobject_codecentries_current['information'] = substr($ASFHeaderData, $offset, $CodecInformationLength);
       
   350 						$offset += $CodecInformationLength;
       
   351 
       
   352 						if ($thisfile_asf_codeclistobject_codecentries_current['type_raw'] == 2) { // audio codec
       
   353 
       
   354 							if (strpos($thisfile_asf_codeclistobject_codecentries_current['description'], ',') === false) {
       
   355 								$info['warning'][] = '[asf][codec_list_object][codec_entries]['.$CodecEntryCounter.'][description] expected to contain comma-seperated list of parameters: "'.$thisfile_asf_codeclistobject_codecentries_current['description'].'"';
       
   356 							} else {
       
   357 
       
   358 								list($AudioCodecBitrate, $AudioCodecFrequency, $AudioCodecChannels) = explode(',', $this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['description']));
       
   359 								$thisfile_audio['codec'] = $this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['name']);
       
   360 
       
   361 								if (!isset($thisfile_audio['bitrate']) && strstr($AudioCodecBitrate, 'kbps')) {
       
   362 									$thisfile_audio['bitrate'] = (int) (trim(str_replace('kbps', '', $AudioCodecBitrate)) * 1000);
       
   363 								}
       
   364 								//if (!isset($thisfile_video['bitrate']) && isset($thisfile_audio['bitrate']) && isset($thisfile_asf['file_properties_object']['max_bitrate']) && ($thisfile_asf_codeclistobject['codec_entries_count'] > 1)) {
       
   365 								if (empty($thisfile_video['bitrate']) && !empty($thisfile_audio['bitrate']) && !empty($info['bitrate'])) {
       
   366 									//$thisfile_video['bitrate'] = $thisfile_asf['file_properties_object']['max_bitrate'] - $thisfile_audio['bitrate'];
       
   367 									$thisfile_video['bitrate'] = $info['bitrate'] - $thisfile_audio['bitrate'];
       
   368 								}
       
   369 
       
   370 								$AudioCodecFrequency = (int) trim(str_replace('kHz', '', $AudioCodecFrequency));
       
   371 								switch ($AudioCodecFrequency) {
       
   372 									case 8:
       
   373 									case 8000:
       
   374 										$thisfile_audio['sample_rate'] = 8000;
       
   375 										break;
       
   376 
       
   377 									case 11:
       
   378 									case 11025:
       
   379 										$thisfile_audio['sample_rate'] = 11025;
       
   380 										break;
       
   381 
       
   382 									case 12:
       
   383 									case 12000:
       
   384 										$thisfile_audio['sample_rate'] = 12000;
       
   385 										break;
       
   386 
       
   387 									case 16:
       
   388 									case 16000:
       
   389 										$thisfile_audio['sample_rate'] = 16000;
       
   390 										break;
       
   391 
       
   392 									case 22:
       
   393 									case 22050:
       
   394 										$thisfile_audio['sample_rate'] = 22050;
       
   395 										break;
       
   396 
       
   397 									case 24:
       
   398 									case 24000:
       
   399 										$thisfile_audio['sample_rate'] = 24000;
       
   400 										break;
       
   401 
       
   402 									case 32:
       
   403 									case 32000:
       
   404 										$thisfile_audio['sample_rate'] = 32000;
       
   405 										break;
       
   406 
       
   407 									case 44:
       
   408 									case 441000:
       
   409 										$thisfile_audio['sample_rate'] = 44100;
       
   410 										break;
       
   411 
       
   412 									case 48:
       
   413 									case 48000:
       
   414 										$thisfile_audio['sample_rate'] = 48000;
       
   415 										break;
       
   416 
       
   417 									default:
       
   418 										$info['warning'][] = 'unknown frequency: "'.$AudioCodecFrequency.'" ('.$this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['description']).')';
       
   419 										break;
       
   420 								}
       
   421 
       
   422 								if (!isset($thisfile_audio['channels'])) {
       
   423 									if (strstr($AudioCodecChannels, 'stereo')) {
       
   424 										$thisfile_audio['channels'] = 2;
       
   425 									} elseif (strstr($AudioCodecChannels, 'mono')) {
       
   426 										$thisfile_audio['channels'] = 1;
       
   427 									}
       
   428 								}
       
   429 
       
   430 							}
       
   431 						}
       
   432 					}
       
   433 					break;
       
   434 
       
   435 				case GETID3_ASF_Script_Command_Object:
       
   436 					// Script Command Object: (optional, one only)
       
   437 					// Field Name                   Field Type   Size (bits)
       
   438 					// Object ID                    GUID         128             // GUID for Script Command object - GETID3_ASF_Script_Command_Object
       
   439 					// Object Size                  QWORD        64              // size of Script Command object, including 44 bytes of Script Command Object header
       
   440 					// Reserved                     GUID         128             // hardcoded: 4B1ACBE3-100B-11D0-A39B-00A0C90348F6
       
   441 					// Commands Count               WORD         16              // number of Commands structures in the Script Commands Objects
       
   442 					// Command Types Count          WORD         16              // number of Command Types structures in the Script Commands Objects
       
   443 					// Command Types                array of:    variable        //
       
   444 					// * Command Type Name Length   WORD         16              // number of Unicode characters for Command Type Name
       
   445 					// * Command Type Name          WCHAR        variable        // array of Unicode characters - name of a type of command
       
   446 					// Commands                     array of:    variable        //
       
   447 					// * Presentation Time          DWORD        32              // presentation time of that command, in milliseconds
       
   448 					// * Type Index                 WORD         16              // type of this command, as a zero-based index into the array of Command Types of this object
       
   449 					// * Command Name Length        WORD         16              // number of Unicode characters for Command Name
       
   450 					// * Command Name               WCHAR        variable        // array of Unicode characters - name of this command
       
   451 
       
   452 					// shortcut
       
   453 					$thisfile_asf['script_command_object'] = array();
       
   454 					$thisfile_asf_scriptcommandobject      = &$thisfile_asf['script_command_object'];
       
   455 
       
   456 					$thisfile_asf_scriptcommandobject['offset']               = $NextObjectOffset + $offset;
       
   457 					$thisfile_asf_scriptcommandobject['objectid']             = $NextObjectGUID;
       
   458 					$thisfile_asf_scriptcommandobject['objectid_guid']        = $NextObjectGUIDtext;
       
   459 					$thisfile_asf_scriptcommandobject['objectsize']           = $NextObjectSize;
       
   460 					$thisfile_asf_scriptcommandobject['reserved']             = substr($ASFHeaderData, $offset, 16);
       
   461 					$offset += 16;
       
   462 					$thisfile_asf_scriptcommandobject['reserved_guid']        = $this->BytestringToGUID($thisfile_asf_scriptcommandobject['reserved']);
       
   463 					if ($thisfile_asf_scriptcommandobject['reserved'] != $this->GUIDtoBytestring('4B1ACBE3-100B-11D0-A39B-00A0C90348F6')) {
       
   464 						$info['warning'][] = 'script_command_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_scriptcommandobject['reserved']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {4B1ACBE3-100B-11D0-A39B-00A0C90348F6}';
       
   465 						//return false;
       
   466 						break;
       
   467 					}
       
   468 					$thisfile_asf_scriptcommandobject['commands_count']       = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
       
   469 					$offset += 2;
       
   470 					$thisfile_asf_scriptcommandobject['command_types_count']  = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
       
   471 					$offset += 2;
       
   472 					for ($CommandTypesCounter = 0; $CommandTypesCounter < $thisfile_asf_scriptcommandobject['command_types_count']; $CommandTypesCounter++) {
       
   473 						$CommandTypeNameLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character
       
   474 						$offset += 2;
       
   475 						$thisfile_asf_scriptcommandobject['command_types'][$CommandTypesCounter]['name'] = substr($ASFHeaderData, $offset, $CommandTypeNameLength);
       
   476 						$offset += $CommandTypeNameLength;
       
   477 					}
       
   478 					for ($CommandsCounter = 0; $CommandsCounter < $thisfile_asf_scriptcommandobject['commands_count']; $CommandsCounter++) {
       
   479 						$thisfile_asf_scriptcommandobject['commands'][$CommandsCounter]['presentation_time']  = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
       
   480 						$offset += 4;
       
   481 						$thisfile_asf_scriptcommandobject['commands'][$CommandsCounter]['type_index']         = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
       
   482 						$offset += 2;
       
   483 
       
   484 						$CommandTypeNameLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character
       
   485 						$offset += 2;
       
   486 						$thisfile_asf_scriptcommandobject['commands'][$CommandsCounter]['name'] = substr($ASFHeaderData, $offset, $CommandTypeNameLength);
       
   487 						$offset += $CommandTypeNameLength;
       
   488 					}
       
   489 					break;
       
   490 
       
   491 				case GETID3_ASF_Marker_Object:
       
   492 					// Marker Object: (optional, one only)
       
   493 					// Field Name                   Field Type   Size (bits)
       
   494 					// Object ID                    GUID         128             // GUID for Marker object - GETID3_ASF_Marker_Object
       
   495 					// Object Size                  QWORD        64              // size of Marker object, including 48 bytes of Marker Object header
       
   496 					// Reserved                     GUID         128             // hardcoded: 4CFEDB20-75F6-11CF-9C0F-00A0C90349CB
       
   497 					// Markers Count                DWORD        32              // number of Marker structures in Marker Object
       
   498 					// Reserved                     WORD         16              // hardcoded: 0x0000
       
   499 					// Name Length                  WORD         16              // number of bytes in the Name field
       
   500 					// Name                         WCHAR        variable        // name of the Marker Object
       
   501 					// Markers                      array of:    variable        //
       
   502 					// * Offset                     QWORD        64              // byte offset into Data Object
       
   503 					// * Presentation Time          QWORD        64              // in 100-nanosecond units
       
   504 					// * Entry Length               WORD         16              // length in bytes of (Send Time + Flags + Marker Description Length + Marker Description + Padding)
       
   505 					// * Send Time                  DWORD        32              // in milliseconds
       
   506 					// * Flags                      DWORD        32              // hardcoded: 0x00000000
       
   507 					// * Marker Description Length  DWORD        32              // number of bytes in Marker Description field
       
   508 					// * Marker Description         WCHAR        variable        // array of Unicode characters - description of marker entry
       
   509 					// * Padding                    BYTESTREAM   variable        // optional padding bytes
       
   510 
       
   511 					// shortcut
       
   512 					$thisfile_asf['marker_object'] = array();
       
   513 					$thisfile_asf_markerobject     = &$thisfile_asf['marker_object'];
       
   514 
       
   515 					$thisfile_asf_markerobject['offset']               = $NextObjectOffset + $offset;
       
   516 					$thisfile_asf_markerobject['objectid']             = $NextObjectGUID;
       
   517 					$thisfile_asf_markerobject['objectid_guid']        = $NextObjectGUIDtext;
       
   518 					$thisfile_asf_markerobject['objectsize']           = $NextObjectSize;
       
   519 					$thisfile_asf_markerobject['reserved']             = substr($ASFHeaderData, $offset, 16);
       
   520 					$offset += 16;
       
   521 					$thisfile_asf_markerobject['reserved_guid']        = $this->BytestringToGUID($thisfile_asf_markerobject['reserved']);
       
   522 					if ($thisfile_asf_markerobject['reserved'] != $this->GUIDtoBytestring('4CFEDB20-75F6-11CF-9C0F-00A0C90349CB')) {
       
   523 						$info['warning'][] = 'marker_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_markerobject['reserved_1']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {4CFEDB20-75F6-11CF-9C0F-00A0C90349CB}';
       
   524 						break;
       
   525 					}
       
   526 					$thisfile_asf_markerobject['markers_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
       
   527 					$offset += 4;
       
   528 					$thisfile_asf_markerobject['reserved_2'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
       
   529 					$offset += 2;
       
   530 					if ($thisfile_asf_markerobject['reserved_2'] != 0) {
       
   531 						$info['warning'][] = 'marker_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_markerobject['reserved_2']).') does not match expected value of "0"';
       
   532 						break;
       
   533 					}
       
   534 					$thisfile_asf_markerobject['name_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
       
   535 					$offset += 2;
       
   536 					$thisfile_asf_markerobject['name'] = substr($ASFHeaderData, $offset, $thisfile_asf_markerobject['name_length']);
       
   537 					$offset += $thisfile_asf_markerobject['name_length'];
       
   538 					for ($MarkersCounter = 0; $MarkersCounter < $thisfile_asf_markerobject['markers_count']; $MarkersCounter++) {
       
   539 						$thisfile_asf_markerobject['markers'][$MarkersCounter]['offset']  = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
       
   540 						$offset += 8;
       
   541 						$thisfile_asf_markerobject['markers'][$MarkersCounter]['presentation_time']         = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
       
   542 						$offset += 8;
       
   543 						$thisfile_asf_markerobject['markers'][$MarkersCounter]['entry_length']              = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
       
   544 						$offset += 2;
       
   545 						$thisfile_asf_markerobject['markers'][$MarkersCounter]['send_time']                 = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
       
   546 						$offset += 4;
       
   547 						$thisfile_asf_markerobject['markers'][$MarkersCounter]['flags']                     = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
       
   548 						$offset += 4;
       
   549 						$thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
       
   550 						$offset += 4;
       
   551 						$thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description']        = substr($ASFHeaderData, $offset, $thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description_length']);
       
   552 						$offset += $thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description_length'];
       
   553 						$PaddingLength = $thisfile_asf_markerobject['markers'][$MarkersCounter]['entry_length'] - 4 -  4 - 4 - $thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description_length'];
       
   554 						if ($PaddingLength > 0) {
       
   555 							$thisfile_asf_markerobject['markers'][$MarkersCounter]['padding']               = substr($ASFHeaderData, $offset, $PaddingLength);
       
   556 							$offset += $PaddingLength;
       
   557 						}
       
   558 					}
       
   559 					break;
       
   560 
       
   561 				case GETID3_ASF_Bitrate_Mutual_Exclusion_Object:
       
   562 					// Bitrate Mutual Exclusion Object: (optional)
       
   563 					// Field Name                   Field Type   Size (bits)
       
   564 					// Object ID                    GUID         128             // GUID for Bitrate Mutual Exclusion object - GETID3_ASF_Bitrate_Mutual_Exclusion_Object
       
   565 					// Object Size                  QWORD        64              // size of Bitrate Mutual Exclusion object, including 42 bytes of Bitrate Mutual Exclusion Object header
       
   566 					// Exlusion Type                GUID         128             // nature of mutual exclusion relationship. one of: (GETID3_ASF_Mutex_Bitrate, GETID3_ASF_Mutex_Unknown)
       
   567 					// Stream Numbers Count         WORD         16              // number of video streams
       
   568 					// Stream Numbers               WORD         variable        // array of mutually exclusive video stream numbers. 1 <= valid <= 127
       
   569 
       
   570 					// shortcut
       
   571 					$thisfile_asf['bitrate_mutual_exclusion_object'] = array();
       
   572 					$thisfile_asf_bitratemutualexclusionobject       = &$thisfile_asf['bitrate_mutual_exclusion_object'];
       
   573 
       
   574 					$thisfile_asf_bitratemutualexclusionobject['offset']               = $NextObjectOffset + $offset;
       
   575 					$thisfile_asf_bitratemutualexclusionobject['objectid']             = $NextObjectGUID;
       
   576 					$thisfile_asf_bitratemutualexclusionobject['objectid_guid']        = $NextObjectGUIDtext;
       
   577 					$thisfile_asf_bitratemutualexclusionobject['objectsize']           = $NextObjectSize;
       
   578 					$thisfile_asf_bitratemutualexclusionobject['reserved']             = substr($ASFHeaderData, $offset, 16);
       
   579 					$thisfile_asf_bitratemutualexclusionobject['reserved_guid']        = $this->BytestringToGUID($thisfile_asf_bitratemutualexclusionobject['reserved']);
       
   580 					$offset += 16;
       
   581 					if (($thisfile_asf_bitratemutualexclusionobject['reserved'] != GETID3_ASF_Mutex_Bitrate) && ($thisfile_asf_bitratemutualexclusionobject['reserved'] != GETID3_ASF_Mutex_Unknown)) {
       
   582 						$info['warning'][] = 'bitrate_mutual_exclusion_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_bitratemutualexclusionobject['reserved']).'} does not match expected "GETID3_ASF_Mutex_Bitrate" GUID {'.$this->BytestringToGUID(GETID3_ASF_Mutex_Bitrate).'} or  "GETID3_ASF_Mutex_Unknown" GUID {'.$this->BytestringToGUID(GETID3_ASF_Mutex_Unknown).'}';
       
   583 						//return false;
       
   584 						break;
       
   585 					}
       
   586 					$thisfile_asf_bitratemutualexclusionobject['stream_numbers_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
       
   587 					$offset += 2;
       
   588 					for ($StreamNumberCounter = 0; $StreamNumberCounter < $thisfile_asf_bitratemutualexclusionobject['stream_numbers_count']; $StreamNumberCounter++) {
       
   589 						$thisfile_asf_bitratemutualexclusionobject['stream_numbers'][$StreamNumberCounter] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
       
   590 						$offset += 2;
       
   591 					}
       
   592 					break;
       
   593 
       
   594 				case GETID3_ASF_Error_Correction_Object:
       
   595 					// Error Correction Object: (optional, one only)
       
   596 					// Field Name                   Field Type   Size (bits)
       
   597 					// Object ID                    GUID         128             // GUID for Error Correction object - GETID3_ASF_Error_Correction_Object
       
   598 					// Object Size                  QWORD        64              // size of Error Correction object, including 44 bytes of Error Correction Object header
       
   599 					// Error Correction Type        GUID         128             // type of error correction. one of: (GETID3_ASF_No_Error_Correction, GETID3_ASF_Audio_Spread)
       
   600 					// Error Correction Data Length DWORD        32              // number of bytes in Error Correction Data field
       
   601 					// Error Correction Data        BYTESTREAM   variable        // structure depends on value of Error Correction Type field
       
   602 
       
   603 					// shortcut
       
   604 					$thisfile_asf['error_correction_object'] = array();
       
   605 					$thisfile_asf_errorcorrectionobject      = &$thisfile_asf['error_correction_object'];
       
   606 
       
   607 					$thisfile_asf_errorcorrectionobject['offset']                = $NextObjectOffset + $offset;
       
   608 					$thisfile_asf_errorcorrectionobject['objectid']              = $NextObjectGUID;
       
   609 					$thisfile_asf_errorcorrectionobject['objectid_guid']         = $NextObjectGUIDtext;
       
   610 					$thisfile_asf_errorcorrectionobject['objectsize']            = $NextObjectSize;
       
   611 					$thisfile_asf_errorcorrectionobject['error_correction_type'] = substr($ASFHeaderData, $offset, 16);
       
   612 					$offset += 16;
       
   613 					$thisfile_asf_errorcorrectionobject['error_correction_guid'] = $this->BytestringToGUID($thisfile_asf_errorcorrectionobject['error_correction_type']);
       
   614 					$thisfile_asf_errorcorrectionobject['error_correction_data_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
       
   615 					$offset += 4;
       
   616 					switch ($thisfile_asf_errorcorrectionobject['error_correction_type']) {
       
   617 						case GETID3_ASF_No_Error_Correction:
       
   618 							// should be no data, but just in case there is, skip to the end of the field
       
   619 							$offset += $thisfile_asf_errorcorrectionobject['error_correction_data_length'];
       
   620 							break;
       
   621 
       
   622 						case GETID3_ASF_Audio_Spread:
       
   623 							// Field Name                   Field Type   Size (bits)
       
   624 							// Span                         BYTE         8               // number of packets over which audio will be spread.
       
   625 							// Virtual Packet Length        WORD         16              // size of largest audio payload found in audio stream
       
   626 							// Virtual Chunk Length         WORD         16              // size of largest audio payload found in audio stream
       
   627 							// Silence Data Length          WORD         16              // number of bytes in Silence Data field
       
   628 							// Silence Data                 BYTESTREAM   variable        // hardcoded: 0x00 * (Silence Data Length) bytes
       
   629 
       
   630 							$thisfile_asf_errorcorrectionobject['span']                  = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 1));
       
   631 							$offset += 1;
       
   632 							$thisfile_asf_errorcorrectionobject['virtual_packet_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
       
   633 							$offset += 2;
       
   634 							$thisfile_asf_errorcorrectionobject['virtual_chunk_length']  = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
       
   635 							$offset += 2;
       
   636 							$thisfile_asf_errorcorrectionobject['silence_data_length']   = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
       
   637 							$offset += 2;
       
   638 							$thisfile_asf_errorcorrectionobject['silence_data']          = substr($ASFHeaderData, $offset, $thisfile_asf_errorcorrectionobject['silence_data_length']);
       
   639 							$offset += $thisfile_asf_errorcorrectionobject['silence_data_length'];
       
   640 							break;
       
   641 
       
   642 						default:
       
   643 							$info['warning'][] = 'error_correction_object.error_correction_type GUID {'.$this->BytestringToGUID($thisfile_asf_errorcorrectionobject['reserved']).'} does not match expected "GETID3_ASF_No_Error_Correction" GUID {'.$this->BytestringToGUID(GETID3_ASF_No_Error_Correction).'} or  "GETID3_ASF_Audio_Spread" GUID {'.$this->BytestringToGUID(GETID3_ASF_Audio_Spread).'}';
       
   644 							//return false;
       
   645 							break;
       
   646 					}
       
   647 
       
   648 					break;
       
   649 
       
   650 				case GETID3_ASF_Content_Description_Object:
       
   651 					// Content Description Object: (optional, one only)
       
   652 					// Field Name                   Field Type   Size (bits)
       
   653 					// Object ID                    GUID         128             // GUID for Content Description object - GETID3_ASF_Content_Description_Object
       
   654 					// Object Size                  QWORD        64              // size of Content Description object, including 34 bytes of Content Description Object header
       
   655 					// Title Length                 WORD         16              // number of bytes in Title field
       
   656 					// Author Length                WORD         16              // number of bytes in Author field
       
   657 					// Copyright Length             WORD         16              // number of bytes in Copyright field
       
   658 					// Description Length           WORD         16              // number of bytes in Description field
       
   659 					// Rating Length                WORD         16              // number of bytes in Rating field
       
   660 					// Title                        WCHAR        16              // array of Unicode characters - Title
       
   661 					// Author                       WCHAR        16              // array of Unicode characters - Author
       
   662 					// Copyright                    WCHAR        16              // array of Unicode characters - Copyright
       
   663 					// Description                  WCHAR        16              // array of Unicode characters - Description
       
   664 					// Rating                       WCHAR        16              // array of Unicode characters - Rating
       
   665 
       
   666 					// shortcut
       
   667 					$thisfile_asf['content_description_object'] = array();
       
   668 					$thisfile_asf_contentdescriptionobject      = &$thisfile_asf['content_description_object'];
       
   669 
       
   670 					$thisfile_asf_contentdescriptionobject['offset']                = $NextObjectOffset + $offset;
       
   671 					$thisfile_asf_contentdescriptionobject['objectid']              = $NextObjectGUID;
       
   672 					$thisfile_asf_contentdescriptionobject['objectid_guid']         = $NextObjectGUIDtext;
       
   673 					$thisfile_asf_contentdescriptionobject['objectsize']            = $NextObjectSize;
       
   674 					$thisfile_asf_contentdescriptionobject['title_length']          = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
       
   675 					$offset += 2;
       
   676 					$thisfile_asf_contentdescriptionobject['author_length']         = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
       
   677 					$offset += 2;
       
   678 					$thisfile_asf_contentdescriptionobject['copyright_length']      = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
       
   679 					$offset += 2;
       
   680 					$thisfile_asf_contentdescriptionobject['description_length']    = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
       
   681 					$offset += 2;
       
   682 					$thisfile_asf_contentdescriptionobject['rating_length']         = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
       
   683 					$offset += 2;
       
   684 					$thisfile_asf_contentdescriptionobject['title']                 = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['title_length']);
       
   685 					$offset += $thisfile_asf_contentdescriptionobject['title_length'];
       
   686 					$thisfile_asf_contentdescriptionobject['author']                = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['author_length']);
       
   687 					$offset += $thisfile_asf_contentdescriptionobject['author_length'];
       
   688 					$thisfile_asf_contentdescriptionobject['copyright']             = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['copyright_length']);
       
   689 					$offset += $thisfile_asf_contentdescriptionobject['copyright_length'];
       
   690 					$thisfile_asf_contentdescriptionobject['description']           = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['description_length']);
       
   691 					$offset += $thisfile_asf_contentdescriptionobject['description_length'];
       
   692 					$thisfile_asf_contentdescriptionobject['rating']                = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['rating_length']);
       
   693 					$offset += $thisfile_asf_contentdescriptionobject['rating_length'];
       
   694 
       
   695 					$ASFcommentKeysToCopy = array('title'=>'title', 'author'=>'artist', 'copyright'=>'copyright', 'description'=>'comment', 'rating'=>'rating');
       
   696 					foreach ($ASFcommentKeysToCopy as $keytocopyfrom => $keytocopyto) {
       
   697 						if (!empty($thisfile_asf_contentdescriptionobject[$keytocopyfrom])) {
       
   698 							$thisfile_asf_comments[$keytocopyto][] = $this->TrimTerm($thisfile_asf_contentdescriptionobject[$keytocopyfrom]);
       
   699 						}
       
   700 					}
       
   701 					break;
       
   702 
       
   703 				case GETID3_ASF_Extended_Content_Description_Object:
       
   704 					// Extended Content Description Object: (optional, one only)
       
   705 					// Field Name                   Field Type   Size (bits)
       
   706 					// Object ID                    GUID         128             // GUID for Extended Content Description object - GETID3_ASF_Extended_Content_Description_Object
       
   707 					// Object Size                  QWORD        64              // size of ExtendedContent Description object, including 26 bytes of Extended Content Description Object header
       
   708 					// Content Descriptors Count    WORD         16              // number of entries in Content Descriptors list
       
   709 					// Content Descriptors          array of:    variable        //
       
   710 					// * Descriptor Name Length     WORD         16              // size in bytes of Descriptor Name field
       
   711 					// * Descriptor Name            WCHAR        variable        // array of Unicode characters - Descriptor Name
       
   712 					// * Descriptor Value Data Type WORD         16              // Lookup array:
       
   713 																					// 0x0000 = Unicode String (variable length)
       
   714 																					// 0x0001 = BYTE array     (variable length)
       
   715 																					// 0x0002 = BOOL           (DWORD, 32 bits)
       
   716 																					// 0x0003 = DWORD          (DWORD, 32 bits)
       
   717 																					// 0x0004 = QWORD          (QWORD, 64 bits)
       
   718 																					// 0x0005 = WORD           (WORD,  16 bits)
       
   719 					// * Descriptor Value Length    WORD         16              // number of bytes stored in Descriptor Value field
       
   720 					// * Descriptor Value           variable     variable        // value for Content Descriptor
       
   721 
       
   722 					// shortcut
       
   723 					$thisfile_asf['extended_content_description_object'] = array();
       
   724 					$thisfile_asf_extendedcontentdescriptionobject       = &$thisfile_asf['extended_content_description_object'];
       
   725 
       
   726 					$thisfile_asf_extendedcontentdescriptionobject['offset']                    = $NextObjectOffset + $offset;
       
   727 					$thisfile_asf_extendedcontentdescriptionobject['objectid']                  = $NextObjectGUID;
       
   728 					$thisfile_asf_extendedcontentdescriptionobject['objectid_guid']             = $NextObjectGUIDtext;
       
   729 					$thisfile_asf_extendedcontentdescriptionobject['objectsize']                = $NextObjectSize;
       
   730 					$thisfile_asf_extendedcontentdescriptionobject['content_descriptors_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
       
   731 					$offset += 2;
       
   732 					for ($ExtendedContentDescriptorsCounter = 0; $ExtendedContentDescriptorsCounter < $thisfile_asf_extendedcontentdescriptionobject['content_descriptors_count']; $ExtendedContentDescriptorsCounter++) {
       
   733 						// shortcut
       
   734 						$thisfile_asf_extendedcontentdescriptionobject['content_descriptors'][$ExtendedContentDescriptorsCounter] = array();
       
   735 						$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current                 = &$thisfile_asf_extendedcontentdescriptionobject['content_descriptors'][$ExtendedContentDescriptorsCounter];
       
   736 
       
   737 						$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['base_offset']  = $offset + 30;
       
   738 						$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name_length']  = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
       
   739 						$offset += 2;
       
   740 						$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name']         = substr($ASFHeaderData, $offset, $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name_length']);
       
   741 						$offset += $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name_length'];
       
   742 						$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type']   = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
       
   743 						$offset += 2;
       
   744 						$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
       
   745 						$offset += 2;
       
   746 						$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']        = substr($ASFHeaderData, $offset, $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_length']);
       
   747 						$offset += $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_length'];
       
   748 						switch ($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type']) {
       
   749 							case 0x0000: // Unicode string
       
   750 								break;
       
   751 
       
   752 							case 0x0001: // BYTE array
       
   753 								// do nothing
       
   754 								break;
       
   755 
       
   756 							case 0x0002: // BOOL
       
   757 								$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'] = (bool) getid3_lib::LittleEndian2Int($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']);
       
   758 								break;
       
   759 
       
   760 							case 0x0003: // DWORD
       
   761 							case 0x0004: // QWORD
       
   762 							case 0x0005: // WORD
       
   763 								$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'] = getid3_lib::LittleEndian2Int($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']);
       
   764 								break;
       
   765 
       
   766 							default:
       
   767 								$info['warning'][] = 'extended_content_description.content_descriptors.'.$ExtendedContentDescriptorsCounter.'.value_type is invalid ('.$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type'].')';
       
   768 								//return false;
       
   769 								break;
       
   770 						}
       
   771 						switch ($this->TrimConvert(strtolower($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name']))) {
       
   772 
       
   773 							case 'wm/albumartist':
       
   774 							case 'artist':
       
   775 								// Note: not 'artist', that comes from 'author' tag
       
   776 								$thisfile_asf_comments['albumartist'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
       
   777 								break;
       
   778 
       
   779 							case 'wm/albumtitle':
       
   780 							case 'album':
       
   781 								$thisfile_asf_comments['album']  = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
       
   782 								break;
       
   783 
       
   784 							case 'wm/genre':
       
   785 							case 'genre':
       
   786 								$thisfile_asf_comments['genre'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
       
   787 								break;
       
   788 
       
   789 							case 'wm/partofset':
       
   790 								$thisfile_asf_comments['partofset'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
       
   791 								break;
       
   792 
       
   793 							case 'wm/tracknumber':
       
   794 							case 'tracknumber':
       
   795 								// be careful casting to int: casting unicode strings to int gives unexpected results (stops parsing at first non-numeric character)
       
   796 								$thisfile_asf_comments['track'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
       
   797 								foreach ($thisfile_asf_comments['track'] as $key => $value) {
       
   798 									if (preg_match('/^[0-9\x00]+$/', $value)) {
       
   799 										$thisfile_asf_comments['track'][$key] = intval(str_replace("\x00", '', $value));
       
   800 									}
       
   801 								}
       
   802 								break;
       
   803 
       
   804 							case 'wm/track':
       
   805 								if (empty($thisfile_asf_comments['track'])) {
       
   806 									$thisfile_asf_comments['track'] = array(1 + $this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
       
   807 								}
       
   808 								break;
       
   809 
       
   810 							case 'wm/year':
       
   811 							case 'year':
       
   812 							case 'date':
       
   813 								$thisfile_asf_comments['year'] = array( $this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
       
   814 								break;
       
   815 
       
   816 							case 'wm/lyrics':
       
   817 							case 'lyrics':
       
   818 								$thisfile_asf_comments['lyrics'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
       
   819 								break;
       
   820 
       
   821 							case 'isvbr':
       
   822 								if ($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']) {
       
   823 									$thisfile_audio['bitrate_mode'] = 'vbr';
       
   824 									$thisfile_video['bitrate_mode'] = 'vbr';
       
   825 								}
       
   826 								break;
       
   827 
       
   828 							case 'id3':
       
   829 								// id3v2 module might not be loaded
       
   830 								if (class_exists('getid3_id3v2')) {
       
   831 									$tempfile         = tempnam(GETID3_TEMP_DIR, 'getID3');
       
   832 									$tempfilehandle   = fopen($tempfile, 'wb');
       
   833 									$tempThisfileInfo = array('encoding'=>$info['encoding']);
       
   834 									fwrite($tempfilehandle, $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']);
       
   835 									fclose($tempfilehandle);
       
   836 
       
   837 									$getid3_temp = new getID3();
       
   838 									$getid3_temp->openfile($tempfile);
       
   839 									$getid3_id3v2 = new getid3_id3v2($getid3_temp);
       
   840 									$getid3_id3v2->Analyze();
       
   841 									$info['id3v2'] = $getid3_temp->info['id3v2'];
       
   842 									unset($getid3_temp, $getid3_id3v2);
       
   843 
       
   844 									unlink($tempfile);
       
   845 								}
       
   846 								break;
       
   847 
       
   848 							case 'wm/encodingtime':
       
   849 								$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['encoding_time_unix'] = $this->FILETIMEtoUNIXtime($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']);
       
   850 								$thisfile_asf_comments['encoding_time_unix'] = array($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['encoding_time_unix']);
       
   851 								break;
       
   852 
       
   853 							case 'wm/picture':
       
   854 								$WMpicture = $this->ASF_WMpicture($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']);
       
   855 								foreach ($WMpicture as $key => $value) {
       
   856 									$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current[$key] = $value;
       
   857 								}
       
   858 								unset($WMpicture);
       
   859 /*
       
   860 								$wm_picture_offset = 0;
       
   861 								$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_type_id'] = getid3_lib::LittleEndian2Int(substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset, 1));
       
   862 								$wm_picture_offset += 1;
       
   863 								$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_type']    = $this->WMpictureTypeLookup($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_type_id']);
       
   864 								$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_size']    = getid3_lib::LittleEndian2Int(substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset, 4));
       
   865 								$wm_picture_offset += 4;
       
   866 
       
   867 								$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime'] = '';
       
   868 								do {
       
   869 									$next_byte_pair = substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset, 2);
       
   870 									$wm_picture_offset += 2;
       
   871 									$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime'] .= $next_byte_pair;
       
   872 								} while ($next_byte_pair !== "\x00\x00");
       
   873 
       
   874 								$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_description'] = '';
       
   875 								do {
       
   876 									$next_byte_pair = substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset, 2);
       
   877 									$wm_picture_offset += 2;
       
   878 									$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_description'] .= $next_byte_pair;
       
   879 								} while ($next_byte_pair !== "\x00\x00");
       
   880 
       
   881 								$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['dataoffset'] = $wm_picture_offset;
       
   882 								$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['data'] = substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset);
       
   883 								unset($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']);
       
   884 
       
   885 								$imageinfo = array();
       
   886 								$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime'] = '';
       
   887 								$imagechunkcheck = getid3_lib::GetDataImageSize($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['data'], $imageinfo);
       
   888 								unset($imageinfo);
       
   889 								if (!empty($imagechunkcheck)) {
       
   890 									$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]);
       
   891 								}
       
   892 								if (!isset($thisfile_asf_comments['picture'])) {
       
   893 									$thisfile_asf_comments['picture'] = array();
       
   894 								}
       
   895 								$thisfile_asf_comments['picture'][] = array('data'=>$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['data'], 'image_mime'=>$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime']);
       
   896 */
       
   897 								break;
       
   898 
       
   899 							default:
       
   900 								switch ($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type']) {
       
   901 									case 0: // Unicode string
       
   902 										if (substr($this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name']), 0, 3) == 'WM/') {
       
   903 											$thisfile_asf_comments[str_replace('wm/', '', strtolower($this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name'])))] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
       
   904 										}
       
   905 										break;
       
   906 
       
   907 									case 1:
       
   908 										break;
       
   909 								}
       
   910 								break;
       
   911 						}
       
   912 
       
   913 					}
       
   914 					break;
       
   915 
       
   916 				case GETID3_ASF_Stream_Bitrate_Properties_Object:
       
   917 					// Stream Bitrate Properties Object: (optional, one only)
       
   918 					// Field Name                   Field Type   Size (bits)
       
   919 					// Object ID                    GUID         128             // GUID for Stream Bitrate Properties object - GETID3_ASF_Stream_Bitrate_Properties_Object
       
   920 					// Object Size                  QWORD        64              // size of Extended Content Description object, including 26 bytes of Stream Bitrate Properties Object header
       
   921 					// Bitrate Records Count        WORD         16              // number of records in Bitrate Records
       
   922 					// Bitrate Records              array of:    variable        //
       
   923 					// * Flags                      WORD         16              //
       
   924 					// * * Stream Number            bits         7  (0x007F)     // number of this stream
       
   925 					// * * Reserved                 bits         9  (0xFF80)     // hardcoded: 0
       
   926 					// * Average Bitrate            DWORD        32              // in bits per second
       
   927 
       
   928 					// shortcut
       
   929 					$thisfile_asf['stream_bitrate_properties_object'] = array();
       
   930 					$thisfile_asf_streambitratepropertiesobject       = &$thisfile_asf['stream_bitrate_properties_object'];
       
   931 
       
   932 					$thisfile_asf_streambitratepropertiesobject['offset']                    = $NextObjectOffset + $offset;
       
   933 					$thisfile_asf_streambitratepropertiesobject['objectid']                  = $NextObjectGUID;
       
   934 					$thisfile_asf_streambitratepropertiesobject['objectid_guid']             = $NextObjectGUIDtext;
       
   935 					$thisfile_asf_streambitratepropertiesobject['objectsize']                = $NextObjectSize;
       
   936 					$thisfile_asf_streambitratepropertiesobject['bitrate_records_count']     = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
       
   937 					$offset += 2;
       
   938 					for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < $thisfile_asf_streambitratepropertiesobject['bitrate_records_count']; $BitrateRecordsCounter++) {
       
   939 						$thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['flags_raw'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
       
   940 						$offset += 2;
       
   941 						$thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['flags']['stream_number'] = $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['flags_raw'] & 0x007F;
       
   942 						$thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['bitrate'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
       
   943 						$offset += 4;
       
   944 					}
       
   945 					break;
       
   946 
       
   947 				case GETID3_ASF_Padding_Object:
       
   948 					// Padding Object: (optional)
       
   949 					// Field Name                   Field Type   Size (bits)
       
   950 					// Object ID                    GUID         128             // GUID for Padding object - GETID3_ASF_Padding_Object
       
   951 					// Object Size                  QWORD        64              // size of Padding object, including 24 bytes of ASF Padding Object header
       
   952 					// Padding Data                 BYTESTREAM   variable        // ignore
       
   953 
       
   954 					// shortcut
       
   955 					$thisfile_asf['padding_object'] = array();
       
   956 					$thisfile_asf_paddingobject     = &$thisfile_asf['padding_object'];
       
   957 
       
   958 					$thisfile_asf_paddingobject['offset']                    = $NextObjectOffset + $offset;
       
   959 					$thisfile_asf_paddingobject['objectid']                  = $NextObjectGUID;
       
   960 					$thisfile_asf_paddingobject['objectid_guid']             = $NextObjectGUIDtext;
       
   961 					$thisfile_asf_paddingobject['objectsize']                = $NextObjectSize;
       
   962 					$thisfile_asf_paddingobject['padding_length']            = $thisfile_asf_paddingobject['objectsize'] - 16 - 8;
       
   963 					$thisfile_asf_paddingobject['padding']                   = substr($ASFHeaderData, $offset, $thisfile_asf_paddingobject['padding_length']);
       
   964 					$offset += ($NextObjectSize - 16 - 8);
       
   965 					break;
       
   966 
       
   967 				case GETID3_ASF_Extended_Content_Encryption_Object:
       
   968 				case GETID3_ASF_Content_Encryption_Object:
       
   969 					// WMA DRM - just ignore
       
   970 					$offset += ($NextObjectSize - 16 - 8);
       
   971 					break;
       
   972 
       
   973 				default:
       
   974 					// Implementations shall ignore any standard or non-standard object that they do not know how to handle.
       
   975 					if ($this->GUIDname($NextObjectGUIDtext)) {
       
   976 						$info['warning'][] = 'unhandled GUID "'.$this->GUIDname($NextObjectGUIDtext).'" {'.$NextObjectGUIDtext.'} in ASF header at offset '.($offset - 16 - 8);
       
   977 					} else {
       
   978 						$info['warning'][] = 'unknown GUID {'.$NextObjectGUIDtext.'} in ASF header at offset '.($offset - 16 - 8);
       
   979 					}
       
   980 					$offset += ($NextObjectSize - 16 - 8);
       
   981 					break;
       
   982 			}
       
   983 		}
       
   984 		if (isset($thisfile_asf_streambitrateproperties['bitrate_records_count'])) {
       
   985 			$ASFbitrateAudio = 0;
       
   986 			$ASFbitrateVideo = 0;
       
   987 			for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < $thisfile_asf_streambitrateproperties['bitrate_records_count']; $BitrateRecordsCounter++) {
       
   988 				if (isset($thisfile_asf_codeclistobject['codec_entries'][$BitrateRecordsCounter])) {
       
   989 					switch ($thisfile_asf_codeclistobject['codec_entries'][$BitrateRecordsCounter]['type_raw']) {
       
   990 						case 1:
       
   991 							$ASFbitrateVideo += $thisfile_asf_streambitrateproperties['bitrate_records'][$BitrateRecordsCounter]['bitrate'];
       
   992 							break;
       
   993 
       
   994 						case 2:
       
   995 							$ASFbitrateAudio += $thisfile_asf_streambitrateproperties['bitrate_records'][$BitrateRecordsCounter]['bitrate'];
       
   996 							break;
       
   997 
       
   998 						default:
       
   999 							// do nothing
       
  1000 							break;
       
  1001 					}
       
  1002 				}
       
  1003 			}
       
  1004 			if ($ASFbitrateAudio > 0) {
       
  1005 				$thisfile_audio['bitrate'] = $ASFbitrateAudio;
       
  1006 			}
       
  1007 			if ($ASFbitrateVideo > 0) {
       
  1008 				$thisfile_video['bitrate'] = $ASFbitrateVideo;
       
  1009 			}
       
  1010 		}
       
  1011 		if (isset($thisfile_asf['stream_properties_object']) && is_array($thisfile_asf['stream_properties_object'])) {
       
  1012 
       
  1013 			$thisfile_audio['bitrate'] = 0;
       
  1014 			$thisfile_video['bitrate'] = 0;
       
  1015 
       
  1016 			foreach ($thisfile_asf['stream_properties_object'] as $streamnumber => $streamdata) {
       
  1017 
       
  1018 				switch ($streamdata['stream_type']) {
       
  1019 					case GETID3_ASF_Audio_Media:
       
  1020 						// Field Name                   Field Type   Size (bits)
       
  1021 						// Codec ID / Format Tag        WORD         16              // unique ID of audio codec - defined as wFormatTag field of WAVEFORMATEX structure
       
  1022 						// Number of Channels           WORD         16              // number of channels of audio - defined as nChannels field of WAVEFORMATEX structure
       
  1023 						// Samples Per Second           DWORD        32              // in Hertz - defined as nSamplesPerSec field of WAVEFORMATEX structure
       
  1024 						// Average number of Bytes/sec  DWORD        32              // bytes/sec of audio stream  - defined as nAvgBytesPerSec field of WAVEFORMATEX structure
       
  1025 						// Block Alignment              WORD         16              // block size in bytes of audio codec - defined as nBlockAlign field of WAVEFORMATEX structure
       
  1026 						// 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
       
  1027 						// Codec Specific Data Size     WORD         16              // size in bytes of Codec Specific Data buffer - defined as cbSize field of WAVEFORMATEX structure
       
  1028 						// Codec Specific Data          BYTESTREAM   variable        // array of codec-specific data bytes
       
  1029 
       
  1030 						// shortcut
       
  1031 						$thisfile_asf['audio_media'][$streamnumber] = array();
       
  1032 						$thisfile_asf_audiomedia_currentstream      = &$thisfile_asf['audio_media'][$streamnumber];
       
  1033 
       
  1034 						$audiomediaoffset = 0;
       
  1035 
       
  1036 						$thisfile_asf_audiomedia_currentstream = getid3_riff::parseWAVEFORMATex(substr($streamdata['type_specific_data'], $audiomediaoffset, 16));
       
  1037 						$audiomediaoffset += 16;
       
  1038 
       
  1039 						$thisfile_audio['lossless'] = false;
       
  1040 						switch ($thisfile_asf_audiomedia_currentstream['raw']['wFormatTag']) {
       
  1041 							case 0x0001: // PCM
       
  1042 							case 0x0163: // WMA9 Lossless
       
  1043 								$thisfile_audio['lossless'] = true;
       
  1044 								break;
       
  1045 						}
       
  1046 
       
  1047 						if (!empty($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'])) {
       
  1048 							foreach ($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'] as $dummy => $dataarray) {
       
  1049 								if (isset($dataarray['flags']['stream_number']) && ($dataarray['flags']['stream_number'] == $streamnumber)) {
       
  1050 									$thisfile_asf_audiomedia_currentstream['bitrate'] = $dataarray['bitrate'];
       
  1051 									$thisfile_audio['bitrate'] += $dataarray['bitrate'];
       
  1052 									break;
       
  1053 								}
       
  1054 							}
       
  1055 						} else {
       
  1056 							if (!empty($thisfile_asf_audiomedia_currentstream['bytes_sec'])) {
       
  1057 								$thisfile_audio['bitrate'] += $thisfile_asf_audiomedia_currentstream['bytes_sec'] * 8;
       
  1058 							} elseif (!empty($thisfile_asf_audiomedia_currentstream['bitrate'])) {
       
  1059 								$thisfile_audio['bitrate'] += $thisfile_asf_audiomedia_currentstream['bitrate'];
       
  1060 							}
       
  1061 						}
       
  1062 						$thisfile_audio['streams'][$streamnumber]                = $thisfile_asf_audiomedia_currentstream;
       
  1063 						$thisfile_audio['streams'][$streamnumber]['wformattag']  = $thisfile_asf_audiomedia_currentstream['raw']['wFormatTag'];
       
  1064 						$thisfile_audio['streams'][$streamnumber]['lossless']    = $thisfile_audio['lossless'];
       
  1065 						$thisfile_audio['streams'][$streamnumber]['bitrate']     = $thisfile_audio['bitrate'];
       
  1066 						$thisfile_audio['streams'][$streamnumber]['dataformat']  = 'wma';
       
  1067 						unset($thisfile_audio['streams'][$streamnumber]['raw']);
       
  1068 
       
  1069 						$thisfile_asf_audiomedia_currentstream['codec_data_size'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $audiomediaoffset, 2));
       
  1070 						$audiomediaoffset += 2;
       
  1071 						$thisfile_asf_audiomedia_currentstream['codec_data']      = substr($streamdata['type_specific_data'], $audiomediaoffset, $thisfile_asf_audiomedia_currentstream['codec_data_size']);
       
  1072 						$audiomediaoffset += $thisfile_asf_audiomedia_currentstream['codec_data_size'];
       
  1073 
       
  1074 						break;
       
  1075 
       
  1076 					case GETID3_ASF_Video_Media:
       
  1077 						// Field Name                   Field Type   Size (bits)
       
  1078 						// Encoded Image Width          DWORD        32              // width of image in pixels
       
  1079 						// Encoded Image Height         DWORD        32              // height of image in pixels
       
  1080 						// Reserved Flags               BYTE         8               // hardcoded: 0x02
       
  1081 						// Format Data Size             WORD         16              // size of Format Data field in bytes
       
  1082 						// Format Data                  array of:    variable        //
       
  1083 						// * Format Data Size           DWORD        32              // number of bytes in Format Data field, in bytes - defined as biSize field of BITMAPINFOHEADER structure
       
  1084 						// * Image Width                LONG         32              // width of encoded image in pixels - defined as biWidth field of BITMAPINFOHEADER structure
       
  1085 						// * Image Height               LONG         32              // height of encoded image in pixels - defined as biHeight field of BITMAPINFOHEADER structure
       
  1086 						// * Reserved                   WORD         16              // hardcoded: 0x0001 - defined as biPlanes field of BITMAPINFOHEADER structure
       
  1087 						// * Bits Per Pixel Count       WORD         16              // bits per pixel - defined as biBitCount field of BITMAPINFOHEADER structure
       
  1088 						// * Compression ID             FOURCC       32              // fourcc of video codec - defined as biCompression field of BITMAPINFOHEADER structure
       
  1089 						// * Image Size                 DWORD        32              // image size in bytes - defined as biSizeImage field of BITMAPINFOHEADER structure
       
  1090 						// * Horizontal Pixels / Meter  DWORD        32              // horizontal resolution of target device in pixels per meter - defined as biXPelsPerMeter field of BITMAPINFOHEADER structure
       
  1091 						// * Vertical Pixels / Meter    DWORD        32              // vertical resolution of target device in pixels per meter - defined as biYPelsPerMeter field of BITMAPINFOHEADER structure
       
  1092 						// * Colors Used Count          DWORD        32              // number of color indexes in the color table that are actually used - defined as biClrUsed field of BITMAPINFOHEADER structure
       
  1093 						// * 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
       
  1094 						// * Codec Specific Data        BYTESTREAM   variable        // array of codec-specific data bytes
       
  1095 
       
  1096 						// shortcut
       
  1097 						$thisfile_asf['video_media'][$streamnumber] = array();
       
  1098 						$thisfile_asf_videomedia_currentstream      = &$thisfile_asf['video_media'][$streamnumber];
       
  1099 
       
  1100 						$videomediaoffset = 0;
       
  1101 						$thisfile_asf_videomedia_currentstream['image_width']                     = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
       
  1102 						$videomediaoffset += 4;
       
  1103 						$thisfile_asf_videomedia_currentstream['image_height']                    = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
       
  1104 						$videomediaoffset += 4;
       
  1105 						$thisfile_asf_videomedia_currentstream['flags']                           = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 1));
       
  1106 						$videomediaoffset += 1;
       
  1107 						$thisfile_asf_videomedia_currentstream['format_data_size']                = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 2));
       
  1108 						$videomediaoffset += 2;
       
  1109 						$thisfile_asf_videomedia_currentstream['format_data']['format_data_size'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
       
  1110 						$videomediaoffset += 4;
       
  1111 						$thisfile_asf_videomedia_currentstream['format_data']['image_width']      = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
       
  1112 						$videomediaoffset += 4;
       
  1113 						$thisfile_asf_videomedia_currentstream['format_data']['image_height']     = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
       
  1114 						$videomediaoffset += 4;
       
  1115 						$thisfile_asf_videomedia_currentstream['format_data']['reserved']         = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 2));
       
  1116 						$videomediaoffset += 2;
       
  1117 						$thisfile_asf_videomedia_currentstream['format_data']['bits_per_pixel']   = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 2));
       
  1118 						$videomediaoffset += 2;
       
  1119 						$thisfile_asf_videomedia_currentstream['format_data']['codec_fourcc']     = substr($streamdata['type_specific_data'], $videomediaoffset, 4);
       
  1120 						$videomediaoffset += 4;
       
  1121 						$thisfile_asf_videomedia_currentstream['format_data']['image_size']       = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
       
  1122 						$videomediaoffset += 4;
       
  1123 						$thisfile_asf_videomedia_currentstream['format_data']['horizontal_pels']  = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
       
  1124 						$videomediaoffset += 4;
       
  1125 						$thisfile_asf_videomedia_currentstream['format_data']['vertical_pels']    = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
       
  1126 						$videomediaoffset += 4;
       
  1127 						$thisfile_asf_videomedia_currentstream['format_data']['colors_used']      = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
       
  1128 						$videomediaoffset += 4;
       
  1129 						$thisfile_asf_videomedia_currentstream['format_data']['colors_important'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
       
  1130 						$videomediaoffset += 4;
       
  1131 						$thisfile_asf_videomedia_currentstream['format_data']['codec_data']       = substr($streamdata['type_specific_data'], $videomediaoffset);
       
  1132 
       
  1133 						if (!empty($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'])) {
       
  1134 							foreach ($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'] as $dummy => $dataarray) {
       
  1135 								if (isset($dataarray['flags']['stream_number']) && ($dataarray['flags']['stream_number'] == $streamnumber)) {
       
  1136 									$thisfile_asf_videomedia_currentstream['bitrate'] = $dataarray['bitrate'];
       
  1137 									$thisfile_video['streams'][$streamnumber]['bitrate'] = $dataarray['bitrate'];
       
  1138 									$thisfile_video['bitrate'] += $dataarray['bitrate'];
       
  1139 									break;
       
  1140 								}
       
  1141 							}
       
  1142 						}
       
  1143 
       
  1144 						$thisfile_asf_videomedia_currentstream['format_data']['codec'] = getid3_riff::fourccLookup($thisfile_asf_videomedia_currentstream['format_data']['codec_fourcc']);
       
  1145 
       
  1146 						$thisfile_video['streams'][$streamnumber]['fourcc']          = $thisfile_asf_videomedia_currentstream['format_data']['codec_fourcc'];
       
  1147 						$thisfile_video['streams'][$streamnumber]['codec']           = $thisfile_asf_videomedia_currentstream['format_data']['codec'];
       
  1148 						$thisfile_video['streams'][$streamnumber]['resolution_x']    = $thisfile_asf_videomedia_currentstream['image_width'];
       
  1149 						$thisfile_video['streams'][$streamnumber]['resolution_y']    = $thisfile_asf_videomedia_currentstream['image_height'];
       
  1150 						$thisfile_video['streams'][$streamnumber]['bits_per_sample'] = $thisfile_asf_videomedia_currentstream['format_data']['bits_per_pixel'];
       
  1151 						break;
       
  1152 
       
  1153 					default:
       
  1154 						break;
       
  1155 				}
       
  1156 			}
       
  1157 		}
       
  1158 
       
  1159 		while (ftell($this->getid3->fp) < $info['avdataend']) {
       
  1160 			$NextObjectDataHeader = fread($this->getid3->fp, 24);
       
  1161 			$offset = 0;
       
  1162 			$NextObjectGUID = substr($NextObjectDataHeader, 0, 16);
       
  1163 			$offset += 16;
       
  1164 			$NextObjectGUIDtext = $this->BytestringToGUID($NextObjectGUID);
       
  1165 			$NextObjectSize = getid3_lib::LittleEndian2Int(substr($NextObjectDataHeader, $offset, 8));
       
  1166 			$offset += 8;
       
  1167 
       
  1168 			switch ($NextObjectGUID) {
       
  1169 				case GETID3_ASF_Data_Object:
       
  1170 					// Data Object: (mandatory, one only)
       
  1171 					// Field Name                       Field Type   Size (bits)
       
  1172 					// Object ID                        GUID         128             // GUID for Data object - GETID3_ASF_Data_Object
       
  1173 					// Object Size                      QWORD        64              // size of Data object, including 50 bytes of Data Object header. may be 0 if FilePropertiesObject.BroadcastFlag == 1
       
  1174 					// File ID                          GUID         128             // unique identifier. identical to File ID field in Header Object
       
  1175 					// Total Data Packets               QWORD        64              // number of Data Packet entries in Data Object. invalid if FilePropertiesObject.BroadcastFlag == 1
       
  1176 					// Reserved                         WORD         16              // hardcoded: 0x0101
       
  1177 
       
  1178 					// shortcut
       
  1179 					$thisfile_asf['data_object'] = array();
       
  1180 					$thisfile_asf_dataobject     = &$thisfile_asf['data_object'];
       
  1181 
       
  1182 					$DataObjectData = $NextObjectDataHeader.fread($this->getid3->fp, 50 - 24);
       
  1183 					$offset = 24;
       
  1184 
       
  1185 					$thisfile_asf_dataobject['objectid']           = $NextObjectGUID;
       
  1186 					$thisfile_asf_dataobject['objectid_guid']      = $NextObjectGUIDtext;
       
  1187 					$thisfile_asf_dataobject['objectsize']         = $NextObjectSize;
       
  1188 
       
  1189 					$thisfile_asf_dataobject['fileid']             = substr($DataObjectData, $offset, 16);
       
  1190 					$offset += 16;
       
  1191 					$thisfile_asf_dataobject['fileid_guid']        = $this->BytestringToGUID($thisfile_asf_dataobject['fileid']);
       
  1192 					$thisfile_asf_dataobject['total_data_packets'] = getid3_lib::LittleEndian2Int(substr($DataObjectData, $offset, 8));
       
  1193 					$offset += 8;
       
  1194 					$thisfile_asf_dataobject['reserved']           = getid3_lib::LittleEndian2Int(substr($DataObjectData, $offset, 2));
       
  1195 					$offset += 2;
       
  1196 					if ($thisfile_asf_dataobject['reserved'] != 0x0101) {
       
  1197 						$info['warning'][] = 'data_object.reserved ('.getid3_lib::PrintHexBytes($thisfile_asf_dataobject['reserved']).') does not match expected value of "0x0101"';
       
  1198 						//return false;
       
  1199 						break;
       
  1200 					}
       
  1201 
       
  1202 					// Data Packets                     array of:    variable        //
       
  1203 					// * Error Correction Flags         BYTE         8               //
       
  1204 					// * * Error Correction Data Length bits         4               // if Error Correction Length Type == 00, size of Error Correction Data in bytes, else hardcoded: 0000
       
  1205 					// * * Opaque Data Present          bits         1               //
       
  1206 					// * * Error Correction Length Type bits         2               // number of bits for size of the error correction data. hardcoded: 00
       
  1207 					// * * Error Correction Present     bits         1               // If set, use Opaque Data Packet structure, else use Payload structure
       
  1208 					// * Error Correction Data
       
  1209 
       
  1210 					$info['avdataoffset'] = ftell($this->getid3->fp);
       
  1211 					fseek($this->getid3->fp, ($thisfile_asf_dataobject['objectsize'] - 50), SEEK_CUR); // skip actual audio/video data
       
  1212 					$info['avdataend'] = ftell($this->getid3->fp);
       
  1213 					break;
       
  1214 
       
  1215 				case GETID3_ASF_Simple_Index_Object:
       
  1216 					// Simple Index Object: (optional, recommended, one per video stream)
       
  1217 					// Field Name                       Field Type   Size (bits)
       
  1218 					// Object ID                        GUID         128             // GUID for Simple Index object - GETID3_ASF_Data_Object
       
  1219 					// Object Size                      QWORD        64              // size of Simple Index object, including 56 bytes of Simple Index Object header
       
  1220 					// File ID                          GUID         128             // unique identifier. may be zero or identical to File ID field in Data Object and Header Object
       
  1221 					// Index Entry Time Interval        QWORD        64              // interval between index entries in 100-nanosecond units
       
  1222 					// Maximum Packet Count             DWORD        32              // maximum packet count for all index entries
       
  1223 					// Index Entries Count              DWORD        32              // number of Index Entries structures
       
  1224 					// Index Entries                    array of:    variable        //
       
  1225 					// * Packet Number                  DWORD        32              // number of the Data Packet associated with this index entry
       
  1226 					// * Packet Count                   WORD         16              // number of Data Packets to sent at this index entry
       
  1227 
       
  1228 					// shortcut
       
  1229 					$thisfile_asf['simple_index_object'] = array();
       
  1230 					$thisfile_asf_simpleindexobject      = &$thisfile_asf['simple_index_object'];
       
  1231 
       
  1232 					$SimpleIndexObjectData = $NextObjectDataHeader.fread($this->getid3->fp, 56 - 24);
       
  1233 					$offset = 24;
       
  1234 
       
  1235 					$thisfile_asf_simpleindexobject['objectid']                  = $NextObjectGUID;
       
  1236 					$thisfile_asf_simpleindexobject['objectid_guid']             = $NextObjectGUIDtext;
       
  1237 					$thisfile_asf_simpleindexobject['objectsize']                = $NextObjectSize;
       
  1238 
       
  1239 					$thisfile_asf_simpleindexobject['fileid']                    =                  substr($SimpleIndexObjectData, $offset, 16);
       
  1240 					$offset += 16;
       
  1241 					$thisfile_asf_simpleindexobject['fileid_guid']               = $this->BytestringToGUID($thisfile_asf_simpleindexobject['fileid']);
       
  1242 					$thisfile_asf_simpleindexobject['index_entry_time_interval'] = getid3_lib::LittleEndian2Int(substr($SimpleIndexObjectData, $offset, 8));
       
  1243 					$offset += 8;
       
  1244 					$thisfile_asf_simpleindexobject['maximum_packet_count']      = getid3_lib::LittleEndian2Int(substr($SimpleIndexObjectData, $offset, 4));
       
  1245 					$offset += 4;
       
  1246 					$thisfile_asf_simpleindexobject['index_entries_count']       = getid3_lib::LittleEndian2Int(substr($SimpleIndexObjectData, $offset, 4));
       
  1247 					$offset += 4;
       
  1248 
       
  1249 					$IndexEntriesData = $SimpleIndexObjectData.fread($this->getid3->fp, 6 * $thisfile_asf_simpleindexobject['index_entries_count']);
       
  1250 					for ($IndexEntriesCounter = 0; $IndexEntriesCounter < $thisfile_asf_simpleindexobject['index_entries_count']; $IndexEntriesCounter++) {
       
  1251 						$thisfile_asf_simpleindexobject['index_entries'][$IndexEntriesCounter]['packet_number'] = getid3_lib::LittleEndian2Int(substr($IndexEntriesData, $offset, 4));
       
  1252 						$offset += 4;
       
  1253 						$thisfile_asf_simpleindexobject['index_entries'][$IndexEntriesCounter]['packet_count']  = getid3_lib::LittleEndian2Int(substr($IndexEntriesData, $offset, 4));
       
  1254 						$offset += 2;
       
  1255 					}
       
  1256 
       
  1257 					break;
       
  1258 
       
  1259 				case GETID3_ASF_Index_Object:
       
  1260 					// 6.2 ASF top-level Index Object (optional but recommended when appropriate, 0 or 1)
       
  1261 					// Field Name                       Field Type   Size (bits)
       
  1262 					// Object ID                        GUID         128             // GUID for the Index Object - GETID3_ASF_Index_Object
       
  1263 					// Object Size                      QWORD        64              // Specifies the size, in bytes, of the Index Object, including at least 34 bytes of Index Object header
       
  1264 					// Index Entry Time Interval        DWORD        32              // Specifies the time interval between each index entry in ms.
       
  1265 					// Index Specifiers Count           WORD         16              // Specifies the number of Index Specifiers structures in this Index Object.
       
  1266 					// Index Blocks Count               DWORD        32              // Specifies the number of Index Blocks structures in this Index Object.
       
  1267 
       
  1268 					// Index Entry Time Interval        DWORD        32              // Specifies the time interval between index entries in milliseconds.  This value cannot be 0.
       
  1269 					// Index Specifiers Count           WORD         16              // Specifies the number of entries in the Index Specifiers list.  Valid values are 1 and greater.
       
  1270 					// Index Specifiers                 array of:    varies          //
       
  1271 					// * Stream Number                  WORD         16              // Specifies the stream number that the Index Specifiers refer to. Valid values are between 1 and 127.
       
  1272 					// * Index Type                     WORD         16              // Specifies Index Type values as follows:
       
  1273 																					//   1 = Nearest Past Data Packet - indexes point to the data packet whose presentation time is closest to the index entry time.
       
  1274 																					//   2 = Nearest Past Media Object - indexes point to the closest data packet containing an entire object or first fragment of an object.
       
  1275 																					//   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.
       
  1276 																					//   Nearest Past Cleanpoint is the most common type of index.
       
  1277 					// Index Entry Count                DWORD        32              // Specifies the number of Index Entries in the block.
       
  1278 					// * 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.
       
  1279 					// * Index Entries                  array of:    varies          //
       
  1280 					// * * Offsets                      DWORD        varies          // An offset value of 0xffffffff indicates an invalid offset value
       
  1281 
       
  1282 					// shortcut
       
  1283 					$thisfile_asf['asf_index_object'] = array();
       
  1284 					$thisfile_asf_asfindexobject      = &$thisfile_asf['asf_index_object'];
       
  1285 
       
  1286 					$ASFIndexObjectData = $NextObjectDataHeader.fread($this->getid3->fp, 34 - 24);
       
  1287 					$offset = 24;
       
  1288 
       
  1289 					$thisfile_asf_asfindexobject['objectid']                  = $NextObjectGUID;
       
  1290 					$thisfile_asf_asfindexobject['objectid_guid']             = $NextObjectGUIDtext;
       
  1291 					$thisfile_asf_asfindexobject['objectsize']                = $NextObjectSize;
       
  1292 
       
  1293 					$thisfile_asf_asfindexobject['entry_time_interval']       = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4));
       
  1294 					$offset += 4;
       
  1295 					$thisfile_asf_asfindexobject['index_specifiers_count']    = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 2));
       
  1296 					$offset += 2;
       
  1297 					$thisfile_asf_asfindexobject['index_blocks_count']        = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4));
       
  1298 					$offset += 4;
       
  1299 
       
  1300 					$ASFIndexObjectData .= fread($this->getid3->fp, 4 * $thisfile_asf_asfindexobject['index_specifiers_count']);
       
  1301 					for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) {
       
  1302 						$IndexSpecifierStreamNumber = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 2));
       
  1303 						$offset += 2;
       
  1304 						$thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['stream_number']   = $IndexSpecifierStreamNumber;
       
  1305 						$thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['index_type']      = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 2));
       
  1306 						$offset += 2;
       
  1307 						$thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['index_type_text'] = $this->ASFIndexObjectIndexTypeLookup($thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['index_type']);
       
  1308 					}
       
  1309 
       
  1310 					$ASFIndexObjectData .= fread($this->getid3->fp, 4);
       
  1311 					$thisfile_asf_asfindexobject['index_entry_count'] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4));
       
  1312 					$offset += 4;
       
  1313 
       
  1314 					$ASFIndexObjectData .= fread($this->getid3->fp, 8 * $thisfile_asf_asfindexobject['index_specifiers_count']);
       
  1315 					for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) {
       
  1316 						$thisfile_asf_asfindexobject['block_positions'][$IndexSpecifiersCounter] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 8));
       
  1317 						$offset += 8;
       
  1318 					}
       
  1319 
       
  1320 					$ASFIndexObjectData .= fread($this->getid3->fp, 4 * $thisfile_asf_asfindexobject['index_specifiers_count'] * $thisfile_asf_asfindexobject['index_entry_count']);
       
  1321 					for ($IndexEntryCounter = 0; $IndexEntryCounter < $thisfile_asf_asfindexobject['index_entry_count']; $IndexEntryCounter++) {
       
  1322 						for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) {
       
  1323 							$thisfile_asf_asfindexobject['offsets'][$IndexSpecifiersCounter][$IndexEntryCounter] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4));
       
  1324 							$offset += 4;
       
  1325 						}
       
  1326 					}
       
  1327 					break;
       
  1328 
       
  1329 
       
  1330 				default:
       
  1331 					// Implementations shall ignore any standard or non-standard object that they do not know how to handle.
       
  1332 					if ($this->GUIDname($NextObjectGUIDtext)) {
       
  1333 						$info['warning'][] = 'unhandled GUID "'.$this->GUIDname($NextObjectGUIDtext).'" {'.$NextObjectGUIDtext.'} in ASF body at offset '.($offset - 16 - 8);
       
  1334 					} else {
       
  1335 						$info['warning'][] = 'unknown GUID {'.$NextObjectGUIDtext.'} in ASF body at offset '.(ftell($this->getid3->fp) - 16 - 8);
       
  1336 					}
       
  1337 					fseek($this->getid3->fp, ($NextObjectSize - 16 - 8), SEEK_CUR);
       
  1338 					break;
       
  1339 			}
       
  1340 		}
       
  1341 
       
  1342 		if (isset($thisfile_asf_codeclistobject['codec_entries']) && is_array($thisfile_asf_codeclistobject['codec_entries'])) {
       
  1343 			foreach ($thisfile_asf_codeclistobject['codec_entries'] as $streamnumber => $streamdata) {
       
  1344 				switch ($streamdata['information']) {
       
  1345 					case 'WMV1':
       
  1346 					case 'WMV2':
       
  1347 					case 'WMV3':
       
  1348 					case 'MSS1':
       
  1349 					case 'MSS2':
       
  1350 					case 'WMVA':
       
  1351 					case 'WVC1':
       
  1352 					case 'WMVP':
       
  1353 					case 'WVP2':
       
  1354 						$thisfile_video['dataformat'] = 'wmv';
       
  1355 						$info['mime_type'] = 'video/x-ms-wmv';
       
  1356 						break;
       
  1357 
       
  1358 					case 'MP42':
       
  1359 					case 'MP43':
       
  1360 					case 'MP4S':
       
  1361 					case 'mp4s':
       
  1362 						$thisfile_video['dataformat'] = 'asf';
       
  1363 						$info['mime_type'] = 'video/x-ms-asf';
       
  1364 						break;
       
  1365 
       
  1366 					default:
       
  1367 						switch ($streamdata['type_raw']) {
       
  1368 							case 1:
       
  1369 								if (strstr($this->TrimConvert($streamdata['name']), 'Windows Media')) {
       
  1370 									$thisfile_video['dataformat'] = 'wmv';
       
  1371 									if ($info['mime_type'] == 'video/x-ms-asf') {
       
  1372 										$info['mime_type'] = 'video/x-ms-wmv';
       
  1373 									}
       
  1374 								}
       
  1375 								break;
       
  1376 
       
  1377 							case 2:
       
  1378 								if (strstr($this->TrimConvert($streamdata['name']), 'Windows Media')) {
       
  1379 									$thisfile_audio['dataformat'] = 'wma';
       
  1380 									if ($info['mime_type'] == 'video/x-ms-asf') {
       
  1381 										$info['mime_type'] = 'audio/x-ms-wma';
       
  1382 									}
       
  1383 								}
       
  1384 								break;
       
  1385 
       
  1386 						}
       
  1387 						break;
       
  1388 				}
       
  1389 			}
       
  1390 		}
       
  1391 
       
  1392 		switch (isset($thisfile_audio['codec']) ? $thisfile_audio['codec'] : '') {
       
  1393 			case 'MPEG Layer-3':
       
  1394 				$thisfile_audio['dataformat'] = 'mp3';
       
  1395 				break;
       
  1396 
       
  1397 			default:
       
  1398 				break;
       
  1399 		}
       
  1400 
       
  1401 		if (isset($thisfile_asf_codeclistobject['codec_entries'])) {
       
  1402 			foreach ($thisfile_asf_codeclistobject['codec_entries'] as $streamnumber => $streamdata) {
       
  1403 				switch ($streamdata['type_raw']) {
       
  1404 
       
  1405 					case 1: // video
       
  1406 						$thisfile_video['encoder'] = $this->TrimConvert($thisfile_asf_codeclistobject['codec_entries'][$streamnumber]['name']);
       
  1407 						break;
       
  1408 
       
  1409 					case 2: // audio
       
  1410 						$thisfile_audio['encoder'] = $this->TrimConvert($thisfile_asf_codeclistobject['codec_entries'][$streamnumber]['name']);
       
  1411 
       
  1412 						// AH 2003-10-01
       
  1413 						$thisfile_audio['encoder_options'] = $this->TrimConvert($thisfile_asf_codeclistobject['codec_entries'][0]['description']);
       
  1414 
       
  1415 						$thisfile_audio['codec']   = $thisfile_audio['encoder'];
       
  1416 						break;
       
  1417 
       
  1418 					default:
       
  1419 						$info['warning'][] = 'Unknown streamtype: [codec_list_object][codec_entries]['.$streamnumber.'][type_raw] == '.$streamdata['type_raw'];
       
  1420 						break;
       
  1421 
       
  1422 				}
       
  1423 			}
       
  1424 		}
       
  1425 
       
  1426 		if (isset($info['audio'])) {
       
  1427 			$thisfile_audio['lossless']           = (isset($thisfile_audio['lossless'])           ? $thisfile_audio['lossless']           : false);
       
  1428 			$thisfile_audio['dataformat']         = (!empty($thisfile_audio['dataformat'])        ? $thisfile_audio['dataformat']         : 'asf');
       
  1429 		}
       
  1430 		if (!empty($thisfile_video['dataformat'])) {
       
  1431 			$thisfile_video['lossless']           = (isset($thisfile_audio['lossless'])           ? $thisfile_audio['lossless']           : false);
       
  1432 			$thisfile_video['pixel_aspect_ratio'] = (isset($thisfile_audio['pixel_aspect_ratio']) ? $thisfile_audio['pixel_aspect_ratio'] : (float) 1);
       
  1433 			$thisfile_video['dataformat']         = (!empty($thisfile_video['dataformat'])        ? $thisfile_video['dataformat']         : 'asf');
       
  1434 		}
       
  1435 		if (!empty($thisfile_video['streams'])) {
       
  1436 			$thisfile_video['streams']['resolution_x'] = 0;
       
  1437 			$thisfile_video['streams']['resolution_y'] = 0;
       
  1438 			foreach ($thisfile_video['streams'] as $key => $valuearray) {
       
  1439 				if (($valuearray['resolution_x'] > $thisfile_video['streams']['resolution_x']) || ($valuearray['resolution_y'] > $thisfile_video['streams']['resolution_y'])) {
       
  1440 					$thisfile_video['resolution_x'] = $valuearray['resolution_x'];
       
  1441 					$thisfile_video['resolution_y'] = $valuearray['resolution_y'];
       
  1442 				}
       
  1443 			}
       
  1444 		}
       
  1445 		$info['bitrate'] = (isset($thisfile_audio['bitrate']) ? $thisfile_audio['bitrate'] : 0) + (isset($thisfile_video['bitrate']) ? $thisfile_video['bitrate'] : 0);
       
  1446 
       
  1447 		if ((!isset($info['playtime_seconds']) || ($info['playtime_seconds'] <= 0)) && ($info['bitrate'] > 0)) {
       
  1448 			$info['playtime_seconds'] = ($info['filesize'] - $info['avdataoffset']) / ($info['bitrate'] / 8);
       
  1449 		}
       
  1450 
       
  1451 		return true;
       
  1452 	}
       
  1453 
       
  1454 	public static function ASFCodecListObjectTypeLookup($CodecListType) {
       
  1455 		static $ASFCodecListObjectTypeLookup = array();
       
  1456 		if (empty($ASFCodecListObjectTypeLookup)) {
       
  1457 			$ASFCodecListObjectTypeLookup[0x0001] = 'Video Codec';
       
  1458 			$ASFCodecListObjectTypeLookup[0x0002] = 'Audio Codec';
       
  1459 			$ASFCodecListObjectTypeLookup[0xFFFF] = 'Unknown Codec';
       
  1460 		}
       
  1461 
       
  1462 		return (isset($ASFCodecListObjectTypeLookup[$CodecListType]) ? $ASFCodecListObjectTypeLookup[$CodecListType] : 'Invalid Codec Type');
       
  1463 	}
       
  1464 
       
  1465 	public static function KnownGUIDs() {
       
  1466 		static $GUIDarray = array(
       
  1467 			'GETID3_ASF_Extended_Stream_Properties_Object'   => '14E6A5CB-C672-4332-8399-A96952065B5A',
       
  1468 			'GETID3_ASF_Padding_Object'                      => '1806D474-CADF-4509-A4BA-9AABCB96AAE8',
       
  1469 			'GETID3_ASF_Payload_Ext_Syst_Pixel_Aspect_Ratio' => '1B1EE554-F9EA-4BC8-821A-376B74E4C4B8',
       
  1470 			'GETID3_ASF_Script_Command_Object'               => '1EFB1A30-0B62-11D0-A39B-00A0C90348F6',
       
  1471 			'GETID3_ASF_No_Error_Correction'                 => '20FB5700-5B55-11CF-A8FD-00805F5C442B',
       
  1472 			'GETID3_ASF_Content_Branding_Object'             => '2211B3FA-BD23-11D2-B4B7-00A0C955FC6E',
       
  1473 			'GETID3_ASF_Content_Encryption_Object'           => '2211B3FB-BD23-11D2-B4B7-00A0C955FC6E',
       
  1474 			'GETID3_ASF_Digital_Signature_Object'            => '2211B3FC-BD23-11D2-B4B7-00A0C955FC6E',
       
  1475 			'GETID3_ASF_Extended_Content_Encryption_Object'  => '298AE614-2622-4C17-B935-DAE07EE9289C',
       
  1476 			'GETID3_ASF_Simple_Index_Object'                 => '33000890-E5B1-11CF-89F4-00A0C90349CB',
       
  1477 			'GETID3_ASF_Degradable_JPEG_Media'               => '35907DE0-E415-11CF-A917-00805F5C442B',
       
  1478 			'GETID3_ASF_Payload_Extension_System_Timecode'   => '399595EC-8667-4E2D-8FDB-98814CE76C1E',
       
  1479 			'GETID3_ASF_Binary_Media'                        => '3AFB65E2-47EF-40F2-AC2C-70A90D71D343',
       
  1480 			'GETID3_ASF_Timecode_Index_Object'               => '3CB73FD0-0C4A-4803-953D-EDF7B6228F0C',
       
  1481 			'GETID3_ASF_Metadata_Library_Object'             => '44231C94-9498-49D1-A141-1D134E457054',
       
  1482 			'GETID3_ASF_Reserved_3'                          => '4B1ACBE3-100B-11D0-A39B-00A0C90348F6',
       
  1483 			'GETID3_ASF_Reserved_4'                          => '4CFEDB20-75F6-11CF-9C0F-00A0C90349CB',
       
  1484 			'GETID3_ASF_Command_Media'                       => '59DACFC0-59E6-11D0-A3AC-00A0C90348F6',
       
  1485 			'GETID3_ASF_Header_Extension_Object'             => '5FBF03B5-A92E-11CF-8EE3-00C00C205365',
       
  1486 			'GETID3_ASF_Media_Object_Index_Parameters_Obj'   => '6B203BAD-3F11-4E84-ACA8-D7613DE2CFA7',
       
  1487 			'GETID3_ASF_Header_Object'                       => '75B22630-668E-11CF-A6D9-00AA0062CE6C',
       
  1488 			'GETID3_ASF_Content_Description_Object'          => '75B22633-668E-11CF-A6D9-00AA0062CE6C',
       
  1489 			'GETID3_ASF_Error_Correction_Object'             => '75B22635-668E-11CF-A6D9-00AA0062CE6C',
       
  1490 			'GETID3_ASF_Data_Object'                         => '75B22636-668E-11CF-A6D9-00AA0062CE6C',
       
  1491 			'GETID3_ASF_Web_Stream_Media_Subtype'            => '776257D4-C627-41CB-8F81-7AC7FF1C40CC',
       
  1492 			'GETID3_ASF_Stream_Bitrate_Properties_Object'    => '7BF875CE-468D-11D1-8D82-006097C9A2B2',
       
  1493 			'GETID3_ASF_Language_List_Object'                => '7C4346A9-EFE0-4BFC-B229-393EDE415C85',
       
  1494 			'GETID3_ASF_Codec_List_Object'                   => '86D15240-311D-11D0-A3A4-00A0C90348F6',
       
  1495 			'GETID3_ASF_Reserved_2'                          => '86D15241-311D-11D0-A3A4-00A0C90348F6',
       
  1496 			'GETID3_ASF_File_Properties_Object'              => '8CABDCA1-A947-11CF-8EE4-00C00C205365',
       
  1497 			'GETID3_ASF_File_Transfer_Media'                 => '91BD222C-F21C-497A-8B6D-5AA86BFC0185',
       
  1498 			'GETID3_ASF_Old_RTP_Extension_Data'              => '96800C63-4C94-11D1-837B-0080C7A37F95',
       
  1499 			'GETID3_ASF_Advanced_Mutual_Exclusion_Object'    => 'A08649CF-4775-4670-8A16-6E35357566CD',
       
  1500 			'GETID3_ASF_Bandwidth_Sharing_Object'            => 'A69609E6-517B-11D2-B6AF-00C04FD908E9',
       
  1501 			'GETID3_ASF_Reserved_1'                          => 'ABD3D211-A9BA-11cf-8EE6-00C00C205365',
       
  1502 			'GETID3_ASF_Bandwidth_Sharing_Exclusive'         => 'AF6060AA-5197-11D2-B6AF-00C04FD908E9',
       
  1503 			'GETID3_ASF_Bandwidth_Sharing_Partial'           => 'AF6060AB-5197-11D2-B6AF-00C04FD908E9',
       
  1504 			'GETID3_ASF_JFIF_Media'                          => 'B61BE100-5B4E-11CF-A8FD-00805F5C442B',
       
  1505 			'GETID3_ASF_Stream_Properties_Object'            => 'B7DC0791-A9B7-11CF-8EE6-00C00C205365',
       
  1506 			'GETID3_ASF_Video_Media'                         => 'BC19EFC0-5B4D-11CF-A8FD-00805F5C442B',
       
  1507 			'GETID3_ASF_Audio_Spread'                        => 'BFC3CD50-618F-11CF-8BB2-00AA00B4E220',
       
  1508 			'GETID3_ASF_Metadata_Object'                     => 'C5F8CBEA-5BAF-4877-8467-AA8C44FA4CCA',
       
  1509 			'GETID3_ASF_Payload_Ext_Syst_Sample_Duration'    => 'C6BD9450-867F-4907-83A3-C77921B733AD',
       
  1510 			'GETID3_ASF_Group_Mutual_Exclusion_Object'       => 'D1465A40-5A79-4338-B71B-E36B8FD6C249',
       
  1511 			'GETID3_ASF_Extended_Content_Description_Object' => 'D2D0A440-E307-11D2-97F0-00A0C95EA850',
       
  1512 			'GETID3_ASF_Stream_Prioritization_Object'        => 'D4FED15B-88D3-454F-81F0-ED5C45999E24',
       
  1513 			'GETID3_ASF_Payload_Ext_System_Content_Type'     => 'D590DC20-07BC-436C-9CF7-F3BBFBF1A4DC',
       
  1514 			'GETID3_ASF_Old_File_Properties_Object'          => 'D6E229D0-35DA-11D1-9034-00A0C90349BE',
       
  1515 			'GETID3_ASF_Old_ASF_Header_Object'               => 'D6E229D1-35DA-11D1-9034-00A0C90349BE',
       
  1516 			'GETID3_ASF_Old_ASF_Data_Object'                 => 'D6E229D2-35DA-11D1-9034-00A0C90349BE',
       
  1517 			'GETID3_ASF_Index_Object'                        => 'D6E229D3-35DA-11D1-9034-00A0C90349BE',
       
  1518 			'GETID3_ASF_Old_Stream_Properties_Object'        => 'D6E229D4-35DA-11D1-9034-00A0C90349BE',
       
  1519 			'GETID3_ASF_Old_Content_Description_Object'      => 'D6E229D5-35DA-11D1-9034-00A0C90349BE',
       
  1520 			'GETID3_ASF_Old_Script_Command_Object'           => 'D6E229D6-35DA-11D1-9034-00A0C90349BE',
       
  1521 			'GETID3_ASF_Old_Marker_Object'                   => 'D6E229D7-35DA-11D1-9034-00A0C90349BE',
       
  1522 			'GETID3_ASF_Old_Component_Download_Object'       => 'D6E229D8-35DA-11D1-9034-00A0C90349BE',
       
  1523 			'GETID3_ASF_Old_Stream_Group_Object'             => 'D6E229D9-35DA-11D1-9034-00A0C90349BE',
       
  1524 			'GETID3_ASF_Old_Scalable_Object'                 => 'D6E229DA-35DA-11D1-9034-00A0C90349BE',
       
  1525 			'GETID3_ASF_Old_Prioritization_Object'           => 'D6E229DB-35DA-11D1-9034-00A0C90349BE',
       
  1526 			'GETID3_ASF_Bitrate_Mutual_Exclusion_Object'     => 'D6E229DC-35DA-11D1-9034-00A0C90349BE',
       
  1527 			'GETID3_ASF_Old_Inter_Media_Dependency_Object'   => 'D6E229DD-35DA-11D1-9034-00A0C90349BE',
       
  1528 			'GETID3_ASF_Old_Rating_Object'                   => 'D6E229DE-35DA-11D1-9034-00A0C90349BE',
       
  1529 			'GETID3_ASF_Index_Parameters_Object'             => 'D6E229DF-35DA-11D1-9034-00A0C90349BE',
       
  1530 			'GETID3_ASF_Old_Color_Table_Object'              => 'D6E229E0-35DA-11D1-9034-00A0C90349BE',
       
  1531 			'GETID3_ASF_Old_Language_List_Object'            => 'D6E229E1-35DA-11D1-9034-00A0C90349BE',
       
  1532 			'GETID3_ASF_Old_Audio_Media'                     => 'D6E229E2-35DA-11D1-9034-00A0C90349BE',
       
  1533 			'GETID3_ASF_Old_Video_Media'                     => 'D6E229E3-35DA-11D1-9034-00A0C90349BE',
       
  1534 			'GETID3_ASF_Old_Image_Media'                     => 'D6E229E4-35DA-11D1-9034-00A0C90349BE',
       
  1535 			'GETID3_ASF_Old_Timecode_Media'                  => 'D6E229E5-35DA-11D1-9034-00A0C90349BE',
       
  1536 			'GETID3_ASF_Old_Text_Media'                      => 'D6E229E6-35DA-11D1-9034-00A0C90349BE',
       
  1537 			'GETID3_ASF_Old_MIDI_Media'                      => 'D6E229E7-35DA-11D1-9034-00A0C90349BE',
       
  1538 			'GETID3_ASF_Old_Command_Media'                   => 'D6E229E8-35DA-11D1-9034-00A0C90349BE',
       
  1539 			'GETID3_ASF_Old_No_Error_Concealment'            => 'D6E229EA-35DA-11D1-9034-00A0C90349BE',
       
  1540 			'GETID3_ASF_Old_Scrambled_Audio'                 => 'D6E229EB-35DA-11D1-9034-00A0C90349BE',
       
  1541 			'GETID3_ASF_Old_No_Color_Table'                  => 'D6E229EC-35DA-11D1-9034-00A0C90349BE',
       
  1542 			'GETID3_ASF_Old_SMPTE_Time'                      => 'D6E229ED-35DA-11D1-9034-00A0C90349BE',
       
  1543 			'GETID3_ASF_Old_ASCII_Text'                      => 'D6E229EE-35DA-11D1-9034-00A0C90349BE',
       
  1544 			'GETID3_ASF_Old_Unicode_Text'                    => 'D6E229EF-35DA-11D1-9034-00A0C90349BE',
       
  1545 			'GETID3_ASF_Old_HTML_Text'                       => 'D6E229F0-35DA-11D1-9034-00A0C90349BE',
       
  1546 			'GETID3_ASF_Old_URL_Command'                     => 'D6E229F1-35DA-11D1-9034-00A0C90349BE',
       
  1547 			'GETID3_ASF_Old_Filename_Command'                => 'D6E229F2-35DA-11D1-9034-00A0C90349BE',
       
  1548 			'GETID3_ASF_Old_ACM_Codec'                       => 'D6E229F3-35DA-11D1-9034-00A0C90349BE',
       
  1549 			'GETID3_ASF_Old_VCM_Codec'                       => 'D6E229F4-35DA-11D1-9034-00A0C90349BE',
       
  1550 			'GETID3_ASF_Old_QuickTime_Codec'                 => 'D6E229F5-35DA-11D1-9034-00A0C90349BE',
       
  1551 			'GETID3_ASF_Old_DirectShow_Transform_Filter'     => 'D6E229F6-35DA-11D1-9034-00A0C90349BE',
       
  1552 			'GETID3_ASF_Old_DirectShow_Rendering_Filter'     => 'D6E229F7-35DA-11D1-9034-00A0C90349BE',
       
  1553 			'GETID3_ASF_Old_No_Enhancement'                  => 'D6E229F8-35DA-11D1-9034-00A0C90349BE',
       
  1554 			'GETID3_ASF_Old_Unknown_Enhancement_Type'        => 'D6E229F9-35DA-11D1-9034-00A0C90349BE',
       
  1555 			'GETID3_ASF_Old_Temporal_Enhancement'            => 'D6E229FA-35DA-11D1-9034-00A0C90349BE',
       
  1556 			'GETID3_ASF_Old_Spatial_Enhancement'             => 'D6E229FB-35DA-11D1-9034-00A0C90349BE',
       
  1557 			'GETID3_ASF_Old_Quality_Enhancement'             => 'D6E229FC-35DA-11D1-9034-00A0C90349BE',
       
  1558 			'GETID3_ASF_Old_Number_of_Channels_Enhancement'  => 'D6E229FD-35DA-11D1-9034-00A0C90349BE',
       
  1559 			'GETID3_ASF_Old_Frequency_Response_Enhancement'  => 'D6E229FE-35DA-11D1-9034-00A0C90349BE',
       
  1560 			'GETID3_ASF_Old_Media_Object'                    => 'D6E229FF-35DA-11D1-9034-00A0C90349BE',
       
  1561 			'GETID3_ASF_Mutex_Language'                      => 'D6E22A00-35DA-11D1-9034-00A0C90349BE',
       
  1562 			'GETID3_ASF_Mutex_Bitrate'                       => 'D6E22A01-35DA-11D1-9034-00A0C90349BE',
       
  1563 			'GETID3_ASF_Mutex_Unknown'                       => 'D6E22A02-35DA-11D1-9034-00A0C90349BE',
       
  1564 			'GETID3_ASF_Old_ASF_Placeholder_Object'          => 'D6E22A0E-35DA-11D1-9034-00A0C90349BE',
       
  1565 			'GETID3_ASF_Old_Data_Unit_Extension_Object'      => 'D6E22A0F-35DA-11D1-9034-00A0C90349BE',
       
  1566 			'GETID3_ASF_Web_Stream_Format'                   => 'DA1E6B13-8359-4050-B398-388E965BF00C',
       
  1567 			'GETID3_ASF_Payload_Ext_System_File_Name'        => 'E165EC0E-19ED-45D7-B4A7-25CBD1E28E9B',
       
  1568 			'GETID3_ASF_Marker_Object'                       => 'F487CD01-A951-11CF-8EE6-00C00C205365',
       
  1569 			'GETID3_ASF_Timecode_Index_Parameters_Object'    => 'F55E496D-9797-4B5D-8C8B-604DFE9BFB24',
       
  1570 			'GETID3_ASF_Audio_Media'                         => 'F8699E40-5B4D-11CF-A8FD-00805F5C442B',
       
  1571 			'GETID3_ASF_Media_Object_Index_Object'           => 'FEB103F8-12AD-4C64-840F-2A1D2F7AD48C',
       
  1572 			'GETID3_ASF_Alt_Extended_Content_Encryption_Obj' => 'FF889EF1-ADEE-40DA-9E71-98704BB928CE',
       
  1573 			'GETID3_ASF_Index_Placeholder_Object'            => 'D9AADE20-7C17-4F9C-BC28-8555DD98E2A2', // http://cpan.uwinnipeg.ca/htdocs/Audio-WMA/Audio/WMA.pm.html
       
  1574 			'GETID3_ASF_Compatibility_Object'                => '26F18B5D-4584-47EC-9F5F-0E651F0452C9', // http://cpan.uwinnipeg.ca/htdocs/Audio-WMA/Audio/WMA.pm.html
       
  1575 		);
       
  1576 		return $GUIDarray;
       
  1577 	}
       
  1578 
       
  1579 	public static function GUIDname($GUIDstring) {
       
  1580 		static $GUIDarray = array();
       
  1581 		if (empty($GUIDarray)) {
       
  1582 			$GUIDarray = self::KnownGUIDs();
       
  1583 		}
       
  1584 		return array_search($GUIDstring, $GUIDarray);
       
  1585 	}
       
  1586 
       
  1587 	public static function ASFIndexObjectIndexTypeLookup($id) {
       
  1588 		static $ASFIndexObjectIndexTypeLookup = array();
       
  1589 		if (empty($ASFIndexObjectIndexTypeLookup)) {
       
  1590 			$ASFIndexObjectIndexTypeLookup[1] = 'Nearest Past Data Packet';
       
  1591 			$ASFIndexObjectIndexTypeLookup[2] = 'Nearest Past Media Object';
       
  1592 			$ASFIndexObjectIndexTypeLookup[3] = 'Nearest Past Cleanpoint';
       
  1593 		}
       
  1594 		return (isset($ASFIndexObjectIndexTypeLookup[$id]) ? $ASFIndexObjectIndexTypeLookup[$id] : 'invalid');
       
  1595 	}
       
  1596 
       
  1597 	public static function GUIDtoBytestring($GUIDstring) {
       
  1598 		// Microsoft defines these 16-byte (128-bit) GUIDs in the strangest way:
       
  1599 		// first 4 bytes are in little-endian order
       
  1600 		// next 2 bytes are appended in little-endian order
       
  1601 		// next 2 bytes are appended in little-endian order
       
  1602 		// next 2 bytes are appended in big-endian order
       
  1603 		// next 6 bytes are appended in big-endian order
       
  1604 
       
  1605 		// AaBbCcDd-EeFf-GgHh-IiJj-KkLlMmNnOoPp is stored as this 16-byte string:
       
  1606 		// $Dd $Cc $Bb $Aa $Ff $Ee $Hh $Gg $Ii $Jj $Kk $Ll $Mm $Nn $Oo $Pp
       
  1607 
       
  1608 		$hexbytecharstring  = chr(hexdec(substr($GUIDstring,  6, 2)));
       
  1609 		$hexbytecharstring .= chr(hexdec(substr($GUIDstring,  4, 2)));
       
  1610 		$hexbytecharstring .= chr(hexdec(substr($GUIDstring,  2, 2)));
       
  1611 		$hexbytecharstring .= chr(hexdec(substr($GUIDstring,  0, 2)));
       
  1612 
       
  1613 		$hexbytecharstring .= chr(hexdec(substr($GUIDstring, 11, 2)));
       
  1614 		$hexbytecharstring .= chr(hexdec(substr($GUIDstring,  9, 2)));
       
  1615 
       
  1616 		$hexbytecharstring .= chr(hexdec(substr($GUIDstring, 16, 2)));
       
  1617 		$hexbytecharstring .= chr(hexdec(substr($GUIDstring, 14, 2)));
       
  1618 
       
  1619 		$hexbytecharstring .= chr(hexdec(substr($GUIDstring, 19, 2)));
       
  1620 		$hexbytecharstring .= chr(hexdec(substr($GUIDstring, 21, 2)));
       
  1621 
       
  1622 		$hexbytecharstring .= chr(hexdec(substr($GUIDstring, 24, 2)));
       
  1623 		$hexbytecharstring .= chr(hexdec(substr($GUIDstring, 26, 2)));
       
  1624 		$hexbytecharstring .= chr(hexdec(substr($GUIDstring, 28, 2)));
       
  1625 		$hexbytecharstring .= chr(hexdec(substr($GUIDstring, 30, 2)));
       
  1626 		$hexbytecharstring .= chr(hexdec(substr($GUIDstring, 32, 2)));
       
  1627 		$hexbytecharstring .= chr(hexdec(substr($GUIDstring, 34, 2)));
       
  1628 
       
  1629 		return $hexbytecharstring;
       
  1630 	}
       
  1631 
       
  1632 	public static function BytestringToGUID($Bytestring) {
       
  1633 		$GUIDstring  = str_pad(dechex(ord($Bytestring{3})),  2, '0', STR_PAD_LEFT);
       
  1634 		$GUIDstring .= str_pad(dechex(ord($Bytestring{2})),  2, '0', STR_PAD_LEFT);
       
  1635 		$GUIDstring .= str_pad(dechex(ord($Bytestring{1})),  2, '0', STR_PAD_LEFT);
       
  1636 		$GUIDstring .= str_pad(dechex(ord($Bytestring{0})),  2, '0', STR_PAD_LEFT);
       
  1637 		$GUIDstring .= '-';
       
  1638 		$GUIDstring .= str_pad(dechex(ord($Bytestring{5})),  2, '0', STR_PAD_LEFT);
       
  1639 		$GUIDstring .= str_pad(dechex(ord($Bytestring{4})),  2, '0', STR_PAD_LEFT);
       
  1640 		$GUIDstring .= '-';
       
  1641 		$GUIDstring .= str_pad(dechex(ord($Bytestring{7})),  2, '0', STR_PAD_LEFT);
       
  1642 		$GUIDstring .= str_pad(dechex(ord($Bytestring{6})),  2, '0', STR_PAD_LEFT);
       
  1643 		$GUIDstring .= '-';
       
  1644 		$GUIDstring .= str_pad(dechex(ord($Bytestring{8})),  2, '0', STR_PAD_LEFT);
       
  1645 		$GUIDstring .= str_pad(dechex(ord($Bytestring{9})),  2, '0', STR_PAD_LEFT);
       
  1646 		$GUIDstring .= '-';
       
  1647 		$GUIDstring .= str_pad(dechex(ord($Bytestring{10})), 2, '0', STR_PAD_LEFT);
       
  1648 		$GUIDstring .= str_pad(dechex(ord($Bytestring{11})), 2, '0', STR_PAD_LEFT);
       
  1649 		$GUIDstring .= str_pad(dechex(ord($Bytestring{12})), 2, '0', STR_PAD_LEFT);
       
  1650 		$GUIDstring .= str_pad(dechex(ord($Bytestring{13})), 2, '0', STR_PAD_LEFT);
       
  1651 		$GUIDstring .= str_pad(dechex(ord($Bytestring{14})), 2, '0', STR_PAD_LEFT);
       
  1652 		$GUIDstring .= str_pad(dechex(ord($Bytestring{15})), 2, '0', STR_PAD_LEFT);
       
  1653 
       
  1654 		return strtoupper($GUIDstring);
       
  1655 	}
       
  1656 
       
  1657 	public static function FILETIMEtoUNIXtime($FILETIME, $round=true) {
       
  1658 		// FILETIME is a 64-bit unsigned integer representing
       
  1659 		// the number of 100-nanosecond intervals since January 1, 1601
       
  1660 		// UNIX timestamp is number of seconds since January 1, 1970
       
  1661 		// 116444736000000000 = 10000000 * 60 * 60 * 24 * 365 * 369 + 89 leap days
       
  1662 		if ($round) {
       
  1663 			return intval(round(($FILETIME - 116444736000000000) / 10000000));
       
  1664 		}
       
  1665 		return ($FILETIME - 116444736000000000) / 10000000;
       
  1666 	}
       
  1667 
       
  1668 	public static function WMpictureTypeLookup($WMpictureType) {
       
  1669 		static $WMpictureTypeLookup = array();
       
  1670 		if (empty($WMpictureTypeLookup)) {
       
  1671 			$WMpictureTypeLookup[0x03] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Front Cover');
       
  1672 			$WMpictureTypeLookup[0x04] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Back Cover');
       
  1673 			$WMpictureTypeLookup[0x00] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'User Defined');
       
  1674 			$WMpictureTypeLookup[0x05] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Leaflet Page');
       
  1675 			$WMpictureTypeLookup[0x06] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Media Label');
       
  1676 			$WMpictureTypeLookup[0x07] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Lead Artist');
       
  1677 			$WMpictureTypeLookup[0x08] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Artist');
       
  1678 			$WMpictureTypeLookup[0x09] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Conductor');
       
  1679 			$WMpictureTypeLookup[0x0A] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Band');
       
  1680 			$WMpictureTypeLookup[0x0B] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Composer');
       
  1681 			$WMpictureTypeLookup[0x0C] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Lyricist');
       
  1682 			$WMpictureTypeLookup[0x0D] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Recording Location');
       
  1683 			$WMpictureTypeLookup[0x0E] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'During Recording');
       
  1684 			$WMpictureTypeLookup[0x0F] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'During Performance');
       
  1685 			$WMpictureTypeLookup[0x10] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Video Screen Capture');
       
  1686 			$WMpictureTypeLookup[0x12] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Illustration');
       
  1687 			$WMpictureTypeLookup[0x13] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Band Logotype');
       
  1688 			$WMpictureTypeLookup[0x14] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Publisher Logotype');
       
  1689 		}
       
  1690 		return (isset($WMpictureTypeLookup[$WMpictureType]) ? $WMpictureTypeLookup[$WMpictureType] : '');
       
  1691 	}
       
  1692 
       
  1693 	public function ASF_HeaderExtensionObjectDataParse(&$asf_header_extension_object_data, &$unhandled_sections) {
       
  1694 		// http://msdn.microsoft.com/en-us/library/bb643323.aspx
       
  1695 
       
  1696 		$offset = 0;
       
  1697 		$objectOffset = 0;
       
  1698 		$HeaderExtensionObjectParsed = array();
       
  1699 		while ($objectOffset < strlen($asf_header_extension_object_data)) {
       
  1700 			$offset = $objectOffset;
       
  1701 			$thisObject = array();
       
  1702 
       
  1703 			$thisObject['guid']                              =                              substr($asf_header_extension_object_data, $offset, 16);
       
  1704 			$offset += 16;
       
  1705 			$thisObject['guid_text'] = $this->BytestringToGUID($thisObject['guid']);
       
  1706 			$thisObject['guid_name'] = $this->GUIDname($thisObject['guid_text']);
       
  1707 
       
  1708 			$thisObject['size']                              = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  8));
       
  1709 			$offset += 8;
       
  1710 			if ($thisObject['size'] <= 0) {
       
  1711 				break;
       
  1712 			}
       
  1713 
       
  1714 			switch ($thisObject['guid']) {
       
  1715 				case GETID3_ASF_Extended_Stream_Properties_Object:
       
  1716 					$thisObject['start_time']                        = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  8));
       
  1717 					$offset += 8;
       
  1718 					$thisObject['start_time_unix']                   = $this->FILETIMEtoUNIXtime($thisObject['start_time']);
       
  1719 
       
  1720 					$thisObject['end_time']                          = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  8));
       
  1721 					$offset += 8;
       
  1722 					$thisObject['end_time_unix']                     = $this->FILETIMEtoUNIXtime($thisObject['end_time']);
       
  1723 
       
  1724 					$thisObject['data_bitrate']                      = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
       
  1725 					$offset += 4;
       
  1726 
       
  1727 					$thisObject['buffer_size']                       = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
       
  1728 					$offset += 4;
       
  1729 
       
  1730 					$thisObject['initial_buffer_fullness']           = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
       
  1731 					$offset += 4;
       
  1732 
       
  1733 					$thisObject['alternate_data_bitrate']            = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
       
  1734 					$offset += 4;
       
  1735 
       
  1736 					$thisObject['alternate_buffer_size']             = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
       
  1737 					$offset += 4;
       
  1738 
       
  1739 					$thisObject['alternate_initial_buffer_fullness'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
       
  1740 					$offset += 4;
       
  1741 
       
  1742 					$thisObject['maximum_object_size']               = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
       
  1743 					$offset += 4;
       
  1744 
       
  1745 					$thisObject['flags_raw']                         = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
       
  1746 					$offset += 4;
       
  1747 					$thisObject['flags']['reliable']                = (bool) $thisObject['flags_raw'] & 0x00000001;
       
  1748 					$thisObject['flags']['seekable']                = (bool) $thisObject['flags_raw'] & 0x00000002;
       
  1749 					$thisObject['flags']['no_cleanpoints']          = (bool) $thisObject['flags_raw'] & 0x00000004;
       
  1750 					$thisObject['flags']['resend_live_cleanpoints'] = (bool) $thisObject['flags_raw'] & 0x00000008;
       
  1751 
       
  1752 					$thisObject['stream_number']                     = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
       
  1753 					$offset += 2;
       
  1754 
       
  1755 					$thisObject['stream_language_id_index']          = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
       
  1756 					$offset += 2;
       
  1757 
       
  1758 					$thisObject['average_time_per_frame']            = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
       
  1759 					$offset += 4;
       
  1760 
       
  1761 					$thisObject['stream_name_count']                 = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
       
  1762 					$offset += 2;
       
  1763 
       
  1764 					$thisObject['payload_extension_system_count']    = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
       
  1765 					$offset += 2;
       
  1766 
       
  1767 					for ($i = 0; $i < $thisObject['stream_name_count']; $i++) {
       
  1768 						$streamName = array();
       
  1769 
       
  1770 						$streamName['language_id_index']             = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
       
  1771 						$offset += 2;
       
  1772 
       
  1773 						$streamName['stream_name_length']            = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
       
  1774 						$offset += 2;
       
  1775 
       
  1776 						$streamName['stream_name']                   = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  $streamName['stream_name_length']));
       
  1777 						$offset += $streamName['stream_name_length'];
       
  1778 
       
  1779 						$thisObject['stream_names'][$i] = $streamName;
       
  1780 					}
       
  1781 
       
  1782 					for ($i = 0; $i < $thisObject['payload_extension_system_count']; $i++) {
       
  1783 						$payloadExtensionSystem = array();
       
  1784 
       
  1785 						$payloadExtensionSystem['extension_system_id']   =                              substr($asf_header_extension_object_data, $offset, 16);
       
  1786 						$offset += 16;
       
  1787 						$payloadExtensionSystem['extension_system_id_text'] = $this->BytestringToGUID($payloadExtensionSystem['extension_system_id']);
       
  1788 
       
  1789 						$payloadExtensionSystem['extension_system_size'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
       
  1790 						$offset += 2;
       
  1791 						if ($payloadExtensionSystem['extension_system_size'] <= 0) {
       
  1792 							break 2;
       
  1793 						}
       
  1794 
       
  1795 						$payloadExtensionSystem['extension_system_info_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
       
  1796 						$offset += 4;
       
  1797 
       
  1798 						$payloadExtensionSystem['extension_system_info_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  $payloadExtensionSystem['extension_system_info_length']));
       
  1799 						$offset += $payloadExtensionSystem['extension_system_info_length'];
       
  1800 
       
  1801 						$thisObject['payload_extension_systems'][$i] = $payloadExtensionSystem;
       
  1802 					}
       
  1803 
       
  1804 					break;
       
  1805 
       
  1806 				case GETID3_ASF_Padding_Object:
       
  1807 					// padding, skip it
       
  1808 					break;
       
  1809 
       
  1810 				case GETID3_ASF_Metadata_Object:
       
  1811 					$thisObject['description_record_counts'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
       
  1812 					$offset += 2;
       
  1813 
       
  1814 					for ($i = 0; $i < $thisObject['description_record_counts']; $i++) {
       
  1815 						$descriptionRecord = array();
       
  1816 
       
  1817 						$descriptionRecord['reserved_1']         = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2)); // must be zero
       
  1818 						$offset += 2;
       
  1819 
       
  1820 						$descriptionRecord['stream_number']      = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
       
  1821 						$offset += 2;
       
  1822 
       
  1823 						$descriptionRecord['name_length']        = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
       
  1824 						$offset += 2;
       
  1825 
       
  1826 						$descriptionRecord['data_type']          = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
       
  1827 						$offset += 2;
       
  1828 						$descriptionRecord['data_type_text'] = $this->ASFmetadataLibraryObjectDataTypeLookup($descriptionRecord['data_type']);
       
  1829 
       
  1830 						$descriptionRecord['data_length']        = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
       
  1831 						$offset += 4;
       
  1832 
       
  1833 						$descriptionRecord['name']               =                              substr($asf_header_extension_object_data, $offset,  $descriptionRecord['name_length']);
       
  1834 						$offset += $descriptionRecord['name_length'];
       
  1835 
       
  1836 						$descriptionRecord['data']               =                              substr($asf_header_extension_object_data, $offset,  $descriptionRecord['data_length']);
       
  1837 						$offset += $descriptionRecord['data_length'];
       
  1838 						switch ($descriptionRecord['data_type']) {
       
  1839 							case 0x0000: // Unicode string
       
  1840 								break;
       
  1841 
       
  1842 							case 0x0001: // BYTE array
       
  1843 								// do nothing
       
  1844 								break;
       
  1845 
       
  1846 							case 0x0002: // BOOL
       
  1847 								$descriptionRecord['data'] = (bool) getid3_lib::LittleEndian2Int($descriptionRecord['data']);
       
  1848 								break;
       
  1849 
       
  1850 							case 0x0003: // DWORD
       
  1851 							case 0x0004: // QWORD
       
  1852 							case 0x0005: // WORD
       
  1853 								$descriptionRecord['data'] = getid3_lib::LittleEndian2Int($descriptionRecord['data']);
       
  1854 								break;
       
  1855 
       
  1856 							case 0x0006: // GUID
       
  1857 								$descriptionRecord['data_text'] = $this->BytestringToGUID($descriptionRecord['data']);
       
  1858 								break;
       
  1859 						}
       
  1860 
       
  1861 						$thisObject['description_record'][$i] = $descriptionRecord;
       
  1862 					}
       
  1863 					break;
       
  1864 
       
  1865 				case GETID3_ASF_Language_List_Object:
       
  1866 					$thisObject['language_id_record_counts'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
       
  1867 					$offset += 2;
       
  1868 
       
  1869 					for ($i = 0; $i < $thisObject['language_id_record_counts']; $i++) {
       
  1870 						$languageIDrecord = array();
       
  1871 
       
  1872 						$languageIDrecord['language_id_length']         = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  1));
       
  1873 						$offset += 1;
       
  1874 
       
  1875 						$languageIDrecord['language_id']                =                              substr($asf_header_extension_object_data, $offset,  $languageIDrecord['language_id_length']);
       
  1876 						$offset += $languageIDrecord['language_id_length'];
       
  1877 
       
  1878 						$thisObject['language_id_record'][$i] = $languageIDrecord;
       
  1879 					}
       
  1880 					break;
       
  1881 
       
  1882 				case GETID3_ASF_Metadata_Library_Object:
       
  1883 					$thisObject['description_records_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
       
  1884 					$offset += 2;
       
  1885 
       
  1886 					for ($i = 0; $i < $thisObject['description_records_count']; $i++) {
       
  1887 						$descriptionRecord = array();
       
  1888 
       
  1889 						$descriptionRecord['language_list_index'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
       
  1890 						$offset += 2;
       
  1891 
       
  1892 						$descriptionRecord['stream_number']       = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
       
  1893 						$offset += 2;
       
  1894 
       
  1895 						$descriptionRecord['name_length']         = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
       
  1896 						$offset += 2;
       
  1897 
       
  1898 						$descriptionRecord['data_type']           = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
       
  1899 						$offset += 2;
       
  1900 						$descriptionRecord['data_type_text'] = $this->ASFmetadataLibraryObjectDataTypeLookup($descriptionRecord['data_type']);
       
  1901 
       
  1902 						$descriptionRecord['data_length']         = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
       
  1903 						$offset += 4;
       
  1904 
       
  1905 						$descriptionRecord['name']                =                              substr($asf_header_extension_object_data, $offset,  $descriptionRecord['name_length']);
       
  1906 						$offset += $descriptionRecord['name_length'];
       
  1907 
       
  1908 						$descriptionRecord['data']                =                              substr($asf_header_extension_object_data, $offset,  $descriptionRecord['data_length']);
       
  1909 						$offset += $descriptionRecord['data_length'];
       
  1910 
       
  1911 						if (preg_match('#^WM/Picture$#', str_replace("\x00", '', trim($descriptionRecord['name'])))) {
       
  1912 							$WMpicture = $this->ASF_WMpicture($descriptionRecord['data']);
       
  1913 							foreach ($WMpicture as $key => $value) {
       
  1914 								$descriptionRecord['data'] = $WMpicture;
       
  1915 							}
       
  1916 							unset($WMpicture);
       
  1917 						}
       
  1918 
       
  1919 						$thisObject['description_record'][$i] = $descriptionRecord;
       
  1920 					}
       
  1921 					break;
       
  1922 
       
  1923 				default:
       
  1924 					$unhandled_sections++;
       
  1925 					if ($this->GUIDname($thisObject['guid_text'])) {
       
  1926 						$this->getid3->info['warning'][] = 'unhandled Header Extension Object GUID "'.$this->GUIDname($thisObject['guid_text']).'" {'.$thisObject['guid_text'].'} at offset '.($offset - 16 - 8);
       
  1927 					} else {
       
  1928 						$this->getid3->info['warning'][] = 'unknown Header Extension Object GUID {'.$thisObject['guid_text'].'} in at offset '.($offset - 16 - 8);
       
  1929 					}
       
  1930 					break;
       
  1931 			}
       
  1932 			$HeaderExtensionObjectParsed[] = $thisObject;
       
  1933 
       
  1934 			$objectOffset += $thisObject['size'];
       
  1935 		}
       
  1936 		return $HeaderExtensionObjectParsed;
       
  1937 	}
       
  1938 
       
  1939 
       
  1940 	public static function ASFmetadataLibraryObjectDataTypeLookup($id) {
       
  1941 		static $ASFmetadataLibraryObjectDataTypeLookup = array(
       
  1942 			0x0000 => 'Unicode string', // The data consists of a sequence of Unicode characters
       
  1943 			0x0001 => 'BYTE array',     // The type of the data is implementation-specific
       
  1944 			0x0002 => 'BOOL',           // The data is 2 bytes long and should be interpreted as a 16-bit unsigned integer. Only 0x0000 or 0x0001 are permitted values
       
  1945 			0x0003 => 'DWORD',          // The data is 4 bytes long and should be interpreted as a 32-bit unsigned integer
       
  1946 			0x0004 => 'QWORD',          // The data is 8 bytes long and should be interpreted as a 64-bit unsigned integer
       
  1947 			0x0005 => 'WORD',           // The data is 2 bytes long and should be interpreted as a 16-bit unsigned integer
       
  1948 			0x0006 => 'GUID',           // The data is 16 bytes long and should be interpreted as a 128-bit GUID
       
  1949 		);
       
  1950 		return (isset($ASFmetadataLibraryObjectDataTypeLookup[$id]) ? $ASFmetadataLibraryObjectDataTypeLookup[$id] : 'invalid');
       
  1951 	}
       
  1952 
       
  1953 	public function ASF_WMpicture(&$data) {
       
  1954 		//typedef struct _WMPicture{
       
  1955 		//  LPWSTR  pwszMIMEType;
       
  1956 		//  BYTE  bPictureType;
       
  1957 		//  LPWSTR  pwszDescription;
       
  1958 		//  DWORD  dwDataLen;
       
  1959 		//  BYTE*  pbData;
       
  1960 		//} WM_PICTURE;
       
  1961 
       
  1962 		$WMpicture = array();
       
  1963 
       
  1964 		$offset = 0;
       
  1965 		$WMpicture['image_type_id'] = getid3_lib::LittleEndian2Int(substr($data, $offset, 1));
       
  1966 		$offset += 1;
       
  1967 		$WMpicture['image_type']    = $this->WMpictureTypeLookup($WMpicture['image_type_id']);
       
  1968 		$WMpicture['image_size']    = getid3_lib::LittleEndian2Int(substr($data, $offset, 4));
       
  1969 		$offset += 4;
       
  1970 
       
  1971 		$WMpicture['image_mime'] = '';
       
  1972 		do {
       
  1973 			$next_byte_pair = substr($data, $offset, 2);
       
  1974 			$offset += 2;
       
  1975 			$WMpicture['image_mime'] .= $next_byte_pair;
       
  1976 		} while ($next_byte_pair !== "\x00\x00");
       
  1977 
       
  1978 		$WMpicture['image_description'] = '';
       
  1979 		do {
       
  1980 			$next_byte_pair = substr($data, $offset, 2);
       
  1981 			$offset += 2;
       
  1982 			$WMpicture['image_description'] .= $next_byte_pair;
       
  1983 		} while ($next_byte_pair !== "\x00\x00");
       
  1984 
       
  1985 		$WMpicture['dataoffset'] = $offset;
       
  1986 		$WMpicture['data'] = substr($data, $offset);
       
  1987 
       
  1988 		$imageinfo = array();
       
  1989 		$WMpicture['image_mime'] = '';
       
  1990 		$imagechunkcheck = getid3_lib::GetDataImageSize($WMpicture['data'], $imageinfo);
       
  1991 		unset($imageinfo);
       
  1992 		if (!empty($imagechunkcheck)) {
       
  1993 			$WMpicture['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]);
       
  1994 		}
       
  1995 		if (!isset($this->getid3->info['asf']['comments']['picture'])) {
       
  1996 			$this->getid3->info['asf']['comments']['picture'] = array();
       
  1997 		}
       
  1998 		$this->getid3->info['asf']['comments']['picture'][] = array('data'=>$WMpicture['data'], 'image_mime'=>$WMpicture['image_mime']);
       
  1999 
       
  2000 		return $WMpicture;
       
  2001 	}
       
  2002 
       
  2003 
       
  2004 	// Remove terminator 00 00 and convert UTF-16LE to Latin-1
       
  2005 	public static function TrimConvert($string) {
       
  2006 		return trim(getid3_lib::iconv_fallback('UTF-16LE', 'ISO-8859-1', self::TrimTerm($string)), ' ');
       
  2007 	}
       
  2008 
       
  2009 
       
  2010 	// Remove terminator 00 00
       
  2011 	public static function TrimTerm($string) {
       
  2012 		// remove terminator, only if present (it should be, but...)
       
  2013 		if (substr($string, -2) === "\x00\x00") {
       
  2014 			$string = substr($string, 0, -2);
       
  2015 		}
       
  2016 		return $string;
       
  2017 	}
       
  2018 
       
  2019 }