1 /* 2 * Copyright (C) 2017 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 "StreamHandler.h" 18 19 #include <stdio.h> 20 #include <string.h> 21 22 #include <log/log.h> 23 #include <cutils/native_handle.h> 24 25 26 StreamHandler::StreamHandler(android::sp <IEvsCamera> pCamera) : 27 mCamera(pCamera) 28 { 29 // We rely on the camera having at least two buffers available since we'll hold one and 30 // expect the camera to be able to capture a new image in the background. 31 pCamera->setMaxFramesInFlight(2); 32 } 33 34 35 void StreamHandler::shutdown() 36 { 37 // Make sure we're not still streaming 38 blockingStopStream(); 39 40 // At this point, the receiver thread is no longer running, so we can safely drop 41 // our remote object references so they can be freed 42 mCamera = nullptr; 43 } 44 45 46 bool StreamHandler::startStream() { 47 std::unique_lock<std::mutex> lock(mLock); 48 49 if (!mRunning) { 50 // Tell the camera to start streaming 51 Return <EvsResult> result = mCamera->startVideoStream(this); 52 if (result != EvsResult::OK) { 53 return false; 54 } 55 56 // Mark ourselves as running 57 mRunning = true; 58 } 59 60 return true; 61 } 62 63 64 void StreamHandler::asyncStopStream() { 65 // Tell the camera to stop streaming. 66 // This will result in a null frame being delivered when the stream actually stops. 67 mCamera->stopVideoStream(); 68 } 69 70 71 void StreamHandler::blockingStopStream() { 72 // Tell the stream to stop 73 asyncStopStream(); 74 75 // Wait until the stream has actually stopped 76 std::unique_lock<std::mutex> lock(mLock); 77 if (mRunning) { 78 mSignal.wait(lock, [this]() { return !mRunning; }); 79 } 80 } 81 82 83 bool StreamHandler::isRunning() { 84 std::unique_lock<std::mutex> lock(mLock); 85 return mRunning; 86 } 87 88 89 bool StreamHandler::newFrameAvailable() { 90 std::unique_lock<std::mutex> lock(mLock); 91 return (mReadyBuffer >= 0); 92 } 93 94 95 const BufferDesc& StreamHandler::getNewFrame() { 96 std::unique_lock<std::mutex> lock(mLock); 97 98 if (mHeldBuffer >= 0) { 99 ALOGE("Ignored call for new frame while still holding the old one."); 100 } else { 101 if (mReadyBuffer < 0) { 102 ALOGE("Returning invalid buffer because we don't have any. Call newFrameAvailable first?"); 103 mReadyBuffer = 0; // This is a lie! 104 } 105 106 // Move the ready buffer into the held position, and clear the ready position 107 mHeldBuffer = mReadyBuffer; 108 mReadyBuffer = -1; 109 } 110 111 return mBuffers[mHeldBuffer]; 112 } 113 114 115 void StreamHandler::doneWithFrame(const BufferDesc& buffer) { 116 std::unique_lock<std::mutex> lock(mLock); 117 118 // We better be getting back the buffer we original delivered! 119 if ((mHeldBuffer < 0) || (buffer.bufferId != mBuffers[mHeldBuffer].bufferId)) { 120 ALOGE("StreamHandler::doneWithFrame got an unexpected buffer!"); 121 } 122 123 // Send the buffer back to the underlying camera 124 mCamera->doneWithFrame(mBuffers[mHeldBuffer]); 125 126 // Clear the held position 127 mHeldBuffer = -1; 128 } 129 130 131 Return<void> StreamHandler::deliverFrame(const BufferDesc& buffer) { 132 ALOGD("Received a frame from the camera (%p)", buffer.memHandle.getNativeHandle()); 133 134 // Take the lock to protect our frame slots and running state variable 135 { 136 std::unique_lock <std::mutex> lock(mLock); 137 138 if (buffer.memHandle.getNativeHandle() == nullptr) { 139 // Signal that the last frame has been received and the stream is stopped 140 mRunning = false; 141 } else { 142 // Do we already have a "ready" frame? 143 if (mReadyBuffer >= 0) { 144 // Send the previously saved buffer back to the camera unused 145 mCamera->doneWithFrame(mBuffers[mReadyBuffer]); 146 147 // We'll reuse the same ready buffer index 148 } else if (mHeldBuffer >= 0) { 149 // The client is holding a buffer, so use the other slot for "on deck" 150 mReadyBuffer = 1 - mHeldBuffer; 151 } else { 152 // This is our first buffer, so just pick a slot 153 mReadyBuffer = 0; 154 } 155 156 // Save this frame until our client is interested in it 157 mBuffers[mReadyBuffer] = buffer; 158 } 159 } 160 161 // Notify anybody who cares that things have changed 162 mSignal.notify_all(); 163 164 return Void(); 165 } 166