/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "Camera2-StreamingProcessor" #define ATRACE_TAG ATRACE_TAG_CAMERA //#define LOG_NDEBUG 0 //#define LOG_NNDEBUG 0 // Per-frame verbose logging #ifdef LOG_NNDEBUG #define ALOGVV(...) ALOGV(__VA_ARGS__) #else #define ALOGVV(...) ((void)0) #endif #include #include #include #include #include #include #include "common/CameraDeviceBase.h" #include "api1/Camera2Client.h" #include "api1/client2/StreamingProcessor.h" #include "api1/client2/Camera2Heap.h" namespace android { namespace camera2 { StreamingProcessor::StreamingProcessor(sp client): mClient(client), mDevice(client->getCameraDevice()), mId(client->getCameraId()), mActiveRequest(NONE), mPaused(false), mPreviewRequestId(Camera2Client::kPreviewRequestIdStart), mPreviewStreamId(NO_STREAM), mRecordingRequestId(Camera2Client::kRecordingRequestIdStart), mRecordingStreamId(NO_STREAM), mRecordingFrameAvailable(false), mRecordingHeapCount(kDefaultRecordingHeapCount), mRecordingHeapFree(kDefaultRecordingHeapCount), mRecordingFormat(kDefaultRecordingFormat), mRecordingDataSpace(kDefaultRecordingDataSpace), mRecordingGrallocUsage(kDefaultRecordingGrallocUsage) { } StreamingProcessor::~StreamingProcessor() { deletePreviewStream(); deleteRecordingStream(); } status_t StreamingProcessor::setPreviewWindow(sp window) { ATRACE_CALL(); status_t res; res = deletePreviewStream(); if (res != OK) return res; Mutex::Autolock m(mMutex); mPreviewWindow = window; return OK; } bool StreamingProcessor::haveValidPreviewWindow() const { Mutex::Autolock m(mMutex); return mPreviewWindow != 0; } status_t StreamingProcessor::updatePreviewRequest(const Parameters ¶ms) { ATRACE_CALL(); status_t res; sp device = mDevice.promote(); if (device == 0) { ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId); return INVALID_OPERATION; } Mutex::Autolock m(mMutex); if (mPreviewRequest.entryCount() == 0) { sp client = mClient.promote(); if (client == 0) { ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId); return INVALID_OPERATION; } // Use CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG for ZSL streaming case. if (client->getCameraDeviceVersion() >= CAMERA_DEVICE_API_VERSION_3_0) { if (params.zslMode && !params.recordingHint) { res = device->createDefaultRequest(CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG, &mPreviewRequest); } else { res = device->createDefaultRequest(CAMERA3_TEMPLATE_PREVIEW, &mPreviewRequest); } } else { res = device->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW, &mPreviewRequest); } if (res != OK) { ALOGE("%s: Camera %d: Unable to create default preview request: " "%s (%d)", __FUNCTION__, mId, strerror(-res), res); return res; } } res = params.updateRequest(&mPreviewRequest); if (res != OK) { ALOGE("%s: Camera %d: Unable to update common entries of preview " "request: %s (%d)", __FUNCTION__, mId, strerror(-res), res); return res; } res = mPreviewRequest.update(ANDROID_REQUEST_ID, &mPreviewRequestId, 1); if (res != OK) { ALOGE("%s: Camera %d: Unable to update request id for preview: %s (%d)", __FUNCTION__, mId, strerror(-res), res); return res; } return OK; } status_t StreamingProcessor::updatePreviewStream(const Parameters ¶ms) { ATRACE_CALL(); Mutex::Autolock m(mMutex); status_t res; sp device = mDevice.promote(); if (device == 0) { ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId); return INVALID_OPERATION; } if (mPreviewStreamId != NO_STREAM) { // Check if stream parameters have to change uint32_t currentWidth, currentHeight; res = device->getStreamInfo(mPreviewStreamId, ¤tWidth, ¤tHeight, 0, 0); if (res != OK) { ALOGE("%s: Camera %d: Error querying preview stream info: " "%s (%d)", __FUNCTION__, mId, strerror(-res), res); return res; } if (currentWidth != (uint32_t)params.previewWidth || currentHeight != (uint32_t)params.previewHeight) { ALOGV("%s: Camera %d: Preview size switch: %d x %d -> %d x %d", __FUNCTION__, mId, currentWidth, currentHeight, params.previewWidth, params.previewHeight); res = device->waitUntilDrained(); if (res != OK) { ALOGE("%s: Camera %d: Error waiting for preview to drain: " "%s (%d)", __FUNCTION__, mId, strerror(-res), res); return res; } res = device->deleteStream(mPreviewStreamId); if (res != OK) { ALOGE("%s: Camera %d: Unable to delete old output stream " "for preview: %s (%d)", __FUNCTION__, mId, strerror(-res), res); return res; } mPreviewStreamId = NO_STREAM; } } if (mPreviewStreamId == NO_STREAM) { res = device->createStream(mPreviewWindow, params.previewWidth, params.previewHeight, CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, HAL_DATASPACE_UNKNOWN, CAMERA3_STREAM_ROTATION_0, &mPreviewStreamId); if (res != OK) { ALOGE("%s: Camera %d: Unable to create preview stream: %s (%d)", __FUNCTION__, mId, strerror(-res), res); return res; } } res = device->setStreamTransform(mPreviewStreamId, params.previewTransform); if (res != OK) { ALOGE("%s: Camera %d: Unable to set preview stream transform: " "%s (%d)", __FUNCTION__, mId, strerror(-res), res); return res; } return OK; } status_t StreamingProcessor::deletePreviewStream() { ATRACE_CALL(); status_t res; Mutex::Autolock m(mMutex); if (mPreviewStreamId != NO_STREAM) { sp device = mDevice.promote(); if (device == 0) { ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId); return INVALID_OPERATION; } ALOGV("%s: for cameraId %d on streamId %d", __FUNCTION__, mId, mPreviewStreamId); res = device->waitUntilDrained(); if (res != OK) { ALOGE("%s: Error waiting for preview to drain: %s (%d)", __FUNCTION__, strerror(-res), res); return res; } res = device->deleteStream(mPreviewStreamId); if (res != OK) { ALOGE("%s: Unable to delete old preview stream: %s (%d)", __FUNCTION__, strerror(-res), res); return res; } mPreviewStreamId = NO_STREAM; } return OK; } int StreamingProcessor::getPreviewStreamId() const { Mutex::Autolock m(mMutex); return mPreviewStreamId; } status_t StreamingProcessor::setRecordingBufferCount(size_t count) { ATRACE_CALL(); // Make sure we can support this many buffer slots if (count > BufferQueue::NUM_BUFFER_SLOTS) { ALOGE("%s: Camera %d: Too many recording buffers requested: %zu, max %d", __FUNCTION__, mId, count, BufferQueue::NUM_BUFFER_SLOTS); return BAD_VALUE; } Mutex::Autolock m(mMutex); ALOGV("%s: Camera %d: New recording buffer count from encoder: %zu", __FUNCTION__, mId, count); // Need to re-size consumer and heap if (mRecordingHeapCount != count) { ALOGV("%s: Camera %d: Resetting recording heap and consumer", __FUNCTION__, mId); if (isStreamActive(mActiveStreamIds, mRecordingStreamId)) { ALOGE("%s: Camera %d: Setting recording buffer count when " "recording stream is already active!", __FUNCTION__, mId); return INVALID_OPERATION; } releaseAllRecordingFramesLocked(); if (mRecordingHeap != 0) { mRecordingHeap.clear(); } mRecordingHeapCount = count; mRecordingHeapFree = count; mRecordingConsumer.clear(); } return OK; } status_t StreamingProcessor::setRecordingFormat(int format, android_dataspace dataSpace) { ATRACE_CALL(); Mutex::Autolock m(mMutex); ALOGV("%s: Camera %d: New recording format/dataspace from encoder: %X, %X", __FUNCTION__, mId, format, dataSpace); mRecordingFormat = format; mRecordingDataSpace = dataSpace; int prevGrallocUsage = mRecordingGrallocUsage; if (mRecordingFormat == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) { mRecordingGrallocUsage = GRALLOC_USAGE_HW_VIDEO_ENCODER; } else { mRecordingGrallocUsage = GRALLOC_USAGE_SW_READ_OFTEN; } ALOGV("%s: Camera %d: New recording gralloc usage: %08X", __FUNCTION__, mId, mRecordingGrallocUsage); if (prevGrallocUsage != mRecordingGrallocUsage) { ALOGV("%s: Camera %d: Resetting recording consumer for new usage", __FUNCTION__, mId); if (isStreamActive(mActiveStreamIds, mRecordingStreamId)) { ALOGE("%s: Camera %d: Changing recording format when " "recording stream is already active!", __FUNCTION__, mId); return INVALID_OPERATION; } releaseAllRecordingFramesLocked(); mRecordingConsumer.clear(); } return OK; } status_t StreamingProcessor::updateRecordingRequest(const Parameters ¶ms) { ATRACE_CALL(); status_t res; Mutex::Autolock m(mMutex); sp device = mDevice.promote(); if (device == 0) { ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId); return INVALID_OPERATION; } if (mRecordingRequest.entryCount() == 0) { res = device->createDefaultRequest(CAMERA2_TEMPLATE_VIDEO_RECORD, &mRecordingRequest); if (res != OK) { ALOGE("%s: Camera %d: Unable to create default recording request:" " %s (%d)", __FUNCTION__, mId, strerror(-res), res); return res; } } res = params.updateRequest(&mRecordingRequest); if (res != OK) { ALOGE("%s: Camera %d: Unable to update common entries of recording " "request: %s (%d)", __FUNCTION__, mId, strerror(-res), res); return res; } res = mRecordingRequest.update(ANDROID_REQUEST_ID, &mRecordingRequestId, 1); if (res != OK) { ALOGE("%s: Camera %d: Unable to update request id for request: %s (%d)", __FUNCTION__, mId, strerror(-res), res); return res; } return OK; } status_t StreamingProcessor::recordingStreamNeedsUpdate( const Parameters ¶ms, bool *needsUpdate) { status_t res; if (needsUpdate == 0) { ALOGE("%s: Camera %d: invalid argument", __FUNCTION__, mId); return INVALID_OPERATION; } if (mRecordingStreamId == NO_STREAM) { *needsUpdate = true; return OK; } sp device = mDevice.promote(); if (device == 0) { ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId); return INVALID_OPERATION; } uint32_t currentWidth, currentHeight, currentFormat; android_dataspace currentDataSpace; res = device->getStreamInfo(mRecordingStreamId, ¤tWidth, ¤tHeight, ¤tFormat, ¤tDataSpace); if (res != OK) { ALOGE("%s: Camera %d: Error querying recording output stream info: " "%s (%d)", __FUNCTION__, mId, strerror(-res), res); return res; } if (mRecordingConsumer == 0 || currentWidth != (uint32_t)params.videoWidth || currentHeight != (uint32_t)params.videoHeight || currentFormat != (uint32_t)mRecordingFormat || currentDataSpace != mRecordingDataSpace) { *needsUpdate = true; } *needsUpdate = false; return res; } status_t StreamingProcessor::updateRecordingStream(const Parameters ¶ms) { ATRACE_CALL(); status_t res; Mutex::Autolock m(mMutex); sp device = mDevice.promote(); if (device == 0) { ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId); return INVALID_OPERATION; } bool newConsumer = false; if (mRecordingConsumer == 0) { ALOGV("%s: Camera %d: Creating recording consumer with %zu + 1 " "consumer-side buffers", __FUNCTION__, mId, mRecordingHeapCount); // Create CPU buffer queue endpoint. We need one more buffer here so that we can // always acquire and free a buffer when the heap is full; otherwise the consumer // will have buffers in flight we'll never clear out. sp producer; sp consumer; BufferQueue::createBufferQueue(&producer, &consumer); mRecordingConsumer = new BufferItemConsumer(consumer, mRecordingGrallocUsage, mRecordingHeapCount + 1); mRecordingConsumer->setFrameAvailableListener(this); mRecordingConsumer->setName(String8("Camera2-RecordingConsumer")); mRecordingWindow = new Surface(producer); newConsumer = true; // Allocate memory later, since we don't know buffer size until receipt } if (mRecordingStreamId != NO_STREAM) { // Check if stream parameters have to change uint32_t currentWidth, currentHeight; uint32_t currentFormat; android_dataspace currentDataSpace; res = device->getStreamInfo(mRecordingStreamId, ¤tWidth, ¤tHeight, ¤tFormat, ¤tDataSpace); if (res != OK) { ALOGE("%s: Camera %d: Error querying recording output stream info: " "%s (%d)", __FUNCTION__, mId, strerror(-res), res); return res; } if (currentWidth != (uint32_t)params.videoWidth || currentHeight != (uint32_t)params.videoHeight || currentFormat != (uint32_t)mRecordingFormat || currentDataSpace != mRecordingDataSpace || newConsumer) { // TODO: Should wait to be sure previous recording has finished res = device->deleteStream(mRecordingStreamId); if (res == -EBUSY) { ALOGV("%s: Camera %d: Device is busy, call " "updateRecordingStream after it becomes idle", __FUNCTION__, mId); return res; } else if (res != OK) { ALOGE("%s: Camera %d: Unable to delete old output stream " "for recording: %s (%d)", __FUNCTION__, mId, strerror(-res), res); return res; } mRecordingStreamId = NO_STREAM; } } if (mRecordingStreamId == NO_STREAM) { mRecordingFrameCount = 0; res = device->createStream(mRecordingWindow, params.videoWidth, params.videoHeight, mRecordingFormat, mRecordingDataSpace, CAMERA3_STREAM_ROTATION_0, &mRecordingStreamId); if (res != OK) { ALOGE("%s: Camera %d: Can't create output stream for recording: " "%s (%d)", __FUNCTION__, mId, strerror(-res), res); return res; } } return OK; } status_t StreamingProcessor::deleteRecordingStream() { ATRACE_CALL(); status_t res; Mutex::Autolock m(mMutex); if (mRecordingStreamId != NO_STREAM) { sp device = mDevice.promote(); if (device == 0) { ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId); return INVALID_OPERATION; } res = device->waitUntilDrained(); if (res != OK) { ALOGE("%s: Error waiting for HAL to drain: %s (%d)", __FUNCTION__, strerror(-res), res); return res; } res = device->deleteStream(mRecordingStreamId); if (res != OK) { ALOGE("%s: Unable to delete recording stream: %s (%d)", __FUNCTION__, strerror(-res), res); return res; } mRecordingStreamId = NO_STREAM; } return OK; } int StreamingProcessor::getRecordingStreamId() const { return mRecordingStreamId; } status_t StreamingProcessor::startStream(StreamType type, const Vector &outputStreams) { ATRACE_CALL(); status_t res; if (type == NONE) return INVALID_OPERATION; sp device = mDevice.promote(); if (device == 0) { ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId); return INVALID_OPERATION; } ALOGV("%s: Camera %d: type = %d", __FUNCTION__, mId, type); Mutex::Autolock m(mMutex); // If a recording stream is being started up and no recording // stream is active yet, free up any outstanding buffers left // from the previous recording session. There should never be // any, so if there are, warn about it. bool isRecordingStreamIdle = !isStreamActive(mActiveStreamIds, mRecordingStreamId); bool startRecordingStream = isStreamActive(outputStreams, mRecordingStreamId); if (startRecordingStream && isRecordingStreamIdle) { releaseAllRecordingFramesLocked(); } ALOGV("%s: Camera %d: %s started, recording heap has %zu free of %zu", __FUNCTION__, mId, (type == PREVIEW) ? "preview" : "recording", mRecordingHeapFree, mRecordingHeapCount); CameraMetadata &request = (type == PREVIEW) ? mPreviewRequest : mRecordingRequest; res = request.update( ANDROID_REQUEST_OUTPUT_STREAMS, outputStreams); if (res != OK) { ALOGE("%s: Camera %d: Unable to set up preview request: %s (%d)", __FUNCTION__, mId, strerror(-res), res); return res; } res = request.sort(); if (res != OK) { ALOGE("%s: Camera %d: Error sorting preview request: %s (%d)", __FUNCTION__, mId, strerror(-res), res); return res; } res = device->setStreamingRequest(request); if (res != OK) { ALOGE("%s: Camera %d: Unable to set preview request to start preview: " "%s (%d)", __FUNCTION__, mId, strerror(-res), res); return res; } mActiveRequest = type; mPaused = false; mActiveStreamIds = outputStreams; return OK; } status_t StreamingProcessor::togglePauseStream(bool pause) { ATRACE_CALL(); status_t res; sp device = mDevice.promote(); if (device == 0) { ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId); return INVALID_OPERATION; } ALOGV("%s: Camera %d: toggling pause to %d", __FUNCTION__, mId, pause); Mutex::Autolock m(mMutex); if (mActiveRequest == NONE) { ALOGE("%s: Camera %d: Can't toggle pause, streaming was not started", __FUNCTION__, mId); return INVALID_OPERATION; } if (mPaused == pause) { return OK; } if (pause) { res = device->clearStreamingRequest(); if (res != OK) { ALOGE("%s: Camera %d: Can't clear stream request: %s (%d)", __FUNCTION__, mId, strerror(-res), res); return res; } } else { CameraMetadata &request = (mActiveRequest == PREVIEW) ? mPreviewRequest : mRecordingRequest; res = device->setStreamingRequest(request); if (res != OK) { ALOGE("%s: Camera %d: Unable to set preview request to resume: " "%s (%d)", __FUNCTION__, mId, strerror(-res), res); return res; } } mPaused = pause; return OK; } status_t StreamingProcessor::stopStream() { ATRACE_CALL(); status_t res; Mutex::Autolock m(mMutex); sp device = mDevice.promote(); if (device == 0) { ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId); return INVALID_OPERATION; } res = device->clearStreamingRequest(); if (res != OK) { ALOGE("%s: Camera %d: Can't clear stream request: %s (%d)", __FUNCTION__, mId, strerror(-res), res); return res; } mActiveRequest = NONE; mActiveStreamIds.clear(); mPaused = false; return OK; } int32_t StreamingProcessor::getActiveRequestId() const { Mutex::Autolock m(mMutex); switch (mActiveRequest) { case NONE: return 0; case PREVIEW: return mPreviewRequestId; case RECORD: return mRecordingRequestId; default: ALOGE("%s: Unexpected mode %d", __FUNCTION__, mActiveRequest); return 0; } } status_t StreamingProcessor::incrementStreamingIds() { ATRACE_CALL(); Mutex::Autolock m(mMutex); mPreviewRequestId++; if (mPreviewRequestId >= Camera2Client::kPreviewRequestIdEnd) { mPreviewRequestId = Camera2Client::kPreviewRequestIdStart; } mRecordingRequestId++; if (mRecordingRequestId >= Camera2Client::kRecordingRequestIdEnd) { mRecordingRequestId = Camera2Client::kRecordingRequestIdStart; } return OK; } void StreamingProcessor::onFrameAvailable(const BufferItem& /*item*/) { ATRACE_CALL(); Mutex::Autolock l(mMutex); if (!mRecordingFrameAvailable) { mRecordingFrameAvailable = true; mRecordingFrameAvailableSignal.signal(); } } bool StreamingProcessor::threadLoop() { status_t res; { Mutex::Autolock l(mMutex); while (!mRecordingFrameAvailable) { res = mRecordingFrameAvailableSignal.waitRelative( mMutex, kWaitDuration); if (res == TIMED_OUT) return true; } mRecordingFrameAvailable = false; } do { res = processRecordingFrame(); } while (res == OK); return true; } status_t StreamingProcessor::processRecordingFrame() { ATRACE_CALL(); status_t res; sp recordingHeap; size_t heapIdx = 0; nsecs_t timestamp; sp client = mClient.promote(); if (client == 0) { // Discard frames during shutdown BufferItem imgBuffer; res = mRecordingConsumer->acquireBuffer(&imgBuffer, 0); if (res != OK) { if (res != BufferItemConsumer::NO_BUFFER_AVAILABLE) { ALOGE("%s: Camera %d: Can't acquire recording buffer: %s (%d)", __FUNCTION__, mId, strerror(-res), res); } return res; } mRecordingConsumer->releaseBuffer(imgBuffer); return OK; } { /* acquire SharedParameters before mMutex so we don't dead lock with Camera2Client code calling into StreamingProcessor */ SharedParameters::Lock l(client->getParameters()); Mutex::Autolock m(mMutex); BufferItem imgBuffer; res = mRecordingConsumer->acquireBuffer(&imgBuffer, 0); if (res != OK) { if (res != BufferItemConsumer::NO_BUFFER_AVAILABLE) { ALOGE("%s: Camera %d: Can't acquire recording buffer: %s (%d)", __FUNCTION__, mId, strerror(-res), res); } return res; } timestamp = imgBuffer.mTimestamp; mRecordingFrameCount++; ALOGVV("OnRecordingFrame: Frame %d", mRecordingFrameCount); if (l.mParameters.state != Parameters::RECORD && l.mParameters.state != Parameters::VIDEO_SNAPSHOT) { ALOGV("%s: Camera %d: Discarding recording image buffers " "received after recording done", __FUNCTION__, mId); mRecordingConsumer->releaseBuffer(imgBuffer); return INVALID_OPERATION; } if (mRecordingHeap == 0) { size_t payloadSize = sizeof(VideoNativeMetadata); ALOGV("%s: Camera %d: Creating recording heap with %zu buffers of " "size %zu bytes", __FUNCTION__, mId, mRecordingHeapCount, payloadSize); mRecordingHeap = new Camera2Heap(payloadSize, mRecordingHeapCount, "Camera2Client::RecordingHeap"); if (mRecordingHeap->mHeap->getSize() == 0) { ALOGE("%s: Camera %d: Unable to allocate memory for recording", __FUNCTION__, mId); mRecordingConsumer->releaseBuffer(imgBuffer); return NO_MEMORY; } for (size_t i = 0; i < mRecordingBuffers.size(); i++) { if (mRecordingBuffers[i].mBuf != BufferItemConsumer::INVALID_BUFFER_SLOT) { ALOGE("%s: Camera %d: Non-empty recording buffers list!", __FUNCTION__, mId); } } mRecordingBuffers.clear(); mRecordingBuffers.setCapacity(mRecordingHeapCount); mRecordingBuffers.insertAt(0, mRecordingHeapCount); mRecordingHeapHead = 0; mRecordingHeapFree = mRecordingHeapCount; } if (mRecordingHeapFree == 0) { ALOGE("%s: Camera %d: No free recording buffers, dropping frame", __FUNCTION__, mId); mRecordingConsumer->releaseBuffer(imgBuffer); return NO_MEMORY; } heapIdx = mRecordingHeapHead; mRecordingHeapHead = (mRecordingHeapHead + 1) % mRecordingHeapCount; mRecordingHeapFree--; ALOGVV("%s: Camera %d: Timestamp %lld", __FUNCTION__, mId, timestamp); ssize_t offset; size_t size; sp heap = mRecordingHeap->mBuffers[heapIdx]->getMemory(&offset, &size); VideoNativeMetadata *payload = reinterpret_cast( (uint8_t*)heap->getBase() + offset); payload->eType = kMetadataBufferTypeANWBuffer; payload->pBuffer = imgBuffer.mGraphicBuffer->getNativeBuffer(); payload->nFenceFd = -1; ALOGVV("%s: Camera %d: Sending out ANWBuffer %p", __FUNCTION__, mId, payload->pBuffer); mRecordingBuffers.replaceAt(imgBuffer, heapIdx); recordingHeap = mRecordingHeap; } // Call outside locked parameters to allow re-entrancy from notification Camera2Client::SharedCameraCallbacks::Lock l(client->mSharedCameraCallbacks); if (l.mRemoteCallback != 0) { l.mRemoteCallback->dataCallbackTimestamp(timestamp, CAMERA_MSG_VIDEO_FRAME, recordingHeap->mBuffers[heapIdx]); } else { ALOGW("%s: Camera %d: Remote callback gone", __FUNCTION__, mId); } return OK; } void StreamingProcessor::releaseRecordingFrame(const sp& mem) { ATRACE_CALL(); status_t res; Mutex::Autolock m(mMutex); // Make sure this is for the current heap ssize_t offset; size_t size; sp heap = mem->getMemory(&offset, &size); if (heap->getHeapID() != mRecordingHeap->mHeap->getHeapID()) { ALOGW("%s: Camera %d: Mismatched heap ID, ignoring release " "(got %x, expected %x)", __FUNCTION__, mId, heap->getHeapID(), mRecordingHeap->mHeap->getHeapID()); return; } VideoNativeMetadata *payload = reinterpret_cast( (uint8_t*)heap->getBase() + offset); if (payload->eType != kMetadataBufferTypeANWBuffer) { ALOGE("%s: Camera %d: Recording frame type invalid (got %x, expected %x)", __FUNCTION__, mId, payload->eType, kMetadataBufferTypeANWBuffer); return; } // Release the buffer back to the recording queue size_t itemIndex; for (itemIndex = 0; itemIndex < mRecordingBuffers.size(); itemIndex++) { const BufferItem item = mRecordingBuffers[itemIndex]; if (item.mBuf != BufferItemConsumer::INVALID_BUFFER_SLOT && item.mGraphicBuffer->getNativeBuffer() == payload->pBuffer) { break; } } if (itemIndex == mRecordingBuffers.size()) { ALOGE("%s: Camera %d: Can't find returned ANW Buffer %p in list of " "outstanding buffers", __FUNCTION__, mId, payload->pBuffer); return; } ALOGVV("%s: Camera %d: Freeing returned ANW buffer %p index %d", __FUNCTION__, mId, payload->pBuffer, itemIndex); res = mRecordingConsumer->releaseBuffer(mRecordingBuffers[itemIndex]); if (res != OK) { ALOGE("%s: Camera %d: Unable to free recording frame " "(Returned ANW buffer: %p): %s (%d)", __FUNCTION__, mId, payload->pBuffer, strerror(-res), res); return; } mRecordingBuffers.replaceAt(itemIndex); mRecordingHeapFree++; ALOGV_IF(mRecordingHeapFree == mRecordingHeapCount, "%s: Camera %d: All %d recording buffers returned", __FUNCTION__, mId, mRecordingHeapCount); } void StreamingProcessor::releaseAllRecordingFramesLocked() { ATRACE_CALL(); status_t res; if (mRecordingConsumer == 0) { return; } ALOGV("%s: Camera %d: Releasing all recording buffers", __FUNCTION__, mId); size_t releasedCount = 0; for (size_t itemIndex = 0; itemIndex < mRecordingBuffers.size(); itemIndex++) { const BufferItem item = mRecordingBuffers[itemIndex]; if (item.mBuf != BufferItemConsumer::INVALID_BUFFER_SLOT) { res = mRecordingConsumer->releaseBuffer(mRecordingBuffers[itemIndex]); if (res != OK) { ALOGE("%s: Camera %d: Unable to free recording frame " "(buffer_handle_t: %p): %s (%d)", __FUNCTION__, mId, item.mGraphicBuffer->handle, strerror(-res), res); } mRecordingBuffers.replaceAt(itemIndex); releasedCount++; } } if (releasedCount > 0) { ALOGW("%s: Camera %d: Force-freed %zu outstanding buffers " "from previous recording session", __FUNCTION__, mId, releasedCount); ALOGE_IF(releasedCount != mRecordingHeapCount - mRecordingHeapFree, "%s: Camera %d: Force-freed %zu buffers, but expected %zu", __FUNCTION__, mId, releasedCount, mRecordingHeapCount - mRecordingHeapFree); } mRecordingHeapHead = 0; mRecordingHeapFree = mRecordingHeapCount; } bool StreamingProcessor::isStreamActive(const Vector &streams, int32_t recordingStreamId) { for (size_t i = 0; i < streams.size(); i++) { if (streams[i] == recordingStreamId) { return true; } } return false; } status_t StreamingProcessor::dump(int fd, const Vector& /*args*/) { String8 result; result.append(" Current requests:\n"); if (mPreviewRequest.entryCount() != 0) { result.append(" Preview request:\n"); write(fd, result.string(), result.size()); mPreviewRequest.dump(fd, 2, 6); result.clear(); } else { result.append(" Preview request: undefined\n"); } if (mRecordingRequest.entryCount() != 0) { result = " Recording request:\n"; write(fd, result.string(), result.size()); mRecordingRequest.dump(fd, 2, 6); result.clear(); } else { result = " Recording request: undefined\n"; } const char* streamTypeString[] = { "none", "preview", "record" }; result.append(String8::format(" Active request: %s (paused: %s)\n", streamTypeString[mActiveRequest], mPaused ? "yes" : "no")); write(fd, result.string(), result.size()); return OK; } }; // namespace camera2 }; // namespace android