A USB camera that enumerates cleanly but stalls the moment your Android board opens it is a buffer problem, not a camera fault. Two log lines repeat on a 3 s clock — Camera3-Stream asking for an output buffer, RequestThread dropping the request with -110 — and the first open stretches from a few hundred milliseconds to half a minute. This troubleshooting guide is for engineers embedding UVC cameras on ARM boards running Android 8 or 9 with 2 GB of RAM. You will read the timeout exactly, find which of three places is holding your two buffers, run the USB bandwidth arithmetic that decides whether your chosen resolution can stream at all, and apply the fixes in the order that costs least.
What does "getBuffer: wait for output buffer return timed out after 3000ms" actually mean?
Both output buffers on the stream are checked out and none came back, so the framework's Camera3-Stream queue waited its fixed 3000 ms, gave up, and RequestThread dropped the capture request with -110, the Linux ETIMEDOUT code.
HAL3 gives every stream a fixed pool of graphics buffers, sized by max_buffers. For each process_capture_request the HAL dequeues one output buffer from the pool, fills it with frame data, and returns it in the capture result. Your consumer — a Surface, an ImageReader, a recorder — holds the buffer until it finishes with it; only then does the buffer rejoin the free queue. Your log states the pool size: max_buffers 2. One buffer in flight, one with the consumer, zero spare.
E Camera3-Stream: getBuffer: wait for output buffer return timed out after 3000ms (max_buffers 2)
E Camera3-Device: RequestThread: Can't get output buffer, skipping request: Connection timed out (-110)
After 3000 ms the framework stops waiting: Camera3-Stream logs the timeout and RequestThread skips the whole request with -110. The loop then hits the same wall on the next request, which is why the lines repeat at an exact 3.000 s cadence — that spacing is the timeout speaking, not fresh failures. If your case instead shows the host reachable but no pixels arriving, the blank-pipeline probe walks the stages below the HAL; if the sensor never enumerates at all, the Android Camera2 HAL and driver basics cover the layer underneath.
Why does the first open hang and take a picture on its own?
The framework starts firing capture requests the moment you configure the session, so the picture you never asked for is that first burst; with the stream starved, every request burns one 3000 ms timeout and an open that should take a few hundred milliseconds runs for tens of seconds.
The automatic first capture is by design: the framework submits an initial burst of requests at session configuration, before your first frame callback ever runs. On a healthy path that burst returns almost immediately. On a starved stream each request costs a full timeout, so open looks like a hang and the first picture feels like the camera acting on its own.
The Android version decides where the bug lives. Android gained a built-in external-camera HAL for USB devices in the version 9 era; on 8.x builds the UVC path is whatever the board vendor's BSP ships, so buffer behavior differs board to board even with the same camera. That is also why release notes listing a short list of validated webcams read as "units the vendor tested", not as a UVC whitelist — any compliant camera enumerates, but only the tested ones have a proven buffer path. The UVC compatibility guide separates what the standard guarantees from what a BSP actually delivers.
Where do the two buffers get stuck?
In order of probability: your consumer still holds one or both images, the HAL holds them because USB cannot deliver frames on time, or the vendor UVC HAL lost a buffer on an error path and never queued it back.
Work down the list in that order, because the tests run from cheapest to most revealing.
- Your consumer holds them (most common). Every image your ImageReader callback leaves unclosed is one of your two buffers. A stalled recorder or a Surface nobody composites hoards the same way. Test: strip the session to a single preview stream straight to the display; if the timeout stops, the consumer was the hoarder.
- USB delivers frames late. The HAL dequeued a buffer and sits waiting for frame data the link cannot carry on schedule. Test: read the negotiated speed from the enumeration line in dmesg (low, full, high or super speed), then measure delivered frames per second. A link that fell to full speed — usually cable, connector or hub — cannot carry 720p uncompressed at any useful rate, and the arithmetic in the next section makes that exact.
-
The vendor HAL leaked a buffer. An error path dequeues a buffer and never requeues it — the
dequeueBuffer/createGraphicBufferfailure class reported in public Android camera trackers. Memory pressure feeds this: on a 2 GB board a 12 MP YUV buffer alone is 18 MB (4000 × 3000 × 1.5 B), so two still-size streams plus preview can push allocation into failure. Test: idle consumer, 640 × 480, 30 fps. Still timing out? The leak is in HAL code and the fix is a BSP update, not an app change.
How much USB bandwidth does your resolution really need?
Multiply width × height × bytes per pixel × fps and compare it with 24.6 MB/s, the isochronous ceiling of USB 2.0 high-speed: 720p YUYV at 30 fps works out to 55.3 MB/s, so it physically cannot stream uncompressed and the HAL starves while it waits.
Worked example, 1280 × 720 YUYV (2 bytes per pixel) at 30 fps:
- bytes per frame: 1280 × 720 × 2 = 1,843,200 B ≈ 1.84 MB
- required payload rate: 1,843,200 B × 30 = 55,296,000 B/s ≈ 55.3 MB/s
- ceiling check: 55.3 ÷ 24.6 ≈ 2.25× over the ceiling, so uncompressed 720p at 30 fps is impossible on this link
- honest uncompressed cap: 24,576,000 ÷ 1,843,200 ≈ 13.3 fps — which is why compliant cameras list 720p at 15 fps uncompressed
- MJPEG at a typical 10:1 compression: ≈ 5.5 MB/s, fitting 30 fps with about 4.5× headroom (an estimate; the ratio depends on scene)
The full-speed case settles the diagnosis by itself: the full-speed isochronous ceiling is about 1.0 MB/s (1023 B per 1 ms frame), so a single 1.84 MB frame takes 1.8 s and a two-buffer pool cannot complete one round trip inside the 3 s window. A wrong negotiated speed explains most "works on the bench, dies in the housing" reports; the USB link checks after a cable swap catch the physical fault, and the bandwidth-first hub budget applies once a hub joins the path. When the timeout only appears above a set resolution, the USB camera timeout at high resolution guide is the closest worked example to this fault.
Which fix do you apply first?
Run one stream at 640 × 480, 30 fps, straight to the screen with nothing else attached: if that is clean, work down the list — consumer, USB link, format, HAL — because each fix costs less than the one after it.
- Cut the session to one stream. Every extra stream adds its own max_buffers pool and its own USB load, and the still-size stream is usually what tips a 2 GB board into allocation failures.
- Tighten the consumer. Close each image inside its callback, budget one frame period for the release (33.3 ms at 30 fps), keep the working target under 100 ms, and treat 3000 ms as a ceiling you never approach.
- Check the link. Reseat both ends, shorten the cable, move the plug to the board's root port instead of a hub, and confirm the negotiated speed in dmesg.
- Match the format to the budget. Force MJPEG wherever you want uncompressed 720p at 30 fps, or keep uncompressed and cap the rate near 13 fps.
- Update the BSP camera HAL. If the idle-consumer test still times out at 640 × 480, the buffer leak is in vendor code and a BSP update is the fix.
- Swap the camera last, after the code and cable are proven, so you change one variable at a time.
Cabling deserves one line of its own. An office-grade cable fatigues where a camera moves, and a tired cable drops the link to a slower speed — the slow-link fault from the bandwidth section above. The LS-CBL-0219 is a 3 m USB3.0 camera cable built for drag-chain flexing on moving carriages and arms.
How do you prove the fix and keep it from coming back?
A fixed unit shows three numbers over a 10 minute soak: zero RequestThread skip lines, delivered frames within 5% of the negotiated rate, and open-to-first-frame under 1 s.
Run the soak as continuous open-stream-close cycles with a consumer that closes every image. At 30 fps a healthy stream delivers about 1,800 frames per minute, so 1,710–1,890 passes and anything below needs a look; then let the build run an hour or a temperature cycle, because buffer leaks show up as creeping lateness rather than instant timeouts. Prevention is arithmetic, not a setting: redo the bandwidth multiplication and the buffer count before you add a stream or raise a resolution, and rerun the soak after every BSP update. Keep the swap discipline from the bench too — the FFC and cable swap test clears a suspect cable in fifteen minutes, and the same method settles camera-versus-board questions. More faults of this family are collected on the systems topic page.
When is the camera hardware the problem, not your code?
When a known-good camera on the same port streams the same resolution cleanly and yours still stalls after the cable and format checks, the camera's USB path is the suspect, not your buffer code.
Consumer webcams prove software; they are the wrong part for a product that ships. For the build itself, pick a camera made for continuous streaming: global shutter so motion does not smear, locked connectors instead of friction-fit plugs, and a model your vendor keeps in production across the life of your device. The board level cameras category and the embedded vision selection guide are the starting shelves.
Buffer headroom is exactly what you are buying when you move up. The LS-BCM-0003 pairs a 3.1 MP sensor on a 1/1.8" global shutter with 120 fps over USB3. That headroom is the fix for this fault class: streams that overflowed USB 2.0 sit deep inside a USB 3.x pipe instead of 2.25× over a ceiling.
- Sensor format
- 1/1.8"
- Lens mount
- C-mount
- Interface
- USB3
- Resolution
- 5 MP
Where the deliverable is a measurement still rather than video, the LS-CMR-0166 reads its full 4000 × 3000 sensor at 30 fps over USB3. A rate no uncompressed USB 2.0 link can carry is routine here, and that difference is the whole argument.
- Sensor format
- 1/1.7"
- Interface
- USB3
- Resolution
- 12 MP
- Shutter
- Rolling
To size the whole chain — camera, lens, cable — the camera finder filters by interface, resolution and shutter, the configurator assembles a matched set, and the area scan cameras shelf extends to GigE and CoaXPress when the bandwidth argument points off-USB. If you want the math checked against a real parts list before you order, the contact page reaches the applications team.
Questions
Can I increase the 3000 ms timeout instead of fixing the buffer flow?
No. The 3000 ms wait and the skip behavior are compiled into the framework's stream and request-loop code, not exposed as a system property or an app-level parameter. Waiting longer would not help either: the buffers are still checked out, so you would trade a 3 s stall per request for a longer one. Fix the release rate or the bandwidth instead.
Why does the log say max_buffers 2 when my app never set a buffer count?
max_buffers is negotiated per stream at configure time: the HAL reports how many buffers it can pipeline and the framework allocates that many graphics buffers. Board vendors set it low — 2 is common on 2 GB boards — to protect memory, and a 12 MP YUV buffer alone is 18 MB. Your app cannot raise it, so reduce the number and size of streams instead.
Does the same starvation happen with USB3 Vision or GigE cameras on Linux?
The names change, the physics does not. A GigE Vision or USB3 Vision SDK keeps its buffers in the driver and transport library, so a slow consumer shows up as dropped frames or a stream timeout rather than a Camera3-Stream log line. The budget check is identical — payload size × frame rate against link capacity — and the Ethernet-side twin of this fault is covered in the [GigE camera buffer timeouts guide](learn:gige-camera-buffer-timeouts-on-embedded-linux-socket-buffer-tuning).
How many buffers does a stream need to run smoothly?
Three is the practical floor: one in the HAL being filled, one with the consumer, and one queued so a single late frame does not stall the request loop. At 30 fps a frame period is 33.3 ms, so with max_buffers 2 a consumer that holds an image beyond about 66 ms will eventually trip the timeout. Budget four buffers when you also record.
Should I put the camera behind a USB hub to get more ports?
Not for a streaming camera. A hub shares one upstream link, so its bandwidth budget is the sum of everything hung on it, and most embedded boards wire all their ports to a single controller anyway. Wire the camera straight to the root port, or compute the shared budget first and leave about 30% headroom for isochronous traffic.


