- Timestamp:
- 10/10/2021 01:15:16 AM (3 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/ID3/module.audio-video.quicktime.php
r51900 r51901 25 25 { 26 26 27 /** audio-video.quicktime 28 * return all parsed data from all atoms if true, otherwise just returned parsed metadata 29 * 30 * @var bool 31 */ 32 public $ReturnAtomData = false; 33 34 /** audio-video.quicktime 35 * return all parsed data from all atoms if true, otherwise just returned parsed metadata 36 * 37 * @var bool 38 */ 27 public $ReturnAtomData = true; 39 28 public $ParseAllPossibleAtoms = false; 40 29 … … 182 171 } 183 172 184 if (!isset($info['bitrate']) && !empty($info['playtime_seconds'])) {173 if (!isset($info['bitrate']) && isset($info['playtime_seconds'])) { 185 174 $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; 186 175 } … … 572 561 $atom_structure['data'] = substr($boxdata, 8); 573 562 if ($atomname == 'covr') { 574 if (!empty($atom_structure['data'])) { 575 $atom_structure['image_mime'] = 'image/unknown'; // provide default MIME type to ensure array keys exist 576 if (function_exists('getimagesizefromstring') && ($getimagesize = getimagesizefromstring($atom_structure['data'])) && !empty($getimagesize['mime'])) { 577 $atom_structure['image_mime'] = $getimagesize['mime']; 578 } else { 579 // if getimagesizefromstring is not available, or fails for some reason, fall back to simple detection of common image formats 580 $ImageFormatSignatures = array( 581 'image/jpeg' => "\xFF\xD8\xFF", 582 'image/png' => "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 583 'image/gif' => 'GIF', 584 ); 585 foreach ($ImageFormatSignatures as $mime => $image_format_signature) { 586 if (substr($atom_structure['data'], 0, strlen($image_format_signature)) == $image_format_signature) { 587 $atom_structure['image_mime'] = $mime; 588 break; 589 } 590 } 591 } 592 $info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_structure['data'], 'description'=>'cover'); 593 } else { 594 $this->warning('Unknown empty "covr" image at offset '.$baseoffset); 563 // not a foolproof check, but better than nothing 564 if (preg_match('#^\\xFF\\xD8\\xFF#', $atom_structure['data'])) { 565 $atom_structure['image_mime'] = 'image/jpeg'; 566 } elseif (preg_match('#^\\x89\\x50\\x4E\\x47\\x0D\\x0A\\x1A\\x0A#', $atom_structure['data'])) { 567 $atom_structure['image_mime'] = 'image/png'; 568 } elseif (preg_match('#^GIF#', $atom_structure['data'])) { 569 $atom_structure['image_mime'] = 'image/gif'; 595 570 } 571 $info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_structure['data'], 'description'=>'cover'); 596 572 } 597 573 break; … … 753 729 $atom_structure['flags']['slide_show'] = (bool) $atom_structure['slide_show_flag']; 754 730 755 $ptv_lookup = array( 756 0 => 'normal', 757 1 => 'double', 758 2 => 'half', 759 3 => 'full', 760 4 => 'current' 761 ); 731 $ptv_lookup[0] = 'normal'; 732 $ptv_lookup[1] = 'double'; 733 $ptv_lookup[2] = 'half'; 734 $ptv_lookup[3] = 'full'; 735 $ptv_lookup[4] = 'current'; 762 736 if (isset($ptv_lookup[$atom_structure['display_size_raw']])) { 763 737 $atom_structure['display_size'] = $ptv_lookup[$atom_structure['display_size_raw']]; … … 935 909 $atom_structure['sample_description_table'][$i]['video_color_table_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 68, 2)); 936 910 937 $atom_structure['sample_description_table'][$i]['video_pixel_color_type'] = (( (int)$atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color');911 $atom_structure['sample_description_table'][$i]['video_pixel_color_type'] = (($atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color'); 938 912 $atom_structure['sample_description_table'][$i]['video_pixel_color_name'] = $this->QuicktimeColorNameLookup($atom_structure['sample_description_table'][$i]['video_pixel_color_depth']); 939 913 … … 941 915 $info['quicktime']['video']['codec_fourcc'] = $atom_structure['sample_description_table'][$i]['data_format']; 942 916 $info['quicktime']['video']['codec_fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($atom_structure['sample_description_table'][$i]['data_format']); 943 $info['quicktime']['video']['codec'] = (( (int)$atom_structure['sample_description_table'][$i]['video_encoder_name_len'] > 0) ? $atom_structure['sample_description_table'][$i]['video_encoder_name'] : $atom_structure['sample_description_table'][$i]['data_format']);917 $info['quicktime']['video']['codec'] = (($atom_structure['sample_description_table'][$i]['video_encoder_name_len'] > 0) ? $atom_structure['sample_description_table'][$i]['video_encoder_name'] : $atom_structure['sample_description_table'][$i]['data_format']); 944 918 $info['quicktime']['video']['color_depth'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_depth']; 945 919 $info['quicktime']['video']['color_depth_name'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_name']; … … 1625 1599 1626 1600 case 'NCDT': 1627 // http s://exiftool.org/TagNames/Nikon.html1601 // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html 1628 1602 // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100 1629 1603 $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 4, $atomHierarchy, $ParseAllPossibleAtoms); … … 1631 1605 case 'NCTH': // Nikon Camera THumbnail image 1632 1606 case 'NCVW': // Nikon Camera preVieW image 1633 case 'NCM1': // Nikon Camera preview iMage 1 1634 case 'NCM2': // Nikon Camera preview iMage 2 1635 // https://exiftool.org/TagNames/Nikon.html 1607 // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html 1636 1608 if (preg_match('/^\xFF\xD8\xFF/', $atom_data)) { 1637 $descriptions = array(1638 'NCTH' => 'Nikon Camera Thumbnail Image',1639 'NCVW' => 'Nikon Camera Preview Image',1640 'NCM1' => 'Nikon Camera Preview Image 1',1641 'NCM2' => 'Nikon Camera Preview Image 2',1642 );1643 1609 $atom_structure['data'] = $atom_data; 1644 1610 $atom_structure['image_mime'] = 'image/jpeg'; 1645 $atom_structure['description'] = isset($descriptions[$atomname]) ? $descriptions[$atomname] : 'Nikon preview image'; 1646 $info['quicktime']['comments']['picture'][] = array( 1647 'image_mime' => $atom_structure['image_mime'], 1648 'data' => $atom_data, 1649 'description' => $atom_structure['description'] 1650 ); 1651 } 1652 break; 1653 case 'NCTG': // Nikon - https://exiftool.org/TagNames/Nikon.html#NCTG 1654 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.nikon-nctg.php', __FILE__, true); 1655 $nikonNCTG = new getid3_tag_nikon_nctg($this->getid3); 1656 1657 $atom_structure['data'] = $nikonNCTG->parse($atom_data); 1658 break; 1659 case 'NCHD': // Nikon:MakerNoteVersion - https://exiftool.org/TagNames/Nikon.html 1660 $makerNoteVersion = ''; 1661 for ($i = 0, $iMax = strlen($atom_data); $i < $iMax; ++$i) { 1662 if (ord($atom_data[$i]) >= 0x00 && ord($atom_data[$i]) <= 0x1F) { 1663 $makerNoteVersion .= ' '.ord($atom_data[$i]); 1664 } else { 1665 $makerNoteVersion .= $atom_data[$i]; 1666 } 1667 } 1668 $makerNoteVersion = rtrim($makerNoteVersion, "\x00"); 1669 $atom_structure['data'] = array( 1670 'MakerNoteVersion' => $makerNoteVersion 1671 ); 1672 break; 1673 case 'NCDB': // Nikon - https://exiftool.org/TagNames/Nikon.html 1674 case 'CNCV': // Canon:CompressorVersion - https://exiftool.org/TagNames/Canon.html 1611 $atom_structure['description'] = (($atomname == 'NCTH') ? 'Nikon Camera Thumbnail Image' : (($atomname == 'NCVW') ? 'Nikon Camera Preview Image' : 'Nikon preview image')); 1612 $info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_data, 'description'=>$atom_structure['description']); 1613 } 1614 break; 1615 case 'NCTG': // Nikon - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG 1616 $atom_structure['data'] = $this->QuicktimeParseNikonNCTG($atom_data); 1617 break; 1618 case 'NCHD': // Nikon:MakerNoteVersion - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html 1619 case 'NCDB': // Nikon - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html 1620 case 'CNCV': // Canon:CompressorVersion - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Canon.html 1675 1621 $atom_structure['data'] = $atom_data; 1676 1622 break; … … 1679 1625 // some kind of metacontainer, may contain a big data dump such as: 1680 1626 // mdta keys \005 mdtacom.apple.quicktime.make (mdtacom.apple.quicktime.creationdate ,mdtacom.apple.quicktime.location.ISO6709 $mdtacom.apple.quicktime.software !mdtacom.apple.quicktime.model ilst \01D \001 \015data \001DE\010Apple 0 \002 (data \001DE\0102011-05-11T17:54:04+0200 2 \003 *data \001DE\010+52.4936+013.3897+040.247/ \01D \004 \015data \001DE\0104.3.1 \005 \018data \001DE\010iPhone 4 1681 // http s://xhelmboyx.tripod.com/formats/qti-layout.txt1627 // http://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt 1682 1628 1683 1629 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); … … 1776 1722 'debug_list' => '', // Used to debug variables stored as comma delimited strings 1777 1723 ); 1778 $debug_structure = array();1779 1724 $debug_structure['debug_items'] = array(); 1780 1725 // Can start loop here to decode all sensor data in 32 Byte chunks: … … 2095 2040 */ 2096 2041 public function QuicktimeParseContainerAtom($atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) { 2097 $atom_structure = array();2042 $atom_structure = false; 2098 2043 $subatomoffset = 0; 2099 2044 $subatomcounter = 0; … … 2113 2058 continue; 2114 2059 } 2115 break;2060 return $atom_structure; 2116 2061 } 2117 2062 if (strlen($subatomdata) < ($subatomsize - 8)) { … … 2119 2064 // this may be because we are refusing to parse large subatoms, or it may be because this atom had its size set too large 2120 2065 // so we passed in the start of a following atom incorrectly? 2121 break;2066 return $atom_structure; 2122 2067 } 2123 2068 $atom_structure[$subatomcounter++] = $this->QuicktimeParseAtom($subatomname, $subatomsize, $subatomdata, $baseoffset + $subatomoffset, $atomHierarchy, $ParseAllPossibleAtoms); 2124 2069 $subatomoffset += $subatomsize; 2125 2070 } 2126 2127 if (empty($atom_structure)) {2128 return false;2129 }2130 2131 2071 return $atom_structure; 2132 2072 } … … 2613 2553 if (empty($QuicktimeContentRatingLookup)) { 2614 2554 $QuicktimeContentRatingLookup[0] = 'None'; 2615 $QuicktimeContentRatingLookup[1] = 'Explicit';2616 2555 $QuicktimeContentRatingLookup[2] = 'Clean'; 2617 $QuicktimeContentRatingLookup[4] = 'Explicit (old)';2556 $QuicktimeContentRatingLookup[4] = 'Explicit'; 2618 2557 } 2619 2558 return (isset($QuicktimeContentRatingLookup[$rtng]) ? $QuicktimeContentRatingLookup[$rtng] : 'invalid'); … … 2666 2605 } 2667 2606 return (isset($QuicktimeStoreFrontCodeLookup[$sfid]) ? $QuicktimeStoreFrontCodeLookup[$sfid] : 'invalid'); 2607 } 2608 2609 /** 2610 * @param string $atom_data 2611 * 2612 * @return array 2613 */ 2614 public function QuicktimeParseNikonNCTG($atom_data) { 2615 // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG 2616 // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100 2617 // Data is stored as records of: 2618 // * 4 bytes record type 2619 // * 2 bytes size of data field type: 2620 // 0x0001 = flag (size field *= 1-byte) 2621 // 0x0002 = char (size field *= 1-byte) 2622 // 0x0003 = DWORD+ (size field *= 2-byte), values are stored CDAB 2623 // 0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD 2624 // 0x0005 = float (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together 2625 // 0x0007 = bytes (size field *= 1-byte), values are stored as ?????? 2626 // 0x0008 = ????? (size field *= 2-byte), values are stored as ?????? 2627 // * 2 bytes data size field 2628 // * ? bytes data (string data may be null-padded; datestamp fields are in the format "2011:05:25 20:24:15") 2629 // all integers are stored BigEndian 2630 2631 $NCTGtagName = array( 2632 0x00000001 => 'Make', 2633 0x00000002 => 'Model', 2634 0x00000003 => 'Software', 2635 0x00000011 => 'CreateDate', 2636 0x00000012 => 'DateTimeOriginal', 2637 0x00000013 => 'FrameCount', 2638 0x00000016 => 'FrameRate', 2639 0x00000022 => 'FrameWidth', 2640 0x00000023 => 'FrameHeight', 2641 0x00000032 => 'AudioChannels', 2642 0x00000033 => 'AudioBitsPerSample', 2643 0x00000034 => 'AudioSampleRate', 2644 0x02000001 => 'MakerNoteVersion', 2645 0x02000005 => 'WhiteBalance', 2646 0x0200000b => 'WhiteBalanceFineTune', 2647 0x0200001e => 'ColorSpace', 2648 0x02000023 => 'PictureControlData', 2649 0x02000024 => 'WorldTime', 2650 0x02000032 => 'UnknownInfo', 2651 0x02000083 => 'LensType', 2652 0x02000084 => 'Lens', 2653 ); 2654 2655 $offset = 0; 2656 $data = null; 2657 $datalength = strlen($atom_data); 2658 $parsed = array(); 2659 while ($offset < $datalength) { 2660 $record_type = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4)); $offset += 4; 2661 $data_size_type = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2)); $offset += 2; 2662 $data_size = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2)); $offset += 2; 2663 switch ($data_size_type) { 2664 case 0x0001: // 0x0001 = flag (size field *= 1-byte) 2665 $data = getid3_lib::BigEndian2Int(substr($atom_data, $offset, $data_size * 1)); 2666 $offset += ($data_size * 1); 2667 break; 2668 case 0x0002: // 0x0002 = char (size field *= 1-byte) 2669 $data = substr($atom_data, $offset, $data_size * 1); 2670 $offset += ($data_size * 1); 2671 $data = rtrim($data, "\x00"); 2672 break; 2673 case 0x0003: // 0x0003 = DWORD+ (size field *= 2-byte), values are stored CDAB 2674 $data = ''; 2675 for ($i = $data_size - 1; $i >= 0; $i--) { 2676 $data .= substr($atom_data, $offset + ($i * 2), 2); 2677 } 2678 $data = getid3_lib::BigEndian2Int($data); 2679 $offset += ($data_size * 2); 2680 break; 2681 case 0x0004: // 0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD 2682 $data = ''; 2683 for ($i = $data_size - 1; $i >= 0; $i--) { 2684 $data .= substr($atom_data, $offset + ($i * 4), 4); 2685 } 2686 $data = getid3_lib::BigEndian2Int($data); 2687 $offset += ($data_size * 4); 2688 break; 2689 case 0x0005: // 0x0005 = float (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together 2690 $data = array(); 2691 for ($i = 0; $i < $data_size; $i++) { 2692 $numerator = getid3_lib::BigEndian2Int(substr($atom_data, $offset + ($i * 8) + 0, 4)); 2693 $denomninator = getid3_lib::BigEndian2Int(substr($atom_data, $offset + ($i * 8) + 4, 4)); 2694 if ($denomninator == 0) { 2695 $data[$i] = false; 2696 } else { 2697 $data[$i] = (double) $numerator / $denomninator; 2698 } 2699 } 2700 $offset += (8 * $data_size); 2701 if (count($data) == 1) { 2702 $data = $data[0]; 2703 } 2704 break; 2705 case 0x0007: // 0x0007 = bytes (size field *= 1-byte), values are stored as ?????? 2706 $data = substr($atom_data, $offset, $data_size * 1); 2707 $offset += ($data_size * 1); 2708 break; 2709 case 0x0008: // 0x0008 = ????? (size field *= 2-byte), values are stored as ?????? 2710 $data = substr($atom_data, $offset, $data_size * 2); 2711 $offset += ($data_size * 2); 2712 break; 2713 default: 2714 echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br>'; 2715 break 2; 2716 } 2717 2718 switch ($record_type) { 2719 case 0x00000011: // CreateDate 2720 case 0x00000012: // DateTimeOriginal 2721 $data = strtotime($data); 2722 break; 2723 case 0x0200001e: // ColorSpace 2724 switch ($data) { 2725 case 1: 2726 $data = 'sRGB'; 2727 break; 2728 case 2: 2729 $data = 'Adobe RGB'; 2730 break; 2731 } 2732 break; 2733 case 0x02000023: // PictureControlData 2734 $PictureControlAdjust = array(0=>'default', 1=>'quick', 2=>'full'); 2735 $FilterEffect = array(0x80=>'off', 0x81=>'yellow', 0x82=>'orange', 0x83=>'red', 0x84=>'green', 0xff=>'n/a'); 2736 $ToningEffect = array(0x80=>'b&w', 0x81=>'sepia', 0x82=>'cyanotype', 0x83=>'red', 0x84=>'yellow', 0x85=>'green', 0x86=>'blue-green', 0x87=>'blue', 0x88=>'purple-blue', 0x89=>'red-purple', 0xff=>'n/a'); 2737 $data = array( 2738 'PictureControlVersion' => substr($data, 0, 4), 2739 'PictureControlName' => rtrim(substr($data, 4, 20), "\x00"), 2740 'PictureControlBase' => rtrim(substr($data, 24, 20), "\x00"), 2741 //'?' => substr($data, 44, 4), 2742 'PictureControlAdjust' => $PictureControlAdjust[ord(substr($data, 48, 1))], 2743 'PictureControlQuickAdjust' => ord(substr($data, 49, 1)), 2744 'Sharpness' => ord(substr($data, 50, 1)), 2745 'Contrast' => ord(substr($data, 51, 1)), 2746 'Brightness' => ord(substr($data, 52, 1)), 2747 'Saturation' => ord(substr($data, 53, 1)), 2748 'HueAdjustment' => ord(substr($data, 54, 1)), 2749 'FilterEffect' => $FilterEffect[ord(substr($data, 55, 1))], 2750 'ToningEffect' => $ToningEffect[ord(substr($data, 56, 1))], 2751 'ToningSaturation' => ord(substr($data, 57, 1)), 2752 ); 2753 break; 2754 case 0x02000024: // WorldTime 2755 // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#WorldTime 2756 // timezone is stored as offset from GMT in minutes 2757 $timezone = getid3_lib::BigEndian2Int(substr($data, 0, 2)); 2758 if ($timezone & 0x8000) { 2759 $timezone = 0 - (0x10000 - $timezone); 2760 } 2761 $timezone /= 60; 2762 2763 $dst = (bool) getid3_lib::BigEndian2Int(substr($data, 2, 1)); 2764 switch (getid3_lib::BigEndian2Int(substr($data, 3, 1))) { 2765 case 2: 2766 $datedisplayformat = 'D/M/Y'; break; 2767 case 1: 2768 $datedisplayformat = 'M/D/Y'; break; 2769 case 0: 2770 default: 2771 $datedisplayformat = 'Y/M/D'; break; 2772 } 2773 2774 $data = array('timezone'=>floatval($timezone), 'dst'=>$dst, 'display'=>$datedisplayformat); 2775 break; 2776 case 0x02000083: // LensType 2777 $data = array( 2778 //'_' => $data, 2779 'mf' => (bool) ($data & 0x01), 2780 'd' => (bool) ($data & 0x02), 2781 'g' => (bool) ($data & 0x04), 2782 'vr' => (bool) ($data & 0x08), 2783 ); 2784 break; 2785 } 2786 $tag_name = (isset($NCTGtagName[$record_type]) ? $NCTGtagName[$record_type] : '0x'.str_pad(dechex($record_type), 8, '0', STR_PAD_LEFT)); 2787 $parsed[$tag_name] = $data; 2788 } 2789 return $parsed; 2668 2790 } 2669 2791
Note: See TracChangeset
for help on using the changeset viewer.