Jan Sebechlebsky | 5cb3996 | 2023-11-22 17:33:07 +0100 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2023 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_NDEBUG 0 |
| 18 | #define LOG_TAG "VirtualCameraStream" |
| 19 | #include "VirtualCameraStream.h" |
| 20 | |
| 21 | #include <cstdint> |
| 22 | #include <memory> |
| 23 | #include <mutex> |
| 24 | #include <tuple> |
| 25 | #include <utility> |
| 26 | |
| 27 | #include "EGL/egl.h" |
| 28 | #include "aidl/android/hardware/camera/device/Stream.h" |
| 29 | #include "aidl/android/hardware/camera/device/StreamBuffer.h" |
| 30 | #include "aidl/android/hardware/graphics/common/PixelFormat.h" |
| 31 | #include "aidlcommonsupport/NativeHandle.h" |
| 32 | #include "android/hardware_buffer.h" |
| 33 | #include "cutils/native_handle.h" |
| 34 | #include "ui/GraphicBuffer.h" |
| 35 | #include "ui/GraphicBufferMapper.h" |
| 36 | |
| 37 | namespace android { |
| 38 | namespace companion { |
| 39 | namespace virtualcamera { |
| 40 | |
| 41 | using ::aidl::android::hardware::camera::device::Stream; |
| 42 | using ::aidl::android::hardware::camera::device::StreamBuffer; |
| 43 | using ::aidl::android::hardware::common::NativeHandle; |
| 44 | using ::aidl::android::hardware::graphics::common::PixelFormat; |
| 45 | |
| 46 | namespace { |
| 47 | |
| 48 | sp<GraphicBuffer> createBlobGraphicBuffer(GraphicBufferMapper& mapper, |
| 49 | buffer_handle_t bufferHandle) { |
| 50 | uint64_t allocationSize; |
| 51 | uint64_t usage; |
| 52 | uint64_t layerCount; |
| 53 | if (mapper.getAllocationSize(bufferHandle, &allocationSize) != NO_ERROR || |
| 54 | mapper.getUsage(bufferHandle, &usage) != NO_ERROR || |
| 55 | mapper.getLayerCount(bufferHandle, &layerCount) != NO_ERROR) { |
| 56 | ALOGE("Error fetching metadata for the imported BLOB buffer handle."); |
| 57 | return nullptr; |
| 58 | } |
| 59 | |
| 60 | return sp<GraphicBuffer>::make( |
| 61 | bufferHandle, GraphicBuffer::HandleWrapMethod::TAKE_HANDLE, |
| 62 | allocationSize, /*height=*/1, static_cast<int>(ui::PixelFormat::BLOB), |
| 63 | layerCount, usage, 0); |
| 64 | } |
| 65 | |
| 66 | sp<GraphicBuffer> createYCbCr420GraphicBuffer(GraphicBufferMapper& mapper, |
| 67 | buffer_handle_t bufferHandle) { |
| 68 | uint64_t width; |
| 69 | uint64_t height; |
| 70 | uint64_t usage; |
| 71 | uint64_t layerCount; |
| 72 | if (mapper.getWidth(bufferHandle, &width) != NO_ERROR || |
| 73 | mapper.getHeight(bufferHandle, &height) != NO_ERROR || |
| 74 | mapper.getUsage(bufferHandle, &usage) != NO_ERROR || |
| 75 | mapper.getLayerCount(bufferHandle, &layerCount) != NO_ERROR) { |
| 76 | ALOGE("Error fetching metadata for the imported YCbCr420 buffer handle."); |
| 77 | return nullptr; |
| 78 | } |
| 79 | |
| 80 | return sp<GraphicBuffer>::make( |
| 81 | bufferHandle, GraphicBuffer::HandleWrapMethod::TAKE_HANDLE, width, height, |
| 82 | static_cast<int>(ui::PixelFormat::YCBCR_420_888), /*layers=*/1, usage, |
| 83 | width); |
| 84 | } |
| 85 | |
| 86 | std::shared_ptr<AHardwareBuffer> importBufferInternal( |
| 87 | const NativeHandle& aidlHandle, const Stream& streamConfig) { |
| 88 | if (aidlHandle.fds.empty()) { |
| 89 | ALOGE("Empty handle - nothing to import"); |
| 90 | return nullptr; |
| 91 | } |
| 92 | std::unique_ptr<native_handle_t, int (*)(native_handle_t*)> nativeHandle( |
| 93 | ::android::makeFromAidl(aidlHandle), native_handle_delete); |
| 94 | |
| 95 | GraphicBufferMapper& mapper = GraphicBufferMapper::get(); |
| 96 | |
| 97 | buffer_handle_t bufferHandle; |
| 98 | // Use importBufferNoValidate to rely on ground-truth metadata passed along |
| 99 | // the buffer. |
| 100 | int ret = mapper.importBufferNoValidate(nativeHandle.get(), &bufferHandle); |
| 101 | if (ret != NO_ERROR) { |
| 102 | ALOGE("Failed to import buffer handle: %d", ret); |
| 103 | return nullptr; |
| 104 | } |
| 105 | |
| 106 | sp<GraphicBuffer> buf = |
| 107 | streamConfig.format == PixelFormat::BLOB |
| 108 | ? createBlobGraphicBuffer(mapper, bufferHandle) |
| 109 | : createYCbCr420GraphicBuffer(mapper, bufferHandle); |
| 110 | |
| 111 | if (buf->initCheck() != NO_ERROR) { |
| 112 | ALOGE("Imported graphic buffer is not correcly initialized."); |
| 113 | return nullptr; |
| 114 | } |
| 115 | |
| 116 | AHardwareBuffer* rawPtr = buf->toAHardwareBuffer(); |
| 117 | AHardwareBuffer_acquire(rawPtr); |
| 118 | |
| 119 | return std::shared_ptr<AHardwareBuffer>(buf->toAHardwareBuffer(), |
| 120 | AHardwareBuffer_release); |
| 121 | } |
| 122 | |
| 123 | } // namespace |
| 124 | |
| 125 | VirtualCameraStream::VirtualCameraStream(const Stream& stream) |
| 126 | : mStreamConfig(stream) { |
| 127 | } |
| 128 | |
| 129 | std::shared_ptr<AHardwareBuffer> VirtualCameraStream::importBuffer( |
| 130 | const ::aidl::android::hardware::camera::device::StreamBuffer& buffer) { |
| 131 | auto hwBufferPtr = importBufferInternal(buffer.buffer, mStreamConfig); |
| 132 | if (hwBufferPtr != nullptr) { |
| 133 | std::lock_guard<std::mutex> lock(mLock); |
| 134 | mBuffers.emplace(std::piecewise_construct, |
| 135 | std::forward_as_tuple(buffer.bufferId), |
| 136 | std::forward_as_tuple(hwBufferPtr)); |
| 137 | } |
| 138 | return hwBufferPtr; |
| 139 | } |
| 140 | |
| 141 | std::shared_ptr<AHardwareBuffer> VirtualCameraStream::getHardwareBuffer( |
| 142 | const int bufferId) { |
| 143 | std::lock_guard<std::mutex> lock(mLock); |
| 144 | return getHardwareBufferLocked(bufferId); |
| 145 | } |
| 146 | |
| 147 | std::shared_ptr<EglFrameBuffer> VirtualCameraStream::getEglFrameBuffer( |
| 148 | const EGLDisplay eglDisplay, const int bufferId) { |
| 149 | const FramebufferMapKey key(bufferId, eglDisplay); |
| 150 | |
| 151 | std::lock_guard<std::mutex> lock(mLock); |
| 152 | |
| 153 | auto it = mEglFramebuffers.find(key); |
| 154 | if (it != mEglFramebuffers.end()) { |
| 155 | return it->second; |
| 156 | } |
| 157 | |
| 158 | std::shared_ptr<AHardwareBuffer> hwBufferPtr = |
| 159 | getHardwareBufferLocked(bufferId); |
| 160 | if (hwBufferPtr == nullptr) { |
| 161 | return nullptr; |
| 162 | } |
| 163 | std::shared_ptr<EglFrameBuffer> framebufferPtr = |
| 164 | std::make_shared<EglFrameBuffer>(eglDisplay, hwBufferPtr); |
| 165 | mEglFramebuffers.emplace(std::piecewise_construct, std::forward_as_tuple(key), |
| 166 | std::forward_as_tuple(framebufferPtr)); |
| 167 | |
| 168 | return framebufferPtr; |
| 169 | } |
| 170 | |
| 171 | std::shared_ptr<AHardwareBuffer> VirtualCameraStream::getHardwareBufferLocked( |
| 172 | const int bufferId) { |
| 173 | auto it = mBuffers.find(bufferId); |
| 174 | return it != mBuffers.end() ? it->second : nullptr; |
| 175 | } |
| 176 | |
| 177 | bool VirtualCameraStream::removeBuffer(int bufferId) { |
| 178 | std::lock_guard<std::mutex> lock(mLock); |
| 179 | |
| 180 | return mBuffers.erase(bufferId) == 1; |
| 181 | } |
| 182 | |
| 183 | Stream VirtualCameraStream::getStreamConfig() const { |
| 184 | return mStreamConfig; |
| 185 | } |
| 186 | |
| 187 | } // namespace virtualcamera |
| 188 | } // namespace companion |
| 189 | } // namespace android |