Skip to content

Add load && save method to ImgFrame - #1852

Open
JakubFara wants to merge 10 commits into
developfrom
feature/imgFrame_load_save
Open

Add load && save method to ImgFrame#1852
JakubFara wants to merge 10 commits into
developfrom
feature/imgFrame_load_save

Conversation

@JakubFara

@JakubFara JakubFara commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

Purpose

  • add load && save functions to ImgFrame
  • This allows to store and load image without any compression with all metadata present.
  • This is useful for the benchmarks / datasets especially when the imgTransformations are present

Notes

  • this can be done for all Buffers except MessageGroup ... for now I did it only for ImgFrame

example of usage:
load_save.py

Summary by CodeRabbit

Release Notes

  • New Features

    • Added disk persistence APIs save(path, metadataOnly=False) and load(path, metadataOnly=False) for image frames, including metadata-only mode that omits payload data.
    • Extended the same file-based persistence (with metadata-only option) to additional datatypes: encoded frames, IMU data, point clouds, and RGBD.
    • Extensionless paths are automatically saved/loaded using a .dai suffix in protobuf-enabled builds.
  • Tests

    • Added on-host roundtrip and failure-mode tests validating full vs metadata-only behavior, pixel/data preservation, .dai path handling, and error handling for missing/invalid files.

@JakubFara
JakubFara marked this pull request as draft June 17, 2026 11:48
@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@JakubFara, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 12 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 43e26112-9623-4723-bd9f-0a59514c86a5

📥 Commits

Reviewing files that changed from the base of the PR and between e9e3b17 and 9760b47.

📒 Files selected for processing (7)
  • include/depthai/pipeline/datatype/EncodedFrame.hpp
  • include/depthai/pipeline/datatype/IMUData.hpp
  • include/depthai/pipeline/datatype/ImgFrame.hpp
  • include/depthai/pipeline/datatype/PointCloudData.hpp
  • include/depthai/pipeline/datatype/RGBDData.hpp
  • src/opencv/ImgFrame.cpp
  • src/utility/ProtoFileIO.hpp
📝 Walkthrough

Walkthrough

Adds protobuf-gated save/load file persistence to shared pipeline datatypes, adds deserialization hooks and file I/O helpers, exposes the APIs in Python, and expands test coverage for roundtrips, metadata-only loads, path handling, and failure cases.

Changes

Protobuf File Persistence

Layer / File(s) Summary
Core API and deserialization hooks
include/depthai/utility/ProtoSerializable.hpp, src/utility/ProtoSerializable.cpp, include/depthai/pipeline/datatype/*.hpp, src/pipeline/datatype/*.cpp, src/opencv/ImgFrame.cpp
Declares protobuf-enabled file persistence on the shared base class, adds derived datatype deserializeProtoMessage overrides, and implements path resolution plus binary file read/write helpers behind DEPTHAI_ENABLE_PROTOBUF.
Python bindings for save/load
bindings/python/src/pipeline/datatype/*.cpp
Registers conditional save and load methods for ImgFrame, EncodedFrame, IMUData, PointCloudData, and RGBDData in the Python layer.
Roundtrip and failure tests
bindings/python/tests/imgframe_test.py, tests/CMakeLists.txt, tests/src/onhost_tests/pipeline/datatype/proto_file_io_test.cpp
Adds Python and on-host coverage for full and metadata-only roundtrips, path extension handling, payload preservation, and error cases for missing or invalid protobuf files.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • luxonis/depthai-core#1715: Main PR’s protobuf file persistence for PointCloudData builds on earlier protobuf serialization behavior for that datatype.

Suggested labels: testable

Suggested reviewers: moratom

Poem

🐇 I hop through bytes and .dai trails,
Save my frames with metadata sails.
Load them back—hop, hop, hooray,
Even empty payloads know the way.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.78% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and clearly describes the ImgFrame load/save addition, which is a real part of the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/imgFrame_load_save

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@bindings/python/tests/imgframe_test.py`:
- Line 187: The assertion checking for an empty payload uses the `.size`
attribute which is not available on all possible Python container types returned
by getData(). Replace the emptiness check on recovered.getData().size == 0 with
len(recovered.getData()) == 0 to use a container-agnostic approach that works
with any standard Python container type.

In `@src/opencv/ImgFrame.cpp`:
- Around line 66-70: The function parseImgFrameBytes creates an unnecessary copy
of the input parameter serialized into packetBytes before assigning it to the
packet structure. Remove the intermediate packetBytes copy and instead directly
use serialized.data() and serialized.size() when assigning packet.data and
packet.length. Apply the same optimization to any other instances in the file
that perform similar redundant buffer copies (referenced at lines 106-108) to
eliminate the avoidable memory overhead and CPU cost on large frames.
- Around line 102-108: The methods ImgFrame::save and ImgFrame::load are defined
only when DEPTHAI_HAVE_OPENCV_SUPPORT is enabled, but their declarations in the
header file are unconditional, causing linker errors when OpenCV is disabled.
Either guard the declarations of save and load methods in the ImgFrame header
with `#ifdef` DEPTHAI_HAVE_OPENCV_SUPPORT preprocessing directives, or provide
stub implementations (that throw or return appropriate error values) for the
non-OpenCV build path to ensure the symbols are available in all configurations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 773f4adb-6c44-424b-bcef-fc616bc3fe8d

📥 Commits

Reviewing files that changed from the base of the PR and between 8910c89 and 13766a9.

📒 Files selected for processing (4)
  • bindings/python/src/pipeline/datatype/ImgFrameBindings.cpp
  • bindings/python/tests/imgframe_test.py
  • include/depthai/pipeline/datatype/ImgFrame.hpp
  • src/opencv/ImgFrame.cpp
📜 Review details
🔇 Additional comments (2)
include/depthai/pipeline/datatype/ImgFrame.hpp (1)

4-4: LGTM!

Also applies to: 363-377

bindings/python/src/pipeline/datatype/ImgFrameBindings.cpp (1)

324-334: No action needed. The pybind11/stl/filesystem.h header is already available through the transitive include chain: ImgFrameBindings.cpp includes DatatypeBindings.hpp, which includes pybind11_common.hpp, which includes <pybind11/stl/filesystem.h> at line 14. The std::filesystem::path caster is properly available for the save and load bindings.

recovered.load(path, metadataOnly=True)

assert_frame_metadata_equal(frame, recovered)
assert recovered.getData().size == 0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use a container-agnostic emptiness check for payload.

The assertion currently depends on a .size attribute, which may not exist for all getData() Python return shapes. Use len(...) == 0 to avoid false test failures.

✅ Proposed fix
-    assert recovered.getData().size == 0
+    assert len(recovered.getData()) == 0
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
assert recovered.getData().size == 0
assert len(recovered.getData()) == 0
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bindings/python/tests/imgframe_test.py` at line 187, The assertion checking
for an empty payload uses the `.size` attribute which is not available on all
possible Python container types returned by getData(). Replace the emptiness
check on recovered.getData().size == 0 with len(recovered.getData()) == 0 to use
a container-agnostic approach that works with any standard Python container
type.

Comment thread src/opencv/ImgFrame.cpp Outdated
Comment on lines +66 to +70
std::shared_ptr<ImgFrame> parseImgFrameBytes(const std::vector<uint8_t>& serialized, bool metadataOnly) {
auto packetBytes = serialized;
streamPacketDesc_t packet{};
packet.data = packetBytes.data();
packet.length = packetBytes.size();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Avoid the extra full-buffer copy during load parse.

parseImgFrameBytes copies serialized into packetBytes before parsing. On large frames this doubles peak memory and adds avoidable CPU overhead.

♻️ Proposed change
-std::shared_ptr<ImgFrame> parseImgFrameBytes(const std::vector<uint8_t>& serialized, bool metadataOnly) {
-    auto packetBytes = serialized;
+std::shared_ptr<ImgFrame> parseImgFrameBytes(std::vector<uint8_t> packetBytes, bool metadataOnly) {
     streamPacketDesc_t packet{};
     packet.data = packetBytes.data();
     packet.length = packetBytes.size();
     packet.fd = -1;
@@
 void ImgFrame::load(const std::filesystem::path& path, bool metadataOnly) {
-    *this = *parseImgFrameBytes(readBinaryFile(path), metadataOnly);
+    *this = *parseImgFrameBytes(readBinaryFile(path), metadataOnly);
 }

Also applies to: 106-108

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/opencv/ImgFrame.cpp` around lines 66 - 70, The function
parseImgFrameBytes creates an unnecessary copy of the input parameter serialized
into packetBytes before assigning it to the packet structure. Remove the
intermediate packetBytes copy and instead directly use serialized.data() and
serialized.size() when assigning packet.data and packet.length. Apply the same
optimization to any other instances in the file that perform similar redundant
buffer copies (referenced at lines 106-108) to eliminate the avoidable memory
overhead and CPU cost on large frames.

Comment thread src/opencv/ImgFrame.cpp Outdated
@JakubFara
JakubFara force-pushed the feature/imgFrame_load_save branch 2 times, most recently from 0e9d4ea to b148bc3 Compare July 3, 2026 13:08
@JakubFara
JakubFara marked this pull request as ready for review July 7, 2026 11:18

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@include/depthai/utility/ProtoSerializable.hpp`:
- Around line 20-22: Add Doxygen documentation for ProtoSerializable::save and
ProtoSerializable::load to match the existing serializeProto/serializeSchema
comments, and explicitly document the resolveDataPath behavior that appends a
.dai extension when the provided path has no extension. Mention the metadataOnly
parameter and make it clear that extensionless inputs may be resolved to
<path>.dai so callers understand the final on-disk filename.
- Line 21: The metadata-only path in ProtoSerializable::load leaves existing
payload state attached when reusing objects like ImgFrame, EncodedFrame,
PointCloudData, or RGBDData. Update the load(const std::filesystem::path&, bool
metadataOnly) flow so that when metadataOnly is true it first clears or replaces
the current payload members before applying the new metadata, ensuring stale
buffers/frames are not preserved across reloads.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9564a817-a4cf-4483-860d-2c14bbe23352

📥 Commits

Reviewing files that changed from the base of the PR and between 13766a9 and b148bc3.

📒 Files selected for processing (21)
  • bindings/python/src/pipeline/datatype/EncodedFrameBindings.cpp
  • bindings/python/src/pipeline/datatype/IMUDataBindings.cpp
  • bindings/python/src/pipeline/datatype/ImgFrameBindings.cpp
  • bindings/python/src/pipeline/datatype/PointCloudDataBindings.cpp
  • bindings/python/src/pipeline/datatype/RGBDDataBindings.cpp
  • bindings/python/tests/imgframe_test.py
  • include/depthai/pipeline/datatype/EncodedFrame.hpp
  • include/depthai/pipeline/datatype/IMUData.hpp
  • include/depthai/pipeline/datatype/ImgFrame.hpp
  • include/depthai/pipeline/datatype/PointCloudData.hpp
  • include/depthai/pipeline/datatype/RGBDData.hpp
  • include/depthai/utility/ProtoSerializable.hpp
  • src/opencv/ImgFrame.cpp
  • src/pipeline/datatype/EncodedFrame.cpp
  • src/pipeline/datatype/IMUData.cpp
  • src/pipeline/datatype/ImgFrame.cpp
  • src/pipeline/datatype/PointCloudData.cpp
  • src/pipeline/datatype/RGBDData.cpp
  • src/utility/ProtoSerializable.cpp
  • tests/CMakeLists.txt
  • tests/src/onhost_tests/pipeline/datatype/proto_file_io_test.cpp
📜 Review details
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-03-24T22:39:04.364Z
Learnt from: MaticTonin
Repo: luxonis/depthai-core PR: 1732
File: src/pipeline/Pipeline.cpp:705-705
Timestamp: 2026-03-24T22:39:04.364Z
Learning: Do not flag the `!= ""` part of the auto-calibration condition as redundant when it appears in `PipelineImpl::build()` (or closely related pipeline build logic). If the code uses `utility::getEnvAs<std::string>(..., default)` with a default such as `"ON_START"`, the explicit empty-string guard may still be intentional to treat an explicitly empty env var as “OFF/disabled” (or to avoid special-casing elsewhere). Only consider removing `!= ""` if the codebase has an explicit, enforceable guarantee that `DEPTHAI_AUTOCALIBRATION` can never be set to an empty string (e.g., via validated parsing/CI checks); otherwise, keep the guard.

Applied to files:

  • src/pipeline/datatype/RGBDData.cpp
  • src/pipeline/datatype/PointCloudData.cpp
  • src/pipeline/datatype/IMUData.cpp
  • src/pipeline/datatype/ImgFrame.cpp
  • src/pipeline/datatype/EncodedFrame.cpp
🪛 Cppcheck (2.21.0)
tests/src/onhost_tests/pipeline/datatype/proto_file_io_test.cpp

[error] 393-393: There is an unknown macro here somewhere. Configuration is required. If DEPTHAI_NLOHMANN_DEFINE_TYPE_INTRUSIVE is a macro then please configure it.

(unknownMacro)

src/utility/ProtoSerializable.cpp

[style] 60-60: The function 'serializeSchema' is never used.

(unusedFunction)


[style] 62-62: The function 'save' is never used.

(unusedFunction)


[style] 66-66: The function 'load' is never used.

(unusedFunction)

🔇 Additional comments (25)
bindings/python/tests/imgframe_test.py (2)

178-188: Same .size emptiness-check concern as previously flagged.

This was already raised in a prior review: use a container-agnostic len(...) == 0 check instead of .size for portability across getData() return types.


6-6: LGTM!

Also applies to: 48-79, 165-176, 190-214

include/depthai/utility/ProtoSerializable.hpp (1)

4-4: LGTM!

src/utility/ProtoSerializable.cpp (1)

3-75: LGTM!

src/pipeline/datatype/PointCloudData.cpp (1)

10-10: LGTM!

Also applies to: 247-260

src/pipeline/datatype/RGBDData.cpp (1)

66-69: 🗄️ Data Integrity & Integration

No issue: metadataOnly already cascades in RGBDData

RGBDData forwards metadataOnly into both nested frame serialization and deserialization, so the composite message respects the flag.

			> Likely an incorrect or invalid review comment.
src/pipeline/datatype/IMUData.cpp (1)

19-30: 🎯 Functional Correctness

No change needed for IMUData::serializeProto(bool) IMUData has no metadataOnly-strippable payload, so ignoring the flag here is fine.

			> Likely an incorrect or invalid review comment.
bindings/python/src/pipeline/datatype/RGBDDataBindings.cpp (1)

39-42: 🩺 Stability & Availability

No issue bindings/python/src/DatatypeBindings.hpp already pulls in bindings/python/src/pybind11_common.hpp, which includes pybind11/stl/filesystem.h for this binding.

			> Likely an incorrect or invalid review comment.
include/depthai/pipeline/datatype/RGBDData.hpp (1)

66-73: 🗄️ Data Integrity & Integration

Same schema-compatibility concern as ImgFrame.hpp.

The deserializeProtoMessage override is correct. The DEPTHAI_SERIALIZE change here duplicates the Buffer::tsSystem addition flagged in include/depthai/pipeline/datatype/ImgFrame.hpp (lines 772-780) — see that comment for the wire-compatibility verification request; it applies identically here.

include/depthai/pipeline/datatype/EncodedFrame.hpp (1)

220-243: 🗄️ Data Integrity & Integration

Same schema-compatibility concern as ImgFrame.hpp.

deserializeProtoMessage override is correct; the DEPTHAI_SERIALIZE change duplicates the Buffer::tsSystem addition flagged in include/depthai/pipeline/datatype/ImgFrame.hpp (lines 772-780). See that comment for the verification request regarding host/device wire compatibility.

bindings/python/src/pipeline/datatype/ImgFrameBindings.cpp (2)

329-343: 🗄️ Data Integrity & Integration

Same std::filesystem::path pybind11 caster concern as EncodedFrameBindings.cpp.

save/load bind ImgFrame::save/ImgFrame::load taking std::filesystem::path. As in EncodedFrameBindings.cpp, confirm <pybind11/stl/filesystem.h> (or equivalent) is included in this translation unit so Python str/pathlib.Path arguments convert correctly; otherwise these bindings will raise TypeError at call time despite compiling successfully.


232-241: LGTM!

Also applies to: 309-309

include/depthai/pipeline/datatype/ImgFrame.hpp (2)

34-35: LGTM!

Also applies to: 111-125


772-780: 🗄️ Data Integrity & Integration

Inspect the NOP_STRUCTURE expansion before merging. If it feeds the libnop/XLink serializer, adding Buffer::tsSystem changes the wire layout and can break older firmware; if it only affects the protobuf path, the compatibility concern does not apply.

src/pipeline/datatype/ImgFrame.cpp (1)

1-9: LGTM!

Also applies to: 68-86, 365-368

bindings/python/src/pipeline/datatype/EncodedFrameBindings.cpp (2)

79-79: LGTM!


123-126: 🚀 Performance & Scalability

Drop this note: the filesystem caster is already available here. pipeline/CommonBindings.hpp pulls in pybind11_common.hpp, which includes <pybind11/stl/filesystem.h>, so EncodedFrame::save/load already accept Python path-like objects.

			> Likely an incorrect or invalid review comment.
src/pipeline/datatype/EncodedFrame.cpp (1)

150-168: 🗄️ Data Integrity & Integration

setBufferMetadataFrom already copies sequenceNum, ts, tsDevice, and tsSystem, so this refactor preserves the metadata path in getImgFrameMeta().

			> Likely an incorrect or invalid review comment.
src/opencv/ImgFrame.cpp (1)

10-12: 🎯 Functional Correctness

Confirm this include is actually used / verify save/load relocation resolved the prior OpenCV-link concern.

No symbol from utility/ProtoFileIO.hpp appears used anywhere else in this file (the rest of the file, lines 18-457, is unmodified and contains only setFrame/getFrame/getCvFrame/setCvFrame). A previous review round flagged a critical issue that ImgFrame::save/load were declared unconditionally in the header but only defined in this OpenCV-gated file, causing link errors when OpenCV support is disabled — but neither save/load nor the previously-discussed parseImgFrameBytes helper appear in this file anymore. This suggests the implementation moved elsewhere (e.g. src/pipeline/datatype/ImgFrame.cpp), which would resolve the prior concern, but that file isn't part of this review batch, so it can't be confirmed here. Please confirm the include is needed here (or drop it) and that save/load are defined in an always-compiled translation unit consistent with the unconditional header declaration.

#!/bin/bash
set -euo pipefail

echo "== Usage of ProtoFileIO in this file =="
rg -n 'ProtoFileIO|parseImgFrameBytes' src/opencv/ImgFrame.cpp || echo "no usage found"

echo "== Where are ImgFrame::save/load defined? =="
rg -n 'ImgFrame::save|ImgFrame::load' -g '*.cpp'

echo "== Header declaration guard for save/load =="
rg -n 'DEPTHAI_HAVE_OPENCV_SUPPORT|DEPTHAI_ENABLE_PROTOBUF|void save|void load' include/depthai/pipeline/datatype/ImgFrame.hpp | sed -n '1,80p'
include/depthai/pipeline/datatype/IMUData.hpp (1)

37-73: LGTM!

Also applies to: 262-269

include/depthai/pipeline/datatype/PointCloudData.hpp (1)

47-51: LGTM!

Also applies to: 271-277, 307-308

bindings/python/src/pipeline/datatype/IMUDataBindings.cpp (1)

53-53: LGTM!

Also applies to: 156-162

bindings/python/src/pipeline/datatype/PointCloudDataBindings.cpp (1)

128-128: LGTM!

Also applies to: 186-189

tests/src/onhost_tests/pipeline/datatype/proto_file_io_test.cpp (1)

1-443: LGTM!

tests/CMakeLists.txt (1)

519-522: LGTM!

Comment thread include/depthai/utility/ProtoSerializable.hpp

#ifdef DEPTHAI_ENABLE_PROTOBUF
void save(const std::filesystem::path& path, bool metadataOnly = false) const;
void load(const std::filesystem::path& path, bool metadataOnly = false);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Locate the actual deserialization/message-loading helper referenced by deserializeProtoMessage overrides
fd -i 'ProtoFileIO' 
rg -n -A15 'loadProtoMessageFromBytes' --type=cpp

Repository: luxonis/depthai-core

Length of output: 158


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the relevant header and locate callers/overrides.
git ls-files 'include/depthai/utility/ProtoSerializable.hpp' 'src/**' 'include/**' | sed -n '1,200p'
echo
ast-grep outline include/depthai/utility/ProtoSerializable.hpp --view expanded || true
echo
rg -n --hidden --glob '!**/.git/**' 'deserializeProtoMessage|metadataOnly|load\(const std::filesystem::path& path, bool metadataOnly = false\)' include src

Repository: luxonis/depthai-core

Length of output: 21097


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,120p' src/utility/ProtoSerializable.cpp
echo
sed -n '360,420p' src/pipeline/datatype/ImgFrame.cpp
echo
sed -n '150,190p' src/pipeline/datatype/EncodedFrame.cpp
echo
sed -n '240,270p' src/pipeline/datatype/PointCloudData.cpp
echo
sed -n '1,90p' src/pipeline/datatype/RGBDData.cpp
echo
sed -n '1,60p' src/pipeline/datatype/IMUData.cpp

Repository: luxonis/depthai-core

Length of output: 8552


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1050,1365p' src/utility/ProtoSerialize.cpp

Repository: luxonis/depthai-core

Length of output: 13503


Clear payload state on metadata-only reloads

load(..., metadataOnly=true) updates metadata in place but skips resetting payload members. Reusing an existing ImgFrame, EncodedFrame, PointCloudData, or RGBDData can leave old buffers/frames attached to the newly loaded metadata. Clear or replace the payload state before applying a metadata-only load.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@include/depthai/utility/ProtoSerializable.hpp` at line 21, The metadata-only
path in ProtoSerializable::load leaves existing payload state attached when
reusing objects like ImgFrame, EncodedFrame, PointCloudData, or RGBDData. Update
the load(const std::filesystem::path&, bool metadataOnly) flow so that when
metadataOnly is true it first clears or replaces the current payload members
before applying the new metadata, ensuring stale buffers/frames are not
preserved across reloads.

ProtoSerializable::SchemaPair serializeSchema() const override;
#endif

#ifdef DEPTHAI_ENABLE_PROTOBUF

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is there a separate ifdef? Can this not be included in the above block?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed here: 59b6b6f


#ifdef DEPTHAI_ENABLE_PROTOBUF
protected:
void deserializeProtoMessage(const std::vector<std::uint8_t>& bytes, bool metadataOnly) override;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be with the rest of the methods before properties

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed here: c4afcb3


public:
#else
public:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no need for else, public can be outside the ifdef block

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed here: 8919b57

@asahtik asahtik left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this. I left some comments.

utility/ProtoFileIO.hpp is missing.

I think it could be useful if ImgFrames were stored in a form that could be viewed as an image. On the other hand saving all datatypes in the same way simplifies the feature. @aljazkonec1 thoughts on handling ImgFrames separately to get something viewable? I think PNGs support extra metadata.

ProtoSerializable::SchemaPair serializeSchema() const override;
#endif

#ifdef DEPTHAI_ENABLE_PROTOBUF

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be merged with above ifdef block

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed here: 59b6b6f

ProtoSerializable::SchemaPair serializeSchema() const override;
#endif

#ifdef DEPTHAI_ENABLE_PROTOBUF

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be merged with above ifdef block

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed here: 59b6b6f

ProtoSerializable::SchemaPair serializeSchema() const override;
#endif

#ifdef DEPTHAI_ENABLE_PROTOBUF

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be merged with above ifdef block

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed here: 59b6b6f

Comment thread src/opencv/ImgFrame.cpp Outdated
#include <opencv2/imgproc.hpp>

#ifdef DEPTHAI_ENABLE_PROTOBUF
#include "utility/ProtoFileIO.hpp"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This include seems unnecessary

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed here: d70ee84


#ifdef DEPTHAI_ENABLE_PROTOBUF
void EncodedFrame::deserializeProtoMessage(const std::vector<std::uint8_t>& bytes, bool metadataOnly) {
utility::loadProtoMessageFromBytes(*this, bytes, metadataOnly);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could deserializeProtoMessage be skipped and loadProtoMessageFromBytes be called directly where needed? I'm not sure since the implementation is missing.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deserializeProtoMessage is the virtual hook that ProtoSerializable::load() uses for type-specific deserialization, so the EncodedFrame override is part of the current design, not redundant. Removing it would require redesigning the base ProtoSerializable::load() flow, not a minimal cleanup.

return path;
}
auto resolved = path;
resolved += ".dai";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the extension necessary? I wouldn't change the requested path, if anything I'd prefer to throw here.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea was that load("image.dai") and load("image") would behave the same. This pattern seems quite common to me, but I'm not insisting on it.

@JakubFara
JakubFara force-pushed the feature/imgFrame_load_save branch from b148bc3 to f035e5e Compare July 9, 2026 11:12

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
include/depthai/pipeline/datatype/EncodedFrame.hpp (1)

204-226: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Merge the two adjacent DEPTHAI_ENABLE_PROTOBUF blocks.

Same redundant split as in PointCloudData.hpp: this can be folded into the existing #ifdef DEPTHAI_ENABLE_PROTOBUF block above with a protected:/public: toggle inside, instead of opening a second identical #ifdef.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@include/depthai/pipeline/datatype/EncodedFrame.hpp` around lines 204 - 226,
Merge the redundant DEPTHAI_ENABLE_PROTOBUF guards in EncodedFrame so the
existing protobuf block around serializeProto and serializeSchema also contains
deserializeProtoMessage, using protected:/public: visibility switches inside the
same conditional instead of opening a second identical `#ifdef`. Keep the class
layout consistent with PointCloudData and preserve the access specifiers for
serializeProto, serializeSchema, and deserializeProtoMessage.
include/depthai/pipeline/datatype/PointCloudData.hpp (1)

255-277: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Merge the two adjacent DEPTHAI_ENABLE_PROTOBUF blocks.

Lines 255-269 and 271-277 are both guarded by the same #ifdef DEPTHAI_ENABLE_PROTOBUF; splitting them into two separate blocks just to toggle access specifiers is redundant.

♻️ Proposed merge
 `#ifdef` DEPTHAI_ENABLE_PROTOBUF
     /**
      * Serialize message to proto buffer
      *
      * `@returns` serialized message
      */
     std::vector<std::uint8_t> serializeProto(bool metadataOnly = false) const override;

     /**
      * Serialize schema to proto buffer
      *
      * `@returns` serialized schema
      */
     ProtoSerializable::SchemaPair serializeSchema() const override;
-#endif

-#ifdef DEPTHAI_ENABLE_PROTOBUF
    protected:
     void deserializeProtoMessage(const std::vector<std::uint8_t>& bytes, bool metadataOnly) override;

    public:
 `#endif`
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@include/depthai/pipeline/datatype/PointCloudData.hpp` around lines 255 - 277,
Merge the two adjacent DEPTHAI_ENABLE_PROTOBUF guard blocks in PointCloudData so
the protobuf methods and deserializeProtoMessage are wrapped by a single
conditional section; keep the access specifier changes inside that one block
instead of reopening the same `#ifdef` twice. Update the PointCloudData class
declaration to group serializeProto, serializeSchema, and
deserializeProtoMessage under one DEPTHAI_ENABLE_PROTOBUF block while preserving
the protected/public split.
src/pipeline/datatype/IMUData.cpp (1)

28-30: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

IMUData::serializeProto still ignores metadataOnly
src/pipeline/datatype/IMUData.cpp and src/utility/ProtoSerialize.cpp both drop the flag, so save(path, true) still writes packets. Forward metadataOnly through the IMUData serializer, or the save/load contract stays inconsistent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pipeline/datatype/IMUData.cpp` around lines 28 - 30,
IMUData::serializeProto is still discarding the metadataOnly flag, so save(path,
true) cannot produce metadata-only output. Update IMUData::serializeProto to
accept and forward the metadataOnly argument into utility::getProtoMessage, and
make sure the matching utility::serializeProto path in ProtoSerialize.cpp also
preserves that flag instead of always serializing packets.
♻️ Duplicate comments (2)
include/depthai/utility/ProtoSerializable.hpp (1)

32-32: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Metadata-only load() doesn't clear stale payload state.

load(..., metadataOnly=true) only forwards to deserializeProtoMessage, which (per PointCloudData/RGBDData/ImgFrame overrides) calls utility::loadProtoMessageFromBytes(*this, bytes, metadataOnly). If a caller reuses an existing object (e.g. re-loading metadata into an ImgFrame that already has data/transformation set from a previous full load), old payload/buffers may remain attached alongside the newly loaded metadata since nothing here resets payload fields first. This was already raised in a previous review round and appears unresolved.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@include/depthai/utility/ProtoSerializable.hpp` at line 32, The metadata-only
load path in ProtoSerializable::load leaves stale payload state on reused
objects, so clear any existing payload/buffer fields before calling
deserializeProtoMessage when metadataOnly is true. Update the load path and any
overriding deserializeProtoMessage usage in types like ImgFrame, PointCloudData,
and RGBDData so re-loading metadata cannot retain old data alongside the newly
deserialized metadata.
bindings/python/tests/imgframe_test.py (1)

187-187: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use a container-agnostic emptiness check.

.size may not exist on every possible return type of getData(); len(...) is safer and was already suggested previously.

✅ Proposed fix
-    assert recovered.getData().size == 0
+    assert len(recovered.getData()) == 0
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bindings/python/tests/imgframe_test.py` at line 187, The emptiness assertion
in the imgframe test relies on getData().size, which is not container-agnostic
and may fail for other return types. Update the assertion in the imgframe test
to use a length-based emptiness check on recovered.getData() instead, following
the safer pattern already suggested, so the test works regardless of the конкрет
return container type.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@include/depthai/pipeline/datatype/ImgFrame.hpp`:
- Around line 772-779: Simplify the ImgFrame visibility/protobuf preprocessor
block by removing the redundant public section from the conditional and leaving
the access specifier outside the `#ifdef` DEPTHAI_ENABLE_PROTOBUF guard. In
ImgFrame.hpp, adjust the deserializeProtoMessage declaration block so the
protected/public layout is preserved without a conditional `#else` public: `#endif`
wrapper, keeping the class interface the same while reducing unnecessary
preprocessor branching.

In `@include/depthai/pipeline/datatype/IMUData.hpp`:
- Around line 262-268: The IMUData protobuf declarations are split across two
separate DEPTHAI_ENABLE_PROTOBUF blocks, which should be merged for consistency.
Update IMUData to combine this protected/public deserializeProtoMessage section
with the earlier DEPTHAI_ENABLE_PROTOBUF block already wrapping the other
protobuf methods, matching the pattern used in RGBDData and ImgFrame so the
class has a single contiguous conditional section.

In `@include/depthai/pipeline/datatype/RGBDData.hpp`:
- Around line 66-72: Merge the new DEPTHAI_ENABLE_PROTOBUF guard in RGBDData so
deserializeProtoMessage stays inside the existing protobuf ifdef block already
wrapping the protobuf-related declarations above, rather than opening a second
adjacent `#ifdef`. Keep the access specifier changes (protected/public) within
that same block and remove the redundant guard so the class layout remains a
single contiguous conditional section.

In `@src/opencv/ImgFrame.cpp`:
- Around line 10-17: Remove the unused protobuf include from the ImgFrame.cpp
translation unit, since this file does not use any protobuf symbols. Update the
include block in src/opencv/ImgFrame.cpp to drop utility/ProtoFileIO.hpp, and
keep the protobuf-related serialization hooks confined to ImgFrame.cpp in
src/pipeline/datatype where deserializeProtoMessage and serializeProto are
actually used.

In `@src/utility/ProtoSerializable.cpp`:
- Around line 15-22: resolveDataPath is still silently rewriting extensionless
inputs to add a .dai suffix, which affects both save and load behavior. Update
ProtoSerializable::resolveDataPath so it does not mutate the requested path
implicitly; instead, preserve the original path when no extension is present or
make the function fail explicitly with an error/exception if that is the
intended contract. Make sure the change is applied consistently anywhere
resolveDataPath is used so callers see the expected path handling.

---

Outside diff comments:
In `@include/depthai/pipeline/datatype/EncodedFrame.hpp`:
- Around line 204-226: Merge the redundant DEPTHAI_ENABLE_PROTOBUF guards in
EncodedFrame so the existing protobuf block around serializeProto and
serializeSchema also contains deserializeProtoMessage, using protected:/public:
visibility switches inside the same conditional instead of opening a second
identical `#ifdef`. Keep the class layout consistent with PointCloudData and
preserve the access specifiers for serializeProto, serializeSchema, and
deserializeProtoMessage.

In `@include/depthai/pipeline/datatype/PointCloudData.hpp`:
- Around line 255-277: Merge the two adjacent DEPTHAI_ENABLE_PROTOBUF guard
blocks in PointCloudData so the protobuf methods and deserializeProtoMessage are
wrapped by a single conditional section; keep the access specifier changes
inside that one block instead of reopening the same `#ifdef` twice. Update the
PointCloudData class declaration to group serializeProto, serializeSchema, and
deserializeProtoMessage under one DEPTHAI_ENABLE_PROTOBUF block while preserving
the protected/public split.

In `@src/pipeline/datatype/IMUData.cpp`:
- Around line 28-30: IMUData::serializeProto is still discarding the
metadataOnly flag, so save(path, true) cannot produce metadata-only output.
Update IMUData::serializeProto to accept and forward the metadataOnly argument
into utility::getProtoMessage, and make sure the matching
utility::serializeProto path in ProtoSerialize.cpp also preserves that flag
instead of always serializing packets.

---

Duplicate comments:
In `@bindings/python/tests/imgframe_test.py`:
- Line 187: The emptiness assertion in the imgframe test relies on
getData().size, which is not container-agnostic and may fail for other return
types. Update the assertion in the imgframe test to use a length-based emptiness
check on recovered.getData() instead, following the safer pattern already
suggested, so the test works regardless of the конкрет return container type.

In `@include/depthai/utility/ProtoSerializable.hpp`:
- Line 32: The metadata-only load path in ProtoSerializable::load leaves stale
payload state on reused objects, so clear any existing payload/buffer fields
before calling deserializeProtoMessage when metadataOnly is true. Update the
load path and any overriding deserializeProtoMessage usage in types like
ImgFrame, PointCloudData, and RGBDData so re-loading metadata cannot retain old
data alongside the newly deserialized metadata.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: ff0c55dc-9494-4c13-85f9-7bac619076bf

📥 Commits

Reviewing files that changed from the base of the PR and between b148bc3 and e9e3b17.

📒 Files selected for processing (21)
  • bindings/python/src/pipeline/datatype/EncodedFrameBindings.cpp
  • bindings/python/src/pipeline/datatype/IMUDataBindings.cpp
  • bindings/python/src/pipeline/datatype/ImgFrameBindings.cpp
  • bindings/python/src/pipeline/datatype/PointCloudDataBindings.cpp
  • bindings/python/src/pipeline/datatype/RGBDDataBindings.cpp
  • bindings/python/tests/imgframe_test.py
  • include/depthai/pipeline/datatype/EncodedFrame.hpp
  • include/depthai/pipeline/datatype/IMUData.hpp
  • include/depthai/pipeline/datatype/ImgFrame.hpp
  • include/depthai/pipeline/datatype/PointCloudData.hpp
  • include/depthai/pipeline/datatype/RGBDData.hpp
  • include/depthai/utility/ProtoSerializable.hpp
  • src/opencv/ImgFrame.cpp
  • src/pipeline/datatype/EncodedFrame.cpp
  • src/pipeline/datatype/IMUData.cpp
  • src/pipeline/datatype/ImgFrame.cpp
  • src/pipeline/datatype/PointCloudData.cpp
  • src/pipeline/datatype/RGBDData.cpp
  • src/utility/ProtoSerializable.cpp
  • tests/CMakeLists.txt
  • tests/src/onhost_tests/pipeline/datatype/proto_file_io_test.cpp
📜 Review details
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-03-24T22:39:04.364Z
Learnt from: MaticTonin
Repo: luxonis/depthai-core PR: 1732
File: src/pipeline/Pipeline.cpp:705-705
Timestamp: 2026-03-24T22:39:04.364Z
Learning: Do not flag the `!= ""` part of the auto-calibration condition as redundant when it appears in `PipelineImpl::build()` (or closely related pipeline build logic). If the code uses `utility::getEnvAs<std::string>(..., default)` with a default such as `"ON_START"`, the explicit empty-string guard may still be intentional to treat an explicitly empty env var as “OFF/disabled” (or to avoid special-casing elsewhere). Only consider removing `!= ""` if the codebase has an explicit, enforceable guarantee that `DEPTHAI_AUTOCALIBRATION` can never be set to an empty string (e.g., via validated parsing/CI checks); otherwise, keep the guard.

Applied to files:

  • src/pipeline/datatype/IMUData.cpp
  • src/pipeline/datatype/PointCloudData.cpp
  • src/pipeline/datatype/RGBDData.cpp
  • src/pipeline/datatype/ImgFrame.cpp
  • src/pipeline/datatype/EncodedFrame.cpp
🪛 Cppcheck (2.21.0)
src/utility/ProtoSerializable.cpp

[style] 71-71: The function 'serializeSchema' is never used.

(unusedFunction)


[style] 62-62: The function 'save' is never used.

(unusedFunction)


[style] 66-66: The function 'load' is never used.

(unusedFunction)

tests/src/onhost_tests/pipeline/datatype/proto_file_io_test.cpp

[error] 393-393: There is an unknown macro here somewhere. Configuration is required. If DEPTHAI_NLOHMANN_DEFINE_TYPE_INTRUSIVE is a macro then please configure it.

(unknownMacro)

🔇 Additional comments (16)
src/utility/ProtoSerializable.cpp (2)

62-72: Cppcheck "unused function" hints are false positives.

These functions are invoked from derived-class overrides and Python bindings in other translation units (e.g. ImgFrame.cpp, ImgFrameBindings.cpp), only compiled under DEPTHAI_ENABLE_PROTOBUF, which cppcheck's single-TU analysis misses.


24-45: LGTM!

Also applies to: 47-58

include/depthai/utility/ProtoSerializable.hpp (1)

20-33: Doxygen docs added, resolving prior comment.

The .dai extension behavior and metadataOnly semantics are now documented. This addresses the earlier documentation gap.

src/pipeline/datatype/PointCloudData.cpp (1)

10-10: LGTM!

Also applies to: 248-251

src/pipeline/datatype/RGBDData.cpp (1)

5-5: LGTM!

Also applies to: 66-69

bindings/python/src/pipeline/datatype/EncodedFrameBindings.cpp (1)

123-126: LGTM!

bindings/python/src/pipeline/datatype/IMUDataBindings.cpp (1)

159-162: LGTM!

bindings/python/src/pipeline/datatype/PointCloudDataBindings.cpp (1)

186-189: LGTM!

bindings/python/src/pipeline/datatype/RGBDDataBindings.cpp (1)

39-42: 🎯 Functional Correctness

Same std::filesystem::path pybind11 caster dependency as ImgFrameBindings.cpp.

tests/src/onhost_tests/pipeline/datatype/proto_file_io_test.cpp (1)

1-443: LGTM!

tests/CMakeLists.txt (1)

519-522: LGTM!

bindings/python/src/pipeline/datatype/ImgFrameBindings.cpp (1)

329-343: 🎯 Functional Correctness

Filesystem caster is already available here. bindings/python/src/pipeline/CommonBindings.hpp includes pybind11_common.hpp, which already pulls in pybind11/stl/filesystem.h, so save/load can accept Python path-like arguments as-is.

			> Likely an incorrect or invalid review comment.
src/pipeline/datatype/ImgFrame.cpp (1)

9-9: LGTM!

Also applies to: 365-368

src/pipeline/datatype/EncodedFrame.cpp (1)

4-4: LGTM!

Also applies to: 165-168

src/pipeline/datatype/IMUData.cpp (1)

6-6: LGTM on the new include and deserializeProtoMessage override — consistent with the other datatypes.

Also applies to: 19-22

bindings/python/tests/imgframe_test.py (1)

6-6: LGTM!

Also applies to: 48-79, 165-176, 190-214

Comment thread include/depthai/pipeline/datatype/ImgFrame.hpp Outdated
Comment thread include/depthai/pipeline/datatype/IMUData.hpp Outdated
Comment thread include/depthai/pipeline/datatype/RGBDData.hpp Outdated
Comment thread src/opencv/ImgFrame.cpp Outdated
Comment on lines +15 to +22
std::filesystem::path resolveDataPath(const std::filesystem::path& path) {
if(path.has_extension()) {
return path;
}
auto resolved = path;
resolved += ".dai";
return resolved;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Implicit path mutation on extensionless input — previously questioned, still unresolved.

resolveDataPath silently rewrites an extensionless path to <path>.dai for both save and load. A prior reviewer (asahtik) questioned this exact design, suggesting the requested path should not be changed or that it should throw instead. The current implementation still performs the silent rewrite.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utility/ProtoSerializable.cpp` around lines 15 - 22, resolveDataPath is
still silently rewriting extensionless inputs to add a .dai suffix, which
affects both save and load behavior. Update ProtoSerializable::resolveDataPath
so it does not mutate the requested path implicitly; instead, preserve the
original path when no extension is present or make the function fail explicitly
with an error/exception if that is the intended contract. Make sure the change
is applied consistently anywhere resolveDataPath is used so callers see the
expected path handling.

@JakubFara
JakubFara force-pushed the feature/imgFrame_load_save branch 2 times, most recently from c4afcb3 to 9a84a06 Compare July 9, 2026 11:44
@JakubFara
JakubFara force-pushed the feature/imgFrame_load_save branch from c474ca2 to 9760b47 Compare July 9, 2026 11:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants