StreamingProcessor.cpp revision 4865c526e681366481b0ab242ffa1ead57bb02cc
1/* 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 "Camera2-StreamingProcessor" 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 <gui/SurfaceTextureClient.h> 24#include <media/hardware/MetadataBufferType.h> 25 26#include "StreamingProcessor.h" 27#include "Camera2Heap.h" 28#include "../Camera2Client.h" 29#include "../Camera2Device.h" 30 31namespace android { 32namespace camera2 { 33 34StreamingProcessor::StreamingProcessor(wp<Camera2Client> client): 35 mClient(client), 36 mActiveRequest(NONE), 37 mPreviewRequestId(Camera2Client::kPreviewRequestIdStart), 38 mPreviewStreamId(NO_STREAM), 39 mRecordingRequestId(Camera2Client::kRecordingRequestIdStart), 40 mRecordingStreamId(NO_STREAM), 41 mRecordingHeapCount(kDefaultRecordingHeapCount) 42{ 43 44} 45 46StreamingProcessor::~StreamingProcessor() { 47 deletePreviewStream(); 48 deleteRecordingStream(); 49} 50 51status_t StreamingProcessor::setPreviewWindow(sp<ANativeWindow> window) { 52 ATRACE_CALL(); 53 status_t res; 54 55 res = deletePreviewStream(); 56 if (res != OK) return res; 57 58 Mutex::Autolock m(mMutex); 59 60 mPreviewWindow = window; 61 62 return OK; 63} 64 65bool StreamingProcessor::haveValidPreviewWindow() const { 66 Mutex::Autolock m(mMutex); 67 return mPreviewWindow != 0; 68} 69 70status_t StreamingProcessor::updatePreviewRequest(const Parameters ¶ms) { 71 ATRACE_CALL(); 72 status_t res; 73 sp<Camera2Client> client = mClient.promote(); 74 if (client == 0) return INVALID_OPERATION; 75 76 Mutex::Autolock m(mMutex); 77 if (mPreviewRequest.entryCount() == 0) { 78 res = client->getCameraDevice()->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW, 79 &mPreviewRequest); 80 if (res != OK) { 81 ALOGE("%s: Camera %d: Unable to create default preview request: " 82 "%s (%d)", __FUNCTION__, client->getCameraId(), strerror(-res), res); 83 return res; 84 } 85 } 86 87 res = params.updateRequest(&mPreviewRequest); 88 if (res != OK) { 89 ALOGE("%s: Camera %d: Unable to update common entries of preview " 90 "request: %s (%d)", __FUNCTION__, client->getCameraId(), 91 strerror(-res), res); 92 return res; 93 } 94 95 res = mPreviewRequest.update(ANDROID_REQUEST_ID, 96 &mPreviewRequestId, 1); 97 if (res != OK) { 98 ALOGE("%s: Camera %d: Unable to update request id for preview: %s (%d)", 99 __FUNCTION__, client->getCameraId(), strerror(-res), res); 100 return res; 101 } 102 103 return OK; 104} 105 106status_t StreamingProcessor::updatePreviewStream(const Parameters ¶ms) { 107 ATRACE_CALL(); 108 Mutex::Autolock m(mMutex); 109 110 status_t res; 111 sp<Camera2Client> client = mClient.promote(); 112 if (client == 0) return INVALID_OPERATION; 113 sp<Camera2Device> device = client->getCameraDevice(); 114 115 if (mPreviewStreamId != NO_STREAM) { 116 // Check if stream parameters have to change 117 uint32_t currentWidth, currentHeight; 118 res = device->getStreamInfo(mPreviewStreamId, 119 ¤tWidth, ¤tHeight, 0); 120 if (res != OK) { 121 ALOGE("%s: Camera %d: Error querying preview stream info: " 122 "%s (%d)", __FUNCTION__, client->getCameraId(), strerror(-res), res); 123 return res; 124 } 125 if (currentWidth != (uint32_t)params.previewWidth || 126 currentHeight != (uint32_t)params.previewHeight) { 127 ALOGV("%s: Camera %d: Preview size switch: %d x %d -> %d x %d", 128 __FUNCTION__, client->getCameraId(), currentWidth, currentHeight, 129 params.previewWidth, params.previewHeight); 130 res = device->waitUntilDrained(); 131 if (res != OK) { 132 ALOGE("%s: Camera %d: Error waiting for preview to drain: " 133 "%s (%d)", __FUNCTION__, client->getCameraId(), strerror(-res), res); 134 return res; 135 } 136 res = device->deleteStream(mPreviewStreamId); 137 if (res != OK) { 138 ALOGE("%s: Camera %d: Unable to delete old output stream " 139 "for preview: %s (%d)", __FUNCTION__, client->getCameraId(), 140 strerror(-res), res); 141 return res; 142 } 143 mPreviewStreamId = NO_STREAM; 144 } 145 } 146 147 if (mPreviewStreamId == NO_STREAM) { 148 res = device->createStream(mPreviewWindow, 149 params.previewWidth, params.previewHeight, 150 CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, 0, 151 &mPreviewStreamId); 152 if (res != OK) { 153 ALOGE("%s: Camera %d: Unable to create preview stream: %s (%d)", 154 __FUNCTION__, client->getCameraId(), strerror(-res), res); 155 return res; 156 } 157 } 158 159 res = device->setStreamTransform(mPreviewStreamId, 160 params.previewTransform); 161 if (res != OK) { 162 ALOGE("%s: Camera %d: Unable to set preview stream transform: " 163 "%s (%d)", __FUNCTION__, client->getCameraId(), strerror(-res), res); 164 return res; 165 } 166 167 return OK; 168} 169 170status_t StreamingProcessor::deletePreviewStream() { 171 ATRACE_CALL(); 172 status_t res; 173 174 Mutex::Autolock m(mMutex); 175 176 if (mPreviewStreamId != NO_STREAM) { 177 sp<Camera2Client> client = mClient.promote(); 178 if (client == 0) return INVALID_OPERATION; 179 sp<Camera2Device> device = client->getCameraDevice(); 180 181 ALOGV("%s: for cameraId %d on streamId %d", 182 __FUNCTION__, client->getCameraId(), mPreviewStreamId); 183 184 res = device->waitUntilDrained(); 185 if (res != OK) { 186 ALOGE("%s: Error waiting for preview to drain: %s (%d)", 187 __FUNCTION__, strerror(-res), res); 188 return res; 189 } 190 res = device->deleteStream(mPreviewStreamId); 191 if (res != OK) { 192 ALOGE("%s: Unable to delete old preview stream: %s (%d)", 193 __FUNCTION__, strerror(-res), res); 194 return res; 195 } 196 mPreviewStreamId = NO_STREAM; 197 } 198 return OK; 199} 200 201int StreamingProcessor::getPreviewStreamId() const { 202 Mutex::Autolock m(mMutex); 203 return mPreviewStreamId; 204} 205 206status_t StreamingProcessor::setRecordingBufferCount(size_t count) { 207 ATRACE_CALL(); 208 // 32 is the current upper limit on the video buffer count for BufferQueue 209 sp<Camera2Client> client = mClient.promote(); 210 if (client == 0) return INVALID_OPERATION; 211 if (count > 32) { 212 ALOGE("%s: Camera %d: Error setting %d as video buffer count value", 213 __FUNCTION__, client->getCameraId(), count); 214 return BAD_VALUE; 215 } 216 217 Mutex::Autolock m(mMutex); 218 219 // Need to reallocate memory for heap 220 if (mRecordingHeapCount != count) { 221 if (mRecordingHeap != 0) { 222 mRecordingHeap.clear(); 223 mRecordingHeap = NULL; 224 } 225 mRecordingHeapCount = count; 226 } 227 228 return OK; 229} 230 231status_t StreamingProcessor::updateRecordingRequest(const Parameters ¶ms) { 232 ATRACE_CALL(); 233 status_t res; 234 Mutex::Autolock m(mMutex); 235 236 sp<Camera2Client> client = mClient.promote(); 237 if (client == 0) return INVALID_OPERATION; 238 239 if (mRecordingRequest.entryCount() == 0) { 240 res = client->getCameraDevice()->createDefaultRequest(CAMERA2_TEMPLATE_VIDEO_RECORD, 241 &mRecordingRequest); 242 if (res != OK) { 243 ALOGE("%s: Camera %d: Unable to create default recording request:" 244 " %s (%d)", __FUNCTION__, client->getCameraId(), strerror(-res), res); 245 return res; 246 } 247 } 248 249 res = params.updateRequest(&mRecordingRequest); 250 if (res != OK) { 251 ALOGE("%s: Camera %d: Unable to update common entries of recording " 252 "request: %s (%d)", __FUNCTION__, client->getCameraId(), 253 strerror(-res), res); 254 return res; 255 } 256 257 res = mRecordingRequest.update(ANDROID_REQUEST_ID, 258 &mRecordingRequestId, 1); 259 if (res != OK) { 260 ALOGE("%s: Camera %d: Unable to update request id for request: %s (%d)", 261 __FUNCTION__, client->getCameraId(), strerror(-res), res); 262 return res; 263 } 264 265 return OK; 266} 267 268status_t StreamingProcessor::updateRecordingStream(const Parameters ¶ms) { 269 ATRACE_CALL(); 270 status_t res; 271 Mutex::Autolock m(mMutex); 272 273 sp<Camera2Client> client = mClient.promote(); 274 if (client == 0) return INVALID_OPERATION; 275 sp<Camera2Device> device = client->getCameraDevice(); 276 277 if (mRecordingConsumer == 0) { 278 // Create CPU buffer queue endpoint. We need one more buffer here so that we can 279 // always acquire and free a buffer when the heap is full; otherwise the consumer 280 // will have buffers in flight we'll never clear out. 281 mRecordingConsumer = new BufferItemConsumer( 282 GRALLOC_USAGE_HW_VIDEO_ENCODER, 283 mRecordingHeapCount + 1, 284 true); 285 mRecordingConsumer->setFrameAvailableListener(this); 286 mRecordingConsumer->setName(String8("Camera2-RecordingConsumer")); 287 mRecordingWindow = new SurfaceTextureClient( 288 mRecordingConsumer->getProducerInterface()); 289 // Allocate memory later, since we don't know buffer size until receipt 290 } 291 292 if (mRecordingStreamId != NO_STREAM) { 293 // Check if stream parameters have to change 294 uint32_t currentWidth, currentHeight; 295 res = device->getStreamInfo(mRecordingStreamId, 296 ¤tWidth, ¤tHeight, 0); 297 if (res != OK) { 298 ALOGE("%s: Camera %d: Error querying recording output stream info: " 299 "%s (%d)", __FUNCTION__, client->getCameraId(), 300 strerror(-res), res); 301 return res; 302 } 303 if (currentWidth != (uint32_t)params.videoWidth || 304 currentHeight != (uint32_t)params.videoHeight) { 305 // TODO: Should wait to be sure previous recording has finished 306 res = device->deleteStream(mRecordingStreamId); 307 if (res != OK) { 308 ALOGE("%s: Camera %d: Unable to delete old output stream " 309 "for recording: %s (%d)", __FUNCTION__, 310 client->getCameraId(), strerror(-res), res); 311 return res; 312 } 313 mRecordingStreamId = NO_STREAM; 314 } 315 } 316 317 if (mRecordingStreamId == NO_STREAM) { 318 mRecordingFrameCount = 0; 319 res = device->createStream(mRecordingWindow, 320 params.videoWidth, params.videoHeight, 321 CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, 0, &mRecordingStreamId); 322 if (res != OK) { 323 ALOGE("%s: Camera %d: Can't create output stream for recording: " 324 "%s (%d)", __FUNCTION__, client->getCameraId(), 325 strerror(-res), res); 326 return res; 327 } 328 } 329 330 return OK; 331} 332 333status_t StreamingProcessor::deleteRecordingStream() { 334 ATRACE_CALL(); 335 status_t res; 336 337 Mutex::Autolock m(mMutex); 338 339 if (mRecordingStreamId != NO_STREAM) { 340 sp<Camera2Client> client = mClient.promote(); 341 if (client == 0) return INVALID_OPERATION; 342 sp<Camera2Device> device = client->getCameraDevice(); 343 344 res = device->waitUntilDrained(); 345 if (res != OK) { 346 ALOGE("%s: Error waiting for HAL to drain: %s (%d)", 347 __FUNCTION__, strerror(-res), res); 348 return res; 349 } 350 res = device->deleteStream(mRecordingStreamId); 351 if (res != OK) { 352 ALOGE("%s: Unable to delete recording stream: %s (%d)", 353 __FUNCTION__, strerror(-res), res); 354 return res; 355 } 356 mRecordingStreamId = NO_STREAM; 357 } 358 return OK; 359} 360 361int StreamingProcessor::getRecordingStreamId() const { 362 return mRecordingStreamId; 363} 364 365status_t StreamingProcessor::startStream(StreamType type, 366 const Vector<uint8_t> &outputStreams) { 367 ATRACE_CALL(); 368 status_t res; 369 370 if (type == NONE) return INVALID_OPERATION; 371 372 sp<Camera2Client> client = mClient.promote(); 373 if (client == 0) return INVALID_OPERATION; 374 375 ALOGV("%s: Camera %d: type = %d", __FUNCTION__, client->getCameraId(), type); 376 377 Mutex::Autolock m(mMutex); 378 379 CameraMetadata &request = (type == PREVIEW) ? 380 mPreviewRequest : mRecordingRequest; 381 382 res = request.update( 383 ANDROID_REQUEST_OUTPUT_STREAMS, 384 outputStreams); 385 if (res != OK) { 386 ALOGE("%s: Camera %d: Unable to set up preview request: %s (%d)", 387 __FUNCTION__, client->getCameraId(), strerror(-res), res); 388 return res; 389 } 390 391 res = request.sort(); 392 if (res != OK) { 393 ALOGE("%s: Camera %d: Error sorting preview request: %s (%d)", 394 __FUNCTION__, client->getCameraId(), strerror(-res), res); 395 return res; 396 } 397 398 res = client->getCameraDevice()->setStreamingRequest(request); 399 if (res != OK) { 400 ALOGE("%s: Camera %d: Unable to set preview request to start preview: " 401 "%s (%d)", 402 __FUNCTION__, client->getCameraId(), strerror(-res), res); 403 return res; 404 } 405 mActiveRequest = type; 406 407 return OK; 408} 409 410status_t StreamingProcessor::stopStream() { 411 ATRACE_CALL(); 412 status_t res; 413 414 Mutex::Autolock m(mMutex); 415 416 sp<Camera2Client> client = mClient.promote(); 417 if (client == 0) return INVALID_OPERATION; 418 sp<Camera2Device> device = client->getCameraDevice(); 419 420 res = device->clearStreamingRequest(); 421 if (res != OK) { 422 ALOGE("%s: Camera %d: Can't clear stream request: %s (%d)", 423 __FUNCTION__, client->getCameraId(), strerror(-res), res); 424 return res; 425 } 426 mActiveRequest = NONE; 427 428 return OK; 429} 430 431int32_t StreamingProcessor::getActiveRequestId() const { 432 Mutex::Autolock m(mMutex); 433 switch (mActiveRequest) { 434 case NONE: 435 return 0; 436 case PREVIEW: 437 return mPreviewRequestId; 438 case RECORD: 439 return mRecordingRequestId; 440 default: 441 ALOGE("%s: Unexpected mode %d", __FUNCTION__, mActiveRequest); 442 return 0; 443 } 444} 445 446status_t StreamingProcessor::incrementStreamingIds() { 447 ATRACE_CALL(); 448 Mutex::Autolock m(mMutex); 449 450 status_t res; 451 mPreviewRequestId++; 452 if (mPreviewRequestId >= Camera2Client::kPreviewRequestIdEnd) { 453 mPreviewRequestId = Camera2Client::kPreviewRequestIdStart; 454 } 455 mRecordingRequestId++; 456 if (mRecordingRequestId >= Camera2Client::kRecordingRequestIdEnd) { 457 mRecordingRequestId = Camera2Client::kRecordingRequestIdStart; 458 } 459 return OK; 460} 461 462void StreamingProcessor::onFrameAvailable() { 463 ATRACE_CALL(); 464 status_t res; 465 sp<Camera2Heap> recordingHeap; 466 size_t heapIdx = 0; 467 nsecs_t timestamp; 468 469 sp<Camera2Client> client = mClient.promote(); 470 if (client == 0) return; 471 472 { 473 /* acquire SharedParameters before mMutex so we don't dead lock 474 with Camera2Client code calling into StreamingProcessor */ 475 SharedParameters::Lock l(client->getParameters()); 476 Mutex::Autolock m(mMutex); 477 BufferItemConsumer::BufferItem imgBuffer; 478 res = mRecordingConsumer->acquireBuffer(&imgBuffer); 479 if (res != OK) { 480 ALOGE("%s: Camera %d: Error receiving recording buffer: %s (%d)", 481 __FUNCTION__, client->getCameraId(), strerror(-res), res); 482 return; 483 } 484 timestamp = imgBuffer.mTimestamp; 485 486 mRecordingFrameCount++; 487 ALOGV("OnRecordingFrame: Frame %d", mRecordingFrameCount); 488 489 // TODO: Signal errors here upstream 490 if (l.mParameters.state != Parameters::RECORD && 491 l.mParameters.state != Parameters::VIDEO_SNAPSHOT) { 492 ALOGV("%s: Camera %d: Discarding recording image buffers " 493 "received after recording done", __FUNCTION__, 494 client->getCameraId()); 495 mRecordingConsumer->releaseBuffer(imgBuffer); 496 return; 497 } 498 499 if (mRecordingHeap == 0) { 500 const size_t bufferSize = 4 + sizeof(buffer_handle_t); 501 ALOGV("%s: Camera %d: Creating recording heap with %d buffers of " 502 "size %d bytes", __FUNCTION__, client->getCameraId(), 503 mRecordingHeapCount, bufferSize); 504 505 mRecordingHeap = new Camera2Heap(bufferSize, mRecordingHeapCount, 506 "Camera2Client::RecordingHeap"); 507 if (mRecordingHeap->mHeap->getSize() == 0) { 508 ALOGE("%s: Camera %d: Unable to allocate memory for recording", 509 __FUNCTION__, client->getCameraId()); 510 mRecordingConsumer->releaseBuffer(imgBuffer); 511 return; 512 } 513 for (size_t i = 0; i < mRecordingBuffers.size(); i++) { 514 if (mRecordingBuffers[i].mBuf != 515 BufferItemConsumer::INVALID_BUFFER_SLOT) { 516 ALOGE("%s: Camera %d: Non-empty recording buffers list!", 517 __FUNCTION__, client->getCameraId()); 518 } 519 } 520 mRecordingBuffers.clear(); 521 mRecordingBuffers.setCapacity(mRecordingHeapCount); 522 mRecordingBuffers.insertAt(0, mRecordingHeapCount); 523 524 mRecordingHeapHead = 0; 525 mRecordingHeapFree = mRecordingHeapCount; 526 } 527 528 if ( mRecordingHeapFree == 0) { 529 ALOGE("%s: Camera %d: No free recording buffers, dropping frame", 530 __FUNCTION__, client->getCameraId()); 531 mRecordingConsumer->releaseBuffer(imgBuffer); 532 return; 533 } 534 535 heapIdx = mRecordingHeapHead; 536 mRecordingHeapHead = (mRecordingHeapHead + 1) % mRecordingHeapCount; 537 mRecordingHeapFree--; 538 539 ALOGV("%s: Camera %d: Timestamp %lld", 540 __FUNCTION__, client->getCameraId(), timestamp); 541 542 ssize_t offset; 543 size_t size; 544 sp<IMemoryHeap> heap = 545 mRecordingHeap->mBuffers[heapIdx]->getMemory(&offset, 546 &size); 547 548 uint8_t *data = (uint8_t*)heap->getBase() + offset; 549 uint32_t type = kMetadataBufferTypeGrallocSource; 550 *((uint32_t*)data) = type; 551 *((buffer_handle_t*)(data + 4)) = imgBuffer.mGraphicBuffer->handle; 552 ALOGV("%s: Camera %d: Sending out buffer_handle_t %p", 553 __FUNCTION__, client->getCameraId(), 554 imgBuffer.mGraphicBuffer->handle); 555 mRecordingBuffers.replaceAt(imgBuffer, heapIdx); 556 recordingHeap = mRecordingHeap; 557 } 558 559 // Call outside locked parameters to allow re-entrancy from notification 560 Camera2Client::SharedCameraClient::Lock l(client->mSharedCameraClient); 561 if (l.mCameraClient != 0) { 562 l.mCameraClient->dataCallbackTimestamp(timestamp, 563 CAMERA_MSG_VIDEO_FRAME, 564 recordingHeap->mBuffers[heapIdx]); 565 } 566} 567 568void StreamingProcessor::releaseRecordingFrame(const sp<IMemory>& mem) { 569 ATRACE_CALL(); 570 status_t res; 571 572 sp<Camera2Client> client = mClient.promote(); 573 if (client == 0) return; 574 575 Mutex::Autolock m(mMutex); 576 // Make sure this is for the current heap 577 ssize_t offset; 578 size_t size; 579 sp<IMemoryHeap> heap = mem->getMemory(&offset, &size); 580 if (heap->getHeapID() != mRecordingHeap->mHeap->getHeapID()) { 581 ALOGW("%s: Camera %d: Mismatched heap ID, ignoring release " 582 "(got %x, expected %x)", __FUNCTION__, client->getCameraId(), 583 heap->getHeapID(), mRecordingHeap->mHeap->getHeapID()); 584 return; 585 } 586 uint8_t *data = (uint8_t*)heap->getBase() + offset; 587 uint32_t type = *(uint32_t*)data; 588 if (type != kMetadataBufferTypeGrallocSource) { 589 ALOGE("%s: Camera %d: Recording frame type invalid (got %x, expected %x)", 590 __FUNCTION__, client->getCameraId(), type, 591 kMetadataBufferTypeGrallocSource); 592 return; 593 } 594 595 // Release the buffer back to the recording queue 596 597 buffer_handle_t imgHandle = *(buffer_handle_t*)(data + 4); 598 599 size_t itemIndex; 600 for (itemIndex = 0; itemIndex < mRecordingBuffers.size(); itemIndex++) { 601 const BufferItemConsumer::BufferItem item = 602 mRecordingBuffers[itemIndex]; 603 if (item.mBuf != BufferItemConsumer::INVALID_BUFFER_SLOT && 604 item.mGraphicBuffer->handle == imgHandle) { 605 break; 606 } 607 } 608 if (itemIndex == mRecordingBuffers.size()) { 609 ALOGE("%s: Camera %d: Can't find buffer_handle_t %p in list of " 610 "outstanding buffers", __FUNCTION__, client->getCameraId(), 611 imgHandle); 612 return; 613 } 614 615 ALOGV("%s: Camera %d: Freeing buffer_handle_t %p", __FUNCTION__, 616 client->getCameraId(), imgHandle); 617 618 res = mRecordingConsumer->releaseBuffer(mRecordingBuffers[itemIndex]); 619 if (res != OK) { 620 ALOGE("%s: Camera %d: Unable to free recording frame " 621 "(buffer_handle_t: %p): %s (%d)", __FUNCTION__, 622 client->getCameraId(), imgHandle, strerror(-res), res); 623 return; 624 } 625 mRecordingBuffers.replaceAt(itemIndex); 626 627 mRecordingHeapFree++; 628} 629 630 631status_t StreamingProcessor::dump(int fd, const Vector<String16>& args) { 632 String8 result; 633 634 result.append(" Current requests:\n"); 635 if (mPreviewRequest.entryCount() != 0) { 636 result.append(" Preview request:\n"); 637 write(fd, result.string(), result.size()); 638 mPreviewRequest.dump(fd, 2, 6); 639 } else { 640 result.append(" Preview request: undefined\n"); 641 write(fd, result.string(), result.size()); 642 } 643 644 if (mRecordingRequest.entryCount() != 0) { 645 result = " Recording request:\n"; 646 write(fd, result.string(), result.size()); 647 mRecordingRequest.dump(fd, 2, 6); 648 } else { 649 result = " Recording request: undefined\n"; 650 write(fd, result.string(), result.size()); 651 } 652 653 return OK; 654} 655 656}; // namespace camera2 657}; // namespace android 658