/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "StreamHandler.h" #include #include #include #include StreamHandler::StreamHandler(android::sp pCamera) : mCamera(pCamera) { // We rely on the camera having at least two buffers available since we'll hold one and // expect the camera to be able to capture a new image in the background. pCamera->setMaxFramesInFlight(2); } void StreamHandler::shutdown() { // Make sure we're not still streaming blockingStopStream(); // At this point, the receiver thread is no longer running, so we can safely drop // our remote object references so they can be freed mCamera = nullptr; } bool StreamHandler::startStream() { std::unique_lock lock(mLock); if (!mRunning) { // Tell the camera to start streaming Return result = mCamera->startVideoStream(this); if (result != EvsResult::OK) { return false; } // Mark ourselves as running mRunning = true; } return true; } void StreamHandler::asyncStopStream() { // Tell the camera to stop streaming. // This will result in a null frame being delivered when the stream actually stops. mCamera->stopVideoStream(); } void StreamHandler::blockingStopStream() { // Tell the stream to stop asyncStopStream(); // Wait until the stream has actually stopped std::unique_lock lock(mLock); if (mRunning) { mSignal.wait(lock, [this]() { return !mRunning; }); } } bool StreamHandler::isRunning() { std::unique_lock lock(mLock); return mRunning; } bool StreamHandler::newFrameAvailable() { std::unique_lock lock(mLock); return (mReadyBuffer >= 0); } const BufferDesc& StreamHandler::getNewFrame() { std::unique_lock lock(mLock); if (mHeldBuffer >= 0) { ALOGE("Ignored call for new frame while still holding the old one."); } else { if (mReadyBuffer < 0) { ALOGE("Returning invalid buffer because we don't have any. Call newFrameAvailable first?"); mReadyBuffer = 0; // This is a lie! } // Move the ready buffer into the held position, and clear the ready position mHeldBuffer = mReadyBuffer; mReadyBuffer = -1; } return mBuffers[mHeldBuffer]; } void StreamHandler::doneWithFrame(const BufferDesc& buffer) { std::unique_lock lock(mLock); // We better be getting back the buffer we original delivered! if ((mHeldBuffer < 0) || (buffer.bufferId != mBuffers[mHeldBuffer].bufferId)) { ALOGE("StreamHandler::doneWithFrame got an unexpected buffer!"); } // Send the buffer back to the underlying camera mCamera->doneWithFrame(mBuffers[mHeldBuffer]); // Clear the held position mHeldBuffer = -1; } Return StreamHandler::deliverFrame(const BufferDesc& buffer) { ALOGD("Received a frame from the camera (%p)", buffer.memHandle.getNativeHandle()); // Take the lock to protect our frame slots and running state variable { std::unique_lock lock(mLock); if (buffer.memHandle.getNativeHandle() == nullptr) { // Signal that the last frame has been received and the stream is stopped mRunning = false; } else { // Do we already have a "ready" frame? if (mReadyBuffer >= 0) { // Send the previously saved buffer back to the camera unused mCamera->doneWithFrame(mBuffers[mReadyBuffer]); // We'll reuse the same ready buffer index } else if (mHeldBuffer >= 0) { // The client is holding a buffer, so use the other slot for "on deck" mReadyBuffer = 1 - mHeldBuffer; } else { // This is our first buffer, so just pick a slot mReadyBuffer = 0; } // Save this frame until our client is interested in it mBuffers[mReadyBuffer] = buffer; } } // Notify anybody who cares that things have changed mSignal.notify_all(); return Void(); }