PageRenderTime 63ms CodeModel.GetById 19ms app.highlight 32ms RepoModel.GetById 1ms app.codeStats 1ms

/wp-includes/ID3/module.audio-video.asf.php

https://bitbucket.org/skyarch-iijima/wordpress
PHP | 2013 lines | 1371 code | 274 blank | 368 comment | 132 complexity | 0a250d84a4380f86fa833b65d67d79f3 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1<?php
  2/////////////////////////////////////////////////////////////////
  3/// getID3() by James Heinrich <info@getid3.org>               //
  4//  available at http://getid3.sourceforge.net                 //
  5//            or http://www.getid3.org                         //
  6//          also https://github.com/JamesHeinrich/getID3       //
  7/////////////////////////////////////////////////////////////////
  8// See readme.txt for more details                             //
  9/////////////////////////////////////////////////////////////////
 10//                                                             //
 11// module.audio-video.asf.php                                  //
 12// module for analyzing ASF, WMA and WMV files                 //
 13// dependencies: module.audio-video.riff.php                   //
 14//                                                            ///
 15/////////////////////////////////////////////////////////////////
 16
 17getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
 18
 19class getid3_asf extends getid3_handler {
 20
 21	public function __construct(getID3 $getid3) {
 22		parent::__construct($getid3);  // extends getid3_handler::__construct()
 23
 24		// initialize all GUID constants
 25		$GUIDarray = $this->KnownGUIDs();
 26		foreach ($GUIDarray as $GUIDname => $hexstringvalue) {
 27			if (!defined($GUIDname)) {
 28				define($GUIDname, $this->GUIDtoBytestring($hexstringvalue));
 29			}
 30		}
 31	}
 32
 33	public function Analyze() {
 34		$info = &$this->getid3->info;
 35
 36		// Shortcuts
 37		$thisfile_audio = &$info['audio'];
 38		$thisfile_video = &$info['video'];
 39		$info['asf']  = array();
 40		$thisfile_asf = &$info['asf'];
 41		$thisfile_asf['comments'] = array();
 42		$thisfile_asf_comments    = &$thisfile_asf['comments'];
 43		$thisfile_asf['header_object'] = array();
 44		$thisfile_asf_headerobject     = &$thisfile_asf['header_object'];
 45
 46
 47		// ASF structure:
 48		// * Header Object [required]
 49		//   * File Properties Object [required]   (global file attributes)
 50		//   * Stream Properties Object [required] (defines media stream & characteristics)
 51		//   * Header Extension Object [required]  (additional functionality)
 52		//   * Content Description Object          (bibliographic information)
 53		//   * Script Command Object               (commands for during playback)
 54		//   * Marker Object                       (named jumped points within the file)
 55		// * Data Object [required]
 56		//   * Data Packets
 57		// * Index Object
 58
 59		// Header Object: (mandatory, one only)
 60		// Field Name                   Field Type   Size (bits)
 61		// Object ID                    GUID         128             // GUID for header object - GETID3_ASF_Header_Object
 62		// Object Size                  QWORD        64              // size of header object, including 30 bytes of Header Object header
 63		// Number of Header Objects     DWORD        32              // number of objects in header object
 64		// Reserved1                    BYTE         8               // hardcoded: 0x01
 65		// Reserved2                    BYTE         8               // hardcoded: 0x02
 66
 67		$info['fileformat'] = 'asf';
 68
 69		$this->fseek($info['avdataoffset']);
 70		$HeaderObjectData = $this->fread(30);
 71
 72		$thisfile_asf_headerobject['objectid']      = substr($HeaderObjectData, 0, 16);
 73		$thisfile_asf_headerobject['objectid_guid'] = $this->BytestringToGUID($thisfile_asf_headerobject['objectid']);
 74		if ($thisfile_asf_headerobject['objectid'] != GETID3_ASF_Header_Object) {
 75			unset($info['fileformat'], $info['asf']);
 76			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).'}');
 77		}
 78		$thisfile_asf_headerobject['objectsize']    = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 16, 8));
 79		$thisfile_asf_headerobject['headerobjects'] = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 24, 4));
 80		$thisfile_asf_headerobject['reserved1']     = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 28, 1));
 81		$thisfile_asf_headerobject['reserved2']     = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 29, 1));
 82
 83		$NextObjectOffset = $this->ftell();
 84		$ASFHeaderData = $this->fread($thisfile_asf_headerobject['objectsize'] - 30);
 85		$offset = 0;
 86
 87		for ($HeaderObjectsCounter = 0; $HeaderObjectsCounter < $thisfile_asf_headerobject['headerobjects']; $HeaderObjectsCounter++) {
 88			$NextObjectGUID = substr($ASFHeaderData, $offset, 16);
 89			$offset += 16;
 90			$NextObjectGUIDtext = $this->BytestringToGUID($NextObjectGUID);
 91			$NextObjectSize = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
 92			$offset += 8;
 93			switch ($NextObjectGUID) {
 94
 95				case GETID3_ASF_File_Properties_Object:
 96					// File Properties Object: (mandatory, one only)
 97					// Field Name                   Field Type   Size (bits)
 98					// Object ID                    GUID         128             // GUID for file properties object - GETID3_ASF_File_Properties_Object
 99					// Object Size                  QWORD        64              // size of file properties object, including 104 bytes of File Properties Object header
100					// File ID                      GUID         128             // unique ID - identical to File ID in Data Object
101					// File Size                    QWORD        64              // entire file in bytes. Invalid if Broadcast Flag == 1
102					// Creation Date                QWORD        64              // date & time of file creation. Maybe invalid if Broadcast Flag == 1
103					// Data Packets Count           QWORD        64              // number of data packets in Data Object. Invalid if Broadcast Flag == 1
104					// Play Duration                QWORD        64              // playtime, in 100-nanosecond units. Invalid if Broadcast Flag == 1
105					// Send Duration                QWORD        64              // time needed to send file, in 100-nanosecond units. Players can ignore this value. Invalid if Broadcast Flag == 1
106					// 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
107					// Flags                        DWORD        32              //
108					// * Broadcast Flag             bits         1  (0x01)       // file is currently being written, some header values are invalid
109					// * Seekable Flag              bits         1  (0x02)       // is file seekable
110					// * Reserved                   bits         30 (0xFFFFFFFC) // reserved - set to zero
111					// Minimum Data Packet Size     DWORD        32              // in bytes. should be same as Maximum Data Packet Size. Invalid if Broadcast Flag == 1
112					// Maximum Data Packet Size     DWORD        32              // in bytes. should be same as Minimum Data Packet Size. Invalid if Broadcast Flag == 1
113					// Maximum Bitrate              DWORD        32              // maximum instantaneous bitrate in bits per second for entire file, including all data streams and ASF overhead
114
115					// shortcut
116					$thisfile_asf['file_properties_object'] = array();
117					$thisfile_asf_filepropertiesobject      = &$thisfile_asf['file_properties_object'];
118
119					$thisfile_asf_filepropertiesobject['offset']             = $NextObjectOffset + $offset;
120					$thisfile_asf_filepropertiesobject['objectid']           = $NextObjectGUID;
121					$thisfile_asf_filepropertiesobject['objectid_guid']      = $NextObjectGUIDtext;
122					$thisfile_asf_filepropertiesobject['objectsize']         = $NextObjectSize;
123					$thisfile_asf_filepropertiesobject['fileid']             = substr($ASFHeaderData, $offset, 16);
124					$offset += 16;
125					$thisfile_asf_filepropertiesobject['fileid_guid']        = $this->BytestringToGUID($thisfile_asf_filepropertiesobject['fileid']);
126					$thisfile_asf_filepropertiesobject['filesize']           = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
127					$offset += 8;
128					$thisfile_asf_filepropertiesobject['creation_date']      = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
129					$thisfile_asf_filepropertiesobject['creation_date_unix'] = $this->FILETIMEtoUNIXtime($thisfile_asf_filepropertiesobject['creation_date']);
130					$offset += 8;
131					$thisfile_asf_filepropertiesobject['data_packets']       = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
132					$offset += 8;
133					$thisfile_asf_filepropertiesobject['play_duration']      = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
134					$offset += 8;
135					$thisfile_asf_filepropertiesobject['send_duration']      = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
136					$offset += 8;
137					$thisfile_asf_filepropertiesobject['preroll']            = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
138					$offset += 8;
139					$thisfile_asf_filepropertiesobject['flags_raw']          = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
140					$offset += 4;
141					$thisfile_asf_filepropertiesobject['flags']['broadcast'] = (bool) ($thisfile_asf_filepropertiesobject['flags_raw'] & 0x0001);
142					$thisfile_asf_filepropertiesobject['flags']['seekable']  = (bool) ($thisfile_asf_filepropertiesobject['flags_raw'] & 0x0002);
143
144					$thisfile_asf_filepropertiesobject['min_packet_size']    = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
145					$offset += 4;
146					$thisfile_asf_filepropertiesobject['max_packet_size']    = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
147					$offset += 4;
148					$thisfile_asf_filepropertiesobject['max_bitrate']        = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
149					$offset += 4;
150
151					if ($thisfile_asf_filepropertiesobject['flags']['broadcast']) {
152
153						// broadcast flag is set, some values invalid
154						unset($thisfile_asf_filepropertiesobject['filesize']);
155						unset($thisfile_asf_filepropertiesobject['data_packets']);
156						unset($thisfile_asf_filepropertiesobject['play_duration']);
157						unset($thisfile_asf_filepropertiesobject['send_duration']);
158						unset($thisfile_asf_filepropertiesobject['min_packet_size']);
159						unset($thisfile_asf_filepropertiesobject['max_packet_size']);
160
161					} else {
162
163						// broadcast flag NOT set, perform calculations
164						$info['playtime_seconds'] = ($thisfile_asf_filepropertiesobject['play_duration'] / 10000000) - ($thisfile_asf_filepropertiesobject['preroll'] / 1000);
165
166						//$info['bitrate'] = $thisfile_asf_filepropertiesobject['max_bitrate'];
167						$info['bitrate'] = ((isset($thisfile_asf_filepropertiesobject['filesize']) ? $thisfile_asf_filepropertiesobject['filesize'] : $info['filesize']) * 8) / $info['playtime_seconds'];
168					}
169					break;
170
171				case GETID3_ASF_Stream_Properties_Object:
172					// Stream Properties Object: (mandatory, one per media stream)
173					// Field Name                   Field Type   Size (bits)
174					// Object ID                    GUID         128             // GUID for stream properties object - GETID3_ASF_Stream_Properties_Object
175					// Object Size                  QWORD        64              // size of stream properties object, including 78 bytes of Stream Properties Object header
176					// Stream Type                  GUID         128             // GETID3_ASF_Audio_Media, GETID3_ASF_Video_Media or GETID3_ASF_Command_Media
177					// Error Correction Type        GUID         128             // GETID3_ASF_Audio_Spread for audio-only streams, GETID3_ASF_No_Error_Correction for other stream types
178					// Time Offset                  QWORD        64              // 100-nanosecond units. typically zero. added to all timestamps of samples in the stream
179					// Type-Specific Data Length    DWORD        32              // number of bytes for Type-Specific Data field
180					// Error Correction Data Length DWORD        32              // number of bytes for Error Correction Data field
181					// Flags                        WORD         16              //
182					// * Stream Number              bits         7 (0x007F)      // number of this stream.  1 <= valid <= 127
183					// * Reserved                   bits         8 (0x7F80)      // reserved - set to zero
184					// * Encrypted Content Flag     bits         1 (0x8000)      // stream contents encrypted if set
185					// Reserved                     DWORD        32              // reserved - set to zero
186					// Type-Specific Data           BYTESTREAM   variable        // type-specific format data, depending on value of Stream Type
187					// Error Correction Data        BYTESTREAM   variable        // error-correction-specific format data, depending on value of Error Correct Type
188
189					// There is one GETID3_ASF_Stream_Properties_Object for each stream (audio, video) but the
190					// stream number isn't known until halfway through decoding the structure, hence it
191					// it is decoded to a temporary variable and then stuck in the appropriate index later
192
193					$StreamPropertiesObjectData['offset']             = $NextObjectOffset + $offset;
194					$StreamPropertiesObjectData['objectid']           = $NextObjectGUID;
195					$StreamPropertiesObjectData['objectid_guid']      = $NextObjectGUIDtext;
196					$StreamPropertiesObjectData['objectsize']         = $NextObjectSize;
197					$StreamPropertiesObjectData['stream_type']        = substr($ASFHeaderData, $offset, 16);
198					$offset += 16;
199					$StreamPropertiesObjectData['stream_type_guid']   = $this->BytestringToGUID($StreamPropertiesObjectData['stream_type']);
200					$StreamPropertiesObjectData['error_correct_type'] = substr($ASFHeaderData, $offset, 16);
201					$offset += 16;
202					$StreamPropertiesObjectData['error_correct_guid'] = $this->BytestringToGUID($StreamPropertiesObjectData['error_correct_type']);
203					$StreamPropertiesObjectData['time_offset']        = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
204					$offset += 8;
205					$StreamPropertiesObjectData['type_data_length']   = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
206					$offset += 4;
207					$StreamPropertiesObjectData['error_data_length']  = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
208					$offset += 4;
209					$StreamPropertiesObjectData['flags_raw']          = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
210					$offset += 2;
211					$StreamPropertiesObjectStreamNumber               = $StreamPropertiesObjectData['flags_raw'] & 0x007F;
212					$StreamPropertiesObjectData['flags']['encrypted'] = (bool) ($StreamPropertiesObjectData['flags_raw'] & 0x8000);
213
214					$offset += 4; // reserved - DWORD
215					$StreamPropertiesObjectData['type_specific_data'] = substr($ASFHeaderData, $offset, $StreamPropertiesObjectData['type_data_length']);
216					$offset += $StreamPropertiesObjectData['type_data_length'];
217					$StreamPropertiesObjectData['error_correct_data'] = substr($ASFHeaderData, $offset, $StreamPropertiesObjectData['error_data_length']);
218					$offset += $StreamPropertiesObjectData['error_data_length'];
219
220					switch ($StreamPropertiesObjectData['stream_type']) {
221
222						case GETID3_ASF_Audio_Media:
223							$thisfile_audio['dataformat']   = (!empty($thisfile_audio['dataformat'])   ? $thisfile_audio['dataformat']   : 'asf');
224							$thisfile_audio['bitrate_mode'] = (!empty($thisfile_audio['bitrate_mode']) ? $thisfile_audio['bitrate_mode'] : 'cbr');
225
226							$audiodata = getid3_riff::parseWAVEFORMATex(substr($StreamPropertiesObjectData['type_specific_data'], 0, 16));
227							unset($audiodata['raw']);
228							$thisfile_audio = getid3_lib::array_merge_noclobber($audiodata, $thisfile_audio);
229							break;
230
231						case GETID3_ASF_Video_Media:
232							$thisfile_video['dataformat']   = (!empty($thisfile_video['dataformat'])   ? $thisfile_video['dataformat']   : 'asf');
233							$thisfile_video['bitrate_mode'] = (!empty($thisfile_video['bitrate_mode']) ? $thisfile_video['bitrate_mode'] : 'cbr');
234							break;
235
236						case GETID3_ASF_Command_Media:
237						default:
238							// do nothing
239							break;
240
241					}
242
243					$thisfile_asf['stream_properties_object'][$StreamPropertiesObjectStreamNumber] = $StreamPropertiesObjectData;
244					unset($StreamPropertiesObjectData); // clear for next stream, if any
245					break;
246
247				case GETID3_ASF_Header_Extension_Object:
248					// Header Extension Object: (mandatory, one only)
249					// Field Name                   Field Type   Size (bits)
250					// Object ID                    GUID         128             // GUID for Header Extension object - GETID3_ASF_Header_Extension_Object
251					// Object Size                  QWORD        64              // size of Header Extension object, including 46 bytes of Header Extension Object header
252					// Reserved Field 1             GUID         128             // hardcoded: GETID3_ASF_Reserved_1
253					// Reserved Field 2             WORD         16              // hardcoded: 0x00000006
254					// Header Extension Data Size   DWORD        32              // in bytes. valid: 0, or > 24. equals object size minus 46
255					// Header Extension Data        BYTESTREAM   variable        // array of zero or more extended header objects
256
257					// shortcut
258					$thisfile_asf['header_extension_object'] = array();
259					$thisfile_asf_headerextensionobject      = &$thisfile_asf['header_extension_object'];
260
261					$thisfile_asf_headerextensionobject['offset']              = $NextObjectOffset + $offset;
262					$thisfile_asf_headerextensionobject['objectid']            = $NextObjectGUID;
263					$thisfile_asf_headerextensionobject['objectid_guid']       = $NextObjectGUIDtext;
264					$thisfile_asf_headerextensionobject['objectsize']          = $NextObjectSize;
265					$thisfile_asf_headerextensionobject['reserved_1']          = substr($ASFHeaderData, $offset, 16);
266					$offset += 16;
267					$thisfile_asf_headerextensionobject['reserved_1_guid']     = $this->BytestringToGUID($thisfile_asf_headerextensionobject['reserved_1']);
268					if ($thisfile_asf_headerextensionobject['reserved_1'] != GETID3_ASF_Reserved_1) {
269						$this->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).')');
270						//return false;
271						break;
272					}
273					$thisfile_asf_headerextensionobject['reserved_2']          = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
274					$offset += 2;
275					if ($thisfile_asf_headerextensionobject['reserved_2'] != 6) {
276						$this->warning('header_extension_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_headerextensionobject['reserved_2']).') does not match expected value of "6"');
277						//return false;
278						break;
279					}
280					$thisfile_asf_headerextensionobject['extension_data_size'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
281					$offset += 4;
282					$thisfile_asf_headerextensionobject['extension_data']      =                              substr($ASFHeaderData, $offset, $thisfile_asf_headerextensionobject['extension_data_size']);
283					$unhandled_sections = 0;
284					$thisfile_asf_headerextensionobject['extension_data_parsed'] = $this->HeaderExtensionObjectDataParse($thisfile_asf_headerextensionobject['extension_data'], $unhandled_sections);
285					if ($unhandled_sections === 0) {
286						unset($thisfile_asf_headerextensionobject['extension_data']);
287					}
288					$offset += $thisfile_asf_headerextensionobject['extension_data_size'];
289					break;
290
291				case GETID3_ASF_Codec_List_Object:
292					// Codec List Object: (optional, one only)
293					// Field Name                   Field Type   Size (bits)
294					// Object ID                    GUID         128             // GUID for Codec List object - GETID3_ASF_Codec_List_Object
295					// Object Size                  QWORD        64              // size of Codec List object, including 44 bytes of Codec List Object header
296					// Reserved                     GUID         128             // hardcoded: 86D15241-311D-11D0-A3A4-00A0C90348F6
297					// Codec Entries Count          DWORD        32              // number of entries in Codec Entries array
298					// Codec Entries                array of:    variable        //
299					// * Type                       WORD         16              // 0x0001 = Video Codec, 0x0002 = Audio Codec, 0xFFFF = Unknown Codec
300					// * Codec Name Length          WORD         16              // number of Unicode characters stored in the Codec Name field
301					// * Codec Name                 WCHAR        variable        // array of Unicode characters - name of codec used to create the content
302					// * Codec Description Length   WORD         16              // number of Unicode characters stored in the Codec Description field
303					// * Codec Description          WCHAR        variable        // array of Unicode characters - description of format used to create the content
304					// * Codec Information Length   WORD         16              // number of Unicode characters stored in the Codec Information field
305					// * Codec Information          BYTESTREAM   variable        // opaque array of information bytes about the codec used to create the content
306
307					// shortcut
308					$thisfile_asf['codec_list_object'] = array();
309					$thisfile_asf_codeclistobject      = &$thisfile_asf['codec_list_object'];
310
311					$thisfile_asf_codeclistobject['offset']                    = $NextObjectOffset + $offset;
312					$thisfile_asf_codeclistobject['objectid']                  = $NextObjectGUID;
313					$thisfile_asf_codeclistobject['objectid_guid']             = $NextObjectGUIDtext;
314					$thisfile_asf_codeclistobject['objectsize']                = $NextObjectSize;
315					$thisfile_asf_codeclistobject['reserved']                  = substr($ASFHeaderData, $offset, 16);
316					$offset += 16;
317					$thisfile_asf_codeclistobject['reserved_guid']             = $this->BytestringToGUID($thisfile_asf_codeclistobject['reserved']);
318					if ($thisfile_asf_codeclistobject['reserved'] != $this->GUIDtoBytestring('86D15241-311D-11D0-A3A4-00A0C90348F6')) {
319						$this->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}');
320						//return false;
321						break;
322					}
323					$thisfile_asf_codeclistobject['codec_entries_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
324					$offset += 4;
325					for ($CodecEntryCounter = 0; $CodecEntryCounter < $thisfile_asf_codeclistobject['codec_entries_count']; $CodecEntryCounter++) {
326						// shortcut
327						$thisfile_asf_codeclistobject['codec_entries'][$CodecEntryCounter] = array();
328						$thisfile_asf_codeclistobject_codecentries_current = &$thisfile_asf_codeclistobject['codec_entries'][$CodecEntryCounter];
329
330						$thisfile_asf_codeclistobject_codecentries_current['type_raw'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
331						$offset += 2;
332						$thisfile_asf_codeclistobject_codecentries_current['type'] = self::codecListObjectTypeLookup($thisfile_asf_codeclistobject_codecentries_current['type_raw']);
333
334						$CodecNameLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character
335						$offset += 2;
336						$thisfile_asf_codeclistobject_codecentries_current['name'] = substr($ASFHeaderData, $offset, $CodecNameLength);
337						$offset += $CodecNameLength;
338
339						$CodecDescriptionLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character
340						$offset += 2;
341						$thisfile_asf_codeclistobject_codecentries_current['description'] = substr($ASFHeaderData, $offset, $CodecDescriptionLength);
342						$offset += $CodecDescriptionLength;
343
344						$CodecInformationLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
345						$offset += 2;
346						$thisfile_asf_codeclistobject_codecentries_current['information'] = substr($ASFHeaderData, $offset, $CodecInformationLength);
347						$offset += $CodecInformationLength;
348
349						if ($thisfile_asf_codeclistobject_codecentries_current['type_raw'] == 2) { // audio codec
350
351							if (strpos($thisfile_asf_codeclistobject_codecentries_current['description'], ',') === false) {
352								$this->warning('[asf][codec_list_object][codec_entries]['.$CodecEntryCounter.'][description] expected to contain comma-separated list of parameters: "'.$thisfile_asf_codeclistobject_codecentries_current['description'].'"');
353							} else {
354
355								list($AudioCodecBitrate, $AudioCodecFrequency, $AudioCodecChannels) = explode(',', $this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['description']));
356								$thisfile_audio['codec'] = $this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['name']);
357
358								if (!isset($thisfile_audio['bitrate']) && strstr($AudioCodecBitrate, 'kbps')) {
359									$thisfile_audio['bitrate'] = (int) (trim(str_replace('kbps', '', $AudioCodecBitrate)) * 1000);
360								}
361								//if (!isset($thisfile_video['bitrate']) && isset($thisfile_audio['bitrate']) && isset($thisfile_asf['file_properties_object']['max_bitrate']) && ($thisfile_asf_codeclistobject['codec_entries_count'] > 1)) {
362								if (empty($thisfile_video['bitrate']) && !empty($thisfile_audio['bitrate']) && !empty($info['bitrate'])) {
363									//$thisfile_video['bitrate'] = $thisfile_asf['file_properties_object']['max_bitrate'] - $thisfile_audio['bitrate'];
364									$thisfile_video['bitrate'] = $info['bitrate'] - $thisfile_audio['bitrate'];
365								}
366
367								$AudioCodecFrequency = (int) trim(str_replace('kHz', '', $AudioCodecFrequency));
368								switch ($AudioCodecFrequency) {
369									case 8:
370									case 8000:
371										$thisfile_audio['sample_rate'] = 8000;
372										break;
373
374									case 11:
375									case 11025:
376										$thisfile_audio['sample_rate'] = 11025;
377										break;
378
379									case 12:
380									case 12000:
381										$thisfile_audio['sample_rate'] = 12000;
382										break;
383
384									case 16:
385									case 16000:
386										$thisfile_audio['sample_rate'] = 16000;
387										break;
388
389									case 22:
390									case 22050:
391										$thisfile_audio['sample_rate'] = 22050;
392										break;
393
394									case 24:
395									case 24000:
396										$thisfile_audio['sample_rate'] = 24000;
397										break;
398
399									case 32:
400									case 32000:
401										$thisfile_audio['sample_rate'] = 32000;
402										break;
403
404									case 44:
405									case 441000:
406										$thisfile_audio['sample_rate'] = 44100;
407										break;
408
409									case 48:
410									case 48000:
411										$thisfile_audio['sample_rate'] = 48000;
412										break;
413
414									default:
415										$this->warning('unknown frequency: "'.$AudioCodecFrequency.'" ('.$this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['description']).')');
416										break;
417								}
418
419								if (!isset($thisfile_audio['channels'])) {
420									if (strstr($AudioCodecChannels, 'stereo')) {
421										$thisfile_audio['channels'] = 2;
422									} elseif (strstr($AudioCodecChannels, 'mono')) {
423										$thisfile_audio['channels'] = 1;
424									}
425								}
426
427							}
428						}
429					}
430					break;
431
432				case GETID3_ASF_Script_Command_Object:
433					// Script Command Object: (optional, one only)
434					// Field Name                   Field Type   Size (bits)
435					// Object ID                    GUID         128             // GUID for Script Command object - GETID3_ASF_Script_Command_Object
436					// Object Size                  QWORD        64              // size of Script Command object, including 44 bytes of Script Command Object header
437					// Reserved                     GUID         128             // hardcoded: 4B1ACBE3-100B-11D0-A39B-00A0C90348F6
438					// Commands Count               WORD         16              // number of Commands structures in the Script Commands Objects
439					// Command Types Count          WORD         16              // number of Command Types structures in the Script Commands Objects
440					// Command Types                array of:    variable        //
441					// * Command Type Name Length   WORD         16              // number of Unicode characters for Command Type Name
442					// * Command Type Name          WCHAR        variable        // array of Unicode characters - name of a type of command
443					// Commands                     array of:    variable        //
444					// * Presentation Time          DWORD        32              // presentation time of that command, in milliseconds
445					// * Type Index                 WORD         16              // type of this command, as a zero-based index into the array of Command Types of this object
446					// * Command Name Length        WORD         16              // number of Unicode characters for Command Name
447					// * Command Name               WCHAR        variable        // array of Unicode characters - name of this command
448
449					// shortcut
450					$thisfile_asf['script_command_object'] = array();
451					$thisfile_asf_scriptcommandobject      = &$thisfile_asf['script_command_object'];
452
453					$thisfile_asf_scriptcommandobject['offset']               = $NextObjectOffset + $offset;
454					$thisfile_asf_scriptcommandobject['objectid']             = $NextObjectGUID;
455					$thisfile_asf_scriptcommandobject['objectid_guid']        = $NextObjectGUIDtext;
456					$thisfile_asf_scriptcommandobject['objectsize']           = $NextObjectSize;
457					$thisfile_asf_scriptcommandobject['reserved']             = substr($ASFHeaderData, $offset, 16);
458					$offset += 16;
459					$thisfile_asf_scriptcommandobject['reserved_guid']        = $this->BytestringToGUID($thisfile_asf_scriptcommandobject['reserved']);
460					if ($thisfile_asf_scriptcommandobject['reserved'] != $this->GUIDtoBytestring('4B1ACBE3-100B-11D0-A39B-00A0C90348F6')) {
461						$this->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}');
462						//return false;
463						break;
464					}
465					$thisfile_asf_scriptcommandobject['commands_count']       = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
466					$offset += 2;
467					$thisfile_asf_scriptcommandobject['command_types_count']  = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
468					$offset += 2;
469					for ($CommandTypesCounter = 0; $CommandTypesCounter < $thisfile_asf_scriptcommandobject['command_types_count']; $CommandTypesCounter++) {
470						$CommandTypeNameLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character
471						$offset += 2;
472						$thisfile_asf_scriptcommandobject['command_types'][$CommandTypesCounter]['name'] = substr($ASFHeaderData, $offset, $CommandTypeNameLength);
473						$offset += $CommandTypeNameLength;
474					}
475					for ($CommandsCounter = 0; $CommandsCounter < $thisfile_asf_scriptcommandobject['commands_count']; $CommandsCounter++) {
476						$thisfile_asf_scriptcommandobject['commands'][$CommandsCounter]['presentation_time']  = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
477						$offset += 4;
478						$thisfile_asf_scriptcommandobject['commands'][$CommandsCounter]['type_index']         = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
479						$offset += 2;
480
481						$CommandTypeNameLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character
482						$offset += 2;
483						$thisfile_asf_scriptcommandobject['commands'][$CommandsCounter]['name'] = substr($ASFHeaderData, $offset, $CommandTypeNameLength);
484						$offset += $CommandTypeNameLength;
485					}
486					break;
487
488				case GETID3_ASF_Marker_Object:
489					// Marker Object: (optional, one only)
490					// Field Name                   Field Type   Size (bits)
491					// Object ID                    GUID         128             // GUID for Marker object - GETID3_ASF_Marker_Object
492					// Object Size                  QWORD        64              // size of Marker object, including 48 bytes of Marker Object header
493					// Reserved                     GUID         128             // hardcoded: 4CFEDB20-75F6-11CF-9C0F-00A0C90349CB
494					// Markers Count                DWORD        32              // number of Marker structures in Marker Object
495					// Reserved                     WORD         16              // hardcoded: 0x0000
496					// Name Length                  WORD         16              // number of bytes in the Name field
497					// Name                         WCHAR        variable        // name of the Marker Object
498					// Markers                      array of:    variable        //
499					// * Offset                     QWORD        64              // byte offset into Data Object
500					// * Presentation Time          QWORD        64              // in 100-nanosecond units
501					// * Entry Length               WORD         16              // length in bytes of (Send Time + Flags + Marker Description Length + Marker Description + Padding)
502					// * Send Time                  DWORD        32              // in milliseconds
503					// * Flags                      DWORD        32              // hardcoded: 0x00000000
504					// * Marker Description Length  DWORD        32              // number of bytes in Marker Description field
505					// * Marker Description         WCHAR        variable        // array of Unicode characters - description of marker entry
506					// * Padding                    BYTESTREAM   variable        // optional padding bytes
507
508					// shortcut
509					$thisfile_asf['marker_object'] = array();
510					$thisfile_asf_markerobject     = &$thisfile_asf['marker_object'];
511
512					$thisfile_asf_markerobject['offset']               = $NextObjectOffset + $offset;
513					$thisfile_asf_markerobject['objectid']             = $NextObjectGUID;
514					$thisfile_asf_markerobject['objectid_guid']        = $NextObjectGUIDtext;
515					$thisfile_asf_markerobject['objectsize']           = $NextObjectSize;
516					$thisfile_asf_markerobject['reserved']             = substr($ASFHeaderData, $offset, 16);
517					$offset += 16;
518					$thisfile_asf_markerobject['reserved_guid']        = $this->BytestringToGUID($thisfile_asf_markerobject['reserved']);
519					if ($thisfile_asf_markerobject['reserved'] != $this->GUIDtoBytestring('4CFEDB20-75F6-11CF-9C0F-00A0C90349CB')) {
520						$this->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}');
521						break;
522					}
523					$thisfile_asf_markerobject['markers_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
524					$offset += 4;
525					$thisfile_asf_markerobject['reserved_2'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
526					$offset += 2;
527					if ($thisfile_asf_markerobject['reserved_2'] != 0) {
528						$this->warning('marker_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_markerobject['reserved_2']).') does not match expected value of "0"');
529						break;
530					}
531					$thisfile_asf_markerobject['name_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
532					$offset += 2;
533					$thisfile_asf_markerobject['name'] = substr($ASFHeaderData, $offset, $thisfile_asf_markerobject['name_length']);
534					$offset += $thisfile_asf_markerobject['name_length'];
535					for ($MarkersCounter = 0; $MarkersCounter < $thisfile_asf_markerobject['markers_count']; $MarkersCounter++) {
536						$thisfile_asf_markerobject['markers'][$MarkersCounter]['offset']  = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
537						$offset += 8;
538						$thisfile_asf_markerobject['markers'][$MarkersCounter]['presentation_time']         = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
539						$offset += 8;
540						$thisfile_asf_markerobject['markers'][$MarkersCounter]['entry_length']              = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
541						$offset += 2;
542						$thisfile_asf_markerobject['markers'][$MarkersCounter]['send_time']                 = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
543						$offset += 4;
544						$thisfile_asf_markerobject['markers'][$MarkersCounter]['flags']                     = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
545						$offset += 4;
546						$thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
547						$offset += 4;
548						$thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description']        = substr($ASFHeaderData, $offset, $thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description_length']);
549						$offset += $thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description_length'];
550						$PaddingLength = $thisfile_asf_markerobject['markers'][$MarkersCounter]['entry_length'] - 4 -  4 - 4 - $thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description_length'];
551						if ($PaddingLength > 0) {
552							$thisfile_asf_markerobject['markers'][$MarkersCounter]['padding']               = substr($ASFHeaderData, $offset, $PaddingLength);
553							$offset += $PaddingLength;
554						}
555					}
556					break;
557
558				case GETID3_ASF_Bitrate_Mutual_Exclusion_Object:
559					// Bitrate Mutual Exclusion Object: (optional)
560					// Field Name                   Field Type   Size (bits)
561					// Object ID                    GUID         128             // GUID for Bitrate Mutual Exclusion object - GETID3_ASF_Bitrate_Mutual_Exclusion_Object
562					// Object Size                  QWORD        64              // size of Bitrate Mutual Exclusion object, including 42 bytes of Bitrate Mutual Exclusion Object header
563					// Exlusion Type                GUID         128             // nature of mutual exclusion relationship. one of: (GETID3_ASF_Mutex_Bitrate, GETID3_ASF_Mutex_Unknown)
564					// Stream Numbers Count         WORD         16              // number of video streams
565					// Stream Numbers               WORD         variable        // array of mutually exclusive video stream numbers. 1 <= valid <= 127
566
567					// shortcut
568					$thisfile_asf['bitrate_mutual_exclusion_object'] = array();
569					$thisfile_asf_bitratemutualexclusionobject       = &$thisfile_asf['bitrate_mutual_exclusion_object'];
570
571					$thisfile_asf_bitratemutualexclusionobject['offset']               = $NextObjectOffset + $offset;
572					$thisfile_asf_bitratemutualexclusionobject['objectid']             = $NextObjectGUID;
573					$thisfile_asf_bitratemutualexclusionobject['objectid_guid']        = $NextObjectGUIDtext;
574					$thisfile_asf_bitratemutualexclusionobject['objectsize']           = $NextObjectSize;
575					$thisfile_asf_bitratemutualexclusionobject['reserved']             = substr($ASFHeaderData, $offset, 16);
576					$thisfile_asf_bitratemutualexclusionobject['reserved_guid']        = $this->BytestringToGUID($thisfile_asf_bitratemutualexclusionobject['reserved']);
577					$offset += 16;
578					if (($thisfile_asf_bitratemutualexclusionobject['reserved'] != GETID3_ASF_Mutex_Bitrate) && ($thisfile_asf_bitratemutualexclusionobject['reserved'] != GETID3_ASF_Mutex_Unknown)) {
579						$this->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).'}');
580						//return false;
581						break;
582					}
583					$thisfile_asf_bitratemutualexclusionobject['stream_numbers_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
584					$offset += 2;
585					for ($StreamNumberCounter = 0; $StreamNumberCounter < $thisfile_asf_bitratemutualexclusionobject['stream_numbers_count']; $StreamNumberCounter++) {
586						$thisfile_asf_bitratemutualexclusionobject['stream_numbers'][$StreamNumberCounter] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
587						$offset += 2;
588					}
589					break;
590
591				case GETID3_ASF_Error_Correction_Object:
592					// Error Correction Object: (optional, one only)
593					// Field Name                   Field Type   Size (bits)
594					// Object ID                    GUID         128             // GUID for Error Correction object - GETID3_ASF_Error_Correction_Object
595					// Object Size                  QWORD        64              // size of Error Correction object, including 44 bytes of Error Correction Object header
596					// Error Correction Type        GUID         128             // type of error correction. one of: (GETID3_ASF_No_Error_Correction, GETID3_ASF_Audio_Spread)
597					// Error Correction Data Length DWORD        32              // number of bytes in Error Correction Data field
598					// Error Correction Data        BYTESTREAM   variable        // structure depends on value of Error Correction Type field
599
600					// shortcut
601					$thisfile_asf['error_correction_object'] = array();
602					$thisfile_asf_errorcorrectionobject      = &$thisfile_asf['error_correction_object'];
603
604					$thisfile_asf_errorcorrectionobject['offset']                = $NextObjectOffset + $offset;
605					$thisfile_asf_errorcorrectionobject['objectid']              = $NextObjectGUID;
606					$thisfile_asf_errorcorrectionobject['objectid_guid']         = $NextObjectGUIDtext;
607					$thisfile_asf_errorcorrectionobject['objectsize']            = $NextObjectSize;
608					$thisfile_asf_errorcorrectionobject['error_correction_type'] = substr($ASFHeaderData, $offset, 16);
609					$offset += 16;
610					$thisfile_asf_errorcorrectionobject['error_correction_guid'] = $this->BytestringToGUID($thisfile_asf_errorcorrectionobject['error_correction_type']);
611					$thisfile_asf_errorcorrectionobject['error_correction_data_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
612					$offset += 4;
613					switch ($thisfile_asf_errorcorrectionobject['error_correction_type']) {
614						case GETID3_ASF_No_Error_Correction:
615							// should be no data, but just in case there is, skip to the end of the field
616							$offset += $thisfile_asf_errorcorrectionobject['error_correction_data_length'];
617							break;
618
619						case GETID3_ASF_Audio_Spread:
620							// Field Name                   Field Type   Size (bits)
621							// Span                         BYTE         8               // number of packets over which audio will be spread.
622							// Virtual Packet Length        WORD         16              // size of largest audio payload found in audio stream
623							// Virtual Chunk Length         WORD         16              // size of largest audio payload found in audio stream
624							// Silence Data Length          WORD         16              // number of bytes in Silence Data field
625							// Silence Data                 BYTESTREAM   variable        // hardcoded: 0x00 * (Silence Data Length) bytes
626
627							$thisfile_asf_errorcorrectionobject['span']                  = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 1));
628							$offset += 1;
629							$thisfile_asf_errorcorrectionobject['virtual_packet_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
630							$offset += 2;
631							$thisfile_asf_errorcorrectionobject['virtual_chunk_length']  = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
632							$offset += 2;
633							$thisfile_asf_errorcorrectionobject['silence_data_length']   = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
634							$offset += 2;
635							$thisfile_asf_errorcorrectionobject['silence_data']          = substr($ASFHeaderData, $offset, $thisfile_asf_errorcorrectionobject['silence_data_length']);
636							$offset += $thisfile_asf_errorcorrectionobject['silence_data_length'];
637							break;
638
639						default:
640							$this->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).'}');
641							//return false;
642							break;
643					}
644
645					break;
646
647				case GETID3_ASF_Content_Description_Object:
648					// Content Description Object: (optional, one only)
649					// Field Name                   Field Type   Size (bits)
650					// Object ID                    GUID         128             // GUID for Content Description object - GETID3_ASF_Content_Description_Object
651					// Object Size                  QWORD        64              // size of Content Description object, including 34 bytes of Content Description Object header
652					// Title Length                 WORD         16              // number of bytes in Title field
653					// Author Length                WORD         16              // number of bytes in Author field
654					// Copyright Length             WORD         16              // number of bytes in Copyright field
655					// Description Length           WORD         16              // number of bytes in Description field
656					// Rating Length                WORD         16              // number of bytes in Rating field
657					// Title                        WCHAR        16              // array of Unicode characters - Title
658					// Author                       WCHAR        16              // array of Unicode characters - Author
659					// Copyright                    WCHAR        16              // array of Unicode characters - Copyright
660					// Description                  WCHAR        16              // array of Unicode characters - Description
661					// Rating                       WCHAR        16              // array of Unicode characters - Rating
662
663					// shortcut
664					$thisfile_asf['content_description_object'] = array();
665					$thisfile_asf_contentdescriptionobject      = &$thisfile_asf['content_description_object'];
666
667					$thisfile_asf_contentdescriptionobject['offset']                = $NextObjectOffset + $offset;
668					$thisfile_asf_contentdescriptionobject['objectid']              = $NextObjectGUID;
669					$thisfile_asf_contentdescriptionobject['objectid_guid']         = $NextObjectGUIDtext;
670					$thisfile_asf_contentdescriptionobject['objectsize']            = $NextObjectSize;
671					$thisfile_asf_contentdescriptionobject['title_length']          = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
672					$offset += 2;
673					$thisfile_asf_contentdescriptionobject['author_length']         = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
674					$offset += 2;
675					$thisfile_asf_contentdescriptionobject['copyright_length']      = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
676					$offset += 2;
677					$thisfile_asf_contentdescriptionobject['description_length']    = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
678					$offset += 2;
679					$thisfile_asf_contentdescriptionobject['rating_length']         = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
680					$offset += 2;
681					$thisfile_asf_contentdescriptionobject['title']                 = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['title_length']);
682					$offset += $thisfile_asf_contentdescriptionobject['title_length'];
683					$thisfile_asf_contentdescriptionobject['author']                = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['author_length']);
684					$offset += $thisfile_asf_contentdescriptionobject['author_length'];
685					$thisfile_asf_contentdescriptionobject['copyright']             = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['copyright_length']);
686					$offset += $thisfile_asf_contentdescriptionobject['copyright_length'];
687					$thisfile_asf_contentdescriptionobject['description']           = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['description_length']);
688					$offset += $thisfile_asf_contentdescriptionobject['description_length'];
689					$thisfile_asf_contentdescriptionobject['rating']                = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['rating_length']);
690					$offset += $thisfile_asf_contentdescriptionobject['rating_length'];
691
692					$ASFcommentKeysToCopy = array('title'=>'title', 'author'=>'artist', 'copyright'=>'copyright', 'description'=>'comment', 'rating'=>'rating');
693					foreach ($ASFcommentKeysToCopy as $keytocopyfrom => $keytocopyto) {
694						if (!empty($thisfile_asf_contentdescriptionobject[$keytocopyfrom])) {
695							$thisfile_asf_comments[$keytocopyto][] = $this->TrimTerm($thisfile_asf_contentdescriptionobject[$keytocopyfrom]);
696						}
697					}
698					break;
699
700				case GETID3_ASF_Extended_Content_Description_Object:
701					// Extended Content Description Object: (optional, one only)
702					// Field Name                   Field Type   Size (bits)
703					// Object ID                    GUID         128             // GUID for Extended Content Description object - GETID3_ASF_Extended_Content_Description_Object
704					// Object Size                  QWORD        64              // size of ExtendedContent Description object, including 26 bytes of Extended Content Description Object header
705					// Content Descriptors Count    WORD         16              // number of entries in Content Descriptors list
706					// Content Descriptors          array of:    variable        //
707					// * Descriptor Name Length     WORD         16              // size in bytes of Descriptor Name field
708					// * Descriptor Name            WCHAR        variable        // array of Unicode characters - Descriptor Name
709					// * Descriptor Value Data Type WORD         16              // Lookup array:
710																					// 0x0000 = Unicode String (variable length)
711																					// 0x0001 = BYTE array     (variable length)
712																					// 0x0002 = BOOL           (DWORD, 32 bits)
713																					// 0x0003 = DWORD          (DWORD, 32 bits)
714																			

Large files files are truncated, but you can click here to view the full file