File indexing completed on 2025-05-04 05:28:40
0001 <?php 0002 ///////////////////////////////////////////////////////////////// 0003 /// getID3() by James Heinrich <info@getid3.org> // 0004 // available at http://getid3.sourceforge.net // 0005 // or http://www.getid3.org // 0006 // also https://github.com/JamesHeinrich/getID3 // 0007 ///////////////////////////////////////////////////////////////// 0008 // See readme.txt for more details // 0009 ///////////////////////////////////////////////////////////////// 0010 // // 0011 // module.audio-video.asf.php // 0012 // module for analyzing ASF, WMA and WMV files // 0013 // dependencies: module.audio-video.riff.php // 0014 // /// 0015 ///////////////////////////////////////////////////////////////// 0016 0017 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true); 0018 0019 class getid3_asf extends getid3_handler { 0020 0021 public function __construct(getID3 $getid3) { 0022 parent::__construct($getid3); // extends getid3_handler::__construct() 0023 0024 // initialize all GUID constants 0025 $GUIDarray = $this->KnownGUIDs(); 0026 foreach ($GUIDarray as $GUIDname => $hexstringvalue) { 0027 if (!defined($GUIDname)) { 0028 define($GUIDname, $this->GUIDtoBytestring($hexstringvalue)); 0029 } 0030 } 0031 } 0032 0033 public function Analyze() { 0034 $info = &$this->getid3->info; 0035 0036 // Shortcuts 0037 $thisfile_audio = &$info['audio']; 0038 $thisfile_video = &$info['video']; 0039 $info['asf'] = array(); 0040 $thisfile_asf = &$info['asf']; 0041 $thisfile_asf['comments'] = array(); 0042 $thisfile_asf_comments = &$thisfile_asf['comments']; 0043 $thisfile_asf['header_object'] = array(); 0044 $thisfile_asf_headerobject = &$thisfile_asf['header_object']; 0045 0046 0047 // ASF structure: 0048 // * Header Object [required] 0049 // * File Properties Object [required] (global file attributes) 0050 // * Stream Properties Object [required] (defines media stream & characteristics) 0051 // * Header Extension Object [required] (additional functionality) 0052 // * Content Description Object (bibliographic information) 0053 // * Script Command Object (commands for during playback) 0054 // * Marker Object (named jumped points within the file) 0055 // * Data Object [required] 0056 // * Data Packets 0057 // * Index Object 0058 0059 // Header Object: (mandatory, one only) 0060 // Field Name Field Type Size (bits) 0061 // Object ID GUID 128 // GUID for header object - GETID3_ASF_Header_Object 0062 // Object Size QWORD 64 // size of header object, including 30 bytes of Header Object header 0063 // Number of Header Objects DWORD 32 // number of objects in header object 0064 // Reserved1 BYTE 8 // hardcoded: 0x01 0065 // Reserved2 BYTE 8 // hardcoded: 0x02 0066 0067 $info['fileformat'] = 'asf'; 0068 0069 $this->fseek($info['avdataoffset']); 0070 $HeaderObjectData = $this->fread(30); 0071 0072 $thisfile_asf_headerobject['objectid'] = substr($HeaderObjectData, 0, 16); 0073 $thisfile_asf_headerobject['objectid_guid'] = $this->BytestringToGUID($thisfile_asf_headerobject['objectid']); 0074 if ($thisfile_asf_headerobject['objectid'] != GETID3_ASF_Header_Object) { 0075 unset($info['fileformat'], $info['asf']); 0076 return $this->error('ASF header GUID {'.$this->BytestringToGUID($thisfile_asf_headerobject['objectid']).'} does not match expected "GETID3_ASF_Header_Object" GUID {'.$this->BytestringToGUID(GETID3_ASF_Header_Object).'}'); 0077 } 0078 $thisfile_asf_headerobject['objectsize'] = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 16, 8)); 0079 $thisfile_asf_headerobject['headerobjects'] = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 24, 4)); 0080 $thisfile_asf_headerobject['reserved1'] = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 28, 1)); 0081 $thisfile_asf_headerobject['reserved2'] = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 29, 1)); 0082 0083 $NextObjectOffset = $this->ftell(); 0084 $ASFHeaderData = $this->fread($thisfile_asf_headerobject['objectsize'] - 30); 0085 $offset = 0; 0086 0087 for ($HeaderObjectsCounter = 0; $HeaderObjectsCounter < $thisfile_asf_headerobject['headerobjects']; $HeaderObjectsCounter++) { 0088 $NextObjectGUID = substr($ASFHeaderData, $offset, 16); 0089 $offset += 16; 0090 $NextObjectGUIDtext = $this->BytestringToGUID($NextObjectGUID); 0091 $NextObjectSize = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); 0092 $offset += 8; 0093 switch ($NextObjectGUID) { 0094 0095 case GETID3_ASF_File_Properties_Object: 0096 // File Properties Object: (mandatory, one only) 0097 // Field Name Field Type Size (bits) 0098 // Object ID GUID 128 // GUID for file properties object - GETID3_ASF_File_Properties_Object 0099 // Object Size QWORD 64 // size of file properties object, including 104 bytes of File Properties Object header 0100 // File ID GUID 128 // unique ID - identical to File ID in Data Object 0101 // File Size QWORD 64 // entire file in bytes. Invalid if Broadcast Flag == 1 0102 // Creation Date QWORD 64 // date & time of file creation. Maybe invalid if Broadcast Flag == 1 0103 // Data Packets Count QWORD 64 // number of data packets in Data Object. Invalid if Broadcast Flag == 1 0104 // Play Duration QWORD 64 // playtime, in 100-nanosecond units. Invalid if Broadcast Flag == 1 0105 // Send Duration QWORD 64 // time needed to send file, in 100-nanosecond units. Players can ignore this value. Invalid if Broadcast Flag == 1 0106 // 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 0107 // Flags DWORD 32 // 0108 // * Broadcast Flag bits 1 (0x01) // file is currently being written, some header values are invalid 0109 // * Seekable Flag bits 1 (0x02) // is file seekable 0110 // * Reserved bits 30 (0xFFFFFFFC) // reserved - set to zero 0111 // Minimum Data Packet Size DWORD 32 // in bytes. should be same as Maximum Data Packet Size. Invalid if Broadcast Flag == 1 0112 // Maximum Data Packet Size DWORD 32 // in bytes. should be same as Minimum Data Packet Size. Invalid if Broadcast Flag == 1 0113 // Maximum Bitrate DWORD 32 // maximum instantaneous bitrate in bits per second for entire file, including all data streams and ASF overhead 0114 0115 // shortcut 0116 $thisfile_asf['file_properties_object'] = array(); 0117 $thisfile_asf_filepropertiesobject = &$thisfile_asf['file_properties_object']; 0118 0119 $thisfile_asf_filepropertiesobject['offset'] = $NextObjectOffset + $offset; 0120 $thisfile_asf_filepropertiesobject['objectid'] = $NextObjectGUID; 0121 $thisfile_asf_filepropertiesobject['objectid_guid'] = $NextObjectGUIDtext; 0122 $thisfile_asf_filepropertiesobject['objectsize'] = $NextObjectSize; 0123 $thisfile_asf_filepropertiesobject['fileid'] = substr($ASFHeaderData, $offset, 16); 0124 $offset += 16; 0125 $thisfile_asf_filepropertiesobject['fileid_guid'] = $this->BytestringToGUID($thisfile_asf_filepropertiesobject['fileid']); 0126 $thisfile_asf_filepropertiesobject['filesize'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); 0127 $offset += 8; 0128 $thisfile_asf_filepropertiesobject['creation_date'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); 0129 $thisfile_asf_filepropertiesobject['creation_date_unix'] = $this->FILETIMEtoUNIXtime($thisfile_asf_filepropertiesobject['creation_date']); 0130 $offset += 8; 0131 $thisfile_asf_filepropertiesobject['data_packets'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); 0132 $offset += 8; 0133 $thisfile_asf_filepropertiesobject['play_duration'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); 0134 $offset += 8; 0135 $thisfile_asf_filepropertiesobject['send_duration'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); 0136 $offset += 8; 0137 $thisfile_asf_filepropertiesobject['preroll'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); 0138 $offset += 8; 0139 $thisfile_asf_filepropertiesobject['flags_raw'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); 0140 $offset += 4; 0141 $thisfile_asf_filepropertiesobject['flags']['broadcast'] = (bool) ($thisfile_asf_filepropertiesobject['flags_raw'] & 0x0001); 0142 $thisfile_asf_filepropertiesobject['flags']['seekable'] = (bool) ($thisfile_asf_filepropertiesobject['flags_raw'] & 0x0002); 0143 0144 $thisfile_asf_filepropertiesobject['min_packet_size'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); 0145 $offset += 4; 0146 $thisfile_asf_filepropertiesobject['max_packet_size'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); 0147 $offset += 4; 0148 $thisfile_asf_filepropertiesobject['max_bitrate'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); 0149 $offset += 4; 0150 0151 if ($thisfile_asf_filepropertiesobject['flags']['broadcast']) { 0152 0153 // broadcast flag is set, some values invalid 0154 unset($thisfile_asf_filepropertiesobject['filesize']); 0155 unset($thisfile_asf_filepropertiesobject['data_packets']); 0156 unset($thisfile_asf_filepropertiesobject['play_duration']); 0157 unset($thisfile_asf_filepropertiesobject['send_duration']); 0158 unset($thisfile_asf_filepropertiesobject['min_packet_size']); 0159 unset($thisfile_asf_filepropertiesobject['max_packet_size']); 0160 0161 } else { 0162 0163 // broadcast flag NOT set, perform calculations 0164 $info['playtime_seconds'] = ($thisfile_asf_filepropertiesobject['play_duration'] / 10000000) - ($thisfile_asf_filepropertiesobject['preroll'] / 1000); 0165 0166 //$info['bitrate'] = $thisfile_asf_filepropertiesobject['max_bitrate']; 0167 $info['bitrate'] = ((isset($thisfile_asf_filepropertiesobject['filesize']) ? $thisfile_asf_filepropertiesobject['filesize'] : $info['filesize']) * 8) / $info['playtime_seconds']; 0168 } 0169 break; 0170 0171 case GETID3_ASF_Stream_Properties_Object: 0172 // Stream Properties Object: (mandatory, one per media stream) 0173 // Field Name Field Type Size (bits) 0174 // Object ID GUID 128 // GUID for stream properties object - GETID3_ASF_Stream_Properties_Object 0175 // Object Size QWORD 64 // size of stream properties object, including 78 bytes of Stream Properties Object header 0176 // Stream Type GUID 128 // GETID3_ASF_Audio_Media, GETID3_ASF_Video_Media or GETID3_ASF_Command_Media 0177 // Error Correction Type GUID 128 // GETID3_ASF_Audio_Spread for audio-only streams, GETID3_ASF_No_Error_Correction for other stream types 0178 // Time Offset QWORD 64 // 100-nanosecond units. typically zero. added to all timestamps of samples in the stream 0179 // Type-Specific Data Length DWORD 32 // number of bytes for Type-Specific Data field 0180 // Error Correction Data Length DWORD 32 // number of bytes for Error Correction Data field 0181 // Flags WORD 16 // 0182 // * Stream Number bits 7 (0x007F) // number of this stream. 1 <= valid <= 127 0183 // * Reserved bits 8 (0x7F80) // reserved - set to zero 0184 // * Encrypted Content Flag bits 1 (0x8000) // stream contents encrypted if set 0185 // Reserved DWORD 32 // reserved - set to zero 0186 // Type-Specific Data BYTESTREAM variable // type-specific format data, depending on value of Stream Type 0187 // Error Correction Data BYTESTREAM variable // error-correction-specific format data, depending on value of Error Correct Type 0188 0189 // There is one GETID3_ASF_Stream_Properties_Object for each stream (audio, video) but the 0190 // stream number isn't known until halfway through decoding the structure, hence it 0191 // it is decoded to a temporary variable and then stuck in the appropriate index later 0192 0193 $StreamPropertiesObjectData['offset'] = $NextObjectOffset + $offset; 0194 $StreamPropertiesObjectData['objectid'] = $NextObjectGUID; 0195 $StreamPropertiesObjectData['objectid_guid'] = $NextObjectGUIDtext; 0196 $StreamPropertiesObjectData['objectsize'] = $NextObjectSize; 0197 $StreamPropertiesObjectData['stream_type'] = substr($ASFHeaderData, $offset, 16); 0198 $offset += 16; 0199 $StreamPropertiesObjectData['stream_type_guid'] = $this->BytestringToGUID($StreamPropertiesObjectData['stream_type']); 0200 $StreamPropertiesObjectData['error_correct_type'] = substr($ASFHeaderData, $offset, 16); 0201 $offset += 16; 0202 $StreamPropertiesObjectData['error_correct_guid'] = $this->BytestringToGUID($StreamPropertiesObjectData['error_correct_type']); 0203 $StreamPropertiesObjectData['time_offset'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); 0204 $offset += 8; 0205 $StreamPropertiesObjectData['type_data_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); 0206 $offset += 4; 0207 $StreamPropertiesObjectData['error_data_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); 0208 $offset += 4; 0209 $StreamPropertiesObjectData['flags_raw'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); 0210 $offset += 2; 0211 $StreamPropertiesObjectStreamNumber = $StreamPropertiesObjectData['flags_raw'] & 0x007F; 0212 $StreamPropertiesObjectData['flags']['encrypted'] = (bool) ($StreamPropertiesObjectData['flags_raw'] & 0x8000); 0213 0214 $offset += 4; // reserved - DWORD 0215 $StreamPropertiesObjectData['type_specific_data'] = substr($ASFHeaderData, $offset, $StreamPropertiesObjectData['type_data_length']); 0216 $offset += $StreamPropertiesObjectData['type_data_length']; 0217 $StreamPropertiesObjectData['error_correct_data'] = substr($ASFHeaderData, $offset, $StreamPropertiesObjectData['error_data_length']); 0218 $offset += $StreamPropertiesObjectData['error_data_length']; 0219 0220 switch ($StreamPropertiesObjectData['stream_type']) { 0221 0222 case GETID3_ASF_Audio_Media: 0223 $thisfile_audio['dataformat'] = (!empty($thisfile_audio['dataformat']) ? $thisfile_audio['dataformat'] : 'asf'); 0224 $thisfile_audio['bitrate_mode'] = (!empty($thisfile_audio['bitrate_mode']) ? $thisfile_audio['bitrate_mode'] : 'cbr'); 0225 0226 $audiodata = getid3_riff::parseWAVEFORMATex(substr($StreamPropertiesObjectData['type_specific_data'], 0, 16)); 0227 unset($audiodata['raw']); 0228 $thisfile_audio = getid3_lib::array_merge_noclobber($audiodata, $thisfile_audio); 0229 break; 0230 0231 case GETID3_ASF_Video_Media: 0232 $thisfile_video['dataformat'] = (!empty($thisfile_video['dataformat']) ? $thisfile_video['dataformat'] : 'asf'); 0233 $thisfile_video['bitrate_mode'] = (!empty($thisfile_video['bitrate_mode']) ? $thisfile_video['bitrate_mode'] : 'cbr'); 0234 break; 0235 0236 case GETID3_ASF_Command_Media: 0237 default: 0238 // do nothing 0239 break; 0240 0241 } 0242 0243 $thisfile_asf['stream_properties_object'][$StreamPropertiesObjectStreamNumber] = $StreamPropertiesObjectData; 0244 unset($StreamPropertiesObjectData); // clear for next stream, if any 0245 break; 0246 0247 case GETID3_ASF_Header_Extension_Object: 0248 // Header Extension Object: (mandatory, one only) 0249 // Field Name Field Type Size (bits) 0250 // Object ID GUID 128 // GUID for Header Extension object - GETID3_ASF_Header_Extension_Object 0251 // Object Size QWORD 64 // size of Header Extension object, including 46 bytes of Header Extension Object header 0252 // Reserved Field 1 GUID 128 // hardcoded: GETID3_ASF_Reserved_1 0253 // Reserved Field 2 WORD 16 // hardcoded: 0x00000006 0254 // Header Extension Data Size DWORD 32 // in bytes. valid: 0, or > 24. equals object size minus 46 0255 // Header Extension Data BYTESTREAM variable // array of zero or more extended header objects 0256 0257 // shortcut 0258 $thisfile_asf['header_extension_object'] = array(); 0259 $thisfile_asf_headerextensionobject = &$thisfile_asf['header_extension_object']; 0260 0261 $thisfile_asf_headerextensionobject['offset'] = $NextObjectOffset + $offset; 0262 $thisfile_asf_headerextensionobject['objectid'] = $NextObjectGUID; 0263 $thisfile_asf_headerextensionobject['objectid_guid'] = $NextObjectGUIDtext; 0264 $thisfile_asf_headerextensionobject['objectsize'] = $NextObjectSize; 0265 $thisfile_asf_headerextensionobject['reserved_1'] = substr($ASFHeaderData, $offset, 16); 0266 $offset += 16; 0267 $thisfile_asf_headerextensionobject['reserved_1_guid'] = $this->BytestringToGUID($thisfile_asf_headerextensionobject['reserved_1']); 0268 if ($thisfile_asf_headerextensionobject['reserved_1'] != GETID3_ASF_Reserved_1) { 0269 $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).')'; 0270 //return false; 0271 break; 0272 } 0273 $thisfile_asf_headerextensionobject['reserved_2'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); 0274 $offset += 2; 0275 if ($thisfile_asf_headerextensionobject['reserved_2'] != 6) { 0276 $info['warning'][] = 'header_extension_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_headerextensionobject['reserved_2']).') does not match expected value of "6"'; 0277 //return false; 0278 break; 0279 } 0280 $thisfile_asf_headerextensionobject['extension_data_size'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); 0281 $offset += 4; 0282 $thisfile_asf_headerextensionobject['extension_data'] = substr($ASFHeaderData, $offset, $thisfile_asf_headerextensionobject['extension_data_size']); 0283 $unhandled_sections = 0; 0284 $thisfile_asf_headerextensionobject['extension_data_parsed'] = $this->HeaderExtensionObjectDataParse($thisfile_asf_headerextensionobject['extension_data'], $unhandled_sections); 0285 if ($unhandled_sections === 0) { 0286 unset($thisfile_asf_headerextensionobject['extension_data']); 0287 } 0288 $offset += $thisfile_asf_headerextensionobject['extension_data_size']; 0289 break; 0290 0291 case GETID3_ASF_Codec_List_Object: 0292 // Codec List Object: (optional, one only) 0293 // Field Name Field Type Size (bits) 0294 // Object ID GUID 128 // GUID for Codec List object - GETID3_ASF_Codec_List_Object 0295 // Object Size QWORD 64 // size of Codec List object, including 44 bytes of Codec List Object header 0296 // Reserved GUID 128 // hardcoded: 86D15241-311D-11D0-A3A4-00A0C90348F6 0297 // Codec Entries Count DWORD 32 // number of entries in Codec Entries array 0298 // Codec Entries array of: variable // 0299 // * Type WORD 16 // 0x0001 = Video Codec, 0x0002 = Audio Codec, 0xFFFF = Unknown Codec 0300 // * Codec Name Length WORD 16 // number of Unicode characters stored in the Codec Name field 0301 // * Codec Name WCHAR variable // array of Unicode characters - name of codec used to create the content 0302 // * Codec Description Length WORD 16 // number of Unicode characters stored in the Codec Description field 0303 // * Codec Description WCHAR variable // array of Unicode characters - description of format used to create the content 0304 // * Codec Information Length WORD 16 // number of Unicode characters stored in the Codec Information field 0305 // * Codec Information BYTESTREAM variable // opaque array of information bytes about the codec used to create the content 0306 0307 // shortcut 0308 $thisfile_asf['codec_list_object'] = array(); 0309 $thisfile_asf_codeclistobject = &$thisfile_asf['codec_list_object']; 0310 0311 $thisfile_asf_codeclistobject['offset'] = $NextObjectOffset + $offset; 0312 $thisfile_asf_codeclistobject['objectid'] = $NextObjectGUID; 0313 $thisfile_asf_codeclistobject['objectid_guid'] = $NextObjectGUIDtext; 0314 $thisfile_asf_codeclistobject['objectsize'] = $NextObjectSize; 0315 $thisfile_asf_codeclistobject['reserved'] = substr($ASFHeaderData, $offset, 16); 0316 $offset += 16; 0317 $thisfile_asf_codeclistobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_codeclistobject['reserved']); 0318 if ($thisfile_asf_codeclistobject['reserved'] != $this->GUIDtoBytestring('86D15241-311D-11D0-A3A4-00A0C90348F6')) { 0319 $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}'; 0320 //return false; 0321 break; 0322 } 0323 $thisfile_asf_codeclistobject['codec_entries_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); 0324 $offset += 4; 0325 for ($CodecEntryCounter = 0; $CodecEntryCounter < $thisfile_asf_codeclistobject['codec_entries_count']; $CodecEntryCounter++) { 0326 // shortcut 0327 $thisfile_asf_codeclistobject['codec_entries'][$CodecEntryCounter] = array(); 0328 $thisfile_asf_codeclistobject_codecentries_current = &$thisfile_asf_codeclistobject['codec_entries'][$CodecEntryCounter]; 0329 0330 $thisfile_asf_codeclistobject_codecentries_current['type_raw'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); 0331 $offset += 2; 0332 $thisfile_asf_codeclistobject_codecentries_current['type'] = self::codecListObjectTypeLookup($thisfile_asf_codeclistobject_codecentries_current['type_raw']); 0333 0334 $CodecNameLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character 0335 $offset += 2; 0336 $thisfile_asf_codeclistobject_codecentries_current['name'] = substr($ASFHeaderData, $offset, $CodecNameLength); 0337 $offset += $CodecNameLength; 0338 0339 $CodecDescriptionLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character 0340 $offset += 2; 0341 $thisfile_asf_codeclistobject_codecentries_current['description'] = substr($ASFHeaderData, $offset, $CodecDescriptionLength); 0342 $offset += $CodecDescriptionLength; 0343 0344 $CodecInformationLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); 0345 $offset += 2; 0346 $thisfile_asf_codeclistobject_codecentries_current['information'] = substr($ASFHeaderData, $offset, $CodecInformationLength); 0347 $offset += $CodecInformationLength; 0348 0349 if ($thisfile_asf_codeclistobject_codecentries_current['type_raw'] == 2) { // audio codec 0350 0351 if (strpos($thisfile_asf_codeclistobject_codecentries_current['description'], ',') === false) { 0352 $info['warning'][] = '[asf][codec_list_object][codec_entries]['.$CodecEntryCounter.'][description] expected to contain comma-seperated list of parameters: "'.$thisfile_asf_codeclistobject_codecentries_current['description'].'"'; 0353 } else { 0354 0355 list($AudioCodecBitrate, $AudioCodecFrequency, $AudioCodecChannels) = explode(',', $this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['description'])); 0356 $thisfile_audio['codec'] = $this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['name']); 0357 0358 if (!isset($thisfile_audio['bitrate']) && strstr($AudioCodecBitrate, 'kbps')) { 0359 $thisfile_audio['bitrate'] = (int) (trim(str_replace('kbps', '', $AudioCodecBitrate)) * 1000); 0360 } 0361 //if (!isset($thisfile_video['bitrate']) && isset($thisfile_audio['bitrate']) && isset($thisfile_asf['file_properties_object']['max_bitrate']) && ($thisfile_asf_codeclistobject['codec_entries_count'] > 1)) { 0362 if (empty($thisfile_video['bitrate']) && !empty($thisfile_audio['bitrate']) && !empty($info['bitrate'])) { 0363 //$thisfile_video['bitrate'] = $thisfile_asf['file_properties_object']['max_bitrate'] - $thisfile_audio['bitrate']; 0364 $thisfile_video['bitrate'] = $info['bitrate'] - $thisfile_audio['bitrate']; 0365 } 0366 0367 $AudioCodecFrequency = (int) trim(str_replace('kHz', '', $AudioCodecFrequency)); 0368 switch ($AudioCodecFrequency) { 0369 case 8: 0370 case 8000: 0371 $thisfile_audio['sample_rate'] = 8000; 0372 break; 0373 0374 case 11: 0375 case 11025: 0376 $thisfile_audio['sample_rate'] = 11025; 0377 break; 0378 0379 case 12: 0380 case 12000: 0381 $thisfile_audio['sample_rate'] = 12000; 0382 break; 0383 0384 case 16: 0385 case 16000: 0386 $thisfile_audio['sample_rate'] = 16000; 0387 break; 0388 0389 case 22: 0390 case 22050: 0391 $thisfile_audio['sample_rate'] = 22050; 0392 break; 0393 0394 case 24: 0395 case 24000: 0396 $thisfile_audio['sample_rate'] = 24000; 0397 break; 0398 0399 case 32: 0400 case 32000: 0401 $thisfile_audio['sample_rate'] = 32000; 0402 break; 0403 0404 case 44: 0405 case 441000: 0406 $thisfile_audio['sample_rate'] = 44100; 0407 break; 0408 0409 case 48: 0410 case 48000: 0411 $thisfile_audio['sample_rate'] = 48000; 0412 break; 0413 0414 default: 0415 $info['warning'][] = 'unknown frequency: "'.$AudioCodecFrequency.'" ('.$this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['description']).')'; 0416 break; 0417 } 0418 0419 if (!isset($thisfile_audio['channels'])) { 0420 if (strstr($AudioCodecChannels, 'stereo')) { 0421 $thisfile_audio['channels'] = 2; 0422 } elseif (strstr($AudioCodecChannels, 'mono')) { 0423 $thisfile_audio['channels'] = 1; 0424 } 0425 } 0426 0427 } 0428 } 0429 } 0430 break; 0431 0432 case GETID3_ASF_Script_Command_Object: 0433 // Script Command Object: (optional, one only) 0434 // Field Name Field Type Size (bits) 0435 // Object ID GUID 128 // GUID for Script Command object - GETID3_ASF_Script_Command_Object 0436 // Object Size QWORD 64 // size of Script Command object, including 44 bytes of Script Command Object header 0437 // Reserved GUID 128 // hardcoded: 4B1ACBE3-100B-11D0-A39B-00A0C90348F6 0438 // Commands Count WORD 16 // number of Commands structures in the Script Commands Objects 0439 // Command Types Count WORD 16 // number of Command Types structures in the Script Commands Objects 0440 // Command Types array of: variable // 0441 // * Command Type Name Length WORD 16 // number of Unicode characters for Command Type Name 0442 // * Command Type Name WCHAR variable // array of Unicode characters - name of a type of command 0443 // Commands array of: variable // 0444 // * Presentation Time DWORD 32 // presentation time of that command, in milliseconds 0445 // * Type Index WORD 16 // type of this command, as a zero-based index into the array of Command Types of this object 0446 // * Command Name Length WORD 16 // number of Unicode characters for Command Name 0447 // * Command Name WCHAR variable // array of Unicode characters - name of this command 0448 0449 // shortcut 0450 $thisfile_asf['script_command_object'] = array(); 0451 $thisfile_asf_scriptcommandobject = &$thisfile_asf['script_command_object']; 0452 0453 $thisfile_asf_scriptcommandobject['offset'] = $NextObjectOffset + $offset; 0454 $thisfile_asf_scriptcommandobject['objectid'] = $NextObjectGUID; 0455 $thisfile_asf_scriptcommandobject['objectid_guid'] = $NextObjectGUIDtext; 0456 $thisfile_asf_scriptcommandobject['objectsize'] = $NextObjectSize; 0457 $thisfile_asf_scriptcommandobject['reserved'] = substr($ASFHeaderData, $offset, 16); 0458 $offset += 16; 0459 $thisfile_asf_scriptcommandobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_scriptcommandobject['reserved']); 0460 if ($thisfile_asf_scriptcommandobject['reserved'] != $this->GUIDtoBytestring('4B1ACBE3-100B-11D0-A39B-00A0C90348F6')) { 0461 $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}'; 0462 //return false; 0463 break; 0464 } 0465 $thisfile_asf_scriptcommandobject['commands_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); 0466 $offset += 2; 0467 $thisfile_asf_scriptcommandobject['command_types_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); 0468 $offset += 2; 0469 for ($CommandTypesCounter = 0; $CommandTypesCounter < $thisfile_asf_scriptcommandobject['command_types_count']; $CommandTypesCounter++) { 0470 $CommandTypeNameLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character 0471 $offset += 2; 0472 $thisfile_asf_scriptcommandobject['command_types'][$CommandTypesCounter]['name'] = substr($ASFHeaderData, $offset, $CommandTypeNameLength); 0473 $offset += $CommandTypeNameLength; 0474 } 0475 for ($CommandsCounter = 0; $CommandsCounter < $thisfile_asf_scriptcommandobject['commands_count']; $CommandsCounter++) { 0476 $thisfile_asf_scriptcommandobject['commands'][$CommandsCounter]['presentation_time'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); 0477 $offset += 4; 0478 $thisfile_asf_scriptcommandobject['commands'][$CommandsCounter]['type_index'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); 0479 $offset += 2; 0480 0481 $CommandTypeNameLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character 0482 $offset += 2; 0483 $thisfile_asf_scriptcommandobject['commands'][$CommandsCounter]['name'] = substr($ASFHeaderData, $offset, $CommandTypeNameLength); 0484 $offset += $CommandTypeNameLength; 0485 } 0486 break; 0487 0488 case GETID3_ASF_Marker_Object: 0489 // Marker Object: (optional, one only) 0490 // Field Name Field Type Size (bits) 0491 // Object ID GUID 128 // GUID for Marker object - GETID3_ASF_Marker_Object 0492 // Object Size QWORD 64 // size of Marker object, including 48 bytes of Marker Object header 0493 // Reserved GUID 128 // hardcoded: 4CFEDB20-75F6-11CF-9C0F-00A0C90349CB 0494 // Markers Count DWORD 32 // number of Marker structures in Marker Object 0495 // Reserved WORD 16 // hardcoded: 0x0000 0496 // Name Length WORD 16 // number of bytes in the Name field 0497 // Name WCHAR variable // name of the Marker Object 0498 // Markers array of: variable // 0499 // * Offset QWORD 64 // byte offset into Data Object 0500 // * Presentation Time QWORD 64 // in 100-nanosecond units 0501 // * Entry Length WORD 16 // length in bytes of (Send Time + Flags + Marker Description Length + Marker Description + Padding) 0502 // * Send Time DWORD 32 // in milliseconds 0503 // * Flags DWORD 32 // hardcoded: 0x00000000 0504 // * Marker Description Length DWORD 32 // number of bytes in Marker Description field 0505 // * Marker Description WCHAR variable // array of Unicode characters - description of marker entry 0506 // * Padding BYTESTREAM variable // optional padding bytes 0507 0508 // shortcut 0509 $thisfile_asf['marker_object'] = array(); 0510 $thisfile_asf_markerobject = &$thisfile_asf['marker_object']; 0511 0512 $thisfile_asf_markerobject['offset'] = $NextObjectOffset + $offset; 0513 $thisfile_asf_markerobject['objectid'] = $NextObjectGUID; 0514 $thisfile_asf_markerobject['objectid_guid'] = $NextObjectGUIDtext; 0515 $thisfile_asf_markerobject['objectsize'] = $NextObjectSize; 0516 $thisfile_asf_markerobject['reserved'] = substr($ASFHeaderData, $offset, 16); 0517 $offset += 16; 0518 $thisfile_asf_markerobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_markerobject['reserved']); 0519 if ($thisfile_asf_markerobject['reserved'] != $this->GUIDtoBytestring('4CFEDB20-75F6-11CF-9C0F-00A0C90349CB')) { 0520 $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}'; 0521 break; 0522 } 0523 $thisfile_asf_markerobject['markers_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); 0524 $offset += 4; 0525 $thisfile_asf_markerobject['reserved_2'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); 0526 $offset += 2; 0527 if ($thisfile_asf_markerobject['reserved_2'] != 0) { 0528 $info['warning'][] = 'marker_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_markerobject['reserved_2']).') does not match expected value of "0"'; 0529 break; 0530 } 0531 $thisfile_asf_markerobject['name_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); 0532 $offset += 2; 0533 $thisfile_asf_markerobject['name'] = substr($ASFHeaderData, $offset, $thisfile_asf_markerobject['name_length']); 0534 $offset += $thisfile_asf_markerobject['name_length']; 0535 for ($MarkersCounter = 0; $MarkersCounter < $thisfile_asf_markerobject['markers_count']; $MarkersCounter++) { 0536 $thisfile_asf_markerobject['markers'][$MarkersCounter]['offset'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); 0537 $offset += 8; 0538 $thisfile_asf_markerobject['markers'][$MarkersCounter]['presentation_time'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); 0539 $offset += 8; 0540 $thisfile_asf_markerobject['markers'][$MarkersCounter]['entry_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); 0541 $offset += 2; 0542 $thisfile_asf_markerobject['markers'][$MarkersCounter]['send_time'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); 0543 $offset += 4; 0544 $thisfile_asf_markerobject['markers'][$MarkersCounter]['flags'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); 0545 $offset += 4; 0546 $thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); 0547 $offset += 4; 0548 $thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description'] = substr($ASFHeaderData, $offset, $thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description_length']); 0549 $offset += $thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description_length']; 0550 $PaddingLength = $thisfile_asf_markerobject['markers'][$MarkersCounter]['entry_length'] - 4 - 4 - 4 - $thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description_length']; 0551 if ($PaddingLength > 0) { 0552 $thisfile_asf_markerobject['markers'][$MarkersCounter]['padding'] = substr($ASFHeaderData, $offset, $PaddingLength); 0553 $offset += $PaddingLength; 0554 } 0555 } 0556 break; 0557 0558 case GETID3_ASF_Bitrate_Mutual_Exclusion_Object: 0559 // Bitrate Mutual Exclusion Object: (optional) 0560 // Field Name Field Type Size (bits) 0561 // Object ID GUID 128 // GUID for Bitrate Mutual Exclusion object - GETID3_ASF_Bitrate_Mutual_Exclusion_Object 0562 // Object Size QWORD 64 // size of Bitrate Mutual Exclusion object, including 42 bytes of Bitrate Mutual Exclusion Object header 0563 // Exlusion Type GUID 128 // nature of mutual exclusion relationship. one of: (GETID3_ASF_Mutex_Bitrate, GETID3_ASF_Mutex_Unknown) 0564 // Stream Numbers Count WORD 16 // number of video streams 0565 // Stream Numbers WORD variable // array of mutually exclusive video stream numbers. 1 <= valid <= 127 0566 0567 // shortcut 0568 $thisfile_asf['bitrate_mutual_exclusion_object'] = array(); 0569 $thisfile_asf_bitratemutualexclusionobject = &$thisfile_asf['bitrate_mutual_exclusion_object']; 0570 0571 $thisfile_asf_bitratemutualexclusionobject['offset'] = $NextObjectOffset + $offset; 0572 $thisfile_asf_bitratemutualexclusionobject['objectid'] = $NextObjectGUID; 0573 $thisfile_asf_bitratemutualexclusionobject['objectid_guid'] = $NextObjectGUIDtext; 0574 $thisfile_asf_bitratemutualexclusionobject['objectsize'] = $NextObjectSize; 0575 $thisfile_asf_bitratemutualexclusionobject['reserved'] = substr($ASFHeaderData, $offset, 16); 0576 $thisfile_asf_bitratemutualexclusionobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_bitratemutualexclusionobject['reserved']); 0577 $offset += 16; 0578 if (($thisfile_asf_bitratemutualexclusionobject['reserved'] != GETID3_ASF_Mutex_Bitrate) && ($thisfile_asf_bitratemutualexclusionobject['reserved'] != GETID3_ASF_Mutex_Unknown)) { 0579 $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).'}'; 0580 //return false; 0581 break; 0582 } 0583 $thisfile_asf_bitratemutualexclusionobject['stream_numbers_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); 0584 $offset += 2; 0585 for ($StreamNumberCounter = 0; $StreamNumberCounter < $thisfile_asf_bitratemutualexclusionobject['stream_numbers_count']; $StreamNumberCounter++) { 0586 $thisfile_asf_bitratemutualexclusionobject['stream_numbers'][$StreamNumberCounter] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); 0587 $offset += 2; 0588 } 0589 break; 0590 0591 case GETID3_ASF_Error_Correction_Object: 0592 // Error Correction Object: (optional, one only) 0593 // Field Name Field Type Size (bits) 0594 // Object ID GUID 128 // GUID for Error Correction object - GETID3_ASF_Error_Correction_Object 0595 // Object Size QWORD 64 // size of Error Correction object, including 44 bytes of Error Correction Object header 0596 // Error Correction Type GUID 128 // type of error correction. one of: (GETID3_ASF_No_Error_Correction, GETID3_ASF_Audio_Spread) 0597 // Error Correction Data Length DWORD 32 // number of bytes in Error Correction Data field 0598 // Error Correction Data BYTESTREAM variable // structure depends on value of Error Correction Type field 0599 0600 // shortcut 0601 $thisfile_asf['error_correction_object'] = array(); 0602 $thisfile_asf_errorcorrectionobject = &$thisfile_asf['error_correction_object']; 0603 0604 $thisfile_asf_errorcorrectionobject['offset'] = $NextObjectOffset + $offset; 0605 $thisfile_asf_errorcorrectionobject['objectid'] = $NextObjectGUID; 0606 $thisfile_asf_errorcorrectionobject['objectid_guid'] = $NextObjectGUIDtext; 0607 $thisfile_asf_errorcorrectionobject['objectsize'] = $NextObjectSize; 0608 $thisfile_asf_errorcorrectionobject['error_correction_type'] = substr($ASFHeaderData, $offset, 16); 0609 $offset += 16; 0610 $thisfile_asf_errorcorrectionobject['error_correction_guid'] = $this->BytestringToGUID($thisfile_asf_errorcorrectionobject['error_correction_type']); 0611 $thisfile_asf_errorcorrectionobject['error_correction_data_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); 0612 $offset += 4; 0613 switch ($thisfile_asf_errorcorrectionobject['error_correction_type']) { 0614 case GETID3_ASF_No_Error_Correction: 0615 // should be no data, but just in case there is, skip to the end of the field 0616 $offset += $thisfile_asf_errorcorrectionobject['error_correction_data_length']; 0617 break; 0618 0619 case GETID3_ASF_Audio_Spread: 0620 // Field Name Field Type Size (bits) 0621 // Span BYTE 8 // number of packets over which audio will be spread. 0622 // Virtual Packet Length WORD 16 // size of largest audio payload found in audio stream 0623 // Virtual Chunk Length WORD 16 // size of largest audio payload found in audio stream 0624 // Silence Data Length WORD 16 // number of bytes in Silence Data field 0625 // Silence Data BYTESTREAM variable // hardcoded: 0x00 * (Silence Data Length) bytes 0626 0627 $thisfile_asf_errorcorrectionobject['span'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 1)); 0628 $offset += 1; 0629 $thisfile_asf_errorcorrectionobject['virtual_packet_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); 0630 $offset += 2; 0631 $thisfile_asf_errorcorrectionobject['virtual_chunk_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); 0632 $offset += 2; 0633 $thisfile_asf_errorcorrectionobject['silence_data_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); 0634 $offset += 2; 0635 $thisfile_asf_errorcorrectionobject['silence_data'] = substr($ASFHeaderData, $offset, $thisfile_asf_errorcorrectionobject['silence_data_length']); 0636 $offset += $thisfile_asf_errorcorrectionobject['silence_data_length']; 0637 break; 0638 0639 default: 0640 $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).'}'; 0641 //return false; 0642 break; 0643 } 0644 0645 break; 0646 0647 case GETID3_ASF_Content_Description_Object: 0648 // Content Description Object: (optional, one only) 0649 // Field Name Field Type Size (bits) 0650 // Object ID GUID 128 // GUID for Content Description object - GETID3_ASF_Content_Description_Object 0651 // Object Size QWORD 64 // size of Content Description object, including 34 bytes of Content Description Object header 0652 // Title Length WORD 16 // number of bytes in Title field 0653 // Author Length WORD 16 // number of bytes in Author field 0654 // Copyright Length WORD 16 // number of bytes in Copyright field 0655 // Description Length WORD 16 // number of bytes in Description field 0656 // Rating Length WORD 16 // number of bytes in Rating field 0657 // Title WCHAR 16 // array of Unicode characters - Title 0658 // Author WCHAR 16 // array of Unicode characters - Author 0659 // Copyright WCHAR 16 // array of Unicode characters - Copyright 0660 // Description WCHAR 16 // array of Unicode characters - Description 0661 // Rating WCHAR 16 // array of Unicode characters - Rating 0662 0663 // shortcut 0664 $thisfile_asf['content_description_object'] = array(); 0665 $thisfile_asf_contentdescriptionobject = &$thisfile_asf['content_description_object']; 0666 0667 $thisfile_asf_contentdescriptionobject['offset'] = $NextObjectOffset + $offset; 0668 $thisfile_asf_contentdescriptionobject['objectid'] = $NextObjectGUID; 0669 $thisfile_asf_contentdescriptionobject['objectid_guid'] = $NextObjectGUIDtext; 0670 $thisfile_asf_contentdescriptionobject['objectsize'] = $NextObjectSize; 0671 $thisfile_asf_contentdescriptionobject['title_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); 0672 $offset += 2; 0673 $thisfile_asf_contentdescriptionobject['author_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); 0674 $offset += 2; 0675 $thisfile_asf_contentdescriptionobject['copyright_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); 0676 $offset += 2; 0677 $thisfile_asf_contentdescriptionobject['description_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); 0678 $offset += 2; 0679 $thisfile_asf_contentdescriptionobject['rating_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); 0680 $offset += 2; 0681 $thisfile_asf_contentdescriptionobject['title'] = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['title_length']); 0682 $offset += $thisfile_asf_contentdescriptionobject['title_length']; 0683 $thisfile_asf_contentdescriptionobject['author'] = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['author_length']); 0684 $offset += $thisfile_asf_contentdescriptionobject['author_length']; 0685 $thisfile_asf_contentdescriptionobject['copyright'] = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['copyright_length']); 0686 $offset += $thisfile_asf_contentdescriptionobject['copyright_length']; 0687 $thisfile_asf_contentdescriptionobject['description'] = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['description_length']); 0688 $offset += $thisfile_asf_contentdescriptionobject['description_length']; 0689 $thisfile_asf_contentdescriptionobject['rating'] = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['rating_length']); 0690 $offset += $thisfile_asf_contentdescriptionobject['rating_length']; 0691 0692 $ASFcommentKeysToCopy = array('title'=>'title', 'author'=>'artist', 'copyright'=>'copyright', 'description'=>'comment', 'rating'=>'rating'); 0693 foreach ($ASFcommentKeysToCopy as $keytocopyfrom => $keytocopyto) { 0694 if (!empty($thisfile_asf_contentdescriptionobject[$keytocopyfrom])) { 0695 $thisfile_asf_comments[$keytocopyto][] = $this->TrimTerm($thisfile_asf_contentdescriptionobject[$keytocopyfrom]); 0696 } 0697 } 0698 break; 0699 0700 case GETID3_ASF_Extended_Content_Description_Object: 0701 // Extended Content Description Object: (optional, one only) 0702 // Field Name Field Type Size (bits) 0703 // Object ID GUID 128 // GUID for Extended Content Description object - GETID3_ASF_Extended_Content_Description_Object 0704 // Object Size QWORD 64 // size of ExtendedContent Description object, including 26 bytes of Extended Content Description Object header 0705 // Content Descriptors Count WORD 16 // number of entries in Content Descriptors list 0706 // Content Descriptors array of: variable // 0707 // * Descriptor Name Length WORD 16 // size in bytes of Descriptor Name field 0708 // * Descriptor Name WCHAR variable // array of Unicode characters - Descriptor Name 0709 // * Descriptor Value Data Type WORD 16 // Lookup array: 0710 // 0x0000 = Unicode String (variable length) 0711 // 0x0001 = BYTE array (variable length) 0712 // 0x0002 = BOOL (DWORD, 32 bits) 0713 // 0x0003 = DWORD (DWORD, 32 bits) 0714 // 0x0004 = QWORD (QWORD, 64 bits) 0715 // 0x0005 = WORD (WORD, 16 bits) 0716 // * Descriptor Value Length WORD 16 // number of bytes stored in Descriptor Value field 0717 // * Descriptor Value variable variable // value for Content Descriptor 0718 0719 // shortcut 0720 $thisfile_asf['extended_content_description_object'] = array(); 0721 $thisfile_asf_extendedcontentdescriptionobject = &$thisfile_asf['extended_content_description_object']; 0722 0723 $thisfile_asf_extendedcontentdescriptionobject['offset'] = $NextObjectOffset + $offset; 0724 $thisfile_asf_extendedcontentdescriptionobject['objectid'] = $NextObjectGUID; 0725 $thisfile_asf_extendedcontentdescriptionobject['objectid_guid'] = $NextObjectGUIDtext; 0726 $thisfile_asf_extendedcontentdescriptionobject['objectsize'] = $NextObjectSize; 0727 $thisfile_asf_extendedcontentdescriptionobject['content_descriptors_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); 0728 $offset += 2; 0729 for ($ExtendedContentDescriptorsCounter = 0; $ExtendedContentDescriptorsCounter < $thisfile_asf_extendedcontentdescriptionobject['content_descriptors_count']; $ExtendedContentDescriptorsCounter++) { 0730 // shortcut 0731 $thisfile_asf_extendedcontentdescriptionobject['content_descriptors'][$ExtendedContentDescriptorsCounter] = array(); 0732 $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current = &$thisfile_asf_extendedcontentdescriptionobject['content_descriptors'][$ExtendedContentDescriptorsCounter]; 0733 0734 $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['base_offset'] = $offset + 30; 0735 $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); 0736 $offset += 2; 0737 $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name'] = substr($ASFHeaderData, $offset, $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name_length']); 0738 $offset += $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name_length']; 0739 $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); 0740 $offset += 2; 0741 $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); 0742 $offset += 2; 0743 $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'] = substr($ASFHeaderData, $offset, $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_length']); 0744 $offset += $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_length']; 0745 switch ($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type']) { 0746 case 0x0000: // Unicode string 0747 break; 0748 0749 case 0x0001: // BYTE array 0750 // do nothing 0751 break; 0752 0753 case 0x0002: // BOOL 0754 $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'] = (bool) getid3_lib::LittleEndian2Int($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']); 0755 break; 0756 0757 case 0x0003: // DWORD 0758 case 0x0004: // QWORD 0759 case 0x0005: // WORD 0760 $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'] = getid3_lib::LittleEndian2Int($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']); 0761 break; 0762 0763 default: 0764 $info['warning'][] = 'extended_content_description.content_descriptors.'.$ExtendedContentDescriptorsCounter.'.value_type is invalid ('.$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type'].')'; 0765 //return false; 0766 break; 0767 } 0768 switch ($this->TrimConvert(strtolower($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name']))) { 0769 0770 case 'wm/albumartist': 0771 case 'artist': 0772 // Note: not 'artist', that comes from 'author' tag 0773 $thisfile_asf_comments['albumartist'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); 0774 break; 0775 0776 case 'wm/albumtitle': 0777 case 'album': 0778 $thisfile_asf_comments['album'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); 0779 break; 0780 0781 case 'wm/genre': 0782 case 'genre': 0783 $thisfile_asf_comments['genre'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); 0784 break; 0785 0786 case 'wm/partofset': 0787 $thisfile_asf_comments['partofset'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); 0788 break; 0789 0790 case 'wm/tracknumber': 0791 case 'tracknumber': 0792 // be careful casting to int: casting unicode strings to int gives unexpected results (stops parsing at first non-numeric character) 0793 $thisfile_asf_comments['track'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); 0794 foreach ($thisfile_asf_comments['track'] as $key => $value) { 0795 if (preg_match('/^[0-9\x00]+$/', $value)) { 0796 $thisfile_asf_comments['track'][$key] = intval(str_replace("\x00", '', $value)); 0797 } 0798 } 0799 break; 0800 0801 case 'wm/track': 0802 if (empty($thisfile_asf_comments['track'])) { 0803 $thisfile_asf_comments['track'] = array(1 + $this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); 0804 } 0805 break; 0806 0807 case 'wm/year': 0808 case 'year': 0809 case 'date': 0810 $thisfile_asf_comments['year'] = array( $this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); 0811 break; 0812 0813 case 'wm/lyrics': 0814 case 'lyrics': 0815 $thisfile_asf_comments['lyrics'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); 0816 break; 0817 0818 case 'isvbr': 0819 if ($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']) { 0820 $thisfile_audio['bitrate_mode'] = 'vbr'; 0821 $thisfile_video['bitrate_mode'] = 'vbr'; 0822 } 0823 break; 0824 0825 case 'id3': 0826 $this->getid3->include_module('tag.id3v2'); 0827 0828 $getid3_id3v2 = new getid3_id3v2($this->getid3); 0829 $getid3_id3v2->AnalyzeString($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']); 0830 unset($getid3_id3v2); 0831 0832 if ($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_length'] > 1024) { 0833 $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'] = '<value too large to display>'; 0834 } 0835 break; 0836 0837 case 'wm/encodingtime': 0838 $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['encoding_time_unix'] = $this->FILETIMEtoUNIXtime($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']); 0839 $thisfile_asf_comments['encoding_time_unix'] = array($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['encoding_time_unix']); 0840 break; 0841 0842 case 'wm/picture': 0843 $WMpicture = $this->ASF_WMpicture($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']); 0844 foreach ($WMpicture as $key => $value) { 0845 $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current[$key] = $value; 0846 } 0847 unset($WMpicture); 0848 /* 0849 $wm_picture_offset = 0; 0850 $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_type_id'] = getid3_lib::LittleEndian2Int(substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset, 1)); 0851 $wm_picture_offset += 1; 0852 $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_type'] = self::WMpictureTypeLookup($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_type_id']); 0853 $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_size'] = getid3_lib::LittleEndian2Int(substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset, 4)); 0854 $wm_picture_offset += 4; 0855 0856 $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime'] = ''; 0857 do { 0858 $next_byte_pair = substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset, 2); 0859 $wm_picture_offset += 2; 0860 $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime'] .= $next_byte_pair; 0861 } while ($next_byte_pair !== "\x00\x00"); 0862 0863 $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_description'] = ''; 0864 do { 0865 $next_byte_pair = substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset, 2); 0866 $wm_picture_offset += 2; 0867 $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_description'] .= $next_byte_pair; 0868 } while ($next_byte_pair !== "\x00\x00"); 0869 0870 $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['dataoffset'] = $wm_picture_offset; 0871 $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['data'] = substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset); 0872 unset($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']); 0873 0874 $imageinfo = array(); 0875 $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime'] = ''; 0876 $imagechunkcheck = getid3_lib::GetDataImageSize($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['data'], $imageinfo); 0877 unset($imageinfo); 0878 if (!empty($imagechunkcheck)) { 0879 $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]); 0880 } 0881 if (!isset($thisfile_asf_comments['picture'])) { 0882 $thisfile_asf_comments['picture'] = array(); 0883 } 0884 $thisfile_asf_comments['picture'][] = array('data'=>$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['data'], 'image_mime'=>$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime']); 0885 */ 0886 break; 0887 0888 default: 0889 switch ($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type']) { 0890 case 0: // Unicode string 0891 if (substr($this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name']), 0, 3) == 'WM/') { 0892 $thisfile_asf_comments[str_replace('wm/', '', strtolower($this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name'])))] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); 0893 } 0894 break; 0895 0896 case 1: 0897 break; 0898 } 0899 break; 0900 } 0901 0902 } 0903 break; 0904 0905 case GETID3_ASF_Stream_Bitrate_Properties_Object: 0906 // Stream Bitrate Properties Object: (optional, one only) 0907 // Field Name Field Type Size (bits) 0908 // Object ID GUID 128 // GUID for Stream Bitrate Properties object - GETID3_ASF_Stream_Bitrate_Properties_Object 0909 // Object Size QWORD 64 // size of Extended Content Description object, including 26 bytes of Stream Bitrate Properties Object header 0910 // Bitrate Records Count WORD 16 // number of records in Bitrate Records 0911 // Bitrate Records array of: variable // 0912 // * Flags WORD 16 // 0913 // * * Stream Number bits 7 (0x007F) // number of this stream 0914 // * * Reserved bits 9 (0xFF80) // hardcoded: 0 0915 // * Average Bitrate DWORD 32 // in bits per second 0916 0917 // shortcut 0918 $thisfile_asf['stream_bitrate_properties_object'] = array(); 0919 $thisfile_asf_streambitratepropertiesobject = &$thisfile_asf['stream_bitrate_properties_object']; 0920 0921 $thisfile_asf_streambitratepropertiesobject['offset'] = $NextObjectOffset + $offset; 0922 $thisfile_asf_streambitratepropertiesobject['objectid'] = $NextObjectGUID; 0923 $thisfile_asf_streambitratepropertiesobject['objectid_guid'] = $NextObjectGUIDtext; 0924 $thisfile_asf_streambitratepropertiesobject['objectsize'] = $NextObjectSize; 0925 $thisfile_asf_streambitratepropertiesobject['bitrate_records_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); 0926 $offset += 2; 0927 for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < $thisfile_asf_streambitratepropertiesobject['bitrate_records_count']; $BitrateRecordsCounter++) { 0928 $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['flags_raw'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); 0929 $offset += 2; 0930 $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['flags']['stream_number'] = $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['flags_raw'] & 0x007F; 0931 $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['bitrate'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); 0932 $offset += 4; 0933 } 0934 break; 0935 0936 case GETID3_ASF_Padding_Object: 0937 // Padding Object: (optional) 0938 // Field Name Field Type Size (bits) 0939 // Object ID GUID 128 // GUID for Padding object - GETID3_ASF_Padding_Object 0940 // Object Size QWORD 64 // size of Padding object, including 24 bytes of ASF Padding Object header 0941 // Padding Data BYTESTREAM variable // ignore 0942 0943 // shortcut 0944 $thisfile_asf['padding_object'] = array(); 0945 $thisfile_asf_paddingobject = &$thisfile_asf['padding_object']; 0946 0947 $thisfile_asf_paddingobject['offset'] = $NextObjectOffset + $offset; 0948 $thisfile_asf_paddingobject['objectid'] = $NextObjectGUID; 0949 $thisfile_asf_paddingobject['objectid_guid'] = $NextObjectGUIDtext; 0950 $thisfile_asf_paddingobject['objectsize'] = $NextObjectSize; 0951 $thisfile_asf_paddingobject['padding_length'] = $thisfile_asf_paddingobject['objectsize'] - 16 - 8; 0952 $thisfile_asf_paddingobject['padding'] = substr($ASFHeaderData, $offset, $thisfile_asf_paddingobject['padding_length']); 0953 $offset += ($NextObjectSize - 16 - 8); 0954 break; 0955 0956 case GETID3_ASF_Extended_Content_Encryption_Object: 0957 case GETID3_ASF_Content_Encryption_Object: 0958 // WMA DRM - just ignore 0959 $offset += ($NextObjectSize - 16 - 8); 0960 break; 0961 0962 default: 0963 // Implementations shall ignore any standard or non-standard object that they do not know how to handle. 0964 if ($this->GUIDname($NextObjectGUIDtext)) { 0965 $info['warning'][] = 'unhandled GUID "'.$this->GUIDname($NextObjectGUIDtext).'" {'.$NextObjectGUIDtext.'} in ASF header at offset '.($offset - 16 - 8); 0966 } else { 0967 $info['warning'][] = 'unknown GUID {'.$NextObjectGUIDtext.'} in ASF header at offset '.($offset - 16 - 8); 0968 } 0969 $offset += ($NextObjectSize - 16 - 8); 0970 break; 0971 } 0972 } 0973 if (isset($thisfile_asf_streambitrateproperties['bitrate_records_count'])) { 0974 $ASFbitrateAudio = 0; 0975 $ASFbitrateVideo = 0; 0976 for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < $thisfile_asf_streambitrateproperties['bitrate_records_count']; $BitrateRecordsCounter++) { 0977 if (isset($thisfile_asf_codeclistobject['codec_entries'][$BitrateRecordsCounter])) { 0978 switch ($thisfile_asf_codeclistobject['codec_entries'][$BitrateRecordsCounter]['type_raw']) { 0979 case 1: 0980 $ASFbitrateVideo += $thisfile_asf_streambitrateproperties['bitrate_records'][$BitrateRecordsCounter]['bitrate']; 0981 break; 0982 0983 case 2: 0984 $ASFbitrateAudio += $thisfile_asf_streambitrateproperties['bitrate_records'][$BitrateRecordsCounter]['bitrate']; 0985 break; 0986 0987 default: 0988 // do nothing 0989 break; 0990 } 0991 } 0992 } 0993 if ($ASFbitrateAudio > 0) { 0994 $thisfile_audio['bitrate'] = $ASFbitrateAudio; 0995 } 0996 if ($ASFbitrateVideo > 0) { 0997 $thisfile_video['bitrate'] = $ASFbitrateVideo; 0998 } 0999 } 1000 if (isset($thisfile_asf['stream_properties_object']) && is_array($thisfile_asf['stream_properties_object'])) { 1001 1002 $thisfile_audio['bitrate'] = 0; 1003 $thisfile_video['bitrate'] = 0; 1004 1005 foreach ($thisfile_asf['stream_properties_object'] as $streamnumber => $streamdata) { 1006 1007 switch ($streamdata['stream_type']) { 1008 case GETID3_ASF_Audio_Media: 1009 // Field Name Field Type Size (bits) 1010 // Codec ID / Format Tag WORD 16 // unique ID of audio codec - defined as wFormatTag field of WAVEFORMATEX structure 1011 // Number of Channels WORD 16 // number of channels of audio - defined as nChannels field of WAVEFORMATEX structure 1012 // Samples Per Second DWORD 32 // in Hertz - defined as nSamplesPerSec field of WAVEFORMATEX structure 1013 // Average number of Bytes/sec DWORD 32 // bytes/sec of audio stream - defined as nAvgBytesPerSec field of WAVEFORMATEX structure 1014 // Block Alignment WORD 16 // block size in bytes of audio codec - defined as nBlockAlign field of WAVEFORMATEX structure 1015 // 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 1016 // Codec Specific Data Size WORD 16 // size in bytes of Codec Specific Data buffer - defined as cbSize field of WAVEFORMATEX structure 1017 // Codec Specific Data BYTESTREAM variable // array of codec-specific data bytes 1018 1019 // shortcut 1020 $thisfile_asf['audio_media'][$streamnumber] = array(); 1021 $thisfile_asf_audiomedia_currentstream = &$thisfile_asf['audio_media'][$streamnumber]; 1022 1023 $audiomediaoffset = 0; 1024 1025 $thisfile_asf_audiomedia_currentstream = getid3_riff::parseWAVEFORMATex(substr($streamdata['type_specific_data'], $audiomediaoffset, 16)); 1026 $audiomediaoffset += 16; 1027 1028 $thisfile_audio['lossless'] = false; 1029 switch ($thisfile_asf_audiomedia_currentstream['raw']['wFormatTag']) { 1030 case 0x0001: // PCM 1031 case 0x0163: // WMA9 Lossless 1032 $thisfile_audio['lossless'] = true; 1033 break; 1034 } 1035 1036 if (!empty($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'])) { 1037 foreach ($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'] as $dummy => $dataarray) { 1038 if (isset($dataarray['flags']['stream_number']) && ($dataarray['flags']['stream_number'] == $streamnumber)) { 1039 $thisfile_asf_audiomedia_currentstream['bitrate'] = $dataarray['bitrate']; 1040 $thisfile_audio['bitrate'] += $dataarray['bitrate']; 1041 break; 1042 } 1043 } 1044 } else { 1045 if (!empty($thisfile_asf_audiomedia_currentstream['bytes_sec'])) { 1046 $thisfile_audio['bitrate'] += $thisfile_asf_audiomedia_currentstream['bytes_sec'] * 8; 1047 } elseif (!empty($thisfile_asf_audiomedia_currentstream['bitrate'])) { 1048 $thisfile_audio['bitrate'] += $thisfile_asf_audiomedia_currentstream['bitrate']; 1049 } 1050 } 1051 $thisfile_audio['streams'][$streamnumber] = $thisfile_asf_audiomedia_currentstream; 1052 $thisfile_audio['streams'][$streamnumber]['wformattag'] = $thisfile_asf_audiomedia_currentstream['raw']['wFormatTag']; 1053 $thisfile_audio['streams'][$streamnumber]['lossless'] = $thisfile_audio['lossless']; 1054 $thisfile_audio['streams'][$streamnumber]['bitrate'] = $thisfile_audio['bitrate']; 1055 $thisfile_audio['streams'][$streamnumber]['dataformat'] = 'wma'; 1056 unset($thisfile_audio['streams'][$streamnumber]['raw']); 1057 1058 $thisfile_asf_audiomedia_currentstream['codec_data_size'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $audiomediaoffset, 2)); 1059 $audiomediaoffset += 2; 1060 $thisfile_asf_audiomedia_currentstream['codec_data'] = substr($streamdata['type_specific_data'], $audiomediaoffset, $thisfile_asf_audiomedia_currentstream['codec_data_size']); 1061 $audiomediaoffset += $thisfile_asf_audiomedia_currentstream['codec_data_size']; 1062 1063 break; 1064 1065 case GETID3_ASF_Video_Media: 1066 // Field Name Field Type Size (bits) 1067 // Encoded Image Width DWORD 32 // width of image in pixels 1068 // Encoded Image Height DWORD 32 // height of image in pixels 1069 // Reserved Flags BYTE 8 // hardcoded: 0x02 1070 // Format Data Size WORD 16 // size of Format Data field in bytes 1071 // Format Data array of: variable // 1072 // * Format Data Size DWORD 32 // number of bytes in Format Data field, in bytes - defined as biSize field of BITMAPINFOHEADER structure 1073 // * Image Width LONG 32 // width of encoded image in pixels - defined as biWidth field of BITMAPINFOHEADER structure 1074 // * Image Height LONG 32 // height of encoded image in pixels - defined as biHeight field of BITMAPINFOHEADER structure 1075 // * Reserved WORD 16 // hardcoded: 0x0001 - defined as biPlanes field of BITMAPINFOHEADER structure 1076 // * Bits Per Pixel Count WORD 16 // bits per pixel - defined as biBitCount field of BITMAPINFOHEADER structure 1077 // * Compression ID FOURCC 32 // fourcc of video codec - defined as biCompression field of BITMAPINFOHEADER structure 1078 // * Image Size DWORD 32 // image size in bytes - defined as biSizeImage field of BITMAPINFOHEADER structure 1079 // * Horizontal Pixels / Meter DWORD 32 // horizontal resolution of target device in pixels per meter - defined as biXPelsPerMeter field of BITMAPINFOHEADER structure 1080 // * Vertical Pixels / Meter DWORD 32 // vertical resolution of target device in pixels per meter - defined as biYPelsPerMeter field of BITMAPINFOHEADER structure 1081 // * Colors Used Count DWORD 32 // number of color indexes in the color table that are actually used - defined as biClrUsed field of BITMAPINFOHEADER structure 1082 // * 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 1083 // * Codec Specific Data BYTESTREAM variable // array of codec-specific data bytes 1084 1085 // shortcut 1086 $thisfile_asf['video_media'][$streamnumber] = array(); 1087 $thisfile_asf_videomedia_currentstream = &$thisfile_asf['video_media'][$streamnumber]; 1088 1089 $videomediaoffset = 0; 1090 $thisfile_asf_videomedia_currentstream['image_width'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); 1091 $videomediaoffset += 4; 1092 $thisfile_asf_videomedia_currentstream['image_height'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); 1093 $videomediaoffset += 4; 1094 $thisfile_asf_videomedia_currentstream['flags'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 1)); 1095 $videomediaoffset += 1; 1096 $thisfile_asf_videomedia_currentstream['format_data_size'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 2)); 1097 $videomediaoffset += 2; 1098 $thisfile_asf_videomedia_currentstream['format_data']['format_data_size'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); 1099 $videomediaoffset += 4; 1100 $thisfile_asf_videomedia_currentstream['format_data']['image_width'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); 1101 $videomediaoffset += 4; 1102 $thisfile_asf_videomedia_currentstream['format_data']['image_height'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); 1103 $videomediaoffset += 4; 1104 $thisfile_asf_videomedia_currentstream['format_data']['reserved'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 2)); 1105 $videomediaoffset += 2; 1106 $thisfile_asf_videomedia_currentstream['format_data']['bits_per_pixel'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 2)); 1107 $videomediaoffset += 2; 1108 $thisfile_asf_videomedia_currentstream['format_data']['codec_fourcc'] = substr($streamdata['type_specific_data'], $videomediaoffset, 4); 1109 $videomediaoffset += 4; 1110 $thisfile_asf_videomedia_currentstream['format_data']['image_size'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); 1111 $videomediaoffset += 4; 1112 $thisfile_asf_videomedia_currentstream['format_data']['horizontal_pels'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); 1113 $videomediaoffset += 4; 1114 $thisfile_asf_videomedia_currentstream['format_data']['vertical_pels'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); 1115 $videomediaoffset += 4; 1116 $thisfile_asf_videomedia_currentstream['format_data']['colors_used'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); 1117 $videomediaoffset += 4; 1118 $thisfile_asf_videomedia_currentstream['format_data']['colors_important'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); 1119 $videomediaoffset += 4; 1120 $thisfile_asf_videomedia_currentstream['format_data']['codec_data'] = substr($streamdata['type_specific_data'], $videomediaoffset); 1121 1122 if (!empty($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'])) { 1123 foreach ($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'] as $dummy => $dataarray) { 1124 if (isset($dataarray['flags']['stream_number']) && ($dataarray['flags']['stream_number'] == $streamnumber)) { 1125 $thisfile_asf_videomedia_currentstream['bitrate'] = $dataarray['bitrate']; 1126 $thisfile_video['streams'][$streamnumber]['bitrate'] = $dataarray['bitrate']; 1127 $thisfile_video['bitrate'] += $dataarray['bitrate']; 1128 break; 1129 } 1130 } 1131 } 1132 1133 $thisfile_asf_videomedia_currentstream['format_data']['codec'] = getid3_riff::fourccLookup($thisfile_asf_videomedia_currentstream['format_data']['codec_fourcc']); 1134 1135 $thisfile_video['streams'][$streamnumber]['fourcc'] = $thisfile_asf_videomedia_currentstream['format_data']['codec_fourcc']; 1136 $thisfile_video['streams'][$streamnumber]['codec'] = $thisfile_asf_videomedia_currentstream['format_data']['codec']; 1137 $thisfile_video['streams'][$streamnumber]['resolution_x'] = $thisfile_asf_videomedia_currentstream['image_width']; 1138 $thisfile_video['streams'][$streamnumber]['resolution_y'] = $thisfile_asf_videomedia_currentstream['image_height']; 1139 $thisfile_video['streams'][$streamnumber]['bits_per_sample'] = $thisfile_asf_videomedia_currentstream['format_data']['bits_per_pixel']; 1140 break; 1141 1142 default: 1143 break; 1144 } 1145 } 1146 } 1147 1148 while ($this->ftell() < $info['avdataend']) { 1149 $NextObjectDataHeader = $this->fread(24); 1150 $offset = 0; 1151 $NextObjectGUID = substr($NextObjectDataHeader, 0, 16); 1152 $offset += 16; 1153 $NextObjectGUIDtext = $this->BytestringToGUID($NextObjectGUID); 1154 $NextObjectSize = getid3_lib::LittleEndian2Int(substr($NextObjectDataHeader, $offset, 8)); 1155 $offset += 8; 1156 1157 switch ($NextObjectGUID) { 1158 case GETID3_ASF_Data_Object: 1159 // Data Object: (mandatory, one only) 1160 // Field Name Field Type Size (bits) 1161 // Object ID GUID 128 // GUID for Data object - GETID3_ASF_Data_Object 1162 // Object Size QWORD 64 // size of Data object, including 50 bytes of Data Object header. may be 0 if FilePropertiesObject.BroadcastFlag == 1 1163 // File ID GUID 128 // unique identifier. identical to File ID field in Header Object 1164 // Total Data Packets QWORD 64 // number of Data Packet entries in Data Object. invalid if FilePropertiesObject.BroadcastFlag == 1 1165 // Reserved WORD 16 // hardcoded: 0x0101 1166 1167 // shortcut 1168 $thisfile_asf['data_object'] = array(); 1169 $thisfile_asf_dataobject = &$thisfile_asf['data_object']; 1170 1171 $DataObjectData = $NextObjectDataHeader.$this->fread(50 - 24); 1172 $offset = 24; 1173 1174 $thisfile_asf_dataobject['objectid'] = $NextObjectGUID; 1175 $thisfile_asf_dataobject['objectid_guid'] = $NextObjectGUIDtext; 1176 $thisfile_asf_dataobject['objectsize'] = $NextObjectSize; 1177 1178 $thisfile_asf_dataobject['fileid'] = substr($DataObjectData, $offset, 16); 1179 $offset += 16; 1180 $thisfile_asf_dataobject['fileid_guid'] = $this->BytestringToGUID($thisfile_asf_dataobject['fileid']); 1181 $thisfile_asf_dataobject['total_data_packets'] = getid3_lib::LittleEndian2Int(substr($DataObjectData, $offset, 8)); 1182 $offset += 8; 1183 $thisfile_asf_dataobject['reserved'] = getid3_lib::LittleEndian2Int(substr($DataObjectData, $offset, 2)); 1184 $offset += 2; 1185 if ($thisfile_asf_dataobject['reserved'] != 0x0101) { 1186 $info['warning'][] = 'data_object.reserved ('.getid3_lib::PrintHexBytes($thisfile_asf_dataobject['reserved']).') does not match expected value of "0x0101"'; 1187 //return false; 1188 break; 1189 } 1190 1191 // Data Packets array of: variable // 1192 // * Error Correction Flags BYTE 8 // 1193 // * * Error Correction Data Length bits 4 // if Error Correction Length Type == 00, size of Error Correction Data in bytes, else hardcoded: 0000 1194 // * * Opaque Data Present bits 1 // 1195 // * * Error Correction Length Type bits 2 // number of bits for size of the error correction data. hardcoded: 00 1196 // * * Error Correction Present bits 1 // If set, use Opaque Data Packet structure, else use Payload structure 1197 // * Error Correction Data 1198 1199 $info['avdataoffset'] = $this->ftell(); 1200 $this->fseek(($thisfile_asf_dataobject['objectsize'] - 50), SEEK_CUR); // skip actual audio/video data 1201 $info['avdataend'] = $this->ftell(); 1202 break; 1203 1204 case GETID3_ASF_Simple_Index_Object: 1205 // Simple Index Object: (optional, recommended, one per video stream) 1206 // Field Name Field Type Size (bits) 1207 // Object ID GUID 128 // GUID for Simple Index object - GETID3_ASF_Data_Object 1208 // Object Size QWORD 64 // size of Simple Index object, including 56 bytes of Simple Index Object header 1209 // File ID GUID 128 // unique identifier. may be zero or identical to File ID field in Data Object and Header Object 1210 // Index Entry Time Interval QWORD 64 // interval between index entries in 100-nanosecond units 1211 // Maximum Packet Count DWORD 32 // maximum packet count for all index entries 1212 // Index Entries Count DWORD 32 // number of Index Entries structures 1213 // Index Entries array of: variable // 1214 // * Packet Number DWORD 32 // number of the Data Packet associated with this index entry 1215 // * Packet Count WORD 16 // number of Data Packets to sent at this index entry 1216 1217 // shortcut 1218 $thisfile_asf['simple_index_object'] = array(); 1219 $thisfile_asf_simpleindexobject = &$thisfile_asf['simple_index_object']; 1220 1221 $SimpleIndexObjectData = $NextObjectDataHeader.$this->fread(56 - 24); 1222 $offset = 24; 1223 1224 $thisfile_asf_simpleindexobject['objectid'] = $NextObjectGUID; 1225 $thisfile_asf_simpleindexobject['objectid_guid'] = $NextObjectGUIDtext; 1226 $thisfile_asf_simpleindexobject['objectsize'] = $NextObjectSize; 1227 1228 $thisfile_asf_simpleindexobject['fileid'] = substr($SimpleIndexObjectData, $offset, 16); 1229 $offset += 16; 1230 $thisfile_asf_simpleindexobject['fileid_guid'] = $this->BytestringToGUID($thisfile_asf_simpleindexobject['fileid']); 1231 $thisfile_asf_simpleindexobject['index_entry_time_interval'] = getid3_lib::LittleEndian2Int(substr($SimpleIndexObjectData, $offset, 8)); 1232 $offset += 8; 1233 $thisfile_asf_simpleindexobject['maximum_packet_count'] = getid3_lib::LittleEndian2Int(substr($SimpleIndexObjectData, $offset, 4)); 1234 $offset += 4; 1235 $thisfile_asf_simpleindexobject['index_entries_count'] = getid3_lib::LittleEndian2Int(substr($SimpleIndexObjectData, $offset, 4)); 1236 $offset += 4; 1237 1238 $IndexEntriesData = $SimpleIndexObjectData.$this->fread(6 * $thisfile_asf_simpleindexobject['index_entries_count']); 1239 for ($IndexEntriesCounter = 0; $IndexEntriesCounter < $thisfile_asf_simpleindexobject['index_entries_count']; $IndexEntriesCounter++) { 1240 $thisfile_asf_simpleindexobject['index_entries'][$IndexEntriesCounter]['packet_number'] = getid3_lib::LittleEndian2Int(substr($IndexEntriesData, $offset, 4)); 1241 $offset += 4; 1242 $thisfile_asf_simpleindexobject['index_entries'][$IndexEntriesCounter]['packet_count'] = getid3_lib::LittleEndian2Int(substr($IndexEntriesData, $offset, 4)); 1243 $offset += 2; 1244 } 1245 1246 break; 1247 1248 case GETID3_ASF_Index_Object: 1249 // 6.2 ASF top-level Index Object (optional but recommended when appropriate, 0 or 1) 1250 // Field Name Field Type Size (bits) 1251 // Object ID GUID 128 // GUID for the Index Object - GETID3_ASF_Index_Object 1252 // Object Size QWORD 64 // Specifies the size, in bytes, of the Index Object, including at least 34 bytes of Index Object header 1253 // Index Entry Time Interval DWORD 32 // Specifies the time interval between each index entry in ms. 1254 // Index Specifiers Count WORD 16 // Specifies the number of Index Specifiers structures in this Index Object. 1255 // Index Blocks Count DWORD 32 // Specifies the number of Index Blocks structures in this Index Object. 1256 1257 // Index Entry Time Interval DWORD 32 // Specifies the time interval between index entries in milliseconds. This value cannot be 0. 1258 // Index Specifiers Count WORD 16 // Specifies the number of entries in the Index Specifiers list. Valid values are 1 and greater. 1259 // Index Specifiers array of: varies // 1260 // * Stream Number WORD 16 // Specifies the stream number that the Index Specifiers refer to. Valid values are between 1 and 127. 1261 // * Index Type WORD 16 // Specifies Index Type values as follows: 1262 // 1 = Nearest Past Data Packet - indexes point to the data packet whose presentation time is closest to the index entry time. 1263 // 2 = Nearest Past Media Object - indexes point to the closest data packet containing an entire object or first fragment of an object. 1264 // 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. 1265 // Nearest Past Cleanpoint is the most common type of index. 1266 // Index Entry Count DWORD 32 // Specifies the number of Index Entries in the block. 1267 // * 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. 1268 // * Index Entries array of: varies // 1269 // * * Offsets DWORD varies // An offset value of 0xffffffff indicates an invalid offset value 1270 1271 // shortcut 1272 $thisfile_asf['asf_index_object'] = array(); 1273 $thisfile_asf_asfindexobject = &$thisfile_asf['asf_index_object']; 1274 1275 $ASFIndexObjectData = $NextObjectDataHeader.$this->fread(34 - 24); 1276 $offset = 24; 1277 1278 $thisfile_asf_asfindexobject['objectid'] = $NextObjectGUID; 1279 $thisfile_asf_asfindexobject['objectid_guid'] = $NextObjectGUIDtext; 1280 $thisfile_asf_asfindexobject['objectsize'] = $NextObjectSize; 1281 1282 $thisfile_asf_asfindexobject['entry_time_interval'] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4)); 1283 $offset += 4; 1284 $thisfile_asf_asfindexobject['index_specifiers_count'] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 2)); 1285 $offset += 2; 1286 $thisfile_asf_asfindexobject['index_blocks_count'] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4)); 1287 $offset += 4; 1288 1289 $ASFIndexObjectData .= $this->fread(4 * $thisfile_asf_asfindexobject['index_specifiers_count']); 1290 for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) { 1291 $IndexSpecifierStreamNumber = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 2)); 1292 $offset += 2; 1293 $thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['stream_number'] = $IndexSpecifierStreamNumber; 1294 $thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['index_type'] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 2)); 1295 $offset += 2; 1296 $thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['index_type_text'] = $this->ASFIndexObjectIndexTypeLookup($thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['index_type']); 1297 } 1298 1299 $ASFIndexObjectData .= $this->fread(4); 1300 $thisfile_asf_asfindexobject['index_entry_count'] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4)); 1301 $offset += 4; 1302 1303 $ASFIndexObjectData .= $this->fread(8 * $thisfile_asf_asfindexobject['index_specifiers_count']); 1304 for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) { 1305 $thisfile_asf_asfindexobject['block_positions'][$IndexSpecifiersCounter] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 8)); 1306 $offset += 8; 1307 } 1308 1309 $ASFIndexObjectData .= $this->fread(4 * $thisfile_asf_asfindexobject['index_specifiers_count'] * $thisfile_asf_asfindexobject['index_entry_count']); 1310 for ($IndexEntryCounter = 0; $IndexEntryCounter < $thisfile_asf_asfindexobject['index_entry_count']; $IndexEntryCounter++) { 1311 for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) { 1312 $thisfile_asf_asfindexobject['offsets'][$IndexSpecifiersCounter][$IndexEntryCounter] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4)); 1313 $offset += 4; 1314 } 1315 } 1316 break; 1317 1318 1319 default: 1320 // Implementations shall ignore any standard or non-standard object that they do not know how to handle. 1321 if ($this->GUIDname($NextObjectGUIDtext)) { 1322 $info['warning'][] = 'unhandled GUID "'.$this->GUIDname($NextObjectGUIDtext).'" {'.$NextObjectGUIDtext.'} in ASF body at offset '.($offset - 16 - 8); 1323 } else { 1324 $info['warning'][] = 'unknown GUID {'.$NextObjectGUIDtext.'} in ASF body at offset '.($this->ftell() - 16 - 8); 1325 } 1326 $this->fseek(($NextObjectSize - 16 - 8), SEEK_CUR); 1327 break; 1328 } 1329 } 1330 1331 if (isset($thisfile_asf_codeclistobject['codec_entries']) && is_array($thisfile_asf_codeclistobject['codec_entries'])) { 1332 foreach ($thisfile_asf_codeclistobject['codec_entries'] as $streamnumber => $streamdata) { 1333 switch ($streamdata['information']) { 1334 case 'WMV1': 1335 case 'WMV2': 1336 case 'WMV3': 1337 case 'MSS1': 1338 case 'MSS2': 1339 case 'WMVA': 1340 case 'WVC1': 1341 case 'WMVP': 1342 case 'WVP2': 1343 $thisfile_video['dataformat'] = 'wmv'; 1344 $info['mime_type'] = 'video/x-ms-wmv'; 1345 break; 1346 1347 case 'MP42': 1348 case 'MP43': 1349 case 'MP4S': 1350 case 'mp4s': 1351 $thisfile_video['dataformat'] = 'asf'; 1352 $info['mime_type'] = 'video/x-ms-asf'; 1353 break; 1354 1355 default: 1356 switch ($streamdata['type_raw']) { 1357 case 1: 1358 if (strstr($this->TrimConvert($streamdata['name']), 'Windows Media')) { 1359 $thisfile_video['dataformat'] = 'wmv'; 1360 if ($info['mime_type'] == 'video/x-ms-asf') { 1361 $info['mime_type'] = 'video/x-ms-wmv'; 1362 } 1363 } 1364 break; 1365 1366 case 2: 1367 if (strstr($this->TrimConvert($streamdata['name']), 'Windows Media')) { 1368 $thisfile_audio['dataformat'] = 'wma'; 1369 if ($info['mime_type'] == 'video/x-ms-asf') { 1370 $info['mime_type'] = 'audio/x-ms-wma'; 1371 } 1372 } 1373 break; 1374 1375 } 1376 break; 1377 } 1378 } 1379 } 1380 1381 switch (isset($thisfile_audio['codec']) ? $thisfile_audio['codec'] : '') { 1382 case 'MPEG Layer-3': 1383 $thisfile_audio['dataformat'] = 'mp3'; 1384 break; 1385 1386 default: 1387 break; 1388 } 1389 1390 if (isset($thisfile_asf_codeclistobject['codec_entries'])) { 1391 foreach ($thisfile_asf_codeclistobject['codec_entries'] as $streamnumber => $streamdata) { 1392 switch ($streamdata['type_raw']) { 1393 1394 case 1: // video 1395 $thisfile_video['encoder'] = $this->TrimConvert($thisfile_asf_codeclistobject['codec_entries'][$streamnumber]['name']); 1396 break; 1397 1398 case 2: // audio 1399 $thisfile_audio['encoder'] = $this->TrimConvert($thisfile_asf_codeclistobject['codec_entries'][$streamnumber]['name']); 1400 1401 // AH 2003-10-01 1402 $thisfile_audio['encoder_options'] = $this->TrimConvert($thisfile_asf_codeclistobject['codec_entries'][0]['description']); 1403 1404 $thisfile_audio['codec'] = $thisfile_audio['encoder']; 1405 break; 1406 1407 default: 1408 $info['warning'][] = 'Unknown streamtype: [codec_list_object][codec_entries]['.$streamnumber.'][type_raw] == '.$streamdata['type_raw']; 1409 break; 1410 1411 } 1412 } 1413 } 1414 1415 if (isset($info['audio'])) { 1416 $thisfile_audio['lossless'] = (isset($thisfile_audio['lossless']) ? $thisfile_audio['lossless'] : false); 1417 $thisfile_audio['dataformat'] = (!empty($thisfile_audio['dataformat']) ? $thisfile_audio['dataformat'] : 'asf'); 1418 } 1419 if (!empty($thisfile_video['dataformat'])) { 1420 $thisfile_video['lossless'] = (isset($thisfile_audio['lossless']) ? $thisfile_audio['lossless'] : false); 1421 $thisfile_video['pixel_aspect_ratio'] = (isset($thisfile_audio['pixel_aspect_ratio']) ? $thisfile_audio['pixel_aspect_ratio'] : (float) 1); 1422 $thisfile_video['dataformat'] = (!empty($thisfile_video['dataformat']) ? $thisfile_video['dataformat'] : 'asf'); 1423 } 1424 if (!empty($thisfile_video['streams'])) { 1425 $thisfile_video['resolution_x'] = 0; 1426 $thisfile_video['resolution_y'] = 0; 1427 foreach ($thisfile_video['streams'] as $key => $valuearray) { 1428 if (($valuearray['resolution_x'] > $thisfile_video['resolution_x']) || ($valuearray['resolution_y'] > $thisfile_video['resolution_y'])) { 1429 $thisfile_video['resolution_x'] = $valuearray['resolution_x']; 1430 $thisfile_video['resolution_y'] = $valuearray['resolution_y']; 1431 } 1432 } 1433 } 1434 $info['bitrate'] = (isset($thisfile_audio['bitrate']) ? $thisfile_audio['bitrate'] : 0) + (isset($thisfile_video['bitrate']) ? $thisfile_video['bitrate'] : 0); 1435 1436 if ((!isset($info['playtime_seconds']) || ($info['playtime_seconds'] <= 0)) && ($info['bitrate'] > 0)) { 1437 $info['playtime_seconds'] = ($info['filesize'] - $info['avdataoffset']) / ($info['bitrate'] / 8); 1438 } 1439 1440 return true; 1441 } 1442 1443 public static function codecListObjectTypeLookup($CodecListType) { 1444 static $lookup = array( 1445 0x0001 => 'Video Codec', 1446 0x0002 => 'Audio Codec', 1447 0xFFFF => 'Unknown Codec' 1448 ); 1449 1450 return (isset($lookup[$CodecListType]) ? $lookup[$CodecListType] : 'Invalid Codec Type'); 1451 } 1452 1453 public static function KnownGUIDs() { 1454 static $GUIDarray = array( 1455 'GETID3_ASF_Extended_Stream_Properties_Object' => '14E6A5CB-C672-4332-8399-A96952065B5A', 1456 'GETID3_ASF_Padding_Object' => '1806D474-CADF-4509-A4BA-9AABCB96AAE8', 1457 'GETID3_ASF_Payload_Ext_Syst_Pixel_Aspect_Ratio' => '1B1EE554-F9EA-4BC8-821A-376B74E4C4B8', 1458 'GETID3_ASF_Script_Command_Object' => '1EFB1A30-0B62-11D0-A39B-00A0C90348F6', 1459 'GETID3_ASF_No_Error_Correction' => '20FB5700-5B55-11CF-A8FD-00805F5C442B', 1460 'GETID3_ASF_Content_Branding_Object' => '2211B3FA-BD23-11D2-B4B7-00A0C955FC6E', 1461 'GETID3_ASF_Content_Encryption_Object' => '2211B3FB-BD23-11D2-B4B7-00A0C955FC6E', 1462 'GETID3_ASF_Digital_Signature_Object' => '2211B3FC-BD23-11D2-B4B7-00A0C955FC6E', 1463 'GETID3_ASF_Extended_Content_Encryption_Object' => '298AE614-2622-4C17-B935-DAE07EE9289C', 1464 'GETID3_ASF_Simple_Index_Object' => '33000890-E5B1-11CF-89F4-00A0C90349CB', 1465 'GETID3_ASF_Degradable_JPEG_Media' => '35907DE0-E415-11CF-A917-00805F5C442B', 1466 'GETID3_ASF_Payload_Extension_System_Timecode' => '399595EC-8667-4E2D-8FDB-98814CE76C1E', 1467 'GETID3_ASF_Binary_Media' => '3AFB65E2-47EF-40F2-AC2C-70A90D71D343', 1468 'GETID3_ASF_Timecode_Index_Object' => '3CB73FD0-0C4A-4803-953D-EDF7B6228F0C', 1469 'GETID3_ASF_Metadata_Library_Object' => '44231C94-9498-49D1-A141-1D134E457054', 1470 'GETID3_ASF_Reserved_3' => '4B1ACBE3-100B-11D0-A39B-00A0C90348F6', 1471 'GETID3_ASF_Reserved_4' => '4CFEDB20-75F6-11CF-9C0F-00A0C90349CB', 1472 'GETID3_ASF_Command_Media' => '59DACFC0-59E6-11D0-A3AC-00A0C90348F6', 1473 'GETID3_ASF_Header_Extension_Object' => '5FBF03B5-A92E-11CF-8EE3-00C00C205365', 1474 'GETID3_ASF_Media_Object_Index_Parameters_Obj' => '6B203BAD-3F11-4E84-ACA8-D7613DE2CFA7', 1475 'GETID3_ASF_Header_Object' => '75B22630-668E-11CF-A6D9-00AA0062CE6C', 1476 'GETID3_ASF_Content_Description_Object' => '75B22633-668E-11CF-A6D9-00AA0062CE6C', 1477 'GETID3_ASF_Error_Correction_Object' => '75B22635-668E-11CF-A6D9-00AA0062CE6C', 1478 'GETID3_ASF_Data_Object' => '75B22636-668E-11CF-A6D9-00AA0062CE6C', 1479 'GETID3_ASF_Web_Stream_Media_Subtype' => '776257D4-C627-41CB-8F81-7AC7FF1C40CC', 1480 'GETID3_ASF_Stream_Bitrate_Properties_Object' => '7BF875CE-468D-11D1-8D82-006097C9A2B2', 1481 'GETID3_ASF_Language_List_Object' => '7C4346A9-EFE0-4BFC-B229-393EDE415C85', 1482 'GETID3_ASF_Codec_List_Object' => '86D15240-311D-11D0-A3A4-00A0C90348F6', 1483 'GETID3_ASF_Reserved_2' => '86D15241-311D-11D0-A3A4-00A0C90348F6', 1484 'GETID3_ASF_File_Properties_Object' => '8CABDCA1-A947-11CF-8EE4-00C00C205365', 1485 'GETID3_ASF_File_Transfer_Media' => '91BD222C-F21C-497A-8B6D-5AA86BFC0185', 1486 'GETID3_ASF_Old_RTP_Extension_Data' => '96800C63-4C94-11D1-837B-0080C7A37F95', 1487 'GETID3_ASF_Advanced_Mutual_Exclusion_Object' => 'A08649CF-4775-4670-8A16-6E35357566CD', 1488 'GETID3_ASF_Bandwidth_Sharing_Object' => 'A69609E6-517B-11D2-B6AF-00C04FD908E9', 1489 'GETID3_ASF_Reserved_1' => 'ABD3D211-A9BA-11cf-8EE6-00C00C205365', 1490 'GETID3_ASF_Bandwidth_Sharing_Exclusive' => 'AF6060AA-5197-11D2-B6AF-00C04FD908E9', 1491 'GETID3_ASF_Bandwidth_Sharing_Partial' => 'AF6060AB-5197-11D2-B6AF-00C04FD908E9', 1492 'GETID3_ASF_JFIF_Media' => 'B61BE100-5B4E-11CF-A8FD-00805F5C442B', 1493 'GETID3_ASF_Stream_Properties_Object' => 'B7DC0791-A9B7-11CF-8EE6-00C00C205365', 1494 'GETID3_ASF_Video_Media' => 'BC19EFC0-5B4D-11CF-A8FD-00805F5C442B', 1495 'GETID3_ASF_Audio_Spread' => 'BFC3CD50-618F-11CF-8BB2-00AA00B4E220', 1496 'GETID3_ASF_Metadata_Object' => 'C5F8CBEA-5BAF-4877-8467-AA8C44FA4CCA', 1497 'GETID3_ASF_Payload_Ext_Syst_Sample_Duration' => 'C6BD9450-867F-4907-83A3-C77921B733AD', 1498 'GETID3_ASF_Group_Mutual_Exclusion_Object' => 'D1465A40-5A79-4338-B71B-E36B8FD6C249', 1499 'GETID3_ASF_Extended_Content_Description_Object' => 'D2D0A440-E307-11D2-97F0-00A0C95EA850', 1500 'GETID3_ASF_Stream_Prioritization_Object' => 'D4FED15B-88D3-454F-81F0-ED5C45999E24', 1501 'GETID3_ASF_Payload_Ext_System_Content_Type' => 'D590DC20-07BC-436C-9CF7-F3BBFBF1A4DC', 1502 'GETID3_ASF_Old_File_Properties_Object' => 'D6E229D0-35DA-11D1-9034-00A0C90349BE', 1503 'GETID3_ASF_Old_ASF_Header_Object' => 'D6E229D1-35DA-11D1-9034-00A0C90349BE', 1504 'GETID3_ASF_Old_ASF_Data_Object' => 'D6E229D2-35DA-11D1-9034-00A0C90349BE', 1505 'GETID3_ASF_Index_Object' => 'D6E229D3-35DA-11D1-9034-00A0C90349BE', 1506 'GETID3_ASF_Old_Stream_Properties_Object' => 'D6E229D4-35DA-11D1-9034-00A0C90349BE', 1507 'GETID3_ASF_Old_Content_Description_Object' => 'D6E229D5-35DA-11D1-9034-00A0C90349BE', 1508 'GETID3_ASF_Old_Script_Command_Object' => 'D6E229D6-35DA-11D1-9034-00A0C90349BE', 1509 'GETID3_ASF_Old_Marker_Object' => 'D6E229D7-35DA-11D1-9034-00A0C90349BE', 1510 'GETID3_ASF_Old_Component_Download_Object' => 'D6E229D8-35DA-11D1-9034-00A0C90349BE', 1511 'GETID3_ASF_Old_Stream_Group_Object' => 'D6E229D9-35DA-11D1-9034-00A0C90349BE', 1512 'GETID3_ASF_Old_Scalable_Object' => 'D6E229DA-35DA-11D1-9034-00A0C90349BE', 1513 'GETID3_ASF_Old_Prioritization_Object' => 'D6E229DB-35DA-11D1-9034-00A0C90349BE', 1514 'GETID3_ASF_Bitrate_Mutual_Exclusion_Object' => 'D6E229DC-35DA-11D1-9034-00A0C90349BE', 1515 'GETID3_ASF_Old_Inter_Media_Dependency_Object' => 'D6E229DD-35DA-11D1-9034-00A0C90349BE', 1516 'GETID3_ASF_Old_Rating_Object' => 'D6E229DE-35DA-11D1-9034-00A0C90349BE', 1517 'GETID3_ASF_Index_Parameters_Object' => 'D6E229DF-35DA-11D1-9034-00A0C90349BE', 1518 'GETID3_ASF_Old_Color_Table_Object' => 'D6E229E0-35DA-11D1-9034-00A0C90349BE', 1519 'GETID3_ASF_Old_Language_List_Object' => 'D6E229E1-35DA-11D1-9034-00A0C90349BE', 1520 'GETID3_ASF_Old_Audio_Media' => 'D6E229E2-35DA-11D1-9034-00A0C90349BE', 1521 'GETID3_ASF_Old_Video_Media' => 'D6E229E3-35DA-11D1-9034-00A0C90349BE', 1522 'GETID3_ASF_Old_Image_Media' => 'D6E229E4-35DA-11D1-9034-00A0C90349BE', 1523 'GETID3_ASF_Old_Timecode_Media' => 'D6E229E5-35DA-11D1-9034-00A0C90349BE', 1524 'GETID3_ASF_Old_Text_Media' => 'D6E229E6-35DA-11D1-9034-00A0C90349BE', 1525 'GETID3_ASF_Old_MIDI_Media' => 'D6E229E7-35DA-11D1-9034-00A0C90349BE', 1526 'GETID3_ASF_Old_Command_Media' => 'D6E229E8-35DA-11D1-9034-00A0C90349BE', 1527 'GETID3_ASF_Old_No_Error_Concealment' => 'D6E229EA-35DA-11D1-9034-00A0C90349BE', 1528 'GETID3_ASF_Old_Scrambled_Audio' => 'D6E229EB-35DA-11D1-9034-00A0C90349BE', 1529 'GETID3_ASF_Old_No_Color_Table' => 'D6E229EC-35DA-11D1-9034-00A0C90349BE', 1530 'GETID3_ASF_Old_SMPTE_Time' => 'D6E229ED-35DA-11D1-9034-00A0C90349BE', 1531 'GETID3_ASF_Old_ASCII_Text' => 'D6E229EE-35DA-11D1-9034-00A0C90349BE', 1532 'GETID3_ASF_Old_Unicode_Text' => 'D6E229EF-35DA-11D1-9034-00A0C90349BE', 1533 'GETID3_ASF_Old_HTML_Text' => 'D6E229F0-35DA-11D1-9034-00A0C90349BE', 1534 'GETID3_ASF_Old_URL_Command' => 'D6E229F1-35DA-11D1-9034-00A0C90349BE', 1535 'GETID3_ASF_Old_Filename_Command' => 'D6E229F2-35DA-11D1-9034-00A0C90349BE', 1536 'GETID3_ASF_Old_ACM_Codec' => 'D6E229F3-35DA-11D1-9034-00A0C90349BE', 1537 'GETID3_ASF_Old_VCM_Codec' => 'D6E229F4-35DA-11D1-9034-00A0C90349BE', 1538 'GETID3_ASF_Old_QuickTime_Codec' => 'D6E229F5-35DA-11D1-9034-00A0C90349BE', 1539 'GETID3_ASF_Old_DirectShow_Transform_Filter' => 'D6E229F6-35DA-11D1-9034-00A0C90349BE', 1540 'GETID3_ASF_Old_DirectShow_Rendering_Filter' => 'D6E229F7-35DA-11D1-9034-00A0C90349BE', 1541 'GETID3_ASF_Old_No_Enhancement' => 'D6E229F8-35DA-11D1-9034-00A0C90349BE', 1542 'GETID3_ASF_Old_Unknown_Enhancement_Type' => 'D6E229F9-35DA-11D1-9034-00A0C90349BE', 1543 'GETID3_ASF_Old_Temporal_Enhancement' => 'D6E229FA-35DA-11D1-9034-00A0C90349BE', 1544 'GETID3_ASF_Old_Spatial_Enhancement' => 'D6E229FB-35DA-11D1-9034-00A0C90349BE', 1545 'GETID3_ASF_Old_Quality_Enhancement' => 'D6E229FC-35DA-11D1-9034-00A0C90349BE', 1546 'GETID3_ASF_Old_Number_of_Channels_Enhancement' => 'D6E229FD-35DA-11D1-9034-00A0C90349BE', 1547 'GETID3_ASF_Old_Frequency_Response_Enhancement' => 'D6E229FE-35DA-11D1-9034-00A0C90349BE', 1548 'GETID3_ASF_Old_Media_Object' => 'D6E229FF-35DA-11D1-9034-00A0C90349BE', 1549 'GETID3_ASF_Mutex_Language' => 'D6E22A00-35DA-11D1-9034-00A0C90349BE', 1550 'GETID3_ASF_Mutex_Bitrate' => 'D6E22A01-35DA-11D1-9034-00A0C90349BE', 1551 'GETID3_ASF_Mutex_Unknown' => 'D6E22A02-35DA-11D1-9034-00A0C90349BE', 1552 'GETID3_ASF_Old_ASF_Placeholder_Object' => 'D6E22A0E-35DA-11D1-9034-00A0C90349BE', 1553 'GETID3_ASF_Old_Data_Unit_Extension_Object' => 'D6E22A0F-35DA-11D1-9034-00A0C90349BE', 1554 'GETID3_ASF_Web_Stream_Format' => 'DA1E6B13-8359-4050-B398-388E965BF00C', 1555 'GETID3_ASF_Payload_Ext_System_File_Name' => 'E165EC0E-19ED-45D7-B4A7-25CBD1E28E9B', 1556 'GETID3_ASF_Marker_Object' => 'F487CD01-A951-11CF-8EE6-00C00C205365', 1557 'GETID3_ASF_Timecode_Index_Parameters_Object' => 'F55E496D-9797-4B5D-8C8B-604DFE9BFB24', 1558 'GETID3_ASF_Audio_Media' => 'F8699E40-5B4D-11CF-A8FD-00805F5C442B', 1559 'GETID3_ASF_Media_Object_Index_Object' => 'FEB103F8-12AD-4C64-840F-2A1D2F7AD48C', 1560 'GETID3_ASF_Alt_Extended_Content_Encryption_Obj' => 'FF889EF1-ADEE-40DA-9E71-98704BB928CE', 1561 'GETID3_ASF_Index_Placeholder_Object' => 'D9AADE20-7C17-4F9C-BC28-8555DD98E2A2', // http://cpan.uwinnipeg.ca/htdocs/Audio-WMA/Audio/WMA.pm.html 1562 'GETID3_ASF_Compatibility_Object' => '26F18B5D-4584-47EC-9F5F-0E651F0452C9', // http://cpan.uwinnipeg.ca/htdocs/Audio-WMA/Audio/WMA.pm.html 1563 ); 1564 return $GUIDarray; 1565 } 1566 1567 public static function GUIDname($GUIDstring) { 1568 static $GUIDarray = array(); 1569 if (empty($GUIDarray)) { 1570 $GUIDarray = self::KnownGUIDs(); 1571 } 1572 return array_search($GUIDstring, $GUIDarray); 1573 } 1574 1575 public static function ASFIndexObjectIndexTypeLookup($id) { 1576 static $ASFIndexObjectIndexTypeLookup = array(); 1577 if (empty($ASFIndexObjectIndexTypeLookup)) { 1578 $ASFIndexObjectIndexTypeLookup[1] = 'Nearest Past Data Packet'; 1579 $ASFIndexObjectIndexTypeLookup[2] = 'Nearest Past Media Object'; 1580 $ASFIndexObjectIndexTypeLookup[3] = 'Nearest Past Cleanpoint'; 1581 } 1582 return (isset($ASFIndexObjectIndexTypeLookup[$id]) ? $ASFIndexObjectIndexTypeLookup[$id] : 'invalid'); 1583 } 1584 1585 public static function GUIDtoBytestring($GUIDstring) { 1586 // Microsoft defines these 16-byte (128-bit) GUIDs in the strangest way: 1587 // first 4 bytes are in little-endian order 1588 // next 2 bytes are appended in little-endian order 1589 // next 2 bytes are appended in little-endian order 1590 // next 2 bytes are appended in big-endian order 1591 // next 6 bytes are appended in big-endian order 1592 1593 // AaBbCcDd-EeFf-GgHh-IiJj-KkLlMmNnOoPp is stored as this 16-byte string: 1594 // $Dd $Cc $Bb $Aa $Ff $Ee $Hh $Gg $Ii $Jj $Kk $Ll $Mm $Nn $Oo $Pp 1595 1596 $hexbytecharstring = chr(hexdec(substr($GUIDstring, 6, 2))); 1597 $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 4, 2))); 1598 $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 2, 2))); 1599 $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 0, 2))); 1600 1601 $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 11, 2))); 1602 $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 9, 2))); 1603 1604 $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 16, 2))); 1605 $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 14, 2))); 1606 1607 $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 19, 2))); 1608 $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 21, 2))); 1609 1610 $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 24, 2))); 1611 $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 26, 2))); 1612 $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 28, 2))); 1613 $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 30, 2))); 1614 $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 32, 2))); 1615 $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 34, 2))); 1616 1617 return $hexbytecharstring; 1618 } 1619 1620 public static function BytestringToGUID($Bytestring) { 1621 $GUIDstring = str_pad(dechex(ord($Bytestring{3})), 2, '0', STR_PAD_LEFT); 1622 $GUIDstring .= str_pad(dechex(ord($Bytestring{2})), 2, '0', STR_PAD_LEFT); 1623 $GUIDstring .= str_pad(dechex(ord($Bytestring{1})), 2, '0', STR_PAD_LEFT); 1624 $GUIDstring .= str_pad(dechex(ord($Bytestring{0})), 2, '0', STR_PAD_LEFT); 1625 $GUIDstring .= '-'; 1626 $GUIDstring .= str_pad(dechex(ord($Bytestring{5})), 2, '0', STR_PAD_LEFT); 1627 $GUIDstring .= str_pad(dechex(ord($Bytestring{4})), 2, '0', STR_PAD_LEFT); 1628 $GUIDstring .= '-'; 1629 $GUIDstring .= str_pad(dechex(ord($Bytestring{7})), 2, '0', STR_PAD_LEFT); 1630 $GUIDstring .= str_pad(dechex(ord($Bytestring{6})), 2, '0', STR_PAD_LEFT); 1631 $GUIDstring .= '-'; 1632 $GUIDstring .= str_pad(dechex(ord($Bytestring{8})), 2, '0', STR_PAD_LEFT); 1633 $GUIDstring .= str_pad(dechex(ord($Bytestring{9})), 2, '0', STR_PAD_LEFT); 1634 $GUIDstring .= '-'; 1635 $GUIDstring .= str_pad(dechex(ord($Bytestring{10})), 2, '0', STR_PAD_LEFT); 1636 $GUIDstring .= str_pad(dechex(ord($Bytestring{11})), 2, '0', STR_PAD_LEFT); 1637 $GUIDstring .= str_pad(dechex(ord($Bytestring{12})), 2, '0', STR_PAD_LEFT); 1638 $GUIDstring .= str_pad(dechex(ord($Bytestring{13})), 2, '0', STR_PAD_LEFT); 1639 $GUIDstring .= str_pad(dechex(ord($Bytestring{14})), 2, '0', STR_PAD_LEFT); 1640 $GUIDstring .= str_pad(dechex(ord($Bytestring{15})), 2, '0', STR_PAD_LEFT); 1641 1642 return strtoupper($GUIDstring); 1643 } 1644 1645 public static function FILETIMEtoUNIXtime($FILETIME, $round=true) { 1646 // FILETIME is a 64-bit unsigned integer representing 1647 // the number of 100-nanosecond intervals since January 1, 1601 1648 // UNIX timestamp is number of seconds since January 1, 1970 1649 // 116444736000000000 = 10000000 * 60 * 60 * 24 * 365 * 369 + 89 leap days 1650 if ($round) { 1651 return intval(round(($FILETIME - 116444736000000000) / 10000000)); 1652 } 1653 return ($FILETIME - 116444736000000000) / 10000000; 1654 } 1655 1656 public static function WMpictureTypeLookup($WMpictureType) { 1657 static $lookup = null; 1658 if ($lookup === null) { 1659 $lookup = array( 1660 0x03 => 'Front Cover', 1661 0x04 => 'Back Cover', 1662 0x00 => 'User Defined', 1663 0x05 => 'Leaflet Page', 1664 0x06 => 'Media Label', 1665 0x07 => 'Lead Artist', 1666 0x08 => 'Artist', 1667 0x09 => 'Conductor', 1668 0x0A => 'Band', 1669 0x0B => 'Composer', 1670 0x0C => 'Lyricist', 1671 0x0D => 'Recording Location', 1672 0x0E => 'During Recording', 1673 0x0F => 'During Performance', 1674 0x10 => 'Video Screen Capture', 1675 0x12 => 'Illustration', 1676 0x13 => 'Band Logotype', 1677 0x14 => 'Publisher Logotype' 1678 ); 1679 $lookup = array_map(function($str) { 1680 return getid3_lib::iconv_fallback('UTF-8', 'UTF-16LE', $str); 1681 }, $lookup); 1682 } 1683 1684 return (isset($lookup[$WMpictureType]) ? $lookup[$WMpictureType] : ''); 1685 } 1686 1687 public function HeaderExtensionObjectDataParse(&$asf_header_extension_object_data, &$unhandled_sections) { 1688 // http://msdn.microsoft.com/en-us/library/bb643323.aspx 1689 1690 $offset = 0; 1691 $objectOffset = 0; 1692 $HeaderExtensionObjectParsed = array(); 1693 while ($objectOffset < strlen($asf_header_extension_object_data)) { 1694 $offset = $objectOffset; 1695 $thisObject = array(); 1696 1697 $thisObject['guid'] = substr($asf_header_extension_object_data, $offset, 16); 1698 $offset += 16; 1699 $thisObject['guid_text'] = $this->BytestringToGUID($thisObject['guid']); 1700 $thisObject['guid_name'] = $this->GUIDname($thisObject['guid_text']); 1701 1702 $thisObject['size'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 8)); 1703 $offset += 8; 1704 if ($thisObject['size'] <= 0) { 1705 break; 1706 } 1707 1708 switch ($thisObject['guid']) { 1709 case GETID3_ASF_Extended_Stream_Properties_Object: 1710 $thisObject['start_time'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 8)); 1711 $offset += 8; 1712 $thisObject['start_time_unix'] = $this->FILETIMEtoUNIXtime($thisObject['start_time']); 1713 1714 $thisObject['end_time'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 8)); 1715 $offset += 8; 1716 $thisObject['end_time_unix'] = $this->FILETIMEtoUNIXtime($thisObject['end_time']); 1717 1718 $thisObject['data_bitrate'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); 1719 $offset += 4; 1720 1721 $thisObject['buffer_size'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); 1722 $offset += 4; 1723 1724 $thisObject['initial_buffer_fullness'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); 1725 $offset += 4; 1726 1727 $thisObject['alternate_data_bitrate'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); 1728 $offset += 4; 1729 1730 $thisObject['alternate_buffer_size'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); 1731 $offset += 4; 1732 1733 $thisObject['alternate_initial_buffer_fullness'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); 1734 $offset += 4; 1735 1736 $thisObject['maximum_object_size'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); 1737 $offset += 4; 1738 1739 $thisObject['flags_raw'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); 1740 $offset += 4; 1741 $thisObject['flags']['reliable'] = (bool) $thisObject['flags_raw'] & 0x00000001; 1742 $thisObject['flags']['seekable'] = (bool) $thisObject['flags_raw'] & 0x00000002; 1743 $thisObject['flags']['no_cleanpoints'] = (bool) $thisObject['flags_raw'] & 0x00000004; 1744 $thisObject['flags']['resend_live_cleanpoints'] = (bool) $thisObject['flags_raw'] & 0x00000008; 1745 1746 $thisObject['stream_number'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); 1747 $offset += 2; 1748 1749 $thisObject['stream_language_id_index'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); 1750 $offset += 2; 1751 1752 $thisObject['average_time_per_frame'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); 1753 $offset += 4; 1754 1755 $thisObject['stream_name_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); 1756 $offset += 2; 1757 1758 $thisObject['payload_extension_system_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); 1759 $offset += 2; 1760 1761 for ($i = 0; $i < $thisObject['stream_name_count']; $i++) { 1762 $streamName = array(); 1763 1764 $streamName['language_id_index'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); 1765 $offset += 2; 1766 1767 $streamName['stream_name_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); 1768 $offset += 2; 1769 1770 $streamName['stream_name'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, $streamName['stream_name_length'])); 1771 $offset += $streamName['stream_name_length']; 1772 1773 $thisObject['stream_names'][$i] = $streamName; 1774 } 1775 1776 for ($i = 0; $i < $thisObject['payload_extension_system_count']; $i++) { 1777 $payloadExtensionSystem = array(); 1778 1779 $payloadExtensionSystem['extension_system_id'] = substr($asf_header_extension_object_data, $offset, 16); 1780 $offset += 16; 1781 $payloadExtensionSystem['extension_system_id_text'] = $this->BytestringToGUID($payloadExtensionSystem['extension_system_id']); 1782 1783 $payloadExtensionSystem['extension_system_size'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); 1784 $offset += 2; 1785 if ($payloadExtensionSystem['extension_system_size'] <= 0) { 1786 break 2; 1787 } 1788 1789 $payloadExtensionSystem['extension_system_info_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); 1790 $offset += 4; 1791 1792 $payloadExtensionSystem['extension_system_info_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, $payloadExtensionSystem['extension_system_info_length'])); 1793 $offset += $payloadExtensionSystem['extension_system_info_length']; 1794 1795 $thisObject['payload_extension_systems'][$i] = $payloadExtensionSystem; 1796 } 1797 1798 break; 1799 1800 case GETID3_ASF_Padding_Object: 1801 // padding, skip it 1802 break; 1803 1804 case GETID3_ASF_Metadata_Object: 1805 $thisObject['description_record_counts'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); 1806 $offset += 2; 1807 1808 for ($i = 0; $i < $thisObject['description_record_counts']; $i++) { 1809 $descriptionRecord = array(); 1810 1811 $descriptionRecord['reserved_1'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); // must be zero 1812 $offset += 2; 1813 1814 $descriptionRecord['stream_number'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); 1815 $offset += 2; 1816 1817 $descriptionRecord['name_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); 1818 $offset += 2; 1819 1820 $descriptionRecord['data_type'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); 1821 $offset += 2; 1822 $descriptionRecord['data_type_text'] = self::metadataLibraryObjectDataTypeLookup($descriptionRecord['data_type']); 1823 1824 $descriptionRecord['data_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); 1825 $offset += 4; 1826 1827 $descriptionRecord['name'] = substr($asf_header_extension_object_data, $offset, $descriptionRecord['name_length']); 1828 $offset += $descriptionRecord['name_length']; 1829 1830 $descriptionRecord['data'] = substr($asf_header_extension_object_data, $offset, $descriptionRecord['data_length']); 1831 $offset += $descriptionRecord['data_length']; 1832 switch ($descriptionRecord['data_type']) { 1833 case 0x0000: // Unicode string 1834 break; 1835 1836 case 0x0001: // BYTE array 1837 // do nothing 1838 break; 1839 1840 case 0x0002: // BOOL 1841 $descriptionRecord['data'] = (bool) getid3_lib::LittleEndian2Int($descriptionRecord['data']); 1842 break; 1843 1844 case 0x0003: // DWORD 1845 case 0x0004: // QWORD 1846 case 0x0005: // WORD 1847 $descriptionRecord['data'] = getid3_lib::LittleEndian2Int($descriptionRecord['data']); 1848 break; 1849 1850 case 0x0006: // GUID 1851 $descriptionRecord['data_text'] = $this->BytestringToGUID($descriptionRecord['data']); 1852 break; 1853 } 1854 1855 $thisObject['description_record'][$i] = $descriptionRecord; 1856 } 1857 break; 1858 1859 case GETID3_ASF_Language_List_Object: 1860 $thisObject['language_id_record_counts'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); 1861 $offset += 2; 1862 1863 for ($i = 0; $i < $thisObject['language_id_record_counts']; $i++) { 1864 $languageIDrecord = array(); 1865 1866 $languageIDrecord['language_id_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 1)); 1867 $offset += 1; 1868 1869 $languageIDrecord['language_id'] = substr($asf_header_extension_object_data, $offset, $languageIDrecord['language_id_length']); 1870 $offset += $languageIDrecord['language_id_length']; 1871 1872 $thisObject['language_id_record'][$i] = $languageIDrecord; 1873 } 1874 break; 1875 1876 case GETID3_ASF_Metadata_Library_Object: 1877 $thisObject['description_records_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); 1878 $offset += 2; 1879 1880 for ($i = 0; $i < $thisObject['description_records_count']; $i++) { 1881 $descriptionRecord = array(); 1882 1883 $descriptionRecord['language_list_index'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); 1884 $offset += 2; 1885 1886 $descriptionRecord['stream_number'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); 1887 $offset += 2; 1888 1889 $descriptionRecord['name_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); 1890 $offset += 2; 1891 1892 $descriptionRecord['data_type'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); 1893 $offset += 2; 1894 $descriptionRecord['data_type_text'] = self::metadataLibraryObjectDataTypeLookup($descriptionRecord['data_type']); 1895 1896 $descriptionRecord['data_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); 1897 $offset += 4; 1898 1899 $descriptionRecord['name'] = substr($asf_header_extension_object_data, $offset, $descriptionRecord['name_length']); 1900 $offset += $descriptionRecord['name_length']; 1901 1902 $descriptionRecord['data'] = substr($asf_header_extension_object_data, $offset, $descriptionRecord['data_length']); 1903 $offset += $descriptionRecord['data_length']; 1904 1905 if (preg_match('#^WM/Picture$#', str_replace("\x00", '', trim($descriptionRecord['name'])))) { 1906 $WMpicture = $this->ASF_WMpicture($descriptionRecord['data']); 1907 foreach ($WMpicture as $key => $value) { 1908 $descriptionRecord['data'] = $WMpicture; 1909 } 1910 unset($WMpicture); 1911 } 1912 1913 $thisObject['description_record'][$i] = $descriptionRecord; 1914 } 1915 break; 1916 1917 default: 1918 $unhandled_sections++; 1919 if ($this->GUIDname($thisObject['guid_text'])) { 1920 $this->getid3->info['warning'][] = 'unhandled Header Extension Object GUID "'.$this->GUIDname($thisObject['guid_text']).'" {'.$thisObject['guid_text'].'} at offset '.($offset - 16 - 8); 1921 } else { 1922 $this->getid3->info['warning'][] = 'unknown Header Extension Object GUID {'.$thisObject['guid_text'].'} in at offset '.($offset - 16 - 8); 1923 } 1924 break; 1925 } 1926 $HeaderExtensionObjectParsed[] = $thisObject; 1927 1928 $objectOffset += $thisObject['size']; 1929 } 1930 return $HeaderExtensionObjectParsed; 1931 } 1932 1933 1934 public static function metadataLibraryObjectDataTypeLookup($id) { 1935 static $lookup = array( 1936 0x0000 => 'Unicode string', // The data consists of a sequence of Unicode characters 1937 0x0001 => 'BYTE array', // The type of the data is implementation-specific 1938 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 1939 0x0003 => 'DWORD', // The data is 4 bytes long and should be interpreted as a 32-bit unsigned integer 1940 0x0004 => 'QWORD', // The data is 8 bytes long and should be interpreted as a 64-bit unsigned integer 1941 0x0005 => 'WORD', // The data is 2 bytes long and should be interpreted as a 16-bit unsigned integer 1942 0x0006 => 'GUID', // The data is 16 bytes long and should be interpreted as a 128-bit GUID 1943 ); 1944 return (isset($lookup[$id]) ? $lookup[$id] : 'invalid'); 1945 } 1946 1947 public function ASF_WMpicture(&$data) { 1948 //typedef struct _WMPicture{ 1949 // LPWSTR pwszMIMEType; 1950 // BYTE bPictureType; 1951 // LPWSTR pwszDescription; 1952 // DWORD dwDataLen; 1953 // BYTE* pbData; 1954 //} WM_PICTURE; 1955 1956 $WMpicture = array(); 1957 1958 $offset = 0; 1959 $WMpicture['image_type_id'] = getid3_lib::LittleEndian2Int(substr($data, $offset, 1)); 1960 $offset += 1; 1961 $WMpicture['image_type'] = self::WMpictureTypeLookup($WMpicture['image_type_id']); 1962 $WMpicture['image_size'] = getid3_lib::LittleEndian2Int(substr($data, $offset, 4)); 1963 $offset += 4; 1964 1965 $WMpicture['image_mime'] = ''; 1966 do { 1967 $next_byte_pair = substr($data, $offset, 2); 1968 $offset += 2; 1969 $WMpicture['image_mime'] .= $next_byte_pair; 1970 } while ($next_byte_pair !== "\x00\x00"); 1971 1972 $WMpicture['image_description'] = ''; 1973 do { 1974 $next_byte_pair = substr($data, $offset, 2); 1975 $offset += 2; 1976 $WMpicture['image_description'] .= $next_byte_pair; 1977 } while ($next_byte_pair !== "\x00\x00"); 1978 1979 $WMpicture['dataoffset'] = $offset; 1980 $WMpicture['data'] = substr($data, $offset); 1981 1982 $imageinfo = array(); 1983 $WMpicture['image_mime'] = ''; 1984 $imagechunkcheck = getid3_lib::GetDataImageSize($WMpicture['data'], $imageinfo); 1985 unset($imageinfo); 1986 if (!empty($imagechunkcheck)) { 1987 $WMpicture['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]); 1988 } 1989 if (!isset($this->getid3->info['asf']['comments']['picture'])) { 1990 $this->getid3->info['asf']['comments']['picture'] = array(); 1991 } 1992 $this->getid3->info['asf']['comments']['picture'][] = array('data'=>$WMpicture['data'], 'image_mime'=>$WMpicture['image_mime']); 1993 1994 return $WMpicture; 1995 } 1996 1997 1998 // Remove terminator 00 00 and convert UTF-16LE to Latin-1 1999 public static function TrimConvert($string) { 2000 return trim(getid3_lib::iconv_fallback('UTF-16LE', 'ISO-8859-1', self::TrimTerm($string)), ' '); 2001 } 2002 2003 2004 // Remove terminator 00 00 2005 public static function TrimTerm($string) { 2006 // remove terminator, only if present (it should be, but...) 2007 if (substr($string, -2) === "\x00\x00") { 2008 $string = substr($string, 0, -2); 2009 } 2010 return $string; 2011 } 2012 2013 }