I am working with the camera2 API in android and am trying to understand this code I am using. Part of the code goes like this:
previewReader = ImageReader.newInstance(previewSize.getWidth(), previewSize.getHeight(),
ImageFormat.YUV_420_888, 4);
previewReader.setOnImageAvailableListener(imageListener, backgroundHandler);
// This adds another output surface but not sure where this surface comes from..
previewRequestBuilder.addTarget(previewReader.getSurface());
imageListener
is an object from another class that implements android.media.ImageReader.OnImageAvailableListener
and backgroundHandler
is just a background thread. I am not including code for these two or previewRequestBuilder
as they do not seem to be important for understanding my question.
I have searched extensively but it just seems like some magic happens and previewReader
finds some surface somewhere, somehow. According to the documentation, what getSurface()
does is to:
Get a
Surface
that can be used to produceImage
for thisImageReader
Can anyone explain where it gets this?
That Surface
belongs to the ImageReader
; it was created in the native equivalent of the ImageReader's
constructor, and is (effectively) an ImageReader
private member, with a getter.
Here is the line in the native constructor that sets up the IGraphicBufferProducer
(gbProducer
), which is basically the native equivalent of a Surface
.
Here is where you can see that the native code uses that same member to form the return value from getSurface()/nativeGetSurface()
(you may have to trace through the code a bit, but it's all there).
So that's the literal answer to your question. But maybe you were asking because it isn't clear why the camera doesn't create the Surface
, and force you to give it to the ImageReader
, instead: A Surface
is a complex object (actually, a buffer queue), and shouldn't be thought of as a simple, pre-allocated bitmap. At the time the capture takes place, the camera pipeline will communicate with its output Surfaces
, and set up the correct dimensions and color planes and so forth. (Note that you can add multiple targets via addTarget()
; the camera can use each of them.) All the camera needs to know is where it's going to send its output; it doesn't need to create the output Surface
itself.