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