546 lines
18 KiB
C++
546 lines
18 KiB
C++
/*
|
|
* Copyright (C) 2019 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_NDEBUG 0
|
|
#define LOG_TAG "GCH_ZslBufferManager"
|
|
#define ATRACE_TAG ATRACE_TAG_CAMERA
|
|
#include <cutils/properties.h>
|
|
#include <log/log.h>
|
|
#include <utils/Trace.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include "zsl_buffer_manager.h"
|
|
|
|
namespace android {
|
|
namespace google_camera_hal {
|
|
|
|
ZslBufferManager::ZslBufferManager(IHalBufferAllocator* allocator,
|
|
int partial_result_count)
|
|
: kMemoryProfilingEnabled(
|
|
property_get_bool("persist.vendor.camera.hal.memoryprofile", false)),
|
|
buffer_allocator_(allocator),
|
|
partial_result_count_(partial_result_count) {
|
|
}
|
|
|
|
ZslBufferManager::~ZslBufferManager() {
|
|
ATRACE_CALL();
|
|
std::unique_lock<std::mutex> lock(zsl_buffers_lock_);
|
|
if (buffer_allocator_ != nullptr) {
|
|
buffer_allocator_->FreeBuffers(&buffers_);
|
|
}
|
|
}
|
|
|
|
status_t ZslBufferManager::AllocateBuffers(
|
|
const HalBufferDescriptor& buffer_descriptor) {
|
|
ATRACE_CALL();
|
|
std::unique_lock<std::mutex> lock(zsl_buffers_lock_);
|
|
|
|
if (allocated_) {
|
|
ALOGE("%s: Buffer is already allocated.", __FUNCTION__);
|
|
return ALREADY_EXISTS;
|
|
}
|
|
|
|
// Create a buffer allocator if the client doesn't specify one.
|
|
if (buffer_allocator_ == nullptr) {
|
|
// Create a buffer manager.
|
|
internal_buffer_allocator_ = GrallocBufferAllocator::Create();
|
|
if (internal_buffer_allocator_ == nullptr) {
|
|
ALOGE("%s: Creating a buffer manager failed.", __FUNCTION__);
|
|
return NO_MEMORY;
|
|
}
|
|
|
|
buffer_allocator_ = internal_buffer_allocator_.get();
|
|
}
|
|
|
|
uint32_t num_buffers = buffer_descriptor.immediate_num_buffers;
|
|
buffer_descriptor_ = buffer_descriptor;
|
|
status_t res = AllocateBuffersLocked(num_buffers);
|
|
if (res != OK) {
|
|
ALOGE("%s: Allocating %d buffers failed.", __FUNCTION__, num_buffers);
|
|
return res;
|
|
}
|
|
|
|
allocated_ = true;
|
|
return OK;
|
|
}
|
|
|
|
status_t ZslBufferManager::AllocateBuffersLocked(uint32_t buffer_number) {
|
|
if (buffer_number + buffers_.size() > buffer_descriptor_.max_num_buffers) {
|
|
ALOGE("%s: allocate %d + exist %zu > max buffer number %d", __FUNCTION__,
|
|
buffer_number, buffers_.size(), buffer_descriptor_.max_num_buffers);
|
|
return NO_MEMORY;
|
|
}
|
|
|
|
HalBufferDescriptor buffer_descriptor = buffer_descriptor_;
|
|
buffer_descriptor.immediate_num_buffers = buffer_number;
|
|
std::vector<buffer_handle_t> buffers;
|
|
status_t res = buffer_allocator_->AllocateBuffers(buffer_descriptor, &buffers);
|
|
if (res != OK) {
|
|
ALOGE("%s: AllocateBuffers fail.", __FUNCTION__);
|
|
return res;
|
|
}
|
|
|
|
for (auto& buffer : buffers) {
|
|
if (buffer != kInvalidBufferHandle) {
|
|
buffers_.push_back(buffer);
|
|
empty_zsl_buffers_.push_back(buffer);
|
|
}
|
|
}
|
|
|
|
if (buffers.size() != buffer_number) {
|
|
ALOGE("%s: allocate buffer failed. request %u, get %zu", __FUNCTION__,
|
|
buffer_number, buffers.size());
|
|
return NO_MEMORY;
|
|
}
|
|
|
|
if (kMemoryProfilingEnabled) {
|
|
ALOGI(
|
|
"%s: Allocated %u buffers, res %ux%u, format %d, overall allocated "
|
|
"%zu buffers",
|
|
__FUNCTION__, buffer_number, buffer_descriptor_.width,
|
|
buffer_descriptor_.height, buffer_descriptor_.format, buffers_.size());
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
buffer_handle_t ZslBufferManager::GetEmptyBuffer() {
|
|
ATRACE_CALL();
|
|
std::unique_lock<std::mutex> lock(zsl_buffers_lock_);
|
|
if (!allocated_) {
|
|
ALOGE("%s: Buffers are not allocated.", __FUNCTION__);
|
|
return kInvalidBufferHandle;
|
|
}
|
|
|
|
buffer_handle_t buffer = GetEmptyBufferLocked();
|
|
if (buffer == kInvalidBufferHandle) {
|
|
// Try to allocate one more buffer if there is no empty buffer.
|
|
status_t res = AllocateBuffersLocked(/*buffer_number=*/1);
|
|
if (res != OK) {
|
|
ALOGE("%s: Allocating one more buffer failed: %s(%d)", __FUNCTION__,
|
|
strerror(-res), res);
|
|
return kInvalidBufferHandle;
|
|
}
|
|
|
|
buffer = GetEmptyBufferLocked();
|
|
}
|
|
|
|
return buffer;
|
|
}
|
|
|
|
buffer_handle_t ZslBufferManager::GetEmptyBufferLocked() {
|
|
ATRACE_CALL();
|
|
buffer_handle_t buffer = kInvalidBufferHandle;
|
|
|
|
// Get an empty buffer from empty ZSL buffer queue.
|
|
// If empty ZSL buffer queue is empty,
|
|
// Get the oldest buffer from filled ZSL buffer queue.
|
|
// If filled ZSL buffer queue is empty,
|
|
// Get the oldest buffer from the partially filled ZSL buffer queue.
|
|
if (empty_zsl_buffers_.size() > 0) {
|
|
buffer = empty_zsl_buffers_[0];
|
|
empty_zsl_buffers_.pop_front();
|
|
} else if (filled_zsl_buffers_.size() > 0) {
|
|
auto buffer_iter = filled_zsl_buffers_.begin();
|
|
buffer = buffer_iter->second.buffer.buffer;
|
|
filled_zsl_buffers_.erase(buffer_iter);
|
|
} else if (partially_filled_zsl_buffers_.size() > 0) {
|
|
auto buffer_iter = partially_filled_zsl_buffers_.begin();
|
|
while (buffer_iter != partially_filled_zsl_buffers_.end()) {
|
|
if (buffer_iter->second.partial_result == partial_result_count_) {
|
|
if (buffer_iter->second.buffer.buffer != kInvalidBufferHandle) {
|
|
ALOGE("%s: Invalid: both are ready in partial zsl queue.",
|
|
__FUNCTION__);
|
|
// TODO: clean up resources in this invalid situation.
|
|
return kInvalidBufferHandle;
|
|
}
|
|
ALOGI(
|
|
"%s: Remove metadata-only buffer in partially filled zsl "
|
|
"buffer queue. Releasing the metadata resource.",
|
|
__FUNCTION__);
|
|
} else if (buffer_iter->second.buffer.buffer == kInvalidBufferHandle &&
|
|
buffer_iter->second.partial_result == 0) {
|
|
ALOGE(
|
|
"%s: Invalid: both buffer and metadata are empty in partial "
|
|
"zsl queue.",
|
|
__FUNCTION__);
|
|
// TODO: clean up resources in this invalid situation.
|
|
return kInvalidBufferHandle;
|
|
} else {
|
|
ALOGI(
|
|
"%s: Get buffer-only empty buffer from partially filled zsl "
|
|
"buffer queue.",
|
|
__FUNCTION__);
|
|
buffer = buffer_iter->second.buffer.buffer;
|
|
}
|
|
|
|
// remove whatever visited
|
|
buffer_iter = partially_filled_zsl_buffers_.erase(buffer_iter);
|
|
|
|
if (buffer != kInvalidBufferHandle) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (buffer_iter == partially_filled_zsl_buffers_.end()) {
|
|
ALOGE("%s: No empty buffer available.", __FUNCTION__);
|
|
}
|
|
} else {
|
|
ALOGW("%s: No empty buffer available.", __FUNCTION__);
|
|
}
|
|
|
|
return buffer;
|
|
}
|
|
|
|
void ZslBufferManager::FreeUnusedBuffersLocked() {
|
|
ATRACE_CALL();
|
|
if (empty_zsl_buffers_.size() <= kMaxUnusedBuffers ||
|
|
buffers_.size() <= buffer_descriptor_.immediate_num_buffers) {
|
|
idle_buffer_frame_counter_ = 0;
|
|
return;
|
|
}
|
|
|
|
idle_buffer_frame_counter_++;
|
|
if (idle_buffer_frame_counter_ <= kMaxIdelBufferFrameCounter) {
|
|
return;
|
|
}
|
|
|
|
std::vector<buffer_handle_t> unused_buffers;
|
|
|
|
// When there are at least kMaxUnusedBuffers unused buffers, try to reduce
|
|
// the number of buffers to buffer_descriptor_.immediate_num_buffers.
|
|
while (buffers_.size() > buffer_descriptor_.immediate_num_buffers &&
|
|
empty_zsl_buffers_.size() > 0) {
|
|
buffer_handle_t buffer = empty_zsl_buffers_.back();
|
|
unused_buffers.push_back(buffer);
|
|
empty_zsl_buffers_.pop_back();
|
|
buffers_.erase(std::find(buffers_.begin(), buffers_.end(), buffer));
|
|
}
|
|
|
|
if (kMemoryProfilingEnabled) {
|
|
ALOGI(
|
|
"%s: Freeing %zu buffers, res %ux%u, format %d, overall allocated "
|
|
"%zu buffers",
|
|
__FUNCTION__, unused_buffers.size(), buffer_descriptor_.width,
|
|
buffer_descriptor_.height, buffer_descriptor_.format, buffers_.size());
|
|
}
|
|
|
|
buffer_allocator_->FreeBuffers(&unused_buffers);
|
|
}
|
|
|
|
status_t ZslBufferManager::ReturnEmptyBuffer(buffer_handle_t buffer) {
|
|
ATRACE_CALL();
|
|
if (buffer == kInvalidBufferHandle) {
|
|
ALOGE("%s: buffer is nullptr.", __FUNCTION__);
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
std::unique_lock<std::mutex> lock(zsl_buffers_lock_);
|
|
// Check whether the returned buffer is freed or not
|
|
auto exist_buffer = std::find(buffers_.begin(), buffers_.end(), buffer);
|
|
if (exist_buffer == buffers_.end()) {
|
|
ALOGE("%s: Buffer %p is invalid", __FUNCTION__, buffer);
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
auto empty_buffer = std::find(std::begin(empty_zsl_buffers_),
|
|
std::end(empty_zsl_buffers_), buffer);
|
|
if (empty_buffer != std::end(empty_zsl_buffers_)) {
|
|
ALOGE("%s: Buffer %p was already returned.", __FUNCTION__, buffer);
|
|
return ALREADY_EXISTS;
|
|
}
|
|
|
|
empty_zsl_buffers_.push_back(buffer);
|
|
FreeUnusedBuffersLocked();
|
|
return OK;
|
|
}
|
|
|
|
status_t ZslBufferManager::ReturnFilledBuffer(uint32_t frame_number,
|
|
const StreamBuffer& buffer) {
|
|
ATRACE_CALL();
|
|
ZslBuffer zsl_buffer = {};
|
|
zsl_buffer.frame_number = frame_number;
|
|
zsl_buffer.buffer = buffer;
|
|
|
|
std::unique_lock<std::mutex> lock(zsl_buffers_lock_);
|
|
if (partially_filled_zsl_buffers_.empty() ||
|
|
partially_filled_zsl_buffers_.find(frame_number) ==
|
|
partially_filled_zsl_buffers_.end()) {
|
|
// not able to distinguish these two cases through the current status
|
|
// of the partial buffer
|
|
ALOGV(
|
|
"%s: no entry for frame[%u] in ZslBufferManager. Not created or "
|
|
"has been removed",
|
|
__FUNCTION__, frame_number);
|
|
|
|
zsl_buffer.metadata = nullptr;
|
|
partially_filled_zsl_buffers_[frame_number] = std::move(zsl_buffer);
|
|
} else if (partially_filled_zsl_buffers_[frame_number].buffer.buffer ==
|
|
kInvalidBufferHandle) {
|
|
partially_filled_zsl_buffers_[frame_number].buffer = buffer;
|
|
if (partially_filled_zsl_buffers_[frame_number].partial_result ==
|
|
partial_result_count_) {
|
|
ALOGV(
|
|
"%s: both buffer and metadata for frame[%u] are ready. Move to "
|
|
"filled_zsl_buffers_.",
|
|
__FUNCTION__, frame_number);
|
|
filled_zsl_buffers_[frame_number] =
|
|
std::move(partially_filled_zsl_buffers_[frame_number]);
|
|
partially_filled_zsl_buffers_.erase(frame_number);
|
|
}
|
|
} else {
|
|
ALOGE(
|
|
"%s: the buffer for frame[%u] already returned or the metadata is "
|
|
"missing.",
|
|
__FUNCTION__, frame_number);
|
|
return INVALID_OPERATION;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
status_t ZslBufferManager::ReturnMetadata(uint32_t frame_number,
|
|
const HalCameraMetadata* metadata,
|
|
int partial_result) {
|
|
ATRACE_CALL();
|
|
std::unique_lock<std::mutex> lock(zsl_buffers_lock_);
|
|
|
|
ZslBuffer zsl_buffer = {};
|
|
zsl_buffer.frame_number = frame_number;
|
|
zsl_buffer.partial_result = partial_result;
|
|
|
|
auto partially_filled_buffer_it =
|
|
partially_filled_zsl_buffers_.find(frame_number);
|
|
if (partially_filled_buffer_it == partially_filled_zsl_buffers_.end()) {
|
|
// not able to distinguish these two cases through the current status of
|
|
// the partial buffer
|
|
ALOGV(
|
|
"%s: no entry for frame[%u] in ZslBufferManager. Not created or "
|
|
"has been removed",
|
|
__FUNCTION__, frame_number);
|
|
|
|
zsl_buffer.buffer = {};
|
|
zsl_buffer.metadata = HalCameraMetadata::Clone(metadata);
|
|
if (zsl_buffer.metadata == nullptr) {
|
|
ALOGE("%s: Failed to Clone camera metadata.", __FUNCTION__);
|
|
return NO_MEMORY;
|
|
}
|
|
partially_filled_zsl_buffers_[frame_number] = std::move(zsl_buffer);
|
|
} else if (partial_result < partial_result_count_) {
|
|
partially_filled_buffer_it->second.partial_result = partial_result;
|
|
// Need to wait for more partial results
|
|
if (partially_filled_buffer_it->second.metadata == nullptr) {
|
|
// This is the first partial result, clone to create an entry
|
|
partially_filled_buffer_it->second.metadata =
|
|
HalCameraMetadata::Clone(metadata);
|
|
if (partially_filled_buffer_it->second.metadata == nullptr) {
|
|
ALOGE("%s: Failed to Clone camera metadata.", __FUNCTION__);
|
|
return NO_MEMORY;
|
|
}
|
|
} else {
|
|
// Append to previously received partial results
|
|
partially_filled_buffer_it->second.metadata->Append(
|
|
metadata->GetRawCameraMetadata());
|
|
}
|
|
} else {
|
|
zsl_buffer.buffer = partially_filled_buffer_it->second.buffer;
|
|
partially_filled_buffer_it->second.partial_result = partial_result;
|
|
if (partially_filled_buffer_it->second.metadata == nullptr) {
|
|
// This will happen if partial_result_count_ == 1
|
|
partially_filled_buffer_it->second.metadata =
|
|
HalCameraMetadata::Clone(metadata);
|
|
} else {
|
|
// This is the last partial result, append it to the others
|
|
partially_filled_buffer_it->second.metadata->Append(
|
|
metadata->GetRawCameraMetadata());
|
|
}
|
|
if (partially_filled_buffer_it->second.buffer.buffer !=
|
|
kInvalidBufferHandle) {
|
|
ALOGV(
|
|
"%s: both buffer and metadata for frame[%u] are ready. Move to "
|
|
"filled_zsl_buffers_.",
|
|
__FUNCTION__, frame_number);
|
|
filled_zsl_buffers_[frame_number] =
|
|
std::move(partially_filled_buffer_it->second);
|
|
partially_filled_zsl_buffers_.erase(frame_number);
|
|
}
|
|
}
|
|
|
|
if (partially_filled_zsl_buffers_.size() > kMaxPartialZslBuffers) {
|
|
// Remove the oldest one if it exceeds the maximum number of partial ZSL
|
|
// buffers.
|
|
partially_filled_zsl_buffers_.erase(partially_filled_zsl_buffers_.begin());
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
status_t ZslBufferManager::GetCurrentTimestampNs(int64_t* current_timestamp) {
|
|
if (current_timestamp == nullptr) {
|
|
ALOGE("%s: current_timestamp is nullptr", __FUNCTION__);
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
struct timespec ts;
|
|
if (clock_gettime(CLOCK_BOOTTIME, &ts)) {
|
|
ALOGE("%s: Getting boot time failed.", __FUNCTION__);
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
static const int64_t kNsPerSec = 1000000000;
|
|
*current_timestamp = ts.tv_sec * kNsPerSec + ts.tv_nsec;
|
|
return OK;
|
|
}
|
|
|
|
void ZslBufferManager::GetMostRecentZslBuffers(
|
|
std::vector<ZslBuffer>* zsl_buffers, uint32_t num_buffers,
|
|
uint32_t min_buffers) {
|
|
ATRACE_CALL();
|
|
if (zsl_buffers == nullptr) {
|
|
return;
|
|
}
|
|
|
|
int64_t current_timestamp;
|
|
status_t res = GetCurrentTimestampNs(¤t_timestamp);
|
|
if (res != OK) {
|
|
ALOGE("%s: Getting current timestamp failed: %s(%d)", __FUNCTION__,
|
|
strerror(-res), res);
|
|
return;
|
|
}
|
|
|
|
std::unique_lock<std::mutex> lock(zsl_buffers_lock_);
|
|
if (filled_zsl_buffers_.size() < min_buffers) {
|
|
ALOGD("%s: Requested min_buffers = %u, ZslBufferManager only has %zu",
|
|
__FUNCTION__, min_buffers, filled_zsl_buffers_.size());
|
|
ALOGD("%s: Not enough ZSL buffers to get, returns empty zsl_buffers.",
|
|
__FUNCTION__);
|
|
return;
|
|
}
|
|
|
|
num_buffers =
|
|
std::min(static_cast<uint32_t>(filled_zsl_buffers_.size()), num_buffers);
|
|
auto zsl_buffer_iter = filled_zsl_buffers_.begin();
|
|
|
|
// Skip the older ones.
|
|
for (uint32_t i = 0; i < filled_zsl_buffers_.size() - num_buffers; i++) {
|
|
zsl_buffer_iter++;
|
|
}
|
|
|
|
// Fallback to realtime pipeline capture if there are any flash-fired frame
|
|
// in zsl buffers with AE_MODE_ON_AUTO_FLASH.
|
|
camera_metadata_ro_entry entry = {};
|
|
res = zsl_buffer_iter->second.metadata->Get(ANDROID_CONTROL_AE_MODE, &entry);
|
|
if (res == OK && entry.data.u8[0] == ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH) {
|
|
for (auto search_iter = filled_zsl_buffers_.begin();
|
|
search_iter != filled_zsl_buffers_.end(); search_iter++) {
|
|
res = search_iter->second.metadata->Get(ANDROID_FLASH_STATE, &entry);
|
|
if (res == OK && entry.count == 1) {
|
|
if (entry.data.u8[0] == ANDROID_FLASH_STATE_FIRED) {
|
|
ALOGD("%s: Returns empty zsl_buffers due to flash fired",
|
|
__FUNCTION__);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (uint32_t i = 0; i < num_buffers; i++) {
|
|
camera_metadata_ro_entry entry = {};
|
|
int64_t buffer_timestamp;
|
|
res =
|
|
zsl_buffer_iter->second.metadata->Get(ANDROID_SENSOR_TIMESTAMP, &entry);
|
|
if (res != OK || entry.count != 1) {
|
|
ALOGW("%s: Getting sensor timestamp failed: %s(%d)", __FUNCTION__,
|
|
strerror(-res), res);
|
|
return;
|
|
}
|
|
|
|
buffer_timestamp = entry.data.i64[0];
|
|
// Only include recent buffers.
|
|
if (current_timestamp - buffer_timestamp < kMaxBufferTimestampDiff) {
|
|
zsl_buffers->push_back(std::move(zsl_buffer_iter->second));
|
|
zsl_buffer_iter = filled_zsl_buffers_.erase(zsl_buffer_iter);
|
|
} else {
|
|
zsl_buffer_iter++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ZslBufferManager::ReturnZslBuffer(ZslBuffer zsl_buffer) {
|
|
ATRACE_CALL();
|
|
std::unique_lock<std::mutex> lock(zsl_buffers_lock_);
|
|
filled_zsl_buffers_[zsl_buffer.frame_number] = std::move(zsl_buffer);
|
|
}
|
|
|
|
void ZslBufferManager::ReturnZslBuffers(std::vector<ZslBuffer> zsl_buffers) {
|
|
ATRACE_CALL();
|
|
for (auto& zsl_buffer : zsl_buffers) {
|
|
ReturnZslBuffer(std::move(zsl_buffer));
|
|
}
|
|
}
|
|
|
|
bool ZslBufferManager::IsPendingBufferEmpty() {
|
|
std::lock_guard<std::mutex> lock(pending_zsl_buffers_mutex);
|
|
bool empty = (pending_zsl_buffers_.size() == 0);
|
|
if (!empty) {
|
|
ALOGW("%s: Pending buffer is not empty:%zu.", __FUNCTION__,
|
|
pending_zsl_buffers_.size());
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void ZslBufferManager::AddPendingBuffers(const std::vector<ZslBuffer>& buffers) {
|
|
ATRACE_CALL();
|
|
std::lock_guard<std::mutex> lock(pending_zsl_buffers_mutex);
|
|
for (auto& buffer : buffers) {
|
|
ZslBuffer zsl_buffer = {
|
|
.frame_number = buffer.frame_number,
|
|
.buffer = buffer.buffer,
|
|
.metadata = HalCameraMetadata::Clone(buffer.metadata.get()),
|
|
};
|
|
|
|
pending_zsl_buffers_.emplace(buffer.buffer.buffer, std::move(zsl_buffer));
|
|
}
|
|
}
|
|
|
|
status_t ZslBufferManager::CleanPendingBuffers(std::vector<ZslBuffer>* buffers) {
|
|
ATRACE_CALL();
|
|
if (buffers == nullptr) {
|
|
ALOGE("%s: buffers is nullptr", __FUNCTION__);
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
std::lock_guard<std::mutex> lock(pending_zsl_buffers_mutex);
|
|
if (pending_zsl_buffers_.empty()) {
|
|
ALOGE("%s: There is no empty buffer.", __FUNCTION__);
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
for (auto zsl_buffer_iter = pending_zsl_buffers_.begin();
|
|
zsl_buffer_iter != pending_zsl_buffers_.end(); zsl_buffer_iter++) {
|
|
buffers->push_back(std::move(zsl_buffer_iter->second));
|
|
}
|
|
|
|
pending_zsl_buffers_.clear();
|
|
return OK;
|
|
}
|
|
|
|
} // namespace google_camera_hal
|
|
} // namespace android
|