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 ? 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 }
100
~PlanesLockGuard()101 PlanesLockGuard::~PlanesLockGuard() {
102 if (getStatus() != OK || mHwBuffer == nullptr) {
103 return;
104 }
105 AHardwareBuffer_unlock(mHwBuffer.get(), /*fence=*/nullptr);
106 }
107
getStatus() const108 int PlanesLockGuard::getStatus() const {
109 return mLockStatus;
110 }
111
operator *() const112 const AHardwareBuffer_Planes& PlanesLockGuard::operator*() const {
113 LOG_ALWAYS_FATAL_IF(getStatus() != OK,
114 "Dereferencing unlocked PlanesLockGuard, status is %s",
115 statusToString(mLockStatus).c_str());
116 return mPlanes;
117 }
118
importFence(const NativeHandle & aidlHandle)119 sp<Fence> importFence(const NativeHandle& aidlHandle) {
120 if (aidlHandle.fds.size() != 1) {
121 return sp<Fence>::make();
122 }
123
124 return sp<Fence>::make(::dup(aidlHandle.fds[0].get()));
125 }
126
isPixelFormatSupportedForInput(const Format format)127 bool isPixelFormatSupportedForInput(const Format format) {
128 return std::find(kSupportedFormats.begin(), kSupportedFormats.end(),
129 format) != kSupportedFormats.end();
130 }
131
132 // Returns true if specified format is supported for virtual camera input.
isFormatSupportedForInput(const int width,const int height,const Format format,const int maxFps)133 bool isFormatSupportedForInput(const int width, const int height,
134 const Format format, const int maxFps) {
135 if (!isPixelFormatSupportedForInput(format)) {
136 return false;
137 }
138
139 int maxTextureSize = getMaximumTextureSize();
140 if (width <= 0 || height <= 0 || width > maxTextureSize ||
141 height > maxTextureSize) {
142 return false;
143 }
144
145 if (maxFps <= 0 || maxFps > kMaxFpsUpperLimit) {
146 return false;
147 }
148
149 return true;
150 }
151
operator <<(std::ostream & os,const Resolution & resolution)152 std::ostream& operator<<(std::ostream& os, const Resolution& resolution) {
153 return os << resolution.width << "x" << resolution.height;
154 }
155
156 } // namespace virtualcamera
157 } // namespace companion
158 } // namespace android
159