在初次接觸android的時候就注意到通過模擬器,相機(jī)預(yù)覽的時候只能顯示黑白電影。這些天總算有點空閑時間了,決定研究下這個。 關(guān)于android camera的構(gòu)造不再說了,模擬器上使用用的是一個虛擬的Camera-----FakeCamera這個大家應(yīng)該都知道。 首先初略的了解一下camera preview圖像顯示的原理。Camera application 初始化的時候會創(chuàng)建一個surfaceview,從camera device 接收到的數(shù)據(jù)就可以通過它顯示在屏幕上。內(nèi)部處理的流程是很復(fù)雜的,下面我只給出一個從初始化到繪圖函數(shù)調(diào)用的流程。 Surface初始化: Android_view_surface:: Surface_init-->SurfaceComposerClient::CreateSurface--> SurfaceFlinger:: createSurface-->Android_view_surface:: setSurface Camera數(shù)據(jù)緩沖區(qū)Heap初始化: CameraHardwareStub::initHeapLocked-->new MemoryBase-->new FakeCamera Heap緩沖區(qū)注冊到surface: Android_hardware_camera:: android_hardware_Camera_setPreviewDisplay--> Camera:: setPreviewDisplay-->CameraService::Client::setPreviewDisplay--> CameraService::Client::registerPreviewBuffers-->LayerBuffer::registerBuffers FakeCamera 原始數(shù)據(jù)的傳遞與繪圖: 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得到數(shù)據(jù)為Yuv422, 原以為是庫里某個地方繪圖的時候出問題,但LayerBuffer::OnDraw 往下走很復(fù)雜的: t.format == GGL_PIXEL_FORMAT_YCbCr_420_SP) { // just show the Y plane of YUV buffers。 不明白為什么google這么做。。。。。 但要解決預(yù)覽為黑白電影的問題應(yīng)該就比較簡單了。只要我們將YUV數(shù)據(jù)轉(zhuǎn)換為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。這樣就可以了。不妨動手試一試吧,看看是不是預(yù)覽視頻變?yōu)椴噬牧恕? 對于實際的camera device出來的數(shù)據(jù)如果是yuv的話,也可以通過算法將yuv轉(zhuǎn)換為RGB,這樣做并不會導(dǎo)致轉(zhuǎn)換效率降低,因為即使將yuv得數(shù)據(jù)丟到surfaceflinger中,最終還是會轉(zhuǎn)換為BMp。 ----AlbertChen |
|