引言

上一节分析了Camera2 Hal3的初始化过程。这一节来分析写预览过程,预览过程我将以Camera2Client::startPreview为入口分析这个过程。

时序图

类图

创建流,启动流

startPreview过程会先调用mStreamingProcessor->updatePreviewStream来创建Camera3OutputStream

status_t Camera2Client::startPreview() {...SharedParameters::Lock l(mParameters);//上一节的分析我们知道了l.mParameters.initialize实际上就是调用Parameters::initialize,只不过给它加了一把Mutex而已//所以这里l.mParameters的调用也是返回Parameters对象,同时给它加了一把Mutex锁return startPreviewL(l.mParameters, false);}status_t Camera2Client::startPreviewL(Parameters &params, bool restart) {...res = mStreamingProcessor->updatePreviewStream(params);....}status_t StreamingProcessor::updatePreviewStream(const Parameters &params) {sp<CameraDeviceBase> device = mDevice.promote();//上一节的分析我们知道了mDevice就是指向Camera3Deviceif (mPreviewStreamId == NO_STREAM) {        res = device->createStream(mPreviewWindow,                params.previewWidth, params.previewHeight,                CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, &mPreviewStreamId);}}status_t Camera3Device::createStream(sp<ANativeWindow> consumer,        uint32_t width, uint32_t height, int format, int *id) {        newStream = new Camera3OutputStream(mNextStreamId, consumer,width, height, format);        mOutputStreams.add(mNextStreamId, newStream);}Camera3OutputStream::Camera3OutputStream(int id, sp<ANativeWindow> consumer,uint32_t width, uint32_t height, int format) :        Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, width, height, /*maxSize*/0, format),        mConsumer(consumer),        mTransform(0),        mTraceFirstBuffer(true) {        ......}

在创建Camera3OutputStream的过程中有一个变量要注意一下mPreviewWindow,来看看mPreviewWindow是什么东西。
在初始化camera的时候会调用Camera2Client::setPreviewTarget把绘图相关接口IGraphicBufferProducer传递过来,创建Surface,我们知道Surface相当于一块画布,不同画布的绘图最终会通过SurfaceFlinger去指导合成,最后输出在屏幕上面。

status_t Camera2Client::setPreviewTarget( const sp<IGraphicBufferProducer>& bufferProducer) {    sp<IBinder> binder;    sp<ANativeWindow> window;    if (bufferProducer != 0) {        binder = bufferProducer->asBinder();        // Using controlledByApp flag to ensure that the buffer queue remains in        // async mode for the old camera API, where many applications depend        // on that behavior.        window = new Surface(bufferProducer, /*controlledByApp*/ true);    }    return setPreviewWindowL(binder, window);}status_t Camera2Client::setPreviewWindowL(const sp<IBinder>& binder,sp<ANativeWindow> window) {...res = mStreamingProcessor->setPreviewWindow(window);}status_t StreamingProcessor::setPreviewWindow(sp<ANativeWindow> window) {...    mPreviewWindow = window;}

可以看出mPreviewWindow就是相当于刚才创建的Surface。
继续分析startPreviewL

status_t Camera2Client::startPreviewL(Parameters &params, bool restart) {...res = mStreamingProcessor->updatePreviewStream(params);...outputStreams.push(getPreviewStreamId());//一个Camera3OutputStream对应一个idres = mStreamingProcessor->updatePreviewRequest(params);...res = mStreamingProcessor->startStream(StreamingProcessor::PREVIEW,                outputStreams);}status_t StreamingProcessor::updatePreviewRequest(const Parameters &params) {sp<CameraDeviceBase> device = mDevice.promote();res = device->createDefaultRequest(CAMERA3_TEMPLATE_PREVIEW,&mPreviewRequest);res = mPreviewRequest.update(ANDROID_REQUEST_ID,&mPreviewRequestId, 1);//这个mPreviewRequest下面就会用到}status_t Camera3Device::createDefaultRequest(int templateId,CameraMetadata *request) {        const camera_metadata_t *rawRequest;        rawRequest = mHal3Device->ops->construct_default_request_settings(mHal3Device, templateId);//hal层去填充默认设置        *request = rawRequest;//上一节分析以及指导CameraMetadata维护的就是camera_metadata_t }

继续分析startPreviewL调用的mStreamingProcessor->startStream

status_t StreamingProcessor::startStream(StreamType type,        const Vector<int32_t> &outputStreams) {    CameraMetadata &request = (type == PREVIEW) ?//这里type是PREVIEW所以会使用刚才赋值的mPreviewRequest             mPreviewRequest : mRecordingRequest;    res = request.update(        ANDROID_REQUEST_OUTPUT_STREAMS,        outputStreams);//把刚才创建Camera3OutputStream对应的id保存到这个request里面    ...    res = device->setStreamingRequest(request);}status_t Camera3Device::setStreamingRequest(const CameraMetadata &request,int64_t* /*lastFrameNumber*/) {    List<const CameraMetadata> requests;    requests.push_back(request);    return setStreamingRequestList(requests, /*lastFrameNumber*/NULL);}status_t Camera3Device::setStreamingRequestList(const List<const CameraMetadata> &requests,int64_t *lastFrameNumber) {    return submitRequestsHelper(requests, /*repeating*/true, lastFrameNumber);}status_t Camera3Device::submitRequestsHelper(        const List<const CameraMetadata> &requests, bool repeating,        /*out*/        int64_t *lastFrameNumber) {    RequestList requestList;    res = convertMetadataListToRequestListLocked(requests, /*out*/&requestList);//利用CameraMetadata创建CaptureRequest    if (repeating) {//第二个参数是true        res = mRequestThread->setRepeatingRequests(requestList, lastFrameNumber);    } }status_t Camera3Device::convertMetadataListToRequestListLocked(...){for (List<const CameraMetadata>::const_iterator it = metadataList.begin();it != metadataList.end(); ++it){sp<CaptureRequest> newRequest = setUpRequestLocked(*it);}}sp<Camera3Device::CaptureRequest> Camera3Device::setUpRequestLocked(...){sp<CaptureRequest> newRequest = createCaptureRequest(request);}sp<Camera3Device::CaptureRequest> Camera3Device::createCaptureRequest(...){camera_metadata_entry_t streams =  //获取到刚才保存的id            newRequest->mSettings.find(ANDROID_REQUEST_OUTPUT_STREAMS);for (size_t i = 0; i < streams.count; i++) {int idx = mOutputStreams.indexOfKey(streams.data.i32[i]);sp<Camera3OutputStreamInterface> stream =mOutputStreams.editValueAt(idx);newRequest->mOutputStreams.push(stream);//得到outputstream的对象,保存到CaptureRequest中}}status_t Camera3Device::RequestThread::setRepeatingRequests(const RequestList &requests,/*out*/ int64_t *lastFrameNumber) {    mRepeatingRequests.clear();    mRepeatingRequests.insert(mRepeatingRequests.begin(),requests.begin(), requests.end());    ....}

到了这里,mRepeatingRequests会被插入一个RequestList,mRepeatingRequests如果不为空的话,RequestThread会不断的触发预览事件。

threadLoop和帧数据回调

Camera3Device::RequestThread::threadLoop是一个处理Request的线程,得到request后它会去调用hal接口获取到图像数据,然后hal层会回调Camera3Device::processCaptureResult接口,通过层层调用把图像数据送给显示系统显示图像。

sp<Camera3Device::CaptureRequest> Camera3Device::RequestThread::waitForNextRequest() {    while (mRequestQueue.empty()) {        if (!mRepeatingRequests.empty()) {//从上面知道这里不是空的,mRepeatingRequests也没有擦除,所以一直进来这里            const RequestList &requests = mRepeatingRequests;            RequestList::const_iterator firstRequest =requests.begin();            nextRequest = *firstRequest;            mRequestQueue.insert(mRequestQueue.end(), ++firstRequest, requests.end());        break;//直接退出循环了,无需等待        }        res = mRequestSignal.waitRelative(mRequestLock, kRequestTimeout);        ......    }    ......    return nextRequest;}bool Camera3Device::RequestThread::threadLoop() {sp<CaptureRequest> nextRequest = waitForNextRequest();camera3_capture_request_t request = camera3_capture_request_t();//构建一个camera3_capture_request_t ....outputBuffers.insertAt(camera3_stream_buffer_t(), 0,            nextRequest->mOutputStreams.size());//先插入一个camera3_stream_buffer_t    request.output_buffers = outputBuffers.array();//保存到request中    for (size_t i = 0; i < nextRequest->mOutputStreams.size(); i++) {    res = nextRequest->mOutputStreams.editItemAt(i)->//前面已经知道了这里获取到的item是Camera3OutputStream                getBuffer(&outputBuffers.editItemAt(i));//调用Camera3Stream::returnBuffer去填充camera3_stream_buffer    }    ....    res = mHal3Device->ops->process_capture_request(mHal3Device, &request);//调用hal去获取一帧数据}status_t Camera3Stream::getBuffer(camera3_stream_buffer *buffer) { res = getBufferLocked(buffer);}status_t Camera3OutputStream::getBufferLocked(camera3_stream_buffer *buffer) {ANativeWindowBuffer* anb;sp<ANativeWindow> currentConsumer = mConsumer;//前面创建的surfaceres = currentConsumer->dequeueBuffer(currentConsumer.get(), &anb, &fenceFd);//出队buffer    handoutBufferLocked(*buffer, &(anb->handle), /*acquireFence*/fenceFd,    //填充camera3_stream_buffer                         /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK, /*output*/true);}void Camera3IOStreamBase::handoutBufferLocked(camera3_stream_buffer &buffer,buffer_handle_t *handle,int acquireFence,                                              int releaseFence, camera3_buffer_status_t status,bool output) {    buffer.stream = this;//设置回调    buffer.buffer = handle;    buffer.acquire_fence = acquireFence;    buffer.release_fence = releaseFence;    buffer.status = status;    ...}

(参考类图)camera3_stream_buffer的stream类型是camera3_stream_t *,所以buffer.stream = this让camera3_stream_buffer的stream指向了Camera3OutputStream的父类camera3_stream,通过类图可以知道camera3_stream_buffer是camera3_capture_request的成员,所以camera3_capture_request可以通过camera3_stream_buffer的stream成员拿到camera3_stream的地址,而camera3_stream又是Camera3OutputStream的父类,所以camera3_capture_request可以访问到刚才创建的Camera3OutputStream。这一点非常重要,因为下面的帧数据回调就是以这个为基础的。
填充完一个camera3_capture_request后,threadLoop回调用hal接口mHal3Device->ops->process_capture_request(mHal3Device, &request)去hal层取图像。我这里是取一帧图像。

//hal层camera3_device_ops_t Camera::sOps = {....configure_streams                  = Camera::configureStreams,    .process_capture_request            = Camera::processCaptureRequest,    ...}int Camera::processCaptureRequest(camera3_capture_request_t *request) { const V4l2Device::VBuffer *frame = NULL; Vector<camera3_stream_buffer> buffers;    if(request->input_buffer) {//我这里不关心输入buffer,所以我这里直接设置release_fence为-1        request->input_buffer->release_fence = -1;    }    BENCHMARK_SECTION("Lock/Read") {        frame = mDev->readLock();//其实就是调用ioctl(mFd, VIDIOC_DQBUF, &bufInfo)取出一片buffer    }    for(size_t i = 0; i < request->num_output_buffers; ++i) {//我这里只有一个buffer    const camera3_stream_buffer &srcBuf = request->output_buffers[i];//取出刚才所说的那个camera3_stream_buffer    sp<Fence> acquireFence = new Fence(srcBuf.acquire_fence);//创建一个Fence,Fence是显示系统的一种同步机制        e = acquireFence->wait(1000); /* FIXME: magic number */   //等待一下,返回的时候说明刚才调用dequeueBuffer出队的buffer真正可用了        if(e == NO_ERROR) {            const Rect rect((int)srcBuf.stream->width, (int)srcBuf.stream->height);            e = GraphicBufferMapper::get().lock(*srcBuf.buffer, GRALLOC_USAGE_SW_WRITE_OFTEN, rect, (void **)&buf);//锁住buffer            switch(srcBuf.stream->format) {//这个是在configure_streams的时候指定的            case HAL_PIXEL_FORMAT_RGB_565:{//我这边指定的是rgb565            //把一帧图像数据保存到buf里面            }            }        }for(size_t i = 0; i < request->num_output_buffers; ++i) {//只有一个output bufferconst camera3_stream_buffer &srcBuf = request->output_buffers[i];GraphicBufferMapper::get().unlock(*srcBuf.buffer);//解锁bufferbuffers.push_back(srcBuf);//保存到Vectorbuffers.editTop().acquire_fence = -1;//返回给framework的时候需要指定为-1,表明无需等待了,直接就可以用这个帧数据了buffers.editTop().release_fence = -1;buffers.editTop().status = CAMERA3_BUFFER_STATUS_OK;}processCaptureResult(request->frame_number, result, buffers);    }}void Camera::processCaptureResult(uint32_t frameNumber, const camera_metadata_t *result, const Vector<camera3_stream_buffer> &buffers) {    camera3_capture_result captureResult;    captureResult.frame_number = frameNumber;    captureResult.result = result;    captureResult.num_output_buffers = buffers.size();    captureResult.output_buffers = buffers.array();    captureResult.input_buffer = NULL;    captureResult.partial_result = 0;    mCallbackOps->process_capture_result(mCallbackOps, &captureResult);//把数据送回hal层}

这里的process_capture_result在Camera3Device的构造函数中指定好了,camera3_callback_ops::process_capture_result = &sProcessCaptureResult,所以这里会回调Camera3Device的sProcessCaptureResult函数,进而调用Camera3Device::processCaptureResult函数。

void Camera3Device::processCaptureResult(const camera3_capture_result *result) {for (size_t i = 0; i < result->num_output_buffers; i++){//咦,这个result->output_buffers[i].stream)不就是前面指定为Camera3IOStreamBase了吗//所以这个把Camera3IOStreamBase指针强转成它的父类指针Camera3StreamCamera3Stream *stream =Camera3Stream::cast(result->output_buffers[i].stream);res = stream->returnBuffer(result->output_buffers[i], timestamp);....}}status_t Camera3Stream::returnBuffer(const camera3_stream_buffer &buffer,nsecs_t timestamp) {     status_t res = returnBufferLocked(buffer, timestamp);}status_t Camera3OutputStream::returnBufferLocked( const camera3_stream_buffer &buffer,nsecs_t timestamp) { status_t res = returnAnyBufferLocked(buffer, timestamp, /*output*/true);}status_t Camera3IOStreamBase::returnAnyBufferLocked(const camera3_stream_buffer &buffer,nsecs_t timestamp,bool output) {    sp<Fence> releaseFence;    res = returnBufferCheckedLocked(buffer, timestamp, output,                                    &releaseFence);}status_t Camera3OutputStream::returnBufferCheckedLocked(            const camera3_stream_buffer &buffer,            nsecs_t timestamp,            bool output,            /*out*/            sp<Fence> *releaseFenceOut) {        .....        res = currentConsumer->queueBuffer(currentConsumer.get(),//送帧图像给显示系统,然后会显示在屏幕上面                container_of(buffer.buffer, ANativeWindowBuffer, handle),                anwReleaseFence);}

更多相关文章

  1. android GoogleMap定位(一)
  2. 如何控制android中ImageView的位置
  3. Android(安卓)Studio 串口jni开发
  4. 如何创建一个android的react-native组件(一)
  5. MediaRecorder创建Surface流程学习
  6. Android(安卓)ToolBar 解析与应用(一)创建toolbar
  7. 计算Android(安卓)App占用的各种空间大小
  8. android基础知识06:intent和intentfilter
  9. Android(安卓)8.0以上 竖屏到横屏 返回时出现错误的解决办法

随机推荐

  1. android中完全退出应用程序的方法
  2. Android(安卓)app项目开发步骤总结
  3. Android(安卓)2017 开源库 (持续更新)
  4. [CyanogenMOD移植教程]第二章:android 源
  5. Android(安卓)View、ViewGroup
  6. gradle常用命令和查看错误
  7. 简述关于TextView的属性使用
  8. 玩转Android---组件篇---数据存储之SQLit
  9. android横竖屏和隐藏标题栏、状态栏总结
  10. Ubuntu下android studio如何使用ndk-buil