How to resolve Android Camera Preview on Emulator show white and black square only?

来源:互联网 发布:mac里的影片怎么删除 编辑:程序博客网 时间:2024/05/18 04:01

    在初次接触android的时候就注意到通过模拟器,相机预览的时候只能显示黑白电影。这些天总算有点空闲时间了,决定研究下这个。 关于android camera的构造不再说了,模拟器上使用用的是一个虚拟的Camera-----FakeCamera这个大家应该都知道。
    首先初略的了解一下camera preview图像显示的原理。Camera application 初始化的时候会创建一个surfaceview,从camera device 接收到的数据就可以通过它显示在屏幕上。内部处理的流程是很复杂的,下面我只给出一个从初始化到绘图函数调用的流程。
    Surface初始化:
    Android_view_surface:: Surface_init-->SurfaceComposerClient::CreateSurface-->
    SurfaceFlinger:: createSurface-->Android_view_surface:: setSurface


    Camera数据缓冲区Heap初始化:
    CameraHardwareStub::initHeapLocked-->new MemoryBase-->new FakeCamera


    Heap缓冲区注册到surface:
    Android_hardware_camera:: android_hardware_Camera_setPreviewDisplay-->
    Camera:: setPreviewDisplay-->CameraService::Client::setPreviewDisplay-->
    CameraService::Client::registerPreviewBuffers-->LayerBuffer::registerBuffers


    FakeCamera 原始数据的传递与绘图:
    CameraHardwareStub::previewThread-->CameraService::Client::previewCallback-->
    CameraService::Client::postPreviewFrame-->ISurface:: postBuffer-->
    LayerBuffer::postBuffer--> LayerBuffer::BufferSource::postBuffer-->
    LayerBase::invalidate-->SurfaceFlinger::signalEvent-->SurfaceFlinger::threadLoop-->
    SurfaceFlinger::handleRepaint-->LayerBase::draw-->
    LayerBuffer::BufferSource::onDraw-->LayerBase::drawWithOpenGL

    FakeCamera得到数据为Yuv422, 原以为是库里某个地方绘图的时候出问题,但LayerBuffer::OnDraw 往下走很复杂的,也看不出有什么问题。但要解决预览为黑白电影的问题应该就比较简单了。只要我们将YUV数据转换为RGB丢给cameraService就可以了。用以下的代码替代  ccrgb16toyuv_wo_colorkey。

    int32_t ccrgb16toyuv_wo_colorkey(uint8_t *rgb16,uint8_t *yuv422,uint32_t *param,uint8_t *table[])
    {
        int32_t width_dst = param[0];
       int32_t height_dst = param[1];
        memcpy(yuv422, rgb16, width_dst*height_dst*2);

    }
   CameraService中改动:

    status_t CameraService::Client::registerPreviewBuffers()
   {
        ......
       ISurface::BufferHeap buffers(w, h, w, h,
                                                  PIXEL_FORMAT_RGB_565,
                                                 //PIXEL_FORMAT_YCbCr_420_SP,
                                                  transform,
                                                  0,
                                                  mHardware->getPreviewHeap());

        status_t ret = mSurface->registerBuffers(buffers);
       if (ret != NO_ERROR) {
           LOGE("registerBuffers failed with status %d", ret);

        }
       return ret;
    }

    用PIXEL_FORMAT_RGB_565替换PIXEL_FORMAT_YCbCr_420_SP。这样就可以了。不妨动手试一试吧,看看是不是预览视频变为彩色的了。
对于实际的camera device出来的数据如果是yuv的话,也可以通过算法将yuv转换为RGB,这样做并不会导致转换效率降低,因为即使将yuv得数据丢到surfaceflinger中,最终还是会转换为BMP。

原创粉丝点击