android6.0原始碼分析之Camera API2.0下的Preview(預覽)流程分析
本文將基於android6.0的原始碼,對Camera API2.0下Camera的preview的流程進行分析。在文章android6.0原始碼分析之Camera API2.0下的初始化流程分析中,已經對Camera2內建應用的Open即初始化流程進行了詳細的分析,而在open過程中,定義了一個PreviewCallback,當時並未詳細分析,即Open過程中,會自動開啟預覽過程,即會呼叫OneCameraImpl的startPreview方法,它是捕獲和繪製螢幕預覽幀的開始,預覽才會真正開始提供一個表面。
Camera2文章分析目錄:
android6.0原始碼分析之Camera API2.0簡介
android6.0原始碼分析之Camera2 HAL分析
android6.0原始碼分析之Camera API2.0下的初始化流程分析
android6.0原始碼分析之Camera API2.0下的Preview(預覽)流程分析
android6.0原始碼分析之Camera API2.0下的Capture流程分析
android6.0原始碼分析之Camera API2.0下的video流程分析
Camera API2.0的應用
1、Camera2 preview的應用層流程分析
preview流程都是從startPreview開始的,所以來看startPreview方法的程式碼:
//OneCameraImpl.java
@Override
public void startPreview(Surface previewSurface, CaptureReadyCallback listener) {
mPreviewSurface = previewSurface;
//根據Surface以及CaptureReadyCallback回撥來建立preview環境
setupAsync(mPreviewSurface, listener);
}
這其中有一個比較重要的回撥CaptureReadyCallback,先分析setupAsync方法:
//OneCameraImpl.java
private void setupAsync(final Surface previewSurface, final CaptureReadyCallback listener) {
mCameraHandler.post(new Runnable() {
@Override
public void run() {
//建立preview環境
setup(previewSurface, listener);
}
});
}
這裡通過CameraHandler來post一個Runnable物件,它只會呼叫Runnable的run方法,它仍然屬於UI執行緒,並沒有建立新的執行緒。所以,繼續分析setup方法:
// OneCameraImpl.java
private void setup(Surface previewSurface, final CaptureReadyCallback listener) {
try {
if (mCaptureSession != null) {
mCaptureSession.abortCaptures();
mCaptureSession = null;
}
List<Surface> outputSurfaces = new ArrayList<Surface>(2);
outputSurfaces.add(previewSurface);
outputSurfaces.add(mCaptureImageReader.getSurface());
//建立CaptureSession會話來與Camera Device傳送Preview請求
mDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
@Override
public void onConfigureFailed(CameraCaptureSession session) {
//如果配置失敗,則回撥CaptureReadyCallback的onSetupFailed方法
listener.onSetupFailed();
}
@Override
public void onConfigured(CameraCaptureSession session) {
mCaptureSession = session;
mAFRegions = ZERO_WEIGHT_3A_REGION;
mAERegions = ZERO_WEIGHT_3A_REGION;
mZoomValue = 1f;
mCropRegion = cropRegionForZoom(mZoomValue);
//呼叫repeatingPreview來啟動preview
boolean success = repeatingPreview(null);
if (success) {
//若啟動成功,則回撥CaptureReadyCallback的onReadyForCapture,表示準備拍照成功
listener.onReadyForCapture();
} else {
//若啟動失敗,則回撥CaptureReadyCallback的onSetupFailed,表示preview建立失敗
listener.onSetupFailed();
}
}
@Override
public void onClosed(CameraCaptureSession session) {
super.onClosed(session);
}
}, mCameraHandler);
} catch (CameraAccessException ex) {
Log.e(TAG, "Could not set up capture session", ex);
listener.onSetupFailed();
}
}
首先,呼叫Device的createCaptureSession方法來建立一個會話,並定義了會話的狀態回撥CameraCaptureSession.StateCallback(),其中,當會話建立成功,則會回撥onConfigured()方法,在其中,首先呼叫repeatingPreview來啟動preview,然後處理preview的結果並呼叫先前定義的CaptureReadyCallback來通知使用者進行Capture操作。先分析repeatingPreview方法:
// OneCameraImpl.java
private boolean repeatingPreview(Object tag) {
try {
//通過CameraDevice物件建立一個CaptureRequest的preview請求
CaptureRequest.Builder builder = mDevice.createCaptureRequest(
CameraDevice.TEMPLATE_PREVIEW);
//新增預覽的目標Surface
builder.addTarget(mPreviewSurface);
//設定預覽模式
builder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
addBaselineCaptureKeysToRequest(builder);
//利用會話傳送請求,mCaptureCallback為
mCaptureSession.setRepeatingRequest(builder.build(), mCaptureCallback,mCameraHandler);
Log.v(TAG, String.format("Sent repeating Preview request, zoom = %.2f", mZoomValue));
return true;
} catch (CameraAccessException ex) {
Log.e(TAG, "Could not access camera setting up preview.", ex);
return false;
}
}
首先呼叫CameraDeviceImpl的createCaptureRequest方法建立型別為TEMPLATE_PREVIEW 的CaptureRequest,然後呼叫CameraCaptureSessionImpl的setRepeatingRequest方法將此請求傳送出去:
//CameraCaptureSessionImpl.java
@Override
public synchronized int setRepeatingRequest(CaptureRequest request, CaptureCallback callback,
Handler handler) throws CameraAccessException {
if (request == null) {
throw new IllegalArgumentException("request must not be null");
} else if (request.isReprocess()) {
throw new IllegalArgumentException("repeating reprocess requests are not supported");
}
checkNotClosed();
handler = checkHandler(handler, callback);
...
//將此請求新增到待處理的序列裡
return addPendingSequence(mDeviceImpl.setRepeatingRequest(request,createCaptureCallbackProxy(
handler, callback), mDeviceHandler));
}
至此應用層的preview的請求流程分析結束,繼續分析其結果處理,如果preview開啟成功,則會回撥CaptureReadyCallback的onReadyForCapture方法,現在分析CaptureReadyCallback回撥:
//CaptureModule.java
new CaptureReadyCallback() {
@Override
public void onSetupFailed() {
mCameraOpenCloseLock.release();
Log.e(TAG, "Could not set up preview.");
mMainThread.execute(new Runnable() {
@Override
public void run() {
if (mCamera == null) {
Log.d(TAG, "Camera closed, aborting.");
return;
}
mCamera.close();
mCamera = null;
}
});
}
@Override
public void onReadyForCapture() {
mCameraOpenCloseLock.release();
mMainThread.execute(new Runnable() {
@Override
public void run() {
Log.d(TAG, "Ready for capture.");
if (mCamera == null) {
Log.d(TAG, "Camera closed, aborting.");
return;
}
//
onPreviewStarted();
onReadyStateChanged(true);
mCamera.setReadyStateChangedListener(CaptureModule.this);
mUI.initializeZoom(mCamera.getMaxZoom());
mCamera.setFocusStateListener(CaptureModule.this);
}
});
}
}
根據前面的分析,預覽成功後會回撥onReadyForCapture方法,它主要是通知主執行緒的狀態改變,並設定Camera的ReadyStateChangedListener的監聽,其回撥方法如下:
//CaptureModule.java
@Override
public void onReadyStateChanged(boolean readyForCapture) {
if (readyForCapture) {
mAppController.getCameraAppUI().enableModeOptions();
}
mAppController.setShutterEnabled(readyForCapture);
}
如程式碼所示,當其狀態變成準備好拍照,則將會呼叫CameraActivity的setShutterEnabled方法,即使能快門按鍵,此時也就是說預覽成功結束,可以按快門進行拍照了,所以,到這裡,應用層的preview的流程基本分析完畢,下圖是應用層的關鍵呼叫的流程時序圖:
2、Camera2 preview的Native層流程分析
分析Preview的Native的程式碼真是費了九牛二虎之力,若有分析不正確之處,請各位大神指正,在第一小節的後段最後會呼叫CameraDeviceImpl的setRepeatingRequest方法來提交請求,而在android6.0原始碼分析之Camera API2.0簡介中,分析了Camera2框架Java IPC通訊使用了CameraDeviceUser來進行通訊,所以看Native層的ICameraDeviceUser的onTransact方法來處理請求的提交:
//ICameraDeviceUser.cpp
status_t BnCameraDeviceUser::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
uint32_t flags){
switch(code) {
…
//請求提交
case SUBMIT_REQUEST: {
CHECK_INTERFACE(ICameraDeviceUser, data, reply);
// arg0 = request
sp<CaptureRequest> request;
if (data.readInt32() != 0) {
request = new CaptureRequest();
request->readFromParcel(const_cast<Parcel*>(&data));
}
// arg1 = streaming (bool)
bool repeating = data.readInt32();
// return code: requestId (int32)
reply->writeNoException();
int64_t lastFrameNumber = -1;
//將實現BnCameraDeviceUser的對下崗的submitRequest方法程式碼寫入Binder
reply->writeInt32(submitRequest(request, repeating, &lastFrameNumber));
reply->writeInt32(1);
reply->writeInt64(lastFrameNumber);
return NO_ERROR;
} break;
...
}
CameraDeviceClientBase繼承了BnCameraDeviceUser類,所以CameraDeviceClientBase相當於IPC Binder中的client,所以會呼叫其submitRequest方法,此處,至於IPC Binder通訊原理不做分析,其參照其它資料:
//CameraDeviceClient.cpp
status_t CameraDeviceClient::submitRequest(sp<CaptureRequest> request,bool streaming,
/*out*/int64_t* lastFrameNumber) {
List<sp<CaptureRequest> > requestList;
requestList.push_back(request);
return submitRequestList(requestList, streaming, lastFrameNumber);
}
簡單的呼叫,繼續分析submitRequestList:
// CameraDeviceClient
status_t CameraDeviceClient::submitRequestList(List<sp<CaptureRequest> > requests,bool streaming,
int64_t* lastFrameNumber) {
...
//Metadata連結串列
List<const CameraMetadata> metadataRequestList;
...
for (List<sp<CaptureRequest> >::iterator it = requests.begin(); it != requests.end(); ++it) {
sp<CaptureRequest> request = *it;
...
//初始化Metadata資料
CameraMetadata metadata(request->mMetadata);
...
//設定Stream的容量
Vector<int32_t> outputStreamIds;
outputStreamIds.setCapacity(request->mSurfaceList.size());
//迴圈初始化Surface
for (size_t i = 0; i < request->mSurfaceList.size(); ++i) {
sp<Surface> surface = request->mSurfaceList[i];
if (surface == 0) continue;
sp<IGraphicBufferProducer> gbp = surface->getIGraphicBufferProducer();
int idx = mStreamMap.indexOfKey(IInterface::asBinder(gbp));
...
int streamId = mStreamMap.valueAt(idx);
outputStreamIds.push_back(streamId);
}
//更新資料
metadata.update(ANDROID_REQUEST_OUTPUT_STREAMS, &outputStreamIds[0],
outputStreamIds.size());
if (request->mIsReprocess) {
metadata.update(ANDROID_REQUEST_INPUT_STREAMS, &mInputStream.id, 1);
}
metadata.update(ANDROID_REQUEST_ID, &requestId, /*size*/1);
loopCounter++; // loopCounter starts from 1
//壓棧
metadataRequestList.push_back(metadata);
}
mRequestIdCounter++;
if (streaming) {
//預覽會走此條通道
res = mDevice->setStreamingRequestList(metadataRequestList, lastFrameNumber);
if (res != OK) {
...
} else {
mStreamingRequestList.push_back(requestId);
}
} else {
//Capture等走此條通道
res = mDevice->captureList(metadataRequestList, lastFrameNumber);
if (res != OK) {
...
}
}
if (res == OK) {
return requestId;
}
return res;
}
setStreamingRequestList和captureList方法都呼叫了submitRequestsHelper方法,只是他們的repeating引數一個ture,一個為false,而本節分析的preview呼叫的是setStreamingRequestList方法,並且API2.0下Device的實現為Camera3Device,所以看它的submitRequestsHelper實現:
// Camera3Device.cpp
status_t Camera3Device::submitRequestsHelper(const List<const CameraMetadata> &requests,
bool repeating,/*out*/int64_t *lastFrameNumber) {
...
RequestList requestList;
//在這裡面會進行CaptureRequest的建立,並呼叫configureStreamLocked進行stream的配置,主要是設定了一個回撥captureResultCb,即後面要分析的重要的回撥
res = convertMetadataListToRequestListLocked(requests, /*out*/&requestList);
...
if (repeating) {
//眼熟不,這個方法名和應用層中CameraDevice的setRepeatingRequests一樣
res = mRequestThread->setRepeatingRequests(requestList, lastFrameNumber);
} else {
//不需重複,即repeating為false時,呼叫此方法來講請求提交
res = mRequestThread->queueRequestList(requestList, lastFrameNumber);
}
...
return res;
}
從程式碼可知,在Camera3Device裡建立了要給RequestThread執行緒,呼叫它的setRepeatingRequests或者queueRequestList方法來將應用層傳送過來的Request提交,繼續看setRepeatingRequests方法:
// Camera3Device.cpp
status_t Camera3Device::RequestThread::setRepeatingRequests(const RequestList &requests,
/*out*/int64_t *lastFrameNumber) {
Mutex::Autolock l(mRequestLock);
if (lastFrameNumber != NULL) {
*lastFrameNumber = mRepeatingLastFrameNumber;
}
mRepeatingRequests.clear();
//將其插入mRepeatingRequest連結串列
mRepeatingRequests.insert(mRepeatingRequests.begin(),
requests.begin(), requests.end());
unpauseForNewRequests();
mRepeatingLastFrameNumber = NO_IN_FLIGHT_REPEATING_FRAMES;
return OK;
}
至此,Native層的preview過程基本分析結束,下面的工作將會交給Camera HAL層來處理,先給出Native層的呼叫時序圖:
3、Camera2 preview的CameraHAL層流程分析
本節將不再對Camera的HAL層的初始化以及相關配置進行分析,只對preview等相關流程中的frame metadata的處理流程進行分析,具體的CameraHAL分析請參考android6.0原始碼分析之Camera2 HAL分析.在第二小節的submitRequestsHelper方法中呼叫convertMetadataListToRequestListLocked的時候會進行CaptureRequest的建立,並呼叫configureStreamLocked進行stream的配置,主要是設定了一個回撥captureResultCb,所以Native層在request提交後,會回撥此captureResultCb方法,首先分析captureResultCb:
// QCamera3HWI.cpp
void QCamera3HardwareInterface::captureResultCb(mm_camera_super_buf_t *metadata_buf,
camera3_stream_buffer_t *buffer, uint32_t frame_number)
{
if (metadata_buf) {
if (mBatchSize) {
//批處理模式,但程式碼也是迴圈呼叫handleMetadataWithLock方法
handleBatchMetadata(metadata_buf, true /* free_and_bufdone_meta_buf */);
} else { /* mBatchSize = 0 */
pthread_mutex_lock(&mMutex);
//處理元資料
handleMetadataWithLock(metadata_buf, true /* free_and_bufdone_meta_buf */);
pthread_mutex_unlock(&mMutex);
}
} else {
pthread_mutex_lock(&mMutex);
handleBufferWithLock(buffer, frame_number);
pthread_mutex_unlock(&mMutex);
}
return;
}
一種是通過迴圈來進行元資料的批處理,另一種是直接進行元資料的處理,但是批處理最終也是迴圈呼叫handleMetadataWithLock來處理:
// QCamera3HWI.cpp
void QCamera3HardwareInterface::handleMetadataWithLock(mm_camera_super_buf_t *metadata_buf,
bool free_and_bufdone_meta_buf){
...
//Partial result on process_capture_result for timestamp
if (urgent_frame_number_valid) {
...
for (List<PendingRequestInfo>::iterator i =mPendingRequestsList.begin();
i != mPendingRequestsList.end(); i++) {
...
if (i->frame_number == urgent_frame_number &&i->bUrgentReceived == 0) {
camera3_capture_result_t result;
memset(&result, 0, sizeof(camera3_capture_result_t));
i->partial_result_cnt++;
i->bUrgentReceived = 1;
//提取3A資料
result.result =translateCbUrgentMetadataToResultMetadata(metadata);
...
//對Capture Result進行處理
mCallbackOps->process_capture_result(mCallbackOps, &result);
//釋放camera_metadata_t
free_camera_metadata((camera_metadata_t *)result.result);
break;
}
}
}
...
for (List<PendingRequestInfo>::iterator i = mPendingRequestsList.begin();
i != mPendingRequestsList.end() && i->frame_number <= frame_number;) {
camera3_capture_result_t result;
memset(&result, 0, sizeof(camera3_capture_result_t));
...
if (i->frame_number < frame_number) {
//清空資料結構
camera3_notify_msg_t notify_msg;
memset(¬ify_msg, 0, sizeof(camera3_notify_msg_t));
//定義訊息型別
notify_msg.type = CAMERA3_MSG_SHUTTER;
notify_msg.message.shutter.frame_number = i->frame_number;
notify_msg.message.shutter.timestamp = (uint64_t)capture_time (urgent_frame_number -
i->frame_number) * NSEC_PER_33MSEC;
//呼叫回撥通知應用層發生CAMERA3_MSG_SHUTTER訊息
mCallbackOps->notify(mCallbackOps, ¬ify_msg);
...
CameraMetadata dummyMetadata;
//更新元資料
dummyMetadata.update(ANDROID_SENSOR_TIMESTAMP,
&i->timestamp, 1);
dummyMetadata.update(ANDROID_REQUEST_ID,
&(i->request_id), 1);
//得到元資料釋放結果
result.result = dummyMetadata.release();
} else {
camera3_notify_msg_t notify_msg;
memset(¬ify_msg, 0, sizeof(camera3_notify_msg_t));
// Send shutter notify to frameworks
notify_msg.type = CAMERA3_MSG_SHUTTER;
...
//從HAL中獲得Metadata
result.result = translateFromHalMetadata(metadata,
i->timestamp, i->request_id, i->jpegMetadata, i->pipeline_depth,
i->capture_intent);
saveExifParams(metadata);
if (i->blob_request) {
...
if (enabled && metadata->is_tuning_params_valid) {
//將Metadata複製到檔案
dumpMetadataToFile(metadata->tuning_params, mMetaFrameCount, enabled,
"Snapshot",frame_number);
}
mPictureChannel->queueReprocMetadata(metadata_buf);
} else {
// Return metadata buffer
if (free_and_bufdone_meta_buf) {
mMetadataChannel->bufDone(metadata_buf);
free(metadata_buf);
}
}
}
...
}
}
其中,首先會呼叫回撥的process_capture_result方法來對Capture Result進行處理,然後會呼叫回撥的notify方法來發送一個CAMERA3_MSG_SHUTTER訊息,而process_capture_result所對應的實現其實就是Camera3Device的processCaptureResult方法,先分析processCaptureResult:
//Camera3Device.cpp
void Camera3Device::processCaptureResult(const camera3_capture_result *result) {
...
//對於HAL3.2+,如果HAL不支援partial,當metadata被包含在result中時,它必須將partial_result設定為1
...
{
Mutex::Autolock l(mInFlightLock);
ssize_t idx = mInFlightMap.indexOfKey(frameNumber);
...
InFlightRequest &request = mInFlightMap.editValueAt(idx);
if (result->partial_result != 0)
request.resultExtras.partialResultCount = result->partial_result;
// 檢查結果是否只有partial metadata
if (mUsePartialResult && result->result != NULL) {
if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) {//HAL版本高於3.2
if (result->partial_result > mNumPartialResults || result->partial_result < 1) {
//Log顯示錯誤
return;
}
isPartialResult = (result->partial_result < mNumPartialResults);
if (isPartialResult) {
//將結果加入到請求的結果集中
request.partialResult.collectedResult.append(result->result);
}
} else {//低於3.2
...
}
if (isPartialResult) {
// Fire off a 3A-only result if possible
if (!request.partialResult.haveSent3A) {
request.partialResult.haveSent3A =processPartial3AResult(frameNumber,
request.partialResult.collectedResult,request.resultExtras);
}
}
}
...
if (result->result != NULL && !isPartialResult) {
if (shutterTimestamp == 0) {
request.pendingMetadata = result->result;
request.partialResult.collectedResult = collectedPartialResult;
} else {
CameraMetadata metadata;
metadata = result->result;
//傳送Capture Result
sendCaptureResult(metadata, request.resultExtras, collectedPartialResult,
frameNumber, hasInputBufferInRequest,request.aeTriggerCancelOverride);
}
}
//結果處理好了,將請求移除
removeInFlightRequestIfReadyLocked(idx);
} // scope for mInFlightLock
...
}
由程式碼可知,它會處理區域性的或者全部的metadata資料,最後如果result不為空,且得到的是請求處理的全部資料,則會呼叫sendCaptureResult方法來將請求結果傳送出去:
//Camera3Device.cpp
void Camera3Device::sendCaptureResult(CameraMetadata &pendingMetadata,CaptureResultExtras
&resultExtras,CameraMetadata &collectedPartialResult,uint32_t frameNumber,bool reprocess,
const AeTriggerCancelOverride_t &aeTriggerCancelOverride) {
if (pendingMetadata.isEmpty())//如果資料為空,直接返回
return;
...
CaptureResult captureResult;
captureResult.mResultExtras = resultExtras;
captureResult.mMetadata = pendingMetadata;
//更新metadata
if (captureResult.mMetadata.update(ANDROID_REQUEST_FRAME_COUNT(int32_t*)&frameNumber, 1)
!= OK) {
SET_ERR("Failed to set frame# in metadata (%d)",frameNumber);
return;
} else {
...
}
// Append any previous partials to form a complete result
if (mUsePartialResult && !collectedPartialResult.isEmpty()) {
captureResult.mMetadata.append(collectedPartialResult);
}
//排序
captureResult.mMetadata.sort();
// Check that there's a timestamp in the result metadata
camera_metadata_entry entry = captureResult.mMetadata.find(ANDROID_SENSOR_TIMESTAMP);
...
overrideResultForPrecaptureCancel(&captureResult.mMetadata, aeTriggerCancelOverride);
// 有效的結果,將其插入Buffer
List<CaptureResult>::iterator queuedResult =mResultQueue.insert(mResultQueue.end(),
CaptureResult(captureResult));
...
mResultSignal.signal();
}
最後,它將Capture Result插入了結果佇列,並釋放了結果的訊號量,所以到這裡,Capture Result處理成功,下面分析前面的notify傳送CAMERA3_MSG_SHUTTER訊息:
//Camera3Device.cpp
void Camera3Device::notify(const camera3_notify_msg *msg) {
NotificationListener *listener;
{
Mutex::Autolock l(mOutputLock);
listener = mListener;
}
...
switch (msg->type) {
case CAMERA3_MSG_ERROR: {
notifyError(msg->message.error, listener);
break;
}
case CAMERA3_MSG_SHUTTER: {
notifyShutter(msg->message.shutter, listener);
break;
}
default:
SET_ERR("Unknown notify message from HAL: %d",
msg->type);
}
}
它呼叫了notifyShutter方法:
// Camera3Device.cpp
void Camera3Device::notifyShutter(const camera3_shutter_msg_t &msg,
NotificationListener *listener) {
...
// Set timestamp for the request in the in-flight tracking
// and get the request ID to send upstream
{
Mutex::Autolock l(mInFlightLock);
idx = mInFlightMap.indexOfKey(msg.frame_number);
if (idx >= 0) {
InFlightRequest &r = mInFlightMap.editValueAt(idx);
// Call listener, if any
if (listener != NULL) {
//呼叫監聽的notifyShutter法國法
listener->notifyShutter(r.resultExtras, msg.timestamp);
}
...
//將待處理的result傳送到Buffer
sendCaptureResult(r.pendingMetadata, r.resultExtras,
r.partialResult.collectedResult, msg.frame_number,
r.hasInputBuffer, r.aeTriggerCancelOverride);
returnOutputBuffers(r.pendingOutputBuffers.array(),
r.pendingOutputBuffers.size(), r.shutterTimestamp);
r.pendingOutputBuffers.clear();
removeInFlightRequestIfReadyLocked(idx);
}
}
...
}
首先它會通知listener preview成功,最後會呼叫sendCaptureResult將結果加入到結果佇列。它會呼叫listener的notifyShutter方法,此處的listener其實是CameraDeviceClient類,所以會呼叫CameraDeviceClient類的notifyShutter方法:
//CameraDeviceClient.cpp
void CameraDeviceClient::notifyShutter(const CaptureResultExtras& resultExtras,nsecs_t timestamp) {
// Thread safe. Don't bother locking.
sp<ICameraDeviceCallbacks> remoteCb = getRemoteCallback();
if (remoteCb != 0) {
//呼叫應用層的回撥(CaptureCallback的onCaptureStarted方法)
remoteCb->onCaptureStarted(resultExtras, timestamp);
}
}
此處的ICameraDeviceCallbacks對應的是Java層的CameraDeviceImpl.java中的內部類CameraDeviceCallbacks,所以會呼叫它的onCaptureStarted方法:
//CameraDeviceImpl.java
@Override
public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) {
int requestId = resultExtras.getRequestId();
final long frameNumber = resultExtras.getFrameNumber();
final CaptureCallbackHolder holder;
synchronized(mInterfaceLock) {
if (mRemoteDevice == null) return; // Camera already closed
// Get the callback for this frame ID, if there is one
holder = CameraDeviceImpl.this.mCaptureCallbackMap.get(requestId);
...
// Dispatch capture start notice
holder.getHandler().post(new Runnable() {
@Override
public void run() {
if (!CameraDeviceImpl.this.isClosed()) {
holder.getCallback().onCaptureStarted(CameraDeviceImpl.this,holder.getRequest(
resultExtras.getSubsequenceId()),timestamp, frameNumber);
}
}
});
}
}
它會呼叫OneCameraImpl.java中的mCaptureCallback的onCaptureStarted方法:
//OneCameraImpl.java
//Common listener for preview frame metadata.
private final CameraCaptureSession.CaptureCallback mCaptureCallback =
new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureStarted(CameraCaptureSession session,CaptureRequest request,
long timestamp,long frameNumber) {
if (request.getTag() == RequestTag.CAPTURE&& mLastPictureCallback != null) {
mLastPictureCallback.onQuickExpose();
}
}
…
}
注意:Capture,preview以及autoFocus都是使用的這個回撥,而Capture呼叫的時候,其RequestTag為CAPTURE,而autoFocus的時候為TAP_TO_FOCUS,而preview請求時沒有對RequestTag進行設定,所以回撥到onCaptureStarted方法時,不需要進行處理,但是到此時,preview已經啟動成功,可以進行預覽了,其資料都在buffer裡。所以到此時,preview的流程全部分析結束,下面給出HAL層上的流程時序圖
相關推薦
ANDROID6.0原始碼分析之CAMERA API2.0下的CAPTURE流程分析
前面對Camera2的初始化以及預覽的相關流程進行了詳細分析,本文將會對Camera2的capture(拍照)流程進行分析。 &
android6.0原始碼分析之Camera API2.0下的Preview(預覽)流程分析
本文將基於android6.0的原始碼,對Camera API2.0下Camera的preview的流程進行分析。在文章andro
android6.0原始碼分析之Camera API2.0簡介
前面幾篇主要分析的是android Camera API1.0的架構以及初始化流程,而google在android5.0(Loll
android6.0原始碼分析之Camera API1.0框架簡介
1、架構簡介 由於最近專案涉及到Camera,所以對Camera原始碼進行了研究,本文將分享Camera框架的基本知識。anroid6.0與5.0相比,Camera框架未曾改變,依然提供了兩種API,即API1和API2,依然採用C/S的架構,而client和
Android6.0 原始碼修改之遮蔽導航欄虛擬按鍵(Home和RecentAPP)/動態顯示和隱藏NavigationBar
轉載請註明出處:https://blog.csdn.net/u012932409/article/details/83063075 場景分析, 為了完全實現沉浸式效果,在進入特定的app後可以將導航欄移除,當退出app後再次將導航欄恢復。(下面將採用傳送廣播的方式來移除
Android6.0 原始碼修改之遮蔽系統簡訊功能和來電功能
一、遮蔽系統簡訊功能 1、遮蔽所有簡訊 android 4.2 簡訊傳送流程分析可參考這篇 戳這 原始碼位置 vendor\mediatek\proprietary\packages\apps\Mms\src\com\android\mms\trans
Android6.0原始碼解讀之Activity點選事件分發機制
本篇博文是Android點選事件分發機制系列博文的第四篇,主要是從解讀Activity類的原始碼入手,根據原始碼理清Activity點選事件分發原理,並掌握Activity點選事件分法機制。特別宣告的是,本原始碼解讀是基於最新的Android6.0版本。
Android 5.0 Camera系統原始碼分析(4):Camera預覽流程資料流
1. 前言 上一篇講了怎麼讓Camera進入預覽模式,提到了DisplayClient負責顯示影象資料,而CamAdapter負責提供影象資料,這裡主要記錄了CamAdapter怎麼獲取影象,然後DisplayClient怎麼將影象顯示在螢幕上。 2.
Android 5.0 Camera系統原始碼分析(3):Camera預覽流程控制流
1. 前言 本文分析的是Android系統原始碼,從frameworks層到hal層,記錄了Camera進入預覽模式的重點程式碼,主要為控制流程的程式碼,有關影象buffer的傳遞暫不涉及,硬體平臺基於mt6735。由於某些函式比較複雜,在貼出程式碼時會適當對
webpack4.0原始碼解析之打包後js檔案分析
首先,init之後建立一個簡單的webpack基本的配置,在src目錄下建立兩個js檔案(一個主入口檔案和一個非主入口檔案)和一個html檔案,package.json,webpack.config.js程式碼如下: var name=require('./index1.js') console.log('
webpack4.0原始碼解析之CommonJS規範打包後js檔案分析
首先,init之後建立一個簡單的webpack基本的配置,在src目錄下建立兩個js檔案(一個主入口檔案和一個非主入口檔案)和一個html檔案,package.json,webpack.config.js程式碼如下: var name=require('./index1.js') console.log('
webpack4.0原始碼解析之esModule打包分析
入口檔案index.js採用esModule方式匯入模組檔案,非入口檔案index1.js分別採用CommonJS和esmodule規範進行匯出。 首先,init之後建立一個簡單的webpack基本的配置,在src目錄下建立兩個js檔案(一個主入口檔案和一個非主入口檔案)和一個html檔案,package.j
[Android6.0][RK3399] 電池系統(三)電量計 CW2015 驅動流程分析
Platform: RK3399 OS: Android 6.0 Kernel: 4.4 Version: v2017.04 IC: TI BQ25700、RK808 已知問題 驅動分析 函式呼叫鏈 已知問題 cw2
Android Camera API2.0下全新的Camera FW/HAL架構簡述
本文均屬自己閱讀原始碼的點滴總結,轉賬請註明出處謝謝。歡迎和大家交流。qq:1037701636 email:Software:系統原始碼Android5.1前沿: 前面博文大多少總結的是Camera HAL1到HAL3的系統架構,但這些架構對於Camera A
Android5.0原始碼開發之launcher切換語言後Folder和ShortcutT沒有切換到當前語言
一、桌面快捷方式ShortcutT app的快捷方式一旦生成,info.title都會存到資料庫,檢測到configuration語言改變時,launcher會重新loadworkspace,這時會從資料庫查詢info = getShortcutInfo(c
K8S 原始碼探祕 之 kubelet 同步 Node 狀態(kubelet 心跳機制分析)
一、引言 在 K8S 系統執行過程中,kubelet 需要定期向 API Server 上報節點執行狀態(也就是心跳訊息) 本文從原始碼角度分析下 kubelet 進行節點狀態上報
STL原始碼分析之slist有序容器 下
前言 上節我們對slist的基本構成, 構造析構做了分析, 本節 我們就來分析關於slist的基本元素操作. slist分析 基本屬性資訊 slist是隻有正向迭代, 所以只能直接獲取頭部的資料. template <class T, class Alloc =
STL原始碼分析之list有序容器 下
前言 前兩節對list的push, pop, insert等操作做了分析, 本節準備探討list怎麼實現sort功能. list是一個迴圈雙向連結串列, 不是一個連續地址空間, 所以sort功能需要特殊的演算法單獨實現, 而不能用演算法中的sort. 當然還可以將list的元素插
雲客Drupal8原始碼分析之外掛系統(下)
以下內容僅是一個預覽,完整內容請見文尾: 至此本系列對外掛的介紹全部完成,涵蓋了系統外掛的所有知識 全文目錄(全文10476字): 例項化外掛 外掛對映Plugin mapping 外掛上下文
以太坊原始碼分析之 P2P網路(二、節點發現流程)
區塊鏈特輯 :https://blog.csdn.net/fusan2004/article/details/80879343,歡迎查閱,原創作品,轉載請標明!上一篇文章簡單介紹了下一些基礎的型別定義,從這一篇開始我們將描述p2p網路的更多細節。從關於節點的定義來看,其實不同