1/* 2 * Copyright (C) 2016 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 "HalCamera.h" 18#include "VirtualCamera.h" 19#include "Enumerator.h" 20 21#include <ui/GraphicBufferAllocator.h> 22#include <ui/GraphicBufferMapper.h> 23 24 25namespace android { 26namespace automotive { 27namespace evs { 28namespace V1_0 { 29namespace implementation { 30 31 32// TODO: We need to hook up death monitoring to detect stream death so we can attempt a reconnect 33 34 35sp<VirtualCamera> HalCamera::makeVirtualCamera() { 36 37 // Create the client camera interface object 38 sp<VirtualCamera> client = new VirtualCamera(this); 39 if (client == nullptr) { 40 ALOGE("Failed to create client camera object"); 41 return nullptr; 42 } 43 44 // Make sure we have enough buffers available for all our clients 45 if (!changeFramesInFlight(client->getAllowedBuffers())) { 46 // Gah! We couldn't get enough buffers, so we can't support this client 47 // Null the pointer, dropping our reference, thus destroying the client object 48 client = nullptr; 49 return nullptr; 50 } 51 52 // Add this client to our ownership list via weak pointer 53 mClients.push_back(client); 54 55 // Return the strong pointer to the client 56 return client; 57} 58 59 60void HalCamera::disownVirtualCamera(sp<VirtualCamera> virtualCamera) { 61 // Ignore calls with null pointers 62 if (virtualCamera.get() == nullptr) { 63 ALOGW("Ignoring disownVirtualCamera call with null pointer"); 64 return; 65 } 66 67 // Make sure the virtual camera's stream is stopped 68 virtualCamera->stopVideoStream(); 69 70 // Remove the virtual camera from our client list 71 unsigned clientCount = mClients.size(); 72 mClients.remove(virtualCamera); 73 if (clientCount != mClients.size() + 1) { 74 ALOGE("Couldn't find camera in our client list to remove it"); 75 } 76 virtualCamera->shutdown(); 77 78 // Recompute the number of buffers required with the target camera removed from the list 79 if (!changeFramesInFlight(0)) { 80 ALOGE("Error when trying to reduce the in flight buffer count"); 81 } 82} 83 84 85bool HalCamera::changeFramesInFlight(int delta) { 86 // Walk all our clients and count their currently required frames 87 unsigned bufferCount = 0; 88 for (auto&& client : mClients) { 89 sp<VirtualCamera> virtCam = client.promote(); 90 if (virtCam != nullptr) { 91 bufferCount += virtCam->getAllowedBuffers(); 92 } 93 } 94 95 // Add the requested delta 96 bufferCount += delta; 97 98 // Never drop below 1 buffer -- even if all client cameras get closed 99 if (bufferCount < 1) { 100 bufferCount = 1; 101 } 102 103 // Ask the hardware for the resulting buffer count 104 Return<EvsResult> result = mHwCamera->setMaxFramesInFlight(bufferCount); 105 bool success = (result.isOk() && result == EvsResult::OK); 106 107 // Update the size of our array of outstanding frame records 108 if (success) { 109 std::vector<FrameRecord> newRecords; 110 newRecords.reserve(bufferCount); 111 112 // Copy and compact the old records that are still active 113 for (const auto& rec : mFrames) { 114 if (rec.refCount > 0) { 115 newRecords.emplace_back(rec); 116 } 117 } 118 if (newRecords.size() > (unsigned)bufferCount) { 119 ALOGW("We found more frames in use than requested."); 120 } 121 122 mFrames.swap(newRecords); 123 } 124 125 return success; 126} 127 128 129Return<EvsResult> HalCamera::clientStreamStarting() { 130 Return<EvsResult> result = EvsResult::OK; 131 132 if (mStreamState == STOPPED) { 133 result = mHwCamera->startVideoStream(this); 134 } 135 136 return result; 137} 138 139 140void HalCamera::clientStreamEnding() { 141 // Do we still have a running client? 142 bool stillRunning = false; 143 for (auto&& client : mClients) { 144 sp<VirtualCamera> virtCam = client.promote(); 145 if (virtCam != nullptr) { 146 stillRunning |= virtCam->isStreaming(); 147 } 148 } 149 150 // If not, then stop the hardware stream 151 if (!stillRunning) { 152 mHwCamera->stopVideoStream(); 153 } 154} 155 156 157Return<void> HalCamera::doneWithFrame(const BufferDesc& buffer) { 158 // Find this frame in our list of outstanding frames 159 unsigned i; 160 for (i=0; i<mFrames.size(); i++) { 161 if (mFrames[i].frameId == buffer.bufferId) { 162 break; 163 } 164 } 165 if (i == mFrames.size()) { 166 ALOGE("We got a frame back with an ID we don't recognize!"); 167 } else { 168 // Are there still clients using this buffer? 169 mFrames[i].refCount--; 170 if (mFrames[i].refCount <= 0) { 171 // Since all our clients are done with this buffer, return it to the device layer 172 mHwCamera->doneWithFrame(buffer); 173 } 174 } 175 176 return Void(); 177} 178 179 180Return<void> HalCamera::deliverFrame(const BufferDesc& buffer) { 181 // Run through all our clients and deliver this frame to any who are eligible 182 unsigned frameDeliveries = 0; 183 for (auto&& client : mClients) { 184 sp<VirtualCamera> virtCam = client.promote(); 185 if (virtCam != nullptr) { 186 if (virtCam->deliverFrame(buffer)) { 187 frameDeliveries++; 188 } 189 } 190 } 191 192 if (frameDeliveries < 1) { 193 // If none of our clients could accept the frame, then return it right away 194 ALOGI("Trivially rejecting frame with no acceptances"); 195 mHwCamera->doneWithFrame(buffer); 196 } else { 197 // Add an entry for this frame in our tracking list 198 unsigned i; 199 for (i=0; i<mFrames.size(); i++) { 200 if (mFrames[i].refCount == 0) { 201 break; 202 } 203 } 204 if (i == mFrames.size()) { 205 mFrames.emplace_back(buffer.bufferId); 206 } else { 207 mFrames[i].frameId = buffer.bufferId; 208 } 209 mFrames[i].refCount = frameDeliveries; 210 } 211 212 return Void(); 213} 214 215} // namespace implementation 216} // namespace V1_0 217} // namespace evs 218} // namespace automotive 219} // namespace android 220