I made a little investigation on topic. This presentation (from p.277, Chinese) helped a lot.
Camera preview call chain
As others mentioned, you can get a buffer using a Camera.setPreviewCallback
method.
Here's how it happens there (a verbose version):
- User calls
Camera.startPreview()
which is a native function.
android_hardware_Camera_startPreview
calls startPreview
method of C++ Camera
class.
Camera
calls a startPreview
method of ICamera
interface
ICamera
makes an IPC
call to remote client.
- It calls a
setCameraMode
method of CameraService
class.
CameraService
sets a window to display a preview and calls a startPreview
method of CameraHardwareInterface
class.
- The latter tries to call a
start_preview
method on particular camera_device_t
device.
I didn't looked up further but it should perform a call to the driver.
- When image arrives,
dataCallback
of CameraService
is invoked.
- It passes data to
handlePreviewData
method of client.
- Client either copies the buffer or sends it directly to the
ICameraClient
.
ICameraClient
sends it over IPC
to the Camera
.
Camera
calls a registered listener and passes buffer to JNI
.
- It invokes a callback in Java class. If user provided a buffer with
Camera.addCallbackBuffer
then it copies to the buffer first.
- Finally Java class
Camera
handles the message and invokes a onPreviewFrame
method of Camera.PreviewCallback
.
As you can see 2 IPC
calls were invoked and buffer was copied at least twice on steps 10, 11. First instance of raw buffer which is returned by camera_device_t
is hosted in another process and you cannot access it due to security checks in CameraService
.
Preview surface
However, when you set a preview surface using either Camera.setPreviewTexture
or Camera.setPreviewDisplay
it is be passed directly to the camera device and refreshed in realtime without participation of all the chain above. As it's documentation says:
Handle onto a raw buffer that is being managed by the screen compositor.
Java class Surface
has a method to retrieve it's contents:
public static native Bitmap screenshot(int width, int height, int minLayer, int maxLayer);
But this API is hidden. See i.e. this question for a way to use it.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…