• 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 #include "VirtualCamera.h"
19 #include "Enumerator.h"
20 
21 #include <ui/GraphicBufferAllocator.h>
22 #include <ui/GraphicBufferMapper.h>
23 
24 
25 namespace android {
26 namespace automotive {
27 namespace evs {
28 namespace V1_0 {
29 namespace implementation {
30 
31 
32 // TODO:  We need to hook up death monitoring to detect stream death so we can attempt a reconnect
33 
34 
makeVirtualCamera()35 sp<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 
disownVirtualCamera(sp<VirtualCamera> virtualCamera)60 void 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 
changeFramesInFlight(int delta)85 bool 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 
clientStreamStarting()129 Return<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 
clientStreamEnding()140 void 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 
doneWithFrame(const BufferDesc & buffer)157 Return<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 
deliverFrame(const BufferDesc & buffer)180 Return<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