PageRenderTime 422ms CodeModel.GetById 132ms app.highlight 170ms RepoModel.GetById 101ms app.codeStats 2ms

/getid3/module.audio-video.asf.php

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

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