You press one button and the preview streams; you press the second button and the program stops with a message that the device is already in use. This guide is for anyone wiring camera preview and capture into a GUI: the code shown is the MATLAB image acquisition toolbox, but the failure and the cure are the same in any vision SDK. The cause is that each button callback creates its own capture object for the same camera, and a camera opens exactly once. You will leave with the one-object pattern — create at startup, share the handle, snapshot without stopping the preview — and the checks that separate this ownership fault from other camera problems.
What does the camera 'already in use' error actually mean?
It means a capture object for that camera already exists somewhere, and the acquisition library refuses to hand the same device to a second object: the fault is ownership of one device handle, never a broken camera, cable or driver. The toolbox states the mechanism in the message itself: "A new videoinput object cannot be created for this device while it is in use." The operating system grants a video device to one opener at a time, and the library passes that refusal straight through. Your first decision on reading it is therefore to leave the hardware alone and go find the second create call.
Why does the second create call fail while the preview runs?
videoinput opens the device, so calling it again in the capture callback asks for a second exclusive handle to a camera the preview already owns, and that open is refused with the in-use message. The failing program carries the same block in two callbacks: the preview button's copy runs first and claims the camera, and the capture button's copy fails on its first line.
% Failing pattern - two callbacks, two create calls.
% Preview callback runs first and claims the camera:
vid1 = videoinput('winvideo', 1, 'MJPG_1024x576');
% Capture callback then fails on its own first line:
vid1 = videoinput('winvideo', 1, 'MJPG_1024x576');
The giveaway is where the error points: at the create call, not at preview and not at getsnapshot. Copying the working preview block into the second button is how this happens, because the copy brings its own create call with it — and a second preview into the same axes would fight the first even if the open succeeded. The capture callback needs the camera the preview already holds; it must never try to open its own.
How do I share one capture object between two button callbacks?
Create the object once at GUI startup and store the handle where every callback can read it — a global variable is the smallest change — then the preview button calls preview(vid1) and the capture button calls getsnapshot(vid1) on that same object.
Startup, once:
% Startup - runs once, before any button can fire.
% vid1: videoinput object, shared by every callback.
global vid1
vid1 = videoinput('winvideo', 1, 'MJPG_1024x576');
vid1.FramesPerTrigger = 1;
vid1.ReturnedColorspace = 'rgb';
triggerconfig(vid1, 'manual');
Preview button (example callback names; your GUI generates its own):
function PreviewButton_Callback(hObject, eventdata, handles)
% hObject, eventdata, handles: the GUI framework's callback arguments.
global vid1
vid1Res = get(vid1, 'VideoResolution'); % [width height], pixels
imWidth = vid1Res(1);
imHeight = vid1Res(2);
nBands = get(vid1, 'NumberOfBands');
hImage = image(zeros(imHeight, imWidth, nBands), 'parent', handles.axes7);
preview(vid1, hImage);
Capture button:
function CaptureButton_Callback(hObject, eventdata, handles)
global vid1
im = getsnapshot(vid1); % im: one frame, taken on demand
getsnapshot takes its frame on demand while the preview keeps displaying, because both are services of the one open object — the snapshot is served by the same device the preview is already streaming. The manual trigger configuration and FramesPerTrigger = 1 stay on the shared object for the day you move on to logged sequences, so sharing costs you nothing. A global is the smallest fix; the GUI's application-data storage does the same job without touching the base workspace. Two habits follow from the same ownership rule: software trigger ownership in image acquisition decides who may fire the trigger, and keeping a camera open and ready between triggered grabs stops reopen delays.
How do I prove the fix works before shipping it?
Press Preview, then Capture, then Capture again, then close and reopen the whole GUI and repeat: every capture must return a frame, and no press in either order may raise the in-use message. The frame itself proves the plumbing, and its size is predictable from your settings. The format string 'MJPG_1024x576' fixes the width at 1024 pixels and the height at 576; ReturnedColorspace 'rgb' gives three bands; at 8 bits per sample, one band sample is one byte.
So a healthy capture returns a 576-by-1024-by-3 array — height first, then width, then bands, which is why the preview callback builds its display axes that way round. At a typical webcam rate of 30 frames per second the stream decodes to about 1,769,472 × 30 ≈ 53 MB/s; the format string carries no frame rate, so treat 30 as a representative figure. One more reason not to open the device twice: a second object would decode the same frames again for nothing.
What if the error still appears with only one create call?
Hunt the previous opener in this order: a leftover process of your own program, then another application holding the camera, then a stale capture object from an earlier run, then a second copy of your GUI.
- Leftover process of your own program. A run that crashed while the preview was live can leave a process holding the device. Test: open the Windows process list, end the leftover copy, run again.
- Another application. A browser tab, a video-call client or the built-in camera app may hold the camera; the camera app reports code 0xA00F4243 when something else has the device. Test: close them, press preview, and confirm the camera app then shows an image.
- Stale capture object. An object left from an earlier run in the same session still claims the device. Test: clear the variable so the object is destroyed, then create again.
- Second copy of your GUI. Two windows, two owners. Test: close one.
Does closing the preview release the camera?
No: the preview is only a display attached to the capture object, so the device stays claimed until the object itself is destroyed — stopping the display never opens a slot for a second owner. The lifecycle is create, use, destroy, and the claim on the device spans the whole of it. That is why 'stop the preview, then open the camera elsewhere' fails, and why the working pattern is restarting a live camera preview without reopening the device. Destroy the shared object once, at shutdown, with the preview closed first.
Does the same one-owner rule apply to industrial cameras?
Yes: a GigE Vision camera accepts one controlling client, and a USB camera is granted to one process at a time, so industrial set-ups run acquisition in one program and publish frames to everything else that needs them. The pattern you just fixed survives the upgrade unchanged: one create call, one shared handle, one owner process. When the GUI graduates from a webcam to a machine-vision camera, plan the host side with it. For GigE cameras, give the acquisition host a network card whose ports belong to the cameras alone:
- Interface
- GigE
- Ports
- 2 ports
For a USB3 camera on a moving stage, choose the camera and its drag-chain data cable together:
- Sensor format
- 1/1.8"
- Lens mount
- C-mount
The area scan cameras range spans both interfaces, the frame grabbers range holds the host cards, and the cables range carries the leads. When capture later fires on hardware lines instead of button presses, the timing questions land in trigger call versus exposure time.
What should I check before blaming the camera or the cable?
Nothing on this list is hardware: an in-use message is always an ownership fault, so run the checks below, and only then look at cables, ports and drivers, which fail with different symptoms.
- One create call in the project, in startup code — two hits is the bug this article fixes.
- The shared handle exists before any button can fire, so no callback ever creates on demand.
- No leftover process of your program and no second GUI window is open.
- No browser, call client or camera app holds the device.
- Capture and preview pass in both press orders and again after a full restart.
- The object is destroyed once at shutdown, preview closed first.
If the front end is outgrowing webcams, start from the camera finder or the system configurator. If a set-up is stuck on a message like this one, bring the exact text and your create call to the contact page.
Questions
Can two programs capture from the same USB camera at the same time?
No. The operating system hands a video device to one process at a time, so the second program receives the same in-use refusal — and that includes browsers, video-call clients and the built-in camera app holding the camera in the background. When two tools need the image, let one program own the camera and hand copies of the frames to the other through a file, a socket or shared memory.
Is device ID 1 always the same physical camera?
Not guaranteed. The number is the camera's position in the list the Windows video adaptor builds at start-up, so unplugging a camera, adding another one or moving to a different port can renumber it. With several identical webcams, fix the cabling and keep the list stable, or choose the camera by name in the create call where your software supports that.
Should the capture object be created at program start or when preview is first requested?
Either works if it happens exactly once and the handle is stored before any other callback runs. Creating it at GUI start is the safer default: the preview needs the object immediately, and the capture callback must never be the creator, or the error returns on the first capture press with the preview already live.
What happens if the shared object is cleared while the preview still runs?
The display freezes and the next callback that touches the handle fails on an empty variable. Destroy the object only at shutdown with the preview closed first, and have each callback confirm the shared handle exists before using it, so an early shutdown cannot crash a late button press.
Do the manual trigger settings matter for a one-shot snapshot?
No: the snapshot path takes its single frame on demand, whatever trigger configuration the object carries. The manual trigger configuration and FramesPerTrigger = 1 matter when you move on to logged sequences, where one trigger delivers a set number of frames. Keep those settings on the shared object either way — a change made in one callback is a change every other callback sees.


