camera open之後,可以調用startPreview函數進行preview,今天主要講解Camera HAL層startPreview的follow。
先判定camera是否打開,沒有打開則直接返回。
status_t CameraHardware:: startPreview()
{
status_t ret = NO_ERROR;
int PreviewFrameSize;
if (mCameraOpened == false)
return UNKNOWN_ERROR;
HAL層有提供函數判定Camera是否打開:
bool CameraHardware::isCameraOpened()
{
return mCameraOpened;
};
camera打開後,先判定是否已經在preview,如果已經preview,直接返回
ALOGI("startPreview");
Mutex::Autolock lock(mPreviewLock);
if (mPreviewEnabled) {
ALOGE("Preview already running");
return ALREADY_EXISTS;
}
根據preview的格式,計算previewFramesize:
if (strcmp(mParameters.getPreviewFormat(), CameraParameters::PIXEL_FORMAT_YUV420SP) == 0 ||
strcmp(mParameters.getPreviewFormat(), CameraParameters::PIXEL_FORMAT_YUV420P) == 0 ) {
// YUV420SP
mPreviewFrameSize = mWidth * mHeight * 3 / 2;
} else {
// YUV422
mPreviewFrameSize = mWidth * mHeight * 2;
}
最後進行JpegDecoder初始化以及開啓decoder和preview thread
mJpegDecoder.Init();
usleep(1000 * 1000 );
mPreviewEnabled = true;
mDecodeThread = new DecodeThread(this);
mPreviewThread = new PreviewThread(this);
在CameraHardWare.h中定義DecodeThread:
class DecodeThread : public Thread {
CameraHardware* mHal;
public:
DecodeThread(CameraHardware* hal) :
#ifdef SINGLE_PROCESS
// In single process mode this thread needs to be a java thread,
// since we won't be calling through the binder.
Thread(true),
#else
Thread(false),
#endif
mHal(hal) {}
virtual void onFirstRef() {
run("CameraDecodeThread", PRIORITY_URGENT_DISPLAY);
}
virtual bool threadLoop() {
mHal->decodeThread();
// loop until we need to quit
return true;
}
};
可以看到,此線程一直在執行mHal->decodeThread();,即調用CameraHardware::decodeThread()
在CameraHardWare.h中定義PreviewThread:
class PreviewThread : public Thread {
CameraHardware* mHal;
public:
PreviewThread(CameraHardware* hal) :
#ifdef SINGLE_PROCESS
// In single process mode this thread needs to be a java thread,
// since we won't be calling through the binder.
Thread(true),
#else
Thread(false),
#endif
mHal(hal) {}
virtual void onFirstRef() {
run("CameraPreviewThread", PRIORITY_URGENT_DISPLAY);
}
virtual bool threadLoop() {
mHal->previewThread();
// loop until we need to quit
return true;
}
};
同decodeThread,最終調用到CameraHardware::previewThread()。
int CameraHardware::decodeThread()
{
if (mPreviewEnabled && mImageFormat == V4L2_PIX_FMT_MJPEG
&&( mANativeWindow != NULL || mRecordingEnabled)) {
void* buf = mJpegDecoder.GetEmptyYuvBuffer();
if (buf == NULL)
return NO_ERROR;
char *rawFramePointer = mCamera->GrabRawFrame();
if (rawFramePointer) {
if (mJpegDecoder.Decode(mPreviewBufs, rawFramePointer, mCamera->videoIn->buf.bytesused, buf))
mJpegDecoder.SetYuvBufferState(buf, false);
} else if (!rawFramePointer) {
ALOGE("Got EMPTY raw data !!!!!");
usleep(1000 * 50 );
return UNKNOWN_ERROR;
}
#if DUMP_JPEG
char fname[50];
FILE *file;
static int nCapture = 0;
sprintf(fname, "/var/tmp/media/capture-%06u.jpg", nCapture);
nCapture++;
if (nCapture >= 5)
nCapture = 0;
file = fopen(fname, "wb");
if (file != NULL) {
fwrite(rawFramePointer, mCamera->videoIn->buf.bytesused, 1, file);
fclose(file);
}
#endif
mCamera->ProcessRawFrameDone();
}
return NO_ERROR;
}
主要是對camera獲取的buffer數據進行decode,可以通過DUMP_JPEG查看preview的圖片。
同樣在previewThread中可以打印出當前preview的fps:
#if COUNT_FPS
static time_t start, end;
static int totalframe = 0;
if (totalframe == 0)
time(&start);
time(&end);
totalframe ++;
if (difftime (end,start) >= 1) {
ALOGI("FPS(%d, %d) ::::::::::::::::: %d", mWidth, mHeight, totalframe);
totalframe = 0;
}
#endif