diff --git a/getid3/module.audio-video.asf.php b/getid3/module.audio-video.asf.php index 40b62909..e83de754 100644 --- a/getid3/module.audio-video.asf.php +++ b/getid3/module.audio-video.asf.php @@ -20,6 +20,24 @@ class getid3_asf extends getid3_handler { + protected static $ASFIndexParametersObjectIndexSpecifiersIndexTypes = array( + 1 => 'Nearest Past Data Packet', + 2 => 'Nearest Past Media Object', + 3 => 'Nearest Past Cleanpoint' + ); + + protected static $ASFMediaObjectIndexParametersObjectIndexSpecifiersIndexTypes = array( + 1 => 'Nearest Past Data Packet', + 2 => 'Nearest Past Media Object', + 3 => 'Nearest Past Cleanpoint', + 0xFF => 'Frame Number Offset' + ); + + protected static $ASFTimecodeIndexParametersObjectIndexSpecifiersIndexTypes = array( + 2 => 'Nearest Past Media Object', + 3 => 'Nearest Past Cleanpoint' + ); + /** * @param getID3 $getid3 */ @@ -1581,8 +1599,9 @@ public static function KnownGUIDs() { 'GETID3_ASF_Audio_Media' => 'F8699E40-5B4D-11CF-A8FD-00805F5C442B', 'GETID3_ASF_Media_Object_Index_Object' => 'FEB103F8-12AD-4C64-840F-2A1D2F7AD48C', 'GETID3_ASF_Alt_Extended_Content_Encryption_Obj' => 'FF889EF1-ADEE-40DA-9E71-98704BB928CE', - 'GETID3_ASF_Index_Placeholder_Object' => 'D9AADE20-7C17-4F9C-BC28-8555DD98E2A2', // http://cpan.uwinnipeg.ca/htdocs/Audio-WMA/Audio/WMA.pm.html - 'GETID3_ASF_Compatibility_Object' => '26F18B5D-4584-47EC-9F5F-0E651F0452C9', // http://cpan.uwinnipeg.ca/htdocs/Audio-WMA/Audio/WMA.pm.html + 'GETID3_ASF_Index_Placeholder_Object' => 'D9AADE20-7C17-4F9C-BC28-8555DD98E2A2', // https://metacpan.org/dist/Audio-WMA/source/WMA.pm + 'GETID3_ASF_Compatibility_Object' => '26F18B5D-4584-47EC-9F5F-0E651F0452C9', // https://metacpan.org/dist/Audio-WMA/source/WMA.pm + 'GETID3_ASF_Media_Object_Index_Parameters_Object'=> '6B203BAD-3F11-48E4-ACA8-D7613DE2CFA7', ); return $GUIDarray; } @@ -1745,7 +1764,7 @@ public static function WMpictureTypeLookup($WMpictureType) { * @return array */ public function HeaderExtensionObjectDataParse(&$asf_header_extension_object_data, &$unhandled_sections) { - // http://msdn.microsoft.com/en-us/library/bb643323.aspx + // https://web.archive.org/web/20140419205228/http://msdn.microsoft.com/en-us/library/bb643323.aspx $offset = 0; $objectOffset = 0; @@ -1857,6 +1876,40 @@ public function HeaderExtensionObjectDataParse(&$asf_header_extension_object_dat break; + case GETID3_ASF_Advanced_Mutual_Exclusion_Object: + $thisObject['exclusion_type'] = substr($asf_header_extension_object_data, $offset, 16); + $offset += 16; + $thisObject['exclusion_type_text'] = $this->BytestringToGUID($thisObject['exclusion_type']); + + $thisObject['stream_numbers_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + + for ($i = 0; $i < $thisObject['stream_numbers_count']; $i++) { + $thisObject['stream_numbers'][$i] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + } + + break; + + case GETID3_ASF_Stream_Prioritization_Object: + $thisObject['priority_records_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + + for ($i = 0; $i < $thisObject['priority_records_count']; $i++) { + $priorityRecord = array(); + + $priorityRecord['stream_number'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + + $priorityRecord['flags_raw'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + $priorityRecord['flags']['mandatory'] = (bool) $priorityRecord['flags_raw'] & 0x00000001; + + $thisObject['priority_records'][$i] = $priorityRecord; + } + + break; + case GETID3_ASF_Padding_Object: // padding, skip it break; @@ -1974,6 +2027,103 @@ public function HeaderExtensionObjectDataParse(&$asf_header_extension_object_dat } break; + case GETID3_ASF_Index_Parameters_Object: + $thisObject['index_entry_time_interval'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); + $offset += 4; + + $thisObject['index_specifiers_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + + for ($i = 0; $i < $thisObject['index_specifiers_count']; $i++) { + $indexSpecifier = array(); + + $indexSpecifier['stream_number'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + + $indexSpecifier['index_type'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + $indexSpecifier['index_type_text'] = isset(static::$ASFIndexParametersObjectIndexSpecifiersIndexTypes[$indexSpecifier['index_type']]) + ? static::$ASFIndexParametersObjectIndexSpecifiersIndexTypes[$indexSpecifier['index_type']] + : 'invalid' + ; + + $thisObject['index_specifiers'][$i] = $indexSpecifier; + } + + break; + + case GETID3_ASF_Media_Object_Index_Parameters_Object: + $thisObject['index_entry_count_interval'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); + $offset += 4; + + $thisObject['index_specifiers_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + + for ($i = 0; $i < $thisObject['index_specifiers_count']; $i++) { + $indexSpecifier = array(); + + $indexSpecifier['stream_number'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + + $indexSpecifier['index_type'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + $indexSpecifier['index_type_text'] = isset(static::$ASFMediaObjectIndexParametersObjectIndexSpecifiersIndexTypes[$indexSpecifier['index_type']]) + ? static::$ASFMediaObjectIndexParametersObjectIndexSpecifiersIndexTypes[$indexSpecifier['index_type']] + : 'invalid' + ; + + $thisObject['index_specifiers'][$i] = $indexSpecifier; + } + + break; + + case GETID3_ASF_Timecode_Index_Parameters_Object: + // 4.11 Timecode Index Parameters Object (mandatory only if TIMECODE index is present in file, 0 or 1) + // Field name Field type Size (bits) + // Object ID GUID 128 // GUID for the Timecode Index Parameters Object - ASF_Timecode_Index_Parameters_Object + // Object Size QWORD 64 // Specifies the size, in bytes, of the Timecode Index Parameters Object. Valid values are at least 34 bytes. + // Index Entry Count Interval DWORD 32 // This value is ignored for the Timecode Index Parameters Object. + // Index Specifiers Count WORD 16 // Specifies the number of entries in the Index Specifiers list. Valid values are 1 and greater. + // Index Specifiers array of: varies // + // * Stream Number WORD 16 // Specifies the stream number that the Index Specifiers refer to. Valid values are between 1 and 127. + // * Index Type WORD 16 // Specifies the type of index. Values are defined as follows (1 is not a valid value): + // 2 = Nearest Past Media Object - indexes point to the closest data packet containing an entire video frame or the first fragment of a video frame + // 3 = Nearest Past Cleanpoint - indexes point to the closest data packet containing an entire video frame (or first fragment of a video frame) that is a key frame. + // Nearest Past Media Object is the most common value + + $thisObject['index_entry_count_interval'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); + $offset += 4; + + $thisObject['index_specifiers_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + + for ($i = 0; $i < $thisObject['index_specifiers_count']; $i++) { + $indexSpecifier = array(); + + $indexSpecifier['stream_number'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + + $indexSpecifier['index_type'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + $indexSpecifier['index_type_text'] = isset(static::$ASFTimecodeIndexParametersObjectIndexSpecifiersIndexTypes[$indexSpecifier['index_type']]) + ? static::$ASFTimecodeIndexParametersObjectIndexSpecifiersIndexTypes[$indexSpecifier['index_type']] + : 'invalid' + ; + + $thisObject['index_specifiers'][$i] = $indexSpecifier; + } + + break; + + case GETID3_ASF_Compatibility_Object: + $thisObject['profile'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 1)); + $offset += 1; + + $thisObject['mode'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 1)); + $offset += 1; + + break; + default: $unhandled_sections++; if ($this->GUIDname($thisObject['guid_text'])) {