<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net ///
// or http://www.getid3.org ///
/////////////////////////////////////////////////////////////////
// //
// getid3.asf.php - part of getID3() //
// See getid3.readme.txt for more details //
// //
/////////////////////////////////////////////////////////////////
$GUIDarray = KnownGUIDs();
foreach ($GUIDarray as $GUIDname => $hexstringvalue) {
// initialize all GUID constants
define($GUIDname, GUIDtoBytestring($hexstringvalue));
}
function getASFHeaderFilepointer(&$fd, &$ThisFileInfo) {
// ASF structure:
// * Header Object [required]
// * File Properties Object [required] (global file attributes)
// * Stream Properties Object [required] (defines media stream & characteristics)
// * Header Extension Object [required] (additional functionality)
// * Content Description Object (bibliographic information)
// * Script Command Object (commands for during playback)
// * Marker Object (named jumped points within the file)
// * Data Object [required]
// * Data Packets
// * Index Object
// Header Object: (mandatory, one only)
// Field Name Field Type Size (bits)
// Object ID GUID 128 // GUID for header object - ASF_Header_Object
// Object Size QWORD 64 // size of header object, including 30 bytes of Header Object header
// Number of Header Objects DWORD 32 // number of objects in header object
// Reserved1 BYTE 8 // hardcoded: 0x01
// Reserved2 BYTE 8 // hardcoded: 0x02
$ThisFileInfo['fileformat'] = 'asf';
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$HeaderObjectData = fread($fd, 30);
$ThisFileInfo['asf']['header_object']['objectid'] = substr($HeaderObjectData, 0, 16);
$ThisFileInfo['asf']['header_object']['objectid_guid'] = BytestringToGUID($ThisFileInfo['asf']['header_object']['objectid']);
if ($ThisFileInfo['asf']['header_object']['objectid'] != ASF_Header_Object) {
$ThisFileInfo['warning'] .= "\n".'ASF header GUID {'.BytestringToGUID($ThisFileInfo['asf']['header_object']['objectid']).'} does not match expected "ASF_Header_Object" GUID {'.BytestringToGUID(ASF_Header_Object).'}';
unset($ThisFileInfo['fileformat']);
unset($ThisFileInfo['asf']);
return false;
break;
}
$ThisFileInfo['asf']['header_object']['objectsize'] = LittleEndian2Int(substr($HeaderObjectData, 16, 8));
$ThisFileInfo['asf']['header_object']['headerobjects'] = LittleEndian2Int(substr($HeaderObjectData, 24, 4));
$ThisFileInfo['asf']['header_object']['reserved1'] = LittleEndian2Int(substr($HeaderObjectData, 28, 1));
$ThisFileInfo['asf']['header_object']['reserved2'] = LittleEndian2Int(substr($HeaderObjectData, 29, 1));
//$ASFHeaderData = $HeaderObjectData;
$ASFHeaderData = fread($fd, $ThisFileInfo['asf']['header_object']['objectsize'] - 30);
//$offset = 30;
$offset = 0;
for ($HeaderObjectsCounter = 0; $HeaderObjectsCounter < $ThisFileInfo['asf']['header_object']['headerobjects']; $HeaderObjectsCounter++) {
$NextObjectGUID = substr($ASFHeaderData, $offset, 16);
$offset += 16;
$NextObjectGUIDtext = BytestringToGUID($NextObjectGUID);
$NextObjectSize = LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
$offset += 8;
switch ($NextObjectGUID) {
case ASF_File_Properties_Object:
// File Properties Object: (mandatory, one only)
// Field Name Field Type Size (bits)
// Object ID GUID 128 // GUID for file properties object - ASF_File_Properties_Object
// Object Size QWORD 64 // size of file properties object, including 104 bytes of File Properties Object header
// File ID GUID 128 // unique ID - identical to File ID in Data Object
// File Size QWORD 64 // entire file in bytes. Invalid if Broadcast Flag == 1
// Creation Date QWORD 64 // date & time of file creation. Maybe invalid if Broadcast Flag == 1
// Data Packets Count QWORD 64 // number of data packets in Data Object. Invalid if Broadcast Flag == 1
// Play Duration QWORD 64 // playtime, in 100-nanosecond units. Invalid if Broadcast Flag == 1
// Send Duration QWORD 64 // time needed to send file, in 100-nanosecond units. Players can ignore this value. Invalid if Broadcast Flag == 1
// 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
// Flags DWORD 32 //
// * Broadcast Flag bits 1 (0x01) // file is currently being written, some header values are invalid
// * Seekable Flag bits 1 (0x02) // is file seekable
// * Reserved bits 30 (0xFFFFFFFC) // reserved - set to zero
// Minimum Data Packet Size DWORD 32 // in bytes. should be same as Maximum Data Packet Size. Invalid if Broadcast Flag == 1
// Maximum Data Packet Size DWORD 32 // in bytes. should be same as Minimum Data Packet Size. Invalid if Broadcast Flag == 1
// Maximum Bitrate DWORD 32 // maximum instantaneous bitrate in bits per second for entire file, including all data streams and ASF overhead
$ThisFileInfo['asf']['file_properties_object']['objectid'] = $NextObjectGUID;
$ThisFileInfo['asf']['file_properties_object']['objectid_guid'] = $NextObjectGUIDtext;
$ThisFileInfo['asf']['file_properties_object']['objectsize'] = $NextObjectSize;
$ThisFileInfo['asf']['file_properties_object']['fileid'] = substr($ASFHeaderData, $offset, 16);
$offset += 16;
$ThisFileInfo['asf']['file_properties_object']['fileid_guid'] = BytestringToGUID($ThisFileInfo['asf']['file_properties_object']['fileid']);
$ThisFileInfo['asf']['file_properties_object']['filesize'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
$offset += 8;
$ThisFileInfo['asf']['file_properties_object']['creation_date'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
$ThisFileInfo['asf']['file_properties_object']['creation_date_unix'] = FILETIMEtoUNIXtime($ThisFileInfo['asf']['file_properties_object']['creation_date']);
$offset += 8;
$ThisFileInfo['asf']['file_properties_object']['data_packets'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
$offset += 8;
$ThisFileInfo['asf']['file_properties_object']['play_duration'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
$offset += 8;
$ThisFileInfo['asf']['file_properties_object']['send_duration'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
$offset += 8;
$ThisFileInfo['asf']['file_properties_object']['preroll'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
$offset += 8;
$ThisFileInfo['playtime_seconds'] = ($ThisFileInfo['asf']['file_properties_object']['play_duration'] / 10000000) - ($ThisFileInfo['asf']['file_properties_object']['preroll'] / 1000);
$ThisFileInfo['asf']['file_properties_object']['flags_raw'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
$offset += 4;
$ThisFileInfo['asf']['file_properties_object']['flags']['broadcast'] = (bool) ($ThisFileInfo['asf']['file_properties_object']['flags_raw'] & 0x0001);
$ThisFileInfo['asf']['file_properties_object']['flags']['seekable'] = (bool) ($ThisFileInfo['asf']['file_properties_object']['flags_raw'] & 0x0002);
$ThisFileInfo['asf']['file_properties_object']['min_packet_size'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
$offset += 4;
$ThisFileInfo['asf']['file_properties_object']['max_packet_size'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
$offset += 4;
$ThisFileInfo['asf']['file_properties_object']['max_bitrate'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
$offset += 4;
$ThisFileInfo['bitrate'] = $ThisFileInfo['asf']['file_properties_object']['max_bitrate'];
break;
case ASF_Stream_Properties_Object:
// Stream Properties Object: (mandatory, one per media stream)
// Field Name Field Type Size (bits)
// Object ID GUID 128 // GUID for stream properties object - ASF_Stream_Properties_Object
// Object Size QWORD 64 // size of stream properties object, including 78 bytes of Stream Properties Object header
// Stream Type GUID 128 // ASF_Audio_Media, ASF_Video_Media or ASF_Command_Media
// Error Correction Type GUID 128 // ASF_Audio_Spread for audio-only streams, ASF_No_Error_Correction for other stream types
// Time Offset QWORD 64 // 100-nanosecond units. typically zero. added to all timestamps of samples in the stream
// Type-Specific Data Length DWORD 32 // number of bytes for Type-Specific Data field
// Error Correction Data Length DWORD 32 // number of bytes for Error Correction Data field
// Flags WORD 16 //
// * Stream Number bits 7 (0x007F) // number of this stream. 1 <= valid <= 127
// * Reserved bits 8 (0x7F80) // reserved - set to zero
// * Encrypted Content Flag bits 1 (0x8000) // stream contents encrypted if set
// Reserved DWORD 32 // reserved - set to zero
// Type-Specific Data BYTESTREAM variable // type-specific format data, depending on value of Stream Type
// Error Correction Data BYTESTREAM variable // error-correction-specific format data, depending on value of Error Correct Type
// There is one ASF_Stream_Properties_Object for each stream (audio, video) but the
// stream number isn't known until halfway through decoding the structure, hence it
// it is decoded to a temporary variable and then stuck in the appropriate index later
$StreamPropertiesObjectData['objectid'] = $NextObjectGUID;
$StreamPropertiesObjectData['objectid_guid'] = $NextObjectGUIDtext;
$StreamPropertiesObjectData['objectsize'] = $NextObjectSize;
$StreamPropertiesObjectData['stream_type'] = substr($ASFHeaderData, $offset, 16);
$offset += 16;
$StreamPropertiesObjectData['stream_type_guid'] = BytestringToGUID($StreamPropertiesObjectData['stream_type']);
$StreamPropertiesObjectData['error_correct_type'] = substr($ASFHeaderData, $offset, 16);
$offset += 16;
$StreamPropertiesObjectData['error_correct_guid'] = BytestringToGUID($StreamPropertiesObjectData['error_correct_type']);
$StreamPropertiesObjectData['time_offset'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
$offset += 8;
$StreamPropertiesObjectData['type_data_length'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
$offset += 4;
$StreamPropertiesObjectData['error_data_length'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
$offset += 4;
$StreamPropertiesObjectData['flags_raw'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
$offset += 2;
$StreamPropertiesObjectStreamNumber = $StreamPropertiesObjectData['flags_raw'] & 0x007F;
$StreamPropertiesObjectData['flags']['encrypted'] = (bool) ($StreamPropertiesObjectData['flags_raw'] & 0x8000);
$offset += 4; // reserved - DWORD
$StreamPropertiesObjectData['type_specific_data'] = substr($ASFHeaderData, $offset, $StreamPropertiesObjectData['type_data_length']);
$offset += $StreamPropertiesObjectData['type_data_length'];
$StreamPropertiesObjectData['error_correct_data'] = substr($ASFHeaderData, $offset, $StreamPropertiesObjectData['error_data_length']);
$offset += $StreamPropertiesObjectData['error_data_length'];
switch ($StreamPropertiesObjectData['stream_type']) {
case ASF_Audio_Media:
if (empty($ThisFileInfo['audio']['bitrate_mode'])) {
$ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
}
require_once(GETID3_INCLUDEPATH.'getid3.riff.php');
$audiodata = RIFFparseWAVEFORMATex(substr($StreamPropertiesObjectData['type_specific_data'], 0, 16));
unset($audiodata['raw']);
$ThisFileInfo['audio'] = array_merge_noclobber($audiodata, $ThisFileInfo['audio']);
break;
case ASF_Video_Media:
if (empty($ThisFileInfo['video']['bitrate_mode'])) {
$ThisFileInfo['video']['bitrate_mode'] = 'cbr';
}
break;
case ASF_Command_Media:
default:
// do nothing
break;
}
$ThisFileInfo['asf']['stream_properties_object'][$StreamPropertiesObjectStreamNumber] = $StreamPropertiesObjectData;
unset($StreamPropertiesObjectData); // clear for next stream, if any
break;
case ASF_Header_Extension_Object:
// Header Extension Object: (mandatory, one only)
// Field Name Field Type Size (bits)
// Object ID GUID 128 // GUID for Header Extension object - ASF_Header_Extension_Object
// Object Size QWORD 64 // size of Header Extension object, including 46 bytes of Header Extension Object header
// Reserved Field 1 GUID 128 // hardcoded: ASF_Reserved_1
// Reserved Field 2 WORD 16 // hardcoded: 0x00000006
// Header Extension Data Size DWORD 32 // in bytes. valid: 0, or > 24. equals object size minus 46
// Header Extension Data BYTESTREAM variable // array of zero or more extended header objects
$ThisFileInfo['asf']['header_extension_object']['objectid'] = $NextObjectGUID;
$ThisFileInfo['asf']['header_extension_object']['objectid_guid'] = $NextObjectGUIDtext;
$ThisFileInfo['asf']['header_extension_object']['objectsize'] = $NextObjectSize;
$ThisFileInfo['asf']['header_extension_object']['reserved_1'] = substr($ASFHeaderData, $offset, 16);
$offset += 16;
$ThisFileInfo['asf']['header_extension_object']['reserved_1_guid'] = BytestringToGUID($ThisFileInfo['asf']['header_extension_object']['reserved_1']);
if ($ThisFileInfo['asf']['header_extension_object']['reserved_1'] != ASF_Reserved_1) {
$ThisFileInfo['warning'] .= "\n".'header_extension_object.reserved_1 GUID ('.BytestringToGUID($ThisFileInfo['asf']['header_extension_object']['reserved_1']).') does not match expected "ASF_Reserved_1" GUID ('.BytestringToGUID(ASF_Reserved_1).')';
//return false;
break;
}
$ThisFileInfo['asf']['header_extension_object']['reserved_2'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
$offset += 2;
if ($ThisFileInfo['asf']['header_extension_object']['reserved_2'] != 6) {
$ThisFileInfo['warning'] .= "\n".'header_extension_object.reserved_2 ('.PrintHexBytes($ThisFileInfo['asf']['header_extension_object']['reserved_2']).') does not match expected value of "6"';
//return false;
break;
}
$ThisFileInfo['asf']['header_extension_object']['extension_data_size'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
$offset += 4;
$ThisFileInfo['asf']['header_extension_object']['extension_data'] = LittleEndian2Int(substr($ASFHeaderData, $offset, $ThisFileInfo['asf']['header_extension_object']['extension_data_size']));
$offset += $ThisFileInfo['asf']['header_extension_object']['extension_data_size'];
break;
case ASF_Codec_List_Object:
// Codec List Object: (optional, one only)
// Field Name Field Type Size (bits)
// Object ID GUID 128 // GUID for Codec List object - ASF_Codec_List_Object
// Object Size QWORD 64 // size of Codec List object, including 44 bytes of Codec List Object header
// Reserved GUID 128 // hardcoded: 86D15241-311D-11D0-A3A4-00A0C90348F6
// Codec Entries Count DWORD 32 // number of entries in Codec Entries array
// Codec Entries array of: variable //
// * Type WORD 16 // 0x0001 = Video Codec, 0x0002 = Audio Codec, 0xFFFF = Unknown Codec
// * Codec Name Length WORD 16 // number of Unicode characters stored in the Codec Name field
// * Codec Name WCHAR variable // array of Unicode characters - name of codec used to create the content
// * Codec Description Length WORD 16 // number of Unicode characters stored in the Codec Description field
// * Codec Description WCHAR variable // array of Unicode characters - description of format used to create the content
// * Codec Information Length WORD 16 // number of Unicode characters stored in the Codec Information field
// * Codec Information BYTESTREAM variable // opaque array of information bytes about the codec used to create the content
$ThisFileInfo['asf']['codec_list']['objectid'] = $NextObjectGUID;
$ThisFileInfo['asf']['codec_list']['objectid_guid'] = $NextObjectGUIDtext;
$ThisFileInfo['asf']['codec_list']['objectsize'] = $NextObjectSize;
$ThisFileInfo['asf']['codec_list']['reserved'] = substr($ASFHeaderData, $offset, 16);
$offset += 16;
$ThisFileInfo['asf']['codec_list']['reserved_guid'] = BytestringToGUID($ThisFileInfo['asf']['codec_list']['reserved']);
if ($ThisFileInfo['asf']['codec_list']['reserved'] != GUIDtoBytestring('86D15241-311D-11D0-A3A4-00A0C90348F6')) {
$ThisFileInfo['warning'] .= "\n".'codec_list_object.reserved GUID {'.BytestringToGUID($ThisFileInfo['asf']['codec_list']['reserved']).'} does not match expected "ASF_Reserved_1" GUID {86D15241-311D-11D0-A3A4-00A0C90348F6}';
//return false;
break;
}
$ThisFileInfo['asf']['codec_list']['codec_entries_count'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
$offset += 4;
for ($CodecEntryCounter = 0; $CodecEntryCounter < $ThisFileInfo['asf']['codec_list']['codec_entries_count']; $CodecEntryCounter++) {
$ThisFileInfo['asf']['codec_list']['codec_entries'][$CodecEntryCounter]['type_raw'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
$offset += 2;
$ThisFileInfo['asf']['codec_list']['codec_entries'][$CodecEntryCounter]['type'] = ASFCodecListObjectTypeLookup($ThisFileInfo['asf']['codec_list']['codec_entries'][$CodecEntryCounter]['type_raw']);
$CodecNameLength = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character
$offset += 2;
$ThisFileInfo['asf']['codec_list']['codec_entries'][$CodecEntryCounter]['name'] = substr($ASFHeaderData, $offset, $CodecNameLength);
$offset += $CodecNameLength;
$ThisFileInfo['asf']['codec_list']['codec_entries'][$CodecEntryCounter]['name_ascii'] = RoughTranslateUnicodeToASCII($ThisFileInfo['asf']['codec_list']['codec_entries'][$CodecEntryCounter]['name'], 2);
$CodecDescriptionLength = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character
$offset += 2;
$ThisFileInfo['asf']['codec_list']['codec_entries'][$CodecEntryCounter]['description'] = substr($ASFHeaderData, $offset, $CodecDescriptionLength);
$offset += $CodecDescriptionLength;
$ThisFileInfo['asf']['codec_list']['codec_entries'][$CodecEntryCounter]['description_ascii'] = RoughTranslateUnicodeToASCII($ThisFileInfo['asf']['codec_list']['codec_entries'][$CodecEntryCounter]['description'], 2);
$CodecInformationLength = LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
$offset += 2;
$ThisFileInfo['asf']['codec_list']['codec_entries'][$CodecEntryCounter]['information'] = substr($ASFHeaderData, $offset, $CodecInformationLength);
$offset += $CodecInformationLength;
if ($ThisFileInfo['asf']['codec_list']['codec_entries'][$CodecEntryCounter]['type_raw'] == 2) {
// audio codec
$ThisFileInfo['audio']['codec'] = $ThisFileInfo['asf']['codec_list']['codec_entries'][$CodecEntryCounter]['name_ascii'];
list($AudioCodecBitrate, $AudioCodecFrequency, $AudioCodecChannels) = explode(',', $ThisFileInfo['asf']['codec_list']['codec_entries'][$CodecEntryCounter]['description_ascii']);
if (!isset($ThisFileInfo['audio']['bitrate']) && strstr($AudioCodecBitrate, 'kbps')) {
$ThisFileInfo['audio']['bitrate'] = (int) (trim(str_replace('kbps', '', $AudioCodecBitrate)) * 1000);
}
if (!isset($ThisFileInfo['video']['bitrate']) && isset($ThisFileInfo['audio']['bitrate']) && isset($ThisFileInfo['asf']['file_properties_object']['max_bitrate']) && ($ThisFileInfo['asf']['codec_list']['codec_entries_count'] > 1)) {
$ThisFileInfo['video']['bitrate'] = $ThisFileInfo['asf']['file_properties_object']['max_bitrate'] - $ThisFileInfo['audio']['bitrate'];
}
$AudioCodecFrequency = (int) trim(str_replace('kHz', '', $AudioCodecFrequency));
switch ($AudioCodecFrequency) {
case 8:
$ThisFileInfo['audio']['sample_rate'] = 8000;
break;
case 11:
$ThisFileInfo['audio']['sample_rate'] = 11025;
break;
case 12:
$ThisFileInfo['audio']['sample_rate'] = 12000;
break;
case 16:
$ThisFileInfo['audio']['sample_rate'] = 16000;
break;
case 22:
$ThisFileInfo['audio']['sample_rate'] = 22050;
break;
case 24:
$ThisFileInfo['audio']['sample_rate'] = 24000;
break;
case 32:
$ThisFileInfo['audio']['sample_rate'] = 32000;
break;
case 44:
$ThisFileInfo['audio']['sample_rate'] = 44100;
break;
case 48:
$ThisFileInfo['audio']['sample_rate'] = 48000;
break;
default:
$ThisFileInfo['warning'] .= "\n".'unknown frequency: "'.$AudioCodecFrequency.'" ('.$ThisFileInfo['asf']['codec_list']['codec_entries'][$CodecEntryCounter]['description_ascii'].')';
// return false;
break;
}
if (!isset($ThisFileInfo['audio']['channels'])) {
if (strstr($AudioCodecChannels, 'stereo')) {
$ThisFileInfo['audio']['channels'] = 2;
} elseif (strstr($AudioCodecChannels, 'mono')) {
$ThisFileInfo['audio']['channels'] = 1;
}
}
}
}
break;
case ASF_Script_Command_Object:
// Script Command Object: (optional, one only)
// Field Name Field Type Size (bits)
// Object ID GUID 128 // GUID for Script Command object - ASF_Script_Command_Object
// Object Size QWORD 64 // size of Script Command object, including 44 bytes of Script Command Object header
// Reserved GUID 128 // hardcoded: 4B1ACBE3-100B-11D0-A39B-00A0C90348F6
// Commands Count WORD 16 // number of Commands structures in the Script Commands Objects
// Command Types Count WORD 16 // number of Command Types structures in the Script Commands Objects
// Command Types array of: variable //
// * Command Type Name Length WORD 16 // number of Unicode characters for Command Type Name
// * Command Type Name WCHAR variable // array of Unicode characters - name of a type of command
// Commands array of: variable //
// * Presentation Time DWORD 32 // presentation time of that command, in milliseconds
// * Type Index WORD 16 // type of this command, as a zero-based index into the array of Command Types of this object
// * Command Name Length WORD 16 // number of Unicode characters for Command Name
// * Command Name WCHAR variable // array of Unicode characters - name of this command
$ThisFileInfo['asf']['script_command_object']['objectid'] = $NextObjectGUID;
$ThisFileInfo['asf']['script_command_object']['objectid_guid'] = $NextObjectGUIDtext;
$ThisFileInfo['asf']['script_command_object']['objectsize'] = $NextObjectSize;
$ThisFileInfo['asf']['script_command_object']['reserved'] = substr($ASFHeaderData, $offset, 16);
$offset += 16;
$ThisFileInfo['asf']['script_command_object']['reserved_guid'] = BytestringToGUID($ThisFileInfo['asf']['script_command_object']['reserved']);
if ($ThisFileInfo['asf']['script_command_object']['reserved'] != GUIDtoBytestring('4B1ACBE3-100B-11D0-A39B-00A0C90348F6')) {
$ThisFileInfo['warning'] .= "\n".'script_command_object.reserved GUID {'.BytestringToGUID($ThisFileInfo['asf']['script_command_object']['reserved']).'} does not match expected "ASF_Reserved_1" GUID {4B1ACBE3-100B-11D0-A39B-00A0C90348F6}';
//return false;
break;
}
$ThisFileInfo['asf']['script_command_object']['commands_count'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
$offset += 2;
$ThisFileInfo['asf']['script_command_object']['command_types_count'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
$offset += 2;
for ($CommandTypesCounter = 0; $CommandTypesCounter < $ThisFileInfo['asf']['script_command_object']['command_types_count']; $CommandTypesCounter++) {
$CommandTypeNameLength = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character
$offset += 2;
$ThisFileInfo['asf']['script_command_object']['command_types'][$CommandTypesCounter]['name'] = substr($ASFHeaderData, $offset, $CommandTypeNameLength);
$offset += $CommandTypeNameLength;
$ThisFileInfo['asf']['script_command_object']['command_types'][$CommandTypesCounter]['name_ascii'] = RoughTranslateUnicodeToASCII($ThisFileInfo['asf']['script_command_object']['command_types'][$CommandTypesCounter]['name'], 2);
}
for ($CommandsCounter = 0; $CommandsCounter < $ThisFileInfo['asf']['script_command_object']['commands_count']; $CommandsCounter++) {
$ThisFileInfo['asf']['script_command_object']['commands'][$CommandsCounter]['presentation_time'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
$offset += 4;
$ThisFileInfo['asf']['script_command_object']['commands'][$CommandsCounter]['type_index'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
$offset += 2;
$CommandTypeNameLength = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character
$offset += 2;
$ThisFileInfo['asf']['script_command_object']['commands'][$CommandsCounter]['name'] = substr($ASFHeaderData, $offset, $CommandTypeNameLength);
$offset += $CommandTypeNameLength;
$ThisFileInfo['asf']['script_command_object']['commands'][$CommandsCounter]['name_ascii'] = RoughTranslateUnicodeToASCII($ThisFileInfo['asf']['script_command_object']['commands'][$CommandsCounter]['name'], 2);
}
break;
case ASF_Marker_Object:
// Marker Object: (optional, one only)
// Field Name Field Type Size (bits)
// Object ID GUID 128 // GUID for Marker object - ASF_Marker_Object
// Object Size QWORD 64 // size of Marker object, including 48 bytes of Marker Object header
// Reserved GUID 128 // hardcoded: 4CFEDB20-75F6-11CF-9C0F-00A0C90349CB
// Markers Count DWORD 32 // number of Marker structures in Marker Object
// Reserved WORD 16 // hardcoded: 0x0000
// Name Length WORD 16 // number of bytes in the Name field
// Name WCHAR variable // name of the Marker Object
// Markers array of: variable //
// * Offset QWORD 64 // byte offset into Data Object
// * Presentation Time QWORD 64 // in 100-nanosecond units
// * Entry Length WORD 16 // length in bytes of (Send Time + Flags + Marker Description Length + Marker Description + Padding)
// * Send Time DWORD 32 // in milliseconds
// * Flags DWORD 32 // hardcoded: 0x00000000
// * Marker Description Length DWORD 32 // number of bytes in Marker Description field
// * Marker Description WCHAR variable // array of Unicode characters - description of marker entry
// * Padding BYTESTREAM variable // optional padding bytes
$ThisFileInfo['asf']['marker_object']['objectid'] = $NextObjectGUID;
$ThisFileInfo['asf']['marker_object']['objectid_guid'] = $NextObjectGUIDtext;
$ThisFileInfo['asf']['marker_object']['objectsize'] = $NextObjectSize;
$ThisFileInfo['asf']['marker_object']['reserved'] = substr($ASFHeaderData, $offset, 16);
$offset += 16;
$ThisFileInfo['asf']['marker_object']['reserved_guid'] = BytestringToGUID($ThisFileInfo['asf']['marker_object']['reserved']);
if ($ThisFileInfo['asf']['marker_object']['reserved'] != GUIDtoBytestring('4CFEDB20-75F6-11CF-9C0F-00A0C90349CB')) {
$ThisFileInfo['warning'] .= "\n".'marker_object.reserved GUID {'.BytestringToGUID($ThisFileInfo['asf']['marker_object']['reserved_1']).'} does not match expected "ASF_Reserved_1" GUID {4CFEDB20-75F6-11CF-9C0F-00A0C90349CB}';
//return false;
break;
}
$ThisFileInfo['asf']['marker_object']['markers_count'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
$offset += 4;
$ThisFileInfo['asf']['marker_object']['reserved_2'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
$offset += 2;
if ($ThisFileInfo['asf']['marker_object']['reserved_2'] != 0) {
$ThisFileInfo['warning'] .= "\n".'marker_object.reserved_2 ('.PrintHexBytes($ThisFileInfo['asf']['marker_object']['reserved_2']).') does not match expected value of "0"';
//return false;
break;
}
$ThisFileInfo['asf']['marker_object']['name_length'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
$offset += 2;
$ThisFileInfo['asf']['marker_object']['name'] = substr($ASFHeaderData, $offset, $ThisFileInfo['asf']['marker_object']['name_length']);
$offset += $ThisFileInfo['asf']['marker_object']['name_length'];
$ThisFileInfo['asf']['marker_object']['name_ascii'] = RoughTranslateUnicodeToASCII($ThisFileInfo['asf']['marker_object']['name'], 2);
for ($MarkersCounter = 0; $MarkersCounter < $ThisFileInfo['asf']['marker_object']['markers_count']; $MarkersCounter++) {
$ThisFileInfo['asf']['marker_object']['markers'][$MarkersCounter]['offset'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
$offset += 8;
$ThisFileInfo['asf']['marker_object']['markers'][$MarkersCounter]['presentation_time'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
$offset += 8;
$ThisFileInfo['asf']['marker_object']['markers'][$MarkersCounter]['entry_length'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
$offset += 2;
$ThisFileInfo['asf']['marker_object']['markers'][$MarkersCounter]['send_time'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
$offset += 4;
$ThisFileInfo['asf']['marker_object']['markers'][$MarkersCounter]['flags'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
$offset += 4;
$ThisFileInfo['asf']['marker_object']['markers'][$MarkersCounter]['marker_description_length'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
$offset += 4;
$ThisFileInfo['asf']['marker_object']['markers'][$MarkersCounter]['marker_description'] = substr($ASFHeaderData, $offset, $ThisFileInfo['asf']['marker_object']['markers'][$MarkersCounter]['marker_description_length']);
$offset += $ThisFileInfo['asf']['marker_object']['markers'][$MarkersCounter]['marker_description_length'];
$ThisFileInfo['asf']['marker_object']['markers'][$MarkersCounter]['marker_description_ascii'] = RoughTranslateUnicodeToASCII($ThisFileInfo['asf']['marker_object']['markers'][$MarkersCounter]['marker_description'], 2);
$PaddingLength = $ThisFileInfo['asf']['marker_object']['markers'][$MarkersCounter]['entry_length'] - 4 - 4 - 4 - $ThisFileInfo['asf']['marker_object']['markers'][$MarkersCounter]['marker_description_length'];
if ($PaddingLength > 0) {
$ThisFileInfo['asf']['marker_object']['markers'][$MarkersCounter]['padding'] = substr($ASFHeaderData, $offset, $PaddingLength);
$offset += $PaddingLength;
}
}
break;
case ASF_Bitrate_Mutual_Exclusion_Object:
// Bitrate Mutual Exclusion Object: (optional)
// Field Name Field Type Size (bits)
// Object ID GUID 128 // GUID for Bitrate Mutual Exclusion object - ASF_Bitrate_Mutual_Exclusion_Object
// Object Size QWORD 64 // size of Bitrate Mutual Exclusion object, including 42 bytes of Bitrate Mutual Exclusion Object header
// Exlusion Type GUID