该系列文章总目录链接与各部分简介: Android Qcom Display学习(零)
显示系统[1] 简单的Surface测试程序
dequeueBuffer函数分析
Android Camera APP preview buffer 总体流程
基于Android12实现简单的Surface测试程序,部分类内的接口发生了变化,但大体上没啥问题。主要实现两类功能
(1)实现显示RGB图的红绿切换,这个主要来源于上面链接中的显示系统[1],以此为基础在Android S上实现
(2)实现Camera Preview的实时预览,基于Camera api1,源码从Camera的测试程序中剥离出的一些操作接口来实现
API_1 CameraService::connect
Camera.cpp /frameworks/av/camera/
CameraBase.cpp /frameworks/av/camera/
CameraService.cpp /frameworks/av/services/camera/libcameraservice/
connectHelper API_1
API_2 CameraService::connectDevice
CameraManager.java /frameworks/base/core/java/android/hardware/camera2/CameraManager.java
ICameraService.aidl /frameworks/av/camera/aidl/android/hardware/
CameraService.cpp /frameworks/av/services/camera/libcameraservice/
connectHelper API_2
device1 + cameraClient /device3 + camera2Client API1 对应 HAL 1/3
(3)待补充:实现Camera Preview的方式采用api2和v4l2,后续再看单独拿出来研究
API2 可以基于/frameworks/av/camera/tests/CameraBinderTests.cpp的示例去看,
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("media.camera"));
sp<hardware::ICameraService> service = interface_cast<hardware::ICameraService>(binder);
res = service->connectDevice(callbacks, cameraId, packageName,
{}, hardware::ICameraService::USE_CALLING_UID, /*oomScoreOffset*/ 0,
/*targetSdkVersion*/__ANDROID_API_FUTURE__, /*out*/&device);
上图来源自链接Android Camera APP preview buffer 总体流程,非常推荐
IGraphicBufferProducer(生产者) → 提供图像数据(surface)
↑↓
BufferQueue(buffer队列)
↑↓
IGraphicBufferConsumer(消费者) → 合成图像数据(surfacefinger)
Camera::setPreviewTarget
Camera2Client::setPreviewWindow //window = new surface surface继承自ANativeWindow
//class Surface : public ANativeObjectBase<ANativeWindow, Surface, RefBase>
StreamingProcessor::setPreviewWindow //mPreviewWindow
Camera::startPreview
Camera2Client::startPreview
Camera2Client::updatePreviewStream
StreamingProcessor::updatePreviewStream // mPreviewWindow
Camera3Device::createStream // new Camera3OutputStream HAL填充
Camera3Device::configureStreamsLocked //configure_stream
Camera3OutputStream::configureConsumerQueueLocked
//根据当前stream设置的buffer属性,将这些属性值通过ANativeWindow这个接口传递给consumer
StreamingProcessor::startStream
以上窗口准备好后并设置后属性,在后续preview的线程中会一直dequeueBuffers(向BufferQueue申请一块内存用于绘制图像)
和queueBuffer(绘制好的buffer放入BufferQueue队列中并通知回调消费者去使用这块buffer)
1.Android.bp
cc_binary {
name: "surfacetest",
srcs: ["main.cpp"],
shared_libs: [
"libutils",
"libandroidfw",
"libcutils",
"libbinder",
"libui",
"libgui",
"liblog",
"libcamera_client",
"libmedia"
],
header_libs: [
"libsurfaceflinger_headers",
]
}
2.surfacetest
#include <cutils/memory.h>
#include <utils/Log.h>
#include <utils/SystemClock.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <android/native_window.h>
#include <system/camera.h>
#include <camera/Camera.h>
#include <camera/CameraParameters2.h>
#include <hardware/hardware.h>
#include <hardware/camera_common.h>
#include <hardware/hwcomposer_defs.h>
using namespace android;
sp<Camera> mCamera;
CameraParameters2 mParams;
String16 packageName("jerry");
sp<IGraphicBufferProducer> gbp;
int previewWidth, previewHeight;
void android_memset16(unsigned short * _ptr, unsigned short val, unsigned count)
{
unsigned short * ptr = _ptr;
count >>= 1;
while(count--)
*ptr++ = val;
}
int main()
{
// set up the thread-pool
sp<ProcessState> proc(ProcessState::self());
ProcessState::self()->startThreadPool();
// create a client to surfaceflinger SurfaceComposerClient.cpp
sp<SurfaceComposerClient> client = new SurfaceComposerClient();
// surface client get display size
sp<IBinder> displayToken = client->getInternalDisplayToken();
if(nullptr == displayToken)
ALOGE("jerry failed to get the displayToken");
ui::DisplayMode displayinfo = {};
client->getActiveDisplayMode(displayToken, &displayinfo);
ALOGD("jerry get the displayinfo w = %d, h= %d",displayinfo.resolution.getWidth(), displayinfo.resolution.getHeight());
// surface client createsurface different size and format
#if 0
sp<SurfaceControl> surfaceControl = client->createSurface(String8("resize"),
1080, 2160, PIXEL_FORMAT_RGB_565, 0);
#else
sp<SurfaceControl> surfaceControl = client->createSurface(String8("resize"),
720, 1080, HAL_PIXEL_FORMAT_YCrCb_420_SP, 0);
#endif
// surface use to (1)draw full color or (2)camera preview buffer
sp<Surface> surface = surfaceControl->getSurface();
#if 0
//(1)ANativWindow draw full color the hegith*weight RED+GREEN
ANativeWindow_Buffer outBuffer;
surface->lock(&outBuffer, NULL);
ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
android_memset16((uint16_t*)outBuffer.bits, 0xF800, bpr*outBuffer.height);//RGB mask RED
surface->unlockAndPost();
sleep(3);
surface->lock(&outBuffer, NULL);
android_memset16((uint16_t*)outBuffer.bits, 0x07E0, bpr*outBuffer.height);//RGB mask Green
surface->unlockAndPost();
#endif
//(2)surface setPreviewTarget to startPreview on Screen
//frameworks/av/camera/tests/CameraZSLTests.cpp
//frameworks/av/camera/Camera.cpp
//sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName,
// int clientUid, int clientPid, int targetSdkVersion)
mCamera = Camera::connect(0, packageName, Camera::USE_CALLING_UID,
Camera::USE_CALLING_PID, 30);
// camera api get/set parameters
mParams = mCamera->getParameters();
mParams.setPreviewFormat("yuv420sp");
//mParams.getPreviewSize(&previewWidth, &previewHeight);
//mParams.setPreviewFrameRate(30);
//mParams.setPreviewSize(previewWidth, previewHeight);
//mCamera->setParameters(mParams.flatten());
mCamera->sendCommand(CAMERA_CMD_SET_DISPLAY_ORIENTATION, 270, 0);
// surface setPosition/apply
SurfaceComposerClient::Transaction{}.setPosition(surfaceControl, 200, 200).apply();
// surface pass the buffered IGraphicBufferProducer to the camera service
gbp = surface->getIGraphicBufferProducer();
mCamera->setPreviewTarget(gbp);
mCamera->startPreview();
IPCThreadState::self()->joinThreadPool();
return 0;
}