|
2 | 2 | // SPDX-License-Identifier: Apache-2.0 |
3 | 3 | // https://github.com/AcademySoftwareFoundation/OpenImageIO |
4 | 4 |
|
| 5 | +#include <algorithm> |
5 | 6 | #include <cmath> |
6 | 7 | #include <iomanip> |
7 | 8 | #include <memory> |
| 9 | +#include <utility> |
8 | 10 |
|
9 | 11 | #include <OpenEXR/ImfTimeCode.h> //For TimeCode support |
10 | 12 |
|
@@ -77,20 +79,16 @@ class DPXInput final : public ImageInput { |
77 | 79 | } |
78 | 80 |
|
79 | 81 | /// Helper function - retrieve string for libdpx characteristic |
80 | | - /// |
81 | 82 | std::string get_characteristic_string(dpx::Characteristic c); |
82 | 83 |
|
83 | 84 | /// Helper function - retrieve string for libdpx descriptor |
84 | | - /// |
85 | 85 | std::string get_descriptor_string(dpx::Descriptor c); |
86 | 86 |
|
87 | 87 | /// Helper function - fill int array with KeyCode values |
88 | | - /// |
89 | | - void get_keycode_values(int* array); |
| 88 | + void get_keycode_values(span<int> array); |
90 | 89 |
|
91 | 90 | /// Helper function - convert Imf::TimeCode to string; |
92 | | - /// |
93 | | - std::string get_timecode_string(Imf::TimeCode& tc); |
| 91 | + std::string get_timecode_string(const Imf::TimeCode& tc); |
94 | 92 | }; |
95 | 93 |
|
96 | 94 |
|
@@ -174,6 +172,22 @@ DPXInput::open(const std::string& name, ImageSpec& newspec, |
174 | 172 |
|
175 | 173 |
|
176 | 174 |
|
| 175 | +// Helper, given key and a span of (KEY,VAL) pairs, look up which item |
| 176 | +// matches. If no key is found, then return the defaultval. |
| 177 | +template<typename KEY, typename VAL> |
| 178 | +const VAL& |
| 179 | +lookup(const KEY& key, cspan<std::pair<KEY, VAL>> values, const VAL& defaultval) |
| 180 | +{ |
| 181 | + OIIO_ASSERT(values.size() >= 2); |
| 182 | + auto found = std::find_if(values.begin(), values.end(), |
| 183 | + [&key](const std::pair<KEY, VAL>& v) { |
| 184 | + return v.first == key; |
| 185 | + }); |
| 186 | + return (found != values.end()) ? found->second : defaultval; |
| 187 | +} |
| 188 | + |
| 189 | + |
| 190 | + |
177 | 191 | bool |
178 | 192 | DPXInput::seek_subimage(int subimage, int miplevel) |
179 | 193 | { |
@@ -294,18 +308,18 @@ DPXInput::seek_subimage(int subimage, int miplevel) |
294 | 308 | // bits per pixel |
295 | 309 | m_spec.attribute("oiio:BitsPerSample", m_dpx.header.BitDepth(subimage)); |
296 | 310 | // image orientation - see appendix B.2 of the OIIO documentation |
297 | | - int orientation; |
298 | | - switch (m_dpx.header.ImageOrientation()) { |
299 | | - case dpx::kLeftToRightTopToBottom: orientation = 1; break; |
300 | | - case dpx::kRightToLeftTopToBottom: orientation = 2; break; |
301 | | - case dpx::kLeftToRightBottomToTop: orientation = 4; break; |
302 | | - case dpx::kRightToLeftBottomToTop: orientation = 3; break; |
303 | | - case dpx::kTopToBottomLeftToRight: orientation = 5; break; |
304 | | - case dpx::kTopToBottomRightToLeft: orientation = 6; break; |
305 | | - case dpx::kBottomToTopLeftToRight: orientation = 8; break; |
306 | | - case dpx::kBottomToTopRightToLeft: orientation = 7; break; |
307 | | - default: orientation = 0; break; |
308 | | - } |
| 311 | + static const std::pair<dpx::Orientation, int> orientation_table[] |
| 312 | + = { { dpx::kLeftToRightTopToBottom, 1 }, |
| 313 | + { dpx::kRightToLeftTopToBottom, 2 }, |
| 314 | + { dpx::kLeftToRightBottomToTop, 4 }, |
| 315 | + { dpx::kRightToLeftBottomToTop, 3 }, |
| 316 | + { dpx::kTopToBottomLeftToRight, 5 }, |
| 317 | + { dpx::kTopToBottomRightToLeft, 6 }, |
| 318 | + { dpx::kBottomToTopLeftToRight, 8 }, |
| 319 | + { dpx::kBottomToTopRightToLeft, 7 } }; |
| 320 | + int orientation |
| 321 | + = lookup<dpx::Orientation, int>(m_dpx.header.ImageOrientation(), |
| 322 | + orientation_table, 1); |
309 | 323 | m_spec.attribute("Orientation", orientation); |
310 | 324 |
|
311 | 325 | m_spec.attribute("oiio:subimages", (int)m_dpx.header.ImageElementCount()); |
@@ -495,51 +509,31 @@ DPXInput::seek_subimage(int subimage, int miplevel) |
495 | 509 | m_spec.attribute("dpx:FilmEdgeCode", filmedge); |
496 | 510 | } |
497 | 511 |
|
498 | | - tmpstr.clear(); |
499 | | - switch (m_dpx.header.Signal()) { |
500 | | - case dpx::kUndefined: tmpstr = "Undefined"; break; |
501 | | - case dpx::kNTSC: tmpstr = "NTSC"; break; |
502 | | - case dpx::kPAL: tmpstr = "PAL"; break; |
503 | | - case dpx::kPAL_M: tmpstr = "PAL-M"; break; |
504 | | - case dpx::kSECAM: tmpstr = "SECAM"; break; |
505 | | - case dpx::k525LineInterlace43AR: |
506 | | - tmpstr = "YCbCr ITU-R 601-5 525i, 4:3"; |
507 | | - break; |
508 | | - case dpx::k625LineInterlace43AR: |
509 | | - tmpstr = "YCbCr ITU-R 601-5 625i, 4:3"; |
510 | | - break; |
511 | | - case dpx::k525LineInterlace169AR: |
512 | | - tmpstr = "YCbCr ITU-R 601-5 525i, 16:9"; |
513 | | - break; |
514 | | - case dpx::k625LineInterlace169AR: |
515 | | - tmpstr = "YCbCr ITU-R 601-5 625i, 16:9"; |
516 | | - break; |
517 | | - case dpx::k1050LineInterlace169AR: tmpstr = "YCbCr 1050i, 16:9"; break; |
518 | | - case dpx::k1125LineInterlace169AR_274: |
519 | | - tmpstr = "YCbCr 1125i, 16:9 (SMPTE 274M)"; |
520 | | - break; |
521 | | - case dpx::k1250LineInterlace169AR: tmpstr = "YCbCr 1250i, 16:9"; break; |
522 | | - case dpx::k1125LineInterlace169AR_240: |
523 | | - tmpstr = "YCbCr 1125i, 16:9 (SMPTE 240M)"; |
524 | | - break; |
525 | | - case dpx::k525LineProgressive169AR: tmpstr = "YCbCr 525p, 16:9"; break; |
526 | | - case dpx::k625LineProgressive169AR: tmpstr = "YCbCr 625p, 16:9"; break; |
527 | | - case dpx::k750LineProgressive169AR: |
528 | | - tmpstr = "YCbCr 750p, 16:9 (SMPTE 296M)"; |
529 | | - break; |
530 | | - case dpx::k1125LineProgressive169AR: |
531 | | - tmpstr = "YCbCr 1125p, 16:9 (SMPTE 274M)"; |
532 | | - break; |
533 | | - case dpx::k255: |
534 | | - // don't set the attribute at all |
535 | | - break; |
536 | | - default: |
537 | | - tmpstr = Strutil::fmt::format("Undefined {}", |
538 | | - (int)m_dpx.header.Signal()); |
539 | | - break; |
540 | | - } |
541 | | - if (!tmpstr.empty()) |
542 | | - m_spec.attribute("dpx:Signal", tmpstr); |
| 512 | + static const std::pair<dpx::VideoSignal, const char*> signal_table[] = { |
| 513 | + { dpx::kUndefined, "Undefined" }, |
| 514 | + { dpx::kNTSC, "NTSC" }, |
| 515 | + { dpx::kPAL, "PAL" }, |
| 516 | + { dpx::kPAL_M, "PAL-M" }, |
| 517 | + { dpx::kSECAM, "SECAM" }, |
| 518 | + { dpx::k525LineInterlace43AR, "YCbCr ITU-R 601-5 525i, 4:3" }, |
| 519 | + { dpx::k625LineInterlace43AR, "YCbCr ITU-R 601-5 625i, 4:3" }, |
| 520 | + { dpx::k525LineInterlace169AR, "YCbCr ITU-R 601-5 525i, 16:9" }, |
| 521 | + { dpx::k625LineInterlace169AR, "YCbCr ITU-R 601-5 625i, 16:9" }, |
| 522 | + { dpx::k1050LineInterlace169AR, "YCbCr 1050i, 16:9" }, |
| 523 | + { dpx::k1125LineInterlace169AR_274, "YCbCr 1125i, 16:9 (SMPTE 274M)" }, |
| 524 | + { dpx::k1250LineInterlace169AR, "YCbCr 1250i, 16:9" }, |
| 525 | + { dpx::k1125LineInterlace169AR_240, "YCbCr 1125i, 16:9 (SMPTE 240M)" }, |
| 526 | + { dpx::k525LineProgressive169AR, "YCbCr 525p, 16:9" }, |
| 527 | + { dpx::k625LineProgressive169AR, "YCbCr 625p, 16:9" }, |
| 528 | + { dpx::k750LineProgressive169AR, "YCbCr 750p, 16:9 (SMPTE 296M)" }, |
| 529 | + { dpx::k1125LineProgressive169AR, "YCbCr 1125p, 16:9 (SMPTE 274M)" }, |
| 530 | + { dpx::k255, nullptr /* don't set the attribute at all */ }, |
| 531 | + }; |
| 532 | + const char* signal |
| 533 | + = lookup<dpx::VideoSignal, const char*>(m_dpx.header.Signal(), |
| 534 | + signal_table, "Undefined"); |
| 535 | + if (signal) |
| 536 | + m_spec.attribute("dpx:Signal", signal); |
543 | 537 |
|
544 | 538 | // read in user data; don't bother if the buffer is already filled (user |
545 | 539 | // data is per-file, not per-element) |
@@ -619,147 +613,114 @@ DPXInput::read_native_scanlines(int subimage, int miplevel, int ybegin, |
619 | 613 | std::string |
620 | 614 | DPXInput::get_characteristic_string(dpx::Characteristic c) |
621 | 615 | { |
622 | | - switch (c) { |
623 | | - case dpx::kUserDefined: return "User defined"; |
624 | | - case dpx::kPrintingDensity: return "Printing density"; |
625 | | - case dpx::kLinear: return "Linear"; |
626 | | - case dpx::kLogarithmic: return "Logarithmic"; |
627 | | - case dpx::kUnspecifiedVideo: return "Unspecified video"; |
628 | | - case dpx::kSMPTE274M: return "SMPTE 274M"; |
629 | | - case dpx::kITUR709: return "ITU-R 709-4"; |
630 | | - case dpx::kITUR601: return "ITU-R 601-5 system B or G"; |
631 | | - case dpx::kITUR602: return "ITU-R 601-5 system M"; |
632 | | - case dpx::kNTSCCompositeVideo: return "NTSC composite video"; |
633 | | - case dpx::kPALCompositeVideo: return "PAL composite video"; |
634 | | - case dpx::kZLinear: return "Z depth linear"; |
635 | | - case dpx::kZHomogeneous: return "Z depth homogeneous"; |
636 | | - case dpx::kADX: return "ADX"; |
637 | | - case dpx::kUndefinedCharacteristic: |
638 | | - default: return "Undefined"; |
639 | | - } |
| 616 | + // using Val = std::pair<dpx::Characteristic, const char*> |
| 617 | + static const std::pair<dpx::Characteristic, const char*> table[] { |
| 618 | + { dpx::kUserDefined, "User defined" }, |
| 619 | + { dpx::kPrintingDensity, "Printing density" }, |
| 620 | + { dpx::kLinear, "Linear" }, |
| 621 | + { dpx::kLogarithmic, "Logarithmic" }, |
| 622 | + { dpx::kUnspecifiedVideo, "Unspecified video" }, |
| 623 | + { dpx::kSMPTE274M, "SMPTE 274M" }, |
| 624 | + { dpx::kITUR709, "ITU-R 709-4" }, |
| 625 | + { dpx::kITUR601, "ITU-R 601-5 system B or G" }, |
| 626 | + { dpx::kITUR602, "ITU-R 601-5 system M" }, |
| 627 | + { dpx::kNTSCCompositeVideo, "NTSC composite video" }, |
| 628 | + { dpx::kPALCompositeVideo, "PAL composite video" }, |
| 629 | + { dpx::kZLinear, "Z depth linear" }, |
| 630 | + { dpx::kZHomogeneous, "Z depth homogeneous" }, |
| 631 | + { dpx::kADX, "ADX" }, |
| 632 | + { dpx::kUndefinedCharacteristic, "Undefined" } |
| 633 | + }; |
| 634 | + return lookup<dpx::Characteristic, const char*>(c, table, "Undefined"); |
640 | 635 | } |
641 | 636 |
|
642 | 637 |
|
643 | 638 |
|
644 | 639 | std::string |
645 | 640 | DPXInput::get_descriptor_string(dpx::Descriptor c) |
646 | 641 | { |
647 | | - switch (c) { |
648 | | - case dpx::kUserDefinedDescriptor: |
649 | | - case dpx::kUserDefined2Comp: |
650 | | - case dpx::kUserDefined3Comp: |
651 | | - case dpx::kUserDefined4Comp: |
652 | | - case dpx::kUserDefined5Comp: |
653 | | - case dpx::kUserDefined6Comp: |
654 | | - case dpx::kUserDefined7Comp: |
655 | | - case dpx::kUserDefined8Comp: return "User defined"; |
656 | | - case dpx::kRed: return "Red"; |
657 | | - case dpx::kGreen: return "Green"; |
658 | | - case dpx::kBlue: return "Blue"; |
659 | | - case dpx::kAlpha: return "Alpha"; |
660 | | - case dpx::kLuma: return "Luma"; |
661 | | - case dpx::kColorDifference: return "Color difference"; |
662 | | - case dpx::kDepth: return "Depth"; |
663 | | - case dpx::kCompositeVideo: return "Composite video"; |
664 | | - case dpx::kRGB: return "RGB"; |
665 | | - case dpx::kRGBA: return "RGBA"; |
666 | | - case dpx::kABGR: return "ABGR"; |
667 | | - case dpx::kCbYCrY: return "CbYCrY"; |
668 | | - case dpx::kCbYACrYA: return "CbYACrYA"; |
669 | | - case dpx::kCbYCr: return "CbYCr"; |
670 | | - case dpx::kCbYCrA: return "CbYCrA"; |
671 | | - //case dpx::kUndefinedDescriptor: |
672 | | - default: return "Undefined"; |
673 | | - } |
| 642 | + static const std::pair<dpx::Descriptor, const char*> table[] { |
| 643 | + { dpx::kUserDefinedDescriptor, "User defined" }, |
| 644 | + { dpx::kUserDefined2Comp, "User defined" }, |
| 645 | + { dpx::kUserDefined3Comp, "User defined" }, |
| 646 | + { dpx::kUserDefined4Comp, "User defined" }, |
| 647 | + { dpx::kUserDefined5Comp, "User defined" }, |
| 648 | + { dpx::kUserDefined6Comp, "User defined" }, |
| 649 | + { dpx::kUserDefined7Comp, "User defined" }, |
| 650 | + { dpx::kUserDefined8Comp, "User defined" }, |
| 651 | + { dpx::kRed, "Red" }, |
| 652 | + { dpx::kGreen, "Green" }, |
| 653 | + { dpx::kBlue, "Blue" }, |
| 654 | + { dpx::kAlpha, "Alpha" }, |
| 655 | + { dpx::kLuma, "Luma" }, |
| 656 | + { dpx::kColorDifference, "Color difference" }, |
| 657 | + { dpx::kDepth, "Depth" }, |
| 658 | + { dpx::kCompositeVideo, "Composite video" }, |
| 659 | + { dpx::kRGB, "RGB" }, |
| 660 | + { dpx::kRGBA, "RGBA" }, |
| 661 | + { dpx::kABGR, "ABGR" }, |
| 662 | + { dpx::kCbYCrY, "CbYCrY" }, |
| 663 | + { dpx::kCbYACrYA, "CbYACrYA" }, |
| 664 | + { dpx::kCbYCr, "CbYCr" }, |
| 665 | + { dpx::kCbYCrA, "CbYCrA" } |
| 666 | + }; |
| 667 | + return lookup<dpx::Descriptor, const char*>(c, table, "Undefined"); |
674 | 668 | } |
675 | 669 |
|
676 | 670 |
|
677 | 671 |
|
678 | 672 | void |
679 | | -DPXInput::get_keycode_values(int* array) |
| 673 | +DPXInput::get_keycode_values(span<int> array) |
680 | 674 | { |
681 | | - std::stringstream ss; |
682 | | - |
| 675 | + OIIO_ASSERT(array.size() == 7); |
683 | 676 | // Manufacturer code |
684 | | - ss << std::string(m_dpx.header.filmManufacturingIdCode, 2); |
685 | | - ss >> array[0]; |
686 | | - ss.clear(); |
687 | | - ss.str(""); |
688 | | - |
| 677 | + array[0] = Strutil::stoi( |
| 678 | + string_view(m_dpx.header.filmManufacturingIdCode, 2)); |
689 | 679 | // Film type |
690 | | - ss << std::string(m_dpx.header.filmType, 2); |
691 | | - ss >> array[1]; |
692 | | - ss.clear(); |
693 | | - ss.str(""); |
694 | | - |
| 680 | + array[1] = Strutil::stoi(string_view(m_dpx.header.filmType, 2)); |
695 | 681 | // Prefix |
696 | | - ss << std::string(m_dpx.header.prefix, 6); |
697 | | - ss >> array[2]; |
698 | | - ss.clear(); |
699 | | - ss.str(""); |
700 | | - |
| 682 | + array[2] = Strutil::stoi(string_view(m_dpx.header.prefix, 6)); |
701 | 683 | // Count |
702 | | - ss << std::string(m_dpx.header.count, 4); |
703 | | - ss >> array[3]; |
704 | | - ss.clear(); |
705 | | - ss.str(""); |
706 | | - |
| 684 | + array[3] = Strutil::stoi(string_view(m_dpx.header.count, 4)); |
707 | 685 | // Perforation Offset |
708 | | - ss << std::string(m_dpx.header.perfsOffset, 2); |
709 | | - ss >> array[4]; |
710 | | - ss.clear(); |
711 | | - ss.str(""); |
| 686 | + array[4] = Strutil::stoi(string_view(m_dpx.header.perfsOffset, 2)); |
712 | 687 |
|
713 | 688 | // Format |
714 | 689 | std::string format(m_dpx.header.format, 32); |
715 | | - int& perfsPerFrame = array[5]; |
716 | | - int& perfsPerCount = array[6]; |
717 | | - |
718 | | - // default values |
719 | | - perfsPerFrame = 4; |
720 | | - perfsPerCount = 64; |
721 | | - |
| 690 | + int perfsPerFrame = 4; // default values |
| 691 | + int perfsPerCount = 64; |
| 692 | + using Strutil::starts_with; |
722 | 693 | if (format == "8kimax") { |
723 | 694 | perfsPerFrame = 15; |
724 | 695 | perfsPerCount = 120; |
725 | | - } else if (format.substr(0, 4) == "2kvv" || format.substr(0, 4) == "4kvv") { |
| 696 | + } else if (starts_with(format, "2kvv") || starts_with(format, "4kvv")) { |
726 | 697 | perfsPerFrame = 8; |
727 | 698 | } else if (format == "VistaVision") { |
728 | 699 | perfsPerFrame = 8; |
729 | | - } else if (format.substr(0, 4) == "2k35" || format.substr(0, 4) == "4k35") { |
| 700 | + } else if (starts_with(format, "2k35") || starts_with(format, "4k35")) { |
730 | 701 | perfsPerFrame = 4; |
731 | 702 | } else if (format == "Full Aperture") { |
732 | 703 | perfsPerFrame = 4; |
733 | 704 | } else if (format == "Academy") { |
734 | 705 | perfsPerFrame = 4; |
735 | | - } else if (format.substr(0, 7) == "2k3perf" |
736 | | - || format.substr(0, 7) == "4k3perf") { |
| 706 | + } else if (starts_with(format, "2k3perf") |
| 707 | + || starts_with(format, "4k3perf")) { |
737 | 708 | perfsPerFrame = 3; |
738 | 709 | } else if (format == "3perf") { |
739 | 710 | perfsPerFrame = 3; |
740 | 711 | } |
| 712 | + array[5] = perfsPerFrame; |
| 713 | + array[6] = perfsPerCount; |
741 | 714 | } |
742 | 715 |
|
743 | 716 |
|
744 | 717 |
|
745 | 718 | std::string |
746 | | -DPXInput::get_timecode_string(Imf::TimeCode& tc) |
| 719 | +DPXInput::get_timecode_string(const Imf::TimeCode& tc) |
747 | 720 | { |
748 | | - int values[] = { tc.hours(), tc.minutes(), tc.seconds(), tc.frame() }; |
749 | | - std::stringstream ss; |
750 | | - for (int i = 0; i < 4; i++) { |
751 | | - std::ostringstream padded; |
752 | | - padded << std::setw(2) << std::setfill('0') << values[i]; |
753 | | - ss << padded.str(); |
754 | | - if (i != 3) { |
755 | | - if (i == 2) { |
756 | | - tc.dropFrame() ? ss << ';' : ss << ':'; |
757 | | - } else { |
758 | | - ss << ':'; |
759 | | - } |
760 | | - } |
761 | | - } |
762 | | - return ss.str(); |
| 721 | + return Strutil::fmt::format("{:02d}:{:02d}:{:02d}{}{:02d}", tc.hours(), |
| 722 | + tc.minutes(), tc.seconds(), |
| 723 | + (tc.dropFrame() ? ';' : ':'), tc.frame()); |
763 | 724 | } |
764 | 725 |
|
765 | 726 | OIIO_PLUGIN_NAMESPACE_END |
0 commit comments