Merge "libstagefright: Add support for parsing profile and level from CSD for AV1" into qt-dev
diff --git a/media/codec2/components/vpx/C2SoftVpxDec.cpp b/media/codec2/components/vpx/C2SoftVpxDec.cpp
index 42f507f..a52ca15 100644
--- a/media/codec2/components/vpx/C2SoftVpxDec.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxDec.cpp
@@ -18,6 +18,8 @@
#define LOG_TAG "C2SoftVpxDec"
#include <log/log.h>
+#include <algorithm>
+
#include <media/stagefright/foundation/AUtils.h>
#include <media/stagefright/foundation/MediaDefs.h>
@@ -303,13 +305,43 @@
#endif
};
+C2SoftVpxDec::ConverterThread::ConverterThread(
+ const std::shared_ptr<Mutexed<ConversionQueue>> &queue)
+ : Thread(false), mQueue(queue) {}
+
+bool C2SoftVpxDec::ConverterThread::threadLoop() {
+ Mutexed<ConversionQueue>::Locked queue(*mQueue);
+ if (queue->entries.empty()) {
+ queue.waitForCondition(queue->cond);
+ if (queue->entries.empty()) {
+ return true;
+ }
+ }
+ std::function<void()> convert = queue->entries.front();
+ queue->entries.pop_front();
+ if (!queue->entries.empty()) {
+ queue->cond.signal();
+ }
+ queue.unlock();
+
+ convert();
+
+ queue.lock();
+ if (--queue->numPending == 0u) {
+ queue->cond.broadcast();
+ }
+ return true;
+}
+
C2SoftVpxDec::C2SoftVpxDec(
const char *name,
c2_node_id_t id,
const std::shared_ptr<IntfImpl> &intfImpl)
: SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
mIntf(intfImpl),
- mCodecCtx(nullptr) {
+ mCodecCtx(nullptr),
+ mCoreCount(1),
+ mQueue(new Mutexed<ConversionQueue>) {
}
C2SoftVpxDec::~C2SoftVpxDec() {
@@ -399,7 +431,7 @@
vpx_codec_dec_cfg_t cfg;
memset(&cfg, 0, sizeof(vpx_codec_dec_cfg_t));
- cfg.threads = GetCPUCoreCount();
+ cfg.threads = mCoreCount = GetCPUCoreCount();
vpx_codec_flags_t flags;
memset(&flags, 0, sizeof(vpx_codec_flags_t));
@@ -413,6 +445,18 @@
return UNKNOWN_ERROR;
}
+ if (mMode == MODE_VP9) {
+ using namespace std::string_literals;
+ for (int i = 0; i < mCoreCount; ++i) {
+ sp<ConverterThread> thread(new ConverterThread(mQueue));
+ mConverterThreads.push_back(thread);
+ if (thread->run(("vp9conv #"s + std::to_string(i)).c_str(),
+ ANDROID_PRIORITY_AUDIO) != OK) {
+ return UNKNOWN_ERROR;
+ }
+ }
+ }
+
return OK;
}
@@ -422,6 +466,21 @@
delete mCodecCtx;
mCodecCtx = nullptr;
}
+ bool running = true;
+ for (const sp<ConverterThread> &thread : mConverterThreads) {
+ thread->requestExit();
+ }
+ while (running) {
+ mQueue->lock()->cond.broadcast();
+ running = false;
+ for (const sp<ConverterThread> &thread : mConverterThreads) {
+ if (thread->isRunning()) {
+ running = true;
+ break;
+ }
+ }
+ }
+ mConverterThreads.clear();
return OK;
}
@@ -759,15 +818,35 @@
const uint16_t *srcV = (const uint16_t *)img->planes[VPX_PLANE_V];
if (format == HAL_PIXEL_FORMAT_RGBA_1010102) {
- convertYUV420Planar16ToY410((uint32_t *)dst, srcY, srcU, srcV, srcYStride / 2,
- srcUStride / 2, srcVStride / 2,
- dstYStride / sizeof(uint32_t),
- mWidth, mHeight);
+ Mutexed<ConversionQueue>::Locked queue(*mQueue);
+ size_t i = 0;
+ constexpr size_t kHeight = 64;
+ for (; i < mHeight; i += kHeight) {
+ queue->entries.push_back(
+ [dst, srcY, srcU, srcV,
+ srcYStride, srcUStride, srcVStride, dstYStride,
+ width = mWidth, height = std::min(mHeight - i, kHeight)] {
+ convertYUV420Planar16ToY410(
+ (uint32_t *)dst, srcY, srcU, srcV, srcYStride / 2,
+ srcUStride / 2, srcVStride / 2, dstYStride / sizeof(uint32_t),
+ width, height);
+ });
+ srcY += srcYStride / 2 * kHeight;
+ srcU += srcUStride / 2 * (kHeight / 2);
+ srcV += srcVStride / 2 * (kHeight / 2);
+ dst += dstYStride * kHeight;
+ }
+ CHECK_EQ(0u, queue->numPending);
+ queue->numPending = queue->entries.size();
+ while (queue->numPending > 0) {
+ queue->cond.signal();
+ queue.waitForCondition(queue->cond);
+ }
} else {
convertYUV420Planar16ToYUV420Planar(dst, srcY, srcU, srcV, srcYStride / 2,
- srcUStride / 2, srcVStride / 2,
- dstYStride, dstUVStride,
- mWidth, mHeight);
+ srcUStride / 2, srcVStride / 2,
+ dstYStride, dstUVStride,
+ mWidth, mHeight);
}
} else {
const uint8_t *srcY = (const uint8_t *)img->planes[VPX_PLANE_Y];
diff --git a/media/codec2/components/vpx/C2SoftVpxDec.h b/media/codec2/components/vpx/C2SoftVpxDec.h
index 60c8484..e51bcee 100644
--- a/media/codec2/components/vpx/C2SoftVpxDec.h
+++ b/media/codec2/components/vpx/C2SoftVpxDec.h
@@ -50,6 +50,19 @@
MODE_VP9,
} mMode;
+ struct ConversionQueue;
+
+ class ConverterThread : public Thread {
+ public:
+ explicit ConverterThread(
+ const std::shared_ptr<Mutexed<ConversionQueue>> &queue);
+ ~ConverterThread() override = default;
+ bool threadLoop() override;
+
+ private:
+ std::shared_ptr<Mutexed<ConversionQueue>> mQueue;
+ };
+
std::shared_ptr<IntfImpl> mIntf;
vpx_codec_ctx_t *mCodecCtx;
bool mFrameParallelMode; // Frame parallel is only supported by VP9 decoder.
@@ -59,6 +72,15 @@
bool mSignalledOutputEos;
bool mSignalledError;
+ int mCoreCount;
+ struct ConversionQueue {
+ std::list<std::function<void()>> entries;
+ Condition cond;
+ size_t numPending{0u};
+ };
+ std::shared_ptr<Mutexed<ConversionQueue>> mQueue;
+ std::vector<sp<ConverterThread>> mConverterThreads;
+
status_t initDecoder();
status_t destroyDecoder();
void finishWork(uint64_t index, const std::unique_ptr<C2Work> &work,
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 6a9e6cb..00f0d86 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -4401,11 +4401,12 @@
status_t Camera3Device::HalInterface::wrapAsHidlRequest(camera3_capture_request_t* request,
/*out*/device::V3_2::CaptureRequest* captureRequest,
- /*out*/std::vector<native_handle_t*>* handlesCreated) {
+ /*out*/std::vector<native_handle_t*>* handlesCreated,
+ /*out*/std::vector<std::pair<int32_t, int32_t>>* inflightBuffers) {
ATRACE_CALL();
- if (captureRequest == nullptr || handlesCreated == nullptr) {
- ALOGE("%s: captureRequest (%p) and handlesCreated (%p) must not be null",
- __FUNCTION__, captureRequest, handlesCreated);
+ if (captureRequest == nullptr || handlesCreated == nullptr || inflightBuffers == nullptr) {
+ ALOGE("%s: captureRequest (%p), handlesCreated (%p), and inflightBuffers(%p) "
+ "must not be null", __FUNCTION__, captureRequest, handlesCreated, inflightBuffers);
return BAD_VALUE;
}
@@ -4435,8 +4436,8 @@
captureRequest->inputBuffer.releaseFence = nullptr;
pushInflightBufferLocked(captureRequest->frameNumber, streamId,
- request->input_buffer->buffer,
- request->input_buffer->acquire_fence);
+ request->input_buffer->buffer);
+ inflightBuffers->push_back(std::make_pair(captureRequest->frameNumber, streamId));
} else {
captureRequest->inputBuffer.streamId = -1;
captureRequest->inputBuffer.bufferId = BUFFER_ID_NO_BUFFER;
@@ -4475,14 +4476,31 @@
// Output buffers are empty when using HAL buffer manager
if (!mUseHalBufManager) {
- pushInflightBufferLocked(captureRequest->frameNumber, streamId,
- src->buffer, src->acquire_fence);
+ pushInflightBufferLocked(captureRequest->frameNumber, streamId, src->buffer);
+ inflightBuffers->push_back(std::make_pair(captureRequest->frameNumber, streamId));
}
}
}
return OK;
}
+void Camera3Device::HalInterface::cleanupNativeHandles(
+ std::vector<native_handle_t*> *handles, bool closeFd) {
+ if (handles == nullptr) {
+ return;
+ }
+ if (closeFd) {
+ for (auto& handle : *handles) {
+ native_handle_close(handle);
+ }
+ }
+ for (auto& handle : *handles) {
+ native_handle_delete(handle);
+ }
+ handles->clear();
+ return;
+}
+
status_t Camera3Device::HalInterface::processBatchCaptureRequests(
std::vector<camera3_capture_request_t*>& requests,/*out*/uint32_t* numRequestProcessed) {
ATRACE_NAME("CameraHal::processBatchCaptureRequests");
@@ -4503,17 +4521,20 @@
captureRequests.resize(batchSize);
}
std::vector<native_handle_t*> handlesCreated;
+ std::vector<std::pair<int32_t, int32_t>> inflightBuffers;
status_t res = OK;
for (size_t i = 0; i < batchSize; i++) {
if (hidlSession_3_4 != nullptr) {
res = wrapAsHidlRequest(requests[i], /*out*/&captureRequests_3_4[i].v3_2,
- /*out*/&handlesCreated);
+ /*out*/&handlesCreated, /*out*/&inflightBuffers);
} else {
- res = wrapAsHidlRequest(requests[i],
- /*out*/&captureRequests[i], /*out*/&handlesCreated);
+ res = wrapAsHidlRequest(requests[i], /*out*/&captureRequests[i],
+ /*out*/&handlesCreated, /*out*/&inflightBuffers);
}
if (res != OK) {
+ popInflightBuffers(inflightBuffers);
+ cleanupNativeHandles(&handlesCreated);
return res;
}
}
@@ -4610,18 +4631,30 @@
}
if (!err.isOk()) {
ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
- return DEAD_OBJECT;
+ status = common::V1_0::Status::CAMERA_DISCONNECTED;
}
+
if (status == common::V1_0::Status::OK && *numRequestProcessed != batchSize) {
ALOGE("%s: processCaptureRequest returns OK but processed %d/%zu requests",
__FUNCTION__, *numRequestProcessed, batchSize);
status = common::V1_0::Status::INTERNAL_ERROR;
}
- for (auto& handle : handlesCreated) {
- native_handle_delete(handle);
+ res = CameraProviderManager::mapToStatusT(status);
+ if (res == OK) {
+ if (mHidlSession->isRemote()) {
+ // Only close acquire fence FDs when the HIDL transaction succeeds (so the FDs have been
+ // sent to camera HAL processes)
+ cleanupNativeHandles(&handlesCreated, /*closeFd*/true);
+ } else {
+ // In passthrough mode the FDs are now owned by HAL
+ cleanupNativeHandles(&handlesCreated);
+ }
+ } else {
+ popInflightBuffers(inflightBuffers);
+ cleanupNativeHandles(&handlesCreated);
}
- return CameraProviderManager::mapToStatusT(status);
+ return res;
}
status_t Camera3Device::HalInterface::flush() {
@@ -4703,10 +4736,9 @@
}
status_t Camera3Device::HalInterface::pushInflightBufferLocked(
- int32_t frameNumber, int32_t streamId, buffer_handle_t *buffer, int acquireFence) {
+ int32_t frameNumber, int32_t streamId, buffer_handle_t *buffer) {
uint64_t key = static_cast<uint64_t>(frameNumber) << 32 | static_cast<uint64_t>(streamId);
- auto pair = std::make_pair(buffer, acquireFence);
- mInflightBufferMap[key] = pair;
+ mInflightBufferMap[key] = buffer;
return OK;
}
@@ -4718,16 +4750,22 @@
uint64_t key = static_cast<uint64_t>(frameNumber) << 32 | static_cast<uint64_t>(streamId);
auto it = mInflightBufferMap.find(key);
if (it == mInflightBufferMap.end()) return NAME_NOT_FOUND;
- auto pair = it->second;
- *buffer = pair.first;
- int acquireFence = pair.second;
- if (acquireFence > 0) {
- ::close(acquireFence);
+ if (buffer != nullptr) {
+ *buffer = it->second;
}
mInflightBufferMap.erase(it);
return OK;
}
+void Camera3Device::HalInterface::popInflightBuffers(
+ const std::vector<std::pair<int32_t, int32_t>>& buffers) {
+ for (const auto& pair : buffers) {
+ int32_t frameNumber = pair.first;
+ int32_t streamId = pair.second;
+ popInflightBuffer(frameNumber, streamId, nullptr);
+ }
+}
+
status_t Camera3Device::HalInterface::pushInflightRequestBuffer(
uint64_t bufferId, buffer_handle_t* buf, int32_t streamId) {
std::lock_guard<std::mutex> lock(mRequestedBuffersLock);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 4a0d2b6..6e8ac84 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -358,13 +358,21 @@
// Do not free input camera3_capture_request_t before output HIDL request
status_t wrapAsHidlRequest(camera3_capture_request_t* in,
/*out*/hardware::camera::device::V3_2::CaptureRequest* out,
- /*out*/std::vector<native_handle_t*>* handlesCreated);
+ /*out*/std::vector<native_handle_t*>* handlesCreated,
+ /*out*/std::vector<std::pair<int32_t, int32_t>>* inflightBuffers);
status_t pushInflightBufferLocked(int32_t frameNumber, int32_t streamId,
- buffer_handle_t *buffer, int acquireFence);
+ buffer_handle_t *buffer);
+
+ // Pop inflight buffers based on pairs of (frameNumber,streamId)
+ void popInflightBuffers(const std::vector<std::pair<int32_t, int32_t>>& buffers);
+
// Cache of buffer handles keyed off (frameNumber << 32 | streamId)
- // value is a pair of (buffer_handle_t*, acquire_fence FD)
- std::unordered_map<uint64_t, std::pair<buffer_handle_t*, int>> mInflightBufferMap;
+ std::unordered_map<uint64_t, buffer_handle_t*> mInflightBufferMap;
+
+ // Delete and optionally close native handles and clear the input vector afterward
+ static void cleanupNativeHandles(
+ std::vector<native_handle_t*> *handles, bool closeFd = false);
struct BufferHasher {
size_t operator()(const buffer_handle_t& buf) const {