1 <?php |
1 <?php |
2 ///////////////////////////////////////////////////////////////// |
2 ///////////////////////////////////////////////////////////////// |
3 /// getID3() by James Heinrich <info@getid3.org> // |
3 /// getID3() by James Heinrich <info@getid3.org> // |
4 // available at http://getid3.sourceforge.net // |
4 // available at https://github.com/JamesHeinrich/getID3 // |
5 // or http://www.getid3.org // |
5 // or https://www.getid3.org // |
6 // also https://github.com/JamesHeinrich/getID3 // |
6 // or http://getid3.sourceforge.net // |
7 ///////////////////////////////////////////////////////////////// |
7 // see readme.txt for more details // |
8 // See readme.txt for more details // |
|
9 ///////////////////////////////////////////////////////////////// |
8 ///////////////////////////////////////////////////////////////// |
10 // // |
9 // // |
11 // module.audio-video.asf.php // |
10 // module.audio-video.asf.php // |
12 // module for analyzing ASF, WMA and WMV files // |
11 // module for analyzing ASF, WMA and WMV files // |
13 // dependencies: module.audio-video.riff.php // |
12 // dependencies: module.audio-video.riff.php // |
14 // /// |
13 // /// |
15 ///////////////////////////////////////////////////////////////// |
14 ///////////////////////////////////////////////////////////////// |
16 |
15 |
|
16 if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers |
|
17 exit; |
|
18 } |
17 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true); |
19 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true); |
18 |
20 |
19 class getid3_asf extends getid3_handler { |
21 class getid3_asf extends getid3_handler |
20 |
22 { |
|
23 /** |
|
24 * @param getID3 $getid3 |
|
25 */ |
21 public function __construct(getID3 $getid3) { |
26 public function __construct(getID3 $getid3) { |
22 parent::__construct($getid3); // extends getid3_handler::__construct() |
27 parent::__construct($getid3); // extends getid3_handler::__construct() |
23 |
28 |
24 // initialize all GUID constants |
29 // initialize all GUID constants |
25 $GUIDarray = $this->KnownGUIDs(); |
30 $GUIDarray = $this->KnownGUIDs(); |
354 |
364 |
355 list($AudioCodecBitrate, $AudioCodecFrequency, $AudioCodecChannels) = explode(',', $this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['description'])); |
365 list($AudioCodecBitrate, $AudioCodecFrequency, $AudioCodecChannels) = explode(',', $this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['description'])); |
356 $thisfile_audio['codec'] = $this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['name']); |
366 $thisfile_audio['codec'] = $this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['name']); |
357 |
367 |
358 if (!isset($thisfile_audio['bitrate']) && strstr($AudioCodecBitrate, 'kbps')) { |
368 if (!isset($thisfile_audio['bitrate']) && strstr($AudioCodecBitrate, 'kbps')) { |
359 $thisfile_audio['bitrate'] = (int) (trim(str_replace('kbps', '', $AudioCodecBitrate)) * 1000); |
369 $thisfile_audio['bitrate'] = (int) trim(str_replace('kbps', '', $AudioCodecBitrate)) * 1000; |
360 } |
370 } |
361 //if (!isset($thisfile_video['bitrate']) && isset($thisfile_audio['bitrate']) && isset($thisfile_asf['file_properties_object']['max_bitrate']) && ($thisfile_asf_codeclistobject['codec_entries_count'] > 1)) { |
371 //if (!isset($thisfile_video['bitrate']) && isset($thisfile_audio['bitrate']) && isset($thisfile_asf['file_properties_object']['max_bitrate']) && ($thisfile_asf_codeclistobject['codec_entries_count'] > 1)) { |
362 if (empty($thisfile_video['bitrate']) && !empty($thisfile_audio['bitrate']) && !empty($info['bitrate'])) { |
372 if (empty($thisfile_video['bitrate']) && !empty($thisfile_audio['bitrate']) && !empty($info['bitrate'])) { |
363 //$thisfile_video['bitrate'] = $thisfile_asf['file_properties_object']['max_bitrate'] - $thisfile_audio['bitrate']; |
373 //$thisfile_video['bitrate'] = $thisfile_asf['file_properties_object']['max_bitrate'] - $thisfile_audio['bitrate']; |
364 $thisfile_video['bitrate'] = $info['bitrate'] - $thisfile_audio['bitrate']; |
374 $thisfile_video['bitrate'] = $info['bitrate'] - $thisfile_audio['bitrate']; |
788 break; |
798 break; |
789 |
799 |
790 case 'wm/tracknumber': |
800 case 'wm/tracknumber': |
791 case 'tracknumber': |
801 case 'tracknumber': |
792 // be careful casting to int: casting unicode strings to int gives unexpected results (stops parsing at first non-numeric character) |
802 // be careful casting to int: casting unicode strings to int gives unexpected results (stops parsing at first non-numeric character) |
793 $thisfile_asf_comments['track'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); |
803 $thisfile_asf_comments['track_number'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); |
794 foreach ($thisfile_asf_comments['track'] as $key => $value) { |
804 foreach ($thisfile_asf_comments['track_number'] as $key => $value) { |
795 if (preg_match('/^[0-9\x00]+$/', $value)) { |
805 if (preg_match('/^[0-9\x00]+$/', $value)) { |
796 $thisfile_asf_comments['track'][$key] = intval(str_replace("\x00", '', $value)); |
806 $thisfile_asf_comments['track_number'][$key] = intval(str_replace("\x00", '', $value)); |
797 } |
807 } |
798 } |
808 } |
799 break; |
809 break; |
800 |
810 |
801 case 'wm/track': |
811 case 'wm/track': |
802 if (empty($thisfile_asf_comments['track'])) { |
812 if (empty($thisfile_asf_comments['track_number'])) { |
803 $thisfile_asf_comments['track'] = array(1 + $this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); |
813 $thisfile_asf_comments['track_number'] = array(1 + (int) $this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); |
804 } |
814 } |
805 break; |
815 break; |
806 |
816 |
807 case 'wm/year': |
817 case 'wm/year': |
808 case 'year': |
818 case 'year': |
968 } |
978 } |
969 $offset += ($NextObjectSize - 16 - 8); |
979 $offset += ($NextObjectSize - 16 - 8); |
970 break; |
980 break; |
971 } |
981 } |
972 } |
982 } |
973 if (isset($thisfile_asf_streambitrateproperties['bitrate_records_count'])) { |
983 if (isset($thisfile_asf_streambitratepropertiesobject['bitrate_records_count'])) { |
974 $ASFbitrateAudio = 0; |
984 $ASFbitrateAudio = 0; |
975 $ASFbitrateVideo = 0; |
985 $ASFbitrateVideo = 0; |
976 for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < $thisfile_asf_streambitrateproperties['bitrate_records_count']; $BitrateRecordsCounter++) { |
986 for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < $thisfile_asf_streambitratepropertiesobject['bitrate_records_count']; $BitrateRecordsCounter++) { |
977 if (isset($thisfile_asf_codeclistobject['codec_entries'][$BitrateRecordsCounter])) { |
987 if (isset($thisfile_asf_codeclistobject['codec_entries'][$BitrateRecordsCounter])) { |
978 switch ($thisfile_asf_codeclistobject['codec_entries'][$BitrateRecordsCounter]['type_raw']) { |
988 switch ($thisfile_asf_codeclistobject['codec_entries'][$BitrateRecordsCounter]['type_raw']) { |
979 case 1: |
989 case 1: |
980 $ASFbitrateVideo += $thisfile_asf_streambitrateproperties['bitrate_records'][$BitrateRecordsCounter]['bitrate']; |
990 $ASFbitrateVideo += $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['bitrate']; |
981 break; |
991 break; |
982 |
992 |
983 case 2: |
993 case 2: |
984 $ASFbitrateAudio += $thisfile_asf_streambitrateproperties['bitrate_records'][$BitrateRecordsCounter]['bitrate']; |
994 $ASFbitrateAudio += $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['bitrate']; |
985 break; |
995 break; |
986 |
996 |
987 default: |
997 default: |
988 // do nothing |
998 // do nothing |
989 break; |
999 break; |
1438 } |
1448 } |
1439 |
1449 |
1440 return true; |
1450 return true; |
1441 } |
1451 } |
1442 |
1452 |
|
1453 /** |
|
1454 * @param int $CodecListType |
|
1455 * |
|
1456 * @return string |
|
1457 */ |
1443 public static function codecListObjectTypeLookup($CodecListType) { |
1458 public static function codecListObjectTypeLookup($CodecListType) { |
1444 static $lookup = array( |
1459 static $lookup = array( |
1445 0x0001 => 'Video Codec', |
1460 0x0001 => 'Video Codec', |
1446 0x0002 => 'Audio Codec', |
1461 0x0002 => 'Audio Codec', |
1447 0xFFFF => 'Unknown Codec' |
1462 0xFFFF => 'Unknown Codec' |
1448 ); |
1463 ); |
1449 |
1464 |
1450 return (isset($lookup[$CodecListType]) ? $lookup[$CodecListType] : 'Invalid Codec Type'); |
1465 return (isset($lookup[$CodecListType]) ? $lookup[$CodecListType] : 'Invalid Codec Type'); |
1451 } |
1466 } |
1452 |
1467 |
|
1468 /** |
|
1469 * @return array |
|
1470 */ |
1453 public static function KnownGUIDs() { |
1471 public static function KnownGUIDs() { |
1454 static $GUIDarray = array( |
1472 static $GUIDarray = array( |
1455 'GETID3_ASF_Extended_Stream_Properties_Object' => '14E6A5CB-C672-4332-8399-A96952065B5A', |
1473 'GETID3_ASF_Extended_Stream_Properties_Object' => '14E6A5CB-C672-4332-8399-A96952065B5A', |
1456 'GETID3_ASF_Padding_Object' => '1806D474-CADF-4509-A4BA-9AABCB96AAE8', |
1474 'GETID3_ASF_Padding_Object' => '1806D474-CADF-4509-A4BA-9AABCB96AAE8', |
1457 'GETID3_ASF_Payload_Ext_Syst_Pixel_Aspect_Ratio' => '1B1EE554-F9EA-4BC8-821A-376B74E4C4B8', |
1475 'GETID3_ASF_Payload_Ext_Syst_Pixel_Aspect_Ratio' => '1B1EE554-F9EA-4BC8-821A-376B74E4C4B8', |
1562 'GETID3_ASF_Compatibility_Object' => '26F18B5D-4584-47EC-9F5F-0E651F0452C9', // http://cpan.uwinnipeg.ca/htdocs/Audio-WMA/Audio/WMA.pm.html |
1580 'GETID3_ASF_Compatibility_Object' => '26F18B5D-4584-47EC-9F5F-0E651F0452C9', // http://cpan.uwinnipeg.ca/htdocs/Audio-WMA/Audio/WMA.pm.html |
1563 ); |
1581 ); |
1564 return $GUIDarray; |
1582 return $GUIDarray; |
1565 } |
1583 } |
1566 |
1584 |
|
1585 /** |
|
1586 * @param string $GUIDstring |
|
1587 * |
|
1588 * @return string|false |
|
1589 */ |
1567 public static function GUIDname($GUIDstring) { |
1590 public static function GUIDname($GUIDstring) { |
1568 static $GUIDarray = array(); |
1591 static $GUIDarray = array(); |
1569 if (empty($GUIDarray)) { |
1592 if (empty($GUIDarray)) { |
1570 $GUIDarray = self::KnownGUIDs(); |
1593 $GUIDarray = self::KnownGUIDs(); |
1571 } |
1594 } |
1572 return array_search($GUIDstring, $GUIDarray); |
1595 return array_search($GUIDstring, $GUIDarray); |
1573 } |
1596 } |
1574 |
1597 |
|
1598 /** |
|
1599 * @param int $id |
|
1600 * |
|
1601 * @return string |
|
1602 */ |
1575 public static function ASFIndexObjectIndexTypeLookup($id) { |
1603 public static function ASFIndexObjectIndexTypeLookup($id) { |
1576 static $ASFIndexObjectIndexTypeLookup = array(); |
1604 static $ASFIndexObjectIndexTypeLookup = array(); |
1577 if (empty($ASFIndexObjectIndexTypeLookup)) { |
1605 if (empty($ASFIndexObjectIndexTypeLookup)) { |
1578 $ASFIndexObjectIndexTypeLookup[1] = 'Nearest Past Data Packet'; |
1606 $ASFIndexObjectIndexTypeLookup[1] = 'Nearest Past Data Packet'; |
1579 $ASFIndexObjectIndexTypeLookup[2] = 'Nearest Past Media Object'; |
1607 $ASFIndexObjectIndexTypeLookup[2] = 'Nearest Past Media Object'; |
1580 $ASFIndexObjectIndexTypeLookup[3] = 'Nearest Past Cleanpoint'; |
1608 $ASFIndexObjectIndexTypeLookup[3] = 'Nearest Past Cleanpoint'; |
1581 } |
1609 } |
1582 return (isset($ASFIndexObjectIndexTypeLookup[$id]) ? $ASFIndexObjectIndexTypeLookup[$id] : 'invalid'); |
1610 return (isset($ASFIndexObjectIndexTypeLookup[$id]) ? $ASFIndexObjectIndexTypeLookup[$id] : 'invalid'); |
1583 } |
1611 } |
1584 |
1612 |
|
1613 /** |
|
1614 * @param string $GUIDstring |
|
1615 * |
|
1616 * @return string |
|
1617 */ |
1585 public static function GUIDtoBytestring($GUIDstring) { |
1618 public static function GUIDtoBytestring($GUIDstring) { |
1586 // Microsoft defines these 16-byte (128-bit) GUIDs in the strangest way: |
1619 // Microsoft defines these 16-byte (128-bit) GUIDs in the strangest way: |
1587 // first 4 bytes are in little-endian order |
1620 // first 4 bytes are in little-endian order |
1588 // next 2 bytes are appended in little-endian order |
1621 // next 2 bytes are appended in little-endian order |
1589 // next 2 bytes are appended in little-endian order |
1622 // next 2 bytes are appended in little-endian order |
1615 $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 34, 2))); |
1648 $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 34, 2))); |
1616 |
1649 |
1617 return $hexbytecharstring; |
1650 return $hexbytecharstring; |
1618 } |
1651 } |
1619 |
1652 |
|
1653 /** |
|
1654 * @param string $Bytestring |
|
1655 * |
|
1656 * @return string |
|
1657 */ |
1620 public static function BytestringToGUID($Bytestring) { |
1658 public static function BytestringToGUID($Bytestring) { |
1621 $GUIDstring = str_pad(dechex(ord($Bytestring{3})), 2, '0', STR_PAD_LEFT); |
1659 $GUIDstring = str_pad(dechex(ord($Bytestring[3])), 2, '0', STR_PAD_LEFT); |
1622 $GUIDstring .= str_pad(dechex(ord($Bytestring{2})), 2, '0', STR_PAD_LEFT); |
1660 $GUIDstring .= str_pad(dechex(ord($Bytestring[2])), 2, '0', STR_PAD_LEFT); |
1623 $GUIDstring .= str_pad(dechex(ord($Bytestring{1})), 2, '0', STR_PAD_LEFT); |
1661 $GUIDstring .= str_pad(dechex(ord($Bytestring[1])), 2, '0', STR_PAD_LEFT); |
1624 $GUIDstring .= str_pad(dechex(ord($Bytestring{0})), 2, '0', STR_PAD_LEFT); |
1662 $GUIDstring .= str_pad(dechex(ord($Bytestring[0])), 2, '0', STR_PAD_LEFT); |
1625 $GUIDstring .= '-'; |
1663 $GUIDstring .= '-'; |
1626 $GUIDstring .= str_pad(dechex(ord($Bytestring{5})), 2, '0', STR_PAD_LEFT); |
1664 $GUIDstring .= str_pad(dechex(ord($Bytestring[5])), 2, '0', STR_PAD_LEFT); |
1627 $GUIDstring .= str_pad(dechex(ord($Bytestring{4})), 2, '0', STR_PAD_LEFT); |
1665 $GUIDstring .= str_pad(dechex(ord($Bytestring[4])), 2, '0', STR_PAD_LEFT); |
1628 $GUIDstring .= '-'; |
1666 $GUIDstring .= '-'; |
1629 $GUIDstring .= str_pad(dechex(ord($Bytestring{7})), 2, '0', STR_PAD_LEFT); |
1667 $GUIDstring .= str_pad(dechex(ord($Bytestring[7])), 2, '0', STR_PAD_LEFT); |
1630 $GUIDstring .= str_pad(dechex(ord($Bytestring{6})), 2, '0', STR_PAD_LEFT); |
1668 $GUIDstring .= str_pad(dechex(ord($Bytestring[6])), 2, '0', STR_PAD_LEFT); |
1631 $GUIDstring .= '-'; |
1669 $GUIDstring .= '-'; |
1632 $GUIDstring .= str_pad(dechex(ord($Bytestring{8})), 2, '0', STR_PAD_LEFT); |
1670 $GUIDstring .= str_pad(dechex(ord($Bytestring[8])), 2, '0', STR_PAD_LEFT); |
1633 $GUIDstring .= str_pad(dechex(ord($Bytestring{9})), 2, '0', STR_PAD_LEFT); |
1671 $GUIDstring .= str_pad(dechex(ord($Bytestring[9])), 2, '0', STR_PAD_LEFT); |
1634 $GUIDstring .= '-'; |
1672 $GUIDstring .= '-'; |
1635 $GUIDstring .= str_pad(dechex(ord($Bytestring{10})), 2, '0', STR_PAD_LEFT); |
1673 $GUIDstring .= str_pad(dechex(ord($Bytestring[10])), 2, '0', STR_PAD_LEFT); |
1636 $GUIDstring .= str_pad(dechex(ord($Bytestring{11})), 2, '0', STR_PAD_LEFT); |
1674 $GUIDstring .= str_pad(dechex(ord($Bytestring[11])), 2, '0', STR_PAD_LEFT); |
1637 $GUIDstring .= str_pad(dechex(ord($Bytestring{12})), 2, '0', STR_PAD_LEFT); |
1675 $GUIDstring .= str_pad(dechex(ord($Bytestring[12])), 2, '0', STR_PAD_LEFT); |
1638 $GUIDstring .= str_pad(dechex(ord($Bytestring{13})), 2, '0', STR_PAD_LEFT); |
1676 $GUIDstring .= str_pad(dechex(ord($Bytestring[13])), 2, '0', STR_PAD_LEFT); |
1639 $GUIDstring .= str_pad(dechex(ord($Bytestring{14})), 2, '0', STR_PAD_LEFT); |
1677 $GUIDstring .= str_pad(dechex(ord($Bytestring[14])), 2, '0', STR_PAD_LEFT); |
1640 $GUIDstring .= str_pad(dechex(ord($Bytestring{15})), 2, '0', STR_PAD_LEFT); |
1678 $GUIDstring .= str_pad(dechex(ord($Bytestring[15])), 2, '0', STR_PAD_LEFT); |
1641 |
1679 |
1642 return strtoupper($GUIDstring); |
1680 return strtoupper($GUIDstring); |
1643 } |
1681 } |
1644 |
1682 |
|
1683 /** |
|
1684 * @param int $FILETIME |
|
1685 * @param bool $round |
|
1686 * |
|
1687 * @return float|int |
|
1688 */ |
1645 public static function FILETIMEtoUNIXtime($FILETIME, $round=true) { |
1689 public static function FILETIMEtoUNIXtime($FILETIME, $round=true) { |
1646 // FILETIME is a 64-bit unsigned integer representing |
1690 // FILETIME is a 64-bit unsigned integer representing |
1647 // the number of 100-nanosecond intervals since January 1, 1601 |
1691 // the number of 100-nanosecond intervals since January 1, 1601 |
1648 // UNIX timestamp is number of seconds since January 1, 1970 |
1692 // UNIX timestamp is number of seconds since January 1, 1970 |
1649 // 116444736000000000 = 10000000 * 60 * 60 * 24 * 365 * 369 + 89 leap days |
1693 // 116444736000000000 = 10000000 * 60 * 60 * 24 * 365 * 369 + 89 leap days |
1992 $this->getid3->info['asf']['comments']['picture'][] = array('data'=>$WMpicture['data'], 'image_mime'=>$WMpicture['image_mime']); |
2056 $this->getid3->info['asf']['comments']['picture'][] = array('data'=>$WMpicture['data'], 'image_mime'=>$WMpicture['image_mime']); |
1993 |
2057 |
1994 return $WMpicture; |
2058 return $WMpicture; |
1995 } |
2059 } |
1996 |
2060 |
1997 |
2061 /** |
1998 // Remove terminator 00 00 and convert UTF-16LE to Latin-1 |
2062 * Remove terminator 00 00 and convert UTF-16LE to Latin-1. |
|
2063 * |
|
2064 * @param string $string |
|
2065 * |
|
2066 * @return string |
|
2067 */ |
1999 public static function TrimConvert($string) { |
2068 public static function TrimConvert($string) { |
2000 return trim(getid3_lib::iconv_fallback('UTF-16LE', 'ISO-8859-1', self::TrimTerm($string)), ' '); |
2069 return trim(getid3_lib::iconv_fallback('UTF-16LE', 'ISO-8859-1', self::TrimTerm($string)), ' '); |
2001 } |
2070 } |
2002 |
2071 |
2003 |
2072 /** |
2004 // Remove terminator 00 00 |
2073 * Remove terminator 00 00. |
|
2074 * |
|
2075 * @param string $string |
|
2076 * |
|
2077 * @return string |
|
2078 */ |
2005 public static function TrimTerm($string) { |
2079 public static function TrimTerm($string) { |
2006 // remove terminator, only if present (it should be, but...) |
2080 // remove terminator, only if present (it should be, but...) |
2007 if (substr($string, -2) === "\x00\x00") { |
2081 if (substr($string, -2) === "\x00\x00") { |
2008 $string = substr($string, 0, -2); |
2082 $string = substr($string, 0, -2); |
2009 } |
2083 } |