blob: 24ecf28f61ab0717200369b57ff3c2b0eb9c8946 [file] [log] [blame]
Eino-Ville Talvala69230df2012-08-29 17:37:16 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "Camera2Client::CaptureSequencer"
18#define ATRACE_TAG ATRACE_TAG_CAMERA
19//#define LOG_NDEBUG 0
20
21#include <utils/Log.h>
22#include <utils/Trace.h>
23#include <utils/Vector.h>
24
25#include "CaptureSequencer.h"
James Painterc3dbf1a2012-09-05 18:02:32 -070026#include "BurstCapture.h"
Eino-Ville Talvala69230df2012-08-29 17:37:16 -070027#include "../Camera2Device.h"
28#include "../Camera2Client.h"
29#include "Parameters.h"
30
31namespace android {
32namespace camera2 {
33
34/** Public members */
35
36CaptureSequencer::CaptureSequencer(wp<Camera2Client> client):
37 Thread(false),
38 mStartCapture(false),
39 mBusy(false),
40 mNewAEState(false),
41 mNewFrameReceived(false),
42 mNewCaptureReceived(false),
43 mClient(client),
44 mCaptureState(IDLE),
45 mTriggerId(0),
46 mTimeoutCount(0),
47 mCaptureId(Camera2Client::kFirstCaptureRequestId) {
James Painterc3dbf1a2012-09-05 18:02:32 -070048 ALOGV("%s", __FUNCTION__);
Eino-Ville Talvala69230df2012-08-29 17:37:16 -070049}
50
51CaptureSequencer::~CaptureSequencer() {
52 ALOGV("%s: Exit", __FUNCTION__);
53}
54
55void CaptureSequencer::setZslProcessor(wp<ZslProcessor> processor) {
56 Mutex::Autolock l(mInputMutex);
57 mZslProcessor = processor;
58}
59
60status_t CaptureSequencer::startCapture() {
James Painterc3dbf1a2012-09-05 18:02:32 -070061 ALOGV("%s", __FUNCTION__);
Eino-Ville Talvala69230df2012-08-29 17:37:16 -070062 ATRACE_CALL();
63 Mutex::Autolock l(mInputMutex);
64 if (mBusy) {
65 ALOGE("%s: Already busy capturing!", __FUNCTION__);
66 return INVALID_OPERATION;
67 }
68 if (!mStartCapture) {
69 mStartCapture = true;
70 mStartCaptureSignal.signal();
71 }
72 return OK;
73}
74
75void CaptureSequencer::notifyAutoExposure(uint8_t newState, int triggerId) {
76 ATRACE_CALL();
77 Mutex::Autolock l(mInputMutex);
78 mAEState = newState;
79 mAETriggerId = triggerId;
80 if (!mNewAEState) {
81 mNewAEState = true;
82 mNewNotifySignal.signal();
83 }
84}
85
86void CaptureSequencer::onFrameAvailable(int32_t frameId,
87 CameraMetadata &frame) {
James Painterc3dbf1a2012-09-05 18:02:32 -070088 ALOGV("%s: Listener found new frame", __FUNCTION__);
Eino-Ville Talvala69230df2012-08-29 17:37:16 -070089 ATRACE_CALL();
90 Mutex::Autolock l(mInputMutex);
91 mNewFrameId = frameId;
92 mNewFrame.acquire(frame);
93 if (!mNewFrameReceived) {
94 mNewFrameReceived = true;
95 mNewFrameSignal.signal();
96 }
97}
98
99void CaptureSequencer::onCaptureAvailable(nsecs_t timestamp) {
100 ATRACE_CALL();
James Painterc3dbf1a2012-09-05 18:02:32 -0700101 ALOGV("%s", __FUNCTION__);
Eino-Ville Talvala69230df2012-08-29 17:37:16 -0700102 Mutex::Autolock l(mInputMutex);
103 mCaptureTimestamp = timestamp;
104 if (!mNewCaptureReceived) {
105 mNewCaptureReceived = true;
106 mNewCaptureSignal.signal();
107 }
108}
109
110
111void CaptureSequencer::dump(int fd, const Vector<String16>& args) {
112 String8 result;
113 if (mCaptureRequest.entryCount() != 0) {
114 result = " Capture request:\n";
115 write(fd, result.string(), result.size());
116 mCaptureRequest.dump(fd, 2, 6);
117 } else {
118 result = " Capture request: undefined\n";
119 write(fd, result.string(), result.size());
120 }
121 result = String8::format(" Current capture state: %s\n",
122 kStateNames[mCaptureState]);
123 result.append(" Latest captured frame:\n");
124 write(fd, result.string(), result.size());
125 mNewFrame.dump(fd, 2, 6);
126}
127
128/** Private members */
129
130const char* CaptureSequencer::kStateNames[CaptureSequencer::NUM_CAPTURE_STATES+1] =
131{
132 "IDLE",
133 "START",
134 "ZSL_START",
135 "ZSL_WAITING",
136 "ZSL_REPROCESSING",
137 "STANDARD_START",
138 "STANDARD_PRECAPTURE",
139 "STANDARD_CAPTURING",
James Painterc3dbf1a2012-09-05 18:02:32 -0700140 "BURST_CAPTURE_START",
141 "BURST_CAPTURE_WAIT",
Eino-Ville Talvala69230df2012-08-29 17:37:16 -0700142 "DONE",
143 "ERROR",
144 "UNKNOWN"
145};
146
147const CaptureSequencer::StateManager
148 CaptureSequencer::kStateManagers[CaptureSequencer::NUM_CAPTURE_STATES-1] = {
149 &CaptureSequencer::manageIdle,
150 &CaptureSequencer::manageStart,
151 &CaptureSequencer::manageZslStart,
152 &CaptureSequencer::manageZslWaiting,
153 &CaptureSequencer::manageZslReprocessing,
154 &CaptureSequencer::manageStandardStart,
155 &CaptureSequencer::manageStandardPrecaptureWait,
156 &CaptureSequencer::manageStandardCapture,
157 &CaptureSequencer::manageStandardCaptureWait,
James Painterc3dbf1a2012-09-05 18:02:32 -0700158 &CaptureSequencer::manageBurstCaptureStart,
159 &CaptureSequencer::manageBurstCaptureWait,
Eino-Ville Talvala69230df2012-08-29 17:37:16 -0700160 &CaptureSequencer::manageDone,
161};
162
163bool CaptureSequencer::threadLoop() {
164 status_t res;
165
166 sp<Camera2Client> client = mClient.promote();
167 if (client == 0) return false;
168
169 if (mCaptureState < ERROR) {
170 mCaptureState = (this->*kStateManagers[mCaptureState])(client);
171 } else {
172 ALOGE("%s: Bad capture state: %s",
173 __FUNCTION__, kStateNames[mCaptureState]);
174 return false;
175 }
176
177 return true;
178}
179
180CaptureSequencer::CaptureState CaptureSequencer::manageIdle(sp<Camera2Client> &client) {
181 status_t res;
182 ATRACE_CALL();
183 Mutex::Autolock l(mInputMutex);
184 while (!mStartCapture) {
185 res = mStartCaptureSignal.waitRelative(mInputMutex,
186 kWaitDuration);
187 if (res == TIMED_OUT) break;
188 }
189 if (mStartCapture) {
190 mStartCapture = false;
191 mBusy = true;
192 return START;
193 }
194 return IDLE;
195}
196
197CaptureSequencer::CaptureState CaptureSequencer::manageDone(sp<Camera2Client> &client) {
198 status_t res;
199 ATRACE_CALL();
200 mCaptureId++;
201
202 {
203 Mutex::Autolock l(mInputMutex);
204 mBusy = false;
205 }
206
207 SharedParameters::Lock l(client->getParameters());
208 switch (l.mParameters.state) {
209 case Parameters::STILL_CAPTURE:
210 l.mParameters.state = Parameters::STOPPED;
211 break;
212 case Parameters::VIDEO_SNAPSHOT:
213 l.mParameters.state = Parameters::RECORD;
214 break;
215 default:
216 ALOGE("%s: Camera %d: Still image produced unexpectedly "
217 "in state %s!",
218 __FUNCTION__, client->getCameraId(),
219 Parameters::getStateName(l.mParameters.state));
220 }
221
222 return IDLE;
223}
224
225CaptureSequencer::CaptureState CaptureSequencer::manageStart(
226 sp<Camera2Client> &client) {
James Painterc3dbf1a2012-09-05 18:02:32 -0700227 ALOGV("%s", __FUNCTION__);
Eino-Ville Talvala69230df2012-08-29 17:37:16 -0700228 status_t res;
229 ATRACE_CALL();
230 SharedParameters::Lock l(client->getParameters());
231 CaptureState nextState = DONE;
232
233 res = updateCaptureRequest(l.mParameters, client);
234 if (res != OK ) {
235 ALOGE("%s: Camera %d: Can't update still image capture request: %s (%d)",
236 __FUNCTION__, client->getCameraId(), strerror(-res), res);
237 return DONE;
238 }
239
James Painterc3dbf1a2012-09-05 18:02:32 -0700240 if(l.mParameters.lightFx != Parameters::LIGHTFX_NONE &&
241 l.mParameters.state == Parameters::STILL_CAPTURE) {
242 nextState = BURST_CAPTURE_START;
243 }
244 else if (l.mParameters.zslMode &&
Eino-Ville Talvala69230df2012-08-29 17:37:16 -0700245 l.mParameters.state == Parameters::STILL_CAPTURE) {
246 nextState = ZSL_START;
247 } else {
248 nextState = STANDARD_START;
249 }
250
251 return nextState;
252}
253
254CaptureSequencer::CaptureState CaptureSequencer::manageZslStart(
255 sp<Camera2Client> &client) {
Eino-Ville Talvala2954fe92012-09-12 10:42:10 -0700256 ALOGV("%s", __FUNCTION__);
Eino-Ville Talvala69230df2012-08-29 17:37:16 -0700257 status_t res;
258 sp<ZslProcessor> processor = mZslProcessor.promote();
259 if (processor == 0) {
260 ALOGE("%s: No ZSL queue to use!", __FUNCTION__);
261 return DONE;
262 }
263
264 client->registerFrameListener(mCaptureId,
265 this);
266
267 res = client->getCameraDevice()->clearStreamingRequest();
268 if (res != OK) {
269 ALOGE("%s: Camera %d: Unable to stop preview for ZSL capture: "
270 "%s (%d)",
271 __FUNCTION__, client->getCameraId(), strerror(-res), res);
272 return DONE;
273 }
274 // TODO: Actually select the right thing here.
Eino-Ville Talvala2954fe92012-09-12 10:42:10 -0700275 res = processor->pushToReprocess(mCaptureId);
276 if (res != OK) {
Eino-Ville Talvala22745492012-09-17 17:55:07 -0700277 if (res == NOT_ENOUGH_DATA) {
278 ALOGV("%s: Camera %d: ZSL queue doesn't have good frame, "
279 "falling back to normal capture", __FUNCTION__,
280 client->getCameraId());
281 } else {
282 ALOGE("%s: Camera %d: Error in ZSL queue: %s (%d)",
283 __FUNCTION__, client->getCameraId(), strerror(-res), res);
284 }
Eino-Ville Talvala2954fe92012-09-12 10:42:10 -0700285 return STANDARD_START;
286 }
Eino-Ville Talvala69230df2012-08-29 17:37:16 -0700287
Eino-Ville Talvalaa4247b82012-09-19 17:12:50 -0700288 SharedParameters::Lock l(client->getParameters());
289 if (l.mParameters.playShutterSound) {
290 client->getCameraService()->playSound(CameraService::SOUND_SHUTTER);
291 }
292
Eino-Ville Talvala69230df2012-08-29 17:37:16 -0700293 mTimeoutCount = kMaxTimeoutsForCaptureEnd;
294 return STANDARD_CAPTURE_WAIT;
295}
296
297CaptureSequencer::CaptureState CaptureSequencer::manageZslWaiting(
298 sp<Camera2Client> &client) {
Eino-Ville Talvala2954fe92012-09-12 10:42:10 -0700299 ALOGV("%s", __FUNCTION__);
Eino-Ville Talvala69230df2012-08-29 17:37:16 -0700300 return DONE;
301}
302
303CaptureSequencer::CaptureState CaptureSequencer::manageZslReprocessing(
304 sp<Camera2Client> &client) {
Eino-Ville Talvala2954fe92012-09-12 10:42:10 -0700305 ALOGV("%s", __FUNCTION__);
Eino-Ville Talvala69230df2012-08-29 17:37:16 -0700306 return START;
307}
308
309CaptureSequencer::CaptureState CaptureSequencer::manageStandardStart(
310 sp<Camera2Client> &client) {
311 ATRACE_CALL();
312 client->registerFrameListener(mCaptureId,
313 this);
314 {
315 SharedParameters::Lock l(client->getParameters());
316 mTriggerId = l.mParameters.precaptureTriggerCounter++;
317 }
318 client->getCameraDevice()->triggerPrecaptureMetering(mTriggerId);
319
320 mAeInPrecapture = false;
321 mTimeoutCount = kMaxTimeoutsForPrecaptureStart;
322 return STANDARD_PRECAPTURE_WAIT;
323}
324
325CaptureSequencer::CaptureState CaptureSequencer::manageStandardPrecaptureWait(
326 sp<Camera2Client> &client) {
327 status_t res;
328 ATRACE_CALL();
329 Mutex::Autolock l(mInputMutex);
330 while (!mNewAEState) {
331 res = mNewNotifySignal.waitRelative(mInputMutex, kWaitDuration);
332 if (res == TIMED_OUT) {
333 mTimeoutCount--;
334 break;
335 }
336 }
337 if (mTimeoutCount <= 0) {
338 ALOGW("Timed out waiting for precapture %s",
339 mAeInPrecapture ? "end" : "start");
340 return STANDARD_CAPTURE;
341 }
342 if (mNewAEState) {
343 if (!mAeInPrecapture) {
344 // Waiting to see PRECAPTURE state
345 if (mAETriggerId == mTriggerId &&
346 mAEState == ANDROID_CONTROL_AE_STATE_PRECAPTURE) {
347 ALOGV("%s: Got precapture start", __FUNCTION__);
348 mAeInPrecapture = true;
349 mTimeoutCount = kMaxTimeoutsForPrecaptureEnd;
350 }
351 } else {
352 // Waiting to see PRECAPTURE state end
353 if (mAETriggerId == mTriggerId &&
354 mAEState != ANDROID_CONTROL_AE_STATE_PRECAPTURE) {
355 ALOGV("%s: Got precapture end", __FUNCTION__);
356 return STANDARD_CAPTURE;
357 }
358 }
359 mNewAEState = false;
360 }
361 return STANDARD_PRECAPTURE_WAIT;
362}
363
364CaptureSequencer::CaptureState CaptureSequencer::manageStandardCapture(
365 sp<Camera2Client> &client) {
366 status_t res;
367 ATRACE_CALL();
368 SharedParameters::Lock l(client->getParameters());
369 Vector<uint8_t> outputStreams;
370
371 outputStreams.push(client->getPreviewStreamId());
372 outputStreams.push(client->getCaptureStreamId());
373
374 if (l.mParameters.previewCallbackFlags &
375 CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK) {
376 outputStreams.push(client->getCallbackStreamId());
377 }
378
379 if (l.mParameters.state == Parameters::VIDEO_SNAPSHOT) {
380 outputStreams.push(client->getRecordingStreamId());
381 }
382
383 res = mCaptureRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS,
384 outputStreams);
385 if (res == OK) {
386 res = mCaptureRequest.update(ANDROID_REQUEST_ID,
387 &mCaptureId, 1);
388 }
389 if (res == OK) {
390 res = mCaptureRequest.sort();
391 }
392
393 if (res != OK) {
394 ALOGE("%s: Camera %d: Unable to set up still capture request: %s (%d)",
395 __FUNCTION__, client->getCameraId(), strerror(-res), res);
396 return DONE;
397 }
398
399 CameraMetadata captureCopy = mCaptureRequest;
400 if (captureCopy.entryCount() == 0) {
401 ALOGE("%s: Camera %d: Unable to copy capture request for HAL device",
402 __FUNCTION__, client->getCameraId());
403 return DONE;
404 }
405
406 if (l.mParameters.state == Parameters::STILL_CAPTURE) {
407 res = client->getCameraDevice()->clearStreamingRequest();
408 if (res != OK) {
409 ALOGE("%s: Camera %d: Unable to stop preview for still capture: "
410 "%s (%d)",
411 __FUNCTION__, client->getCameraId(), strerror(-res), res);
412 return DONE;
413 }
414 }
415 // TODO: Capture should be atomic with setStreamingRequest here
416 res = client->getCameraDevice()->capture(captureCopy);
417 if (res != OK) {
418 ALOGE("%s: Camera %d: Unable to submit still image capture request: "
419 "%s (%d)",
420 __FUNCTION__, client->getCameraId(), strerror(-res), res);
421 return DONE;
422 }
423
Eino-Ville Talvalabd3a8162012-09-15 13:27:52 -0700424 if (l.mParameters.playShutterSound &&
425 l.mParameters.state == Parameters::STILL_CAPTURE) {
Eino-Ville Talvala33578832012-09-06 18:26:58 -0700426 client->getCameraService()->playSound(CameraService::SOUND_SHUTTER);
427 }
428
Eino-Ville Talvala69230df2012-08-29 17:37:16 -0700429 mTimeoutCount = kMaxTimeoutsForCaptureEnd;
430 return STANDARD_CAPTURE_WAIT;
431}
432
433CaptureSequencer::CaptureState CaptureSequencer::manageStandardCaptureWait(
434 sp<Camera2Client> &client) {
435 status_t res;
436 ATRACE_CALL();
437 Mutex::Autolock l(mInputMutex);
438 while (!mNewFrameReceived) {
439 res = mNewFrameSignal.waitRelative(mInputMutex, kWaitDuration);
440 if (res == TIMED_OUT) {
441 mTimeoutCount--;
442 break;
443 }
444 }
445 while (!mNewCaptureReceived) {
446 res = mNewCaptureSignal.waitRelative(mInputMutex, kWaitDuration);
447 if (res == TIMED_OUT) {
448 mTimeoutCount--;
449 break;
450 }
451 }
452 if (mTimeoutCount <= 0) {
453 ALOGW("Timed out waiting for capture to complete");
454 return DONE;
455 }
456 if (mNewFrameReceived && mNewCaptureReceived) {
457 if (mNewFrameId != mCaptureId) {
458 ALOGW("Mismatched capture frame IDs: Expected %d, got %d",
459 mCaptureId, mNewFrameId);
460 }
461 camera_metadata_entry_t entry;
462 entry = mNewFrame.find(ANDROID_SENSOR_TIMESTAMP);
463 if (entry.count == 0) {
464 ALOGE("No timestamp field in capture frame!");
465 }
466 if (entry.data.i64[0] != mCaptureTimestamp) {
467 ALOGW("Mismatched capture timestamps: Metadata frame %lld,"
468 " captured buffer %lld", entry.data.i64[0], mCaptureTimestamp);
469 }
470 client->removeFrameListener(mCaptureId);
471
472 mNewFrameReceived = false;
473 mNewCaptureReceived = false;
474 return DONE;
475 }
476 return STANDARD_CAPTURE_WAIT;
477}
478
James Painterc3dbf1a2012-09-05 18:02:32 -0700479CaptureSequencer::CaptureState CaptureSequencer::manageBurstCaptureStart(
480 sp<Camera2Client> &client) {
481 ALOGV("%s", __FUNCTION__);
482 status_t res;
483 ATRACE_CALL();
484
485 // check which burst mode is set, create respective burst object
486 {
487 SharedParameters::Lock l(client->getParameters());
488
489 res = updateCaptureRequest(l.mParameters, client);
490 if(res != OK) {
491 return DONE;
492 }
493
494 //
495 // check for burst mode type in mParameters here
496 //
497 mBurstCapture = new BurstCapture(client, this);
498 }
499
500 res = mCaptureRequest.update(ANDROID_REQUEST_ID, &mCaptureId, 1);
501 if (res == OK) {
502 res = mCaptureRequest.sort();
503 }
504 if (res != OK) {
505 ALOGE("%s: Camera %d: Unable to set up still capture request: %s (%d)",
506 __FUNCTION__, client->getCameraId(), strerror(-res), res);
507 return DONE;
508 }
509
510 CameraMetadata captureCopy = mCaptureRequest;
511 if (captureCopy.entryCount() == 0) {
512 ALOGE("%s: Camera %d: Unable to copy capture request for HAL device",
513 __FUNCTION__, client->getCameraId());
514 return DONE;
515 }
516
517 Vector<CameraMetadata> requests;
518 requests.push(mCaptureRequest);
519 res = mBurstCapture->start(requests, mCaptureId);
520 mTimeoutCount = kMaxTimeoutsForCaptureEnd * 10;
521 return BURST_CAPTURE_WAIT;
522}
523
524CaptureSequencer::CaptureState CaptureSequencer::manageBurstCaptureWait(
525 sp<Camera2Client> &client) {
526 status_t res;
527 ATRACE_CALL();
528
529 while (!mNewCaptureReceived) {
530 res = mNewCaptureSignal.waitRelative(mInputMutex, kWaitDuration);
531 if (res == TIMED_OUT) {
532 mTimeoutCount--;
533 break;
534 }
535 }
536
537 if (mTimeoutCount <= 0) {
538 ALOGW("Timed out waiting for burst capture to complete");
539 return DONE;
540 }
541 if (mNewCaptureReceived) {
542 mNewCaptureReceived = false;
543 // TODO: update mCaptureId to last burst's capture ID + 1?
544 return DONE;
545 }
546
547 return BURST_CAPTURE_WAIT;
548}
549
Eino-Ville Talvala69230df2012-08-29 17:37:16 -0700550status_t CaptureSequencer::updateCaptureRequest(const Parameters &params,
551 sp<Camera2Client> &client) {
552 ATRACE_CALL();
553 status_t res;
554 if (mCaptureRequest.entryCount() == 0) {
555 res = client->getCameraDevice()->createDefaultRequest(
556 CAMERA2_TEMPLATE_STILL_CAPTURE,
557 &mCaptureRequest);
558 if (res != OK) {
559 ALOGE("%s: Camera %d: Unable to create default still image request:"
560 " %s (%d)", __FUNCTION__, client->getCameraId(),
561 strerror(-res), res);
562 return res;
563 }
564 }
565
566 res = params.updateRequest(&mCaptureRequest);
567 if (res != OK) {
568 ALOGE("%s: Camera %d: Unable to update common entries of capture "
569 "request: %s (%d)", __FUNCTION__, client->getCameraId(),
570 strerror(-res), res);
571 return res;
572 }
573
574 res = mCaptureRequest.update(ANDROID_JPEG_THUMBNAIL_SIZE,
575 params.jpegThumbSize, 2);
576 if (res != OK) return res;
577 res = mCaptureRequest.update(ANDROID_JPEG_THUMBNAIL_QUALITY,
578 &params.jpegThumbQuality, 1);
579 if (res != OK) return res;
580 res = mCaptureRequest.update(ANDROID_JPEG_QUALITY,
581 &params.jpegQuality, 1);
582 if (res != OK) return res;
583 res = mCaptureRequest.update(
584 ANDROID_JPEG_ORIENTATION,
585 &params.jpegRotation, 1);
586 if (res != OK) return res;
587
588 if (params.gpsEnabled) {
589 res = mCaptureRequest.update(
590 ANDROID_JPEG_GPS_COORDINATES,
591 params.gpsCoordinates, 3);
592 if (res != OK) return res;
593 res = mCaptureRequest.update(
594 ANDROID_JPEG_GPS_TIMESTAMP,
595 &params.gpsTimestamp, 1);
596 if (res != OK) return res;
597 res = mCaptureRequest.update(
598 ANDROID_JPEG_GPS_PROCESSING_METHOD,
599 params.gpsProcessingMethod);
600 if (res != OK) return res;
601 } else {
602 res = mCaptureRequest.erase(ANDROID_JPEG_GPS_COORDINATES);
603 if (res != OK) return res;
604 res = mCaptureRequest.erase(ANDROID_JPEG_GPS_TIMESTAMP);
605 if (res != OK) return res;
606 res = mCaptureRequest.erase(ANDROID_JPEG_GPS_PROCESSING_METHOD);
607 if (res != OK) return res;
608 }
609
610 return OK;
611}
612
613
614}; // namespace camera2
615}; // namespace android