[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

title

Body

[close]

/wp-includes/ID3/ -> module.audio-video.asf.php (source)

   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  
  17  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
  18  
  19  class 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                                                                                      // 0x0004 = QWORD          (QWORD, 64 bits)
 715                                                                                      // 0x0005 = WORD           (WORD,  16 bits)
 716                      // * Descriptor Value Length    WORD         16              // number of bytes stored in Descriptor Value field
 717                      // * Descriptor Value           variable     variable        // value for Content Descriptor
 718  
 719                      // shortcut
 720                      $thisfile_asf['extended_content_description_object'] = array();
 721                      $thisfile_asf_extendedcontentdescriptionobject       = &$thisfile_asf['extended_content_description_object'];
 722  
 723                      $thisfile_asf_extendedcontentdescriptionobject['offset']                    = $NextObjectOffset + $offset;
 724                      $thisfile_asf_extendedcontentdescriptionobject['objectid']                  = $NextObjectGUID;
 725                      $thisfile_asf_extendedcontentdescriptionobject['objectid_guid']             = $NextObjectGUIDtext;
 726                      $thisfile_asf_extendedcontentdescriptionobject['objectsize']                = $NextObjectSize;
 727                      $thisfile_asf_extendedcontentdescriptionobject['content_descriptors_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
 728                      $offset += 2;
 729                      for ($ExtendedContentDescriptorsCounter = 0; $ExtendedContentDescriptorsCounter < $thisfile_asf_extendedcontentdescriptionobject['content_descriptors_count']; $ExtendedContentDescriptorsCounter++) {
 730                          // shortcut
 731                          $thisfile_asf_extendedcontentdescriptionobject['content_descriptors'][$ExtendedContentDescriptorsCounter] = array();
 732                          $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current                 = &$thisfile_asf_extendedcontentdescriptionobject['content_descriptors'][$ExtendedContentDescriptorsCounter];
 733  
 734                          $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['base_offset']  = $offset + 30;
 735                          $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name_length']  = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
 736                          $offset += 2;
 737                          $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name']         = substr($ASFHeaderData, $offset, $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name_length']);
 738                          $offset += $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name_length'];
 739                          $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type']   = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
 740                          $offset += 2;
 741                          $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
 742                          $offset += 2;
 743                          $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']        = substr($ASFHeaderData, $offset, $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_length']);
 744                          $offset += $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_length'];
 745                          switch ($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type']) {
 746                              case 0x0000: // Unicode string
 747                                  break;
 748  
 749                              case 0x0001: // BYTE array
 750                                  // do nothing
 751                                  break;
 752  
 753                              case 0x0002: // BOOL
 754                                  $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'] = (bool) getid3_lib::LittleEndian2Int($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']);
 755                                  break;
 756  
 757                              case 0x0003: // DWORD
 758                              case 0x0004: // QWORD
 759                              case 0x0005: // WORD
 760                                  $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'] = getid3_lib::LittleEndian2Int($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']);
 761                                  break;
 762  
 763                              default:
 764                                  $this->warning('extended_content_description.content_descriptors.'.$ExtendedContentDescriptorsCounter.'.value_type is invalid ('.$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type'].')');
 765                                  //return false;
 766                                  break;
 767                          }
 768                          switch ($this->TrimConvert(strtolower($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name']))) {
 769  
 770                              case 'wm/albumartist':
 771                              case 'artist':
 772                                  // Note: not 'artist', that comes from 'author' tag
 773                                  $thisfile_asf_comments['albumartist'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
 774                                  break;
 775  
 776                              case 'wm/albumtitle':
 777                              case 'album':
 778                                  $thisfile_asf_comments['album']  = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
 779                                  break;
 780  
 781                              case 'wm/genre':
 782                              case 'genre':
 783                                  $thisfile_asf_comments['genre'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
 784                                  break;
 785  
 786                              case 'wm/partofset':
 787                                  $thisfile_asf_comments['partofset'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
 788                                  break;
 789  
 790                              case 'wm/tracknumber':
 791                              case 'tracknumber':
 792                                  // be careful casting to int: casting unicode strings to int gives unexpected results (stops parsing at first non-numeric character)
 793                                  $thisfile_asf_comments['track'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
 794                                  foreach ($thisfile_asf_comments['track'] as $key => $value) {
 795                                      if (preg_match('/^[0-9\x00]+$/', $value)) {
 796                                          $thisfile_asf_comments['track'][$key] = intval(str_replace("\x00", '', $value));
 797                                      }
 798                                  }
 799                                  break;
 800  
 801                              case 'wm/track':
 802                                  if (empty($thisfile_asf_comments['track'])) {
 803                                      $thisfile_asf_comments['track'] = array(1 + $this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
 804                                  }
 805                                  break;
 806  
 807                              case 'wm/year':
 808                              case 'year':
 809                              case 'date':
 810                                  $thisfile_asf_comments['year'] = array( $this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
 811                                  break;
 812  
 813                              case 'wm/lyrics':
 814                              case 'lyrics':
 815                                  $thisfile_asf_comments['lyrics'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
 816                                  break;
 817  
 818                              case 'isvbr':
 819                                  if ($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']) {
 820                                      $thisfile_audio['bitrate_mode'] = 'vbr';
 821                                      $thisfile_video['bitrate_mode'] = 'vbr';
 822                                  }
 823                                  break;
 824  
 825                              case 'id3':
 826                                  $this->getid3->include_module('tag.id3v2');
 827  
 828                                  $getid3_id3v2 = new getid3_id3v2($this->getid3);
 829                                  $getid3_id3v2->AnalyzeString($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']);
 830                                  unset($getid3_id3v2);
 831  
 832                                  if ($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_length'] > 1024) {
 833                                      $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'] = '<value too large to display>';
 834                                  }
 835                                  break;
 836  
 837                              case 'wm/encodingtime':
 838                                  $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['encoding_time_unix'] = $this->FILETIMEtoUNIXtime($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']);
 839                                  $thisfile_asf_comments['encoding_time_unix'] = array($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['encoding_time_unix']);
 840                                  break;
 841  
 842                              case 'wm/picture':
 843                                  $WMpicture = $this->ASF_WMpicture($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']);
 844                                  foreach ($WMpicture as $key => $value) {
 845                                      $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current[$key] = $value;
 846                                  }
 847                                  unset($WMpicture);
 848  /*
 849                                  $wm_picture_offset = 0;
 850                                  $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_type_id'] = getid3_lib::LittleEndian2Int(substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset, 1));
 851                                  $wm_picture_offset += 1;
 852                                  $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_type']    = self::WMpictureTypeLookup($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_type_id']);
 853                                  $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_size']    = getid3_lib::LittleEndian2Int(substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset, 4));
 854                                  $wm_picture_offset += 4;
 855  
 856                                  $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime'] = '';
 857                                  do {
 858                                      $next_byte_pair = substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset, 2);
 859                                      $wm_picture_offset += 2;
 860                                      $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime'] .= $next_byte_pair;
 861                                  } while ($next_byte_pair !== "\x00\x00");
 862  
 863                                  $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_description'] = '';
 864                                  do {
 865                                      $next_byte_pair = substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset, 2);
 866                                      $wm_picture_offset += 2;
 867                                      $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_description'] .= $next_byte_pair;
 868                                  } while ($next_byte_pair !== "\x00\x00");
 869  
 870                                  $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['dataoffset'] = $wm_picture_offset;
 871                                  $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['data'] = substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset);
 872                                  unset($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']);
 873  
 874                                  $imageinfo = array();
 875                                  $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime'] = '';
 876                                  $imagechunkcheck = getid3_lib::GetDataImageSize($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['data'], $imageinfo);
 877                                  unset($imageinfo);
 878                                  if (!empty($imagechunkcheck)) {
 879                                      $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]);
 880                                  }
 881                                  if (!isset($thisfile_asf_comments['picture'])) {
 882                                      $thisfile_asf_comments['picture'] = array();
 883                                  }
 884                                  $thisfile_asf_comments['picture'][] = array('data'=>$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['data'], 'image_mime'=>$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime']);
 885  */
 886                                  break;
 887  
 888                              default:
 889                                  switch ($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type']) {
 890                                      case 0: // Unicode string
 891                                          if (substr($this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name']), 0, 3) == 'WM/') {
 892                                              $thisfile_asf_comments[str_replace('wm/', '', strtolower($this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name'])))] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
 893                                          }
 894                                          break;
 895  
 896                                      case 1:
 897                                          break;
 898                                  }
 899                                  break;
 900                          }
 901  
 902                      }
 903                      break;
 904  
 905                  case GETID3_ASF_Stream_Bitrate_Properties_Object:
 906                      // Stream Bitrate Properties Object: (optional, one only)
 907                      // Field Name                   Field Type   Size (bits)
 908                      // Object ID                    GUID         128             // GUID for Stream Bitrate Properties object - GETID3_ASF_Stream_Bitrate_Properties_Object
 909                      // Object Size                  QWORD        64              // size of Extended Content Description object, including 26 bytes of Stream Bitrate Properties Object header
 910                      // Bitrate Records Count        WORD         16              // number of records in Bitrate Records
 911                      // Bitrate Records              array of:    variable        //
 912                      // * Flags                      WORD         16              //
 913                      // * * Stream Number            bits         7  (0x007F)     // number of this stream
 914                      // * * Reserved                 bits         9  (0xFF80)     // hardcoded: 0
 915                      // * Average Bitrate            DWORD        32              // in bits per second
 916  
 917                      // shortcut
 918                      $thisfile_asf['stream_bitrate_properties_object'] = array();
 919                      $thisfile_asf_streambitratepropertiesobject       = &$thisfile_asf['stream_bitrate_properties_object'];
 920  
 921                      $thisfile_asf_streambitratepropertiesobject['offset']                    = $NextObjectOffset + $offset;
 922                      $thisfile_asf_streambitratepropertiesobject['objectid']                  = $NextObjectGUID;
 923                      $thisfile_asf_streambitratepropertiesobject['objectid_guid']             = $NextObjectGUIDtext;
 924                      $thisfile_asf_streambitratepropertiesobject['objectsize']                = $NextObjectSize;
 925                      $thisfile_asf_streambitratepropertiesobject['bitrate_records_count']     = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
 926                      $offset += 2;
 927                      for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < $thisfile_asf_streambitratepropertiesobject['bitrate_records_count']; $BitrateRecordsCounter++) {
 928                          $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['flags_raw'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
 929                          $offset += 2;
 930                          $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['flags']['stream_number'] = $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['flags_raw'] & 0x007F;
 931                          $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['bitrate'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
 932                          $offset += 4;
 933                      }
 934                      break;
 935  
 936                  case GETID3_ASF_Padding_Object:
 937                      // Padding Object: (optional)
 938                      // Field Name                   Field Type   Size (bits)
 939                      // Object ID                    GUID         128             // GUID for Padding object - GETID3_ASF_Padding_Object
 940                      // Object Size                  QWORD        64              // size of Padding object, including 24 bytes of ASF Padding Object header
 941                      // Padding Data                 BYTESTREAM   variable        // ignore
 942  
 943                      // shortcut
 944                      $thisfile_asf['padding_object'] = array();
 945                      $thisfile_asf_paddingobject     = &$thisfile_asf['padding_object'];
 946  
 947                      $thisfile_asf_paddingobject['offset']                    = $NextObjectOffset + $offset;
 948                      $thisfile_asf_paddingobject['objectid']                  = $NextObjectGUID;
 949                      $thisfile_asf_paddingobject['objectid_guid']             = $NextObjectGUIDtext;
 950                      $thisfile_asf_paddingobject['objectsize']                = $NextObjectSize;
 951                      $thisfile_asf_paddingobject['padding_length']            = $thisfile_asf_paddingobject['objectsize'] - 16 - 8;
 952                      $thisfile_asf_paddingobject['padding']                   = substr($ASFHeaderData, $offset, $thisfile_asf_paddingobject['padding_length']);
 953                      $offset += ($NextObjectSize - 16 - 8);
 954                      break;
 955  
 956                  case GETID3_ASF_Extended_Content_Encryption_Object:
 957                  case GETID3_ASF_Content_Encryption_Object:
 958                      // WMA DRM - just ignore
 959                      $offset += ($NextObjectSize - 16 - 8);
 960                      break;
 961  
 962                  default:
 963                      // Implementations shall ignore any standard or non-standard object that they do not know how to handle.
 964                      if ($this->GUIDname($NextObjectGUIDtext)) {
 965                          $this->warning('unhandled GUID "'.$this->GUIDname($NextObjectGUIDtext).'" {'.$NextObjectGUIDtext.'} in ASF header at offset '.($offset - 16 - 8));
 966                      } else {
 967                          $this->warning('unknown GUID {'.$NextObjectGUIDtext.'} in ASF header at offset '.($offset - 16 - 8));
 968                      }
 969                      $offset += ($NextObjectSize - 16 - 8);
 970                      break;
 971              }
 972          }
 973          if (isset($thisfile_asf_streambitrateproperties['bitrate_records_count'])) {
 974              $ASFbitrateAudio = 0;
 975              $ASFbitrateVideo = 0;
 976              for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < $thisfile_asf_streambitrateproperties['bitrate_records_count']; $BitrateRecordsCounter++) {
 977                  if (isset($thisfile_asf_codeclistobject['codec_entries'][$BitrateRecordsCounter])) {
 978                      switch ($thisfile_asf_codeclistobject['codec_entries'][$BitrateRecordsCounter]['type_raw']) {
 979                          case 1:
 980                              $ASFbitrateVideo += $thisfile_asf_streambitrateproperties['bitrate_records'][$BitrateRecordsCounter]['bitrate'];
 981                              break;
 982  
 983                          case 2:
 984                              $ASFbitrateAudio += $thisfile_asf_streambitrateproperties['bitrate_records'][$BitrateRecordsCounter]['bitrate'];
 985                              break;
 986  
 987                          default:
 988                              // do nothing
 989                              break;
 990                      }
 991                  }
 992              }
 993              if ($ASFbitrateAudio > 0) {
 994                  $thisfile_audio['bitrate'] = $ASFbitrateAudio;
 995              }
 996              if ($ASFbitrateVideo > 0) {
 997                  $thisfile_video['bitrate'] = $ASFbitrateVideo;
 998              }
 999          }
1000          if (isset($thisfile_asf['stream_properties_object']) && is_array($thisfile_asf['stream_properties_object'])) {
1001  
1002              $thisfile_audio['bitrate'] = 0;
1003              $thisfile_video['bitrate'] = 0;
1004  
1005              foreach ($thisfile_asf['stream_properties_object'] as $streamnumber => $streamdata) {
1006  
1007                  switch ($streamdata['stream_type']) {
1008                      case GETID3_ASF_Audio_Media:
1009                          // Field Name                   Field Type   Size (bits)
1010                          // Codec ID / Format Tag        WORD         16              // unique ID of audio codec - defined as wFormatTag field of WAVEFORMATEX structure
1011                          // Number of Channels           WORD         16              // number of channels of audio - defined as nChannels field of WAVEFORMATEX structure
1012                          // Samples Per Second           DWORD        32              // in Hertz - defined as nSamplesPerSec field of WAVEFORMATEX structure
1013                          // Average number of Bytes/sec  DWORD        32              // bytes/sec of audio stream  - defined as nAvgBytesPerSec field of WAVEFORMATEX structure
1014                          // Block Alignment              WORD         16              // block size in bytes of audio codec - defined as nBlockAlign field of WAVEFORMATEX structure
1015                          // Bits per sample              WORD         16              // bits per sample of mono data. set to zero for variable bitrate codecs. defined as wBitsPerSample field of WAVEFORMATEX structure
1016                          // Codec Specific Data Size     WORD         16              // size in bytes of Codec Specific Data buffer - defined as cbSize field of WAVEFORMATEX structure
1017                          // Codec Specific Data          BYTESTREAM   variable        // array of codec-specific data bytes
1018  
1019                          // shortcut
1020                          $thisfile_asf['audio_media'][$streamnumber] = array();
1021                          $thisfile_asf_audiomedia_currentstream      = &$thisfile_asf['audio_media'][$streamnumber];
1022  
1023                          $audiomediaoffset = 0;
1024  
1025                          $thisfile_asf_audiomedia_currentstream = getid3_riff::parseWAVEFORMATex(substr($streamdata['type_specific_data'], $audiomediaoffset, 16));
1026                          $audiomediaoffset += 16;
1027  
1028                          $thisfile_audio['lossless'] = false;
1029                          switch ($thisfile_asf_audiomedia_currentstream['raw']['wFormatTag']) {
1030                              case 0x0001: // PCM
1031                              case 0x0163: // WMA9 Lossless
1032                                  $thisfile_audio['lossless'] = true;
1033                                  break;
1034                          }
1035  
1036                          if (!empty($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'])) {
1037                              foreach ($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'] as $dummy => $dataarray) {
1038                                  if (isset($dataarray['flags']['stream_number']) && ($dataarray['flags']['stream_number'] == $streamnumber)) {
1039                                      $thisfile_asf_audiomedia_currentstream['bitrate'] = $dataarray['bitrate'];
1040                                      $thisfile_audio['bitrate'] += $dataarray['bitrate'];
1041                                      break;
1042                                  }
1043                              }
1044                          } else {
1045                              if (!empty($thisfile_asf_audiomedia_currentstream['bytes_sec'])) {
1046                                  $thisfile_audio['bitrate'] += $thisfile_asf_audiomedia_currentstream['bytes_sec'] * 8;
1047                              } elseif (!empty($thisfile_asf_audiomedia_currentstream['bitrate'])) {
1048                                  $thisfile_audio['bitrate'] += $thisfile_asf_audiomedia_currentstream['bitrate'];
1049                              }
1050                          }
1051                          $thisfile_audio['streams'][$streamnumber]                = $thisfile_asf_audiomedia_currentstream;
1052                          $thisfile_audio['streams'][$streamnumber]['wformattag']  = $thisfile_asf_audiomedia_currentstream['raw']['wFormatTag'];
1053                          $thisfile_audio['streams'][$streamnumber]['lossless']    = $thisfile_audio['lossless'];
1054                          $thisfile_audio['streams'][$streamnumber]['bitrate']     = $thisfile_audio['bitrate'];
1055                          $thisfile_audio['streams'][$streamnumber]['dataformat']  = 'wma';
1056                          unset($thisfile_audio['streams'][$streamnumber]['raw']);
1057  
1058                          $thisfile_asf_audiomedia_currentstream['codec_data_size'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $audiomediaoffset, 2));
1059                          $audiomediaoffset += 2;
1060                          $thisfile_asf_audiomedia_currentstream['codec_data']      = substr($streamdata['type_specific_data'], $audiomediaoffset, $thisfile_asf_audiomedia_currentstream['codec_data_size']);
1061                          $audiomediaoffset += $thisfile_asf_audiomedia_currentstream['codec_data_size'];
1062  
1063                          break;
1064  
1065                      case GETID3_ASF_Video_Media:
1066                          // Field Name                   Field Type   Size (bits)
1067                          // Encoded Image Width          DWORD        32              // width of image in pixels
1068                          // Encoded Image Height         DWORD        32              // height of image in pixels
1069                          // Reserved Flags               BYTE         8               // hardcoded: 0x02
1070                          // Format Data Size             WORD         16              // size of Format Data field in bytes
1071                          // Format Data                  array of:    variable        //
1072                          // * Format Data Size           DWORD        32              // number of bytes in Format Data field, in bytes - defined as biSize field of BITMAPINFOHEADER structure
1073                          // * Image Width                LONG         32              // width of encoded image in pixels - defined as biWidth field of BITMAPINFOHEADER structure
1074                          // * Image Height               LONG         32              // height of encoded image in pixels - defined as biHeight field of BITMAPINFOHEADER structure
1075                          // * Reserved                   WORD         16              // hardcoded: 0x0001 - defined as biPlanes field of BITMAPINFOHEADER structure
1076                          // * Bits Per Pixel Count       WORD         16              // bits per pixel - defined as biBitCount field of BITMAPINFOHEADER structure
1077                          // * Compression ID             FOURCC       32              // fourcc of video codec - defined as biCompression field of BITMAPINFOHEADER structure
1078                          // * Image Size                 DWORD        32              // image size in bytes - defined as biSizeImage field of BITMAPINFOHEADER structure
1079                          // * Horizontal Pixels / Meter  DWORD        32              // horizontal resolution of target device in pixels per meter - defined as biXPelsPerMeter field of BITMAPINFOHEADER structure
1080                          // * Vertical Pixels / Meter    DWORD        32              // vertical resolution of target device in pixels per meter - defined as biYPelsPerMeter field of BITMAPINFOHEADER structure
1081                          // * Colors Used Count          DWORD        32              // number of color indexes in the color table that are actually used - defined as biClrUsed field of BITMAPINFOHEADER structure
1082                          // * Important Colors Count     DWORD        32              // number of color index required for displaying bitmap. if zero, all colors are required. defined as biClrImportant field of BITMAPINFOHEADER structure
1083                          // * Codec Specific Data        BYTESTREAM   variable        // array of codec-specific data bytes
1084  
1085                          // shortcut
1086                          $thisfile_asf['video_media'][$streamnumber] = array();
1087                          $thisfile_asf_videomedia_currentstream      = &$thisfile_asf['video_media'][$streamnumber];
1088  
1089                          $videomediaoffset = 0;
1090                          $thisfile_asf_videomedia_currentstream['image_width']                     = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
1091                          $videomediaoffset += 4;
1092                          $thisfile_asf_videomedia_currentstream['image_height']                    = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
1093                          $videomediaoffset += 4;
1094                          $thisfile_asf_videomedia_currentstream['flags']                           = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 1));
1095                          $videomediaoffset += 1;
1096                          $thisfile_asf_videomedia_currentstream['format_data_size']                = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 2));
1097                          $videomediaoffset += 2;
1098                          $thisfile_asf_videomedia_currentstream['format_data']['format_data_size'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
1099                          $videomediaoffset += 4;
1100                          $thisfile_asf_videomedia_currentstream['format_data']['image_width']      = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
1101                          $videomediaoffset += 4;
1102                          $thisfile_asf_videomedia_currentstream['format_data']['image_height']     = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
1103                          $videomediaoffset += 4;
1104                          $thisfile_asf_videomedia_currentstream['format_data']['reserved']         = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 2));
1105                          $videomediaoffset += 2;
1106                          $thisfile_asf_videomedia_currentstream['format_data']['bits_per_pixel']   = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 2));
1107                          $videomediaoffset += 2;
1108                          $thisfile_asf_videomedia_currentstream['format_data']['codec_fourcc']     = substr($streamdata['type_specific_data'], $videomediaoffset, 4);
1109                          $videomediaoffset += 4;
1110                          $thisfile_asf_videomedia_currentstream['format_data']['image_size']       = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
1111                          $videomediaoffset += 4;
1112                          $thisfile_asf_videomedia_currentstream['format_data']['horizontal_pels']  = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
1113                          $videomediaoffset += 4;
1114                          $thisfile_asf_videomedia_currentstream['format_data']['vertical_pels']    = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
1115                          $videomediaoffset += 4;
1116                          $thisfile_asf_videomedia_currentstream['format_data']['colors_used']      = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
1117                          $videomediaoffset += 4;
1118                          $thisfile_asf_videomedia_currentstream['format_data']['colors_important'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
1119                          $videomediaoffset += 4;
1120                          $thisfile_asf_videomedia_currentstream['format_data']['codec_data']       = substr($streamdata['type_specific_data'], $videomediaoffset);
1121  
1122                          if (!empty($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'])) {
1123                              foreach ($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'] as $dummy => $dataarray) {
1124                                  if (isset($dataarray['flags']['stream_number']) && ($dataarray['flags']['stream_number'] == $streamnumber)) {
1125                                      $thisfile_asf_videomedia_currentstream['bitrate'] = $dataarray['bitrate'];
1126                                      $thisfile_video['streams'][$streamnumber]['bitrate'] = $dataarray['bitrate'];
1127                                      $thisfile_video['bitrate'] += $dataarray['bitrate'];
1128                                      break;
1129                                  }
1130                              }
1131                          }
1132  
1133                          $thisfile_asf_videomedia_currentstream['format_data']['codec'] = getid3_riff::fourccLookup($thisfile_asf_videomedia_currentstream['format_data']['codec_fourcc']);
1134  
1135                          $thisfile_video['streams'][$streamnumber]['fourcc']          = $thisfile_asf_videomedia_currentstream['format_data']['codec_fourcc'];
1136                          $thisfile_video['streams'][$streamnumber]['codec']           = $thisfile_asf_videomedia_currentstream['format_data']['codec'];
1137                          $thisfile_video['streams'][$streamnumber]['resolution_x']    = $thisfile_asf_videomedia_currentstream['image_width'];
1138                          $thisfile_video['streams'][$streamnumber]['resolution_y']    = $thisfile_asf_videomedia_currentstream['image_height'];
1139                          $thisfile_video['streams'][$streamnumber]['bits_per_sample'] = $thisfile_asf_videomedia_currentstream['format_data']['bits_per_pixel'];
1140                          break;
1141  
1142                      default:
1143                          break;
1144                  }
1145              }
1146          }
1147  
1148          while ($this->ftell() < $info['avdataend']) {
1149              $NextObjectDataHeader = $this->fread(24);
1150              $offset = 0;
1151              $NextObjectGUID = substr($NextObjectDataHeader, 0, 16);
1152              $offset += 16;
1153              $NextObjectGUIDtext = $this->BytestringToGUID($NextObjectGUID);
1154              $NextObjectSize = getid3_lib::LittleEndian2Int(substr($NextObjectDataHeader, $offset, 8));
1155              $offset += 8;
1156  
1157              switch ($NextObjectGUID) {
1158                  case GETID3_ASF_Data_Object:
1159                      // Data Object: (mandatory, one only)
1160                      // Field Name                       Field Type   Size (bits)
1161                      // Object ID                        GUID         128             // GUID for Data object - GETID3_ASF_Data_Object
1162                      // Object Size                      QWORD        64              // size of Data object, including 50 bytes of Data Object header. may be 0 if FilePropertiesObject.BroadcastFlag == 1
1163                      // File ID                          GUID         128             // unique identifier. identical to File ID field in Header Object
1164                      // Total Data Packets               QWORD        64              // number of Data Packet entries in Data Object. invalid if FilePropertiesObject.BroadcastFlag == 1
1165                      // Reserved                         WORD         16              // hardcoded: 0x0101
1166  
1167                      // shortcut
1168                      $thisfile_asf['data_object'] = array();
1169                      $thisfile_asf_dataobject     = &$thisfile_asf['data_object'];
1170  
1171                      $DataObjectData = $NextObjectDataHeader.$this->fread(50 - 24);
1172                      $offset = 24;
1173  
1174                      $thisfile_asf_dataobject['objectid']           = $NextObjectGUID;
1175                      $thisfile_asf_dataobject['objectid_guid']      = $NextObjectGUIDtext;
1176                      $thisfile_asf_dataobject['objectsize']         = $NextObjectSize;
1177  
1178                      $thisfile_asf_dataobject['fileid']             = substr($DataObjectData, $offset, 16);
1179                      $offset += 16;
1180                      $thisfile_asf_dataobject['fileid_guid']        = $this->BytestringToGUID($thisfile_asf_dataobject['fileid']);
1181                      $thisfile_asf_dataobject['total_data_packets'] = getid3_lib::LittleEndian2Int(substr($DataObjectData, $offset, 8));
1182                      $offset += 8;
1183                      $thisfile_asf_dataobject['reserved']           = getid3_lib::LittleEndian2Int(substr($DataObjectData, $offset, 2));
1184                      $offset += 2;
1185                      if ($thisfile_asf_dataobject['reserved'] != 0x0101) {
1186                          $this->warning('data_object.reserved ('.getid3_lib::PrintHexBytes($thisfile_asf_dataobject['reserved']).') does not match expected value of "0x0101"');
1187                          //return false;
1188                          break;
1189                      }
1190  
1191                      // Data Packets                     array of:    variable        //
1192                      // * Error Correction Flags         BYTE         8               //
1193                      // * * Error Correction Data Length bits         4               // if Error Correction Length Type == 00, size of Error Correction Data in bytes, else hardcoded: 0000
1194                      // * * Opaque Data Present          bits         1               //
1195                      // * * Error Correction Length Type bits         2               // number of bits for size of the error correction data. hardcoded: 00
1196                      // * * Error Correction Present     bits         1               // If set, use Opaque Data Packet structure, else use Payload structure
1197                      // * Error Correction Data
1198  
1199                      $info['avdataoffset'] = $this->ftell();
1200                      $this->fseek(($thisfile_asf_dataobject['objectsize'] - 50), SEEK_CUR); // skip actual audio/video data
1201                      $info['avdataend'] = $this->ftell();
1202                      break;
1203  
1204                  case GETID3_ASF_Simple_Index_Object:
1205                      // Simple Index Object: (optional, recommended, one per video stream)
1206                      // Field Name                       Field Type   Size (bits)
1207                      // Object ID                        GUID         128             // GUID for Simple Index object - GETID3_ASF_Data_Object
1208                      // Object Size                      QWORD        64              // size of Simple Index object, including 56 bytes of Simple Index Object header
1209                      // File ID                          GUID         128             // unique identifier. may be zero or identical to File ID field in Data Object and Header Object
1210                      // Index Entry Time Interval        QWORD        64              // interval between index entries in 100-nanosecond units
1211                      // Maximum Packet Count             DWORD        32              // maximum packet count for all index entries
1212                      // Index Entries Count              DWORD        32              // number of Index Entries structures
1213                      // Index Entries                    array of:    variable        //
1214                      // * Packet Number                  DWORD        32              // number of the Data Packet associated with this index entry
1215                      // * Packet Count                   WORD         16              // number of Data Packets to sent at this index entry
1216  
1217                      // shortcut
1218                      $thisfile_asf['simple_index_object'] = array();
1219                      $thisfile_asf_simpleindexobject      = &$thisfile_asf['simple_index_object'];
1220  
1221                      $SimpleIndexObjectData = $NextObjectDataHeader.$this->fread(56 - 24);
1222                      $offset = 24;
1223  
1224                      $thisfile_asf_simpleindexobject['objectid']                  = $NextObjectGUID;
1225                      $thisfile_asf_simpleindexobject['objectid_guid']             = $NextObjectGUIDtext;
1226                      $thisfile_asf_simpleindexobject['objectsize']                = $NextObjectSize;
1227  
1228                      $thisfile_asf_simpleindexobject['fileid']                    =                  substr($SimpleIndexObjectData, $offset, 16);
1229                      $offset += 16;
1230                      $thisfile_asf_simpleindexobject['fileid_guid']               = $this->BytestringToGUID($thisfile_asf_simpleindexobject['fileid']);
1231                      $thisfile_asf_simpleindexobject['index_entry_time_interval'] = getid3_lib::LittleEndian2Int(substr($SimpleIndexObjectData, $offset, 8));
1232                      $offset += 8;
1233                      $thisfile_asf_simpleindexobject['maximum_packet_count']      = getid3_lib::LittleEndian2Int(substr($SimpleIndexObjectData, $offset, 4));
1234                      $offset += 4;
1235                      $thisfile_asf_simpleindexobject['index_entries_count']       = getid3_lib::LittleEndian2Int(substr($SimpleIndexObjectData, $offset, 4));
1236                      $offset += 4;
1237  
1238                      $IndexEntriesData = $SimpleIndexObjectData.$this->fread(6 * $thisfile_asf_simpleindexobject['index_entries_count']);
1239                      for ($IndexEntriesCounter = 0; $IndexEntriesCounter < $thisfile_asf_simpleindexobject['index_entries_count']; $IndexEntriesCounter++) {
1240                          $thisfile_asf_simpleindexobject['index_entries'][$IndexEntriesCounter]['packet_number'] = getid3_lib::LittleEndian2Int(substr($IndexEntriesData, $offset, 4));
1241                          $offset += 4;
1242                          $thisfile_asf_simpleindexobject['index_entries'][$IndexEntriesCounter]['packet_count']  = getid3_lib::LittleEndian2Int(substr($IndexEntriesData, $offset, 4));
1243                          $offset += 2;
1244                      }
1245  
1246                      break;
1247  
1248                  case GETID3_ASF_Index_Object:
1249                      // 6.2 ASF top-level Index Object (optional but recommended when appropriate, 0 or 1)
1250                      // Field Name                       Field Type   Size (bits)
1251                      // Object ID                        GUID         128             // GUID for the Index Object - GETID3_ASF_Index_Object
1252                      // Object Size                      QWORD        64              // Specifies the size, in bytes, of the Index Object, including at least 34 bytes of Index Object header
1253                      // Index Entry Time Interval        DWORD        32              // Specifies the time interval between each index entry in ms.
1254                      // Index Specifiers Count           WORD         16              // Specifies the number of Index Specifiers structures in this Index Object.
1255                      // Index Blocks Count               DWORD        32              // Specifies the number of Index Blocks structures in this Index Object.
1256  
1257                      // Index Entry Time Interval        DWORD        32              // Specifies the time interval between index entries in milliseconds.  This value cannot be 0.
1258                      // Index Specifiers Count           WORD         16              // Specifies the number of entries in the Index Specifiers list.  Valid values are 1 and greater.
1259                      // Index Specifiers                 array of:    varies          //
1260                      // * Stream Number                  WORD         16              // Specifies the stream number that the Index Specifiers refer to. Valid values are between 1 and 127.
1261                      // * Index Type                     WORD         16              // Specifies Index Type values as follows:
1262                                                                                      //   1 = Nearest Past Data Packet - indexes point to the data packet whose presentation time is closest to the index entry time.
1263                                                                                      //   2 = Nearest Past Media Object - indexes point to the closest data packet containing an entire object or first fragment of an object.
1264                                                                                      //   3 = Nearest Past Cleanpoint. - indexes point to the closest data packet containing an entire object (or first fragment of an object) that has the Cleanpoint Flag set.
1265                                                                                      //   Nearest Past Cleanpoint is the most common type of index.
1266                      // Index Entry Count                DWORD        32              // Specifies the number of Index Entries in the block.
1267                      // * Block Positions                QWORD        varies          // Specifies a list of byte offsets of the beginnings of the blocks relative to the beginning of the first Data Packet (i.e., the beginning of the Data Object + 50 bytes). The number of entries in this list is specified by the value of the Index Specifiers Count field. The order of those byte offsets is tied to the order in which Index Specifiers are listed.
1268                      // * Index Entries                  array of:    varies          //
1269                      // * * Offsets                      DWORD        varies          // An offset value of 0xffffffff indicates an invalid offset value
1270  
1271                      // shortcut
1272                      $thisfile_asf['asf_index_object'] = array();
1273                      $thisfile_asf_asfindexobject      = &$thisfile_asf['asf_index_object'];
1274  
1275                      $ASFIndexObjectData = $NextObjectDataHeader.$this->fread(34 - 24);
1276                      $offset = 24;
1277  
1278                      $thisfile_asf_asfindexobject['objectid']                  = $NextObjectGUID;
1279                      $thisfile_asf_asfindexobject['objectid_guid']             = $NextObjectGUIDtext;
1280                      $thisfile_asf_asfindexobject['objectsize']                = $NextObjectSize;
1281  
1282                      $thisfile_asf_asfindexobject['entry_time_interval']       = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4));
1283                      $offset += 4;
1284                      $thisfile_asf_asfindexobject['index_specifiers_count']    = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 2));
1285                      $offset += 2;
1286                      $thisfile_asf_asfindexobject['index_blocks_count']        = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4));
1287                      $offset += 4;
1288  
1289                      $ASFIndexObjectData .= $this->fread(4 * $thisfile_asf_asfindexobject['index_specifiers_count']);
1290                      for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) {
1291                          $IndexSpecifierStreamNumber = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 2));
1292                          $offset += 2;
1293                          $thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['stream_number']   = $IndexSpecifierStreamNumber;
1294                          $thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['index_type']      = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 2));
1295                          $offset += 2;
1296                          $thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['index_type_text'] = $this->ASFIndexObjectIndexTypeLookup($thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['index_type']);
1297                      }
1298  
1299                      $ASFIndexObjectData .= $this->fread(4);
1300                      $thisfile_asf_asfindexobject['index_entry_count'] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4));
1301                      $offset += 4;
1302  
1303                      $ASFIndexObjectData .= $this->fread(8 * $thisfile_asf_asfindexobject['index_specifiers_count']);
1304                      for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) {
1305                          $thisfile_asf_asfindexobject['block_positions'][$IndexSpecifiersCounter] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 8));
1306                          $offset += 8;
1307                      }
1308  
1309                      $ASFIndexObjectData .= $this->fread(4 * $thisfile_asf_asfindexobject['index_specifiers_count'] * $thisfile_asf_asfindexobject['index_entry_count']);
1310                      for ($IndexEntryCounter = 0; $IndexEntryCounter < $thisfile_asf_asfindexobject['index_entry_count']; $IndexEntryCounter++) {
1311                          for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) {
1312                              $thisfile_asf_asfindexobject['offsets'][$IndexSpecifiersCounter][$IndexEntryCounter] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4));
1313                              $offset += 4;
1314                          }
1315                      }
1316                      break;
1317  
1318  
1319                  default:
1320                      // Implementations shall ignore any standard or non-standard object that they do not know how to handle.
1321                      if ($this->GUIDname($NextObjectGUIDtext)) {
1322                          $this->warning('unhandled GUID "'.$this->GUIDname($NextObjectGUIDtext).'" {'.$NextObjectGUIDtext.'} in ASF body at offset '.($offset - 16 - 8));
1323                      } else {
1324                          $this->warning('unknown GUID {'.$NextObjectGUIDtext.'} in ASF body at offset '.($this->ftell() - 16 - 8));
1325                      }
1326                      $this->fseek(($NextObjectSize - 16 - 8), SEEK_CUR);
1327                      break;
1328              }
1329          }
1330  
1331          if (isset($thisfile_asf_codeclistobject['codec_entries']) && is_array($thisfile_asf_codeclistobject['codec_entries'])) {
1332              foreach ($thisfile_asf_codeclistobject['codec_entries'] as $streamnumber => $streamdata) {
1333                  switch ($streamdata['information']) {
1334                      case 'WMV1':
1335                      case 'WMV2':
1336                      case 'WMV3':
1337                      case 'MSS1':
1338                      case 'MSS2':
1339                      case 'WMVA':
1340                      case 'WVC1':
1341                      case 'WMVP':
1342                      case 'WVP2':
1343                          $thisfile_video['dataformat'] = 'wmv';
1344                          $info['mime_type'] = 'video/x-ms-wmv';
1345                          break;
1346  
1347                      case 'MP42':
1348                      case 'MP43':
1349                      case 'MP4S':
1350                      case 'mp4s':
1351                          $thisfile_video['dataformat'] = 'asf';
1352                          $info['mime_type'] = 'video/x-ms-asf';
1353                          break;
1354  
1355                      default:
1356                          switch ($streamdata['type_raw']) {
1357                              case 1:
1358                                  if (strstr($this->TrimConvert($streamdata['name']), 'Windows Media')) {
1359                                      $thisfile_video['dataformat'] = 'wmv';
1360                                      if ($info['mime_type'] == 'video/x-ms-asf') {
1361                                          $info['mime_type'] = 'video/x-ms-wmv';
1362                                      }
1363                                  }
1364                                  break;
1365  
1366                              case 2:
1367                                  if (strstr($this->TrimConvert($streamdata['name']), 'Windows Media')) {
1368                                      $thisfile_audio['dataformat'] = 'wma';
1369                                      if ($info['mime_type'] == 'video/x-ms-asf') {
1370                                          $info['mime_type'] = 'audio/x-ms-wma';
1371                                      }
1372                                  }
1373                                  break;
1374  
1375                          }
1376                          break;
1377                  }
1378              }
1379          }
1380  
1381          switch (isset($thisfile_audio['codec']) ? $thisfile_audio['codec'] : '') {
1382              case 'MPEG Layer-3':
1383                  $thisfile_audio['dataformat'] = 'mp3';
1384                  break;
1385  
1386              default:
1387                  break;
1388          }
1389  
1390          if (isset($thisfile_asf_codeclistobject['codec_entries'])) {
1391              foreach ($thisfile_asf_codeclistobject['codec_entries'] as $streamnumber => $streamdata) {
1392                  switch ($streamdata['type_raw']) {
1393  
1394                      case 1: // video
1395                          $thisfile_video['encoder'] = $this->TrimConvert($thisfile_asf_codeclistobject['codec_entries'][$streamnumber]['name']);
1396                          break;
1397  
1398                      case 2: // audio
1399                          $thisfile_audio['encoder'] = $this->TrimConvert($thisfile_asf_codeclistobject['codec_entries'][$streamnumber]['name']);
1400  
1401                          // AH 2003-10-01
1402                          $thisfile_audio['encoder_options'] = $this->TrimConvert($thisfile_asf_codeclistobject['codec_entries'][0]['description']);
1403  
1404                          $thisfile_audio['codec']   = $thisfile_audio['encoder'];
1405                          break;
1406  
1407                      default:
1408                          $this->warning('Unknown streamtype: [codec_list_object][codec_entries]['.$streamnumber.'][type_raw] == '.$streamdata['type_raw']);
1409                          break;
1410  
1411                  }
1412              }
1413          }
1414  
1415          if (isset($info['audio'])) {
1416              $thisfile_audio['lossless']           = (isset($thisfile_audio['lossless'])           ? $thisfile_audio['lossless']           : false);
1417              $thisfile_audio['dataformat']         = (!empty($thisfile_audio['dataformat'])        ? $thisfile_audio['dataformat']         : 'asf');
1418          }
1419          if (!empty($thisfile_video['dataformat'])) {
1420              $thisfile_video['lossless']           = (isset($thisfile_audio['lossless'])           ? $thisfile_audio['lossless']           : false);
1421              $thisfile_video['pixel_aspect_ratio'] = (isset($thisfile_audio['pixel_aspect_ratio']) ? $thisfile_audio['pixel_aspect_ratio'] : (float) 1);
1422              $thisfile_video['dataformat']         = (!empty($thisfile_video['dataformat'])        ? $thisfile_video['dataformat']         : 'asf');
1423          }
1424          if (!empty($thisfile_video['streams'])) {
1425              $thisfile_video['resolution_x'] = 0;
1426              $thisfile_video['resolution_y'] = 0;
1427              foreach ($thisfile_video['streams'] as $key => $valuearray) {
1428                  if (($valuearray['resolution_x'] > $thisfile_video['resolution_x']) || ($valuearray['resolution_y'] > $thisfile_video['resolution_y'])) {
1429                      $thisfile_video['resolution_x'] = $valuearray['resolution_x'];
1430                      $thisfile_video['resolution_y'] = $valuearray['resolution_y'];
1431                  }
1432              }
1433          }
1434          $info['bitrate'] = (isset($thisfile_audio['bitrate']) ? $thisfile_audio['bitrate'] : 0) + (isset($thisfile_video['bitrate']) ? $thisfile_video['bitrate'] : 0);
1435  
1436          if ((!isset($info['playtime_seconds']) || ($info['playtime_seconds'] <= 0)) && ($info['bitrate'] > 0)) {
1437              $info['playtime_seconds'] = ($info['filesize'] - $info['avdataoffset']) / ($info['bitrate'] / 8);
1438          }
1439  
1440          return true;
1441      }
1442  
1443  	public static function codecListObjectTypeLookup($CodecListType) {
1444          static $lookup = array(
1445              0x0001 => 'Video Codec',
1446              0x0002 => 'Audio Codec',
1447              0xFFFF => 'Unknown Codec'
1448          );
1449  
1450          return (isset($lookup[$CodecListType]) ? $lookup[$CodecListType] : 'Invalid Codec Type');
1451      }
1452  
1453  	public static function KnownGUIDs() {
1454          static $GUIDarray = array(
1455              'GETID3_ASF_Extended_Stream_Properties_Object'   => '14E6A5CB-C672-4332-8399-A96952065B5A',
1456              'GETID3_ASF_Padding_Object'                      => '1806D474-CADF-4509-A4BA-9AABCB96AAE8',
1457              'GETID3_ASF_Payload_Ext_Syst_Pixel_Aspect_Ratio' => '1B1EE554-F9EA-4BC8-821A-376B74E4C4B8',
1458              'GETID3_ASF_Script_Command_Object'               => '1EFB1A30-0B62-11D0-A39B-00A0C90348F6',
1459              'GETID3_ASF_No_Error_Correction'                 => '20FB5700-5B55-11CF-A8FD-00805F5C442B',
1460              'GETID3_ASF_Content_Branding_Object'             => '2211B3FA-BD23-11D2-B4B7-00A0C955FC6E',
1461              'GETID3_ASF_Content_Encryption_Object'           => '2211B3FB-BD23-11D2-B4B7-00A0C955FC6E',
1462              'GETID3_ASF_Digital_Signature_Object'            => '2211B3FC-BD23-11D2-B4B7-00A0C955FC6E',
1463              'GETID3_ASF_Extended_Content_Encryption_Object'  => '298AE614-2622-4C17-B935-DAE07EE9289C',
1464              'GETID3_ASF_Simple_Index_Object'                 => '33000890-E5B1-11CF-89F4-00A0C90349CB',
1465              'GETID3_ASF_Degradable_JPEG_Media'               => '35907DE0-E415-11CF-A917-00805F5C442B',
1466              'GETID3_ASF_Payload_Extension_System_Timecode'   => '399595EC-8667-4E2D-8FDB-98814CE76C1E',
1467              'GETID3_ASF_Binary_Media'                        => '3AFB65E2-47EF-40F2-AC2C-70A90D71D343',
1468              'GETID3_ASF_Timecode_Index_Object'               => '3CB73FD0-0C4A-4803-953D-EDF7B6228F0C',
1469              'GETID3_ASF_Metadata_Library_Object'             => '44231C94-9498-49D1-A141-1D134E457054',
1470              'GETID3_ASF_Reserved_3'                          => '4B1ACBE3-100B-11D0-A39B-00A0C90348F6',
1471              'GETID3_ASF_Reserved_4'                          => '4CFEDB20-75F6-11CF-9C0F-00A0C90349CB',
1472              'GETID3_ASF_Command_Media'                       => '59DACFC0-59E6-11D0-A3AC-00A0C90348F6',
1473              'GETID3_ASF_Header_Extension_Object'             => '5FBF03B5-A92E-11CF-8EE3-00C00C205365',
1474              'GETID3_ASF_Media_Object_Index_Parameters_Obj'   => '6B203BAD-3F11-4E84-ACA8-D7613DE2CFA7',
1475              'GETID3_ASF_Header_Object'                       => '75B22630-668E-11CF-A6D9-00AA0062CE6C',
1476              'GETID3_ASF_Content_Description_Object'          => '75B22633-668E-11CF-A6D9-00AA0062CE6C',
1477              'GETID3_ASF_Error_Correction_Object'             => '75B22635-668E-11CF-A6D9-00AA0062CE6C',
1478              'GETID3_ASF_Data_Object'                         => '75B22636-668E-11CF-A6D9-00AA0062CE6C',
1479              'GETID3_ASF_Web_Stream_Media_Subtype'            => '776257D4-C627-41CB-8F81-7AC7FF1C40CC',
1480              'GETID3_ASF_Stream_Bitrate_Properties_Object'    => '7BF875CE-468D-11D1-8D82-006097C9A2B2',
1481              'GETID3_ASF_Language_List_Object'                => '7C4346A9-EFE0-4BFC-B229-393EDE415C85',
1482              'GETID3_ASF_Codec_List_Object'                   => '86D15240-311D-11D0-A3A4-00A0C90348F6',
1483              'GETID3_ASF_Reserved_2'                          => '86D15241-311D-11D0-A3A4-00A0C90348F6',
1484              'GETID3_ASF_File_Properties_Object'              => '8CABDCA1-A947-11CF-8EE4-00C00C205365',
1485              'GETID3_ASF_File_Transfer_Media'                 => '91BD222C-F21C-497A-8B6D-5AA86BFC0185',
1486              'GETID3_ASF_Old_RTP_Extension_Data'              => '96800C63-4C94-11D1-837B-0080C7A37F95',
1487              'GETID3_ASF_Advanced_Mutual_Exclusion_Object'    => 'A08649CF-4775-4670-8A16-6E35357566CD',
1488              'GETID3_ASF_Bandwidth_Sharing_Object'            => 'A69609E6-517B-11D2-B6AF-00C04FD908E9',
1489              'GETID3_ASF_Reserved_1'                          => 'ABD3D211-A9BA-11cf-8EE6-00C00C205365',
1490              'GETID3_ASF_Bandwidth_Sharing_Exclusive'         => 'AF6060AA-5197-11D2-B6AF-00C04FD908E9',
1491              'GETID3_ASF_Bandwidth_Sharing_Partial'           => 'AF6060AB-5197-11D2-B6AF-00C04FD908E9',
1492              'GETID3_ASF_JFIF_Media'                          => 'B61BE100-5B4E-11CF-A8FD-00805F5C442B',
1493              'GETID3_ASF_Stream_Properties_Object'            => 'B7DC0791-A9B7-11CF-8EE6-00C00C205365',
1494              'GETID3_ASF_Video_Media'                         => 'BC19EFC0-5B4D-11CF-A8FD-00805F5C442B',
1495              'GETID3_ASF_Audio_Spread'                        => 'BFC3CD50-618F-11CF-8BB2-00AA00B4E220',
1496              'GETID3_ASF_Metadata_Object'                     => 'C5F8CBEA-5BAF-4877-8467-AA8C44FA4CCA',
1497              'GETID3_ASF_Payload_Ext_Syst_Sample_Duration'    => 'C6BD9450-867F-4907-83A3-C77921B733AD',
1498              'GETID3_ASF_Group_Mutual_Exclusion_Object'       => 'D1465A40-5A79-4338-B71B-E36B8FD6C249',
1499              'GETID3_ASF_Extended_Content_Description_Object' => 'D2D0A440-E307-11D2-97F0-00A0C95EA850',
1500              'GETID3_ASF_Stream_Prioritization_Object'        => 'D4FED15B-88D3-454F-81F0-ED5C45999E24',
1501              'GETID3_ASF_Payload_Ext_System_Content_Type'     => 'D590DC20-07BC-436C-9CF7-F3BBFBF1A4DC',
1502              'GETID3_ASF_Old_File_Properties_Object'          => 'D6E229D0-35DA-11D1-9034-00A0C90349BE',
1503              'GETID3_ASF_Old_ASF_Header_Object'               => 'D6E229D1-35DA-11D1-9034-00A0C90349BE',
1504              'GETID3_ASF_Old_ASF_Data_Object'                 => 'D6E229D2-35DA-11D1-9034-00A0C90349BE',
1505              'GETID3_ASF_Index_Object'                        => 'D6E229D3-35DA-11D1-9034-00A0C90349BE',
1506              'GETID3_ASF_Old_Stream_Properties_Object'        => 'D6E229D4-35DA-11D1-9034-00A0C90349BE',
1507              'GETID3_ASF_Old_Content_Description_Object'      => 'D6E229D5-35DA-11D1-9034-00A0C90349BE',
1508              'GETID3_ASF_Old_Script_Command_Object'           => 'D6E229D6-35DA-11D1-9034-00A0C90349BE',
1509              'GETID3_ASF_Old_Marker_Object'                   => 'D6E229D7-35DA-11D1-9034-00A0C90349BE',
1510              'GETID3_ASF_Old_Component_Download_Object'       => 'D6E229D8-35DA-11D1-9034-00A0C90349BE',
1511              'GETID3_ASF_Old_Stream_Group_Object'             => 'D6E229D9-35DA-11D1-9034-00A0C90349BE',
1512              'GETID3_ASF_Old_Scalable_Object'                 => 'D6E229DA-35DA-11D1-9034-00A0C90349BE',
1513              'GETID3_ASF_Old_Prioritization_Object'           => 'D6E229DB-35DA-11D1-9034-00A0C90349BE',
1514              'GETID3_ASF_Bitrate_Mutual_Exclusion_Object'     => 'D6E229DC-35DA-11D1-9034-00A0C90349BE',
1515              'GETID3_ASF_Old_Inter_Media_Dependency_Object'   => 'D6E229DD-35DA-11D1-9034-00A0C90349BE',
1516              'GETID3_ASF_Old_Rating_Object'                   => 'D6E229DE-35DA-11D1-9034-00A0C90349BE',
1517              'GETID3_ASF_Index_Parameters_Object'             => 'D6E229DF-35DA-11D1-9034-00A0C90349BE',
1518              'GETID3_ASF_Old_Color_Table_Object'              => 'D6E229E0-35DA-11D1-9034-00A0C90349BE',
1519              'GETID3_ASF_Old_Language_List_Object'            => 'D6E229E1-35DA-11D1-9034-00A0C90349BE',
1520              'GETID3_ASF_Old_Audio_Media'                     => 'D6E229E2-35DA-11D1-9034-00A0C90349BE',
1521              'GETID3_ASF_Old_Video_Media'                     => 'D6E229E3-35DA-11D1-9034-00A0C90349BE',
1522              'GETID3_ASF_Old_Image_Media'                     => 'D6E229E4-35DA-11D1-9034-00A0C90349BE',
1523              'GETID3_ASF_Old_Timecode_Media'                  => 'D6E229E5-35DA-11D1-9034-00A0C90349BE',
1524              'GETID3_ASF_Old_Text_Media'                      => 'D6E229E6-35DA-11D1-9034-00A0C90349BE',
1525              'GETID3_ASF_Old_MIDI_Media'                      => 'D6E229E7-35DA-11D1-9034-00A0C90349BE',
1526              'GETID3_ASF_Old_Command_Media'                   => 'D6E229E8-35DA-11D1-9034-00A0C90349BE',
1527              'GETID3_ASF_Old_No_Error_Concealment'            => 'D6E229EA-35DA-11D1-9034-00A0C90349BE',
1528              'GETID3_ASF_Old_Scrambled_Audio'                 => 'D6E229EB-35DA-11D1-9034-00A0C90349BE',
1529              'GETID3_ASF_Old_No_Color_Table'                  => 'D6E229EC-35DA-11D1-9034-00A0C90349BE',
1530              'GETID3_ASF_Old_SMPTE_Time'                      => 'D6E229ED-35DA-11D1-9034-00A0C90349BE',
1531              'GETID3_ASF_Old_ASCII_Text'                      => 'D6E229EE-35DA-11D1-9034-00A0C90349BE',
1532              'GETID3_ASF_Old_Unicode_Text'                    => 'D6E229EF-35DA-11D1-9034-00A0C90349BE',
1533              'GETID3_ASF_Old_HTML_Text'                       => 'D6E229F0-35DA-11D1-9034-00A0C90349BE',
1534              'GETID3_ASF_Old_URL_Command'                     => 'D6E229F1-35DA-11D1-9034-00A0C90349BE',
1535              'GETID3_ASF_Old_Filename_Command'                => 'D6E229F2-35DA-11D1-9034-00A0C90349BE',
1536              'GETID3_ASF_Old_ACM_Codec'                       => 'D6E229F3-35DA-11D1-9034-00A0C90349BE',
1537              'GETID3_ASF_Old_VCM_Codec'                       => 'D6E229F4-35DA-11D1-9034-00A0C90349BE',
1538              'GETID3_ASF_Old_QuickTime_Codec'                 => 'D6E229F5-35DA-11D1-9034-00A0C90349BE',
1539              'GETID3_ASF_Old_DirectShow_Transform_Filter'     => 'D6E229F6-35DA-11D1-9034-00A0C90349BE',
1540              'GETID3_ASF_Old_DirectShow_Rendering_Filter'     => 'D6E229F7-35DA-11D1-9034-00A0C90349BE',
1541              'GETID3_ASF_Old_No_Enhancement'                  => 'D6E229F8-35DA-11D1-9034-00A0C90349BE',
1542              'GETID3_ASF_Old_Unknown_Enhancement_Type'        => 'D6E229F9-35DA-11D1-9034-00A0C90349BE',
1543              'GETID3_ASF_Old_Temporal_Enhancement'            => 'D6E229FA-35DA-11D1-9034-00A0C90349BE',
1544              'GETID3_ASF_Old_Spatial_Enhancement'             => 'D6E229FB-35DA-11D1-9034-00A0C90349BE',
1545              'GETID3_ASF_Old_Quality_Enhancement'             => 'D6E229FC-35DA-11D1-9034-00A0C90349BE',
1546              'GETID3_ASF_Old_Number_of_Channels_Enhancement'  => 'D6E229FD-35DA-11D1-9034-00A0C90349BE',
1547              'GETID3_ASF_Old_Frequency_Response_Enhancement'  => 'D6E229FE-35DA-11D1-9034-00A0C90349BE',
1548              'GETID3_ASF_Old_Media_Object'                    => 'D6E229FF-35DA-11D1-9034-00A0C90349BE',
1549              'GETID3_ASF_Mutex_Language'                      => 'D6E22A00-35DA-11D1-9034-00A0C90349BE',
1550              'GETID3_ASF_Mutex_Bitrate'                       => 'D6E22A01-35DA-11D1-9034-00A0C90349BE',
1551              'GETID3_ASF_Mutex_Unknown'                       => 'D6E22A02-35DA-11D1-9034-00A0C90349BE',
1552              'GETID3_ASF_Old_ASF_Placeholder_Object'          => 'D6E22A0E-35DA-11D1-9034-00A0C90349BE',
1553              'GETID3_ASF_Old_Data_Unit_Extension_Object'      => 'D6E22A0F-35DA-11D1-9034-00A0C90349BE',
1554              'GETID3_ASF_Web_Stream_Format'                   => 'DA1E6B13-8359-4050-B398-388E965BF00C',
1555              'GETID3_ASF_Payload_Ext_System_File_Name'        => 'E165EC0E-19ED-45D7-B4A7-25CBD1E28E9B',
1556              'GETID3_ASF_Marker_Object'                       => 'F487CD01-A951-11CF-8EE6-00C00C205365',
1557              'GETID3_ASF_Timecode_Index_Parameters_Object'    => 'F55E496D-9797-4B5D-8C8B-604DFE9BFB24',
1558              'GETID3_ASF_Audio_Media'                         => 'F8699E40-5B4D-11CF-A8FD-00805F5C442B',
1559              'GETID3_ASF_Media_Object_Index_Object'           => 'FEB103F8-12AD-4C64-840F-2A1D2F7AD48C',
1560              'GETID3_ASF_Alt_Extended_Content_Encryption_Obj' => 'FF889EF1-ADEE-40DA-9E71-98704BB928CE',
1561              'GETID3_ASF_Index_Placeholder_Object'            => 'D9AADE20-7C17-4F9C-BC28-8555DD98E2A2', // http://cpan.uwinnipeg.ca/htdocs/Audio-WMA/Audio/WMA.pm.html
1562              'GETID3_ASF_Compatibility_Object'                => '26F18B5D-4584-47EC-9F5F-0E651F0452C9', // http://cpan.uwinnipeg.ca/htdocs/Audio-WMA/Audio/WMA.pm.html
1563          );
1564          return $GUIDarray;
1565      }
1566  
1567  	public static function GUIDname($GUIDstring) {
1568          static $GUIDarray = array();
1569          if (empty($GUIDarray)) {
1570              $GUIDarray = self::KnownGUIDs();
1571          }
1572          return array_search($GUIDstring, $GUIDarray);
1573      }
1574  
1575  	public static function ASFIndexObjectIndexTypeLookup($id) {
1576          static $ASFIndexObjectIndexTypeLookup = array();
1577          if (empty($ASFIndexObjectIndexTypeLookup)) {
1578              $ASFIndexObjectIndexTypeLookup[1] = 'Nearest Past Data Packet';
1579              $ASFIndexObjectIndexTypeLookup[2] = 'Nearest Past Media Object';
1580              $ASFIndexObjectIndexTypeLookup[3] = 'Nearest Past Cleanpoint';
1581          }
1582          return (isset($ASFIndexObjectIndexTypeLookup[$id]) ? $ASFIndexObjectIndexTypeLookup[$id] : 'invalid');
1583      }
1584  
1585  	public static function GUIDtoBytestring($GUIDstring) {
1586          // Microsoft defines these 16-byte (128-bit) GUIDs in the strangest way:
1587          // first 4 bytes are in little-endian order
1588          // next 2 bytes are appended in little-endian order
1589          // next 2 bytes are appended in little-endian order
1590          // next 2 bytes are appended in big-endian order
1591          // next 6 bytes are appended in big-endian order
1592  
1593          // AaBbCcDd-EeFf-GgHh-IiJj-KkLlMmNnOoPp is stored as this 16-byte string:
1594          // $Dd $Cc $Bb $Aa $Ff $Ee $Hh $Gg $Ii $Jj $Kk $Ll $Mm $Nn $Oo $Pp
1595  
1596          $hexbytecharstring  = chr(hexdec(substr($GUIDstring,  6, 2)));
1597          $hexbytecharstring .= chr(hexdec(substr($GUIDstring,  4, 2)));
1598          $hexbytecharstring .= chr(hexdec(substr($GUIDstring,  2, 2)));
1599          $hexbytecharstring .= chr(hexdec(substr($GUIDstring,  0, 2)));
1600  
1601          $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 11, 2)));
1602          $hexbytecharstring .= chr(hexdec(substr($GUIDstring,  9, 2)));
1603  
1604          $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 16, 2)));
1605          $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 14, 2)));
1606  
1607          $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 19, 2)));
1608          $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 21, 2)));
1609  
1610          $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 24, 2)));
1611          $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 26, 2)));
1612          $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 28, 2)));
1613          $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 30, 2)));
1614          $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 32, 2)));
1615          $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 34, 2)));
1616  
1617          return $hexbytecharstring;
1618      }
1619  
1620  	public static function BytestringToGUID($Bytestring) {
1621          $GUIDstring  = str_pad(dechex(ord($Bytestring{3})),  2, '0', STR_PAD_LEFT);
1622          $GUIDstring .= str_pad(dechex(ord($Bytestring{2})),  2, '0', STR_PAD_LEFT);
1623          $GUIDstring .= str_pad(dechex(ord($Bytestring{1})),  2, '0', STR_PAD_LEFT);
1624          $GUIDstring .= str_pad(dechex(ord($Bytestring{0})),  2, '0', STR_PAD_LEFT);
1625          $GUIDstring .= '-';
1626          $GUIDstring .= str_pad(dechex(ord($Bytestring{5})),  2, '0', STR_PAD_LEFT);
1627          $GUIDstring .= str_pad(dechex(ord($Bytestring{4})),  2, '0', STR_PAD_LEFT);
1628          $GUIDstring .= '-';
1629          $GUIDstring .= str_pad(dechex(ord($Bytestring{7})),  2, '0', STR_PAD_LEFT);
1630          $GUIDstring .= str_pad(dechex(ord($Bytestring{6})),  2, '0', STR_PAD_LEFT);
1631          $GUIDstring .= '-';
1632          $GUIDstring .= str_pad(dechex(ord($Bytestring{8})),  2, '0', STR_PAD_LEFT);
1633          $GUIDstring .= str_pad(dechex(ord($Bytestring{9})),  2, '0', STR_PAD_LEFT);
1634          $GUIDstring .= '-';
1635          $GUIDstring .= str_pad(dechex(ord($Bytestring{10})), 2, '0', STR_PAD_LEFT);
1636          $GUIDstring .= str_pad(dechex(ord($Bytestring{11})), 2, '0', STR_PAD_LEFT);
1637          $GUIDstring .= str_pad(dechex(ord($Bytestring{12})), 2, '0', STR_PAD_LEFT);
1638          $GUIDstring .= str_pad(dechex(ord($Bytestring{13})), 2, '0', STR_PAD_LEFT);
1639          $GUIDstring .= str_pad(dechex(ord($Bytestring{14})), 2, '0', STR_PAD_LEFT);
1640          $GUIDstring .= str_pad(dechex(ord($Bytestring{15})), 2, '0', STR_PAD_LEFT);
1641  
1642          return strtoupper($GUIDstring);
1643      }
1644  
1645  	public static function FILETIMEtoUNIXtime($FILETIME, $round=true) {
1646          // FILETIME is a 64-bit unsigned integer representing
1647          // the number of 100-nanosecond intervals since January 1, 1601
1648          // UNIX timestamp is number of seconds since January 1, 1970
1649          // 116444736000000000 = 10000000 * 60 * 60 * 24 * 365 * 369 + 89 leap days
1650          if ($round) {
1651              return intval(round(($FILETIME - 116444736000000000) / 10000000));
1652          }
1653          return ($FILETIME - 116444736000000000) / 10000000;
1654      }
1655  
1656  	public static function WMpictureTypeLookup($WMpictureType) {
1657          static $lookup = null;
1658          if ($lookup === null) {
1659              $lookup = array(
1660                  0x03 => 'Front Cover',
1661                  0x04 => 'Back Cover',
1662                  0x00 => 'User Defined',
1663                  0x05 => 'Leaflet Page',
1664                  0x06 => 'Media Label',
1665                  0x07 => 'Lead Artist',
1666                  0x08 => 'Artist',
1667                  0x09 => 'Conductor',
1668                  0x0A => 'Band',
1669                  0x0B => 'Composer',
1670                  0x0C => 'Lyricist',
1671                  0x0D => 'Recording Location',
1672                  0x0E => 'During Recording',
1673                  0x0F => 'During Performance',
1674                  0x10 => 'Video Screen Capture',
1675                  0x12 => 'Illustration',
1676                  0x13 => 'Band Logotype',
1677                  0x14 => 'Publisher Logotype'
1678              );
1679              $lookup = array_map(function($str) {
1680                  return getid3_lib::iconv_fallback('UTF-8', 'UTF-16LE', $str);
1681              }, $lookup);
1682          }
1683  
1684          return (isset($lookup[$WMpictureType]) ? $lookup[$WMpictureType] : '');
1685      }
1686  
1687  	public function HeaderExtensionObjectDataParse(&$asf_header_extension_object_data, &$unhandled_sections) {
1688          // http://msdn.microsoft.com/en-us/library/bb643323.aspx
1689  
1690          $offset = 0;
1691          $objectOffset = 0;
1692          $HeaderExtensionObjectParsed = array();
1693          while ($objectOffset < strlen($asf_header_extension_object_data)) {
1694              $offset = $objectOffset;
1695              $thisObject = array();
1696  
1697              $thisObject['guid']                              =                              substr($asf_header_extension_object_data, $offset, 16);
1698              $offset += 16;
1699              $thisObject['guid_text'] = $this->BytestringToGUID($thisObject['guid']);
1700              $thisObject['guid_name'] = $this->GUIDname($thisObject['guid_text']);
1701  
1702              $thisObject['size']                              = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  8));
1703              $offset += 8;
1704              if ($thisObject['size'] <= 0) {
1705                  break;
1706              }
1707  
1708              switch ($thisObject['guid']) {
1709                  case GETID3_ASF_Extended_Stream_Properties_Object:
1710                      $thisObject['start_time']                        = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  8));
1711                      $offset += 8;
1712                      $thisObject['start_time_unix']                   = $this->FILETIMEtoUNIXtime($thisObject['start_time']);
1713  
1714                      $thisObject['end_time']                          = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  8));
1715                      $offset += 8;
1716                      $thisObject['end_time_unix']                     = $this->FILETIMEtoUNIXtime($thisObject['end_time']);
1717  
1718                      $thisObject['data_bitrate']                      = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
1719                      $offset += 4;
1720  
1721                      $thisObject['buffer_size']                       = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
1722                      $offset += 4;
1723  
1724                      $thisObject['initial_buffer_fullness']           = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
1725                      $offset += 4;
1726  
1727                      $thisObject['alternate_data_bitrate']            = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
1728                      $offset += 4;
1729  
1730                      $thisObject['alternate_buffer_size']             = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
1731                      $offset += 4;
1732  
1733                      $thisObject['alternate_initial_buffer_fullness'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
1734                      $offset += 4;
1735  
1736                      $thisObject['maximum_object_size']               = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
1737                      $offset += 4;
1738  
1739                      $thisObject['flags_raw']                         = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
1740                      $offset += 4;
1741                      $thisObject['flags']['reliable']                = (bool) $thisObject['flags_raw'] & 0x00000001;
1742                      $thisObject['flags']['seekable']                = (bool) $thisObject['flags_raw'] & 0x00000002;
1743                      $thisObject['flags']['no_cleanpoints']          = (bool) $thisObject['flags_raw'] & 0x00000004;
1744                      $thisObject['flags']['resend_live_cleanpoints'] = (bool) $thisObject['flags_raw'] & 0x00000008;
1745  
1746                      $thisObject['stream_number']                     = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
1747                      $offset += 2;
1748  
1749                      $thisObject['stream_language_id_index']          = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
1750                      $offset += 2;
1751  
1752                      $thisObject['average_time_per_frame']            = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
1753                      $offset += 4;
1754  
1755                      $thisObject['stream_name_count']                 = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
1756                      $offset += 2;
1757  
1758                      $thisObject['payload_extension_system_count']    = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
1759                      $offset += 2;
1760  
1761                      for ($i = 0; $i < $thisObject['stream_name_count']; $i++) {
1762                          $streamName = array();
1763  
1764                          $streamName['language_id_index']             = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
1765                          $offset += 2;
1766  
1767                          $streamName['stream_name_length']            = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
1768                          $offset += 2;
1769  
1770                          $streamName['stream_name']                   = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  $streamName['stream_name_length']));
1771                          $offset += $streamName['stream_name_length'];
1772  
1773                          $thisObject['stream_names'][$i] = $streamName;
1774                      }
1775  
1776                      for ($i = 0; $i < $thisObject['payload_extension_system_count']; $i++) {
1777                          $payloadExtensionSystem = array();
1778  
1779                          $payloadExtensionSystem['extension_system_id']   =                              substr($asf_header_extension_object_data, $offset, 16);
1780                          $offset += 16;
1781                          $payloadExtensionSystem['extension_system_id_text'] = $this->BytestringToGUID($payloadExtensionSystem['extension_system_id']);
1782  
1783                          $payloadExtensionSystem['extension_system_size'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
1784                          $offset += 2;
1785                          if ($payloadExtensionSystem['extension_system_size'] <= 0) {
1786                              break 2;
1787                          }
1788  
1789                          $payloadExtensionSystem['extension_system_info_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
1790                          $offset += 4;
1791  
1792                          $payloadExtensionSystem['extension_system_info_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  $payloadExtensionSystem['extension_system_info_length']));
1793                          $offset += $payloadExtensionSystem['extension_system_info_length'];
1794  
1795                          $thisObject['payload_extension_systems'][$i] = $payloadExtensionSystem;
1796                      }
1797  
1798                      break;
1799  
1800                  case GETID3_ASF_Padding_Object:
1801                      // padding, skip it
1802                      break;
1803  
1804                  case GETID3_ASF_Metadata_Object:
1805                      $thisObject['description_record_counts'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
1806                      $offset += 2;
1807  
1808                      for ($i = 0; $i < $thisObject['description_record_counts']; $i++) {
1809                          $descriptionRecord = array();
1810  
1811                          $descriptionRecord['reserved_1']         = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2)); // must be zero
1812                          $offset += 2;
1813  
1814                          $descriptionRecord['stream_number']      = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
1815                          $offset += 2;
1816  
1817                          $descriptionRecord['name_length']        = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
1818                          $offset += 2;
1819  
1820                          $descriptionRecord['data_type']          = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
1821                          $offset += 2;
1822                          $descriptionRecord['data_type_text'] = self::metadataLibraryObjectDataTypeLookup($descriptionRecord['data_type']);
1823  
1824                          $descriptionRecord['data_length']        = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
1825                          $offset += 4;
1826  
1827                          $descriptionRecord['name']               =                              substr($asf_header_extension_object_data, $offset,  $descriptionRecord['name_length']);
1828                          $offset += $descriptionRecord['name_length'];
1829  
1830                          $descriptionRecord['data']               =                              substr($asf_header_extension_object_data, $offset,  $descriptionRecord['data_length']);
1831                          $offset += $descriptionRecord['data_length'];
1832                          switch ($descriptionRecord['data_type']) {
1833                              case 0x0000: // Unicode string
1834                                  break;
1835  
1836                              case 0x0001: // BYTE array
1837                                  // do nothing
1838                                  break;
1839  
1840                              case 0x0002: // BOOL
1841                                  $descriptionRecord['data'] = (bool) getid3_lib::LittleEndian2Int($descriptionRecord['data']);
1842                                  break;
1843  
1844                              case 0x0003: // DWORD
1845                              case 0x0004: // QWORD
1846                              case 0x0005: // WORD
1847                                  $descriptionRecord['data'] = getid3_lib::LittleEndian2Int($descriptionRecord['data']);
1848                                  break;
1849  
1850                              case 0x0006: // GUID
1851                                  $descriptionRecord['data_text'] = $this->BytestringToGUID($descriptionRecord['data']);
1852                                  break;
1853                          }
1854  
1855                          $thisObject['description_record'][$i] = $descriptionRecord;
1856                      }
1857                      break;
1858  
1859                  case GETID3_ASF_Language_List_Object:
1860                      $thisObject['language_id_record_counts'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
1861                      $offset += 2;
1862  
1863                      for ($i = 0; $i < $thisObject['language_id_record_counts']; $i++) {
1864                          $languageIDrecord = array();
1865  
1866                          $languageIDrecord['language_id_length']         = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  1));
1867                          $offset += 1;
1868  
1869                          $languageIDrecord['language_id']                =                              substr($asf_header_extension_object_data, $offset,  $languageIDrecord['language_id_length']);
1870                          $offset += $languageIDrecord['language_id_length'];
1871  
1872                          $thisObject['language_id_record'][$i] = $languageIDrecord;
1873                      }
1874                      break;
1875  
1876                  case GETID3_ASF_Metadata_Library_Object:
1877                      $thisObject['description_records_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
1878                      $offset += 2;
1879  
1880                      for ($i = 0; $i < $thisObject['description_records_count']; $i++) {
1881                          $descriptionRecord = array();
1882  
1883                          $descriptionRecord['language_list_index'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
1884                          $offset += 2;
1885  
1886                          $descriptionRecord['stream_number']       = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
1887                          $offset += 2;
1888  
1889                          $descriptionRecord['name_length']         = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
1890                          $offset += 2;
1891  
1892                          $descriptionRecord['data_type']           = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
1893                          $offset += 2;
1894                          $descriptionRecord['data_type_text'] = self::metadataLibraryObjectDataTypeLookup($descriptionRecord['data_type']);
1895  
1896                          $descriptionRecord['data_length']         = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
1897                          $offset += 4;
1898  
1899                          $descriptionRecord['name']                =                              substr($asf_header_extension_object_data, $offset,  $descriptionRecord['name_length']);
1900                          $offset += $descriptionRecord['name_length'];
1901  
1902                          $descriptionRecord['data']                =                              substr($asf_header_extension_object_data, $offset,  $descriptionRecord['data_length']);
1903                          $offset += $descriptionRecord['data_length'];
1904  
1905                          if (preg_match('#^WM/Picture$#', str_replace("\x00", '', trim($descriptionRecord['name'])))) {
1906                              $WMpicture = $this->ASF_WMpicture($descriptionRecord['data']);
1907                              foreach ($WMpicture as $key => $value) {
1908                                  $descriptionRecord['data'] = $WMpicture;
1909                              }
1910                              unset($WMpicture);
1911                          }
1912  
1913                          $thisObject['description_record'][$i] = $descriptionRecord;
1914                      }
1915                      break;
1916  
1917                  default:
1918                      $unhandled_sections++;
1919                      if ($this->GUIDname($thisObject['guid_text'])) {
1920                          $this->warning('unhandled Header Extension Object GUID "'.$this->GUIDname($thisObject['guid_text']).'" {'.$thisObject['guid_text'].'} at offset '.($offset - 16 - 8));
1921                      } else {
1922                          $this->warning('unknown Header Extension Object GUID {'.$thisObject['guid_text'].'} in at offset '.($offset - 16 - 8));
1923                      }
1924                      break;
1925              }
1926              $HeaderExtensionObjectParsed[] = $thisObject;
1927  
1928              $objectOffset += $thisObject['size'];
1929          }
1930          return $HeaderExtensionObjectParsed;
1931      }
1932  
1933  
1934  	public static function metadataLibraryObjectDataTypeLookup($id) {
1935          static $lookup = array(
1936              0x0000 => 'Unicode string', // The data consists of a sequence of Unicode characters
1937              0x0001 => 'BYTE array',     // The type of the data is implementation-specific
1938              0x0002 => 'BOOL',           // The data is 2 bytes long and should be interpreted as a 16-bit unsigned integer. Only 0x0000 or 0x0001 are permitted values
1939              0x0003 => 'DWORD',          // The data is 4 bytes long and should be interpreted as a 32-bit unsigned integer
1940              0x0004 => 'QWORD',          // The data is 8 bytes long and should be interpreted as a 64-bit unsigned integer
1941              0x0005 => 'WORD',           // The data is 2 bytes long and should be interpreted as a 16-bit unsigned integer
1942              0x0006 => 'GUID',           // The data is 16 bytes long and should be interpreted as a 128-bit GUID
1943          );
1944          return (isset($lookup[$id]) ? $lookup[$id] : 'invalid');
1945      }
1946  
1947  	public function ASF_WMpicture(&$data) {
1948          //typedef struct _WMPicture{
1949          //  LPWSTR  pwszMIMEType;
1950          //  BYTE  bPictureType;
1951          //  LPWSTR  pwszDescription;
1952          //  DWORD  dwDataLen;
1953          //  BYTE*  pbData;
1954          //} WM_PICTURE;
1955  
1956          $WMpicture = array();
1957  
1958          $offset = 0;
1959          $WMpicture['image_type_id'] = getid3_lib::LittleEndian2Int(substr($data, $offset, 1));
1960          $offset += 1;
1961          $WMpicture['image_type']    = self::WMpictureTypeLookup($WMpicture['image_type_id']);
1962          $WMpicture['image_size']    = getid3_lib::LittleEndian2Int(substr($data, $offset, 4));
1963          $offset += 4;
1964  
1965          $WMpicture['image_mime'] = '';
1966          do {
1967              $next_byte_pair = substr($data, $offset, 2);
1968              $offset += 2;
1969              $WMpicture['image_mime'] .= $next_byte_pair;
1970          } while ($next_byte_pair !== "\x00\x00");
1971  
1972          $WMpicture['image_description'] = '';
1973          do {
1974              $next_byte_pair = substr($data, $offset, 2);
1975              $offset += 2;
1976              $WMpicture['image_description'] .= $next_byte_pair;
1977          } while ($next_byte_pair !== "\x00\x00");
1978  
1979          $WMpicture['dataoffset'] = $offset;
1980          $WMpicture['data'] = substr($data, $offset);
1981  
1982          $imageinfo = array();
1983          $WMpicture['image_mime'] = '';
1984          $imagechunkcheck = getid3_lib::GetDataImageSize($WMpicture['data'], $imageinfo);
1985          unset($imageinfo);
1986          if (!empty($imagechunkcheck)) {
1987              $WMpicture['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]);
1988          }
1989          if (!isset($this->getid3->info['asf']['comments']['picture'])) {
1990              $this->getid3->info['asf']['comments']['picture'] = array();
1991          }
1992          $this->getid3->info['asf']['comments']['picture'][] = array('data'=>$WMpicture['data'], 'image_mime'=>$WMpicture['image_mime']);
1993  
1994          return $WMpicture;
1995      }
1996  
1997  
1998      // Remove terminator 00 00 and convert UTF-16LE to Latin-1
1999  	public static function TrimConvert($string) {
2000          return trim(getid3_lib::iconv_fallback('UTF-16LE', 'ISO-8859-1', self::TrimTerm($string)), ' ');
2001      }
2002  
2003  
2004      // Remove terminator 00 00
2005  	public static function TrimTerm($string) {
2006          // remove terminator, only if present (it should be, but...)
2007          if (substr($string, -2) === "\x00\x00") {
2008              $string = substr($string, 0, -2);
2009          }
2010          return $string;
2011      }
2012  
2013  }


Generated: Mon Jun 17 08:20:02 2019 Cross-referenced by PHPXref 0.7