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 #include "Util.h"
18
19 #include <unistd.h>
20
21 #include <algorithm>
22 #include <array>
23 #include <cstdint>
24 #include <memory>
25
26 #include "EglUtil.h"
27 #include "android/hardware_buffer.h"
28 #include "jpeglib.h"
29 #include "ui/GraphicBuffer.h"
30 #include "utils/Errors.h"
31
32 namespace android {
33 namespace companion {
34 namespace virtualcamera {
35
36 using ::aidl::android::companion::virtualcamera::Format;
37 using ::aidl::android::hardware::common::NativeHandle;
38
39 constexpr int kMaxFpsUpperLimit = 60;
40
41 constexpr std::array<Format, 2> kSupportedFormats{Format::YUV_420_888,
42 Format::RGBA_8888};
43
YCbCrLockGuard(std::shared_ptr<AHardwareBuffer> hwBuffer,const uint32_t usageFlags)44 YCbCrLockGuard::YCbCrLockGuard(std::shared_ptr<AHardwareBuffer> hwBuffer,
45 const uint32_t usageFlags)
46 : mHwBuffer(hwBuffer) {
47 GraphicBuffer* gBuffer = GraphicBuffer::fromAHardwareBuffer(mHwBuffer.get());
48 if (gBuffer == nullptr) {
49 ALOGE("%s: Attempting to lock nullptr buffer.", __func__);
50 return;
51 }
52 mLockStatus = gBuffer->lockYCbCr(usageFlags, &mYCbCr);
53 if (mLockStatus != OK) {
54 ALOGE("%s: Failed to lock graphic buffer: %s", __func__,
55 statusToString(mLockStatus).c_str());
56 }
57 }
58
~YCbCrLockGuard()59 YCbCrLockGuard::~YCbCrLockGuard() {
60 if (getStatus() != OK) {
61 return;
62 }
63
64 GraphicBuffer* gBuffer = GraphicBuffer::fromAHardwareBuffer(mHwBuffer.get());
65 if (gBuffer == nullptr) {
66 return;
67 }
68 status_t status = gBuffer->unlock();
69 if (status != NO_ERROR) {
70 ALOGE("Failed to unlock graphic buffer: %s", statusToString(status).c_str());
71 }
72 }
73
getStatus() const74 status_t YCbCrLockGuard::getStatus() const {
75 return mLockStatus;
76 }
77
operator *() const78 const android_ycbcr& YCbCrLockGuard::operator*() const {
79 LOG_ALWAYS_FATAL_IF(getStatus() != OK,
80 "Dereferencing unlocked YCbCrLockGuard, status is %s",
81 statusToString(mLockStatus).c_str());
82 return mYCbCr;
83 }
84
PlanesLockGuard(std::shared_ptr<AHardwareBuffer> hwBuffer,const uint64_t usageFlags,sp<Fence> fence)85 PlanesLockGuard::PlanesLockGuard(std::shared_ptr<AHardwareBuffer> hwBuffer,
86 const uint64_t usageFlags, sp<Fence> fence) {
87 if (hwBuffer == nullptr) {
88 ALOGE("%s: Attempting to lock nullptr buffer.", __func__);
89 return;
90 }
91
92 const int32_t rawFence = fence != nullptr ? dup(fence->get()) : -1;
93 mLockStatus = static_cast<status_t>(AHardwareBuffer_lockPlanes(
94 hwBuffer.get(), usageFlags, rawFence, nullptr, &mPlanes));
95 if (mLockStatus != OK) {
96 ALOGE("%s: Failed to lock graphic buffer: %s", __func__,
97 statusToString(mLockStatus).c_str());
98 }
99 if (rawFence >= 0) {
100 close(rawFence);
101 }
102 }
103
~PlanesLockGuard()104 PlanesLockGuard::~PlanesLockGuard() {
105 if (getStatus() != OK || mHwBuffer == nullptr) {
106 return;
107 }
108 AHardwareBuffer_unlock(mHwBuffer.get(), /*fence=*/nullptr);
109 }
110
getStatus() const111 int PlanesLockGuard::getStatus() const {
112 return mLockStatus;
113 }
114
operator *() const115 const AHardwareBuffer_Planes& PlanesLockGuard::operator*() const {
116 LOG_ALWAYS_FATAL_IF(getStatus() != OK,
117 "Dereferencing unlocked PlanesLockGuard, status is %s",
118 statusToString(mLockStatus).c_str());
119 return mPlanes;
120 }
121
importFence(const NativeHandle & aidlHandle)122 sp<Fence> importFence(const NativeHandle& aidlHandle) {
123 if (aidlHandle.fds.size() != 1) {
124 return sp<Fence>::make();
125 }
126
127 return sp<Fence>::make(::dup(aidlHandle.fds[0].get()));
128 }
129
isPixelFormatSupportedForInput(const Format format)130 bool isPixelFormatSupportedForInput(const Format format) {
131 return std::find(kSupportedFormats.begin(), kSupportedFormats.end(),
132 format) != kSupportedFormats.end();
133 }
134
135 // Returns true if specified format is supported for virtual camera input.
isFormatSupportedForInput(const int width,const int height,const Format format,const int maxFps)136 bool isFormatSupportedForInput(const int width, const int height,
137 const Format format, const int maxFps) {
138 if (!isPixelFormatSupportedForInput(format)) {
139 return false;
140 }
141
142 int maxTextureSize = getMaximumTextureSize();
143 if (width <= 0 || height <= 0 || width > maxTextureSize ||
144 height > maxTextureSize) {
145 return false;
146 }
147
148 if (maxFps <= 0 || maxFps > kMaxFpsUpperLimit) {
149 return false;
150 }
151
152 return true;
153 }
154
operator <<(std::ostream & os,const Resolution & resolution)155 std::ostream& operator<<(std::ostream& os, const Resolution& resolution) {
156 return os << resolution.width << "x" << resolution.height;
157 }
158
159 } // namespace virtualcamera
160 } // namespace companion
161 } // namespace android
162