[ Index ]

PHP Cross Reference of WordPress

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


Generated: Wed Sep 18 01:00:03 2019 Cross-referenced by PHPXref 0.7.1