Repository navigation
sensing: add a mock backend so the plugin runs without a Jetson - #1340
Open
gareth-morgan-nv wants to merge 10 commits into
Open
gareth-morgan-nv wants to merge 10 commits into
gareth-morgan-nv wants to merge 10 commits into
Conversation
Add SENSING_BACKEND (AUTO, JETSON, MOCK). AUTO keeps JETSON on aarch64, so a Jetson missing the SDK still gets the setup instructions, and falls back to MOCK elsewhere. The mock replaces only SiplCamera and JetsonEncoder. Everything above them is the code that runs on the rig: SensingCamera, the sinks, the YUV-to-RGBA and RGBA-to-NV12 kernels, and the CUDA IPC publisher. - SiplCamera: answers query() from the vendor JSON, including the renumbering of sensors to pipeline indices and the per-deserializer link masks; paints a synthetic NV12 surface and runs the real conversion on it; keeps the three-slot mailbox with its reader lease and a capture TSC shared by every sensor. Fault injection and scaling through SENSING_MOCK_* variables. - JetsonEncoder: runs the real RGBA-to-NV12 kernel and the device-to-host copy, then emits Annex-B shaped units (not decodable video) with the real encoder's contract: six input buffers that make submit() refuse frames when behind, a warm-up delay, microsecond-resolution stamps, and a concatenated tail at end of stream. Tests (sensing_mock_tests) cover the camera, the encoder, SensingCamera end to end, and a CUDA IPC consumer that maps the shared allocation and reads the published frames. The existing test_sipl_query now also runs against the mock. One test is marked [!shouldfail]: the capture TSC of an encoded stream is never recovered, because the encoder returns stamps at microsecond resolution and SensingCamera matches them for nanosecond equality. Nothing here has been run against SIPL or the V4L2 encoder. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
The V4L2 encoder carries the capture stamp on a timeval, so a unit comes back with the stamp truncated to microseconds. SensingCamera remembers the stamp it submitted in nanoseconds and looked the unit up by equality, so the match essentially never succeeded: every metadata record of an encoded stream had capture_tsc_ns == 0, and each failed lookup also discarded the pending stamps ahead of it. Compare at microsecond resolution. The mock encoder reproduces the truncation, and the test that recovers the capture TSC of an encoded stream no longer needs [!shouldfail]. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
- Free a mock sensor's device memory from its own destructor, so a constructor that throws part-way through allocating does not leak. - Abandon queued frames when the mock encoder is torn down instead of encoding them, which made teardown take as long as the queue was deep. - Treat a link index of 8 or more as disabled; a mask holds eight hex digits. - Fail configure with an install hint when the EGL headers cudaEGL.h needs are missing, and name them in the README. - Remove a compile definition nothing used, and a stale comment in tools/. - Remove the tests' temp files on every exit path. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
Every mock sensor shows an animated GIF, by default the bundled robot. Set SENSING_MOCK_GIF for every sensor, or SENSING_MOCK_GIF_<module name> for one (for example the bundled waving hand on a wrist camera). A GIF that cannot be loaded, the bundled one included, is an error; there is no fallback. The GIF is decoded once, held on the GPU, and played on the capture clock, with each frame's delay clamped to at least 20 ms and the animation looping. Transparent pixels are composited onto a plain gray. Frames are scaled to cover the sensor's configured size and centre-cropped, so the aspect ratio is never distorted whatever the GIF's own size: bilinear when enlarging and area-averaged when reducing. The result is full-range BT.709 NV12, the inverse of the matrix the real conversion applies, so it goes through that conversion unchanged. Sequence numbers and stamps advance on every capture even while the GIF shows one image. The bundled GIFs are Animated Noto Emoji (robot U+1F916, waving hand U+1F44B), copyright Google, licensed CC BY 4.0, included unmodified with their licence, source and attribution in mock_assets/. LICENSES/CC-BY-4.0.txt is the canonical text, and the root README notes the exception. Decoding uses stb_image, a public-domain header fetched at a pinned commit and checked against its hash at configure time. The mock backend no longer paints a test pattern. Tests use small generated GIFs of known colours and check sequence, stamps, whole (untorn) frames, the reader lease and the scaling. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
Contributor
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the
|
Add a mock rig config (S56C stereo head camera, two SHF3L wrist cameras) with each camera's real size and aspect. Pictures are chosen by module name, not pipeline index: the head eyes show the robot offset by a fixed stereo disparity, the right wrist is the left wrist's picture flipped. A module with no known picture must be given one by the environment. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
Pictures are fixed by module name, so the per-module and global GIF overrides and the flip knob only added precedence rules and tests. Tests that need a known picture use an internal hook instead. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
The rig tests cover the fixed pictures, the wrist mirror and masking. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
Feed the NV12 buffer to libavcodec's h264_nvenc, set up as the Jetson V4L2 encoder is: High profile, Level 5.2, VBR with a peak, an IDR every GOP with SPS/PPS in front of it, no B-frames, microsecond stamps. The tests decode the output. Drops the fake payload generator and its latency and depth knobs. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
Cover the whole constructor with the cleanup guard, check the encoder option calls, and make the test decoder pad its input and fail on any decoder error or damaged picture. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
2 of 4 tasks
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a
MOCKbackend to the SENSING camera plugin so it builds and runs on any machine with an NVIDIA GPU, not only on a Jetson. The mock replaces onlySiplCameraandJetsonEncoder; everything above them (SensingCamera, the sinks, the YUV-to-RGBA and RGBA-to-NV12 kernels, and the CUDA IPC publisher) is the code that runs on the rig. It also fixes the capture timestamp of encoded streams, which was always zero.Stacked on the SENSING camera plugin PR (#998): the base branch is its head branch, so this diff shows only the changes below.
What changed
SENSING_BACKEND(AUTO,JETSON,MOCK).AUTOpicksJETSONon aarch64 andMOCKelsewhere, so a Jetson without the SDK still gets the existing setup instructions instead of a silent mock. The Jetson SDK checks are unchanged apart from sitting inside theJETSONbranch.--list-sensorsand the link masks from the vendor JSON, including the renumbering of sensors to pipeline indices. Builds a synthetic NV12 surface from an animated GIF and runs the real conversion on it. Keeps the three-slot mailbox with its reader lease and a capture TSC shared by every sensor.SENSING_MOCK_FPS,SENSING_MOCK_FAIL_AFTERandSENSING_MOCK_SCALE_DIVcontrol frame rate, an injected link failure and test-size frames.S56C_HEADthe robot (its two sensors are the left and right eye, offset against each other by an illustrative fixed disparity),SHF3L_LEFTthe waving hand,SHF3L_RIGHTthe hand flipped left to right. It plays on the capture clock, scaled to cover the sensor's configured size and centre-cropped, never stretched. A module with no picture, or a GIF that cannot be loaded, is an error; there is no fallback.mock_assets/mock_rig.jsonis a mock-only three-camera rig (two 2560x1984 head eyes, two 1920x1536 wrists).h264_nvenc, set up as the Jetson encoder is: High profile, Level 5.2, VBR with a peak, an IDR every GOP with SPS/PPS in front of it, no B-frames. The output is real, decodable H.264. It keeps the real encoder's contract: a fixed pool of input buffers that makessubmit()refuse frames when behind, microsecond-resolution stamps, and a concatenated tail at end of stream. Bitstream bytes, unit sizes and latency are NVENC's, not the Jetson engine's. Needslibavcodec-devand a driver with NVENC.SensingCameramatched it against the submitted nanosecond stamp for equality, socapture_tsc_nswas 0 in the metadata of every encoded stream. The comparison is now at microsecond resolution (own commit).mock_assets/.LICENSES/CC-BY-4.0.txtis the canonical text and the root README notes the exception. They are stored through Git LFS. Decoding usesstb_image, a public-domain header fetched at configure time at a pinned commit and checked against its hash; only the mock backend uses it.sensing_mock_tests): the camera, the encoder,SensingCameraend to end, and a CUDA IPC consumer that maps the shared allocation and reads published frames. GIF scaling is covered for upscaling, downscaling and mismatched aspect ratios, at native size and at test size. The existingtest_sipl_queryalso runs against the mock.Validation
sensing_mock_tests: 37 cases pass; the encoder tests decode the output with libavcodec on a laptop with an NVIDIA GPU (CUDA 12.0 toolkit).test_sipl_querypasses against the mock.camera_plugin_sensingbinary run with defaults captured about 220 frames per sensor in 4 seconds and wrote a metadata file.clang-format-14 --dry-run --Werroris clean on every C++ and CUDA file changed.pre-commitover the changed files: 10 hooks pass. The REUSE hook still reports pre-existing SPDX-like string literals inscripts/check_licenses.py,src/core/codegen/generate_trackers.pyandsrc/core/codegen/templates.py, none of which this PR touches; nothing in the files changed here is flagged.SENSING_BACKEND=JETSONon x86 stops at the existing "SIPL headers not found" error.JETSONbackend was never built or run, and nothing was exercised against SIPL, the V4L2 encoder or real cameras.Known limitations / follow-ups
libegl-dev),libavcodec-devwith a driver that has NVENC, and fetchesstb_imageat configure time.JETSONbuild files were restructured (wrapped in the backend switch) without being built here.Test plan
JETSONbackend and confirm the plugin builds and captures as before.cmake -B build -DBUILD_PLUGIN_SENSING=ON -DSENSING_BACKEND=MOCK, then runsensing_mock_testsandcamera_plugin_sensing --list-sensors.sensing_camera.cpp.PR description drafted with Claude Sonnet 5.5.