Short answer: Yes — but whether it is guaranteed to work on your specific phone depends on a value called the Camera2 hardware level. Android publishes a table of stream combinations every Camera2 device must support. On the lowest tier,
LEGACY, the guaranteed way to run two camera consumers at once caps both of them at preview resolution. Apps like Background Camera RemoteStream record with the screen off and serve a live view over your LAN at the same time — and the reason the live view is a lighter, smaller stream than the recorded file is not a shortcut. It is the shape of the guarantee.
The question arrives phrased as a feature request: "Can it record and let me watch at the same time?"
The honest answer is more interesting than yes or no, because "at the same time" is where a phone stops behaving like a camera and starts behaving like a shared resource with a queue. One sensor. One image pipeline. Two things that both want frames — a file on disk, and a browser on the other side of the house.
Android has a documented answer for how many consumers you can attach to that pipeline. Most developers never read it, and almost no consumer-facing article mentions it. So let's read it.
Can an Android phone record video and stream it live at the same time?
Yes, on most modern phones — and it is guaranteed on every Camera2 device if you configure the two outputs correctly. Android's documentation states that "every device that supports Camera2 (API level 21 and higher) can output up to three simultaneous streams using the right configuration and if there isn't too much overhead limiting performance, such as memory, CPU, or thermal constraints." The catch is in "the right configuration": on the lowest hardware tier the guaranteed two-output combinations cap the second stream at preview size, not full recording resolution. So the practical answer is that recording plus live view is a supported design on old hardware — as long as the live view is allowed to be the smaller of the two.
Everything below is why.
The guarantee has exactly three inputs
Android's guidance on running several camera outputs at once is refreshingly blunt about the fact that per-device behaviour varies. What it offers instead is a floor. From the docs:
"Actual performance varies from device to device, though Android provides some guarantees for supporting specific combinations depending on three variables: output type, output size, and hardware level."
Those three are worth defining carefully, because the whole thing collapses into confusion if you blur them.
Output type is the format the frames are encoded in. The documented values are PRIV, YUV, JPEG and RAW. The docs note that for "preview and recording scenarios" where you hand the camera a SurfaceView, TextureView, MediaRecorder, or MediaCodec, you should not specify an image format, and "for compatibility, it will count as ImageFormat.PRIVATE, regardless of the actual format used internally." So: a video recording output is a PRIV output. Frames you intend to look at in your own code are YUV.
Output size sounds like it should mean "any resolution the camera supports," and it doesn't. Although every supported size is listed by StreamConfigurationMap.getOutputSizes(), "only two are related to compatibility: PREVIEW and MAXIMUM. The sizes act as upper bounds." And PREVIEW has a definition that catches people out:
"
PREVIEWrefers to the best size match to the device's screen resolution or to 1080p (1920x1080), whichever is smaller."
Read that again with a five-year-old budget phone in mind. On a 720p handset, PREVIEW is 720p-ish, not 1080p. The compatibility ceiling for a second stream is tied to the panel, not the sensor. A phone can have a 12-megapixel camera and a PREVIEW class of 1280×720.
Hardware level is the tier the device's camera implementation sits in, and it is the variable that does the most work.
The one table that is fully public
Android publishes the guaranteed combinations per hardware level. The table reproduced in the multi-stream guide is the LEGACY one — the lowest tier, described as "the lowest common denominator devices." Here it is, as documented:
| Target 1 | Max size | Target 2 | Max size | Target 3 | Max size | Sample use case |
|---|---|---|---|---|---|---|
PRIV |
MAXIMUM |
Simple preview, GPU video processing, or no-preview video recording | ||||
JPEG |
MAXIMUM |
No-viewfinder still image capture | ||||
YUV |
MAXIMUM |
In-application video/image processing | ||||
PRIV |
PREVIEW |
JPEG |
MAXIMUM |
Standard still imaging | ||
YUV |
PREVIEW |
JPEG |
MAXIMUM |
In-app processing plus still capture | ||
PRIV |
PREVIEW |
PRIV |
PREVIEW |
Standard recording | ||
PRIV |
PREVIEW |
YUV |
PREVIEW |
Preview plus in-app processing | ||
PRIV |
PREVIEW |
YUV |
PREVIEW |
JPEG |
MAXIMUM |
Still capture plus in-app processing |
Three things jump out of that table.
First: a single output can be MAXIMUM. Row one — one PRIV stream at full size — is the "just record, nobody is watching" case, guaranteed everywhere. If you want the highest-quality file the phone can produce with no second consumer, every Camera2 device will give you that.
Second: the moment you add a second output, the video stream drops to PREVIEW. Every two-target row in the guaranteed set has PREVIEW in the size column of the video-ish stream. That is not a doc simplification. It is the price of the second consumer, written down.
Third: the only guaranteed three-output row is preview + in-app frames + a still. There is no guaranteed row giving you two independent full-resolution video streams. If you were hoping to record 4K to disk while shipping 4K over the network, the documented floor does not include it.
The row a phone-as-camera app actually lives on
Look at row seven: PRIV at PREVIEW plus YUV at PREVIEW — labelled "preview plus in-app processing."
That row is the architecture.
A recorded video file is a PRIV output (you hand the camera a MediaRecorder or MediaCodec surface and let the framework pick the internal format). A live view you serve yourself needs frames your own code can touch, encode, and write to a socket — which is a YUV output, read back through an ImageReader. I wrote about the serving half of this previously in a deep-dive on the embedded Ktor server that streams MJPEG over multipart/x-mixed-replace; this is the piece upstream of it, the part that decides what frames that server is even allowed to have.
The docs give the two-surface case explicitly:
"For example, to target a device with
LEGACYhardware level, you could set up two target output surfaces, one usingImageFormat.PRIVATEand another usingImageFormat.YUV_420_888. This is a supported combination while using thePREVIEWsize."
So: record-plus-live-view is a guaranteed combination on the oldest Camera2 hardware in existence. That is genuinely good news, and it is the technical reason a phone-as-camera app can promise both at once without device-specific hacks.
The condition attached to it is the honest part. Both streams are capped at PREVIEW size in the guarantee. If a live viewer is watching, the guaranteed-everywhere recording resolution is preview class — not the sensor's maximum. Many devices will happily exceed that; the docs simply do not promise it, and "many devices" is not a claim you should build a product page on.
What you can do is climb the tiers. The docs describe exactly one escape hatch, and it is a size upgrade rather than a stream-count upgrade:
"
LEGACYhardware level targets the lowest common denominator devices. You can add conditional branching and useRECORDsize for one of the output target surfaces in devices withLIMITEDhardware level, or even increase it toMAXIMUMsize for devices withFULLhardware level."
That single sentence is the whole strategy for supporting a wide device base: same stream count everywhere, better stream size where the device has earned it.
The five tiers, and why "old phone" usually means the bottom two
The Android platform documentation defines the levels reported by android.info.supportedHardwareLevel as follows — quoting, because the differences are easy to get subtly wrong:
-
LEGACY— "These devices expose capabilities to apps through the Camera API2 interfaces that are approximately the same capabilities as those exposed to apps through the Camera API1 interfaces. The legacy frameworks code conceptually translates Camera API2 calls into Camera API1 calls; legacy devices don't support Camera API2 features such as per-frame controls." -
LIMITED— "These devices support some Camera API2 capabilities (but not all) and must use Camera HAL 3.2 or higher." -
FULL— "These devices support all of the major capabilities of Camera API2 and must use Camera HAL 3.2 or higher and Android 5.0 or higher." -
LEVEL_3— "These devices support YUV reprocessing and RAW image capture, along with additional output stream configurations." -
EXTERNAL— "similar toLIMITEDdevices with some exceptions"; used for USB webcams, where some sensor or lens information may be missing and frame rates less stable.
One detail in the LIMITED definition matters more than its brevity suggests: LIMITED devices "can advertise any subset of these capabilities, including none of them." The only thing always present is BACKWARD_COMPATIBLE. So LIMITED is not one tier — it is a range, and two phones both reporting LIMITED can differ substantially.
For our purposes the headline is LEGACY, and specifically that phrase: Camera2 calls are "conceptually translated" into Camera API1 calls. On a LEGACY device you are not really talking to Camera2 — you are talking to a translation layer over the old API wearing the new API's interface. The documentation names the casualty: no per-frame controls.
That has a consequence worth stating, because it explains behaviour people report as a bug. Per-frame control of exposure and gain is how software compensates for a dark room across a long recording. On a LEGACY device that mechanism is not available to any app, because the platform does not expose it. When I wrote about what an old Android phone can and cannot see in the dark, the limits were mostly optical — sensor size, aperture, no IR illuminator. This is the other half of the same ceiling, and it is a software one imposed below the app.
Query it. Do not infer it from the model name.
There is no shortcut here — no "phones after year X are FULL" heuristic worth trusting. The value is a runtime property, and reading it is one line:
val characteristics: CameraCharacteristics = ...
// One of: INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY, _EXTERNAL,
// _LIMITED, _FULL, _3
val hardwareLevel = characteristics.get(
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL)
And the formats and sizes that level actually permits come from the stream configuration map, not from the tier alone:
val config = characteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
val supportedFormats = config.outputFormats
val sizesForFormat = config.getOutputSizes(outputFormat)
The docs note that for preview and recording cases you can query by target class instead and let the framework handle the format: config.getOutputSizes(targetClass).
What happens if you configure a combination outside the guaranteed set? The documentation is careful, and slightly ominous: "Using an unsupported combination of variables may work at a low frame rate; if it does not, it will trigger one of the failure callbacks."
"May work at a low frame rate" is the most important phrase in this entire subject, and it is why device-specific bug reports here are so maddening. Off-table configurations do not reliably fail. They degrade. Your session opens, frames arrive, everything looks fine on your desk — and on someone else's phone the same code silently delivers four frames a second. That is the mechanism behind a whole genre of one-star review: the app didn't crash, it just quietly got worse on hardware the developer never held.
The clause nobody quotes: memory grows linearly
Every multi-stream discussion should end where the docs end, on cost:
"There is a non-trivial performance cost when processing frames, and the cost is multiplied when doing parallel stream or pipeline processing."
"Resources like CPU, GPU, and DSP might be able to take advantage of the framework's reprocessing capabilities, but resources like memory will grow linearly."
Memory grows linearly with streams. And recall that the three-stream guarantee itself is conditioned on "if there isn't too much overhead limiting performance, such as memory, CPU, or thermal constraints."
That word — thermal — is where this stops being an API article. A phone sustaining two camera outputs, a hardware encoder, and an HTTP server is converting a steady wattage into heat inside a plastic shell, usually while plugged in. I have written separately about what that does over days and weeks of continuous 24/7 recording. The relevant point here is that the guarantee has an escape clause, the escape clause is thermal, and thermal is the one variable that gets worse the longer your app succeeds at its job. A stream combination that is legal on a cold phone and legal in the documentation can still be one that phone cannot hold for eleven hours in an unairconditioned room.
The other constraint you are spending is not in these docs at all: one radio. Frames leaving over Wi-Fi contend with everything else on that link, and every extra viewer multiplies the outbound side while the camera side stays fixed — the fan-out problem, and a separate article.
What these docs do not tell you
The guaranteed-combination table above is the LEGACY one. The corresponding tables for LIMITED, FULL, and LEVEL_3 live in the createCaptureSession reference documentation, which the multi-stream guide simply points at: the docs there "describe what is guaranteed to work." I have not reproduced those tables here and will not summarise them from memory.
So there are things I genuinely cannot tell you from these sources:
-
Whether
LIMITEDorFULLguarantee more than three simultaneous streams. The "up to three" statement is made aboutLEGACY. No larger number is stated for any higher tier in the material I am quoting. The only documented improvement is the size upgrade above. -
What
RECORDsize formally means. It appears in the size-upgrade sentence and inTEMPLATE_RECORD, but is not defined in the multi-stream guide. Read theCameraDevicereference rather than trusting an intuition about it. -
What
LEVEL_3's "additional output stream configurations" are, and which HAL or Android versionLEVEL_3andEXTERNALrequire. Stated forLIMITEDandFULL(HAL 3.2+, plus Android 5.0+ forFULL); not for the others.
None of this is a gap in Android's documentation — it is a gap in this page, which is a starting point and says so. The failure mode I am avoiding is the one where a blog post flattens "not stated here" into "does not exist."
The one claim I will make without hedging: for any specific phone, the answer is a runtime query, not a lookup. Two devices from the same year, price bracket and chipset family can land on different tiers. The tier is a property of the vendor's HAL implementation, and it is readable in one line of code.
If you are not building this, only using it
Strip the API names out and here is the part that affects whether an old phone in a window is useful to you:
- Record-only is the cheapest thing you can ask for. One output, full size, guaranteed on every Camera2 device. If you do not need to watch live, do not turn live view on — you are buying quality with the stream you didn't open.
- Live view plus recording is a supported design, not a hack — but expect the live view to be the smaller, lighter stream. That is what the guarantee looks like, and an app being honest about it is following the docs, not cutting a corner.
-
The oldest phones are limited in ways no app can patch. No per-frame exposure control on
LEGACYmeans the low-light ceiling is set below the app. Swapping apps will not move it. - Heat is the real cap on "at the same time." The documented guarantee has a thermal escape clause. Ventilation and placement buy you more sustained capability than any setting in any app.
The engineering summary of a phone-as-camera app is that it is a negotiation with a resource that has published its terms. The terms are unusually clear. They are just in a reference table almost nobody reads.
Further reading from this series
- How an Android phone keeps recording video with the screen off: foreground services, Camera2, and the OS fighting you — the lifecycle layer beneath everything here
- Camera2 API: handling orientation, focus, and exposure in the background — what you must do yourself once there is no Activity
-
How an Android phone serves its own live camera feed over your LAN: an embedded Ktor server deep-dive — where the
YUVstream goes - "Local-only" is not the same as "private": the LAN threat model for a phone-as-camera server — who else can reach that stream
The app: Background Camera RemoteStream records with the screen off, stores footage locally on the device, and serves a live view from a web server running inside the app — no cloud account, no subscription. More at superfunicular.com.
Sources: Use multiple camera streams simultaneously (Android Developers) and Camera version support (Android Open Source Project).
Top comments (0)