在初次接觸
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
往下走很複雜的:
t.format == GGL_PIXEL_FORMAT_YCbCr_420_SP) {
// just show the Y plane of YUV buffers。 不明白為什麼google這麼做。。。。。
但要解決預覽為黑白電影的問題應該就比較簡單了。只要我們將
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
。