- Timestamp:
- 10/10/2021 12:12:03 AM (3 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/ID3/module.audio-video.quicktime.php
r48278 r51900 25 25 { 26 26 27 public $ReturnAtomData = true; 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 */ 28 39 public $ParseAllPossibleAtoms = false; 29 40 … … 171 182 } 172 183 173 if (!isset($info['bitrate']) && isset($info['playtime_seconds'])) {184 if (!isset($info['bitrate']) && !empty($info['playtime_seconds'])) { 174 185 $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; 175 186 } … … 561 572 $atom_structure['data'] = substr($boxdata, 8); 562 573 if ($atomname == 'covr') { 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'; 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); 570 595 } 571 $info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_structure['data'], 'description'=>'cover');572 596 } 573 597 break; … … 729 753 $atom_structure['flags']['slide_show'] = (bool) $atom_structure['slide_show_flag']; 730 754 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'; 755 $ptv_lookup = array( 756 0 => 'normal', 757 1 => 'double', 758 2 => 'half', 759 3 => 'full', 760 4 => 'current' 761 ); 736 762 if (isset($ptv_lookup[$atom_structure['display_size_raw']])) { 737 763 $atom_structure['display_size'] = $ptv_lookup[$atom_structure['display_size_raw']]; … … 909 935 $atom_structure['sample_description_table'][$i]['video_color_table_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 68, 2)); 910 936 911 $atom_structure['sample_description_table'][$i]['video_pixel_color_type'] = (( $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color');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'); 912 938 $atom_structure['sample_description_table'][$i]['video_pixel_color_name'] = $this->QuicktimeColorNameLookup($atom_structure['sample_description_table'][$i]['video_pixel_color_depth']); 913 939 … … 915 941 $info['quicktime']['video']['codec_fourcc'] = $atom_structure['sample_description_table'][$i]['data_format']; 916 942 $info['quicktime']['video']['codec_fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($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']);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']); 918 944 $info['quicktime']['video']['color_depth'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_depth']; 919 945 $info['quicktime']['video']['color_depth_name'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_name']; … … 1599 1625 1600 1626 case 'NCDT': 1601 // http ://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html1627 // https://exiftool.org/TagNames/Nikon.html 1602 1628 // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100 1603 1629 $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 4, $atomHierarchy, $ParseAllPossibleAtoms); … … 1605 1631 case 'NCTH': // Nikon Camera THumbnail image 1606 1632 case 'NCVW': // Nikon Camera preVieW image 1607 // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html 1633 case 'NCM1': // Nikon Camera preview iMage 1 1634 case 'NCM2': // Nikon Camera preview iMage 2 1635 // https://exiftool.org/TagNames/Nikon.html 1608 1636 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 ); 1609 1643 $atom_structure['data'] = $atom_data; 1610 1644 $atom_structure['image_mime'] = 'image/jpeg'; 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 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 1621 1675 $atom_structure['data'] = $atom_data; 1622 1676 break; … … 1625 1679 // some kind of metacontainer, may contain a big data dump such as: 1626 1680 // 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 1627 // http ://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt1681 // https://xhelmboyx.tripod.com/formats/qti-layout.txt 1628 1682 1629 1683 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); … … 1722 1776 'debug_list' => '', // Used to debug variables stored as comma delimited strings 1723 1777 ); 1778 $debug_structure = array(); 1724 1779 $debug_structure['debug_items'] = array(); 1725 1780 // Can start loop here to decode all sensor data in 32 Byte chunks: … … 2040 2095 */ 2041 2096 public function QuicktimeParseContainerAtom($atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) { 2042 $atom_structure = false;2097 $atom_structure = array(); 2043 2098 $subatomoffset = 0; 2044 2099 $subatomcounter = 0; … … 2058 2113 continue; 2059 2114 } 2060 return $atom_structure;2115 break; 2061 2116 } 2062 2117 if (strlen($subatomdata) < ($subatomsize - 8)) { … … 2064 2119 // this may be because we are refusing to parse large subatoms, or it may be because this atom had its size set too large 2065 2120 // so we passed in the start of a following atom incorrectly? 2066 return $atom_structure;2121 break; 2067 2122 } 2068 2123 $atom_structure[$subatomcounter++] = $this->QuicktimeParseAtom($subatomname, $subatomsize, $subatomdata, $baseoffset + $subatomoffset, $atomHierarchy, $ParseAllPossibleAtoms); 2069 2124 $subatomoffset += $subatomsize; 2070 2125 } 2126 2127 if (empty($atom_structure)) { 2128 return false; 2129 } 2130 2071 2131 return $atom_structure; 2072 2132 } … … 2553 2613 if (empty($QuicktimeContentRatingLookup)) { 2554 2614 $QuicktimeContentRatingLookup[0] = 'None'; 2615 $QuicktimeContentRatingLookup[1] = 'Explicit'; 2555 2616 $QuicktimeContentRatingLookup[2] = 'Clean'; 2556 $QuicktimeContentRatingLookup[4] = 'Explicit ';2617 $QuicktimeContentRatingLookup[4] = 'Explicit (old)'; 2557 2618 } 2558 2619 return (isset($QuicktimeContentRatingLookup[$rtng]) ? $QuicktimeContentRatingLookup[$rtng] : 'invalid'); … … 2605 2666 } 2606 2667 return (isset($QuicktimeStoreFrontCodeLookup[$sfid]) ? $QuicktimeStoreFrontCodeLookup[$sfid] : 'invalid'); 2607 }2608 2609 /**2610 * @param string $atom_data2611 *2612 * @return array2613 */2614 public function QuicktimeParseNikonNCTG($atom_data) {2615 // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG2616 // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D51002617 // Data is stored as records of:2618 // * 4 bytes record type2619 // * 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 CDAB2623 // 0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD2624 // 0x0005 = float (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together2625 // 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 field2628 // * ? 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 BigEndian2630 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 CDAB2674 $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 EFGHABCD2682 $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 together2690 $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: // CreateDate2720 case 0x00000012: // DateTimeOriginal2721 $data = strtotime($data);2722 break;2723 case 0x0200001e: // ColorSpace2724 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: // PictureControlData2734 $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: // WorldTime2755 // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#WorldTime2756 // timezone is stored as offset from GMT in minutes2757 $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: // LensType2777 $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;2790 2668 } 2791 2669
Note: See TracChangeset
for help on using the changeset viewer.