QIM SDK C++ App Builder Skill
Use this skill when the user asks for C++ application development with the QIM SDK C++ API described by this skill bundle.
Hard Rules
- Use only APIs, examples, and docs defined in this skill folder and its
references/files. - Always read the minimal matching references before generating output.
- Always load
references/plugin-catalog.mdbefore generating pipeline/app code. - Always load
references/generation-rules.mdbefore generating, editing, validating, or reviewing app artifacts. - Treat
references/plugin-catalog.mdas the authoritative structured plugin catalog:- plugin name
- one-line description
- key properties
- pad/caps notes
- Use
references/plugin-catalog.mdforqtimlpostprocessmodule selection. - If the request names a known model display name or
.tflitefilename, loadreferences/model-catalog.mdbefore selecting postprocess module, delegate, settings, labels, or mandatory results. Catalog model facts override generic heuristics; user-provided paths and values still win. - Always load
references/sdk-architecture.mdbefore generating app structure. - Always load
references/artifact-contract.mdbefore generating deliverable files. - Do not rely on or cite other repos/sources.
- Do not switch to
gst-launch-1.0output unless user explicitly asks. - Do not invent model paths, label paths, settings values, backend configurations, plugin names, or undocumented properties. Use user-provided values as-is; when missing, use explicit placeholders.
- Match requested scope exactly. Do not add daisy-chaining, multistream composition, YAML/config mode, callback-heavy scaffolding, or manual lifecycle control unless the user explicitly asks.
- If the user asks for a simple single-stream app, return a simple single-stream app and nothing more complex.
- For AI pipelines, follow stage order: source -> preprocess -> inference -> postprocess -> metadata/use.
- For overlay pipelines, keep metadata aligned with the main video path using
tee/queueandqtimetamuxbeforeqtivoverlay. - Prefer strongly-typed IMSDK wrappers (
qti::Pipeline,qti::Element,qti::AppSrc,qti::AppSink,qti::CamSrc,qti::MLVConverter,qti::MLPostprocess,qti::MLVideo*Bin) when applicable. - Keep generated C++ syntax aligned with the SDK patterns documented in this skill bundle:
- default to explicit object style:
Element elem("factory", "name"); elem.set(...); pipeline.add(elem); - use fluent factory style (
Pipeline(...).add("factory", "name", ...).link(...).execute()) only when user explicitly asks for fluent/implicit style or when preserving an existing fluent app - do not mix fluent-factory and wrapper-object construction styles in the same generated app unless user explicitly requests mixed style
- default to explicit object style:
- Use exact API names from the SDK headers; do not invent methods or callback signatures.
- If a plugin property/value is not confirmed in SDK headers/apps/docs, keep it as an explicit placeholder.
- Do not hardcode element instance names; use user-provided names when available, otherwise use neutral placeholders and keep names consistent across
add(...),get(...), andlink(...). - For element retrieval, use
pipeline.get("name")for genericqti::Element; useget<T>only for wrappers that support typed retrieval in this SDK. - Use
pipeline.execute()as the default run pattern for generated apps; usestart()/wait()/stop()only when the user explicitly asks for staged lifecycle control. - If the user provides concrete values (for example module names, file paths, labels, settings, thresholds), carry them into generated code directly.
- Use placeholders only for fields the user did not provide and that cannot be confirmed from SDK references.
- For
qtimlpostprocess, use SDK property keys directly (module,labels,settings).settingsis optional by default; include it when user provides postprocess config/settings or threshold-style tuning. Keep placeholders only for unresolved values. - Treat user terms
postprocess config,postprocess settings, andsettingsas the same intent and map toqtimlpostprocesspropertysettings. - For
qtimlpostprocess module, infer fromreferences/plugin-catalog.md; if unresolved, use a placeholder and never invent module names. - For person-foot requests, choose module
qpdwhen request/model/labels/config paths indicate person-foot intent (for exampleperson_footorfoot_track_net) unless user explicitly overrides module. - For PPE equipment/object detection and
gear_guard_netpaths, choose moduleyolov8unless user explicitly overrides module. - For YOLOX detection, choose module
yolov8unless user explicitly overrides module. - For threshold-style tuning (for example confidence), encode it as a JSON string in
settingswith the canonicalconfidencekey (for example"{\"confidence\": 50.0}"). Do not useconfidence_thresholdor semicolon-delimited settings. - For live camera or RTSP object/face/palm detection postprocess (
yolov8,yolov5,yolo-nas,qfd,palmd), setbbox-stabilization=true; omit it for file-source pipelines unless user requests stabilization. - When user asks for backend-specific delegate setup, apply the SDK-documented delegate configuration for the requested flow.
- For
qtimltflite, valid delegate options aregpuandexternal; when usingexternalfor HTP/NPU, setexternal-delegate-path="libQnnTFLiteDelegate.so"andexternal-delegate-options="QNNExternalDelegate,backend_type=htp,log_level=(string)1;"unless the user provides exact delegate options. - For
qtimlvideotflitebin, validinference-delegateoptions aregpuandexternal; when usingexternalfor HTP/NPU, setinference-external-delegate-path="libQnnTFLiteDelegate.so"andinference-external-delegate-options="QNNExternalDelegate,backend_type=htp,log_level=(string)1;"unless the user provides exact delegate options. - For secondary ROI inference stages where the user asks for high-performance HTP/NPU daisy-chain behavior, or for high-concurrency parallel HTP/NPU workloads, use
QNNExternalDelegate,backend_type=htp,htp_performance_mode=(string)2,log_level=(string)1;. For multi-batch HTP/NPU walls, use the named topology section and round-robin batch groups withhtp_device_idwhen multiple HTP devices are present. - Never emit
QNNExecurorBackend:HTP,QNNExecutorBackend:HTP,QNNExternalDelegateBackend:HTP, or colon-separated QNN delegate option strings. - For ML-bin style (
qtimlvideotflitebin/qti::MLVideo*Bin) requests, follow the documented ML-bin property syntax:- inference keys:
inference-delegate,inference-external-delegate-path,inference-external-delegate-options,inference-model - postprocess keys:
postprocess-module,postprocess-labels(and otherpostprocess-*keys when requested)
- inference keys:
- For ML-bin overlay, keep ML-bin stages directly in the media path:
source/decode -> VideoFilter(NV12) -> MLVideo*Bin -> qtivoverlay -> sink, or direct cascades such asmlbin1 -> mlbin2 -> qtivoverlay -> sink. - For PPE or other multi-stage ML-bin requests, use ML-bin for the documented direct fused topology (
source/decode -> mlbin1 -> mlbin2 -> overlay/display). Do not adapt ML-bin into an external metadata branch such astee -> queue -> mlbin -> TextFilter -> qtimetamux; if the request needs original-video branch preservation or tee/metadata fan-in overlay, use discreteqtimlvconverter -> qtimltflite -> qtimlpostprocessstages on the AI branch. - For custom C++ preprocess, use
qti::MLVConverter::set_handler(...)for discrete pipelines orqti::MLVideo*Bin::set_preprocess_handler(...)for ML-bin pipelines. Setengine="none"on discreteMLVConverterand"preprocess-engine", "none"on ML-bin before registering the handler. Do not use postprocess callback APIs for preprocessing. - For custom C++ postprocess placeholders, callback bodies must return a deliberate
bool:return true;for a valid empty/populated result orreturn false;only for a real error path. Do not generate placeholder callbacks that fall through without returning. - Default CMake pattern should link
qimsdk-app-builderdirectly (SDK app style) and should not requirepkg-configunless user explicitly asks. - Use the CMake template from
references/artifact-contract.md(set(TEST_TARGET ...),add_executable,target_link_libraries(... qimsdk-app-builder), andinstall(...)) unless the user requests a different build style. - For ROI-based secondary inference and postprocess tuning, follow SDK-documented configuration and keep unresolved details as placeholders.
- For two-stage daisy-chain requests, preserve stage-wise structure (stage-1 preprocess/infer/postprocess + stage-2 ROI preprocess/infer/postprocess + metadata merge path).
- For two-stage daisy-chain requests, set stage-1
qtimlvconvertermode toimage-batch-non-cumulativeand stage-2qtimlvconvertermode toroi-batch-cumulative. - For gesture-recognition chains (palm detection -> hand landmark -> gesture embedding -> gesture classification), do not use a generic N-stage mux cascade. Use the documented gesture topology: exactly two
qtimetamuxstages,qtimetatransform module="roi-palmd"between the first mux and the second split, stage-2 inference output split into anhlandmarkmetadata branch and atensor -> embedder inference -> classifier inference -> mobilenetclassification branch, then merge both into the second mux beforeqtivoverlay. - For tee +
qtimetamuxfan-in, prefer SDK-stylepipeline.link(...)by element names; do not hardcodesink_0/sink_1pad names unless explicitly confirmed. - For tee +
qtimetamuxfan-in links, terminate each branch at the mux, then linkmetamux -> overlay/displayseparately. Do not fold downstreamqtivoverlayor sink elements into the AI branch link call. - For MP4 file-input flows, default to
filesrc -> qtdemux -> h264parse/h265parse -> v4l2h264dec/v4l2h265dec -> queue; add a queue afterqtdemuxonly when decoupling/robustness is explicitly needed. - C++ string literals never expand shell variables. A literal
"$HOME/..."string passed to any filesystem-bearing property (filesrc.location,qtimltflite.model,qtimlpostprocess.labels/settings,filesink.location) is passed byte-for-byte to the OSopen()call — the app fails at runtime withCould not open '$HOME/...'/Failed to load model file, not at compile time. Always resolveHOME-relative paths in C++ itself before assigning them, with an explicit unset/empty check (do not silently fall back to""and construct an invalid relative path):
This is a language/API-boundary rule, not an app-specific exception — apply it to every filesystem property in every generated app, regardless of topology.std::string expand_home(const std::string& suffix) { const char* home = std::getenv("HOME"); if (home == nullptr || *home == '\0') { throw std::runtime_error("HOME is not set; cannot resolve filesystem path: " + suffix); } return std::string(home) + suffix; } - Each
teebranch gets exactly one completepipeline.link(...)chain to its consumer. Do not also link the tee directly to a downstream element (e.g. a mux) when a separate queued chain already terminates at that same element — GStreamer request pads are allocated perlink()call, so the direct link and the queued link each claim their own pad, leaving the queued branch's padNOT_LINKEDwhile the direct one silently "works." This produces confusing downstream symptoms (encoderInvalid argument,Device or resource busy) that look unrelated to linking. Before adding a link, check whether that consumer already has a queued chain from the same tee. - When a source's demuxed branches run concurrently (e.g. an MP4 with both an H.264 video track and a FLAC/AAC audio track feeding independent downstream paths), give each dynamic
qtdemuxpad — and any intermediate decode boundary within a branch (e.g. afterflacdec, beforeaudioconvert) — its ownqueueimmediately after the pad. One branch's preroll/scheduling can otherwise block the other's, and the pipeline hangs beforePLAYINGwith no obvious error. Reserve the minimal directqtdemux -> parserhop for genuinely single-stream video paths. - For
qticamsrc/qtiqmmfsrccamera inputs, setcamera=0by default unless the user explicitly requests another camera ID. - For
qticamsrc/qtiqmmfsrccamera inputs, if the user does not provide resolution or framerate, constrain the camera stream withVideoFilter().format("NV12").resolution(1920, 1080).framerate(30)before display, branching, or AI preprocessing, and call out1920x1080 @ 30fpsas an assumed camera default in the artifact README. - For H.264 decode stages, set
v4l2h264decIO modes tocapture-io-mode=4andoutput-io-mode=4unless the user explicitly requests a different documented mode. - Select encoder IO modes (
v4l2h264enc) from what actually allocates the buffer arriving at the encoder's input, not from the pipeline's original source type in isolation: usecapture-io-mode=4 output-io-mode=4when the encoder's input is driver-managed/transform-produced NV12 (file/RTSP source decoded through the hardware decoder, or any AppSrc-fed/copied buffer), and reserveoutput-io-mode=5(dmabuf-import) for camera-native DMA import or a documented AV-record dual-input-mux branch. Getting this backwards on a file-source or AppSrc branch produces device-side encoder errors (Invalid argument,Device or resource busy) that look unrelated to IO mode. Seereferences/source-sink-patterns.md"File Recording". - Place a
queueimmediately after every hardware decoder before any filter, tee, AI, display, or mux stage. - Normalize source/decode output to
video/x-raw,format=NV12before branching (tee) or AI preprocessing unless the user explicitly requests a different documented source format. - Add
VideoFilter,TextFilter,TensorFilter,ImageFilter,H264Filter,AudioFilter, and otherStreamFilterobjects withpipeline.add_stream_filter("<name>", filter_obj), never withpipeline.add(...). - Every stream filter name used in
pipeline.link(...)must exactly match the string passed topipeline.add_stream_filter(...); C++ SDKadd_stream_filterrequires a unique name plus filter instance. - For metadata overlay with discrete AI elements, keep a main video branch with
tee, route postprocess metadata throughTextFilter(), and merge video + metadata withqtimetamuxbeforeqtivoverlay. - For segmentation, rendered-mask, alpha-blend, side-by-side, or other video-output postprocess branches, use direct-to-composer topology: passthrough branch plus AI/render branch into
qtivcomposer. Do not force rendered video throughTextFilter/qtimetamux. - The render
VideoFilterafterqtimlpostprocessMUST be.format("RGBA")(neverBGRA/RGB— device src caps arevideo/x-raw,{RGBA,RGBx}; anything else fails to link). Do NOT pin.resolution()on it when a downstreamqtivcomposersizes the tile — device-verified, it fails caps fixation withFixated width in filter caps is not supported with current post-process type!regardless of format; let the composer sink-paddimensionssize it. Seereferences/plugin-catalog.md"Module Output Types". - For super-resolution, audio AI, AI wall, batched multi-stream inference, face recognition, or AI metadata parsing requests, use the named topology sections in
references/pipeline-construction.md; do not reduce these to the generic single-stream or two-stage templates. - For
qtimetamuxwritability, do not assume camera buffers are inherently non-writable; addqtivtransformbeforeqtimetamuxwhen the same source/tee also feedsqtivcomposer(always required — it holds buffers for stream sync), when a sibling branch hasfilesinkorqtimlmetaparser(required under load — these are fast but can still hold the buffer), when a documented source/format path requires conversion/copy, or when runtime logs show the metadata attach warning. - A leaf
appsink(frame/metadata tap) sharing a tee with aqtimlvconverterbranch poisons the DMA pool (Buffer does not have FD memory→ 0 inference); insertqtivtransformbefore thatappsinkto isolate its allocation. Same buffer-ownership family as theqtimetamuxwritability rule. Seereferences/source-sink-patterns.md. - Buffer writability is a shared-tee invariant, not just a
qtimetamux/composer special case: whenever more than one buffer-mutating consumer (in-place overlay, composer, appsink tap) reads off the sameteepad, only one of them can draw/consume in place — the rest silently do nothing (no error, no crash). In a parallel-branch wall where N sibling AI branches each overlay their own result off one sharedtee, give every branch's passthrough leg its ownqtivtransform ! VideoFilter(NV12)copy before itsqtimetamux, or only one branch's overlay will render. Seereferences/pipeline-construction.md"Mixed AI Wall". - Resolve unresolved model/labels/settings paths against the closest known-good reference (working Python cache app, or the original GStreamer C sample) before falling back to a bare placeholder — an app that reaches
PLAYINGwith a literal placeholder string (e.g.<MODEL_PATH_STAGE1_QPD>) is not runnable and will fail withFailed to load model filethe moment it is executed; prefer a concrete, catalog/reference-backed value whenever one is resolvable. - A
qtivcomposer's configuredinput(N)pad geometry must exactly match the number of branches actually linked into it at the time of generation/edit — this is an invariant to re-derive after every topology change, not a fixed count to carry forward. A staleinput(N)call for a pad no longer linked throwsPort: cannot resolve target padbeforePLAYING. This commonly happens when a branch that used to feed the composer as two raw pads (passthrough + rendered mask) is refactored to pre-compose those two into one finished tile on a localqtivcomposerfirst — the top-level composer then needs one fewer configured pad. Seereferences/pipeline-construction.md"Mixed AI Wall". - HRNet and other documented top-down pose models can run either directly on full frames (simpler, one stage) or on a detector-cropped ROI (an extra stage, sharper keypoints when the subject is small/distant). Build the topology the request actually describes — do not silently drop or silently add the stage-1 detector. If the request is ambiguous about whether ROI cropping is wanted, prefer the full-frame single-stage form as the default (fewer moving parts) and ask only if accuracy on small/distant subjects is explicitly a concern. When building the two-stage cascade, use stage-1 person/foot detection with
image-batch-non-cumulative, merge its metadata, then stage-2roi-batch-cumulativeHRNet with a second metadata merge before overlay; settings and results are mandatory for both stages in that case.lite-3dmm(face-recognition stage 2) needs/etc/data/{blendShape,meanFace,shapeBasis}.binon the device — note that prerequisite in the README. Seereferences/model-catalog.md. - For two-stage discrete daisy-chain AI with overlay of both stage outputs, do not generate a single linear
postprocess -> TextFilter -> qtimetamux -> qtivoverlaychain. Use two tee/mux stages: split before stage 1, merge stage-1 metadata withqtimetamux, split the merged stream before stage 2, merge stage-2 metadata with a secondqtimetamux, then overlay. - For display, default
waylandsink fullscreen=true sync=truefor every source type, including live camera sources (qticamsrc,qtiqmmfsrc,v4l2src) — camera source type alone is not a reason to usesync=false. Usesync=falseonly for: (1) more than 8 independent concurrently active input streams AND a processing-heavy topology (shared/batched inference, or a large composer grid where HTP/batch preroll makes frames arrive well behind their PTS) — a 4-stream AI wall, a simple multi-stream playback grid, or a batch group of 8 or fewer streams stayssync=true; (2) display sharing a tee/composer source with a parallel encode/file/metadata sink that can stall the display clock (stream-count-independent, pair withenable-last-sample=falsewhen it is also a multi-sink camera pipeline); (3) the user explicitly requests lower latency over A/V sync. Audio-classification display pipelines omit thesyncproperty entirely. Seereferences/pipeline-construction.md"Display Sink Sync Policy" for the full canonical statement. - For any app that uses
pulsesrcorpulsesink, include the PulseAudio prerequisite in the response and in READMESteps to Run:wpctl status, thenwpctl set-default <node_no.>. Do not invent a default node number;<node_no.>is device-specific. - For single-input pipelines, use minimal queue placement; avoid inserting queue between every stage unless needed for tee branches or explicit decoupling.
- Reject redundant queues (for example adjacent queue stages with no clear reason).
- Default runtime pattern is
pipeline.execute()unless the user explicitly asks for manual lifecycle. - Artifact folder names generated by this skill must start with
qimsdk-cpp-. - Generated C++ app names must use
qimsdk-cpp-<appname>prefix (for example pipeline name and CMake target/binary name unless user explicitly overrides). - Folder name and app/binary name may be the same value.
- Generated examples should include concise comments for major pipeline sections, placeholders, custom preprocess/postprocess TODOs, and non-obvious SDK requirements. Do not comment every obvious line.
- For C++ AppSrc/AppSink callbacks, use
set_buffer_producer(...),set_buffer_consumer(...),set_preroll_handler(...),set_eos_handler(...), andset_enough_handler(...); do not use genericset_handler(...)or old camelCase names. For raw element GObject signals not covered by a typed wrapper, useqti::Element::connect_signal(...)/disconnect_signal(...); do not use them to replace the AppSrc/AppSink handler callbacks. - For event-triggered recording (a resident recorder pipeline gated by a metadata condition on another pipeline), never call
Pipeline::start()/stop()/eos()from inside the gating AppSink's callback — synchronous state transitions there can deadlock the producer/display pipeline. Keep the recorder resident andPLAYINGfrom before the gate can fire; have the callback only flip an in-memory boolean. Forward the gated AppSink's buffer to the recorder's AppSrc withpush_buffer(std::move(buffer))— never allocate a freshqti::Bufferandmemcpyinto it, which breaks the hardware encoder's expected DMA-backed buffer contract and can crash it (SIGSEGV) on the first gated frame. Seereferences/pipeline-construction.md"Event-triggered recording variant".
Custom Preprocess Guardrails
- Use custom C++ preprocess only when requested or when the user explicitly asks for placeholder preprocess logic.
- For discrete pipelines, use
qti::MLVConverter preprocessing("preprocessing"); preprocessing.set("engine", "none"); preprocessing.set_handler(callback);. - For ML-bin wrappers, set
"preprocess-engine", "none"before.set_preprocess_handler(callback)onqti::MLVideoTFLiteBin,qti::MLVideoQNNBin,qti::MLVideoSNPEBin, orqti::MLVideoONNXBin. - Callback type is compatible with
qti::TensorsPreprocessCallback:bool(const qti::MLVideoBlits& blits, qti::MLFrame& output). - Generate an honest TODO placeholder when the user does not provide tensor layout, scale/letterbox policy, quantization, channel order, and normalization details. Do not invent image-to-tensor conversion math.
- Placeholder callbacks return
falseuntil a valid tensor is written. Generated comments must state that after implementing tensor conversion and writing output tensors, the callback must returntrue.
Clarification vs Placeholder Rules
Ask the user upfront when missing info changes topology or element selection:
- input source type is missing (file vs camera vs RTSP)
- output target is missing (display vs file vs appsink vs mixed)
- ML stage count is unclear (single-stage vs daisy-chain)
- backend family is unclear (
qtimltflitevs ML-bin wrappers) - custom preprocess tensor contract is unclear and the user expects working conversion logic rather than a placeholder
Use placeholders when only runtime values are missing:
<INPUT_FILE>,<MODEL_PATH>,<LABELS_PATH>,<SETTINGS_PATH>,<OUTPUT_FILE><POSTPROC_MODULE>when module cannot be inferred from references
After generation, list all placeholders in README so none are missed.
Generation Workflow
- Classify request: basic media app, camera app, AI app, external preprocess app, external postprocess app, or YAML-config app.
- Before generating anything, load
references/artifact-contract.mdandreferences/plugin-catalog.md, then only matching references from this skill. Also loadreferences/generation-rules.mdfor shared generation, placeholder, YAML, comments, and pipeline rules. If the request names a known model display name or.tflitefilename, also loadreferences/model-catalog.md. - For any C++ app generation request, load
references/example-retrieval.mdand runrank_examples.pyto ground the draft in known-good examples — this adds context alongside the rest of this workflow, it does not replace step 2's reference loading or steps 4-5. Finding a retrieval match does not skip or shorten any subsequent step — all of steps 4-5 run unconditionally regardless of what retrieval returns or whether a file was leveraged. Skip this step for plugin-only lookups. - Generate filesystem artifacts (folder + source + README).
- Include
Pipeline FlowwithText SummaryandMermaid Diagramsubsections, plusSteps to Run, in README from actual code wiring. - Validate API usage against
references/api-surface.mdandreferences/sdk-architecture.md.
Request Matching
- General C++ IMSDK app →
references/api-surface.md+references/sdk-architecture.md+references/pipeline-construction.md+references/source-sink-patterns.md - C++ qimsdk SDK app request (user asks for a C++ application using the qimsdk C++ API,
qti::Pipeline/qti::Element/qti::CamSrcclasses) → loadreferences/api-surface.md+references/pipeline-construction.md+references/source-sink-patterns.mdplus the pipeline-topology references that match the request type. Do not loadreferences/c-app-*.mdfor this output type. - AppSrc/AppSink bridging → also load
references/pipeline-construction.md - Camera capture/control → also load
references/pipeline-construction.md+references/source-sink-patterns.md - File/RTSP source or file/RTSP output request → also load
references/source-sink-patterns.md - AI inferencing (TFLite/QNN/SNPE/ONNX bin) → also load
references/ml-and-postprocess.md - Known model filename/display name → also load
references/model-catalog.md - Delegate/backend-specific inferencing request → also load
references/inference-runtimes.md - External C++ preprocess callback → also load
references/ml-and-postprocess.md - External C++ postprocess callback → also load
references/ml-and-postprocess.md - Custom/external postprocess handler request (C++
MLPostprocess::set_handler, app-authored tensor decoding) → loadreferences/ml-and-postprocess.md - YAML config constructor mode → also load
references/pipeline-construction.md - Build/run deliverable request → also load
references/artifact-contract.md - Any C++ app generation request (before drafting, after classification) → also load
references/example-retrieval.mdand runrank_examples.pyto ground the draft in known-good examples
Output Contract
- Generate artifacts by default, not copy-paste-only responses.
- Never return only inline snippets when runnable artifacts are requested.
- Use
references/plugin-catalog.mdas the single plugin allow-list and plugin-facts source; do not maintain separate inline plugin lists in this file. - Whenever generated code is changed (
main.cc,main.cpp,*.cc,*.cpp, orCMakeLists.txt), update the corresponding artifactREADME.mdin the same folder in the same pass so flow, placeholders, and run/build steps remain accurate. - Artifact folder name must use prefix
qimsdk-cpp-(prepend it if user-provided name does not include it). - App name in generated code/build outputs must use
qimsdk-cpp-<appname>prefix by default. - Folder name and app/binary name can be set to the same prefixed string.
- Required folder layout for every request:
<artifact-name>/main.cc<artifact-name>/CMakeLists.txt<artifact-name>/README.md
- YAML config constructor requests also include a YAML config file unless the user explicitly says the YAML is already provided externally and should not be generated.
- README must include:
- purpose and assumptions
Pipeline Flowmapped from actual code, withText SummaryandMermaid Diagramsubsections- required placeholders to fill
Steps to Compile: exactly the lineYocto: https://imsdkdocs.qualcomm.com/advanced/yocto-build#steps-to-build-custom-application— no other compile instructionsSteps to Run
Completion Checklist
- Uses only IMSDK C++ APIs present in
include/qti/*.h. - Pipeline lifecycle is coherent (
start/wait/stoporexecute). - Element names in
.add(...)and.link(...)are consistent. - Any callback signatures match SDK typedefs.
- README
Text SummaryandMermaid Diagrammatch actual code paths. - README includes
Steps to Compile(the Yocto build link only) and clearSteps to Run. - No references to sources outside this skill folder.
- User-specified values are preserved in code instead of being replaced with placeholders.
- Display output defaults to
waylandsink fullscreen=true sync=truefor every source type including live camera sources;sync=falseis used only for the three documented exceptions (>8-stream processing-heavy topology, multi-sink clock-stall, or explicit user low-latency request), and audio-classification pipelines omitsyncentirely. - Queue usage is minimal and justified for single-input flows.
- No invented plugin names or invented
qtimlpostprocessmodule names. - If C++ source/build files were changed,
README.mdin the same artifact folder was updated to match. - Custom preprocess placeholders are explicit about missing image-to-tensor conversion logic.
- Every generated app calls
qti::SetImsdkGstLogMode(qti::ImsdkGstLogMode::ImsdkLog)andqti::SetImsdkLogLevel(qti::ImsdkLogLevel::Debug)at the top ofmain(), before constructing anyPipeline, unless user explicitly requests a different logging mode or verbosity; wrap pipeline construction/execution intry { ... } catch (const std::exception&) - Includes only
<qti/qimsdk.h>— never the individualqimsdk-*.hheaders directly, and never mixes in rawgst_element_factory_make/gst_sample_apps_utils.hC-app scaffolding CMakeLists.txtlinks only against theqimsdk-app-buildertarget (target_link_libraries(<target> PRIVATE qimsdk-app-builder)) — does not additionally link GStreamer or QTI ML/video-base libraries directlyqti::classes/methods/property-prefixes used matchreferences/api-surface.mdexactly (e.g.set_postprocess_handleron ML bins vs.set_handleron discreteMLPostprocess) — do not invent methods or mix bin-style and discrete-style property names on the same element- No SIGINT/Ctrl+C handling is assumed from the SDK — the SDK provides none; only hand-write it if the user explicitly asks for it. CLI arg-parsing is also not emitted by default; add an opt-in
--input-configgetopt_longparser (inmain(), README-documented) only when the user asks for runtime-configurable input
Reference Files
references/plugin-catalog.md— plugin allow-list andqtimlpostprocessmodule-selection guidancereferences/model-catalog.md— known model-to-module/delegate/settings/results lookup tablereferences/generation-rules.md— shared C++ generation defaults, placeholders, comments, YAML mode, and pipeline rulesreferences/api-surface.md— API inventory and valid method namesreferences/sdk-architecture.md—include/andsrc/structure and generation implicationsreferences/pipeline-construction.md— fluent C++ construction patterns from SDK appsreferences/ml-and-postprocess.md— ML bin usage and external preprocess/postprocess callbacksreferences/inference-runtimes.md— inference runtime elements, delegate/backend property mapping, and C++ SDK equivalentsreferences/source-sink-patterns.md— source and sink selection patternsreferences/multimedia-pipeline-patterns.md— multimedia pipeline patternsreferences/artifact-contract.md— artifact folder/readme output contract for this skillreferences/verify-cpp-app.sh— generated C++ artifact verifierreferences/example-retrieval.md— retrieval-grounding: how to runrank_examples.py, screen ranked candidates for a genuine fit, and leverage a real matching file as the starting point (falling back to building fresh from the rules only when none fit).