-
Notifications
You must be signed in to change notification settings - Fork 5
WIP: RSDK-11082: Remove instances of C-style pointer manipulation #30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,6 +27,8 @@ | |
| #include <stdexcept> | ||
| #include <vector> | ||
|
|
||
| #include <boost/core/span.hpp> | ||
|
|
||
| #include <viam/sdk/common/proto_value.hpp> | ||
| #include <viam/sdk/components/camera.hpp> | ||
| #include <viam/sdk/components/component.hpp> | ||
|
|
@@ -76,17 +78,23 @@ struct ViamOBDevice { | |
| std::shared_ptr<ob::Config> config; | ||
| }; | ||
|
|
||
| struct raw_camera_image { | ||
| using deleter_type = void (*)(unsigned char*); | ||
| using uniq = std::unique_ptr<unsigned char[], deleter_type>; | ||
| class raw_camera_image { | ||
| public: | ||
| explicit raw_camera_image(std::size_t sz) : bytes(new unsigned char[sz]), size(sz) {} | ||
|
|
||
| static constexpr deleter_type free_deleter = [](unsigned char* ptr) { free(ptr); }; | ||
| boost::span<unsigned char const> span() const noexcept { | ||
| return boost::span{bytes.get(), size}; | ||
| } | ||
|
|
||
| static constexpr deleter_type array_delete_deleter = [](unsigned char* ptr) { delete[] ptr; }; | ||
| boost::span<unsigned char> span() noexcept { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not critical at all, but could we use std::uint8_t instead of unsigned char to express bytes?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that works!
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @SebastianMunozP I was looking into this and it seems like we may want to use either I believe this project is C++17 so we could use
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. huh, didn't know about std::byte :) , I agree, let's go with that then.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. just added some changes using
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see, in that case let's just go back to |
||
| return boost::span{bytes.get(), size}; | ||
| } | ||
|
|
||
| uniq bytes; | ||
| size_t size; | ||
| private: | ||
| std::unique_ptr<unsigned char[]> bytes; | ||
| std::size_t size; | ||
| }; | ||
|
|
||
| // STRUCTS END | ||
|
|
||
| // GLOBALS BEGIN | ||
|
|
@@ -141,24 +149,24 @@ uint64_t timeSinceFrameUs(uint64_t nowUs, uint64_t imageTimeUs) { | |
| } | ||
|
|
||
| std::vector<unsigned char> RGBPointsToPCD(std::shared_ptr<ob::Frame> frame, float scale) { | ||
| int numPoints = frame->dataSize() / sizeof(OBColorPoint); | ||
| assert(frame->is<ob::PointsFrame>()); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this pattern comes up more often we could write a
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what kind of error message is produced when an assert fails?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It includes the line like:
So it includes the line number and string of the failing assert.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like using asserts, but in this case I would prefer to detect the case of these two asserts and log it and early return. I think it would be better to handle this by looking at logs than forcing the module to terminate. Cc. @nicksanford in case you want to weigh in.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
If the answers to all those questions are 'yes' then this is fine. If the answer to any of them is no then I'll need a justification for why this asset is here.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It's worth noting that as the code is at the moment, these asserts are being removed from the binary since this is a release build. I enabled them by creating a debug build and making sure that I could hit asserts.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Having assets fire in release builds sounds good to me. I'd also be ok with us writing our own assert function. Whichever you feel is best.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So in the current code as is the assert wouldn't get hit unless someone called Per another comment #30 (comment) the use of void f(std::shared_ptr<ob::Frame> frame){
FrameView<OBColorPoint> frameView(frame);
}and we would expect this to be an error if I think A possible option, since we already use Boost, is Boost.Assert. This has the advantage of letting us
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's a good idea, let's do that, let's change the asserts for BOOST_ASSERT |
||
| assert(frame->getFormat() == OBFormat::OB_FORMAT_RGB_POINT); | ||
|
|
||
| auto pointSpan = boost::span{reinterpret_cast<OBColorPoint*>(frame->data()), frame->dataSize() / sizeof(OBColorPoint)}; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Love this :)
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how do we ensure that the span's underlying bytes do not get freed while using it?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @hexbabe that's the responsibility of the calling code; span is a non-owning reference or "view" type, meaning it provides a different view or interface upon some underlying data without taking responsibility for the lifetime of the data. Similar to see https://stackoverflow.com/a/45723820 for further discussion |
||
|
|
||
| OBColorPoint* points = (OBColorPoint*)frame->data(); | ||
| std::vector<PointXYZRGB> pcdPoints; | ||
|
|
||
| for (int i = 0; i < numPoints; i++) { | ||
| OBColorPoint& p = points[i]; | ||
| unsigned int r = (unsigned int)p.r; | ||
| unsigned int g = (unsigned int)p.g; | ||
| unsigned int b = (unsigned int)p.b; | ||
| std::transform(pointSpan.begin(), pointSpan.end(), std::back_inserter(pcdPoints), [scale](const OBColorPoint& p) { | ||
| auto r = static_cast<unsigned int>(p.r); | ||
| auto g = static_cast<unsigned int>(p.g); | ||
| auto b = static_cast<unsigned int>(p.b); | ||
|
|
||
| unsigned int rgb = (r << 16) | (g << 8) | b; | ||
| PointXYZRGB pt; | ||
| pt.x = (p.x * scale); | ||
| pt.y = (p.y * scale); | ||
| pt.z = (p.z * scale); | ||
| pt.rgb = rgb; | ||
| pcdPoints.push_back(pt); | ||
| } | ||
| return PointXYZRGB{p.x * scale, // | ||
| p.y * scale, // | ||
| p.z * scale, // | ||
| rgb}; | ||
| }); | ||
|
|
||
| std::stringstream header; | ||
| header << "VERSION .7\n" | ||
|
|
@@ -174,32 +182,15 @@ std::vector<unsigned char> RGBPointsToPCD(std::shared_ptr<ob::Frame> frame, floa | |
| std::string headerStr = header.str(); | ||
| std::vector<unsigned char> pcdBytes; | ||
| pcdBytes.insert(pcdBytes.end(), headerStr.begin(), headerStr.end()); | ||
| for (auto& p : pcdPoints) { | ||
| unsigned char* x = (unsigned char*)&p.x; | ||
| unsigned char* y = (unsigned char*)&p.y; | ||
| unsigned char* z = (unsigned char*)&p.z; | ||
| unsigned char* rgb = (unsigned char*)&p.rgb; | ||
|
|
||
| pcdBytes.push_back(x[0]); | ||
| pcdBytes.push_back(x[1]); | ||
| pcdBytes.push_back(x[2]); | ||
| pcdBytes.push_back(x[3]); | ||
| // Assert that PointXYZRGB is a POD type, and that it has no padding, thus can be copied as bytes. | ||
| // Since vector is contiguous, we can just copy the whole thing | ||
| static_assert(std::is_pod_v<PointXYZRGB>); | ||
| static_assert(sizeof(PointXYZRGB) == (3 * sizeof(float)) + sizeof(unsigned int), "PointXYZRGB has unexpected padding"); | ||
|
|
||
| pcdBytes.push_back(y[0]); | ||
| pcdBytes.push_back(y[1]); | ||
| pcdBytes.push_back(y[2]); | ||
| pcdBytes.push_back(y[3]); | ||
|
|
||
| pcdBytes.push_back(z[0]); | ||
| pcdBytes.push_back(z[1]); | ||
| pcdBytes.push_back(z[2]); | ||
| pcdBytes.push_back(z[3]); | ||
|
|
||
| pcdBytes.push_back(rgb[0]); | ||
| pcdBytes.push_back(rgb[1]); | ||
| pcdBytes.push_back(rgb[2]); | ||
| pcdBytes.push_back(rgb[3]); | ||
| } | ||
| auto byteSpan = boost::as_bytes(boost::span{pcdPoints}); | ||
| pcdBytes.insert( | ||
| pcdBytes.end(), reinterpret_cast<unsigned char const*>(byteSpan.begin()), reinterpret_cast<unsigned char const*>(byteSpan.end())); | ||
|
|
||
| return pcdBytes; | ||
| } | ||
|
|
@@ -421,18 +412,18 @@ void listDevices(const ob::Context& ctx) { | |
|
|
||
| raw_camera_image encodeDepthRAW(const unsigned char* data, const uint64_t width, const uint64_t height, const bool littleEndian) { | ||
| viam::sdk::Camera::depth_map m = xt::xarray<uint16_t>::from_shape({height, width}); | ||
| std::copy(reinterpret_cast<const uint16_t*>(data), reinterpret_cast<const uint16_t*>(data) + height * width, m.begin()); | ||
|
|
||
| for (size_t i = 0; i < m.size(); i++) { | ||
| m[i] = m[i] * mmToMeterMultiple; | ||
| } | ||
| auto depthPixels = boost::span{reinterpret_cast<uint16_t const*>(data), height * width}; | ||
|
|
||
| std::transform(depthPixels.begin(), depthPixels.end(), m.begin(), [](uint16_t mi) { return mi * mmToMeterMultiple; }); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is sick
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. may i recommend this for inspo 🙂 |
||
|
|
||
| std::vector<unsigned char> encodedData = viam::sdk::Camera::encode_depth_map(m); | ||
|
|
||
| unsigned char* rawBuf = new unsigned char[encodedData.size()]; | ||
| std::memcpy(rawBuf, encodedData.data(), encodedData.size()); | ||
| raw_camera_image rawBuf(encodedData.size()); | ||
|
|
||
| std::copy(encodedData.begin(), encodedData.end(), rawBuf.span().begin()); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. note that most standard library implementations of |
||
|
|
||
| return raw_camera_image{raw_camera_image::uniq(rawBuf, raw_camera_image::array_delete_deleter), encodedData.size()}; | ||
| return rawBuf; | ||
| } | ||
|
|
||
| // HELPERS END | ||
|
|
@@ -682,7 +673,7 @@ vsdk::Camera::image_collection Orbbec::get_images() { | |
| vsdk::Camera::raw_image depth_image; | ||
| depth_image.source_name = kDepthSourceName; | ||
| depth_image.mime_type = kDepthMimeTypeViamDep; | ||
| depth_image.bytes.assign(rci.bytes.get(), rci.bytes.get() + rci.size); | ||
| depth_image.bytes.assign(rci.span().begin(), rci.span().end()); | ||
|
|
||
| vsdk::Camera::image_collection response; | ||
| response.images.emplace_back(std::move(color_image)); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note that
freememory that wasnew'dstd::default_deletetemplate parameter forunique_ptr<T[]>already doesdelete[]https://en.cppreference.com/w/cpp/memory/default_delete.html