前面几章我们分析了UVCCamera的初始化、预览相关的准备工作,本章我们则来看看startPreview的整个流程。按照惯例我们先大概看下调用的时序图:
startPreview
接着之前开启预览过程最终走到AbstractUVCCameraHandler.CameraThread的handleStartPreview方法,继而调用UVCCamera的startPreview,如上图所示,UVCCamera的startPreview最终调用到C层的UVCPreview的startPreview方法。
int UVCPreview::startPreview() {
ENTER();
int result = EXIT_FAILURE;
if (!isRunning()) {
mIsRunning = true;
pthread_mutex_lock(&preview_mutex);
{
if (LIKELY(mPreviewWindow)) {
result = pthread_create(&preview_thread, NULL, preview_thread_func, (void *)this);
}
}
pthread_mutex_unlock(&preview_mutex);
if (UNLIKELY(result != EXIT_SUCCESS)) {
LOGW("UVCCamera::window does not exist/already running/could not create thread etc.");
mIsRunning = false;
pthread_mutex_lock(&preview_mutex);
{
pthread_cond_signal(&preview_sync);
}
pthread_mutex_unlock(&preview_mutex);
}
}
RETURN(result, int);
}
在startPreview方法中通过调用pthread_create起了一个线程,该线程中执行的内容在preview_thread_func中,于是我们继续看preview_thread_func:
void *UVCPreview::preview_thread_func(void *vptr_args) {
int result;
ENTER();
UVCPreview *preview = reinterpret_cast(vptr_args);
if (LIKELY(preview)) {
uvc_stream_ctrl_t ctrl;
result = preview->prepare_preview(&ctrl);
if (LIKELY(!result)) {
preview->do_preview(&ctrl);
}
}
PRE_EXIT();
pthread_exit(NULL);
}
这里我们就关心prepare_preview、do_preview这两个方法。先看prepare_preview:
int UVCPreview::prepare_preview(uvc_stream_ctrl_t *ctrl) {
uvc_error_t result;
ENTER();
result = uvc_get_stream_ctrl_format_size_fps(mDeviceHandle, ctrl,
!requestMode ? UVC_FRAME_FORMAT_YUYV : UVC_FRAME_FORMAT_MJPEG,
requestWidth, requestHeight, requestMinFps, requestMaxFps
);
if (LIKELY(!result)) {
#if LOCAL_DEBUG
uvc_print_stream_ctrl(ctrl, stderr);
#endif
uvc_frame_desc_t *frame_desc;
result = uvc_get_frame_desc(mDeviceHandle, ctrl, &frame_desc);
if (LIKELY(!result)) {
frameWidth = frame_desc->wWidth;
frameHeight = frame_desc->wHeight;
LOGI("frameSize=(%d,%d)@%s", frameWidth, frameHeight, (!requestMode ? "YUYV" : "MJPEG"));
pthread_mutex_lock(&preview_mutex);
if (LIKELY(mPreviewWindow)) {
ANativeWindow_setBuffersGeometry(mPreviewWindow,
frameWidth, frameHeight, previewFormat);
}
pthread_mutex_unlock(&preview_mutex);
} else {
frameWidth = requestWidth;
frameHeight = requestHeight;
}
frameMode = requestMode;
frameBytes = frameWidth * frameHeight * (!requestMode ? 2 : 4);
previewBytes = frameWidth * frameHeight * PREVIEW_PIXEL_BYTES;
} else {
LOGE("c