Skip to content

Commit 89d26ca

Browse files
committed
Add OIIO metadata
Signed-off-by: Thomas Manceau <[email protected]>
1 parent ff7cdc1 commit 89d26ca

File tree

6 files changed

+230
-20
lines changed

6 files changed

+230
-20
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
add_src_and_test(ffprobe)
22
add_src_and_test(openexr)
3+
add_src_and_test(openimageio)
34

45
build_studio_plugins("${STUDIO_PLUGINS}")
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
find_package(OpenImageIO)
2+
3+
SET(LINK_DEPS
4+
xstudio::media_metadata
5+
OpenImageIO::OpenImageIO
6+
)
7+
8+
create_plugin_with_alias(media_metadata_openimageio xstudio::media_metadata::openimageio ${XSTUDIO_GLOBAL_VERSION} "${LINK_DEPS}")
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
#include "openimageio_metadata.hpp"
3+
4+
#include <filesystem>
5+
#include <unordered_set>
6+
7+
#include <OpenImageIO/imageio.h>
8+
#include <OpenImageIO/typedesc.h>
9+
10+
#include "xstudio/utility/helpers.hpp"
11+
12+
namespace fs = std::filesystem;
13+
14+
using namespace xstudio::media_metadata;
15+
using namespace xstudio::utility;
16+
using namespace xstudio;
17+
18+
OpenImageIOMediaMetadata::OpenImageIOMediaMetadata() : MediaMetadata("OpenImageIO") {}
19+
20+
MMCertainty OpenImageIOMediaMetadata::supported(
21+
const caf::uri &uri, const std::array<uint8_t, 16> &signature) {
22+
// Step 1: List of supported extensions by OIIO
23+
static const std::unordered_set<std::string> supported_extensions = {
24+
"JPG",
25+
"JPEG",
26+
"PNG",
27+
"TIF",
28+
"TIFF",
29+
"TGA",
30+
"BMP",
31+
"PSD",
32+
"HDR",
33+
"DPX",
34+
"ACES",
35+
"JP2",
36+
"J2K",
37+
"WEBP",
38+
"EXR",
39+
};
40+
41+
// Step 2: Convert the URI to a POSIX path string and fs::path
42+
std::string path = uri_to_posix_path(uri);
43+
fs::path p(path);
44+
45+
// Step 3: Check if the file exists and is a regular file
46+
// Return not supported if the file does not exist or is not a regular file
47+
if (!fs::exists(p) || !fs::is_regular_file(p)) {
48+
return MMC_NO;
49+
}
50+
51+
// Step 4: Get the upper-case extension (handling platform differences)
52+
#ifdef _WIN32
53+
std::string ext = ltrim_char(to_upper_path(p.extension()), '.');
54+
#else
55+
std::string ext = ltrim_char(to_upper(p.extension().string()), '.');
56+
#endif
57+
58+
// Step 5: Check if the extension is in the supported list
59+
// Return fully supported if the extension is in the supported list
60+
if (supported_extensions.count(ext)) {
61+
return MMC_FULLY;
62+
}
63+
64+
// Step 6: Try to detect via OIIO if the extension is supported
65+
// Return maybe supported if the extension is supported by OIIO
66+
auto in = OIIO::ImageInput::open(path);
67+
if (in) {
68+
in->close();
69+
return MMC_MAYBE;
70+
}
71+
72+
// Step 7: Return not supported if all checks fail
73+
return MMC_NO;
74+
}
75+
76+
nlohmann::json OpenImageIOMediaMetadata::read_metadata(const caf::uri &uri) {
77+
std::string path = uri_to_posix_path(uri);
78+
79+
try {
80+
// Step 1: Open the image using OpenImageIO
81+
auto in = OIIO::ImageInput::open(path);
82+
if (!in) {
83+
throw std::runtime_error("Cannot open: " + OIIO::geterror());
84+
}
85+
86+
// Step 2: Get the image specification
87+
const OIIO::ImageSpec &spec = in->spec();
88+
89+
// Step 3: Initialize a JSON object for metadata
90+
nlohmann::json metadata;
91+
92+
// Step 4: Populate basic image properties (width, height, resolution)
93+
metadata["width"] = spec.width;
94+
metadata["height"] = spec.height;
95+
metadata["resolution"] = fmt::format("{} x {}", spec.width, spec.height);
96+
97+
// Step 5: Extract and format the file extension (format)
98+
fs::path p(path);
99+
#ifdef _WIN32
100+
std::string ext = ltrim_char(to_upper_path(p.extension()), '.');
101+
#else
102+
std::string ext = ltrim_char(to_upper(p.extension().string()), '.');
103+
#endif
104+
metadata["format"] = ext;
105+
106+
// Step 6: Determine bit depth and add to metadata
107+
if (spec.format == OIIO::TypeDesc::UINT8) {
108+
metadata["bit_depth"] = "8 bits";
109+
} else if (spec.format == OIIO::TypeDesc::UINT16) {
110+
metadata["bit_depth"] = "16 bits";
111+
} else if (spec.format == OIIO::TypeDesc::HALF) {
112+
metadata["bit_depth"] = "16 bits float";
113+
} else if (spec.format == OIIO::TypeDesc::FLOAT) {
114+
metadata["bit_depth"] = "32 bits float";
115+
} else {
116+
metadata["bit_depth"] = "unknown";
117+
}
118+
119+
// Step 7: Read pixel aspect ratio and aspect ratio
120+
metadata["pixel_aspect"] = spec.get_float_attribute("PixelAspectRatio", 1.0f);
121+
metadata["aspect_ratio"] = spec.get_float_attribute("XResolution", spec.width)
122+
/ spec.get_float_attribute("YResolution", spec.height);
123+
124+
// Step 8: Add extra attributes to metadata
125+
for (const auto &param : spec.extra_attribs) {
126+
metadata[param.name().string()] = param.get_string();
127+
}
128+
129+
// Step 9: Return metadata
130+
return metadata;
131+
} catch (const std::exception &e) {
132+
spdlog::error("Failed to read metadata from {}: {}", path, e.what());
133+
return nlohmann::json::object();
134+
}
135+
}
136+
137+
std::optional<MediaMetadata::StandardFields>
138+
OpenImageIOMediaMetadata::fill_standard_fields(const nlohmann::json &metadata) {
139+
// Step 1: Initialize StandardFields and set default format
140+
StandardFields fields;
141+
fields.format_ = "OpenImageIO";
142+
143+
// Step 2: Fill in the resolution if present in metadata
144+
if (metadata.contains("resolution")) {
145+
fields.resolution_ = metadata["resolution"].get<std::string>();
146+
}
147+
148+
// Step 3: Fill in the image extension (format) if present in metadata
149+
if (metadata.contains("format")) {
150+
fields.format_ = metadata["format"].get<std::string>();
151+
}
152+
153+
// Step 4: Fill in the bit depth if present in metadata
154+
if (metadata.contains("bit_depth")) {
155+
fields.bit_depth_ = metadata["bit_depth"].get<std::string>();
156+
}
157+
158+
// Step 5: Fill in the pixel aspect ratio if present in metadata
159+
if (metadata.contains("pixel_aspect")) {
160+
fields.pixel_aspect_ = metadata["pixel_aspect"].get<float>();
161+
}
162+
163+
return std::make_optional(fields);
164+
}
165+
166+
// Point d'entrée du plugin
167+
extern "C" {
168+
plugin_manager::PluginFactoryCollection *plugin_factory_collection_ptr() {
169+
return new plugin_manager::PluginFactoryCollection(
170+
std::vector<std::shared_ptr<plugin_manager::PluginFactory>>({std::make_shared<
171+
MediaMetadataPlugin<MediaMetadataActor<OpenImageIOMediaMetadata>>>(
172+
Uuid("8f3c4a7e-9b2d-4e1f-a5c8-3d6f7e8a9b1c"),
173+
"OpenImageIO",
174+
"xStudio",
175+
"OpenImageIO Media Metadata Reader",
176+
semver::version("1.0.0"))}));
177+
}
178+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
#pragma once
3+
4+
#include <array>
5+
6+
#include <nlohmann/json.hpp>
7+
8+
#include "xstudio/media_metadata/media_metadata.hpp"
9+
10+
namespace xstudio {
11+
namespace media_metadata {
12+
13+
class OpenImageIOMediaMetadata : public MediaMetadata {
14+
public:
15+
OpenImageIOMediaMetadata();
16+
~OpenImageIOMediaMetadata() override = default;
17+
18+
MMCertainty
19+
supported(const caf::uri &uri, const std::array<uint8_t, 16> &signature) override;
20+
21+
protected:
22+
nlohmann::json read_metadata(const caf::uri &uri) override;
23+
std::optional<StandardFields>
24+
fill_standard_fields(const nlohmann::json &metadata) override;
25+
};
26+
27+
} // namespace media_metadata
28+
} // namespace xstudio
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
include(CTest)
2+
3+
SET(LINK_DEPS
4+
CAF::core
5+
)
6+
7+
create_tests("${LINK_DEPS}")

src/plugin/media_reader/openimageio/src/openimageio.cpp

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -127,51 +127,39 @@ OIIOMediaReader::OIIOMediaReader(const utility::JsonStore &prefs) : MediaReader(
127127
}
128128

129129
void OIIOMediaReader::update_preferences(const utility::JsonStore &prefs) {
130-
// Set OIIO threading based on preferences
131130
try {
131+
// Set OIIO threading
132132
int threads =
133133
global_store::preference_value<int>(prefs, "/plugin/media_reader/OIIO/threads");
134-
// Apply thread count to OIIO
135134
OIIO::attribute("threads", threads);
136135
} catch (const std::exception &e) {
137-
// Warn if fetching or applying threads fails
138-
spdlog::warn("{} {}", __PRETTY_FUNCTION__, e.what());
139136
}
140137

141-
// Set OIIO EXR-specific threading
142138
try {
139+
// Set OIIO EXR-specific threading
143140
int exr_threads =
144141
global_store::preference_value<int>(prefs, "/plugin/media_reader/OIIO/exr_threads");
145-
// Apply EXR threads to OIIO
146142
OIIO::attribute("exr_threads", exr_threads);
147143
} catch (const std::exception &e) {
148-
// Warn if something went wrong
149-
spdlog::warn("{} {}", __PRETTY_FUNCTION__, e.what());
150144
}
151145

152-
// Enable or disable TBB in OIIO
153146
try {
147+
// Enable or disable TBB in OIIO
154148
int use_tbb =
155149
global_store::preference_value<int>(prefs, "/plugin/media_reader/OIIO/use_tbb");
156-
// Set TBB usage
157150
OIIO::attribute("use_tbb", use_tbb);
158151
} catch (const std::exception &e) {
159-
// Warn on error retrieving or applying use_tbb
160-
spdlog::warn("{} {}", __PRETTY_FUNCTION__, e.what());
161152
}
162153

163-
// Set OIIO log times preference
164-
// When the "log_times" attribute is nonzero, ImageBufAlgo functions are instrumented to
165-
// record the number of times they were called and the total amount of time spent executing
166-
// them.
167154
try {
155+
// Set OIIO log times preference
156+
// When the "log_times" attribute is nonzero, ImageBufAlgo functions are instrumented to
157+
// record the number of times they were called and the total amount of time spent
158+
// executing them.
168159
int log_times =
169160
global_store::preference_value<int>(prefs, "/plugin/media_reader/OIIO/log_times");
170-
// Enable or disable logging of times
171161
OIIO::attribute("log_times", log_times);
172162
} catch (const std::exception &e) {
173-
// Warn if log_times config fails
174-
spdlog::warn("{} {}", __PRETTY_FUNCTION__, e.what());
175163
}
176164
}
177165

@@ -971,7 +959,7 @@ plugin_manager::PluginFactoryCollection *plugin_factory_collection_ptr() {
971959
std::vector<std::shared_ptr<plugin_manager::PluginFactory>>(
972960
{std::make_shared<MediaReaderPlugin<MediaReaderActor<OIIOMediaReader>>>(
973961
s_plugin_uuid,
974-
"OIIO",
962+
"OpenImageIO",
975963
"xStudio",
976964
"OpenImageIO Media Reader",
977965
semver::version("1.0.0"))}));

0 commit comments

Comments
 (0)