Hardware encoding succeeds only when frames reach the Jetson encoder before their delivery deadline and the encoder remains inside its thermal and power operating envelope. A missed deadline appears as latency or dropped video; an unselected hardware factory appears as OpenH264 CPU load. The number that matters is the end-to-end frame time, while sustained current draw and temperature determine whether that time remains stable under load.
Wrong fixes and their failure modes
Changing the C++ language setting between C++14 and C++17 does not, by itself, resolve a group of undefined reference std:: errors. Compilation confirms that headers and source syntax are acceptable; linking separately requires compatible object files, C++ runtime libraries, ABI settings, architecture, and link order.
Wrapping video_encoder_factory also does not activate hardware encoding. WebRTC must receive that factory through the construction path used by the active session. If the application creates its peer connection machinery through another path, the wrapper remains unused and codec negotiation can still select OpenH264.
Enabling LibNvVideoEncoderTemplateAdapter without satisfying its initialization contract is equally ineffective. The reported check adm() failed is a failed internal precondition, not proof that the encoder hardware is defective. Trace the value checked by that assertion and find where the sample normally creates, owns, and passes it before enabling the adapter.
| Attempt or symptom | What it actually indicates | Next measurement |
|---|---|---|
| Switch C++14 to C++17 | Source-language selection changed, but the unresolved symbol contract did not | First missing symbol, defining library, ABI, architecture, and link order |
| Factory wrapper exists but is never called | The active WebRTC construction path does not consume it | Factory construction and encoder-creation call trace |
| OpenH264 remains active | Software H.264 was selected or used as fallback | Negotiated codec and selected encoder implementation |
check adm() failed |
An adapter precondition or dependency is invalid | Checked expression, initialization sequence, and object lifetime |
Hardware-selection mechanism
The pipeline has four distinct decisions: capture a USB-camera frame, convert it to I420, negotiate H.264, and create the encoder implementation. Successful I420 conversion and H.264 negotiation do not prove hardware acceleration. They establish the input format and codec, but the injected encoder factory decides which encoder object handles the frames.
Follow the call path from session creation to encoder creation. Place temporary diagnostics at construction of video_encoder_factory, entry to its encoder-creation method, and entry to LibNvVideoEncoderTemplateAdapter. Record the requested codec at the same points. A factory that is constructed but never receives a creation request is connected to the wrong object graph; a factory that receives a non-H.264 request points to negotiation or capability advertisement; an adapter entered immediately before check adm() failed points to incomplete adapter initialization.
This is heat and timing, not merely logic. Software encoding can saturate CPU resources and increase frame time, while hardware encoding moves the compression workload to a dedicated block. Hardware selection still cannot compensate for capture stalls, slow I420 conversion, queue growth, thermal throttling, or a power mode that cannot sustain the required workload.
Release and package alignment
The installation described here uses a Jetson AGX Orin development board with JetPack 6.0, BSP 36.3, and g++ 11.4.0. Treat those values as one compatibility set. Use the libwebrtc 36.3 package supplied for the Jetson Linux 36.3 release rather than transplanting a 25.2 binary or assuming its successful link proves compatibility.
The 36.3 public sources archive contains webrtc_argus_camera_app_src. The documentation also names WebRTP_r36.3.0-arch64.tbz2; verify that exact archive name and obtain the package from the Jetson Linux 36.3 release materials or the official package location referenced by the documentation. The Argus sample demonstrates an Argus-oriented capture path. A USB-camera application must preserve the hardware-encoder integration while replacing or adapting capture and conversion; the sample name alone does not establish USB compatibility.
| Item | Required comparison | Where to read it |
|---|---|---|
| Hardware | Jetson AGX Orin | Board identification |
| Platform release | JetPack 6.0 and BSP 36.3 | Installed platform release data |
| Compiler | g++ 11.4.0 plus matching runtime | Compiler output and linked C++ runtime |
| WebRTC package | 36.3 build for the installed architecture | Official package metadata and archive contents |
| Frame timing | Capture-to-send time below the application deadline | Timestamp each pipeline boundary |
| Thermal load | No clock reduction during a sustained test | Jetson runtime telemetry |
Undefined C++ reference diagnosis
Start with the first linker error, not the full cascade. Determine which object references the symbol and which archive or shared library should define it. Then inspect whether the defining library is present on the final link command after the object or archive that needs it. Static archive resolution is order-sensitive, and a missing early dependency can generate many secondary std:: failures.
Compare the application and libwebrtc build contracts: target architecture, compiler family and major version, C++ standard library, ABI-related build definitions, exception and runtime assumptions, and debug versus release configuration. Also check whether the downloaded package is a complete developer package rather than only runtime artifacts. Adding arbitrary shared objects can hide the first error while creating an ABI mismatch later.
If libwebrtc 36.3 compiles but the final application link fails while 25.2 links, compare the complete verbose link lines and symbol tables for the two builds. The differing library, path, or ABI marker is more useful than repeatedly changing the language standard.
Encoder integration procedure
- Install the libwebrtc 36.3 package intended for the BSP 36.3 platform and confirm that every library has the target architecture expected by the application.
- Build the supplied 36.3 sample without application modifications. This separates package and linker faults from USB capture integration.
- Run the sample and instrument construction and invocation of
video_encoder_factory. Confirm whether the packaged sample actually reachesLibNvVideoEncoderTemplateAdapter. - Trace the active application's WebRTC initialization. Pass the custom encoder factory into the same construction path that creates the live session; remove or bypass any parallel default path that silently creates a software-only factory.
- Advertise and negotiate H.264, then log the codec requested from the custom factory. Codec negotiation and encoder instantiation must agree.
- Connect the USB capture path to I420 conversion, preserving frame width, height, timestamps, and buffer lifetime until encoding completes. Avoid unnecessary copies and unbounded queues.
- If
check adm() failedoccurs, stop at the failing check, inspect the checked object, and reproduce the sample's creation order, ownership, and thread context. Do not disable the check; doing so can move an invalid object into the encoder and produce a later crash. - Build the complete application with the package's compatible compiler, ABI definitions, libraries, and link order. Resolve the first undefined symbol before proceeding to runtime testing.
Runtime verification and recurring pitfalls
Verification requires implementation identity and performance data. Log the negotiated codec, the factory selected for the session, entry into the hardware adapter, encoded-frame output, and any fallback. In parallel, measure CPU utilization, capture-to-encode latency, output cadence, queue depth, temperature, clocks, and power telemetry during a sustained run.
Use timestamps at USB capture, completion of I420 conversion, encoder submission, encoded-frame return, and network send. A growing submission queue identifies throughput below the input rate. Stable encoder time with irregular capture timestamps identifies the camera path. Rising temperature followed by lower clocks and longer frame time identifies thermal or power limiting.
Recurring integration faults include registering a factory on an unused session path, advertising H.264 while instantiating the default software encoder, releasing an I420 buffer before asynchronous encoding completes, passing incompatible dimensions or layout, and mixing 25.2 artifacts with a 36.3 build. A successful link is only the first gate; a successful H.264 call is not proof of hardware selection.
FAQ
What happens if OpenH264 still appears after registering the factory?
The live session is either using a different factory path or requesting a codec the custom factory does not handle. Log factory construction, the encoder-creation call, the requested codec, and the selected implementation for the same session.
What happens if libwebrtc 36.3 reports undefined std:: references?
Inspect the first missing symbol and compare architecture, C++ runtime, ABI definitions, required libraries, and final link order. Switching only between C++14 and C++17 will not repair a missing library or incompatible binary contract.
What happens if the hardware adapter still fails check adm()?
Stop when the checked dependency cannot be created through the sample's documented initialization path, or when the official 36.3 sample fails unchanged on the aligned JetPack 6.0 and BSP 36.3 installation. Capture the failing expression, stack trace, verbose link command, package identity, and minimal reproduction, then escalate through NVIDIA's official support channel.