Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f6c05e4b authored by Chien-Yu Chen's avatar Chien-Yu Chen Committed by Android Git Automerger
Browse files

am 50d12164: Merge "Camera3Device: Support batch requests" into mnc-dr-dev

* commit '50d12164':
  Camera3Device: Support batch requests
parents 1f7c2457 50d12164
Loading
Loading
Loading
Loading
+318 −186
Original line number Diff line number Diff line
@@ -565,6 +565,18 @@ status_t Camera3Device::convertMetadataListToRequestListLocked(

        ALOGV("%s: requestId = %" PRId32, __FUNCTION__, newRequest->mResultExtras.requestId);
    }

    // Setup batch size if this is a high speed video recording request.
    if (mIsConstrainedHighSpeedConfiguration && requestList->size() > 0) {
        auto firstRequest = requestList->begin();
        for (auto& outputStream : (*firstRequest)->mOutputStreams) {
            if (outputStream->isVideoStream()) {
                (*firstRequest)->mBatchSize = requestList->size();
                break;
            }
        }
    }

    return OK;
}

@@ -1406,7 +1418,7 @@ status_t Camera3Device::flush(int64_t *frameNumber) {

    status_t res;
    if (mHal3Device->common.version >= CAMERA_DEVICE_API_VERSION_3_1) {
        res = mHal3Device->ops->flush(mHal3Device);
        res = mRequestThread->flush();
    } else {
        Mutex::Autolock l(mLock);
        res = waitUntilDrainedLocked();
@@ -1595,6 +1607,7 @@ sp<Camera3Device::CaptureRequest> Camera3Device::createCaptureRequest(
        newRequest->mOutputStreams.push(stream);
    }
    newRequest->mSettings.erase(ANDROID_REQUEST_OUTPUT_STREAMS);
    newRequest->mBatchSize = 1;

    return newRequest;
}
@@ -2766,6 +2779,17 @@ status_t Camera3Device::RequestThread::clear(
    return OK;
}

status_t Camera3Device::RequestThread::flush() {
    ATRACE_CALL();
    Mutex::Autolock l(mFlushLock);

    if (mHal3Device->common.version >= CAMERA_DEVICE_API_VERSION_3_1) {
        return mHal3Device->ops->flush(mHal3Device);
    }

    return -ENOTSUP;
}

void Camera3Device::RequestThread::setPaused(bool paused) {
    Mutex::Autolock l(mPauseLock);
    mDoPause = paused;
@@ -2856,7 +2880,7 @@ void Camera3Device::overrideResultForPrecaptureCancel(
}

bool Camera3Device::RequestThread::threadLoop() {

    ATRACE_CALL();
    status_t res;

    // Handle paused state.
@@ -2864,79 +2888,184 @@ bool Camera3Device::RequestThread::threadLoop() {
        return true;
    }

    // Get work to do

    sp<CaptureRequest> nextRequest = waitForNextRequest();
    if (nextRequest == NULL) {
    // Get next batch of requests.
    Vector<NextRequest> nextRequests;
    waitForNextRequestBatch(&nextRequests);
    const size_t numRequests = nextRequests.size();
    if (numRequests == 0) {
        return true;
    }

    // Create request to HAL
    camera3_capture_request_t request = camera3_capture_request_t();
    request.frame_number = nextRequest->mResultExtras.frameNumber;
    Vector<camera3_stream_buffer_t> outputBuffers;

    // Get the request ID, if any
    int requestId;
    camera_metadata_entry_t requestIdEntry =
            nextRequest->mSettings.find(ANDROID_REQUEST_ID);
    // Get the latest request ID, if any
    int latestRequestId;
    camera_metadata_entry_t requestIdEntry = nextRequests[nextRequests.size() - 1].
            captureRequest->mSettings.find(ANDROID_REQUEST_ID);
    if (requestIdEntry.count > 0) {
        requestId = requestIdEntry.data.i32[0];
        latestRequestId = requestIdEntry.data.i32[0];
    } else {
        ALOGW("%s: Did not have android.request.id set in the request",
                __FUNCTION__);
        requestId = NAME_NOT_FOUND;
        ALOGW("%s: Did not have android.request.id set in the request.", __FUNCTION__);
        latestRequestId = NAME_NOT_FOUND;
    }

    // Prepare a batch of HAL requests and output buffers.
    res = prepareHalRequests(&nextRequests);
    if (res == TIMED_OUT) {
        // Not a fatal error if getting output buffers time out.
        cleanUpFailedRequests(&nextRequests, /*sendRequestError*/ true);
        return true;
    } else if (res != OK) {
        cleanUpFailedRequests(&nextRequests, /*sendRequestError*/ false);
        return false;
    }

    // Inform waitUntilRequestProcessed thread of a new request ID
    {
        Mutex::Autolock al(mLatestRequestMutex);

        mLatestRequestId = latestRequestId;
        mLatestRequestSignal.signal();
    }

    // Submit a batch of requests to HAL.
    // Use flush lock only when submitting multilple requests in a batch.
    // TODO: The problem with flush lock is flush() will be blocked by process_capture_request()
    // which may take a long time to finish so synchronizing flush() and
    // process_capture_request() defeats the purpose of cancelling requests ASAP with flush().
    // For now, only synchronize for high speed recording and we should figure something out for
    // removing the synchronization.
    bool useFlushLock = nextRequests.size() > 1;

    if (useFlushLock) {
        mFlushLock.lock();
    }

    ALOGVV("%s: %d: submitting %d requests in a batch.", __FUNCTION__, __LINE__,
            nextRequests.size());
    for (auto& nextRequest : nextRequests) {
        // Submit request and block until ready for next one
        ATRACE_ASYNC_BEGIN("frame capture", nextRequest.halRequest.frame_number);
        ATRACE_BEGIN("camera3->process_capture_request");
        res = mHal3Device->ops->process_capture_request(mHal3Device, &nextRequest.halRequest);
        ATRACE_END();

        if (res != OK) {
            // Should only get a failure here for malformed requests or device-level
            // errors, so consider all errors fatal.  Bad metadata failures should
            // come through notify.
            SET_ERR("RequestThread: Unable to submit capture request %d to HAL"
                    " device: %s (%d)", nextRequest.halRequest.frame_number, strerror(-res),
                    res);
            cleanUpFailedRequests(&nextRequests, /*sendRequestError*/ false);
            if (useFlushLock) {
                mFlushLock.unlock();
            }
            return false;
        }

        // Mark that the request has be submitted successfully.
        nextRequest.submitted = true;

        // Update the latest request sent to HAL
        if (nextRequest.halRequest.settings != NULL) { // Don't update if they were unchanged
            Mutex::Autolock al(mLatestRequestMutex);

            camera_metadata_t* cloned = clone_camera_metadata(nextRequest.halRequest.settings);
            mLatestRequest.acquire(cloned);
        }

        if (nextRequest.halRequest.settings != NULL) {
            nextRequest.captureRequest->mSettings.unlock(nextRequest.halRequest.settings);
        }

        // Remove any previously queued triggers (after unlock)
        res = removeTriggers(mPrevRequest);
        if (res != OK) {
            SET_ERR("RequestThread: Unable to remove triggers "
                  "(capture request %d, HAL device: %s (%d)",
                  nextRequest.halRequest.frame_number, strerror(-res), res);
            cleanUpFailedRequests(&nextRequests, /*sendRequestError*/ false);
            if (useFlushLock) {
                mFlushLock.unlock();
            }
            return false;
        }
    }

    if (useFlushLock) {
        mFlushLock.unlock();
    }

    // Unset as current request
    {
        Mutex::Autolock l(mRequestLock);
        mNextRequests.clear();
    }

    return true;
}

status_t Camera3Device::RequestThread::prepareHalRequests(Vector<NextRequest> *nextRequests) {
    ATRACE_CALL();

    if (nextRequests == nullptr) {
        return BAD_VALUE;
    }

    for (auto& nextRequest : *nextRequests) {
        sp<CaptureRequest> captureRequest = nextRequest.captureRequest;
        camera3_capture_request_t* halRequest = &nextRequest.halRequest;
        Vector<camera3_stream_buffer_t>* outputBuffers = &nextRequest.outputBuffers;

        // Prepare a request to HAL
        halRequest->frame_number = captureRequest->mResultExtras.frameNumber;

        // Insert any queued triggers (before metadata is locked)
    int32_t triggerCount;
    res = insertTriggers(nextRequest);
        status_t res = insertTriggers(captureRequest);

        if (res < 0) {
            SET_ERR("RequestThread: Unable to insert triggers "
                    "(capture request %d, HAL device: %s (%d)",
                request.frame_number, strerror(-res), res);
        cleanUpFailedRequest(request, nextRequest, outputBuffers);
        return false;
                    halRequest->frame_number, strerror(-res), res);
            return INVALID_OPERATION;
        }
    triggerCount = res;

        int triggerCount = res;
        bool triggersMixedIn = (triggerCount > 0 || mPrevTriggers > 0);
        mPrevTriggers = triggerCount;

        // If the request is the same as last, or we had triggers last time
    if (mPrevRequest != nextRequest || triggersMixedIn) {
        if (mPrevRequest != captureRequest || triggersMixedIn) {
            /**
             * HAL workaround:
             * Insert a dummy trigger ID if a trigger is set but no trigger ID is
             */
        res = addDummyTriggerIds(nextRequest);
            res = addDummyTriggerIds(captureRequest);
            if (res != OK) {
                SET_ERR("RequestThread: Unable to insert dummy trigger IDs "
                        "(capture request %d, HAL device: %s (%d)",
                    request.frame_number, strerror(-res), res);
            cleanUpFailedRequest(request, nextRequest, outputBuffers);
            return false;
                        halRequest->frame_number, strerror(-res), res);
                return INVALID_OPERATION;
            }

            /**
             * The request should be presorted so accesses in HAL
             *   are O(logn). Sidenote, sorting a sorted metadata is nop.
             */
        nextRequest->mSettings.sort();
        request.settings = nextRequest->mSettings.getAndLock();
        mPrevRequest = nextRequest;
            captureRequest->mSettings.sort();
            halRequest->settings = captureRequest->mSettings.getAndLock();
            mPrevRequest = captureRequest;
            ALOGVV("%s: Request settings are NEW", __FUNCTION__);

            IF_ALOGV() {
                camera_metadata_ro_entry_t e = camera_metadata_ro_entry_t();
                find_camera_metadata_ro_entry(
                    request.settings,
                        halRequest->settings,
                        ANDROID_CONTROL_AF_TRIGGER,
                        &e
                );
                if (e.count > 0) {
                    ALOGV("%s: Request (frame num %d) had AF trigger 0x%x",
                          __FUNCTION__,
                      request.frame_number,
                          halRequest->frame_number,
                          e.data.u8[0]);
                }
            }
@@ -2949,118 +3078,56 @@ bool Camera3Device::RequestThread::threadLoop() {
        uint32_t totalNumBuffers = 0;

        // Fill in buffers
    if (nextRequest->mInputStream != NULL) {
        request.input_buffer = &nextRequest->mInputBuffer;
        if (captureRequest->mInputStream != NULL) {
            halRequest->input_buffer = &captureRequest->mInputBuffer;
            totalNumBuffers += 1;
        } else {
        request.input_buffer = NULL;
            halRequest->input_buffer = NULL;
        }

    outputBuffers.insertAt(camera3_stream_buffer_t(), 0,
            nextRequest->mOutputStreams.size());
    request.output_buffers = outputBuffers.array();
    for (size_t i = 0; i < nextRequest->mOutputStreams.size(); i++) {
        res = nextRequest->mOutputStreams.editItemAt(i)->
                getBuffer(&outputBuffers.editItemAt(i));
        outputBuffers->insertAt(camera3_stream_buffer_t(), 0,
                captureRequest->mOutputStreams.size());
        halRequest->output_buffers = outputBuffers->array();
        for (size_t i = 0; i < captureRequest->mOutputStreams.size(); i++) {
            res = captureRequest->mOutputStreams.editItemAt(i)->
                    getBuffer(&outputBuffers->editItemAt(i));
            if (res != OK) {
                // Can't get output buffer from gralloc queue - this could be due to
                // abandoned queue or other consumer misbehavior, so not a fatal
                // error
                ALOGE("RequestThread: Can't get output buffer, skipping request:"
                        " %s (%d)", strerror(-res), res);
            {
                Mutex::Autolock l(mRequestLock);
                if (mListener != NULL) {
                    mListener->notifyError(
                            ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST,
                            nextRequest->mResultExtras);
                }
            }
            cleanUpFailedRequest(request, nextRequest, outputBuffers);
            return true;

                return TIMED_OUT;
            }
        request.num_output_buffers++;
            halRequest->num_output_buffers++;
        }
    totalNumBuffers += request.num_output_buffers;
        totalNumBuffers += halRequest->num_output_buffers;

        // Log request in the in-flight queue
        sp<Camera3Device> parent = mParent.promote();
        if (parent == NULL) {
            // Should not happen, and nowhere to send errors to, so just log it
            CLOGE("RequestThread: Parent is gone");
        cleanUpFailedRequest(request, nextRequest, outputBuffers);
        return false;
            return INVALID_OPERATION;
        }

    res = parent->registerInFlight(request.frame_number,
            totalNumBuffers, nextRequest->mResultExtras,
            /*hasInput*/request.input_buffer != NULL,
            nextRequest->mAeTriggerCancelOverride);
        res = parent->registerInFlight(halRequest->frame_number,
                totalNumBuffers, captureRequest->mResultExtras,
                /*hasInput*/halRequest->input_buffer != NULL,
                captureRequest->mAeTriggerCancelOverride);
        ALOGVV("%s: registered in flight requestId = %" PRId32 ", frameNumber = %" PRId64
               ", burstId = %" PRId32 ".",
                __FUNCTION__,
            nextRequest->mResultExtras.requestId, nextRequest->mResultExtras.frameNumber,
            nextRequest->mResultExtras.burstId);
                captureRequest->mResultExtras.requestId, captureRequest->mResultExtras.frameNumber,
                captureRequest->mResultExtras.burstId);
        if (res != OK) {
            SET_ERR("RequestThread: Unable to register new in-flight request:"
                    " %s (%d)", strerror(-res), res);
        cleanUpFailedRequest(request, nextRequest, outputBuffers);
        return false;
    }

    // Inform waitUntilRequestProcessed thread of a new request ID
    {
        Mutex::Autolock al(mLatestRequestMutex);

        mLatestRequestId = requestId;
        mLatestRequestSignal.signal();
    }

    // Submit request and block until ready for next one
    ATRACE_ASYNC_BEGIN("frame capture", request.frame_number);
    ATRACE_BEGIN("camera3->process_capture_request");
    res = mHal3Device->ops->process_capture_request(mHal3Device, &request);
    ATRACE_END();

    if (res != OK) {
        // Should only get a failure here for malformed requests or device-level
        // errors, so consider all errors fatal.  Bad metadata failures should
        // come through notify.
        SET_ERR("RequestThread: Unable to submit capture request %d to HAL"
                " device: %s (%d)", request.frame_number, strerror(-res), res);
        cleanUpFailedRequest(request, nextRequest, outputBuffers);
        return false;
    }

    // Update the latest request sent to HAL
    if (request.settings != NULL) { // Don't update them if they were unchanged
        Mutex::Autolock al(mLatestRequestMutex);

        camera_metadata_t* cloned = clone_camera_metadata(request.settings);
        mLatestRequest.acquire(cloned);
    }

    if (request.settings != NULL) {
        nextRequest->mSettings.unlock(request.settings);
    }

    // Unset as current request
    {
        Mutex::Autolock l(mRequestLock);
        mNextRequest.clear();
            return INVALID_OPERATION;
        }

    // Remove any previously queued triggers (after unlock)
    res = removeTriggers(mPrevRequest);
    if (res != OK) {
        SET_ERR("RequestThread: Unable to remove triggers "
              "(capture request %d, HAL device: %s (%d)",
              request.frame_number, strerror(-res), res);
        return false;
    }
    mPrevTriggers = triggerCount;

    return true;
    return OK;
}

CameraMetadata Camera3Device::RequestThread::getLatestRequest() const {
@@ -3075,11 +3142,11 @@ bool Camera3Device::RequestThread::isStreamPending(
        sp<Camera3StreamInterface>& stream) {
    Mutex::Autolock l(mRequestLock);

    if (mNextRequest != nullptr) {
        for (const auto& s : mNextRequest->mOutputStreams) {
    for (const auto& nextRequest : mNextRequests) {
        for (const auto& s : nextRequest->mOutputStreams) {
            if (stream == s) return true;
        }
        if (stream == mNextRequest->mInputStream) return true;
        if (stream == nextRequest->mInputStream) return true;
    }

    for (const auto& request : mRequestQueue) {
@@ -3099,37 +3166,104 @@ bool Camera3Device::RequestThread::isStreamPending(
    return false;
}

void Camera3Device::RequestThread::cleanUpFailedRequest(
        camera3_capture_request_t &request,
        sp<CaptureRequest> &nextRequest,
        Vector<camera3_stream_buffer_t> &outputBuffers) {
void Camera3Device::RequestThread::cleanUpFailedRequests(Vector<NextRequest> *nextRequests,
        bool sendRequestError) {
    if (nextRequests == nullptr) {
        return;
    }

    for (auto& nextRequest : *nextRequests) {
        // Skip the ones that have been submitted successfully.
        if (nextRequest.submitted) {
            continue;
        }

        sp<CaptureRequest> captureRequest = nextRequest.captureRequest;
        camera3_capture_request_t* halRequest = &nextRequest.halRequest;
        Vector<camera3_stream_buffer_t>* outputBuffers = &nextRequest.outputBuffers;

    if (request.settings != NULL) {
        nextRequest->mSettings.unlock(request.settings);
        if (halRequest->settings != NULL) {
            captureRequest->mSettings.unlock(halRequest->settings);
        }
    if (nextRequest->mInputStream != NULL) {
        nextRequest->mInputBuffer.status = CAMERA3_BUFFER_STATUS_ERROR;
        nextRequest->mInputStream->returnInputBuffer(nextRequest->mInputBuffer);

        if (captureRequest->mInputStream != NULL) {
            captureRequest->mInputBuffer.status = CAMERA3_BUFFER_STATUS_ERROR;
            captureRequest->mInputStream->returnInputBuffer(captureRequest->mInputBuffer);
        }
    for (size_t i = 0; i < request.num_output_buffers; i++) {
        outputBuffers.editItemAt(i).status = CAMERA3_BUFFER_STATUS_ERROR;
        nextRequest->mOutputStreams.editItemAt(i)->returnBuffer(
            outputBuffers[i], 0);

        for (size_t i = 0; i < halRequest->num_output_buffers; i++) {
            outputBuffers->editItemAt(i).status = CAMERA3_BUFFER_STATUS_ERROR;
            captureRequest->mOutputStreams.editItemAt(i)->returnBuffer((*outputBuffers)[i], 0);
        }

        if (sendRequestError) {
            Mutex::Autolock l(mRequestLock);
    mNextRequest.clear();
            if (mListener != NULL) {
                mListener->notifyError(
                        ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST,
                        captureRequest->mResultExtras);
            }
        }
    }

sp<Camera3Device::CaptureRequest>
        Camera3Device::RequestThread::waitForNextRequest() {
    status_t res;
    sp<CaptureRequest> nextRequest;
    Mutex::Autolock l(mRequestLock);
    mNextRequests.clear();
    nextRequests->clear();
}

void Camera3Device::RequestThread::waitForNextRequestBatch(Vector<NextRequest> *nextRequests) {
    if (nextRequests == nullptr) {
        return;
    }

    // Optimized a bit for the simple steady-state case (single repeating
    // request), to avoid putting that request in the queue temporarily.
    Mutex::Autolock l(mRequestLock);

    nextRequests->clear();
    assert(mNextRequests.empty());

    NextRequest nextRequest;
    nextRequest.captureRequest = waitForNextRequestLocked();
    if (nextRequest.captureRequest == nullptr) {
        return;
    }

    nextRequest.halRequest = camera3_capture_request_t();
    nextRequest.submitted = false;
    nextRequests->add(nextRequest);
    mNextRequests.push_back(nextRequest.captureRequest);

    // Wait for additional requests
    const size_t batchSize = nextRequest.captureRequest->mBatchSize;

    for (size_t i = 1; i < batchSize; i++) {
        NextRequest additionalRequest;
        additionalRequest.captureRequest = waitForNextRequestLocked();
        if (additionalRequest.captureRequest == nullptr) {
            break;
        }

        additionalRequest.halRequest = camera3_capture_request_t();
        additionalRequest.submitted = false;
        nextRequests->add(additionalRequest);
        mNextRequests.push_back(additionalRequest.captureRequest);
    }

    if (nextRequests->size() < batchSize) {
        ALOGE("RequestThread: only get %d out of %d requests. Skipping requests.",
                nextRequests->size(), batchSize);
        cleanUpFailedRequests(nextRequests, /*sendRequestError*/true);
    }

    return;
}

sp<Camera3Device::CaptureRequest>
        Camera3Device::RequestThread::waitForNextRequestLocked() {
    status_t res;
    sp<CaptureRequest> nextRequest;

    while (mRequestQueue.empty()) {
        if (!mRepeatingRequests.empty()) {
            // Always atomically enqueue all requests in a repeating request
@@ -3224,8 +3358,6 @@ sp<Camera3Device::CaptureRequest>

    handleAePrecaptureCancelRequest(nextRequest);

    mNextRequest = nextRequest;

    return nextRequest;
}

+36 −11
Original line number Diff line number Diff line
@@ -264,6 +264,11 @@ class Camera3Device :
        // Used to cancel AE precapture trigger for devices doesn't support
        // CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL
        AeTriggerCancelOverride_t           mAeTriggerCancelOverride;
        // The number of requests that should be submitted to HAL at a time.
        // For example, if batch size is 8, this request and the following 7
        // requests will be submitted to HAL at a time. The batch size for
        // the following 7 requests will be ignored by the request thread.
        int                                 mBatchSize;
    };
    typedef List<sp<CaptureRequest> > RequestList;

@@ -440,6 +445,11 @@ class Camera3Device :
                       /*out*/
                       int64_t *lastFrameNumber = NULL);

        /**
         * Flush all pending requests in HAL.
         */
        status_t flush();

        /**
         * Queue a trigger to be dispatched with the next outgoing
         * process_capture_request. The settings for that request only
@@ -501,16 +511,28 @@ class Camera3Device :

        static const nsecs_t kRequestTimeout = 50e6; // 50 ms

        // Waits for a request, or returns NULL if times out.
        sp<CaptureRequest> waitForNextRequest();
        // Used to prepare a batch of requests.
        struct NextRequest {
            sp<CaptureRequest>              captureRequest;
            camera3_capture_request_t       halRequest;
            Vector<camera3_stream_buffer_t> outputBuffers;
            bool                            submitted;
        };

        // Wait for the next batch of requests.
        void waitForNextRequestBatch(Vector<NextRequest> *nextRequests);

        // Waits for a request, or returns NULL if times out. Must be called with mRequestLock hold.
        sp<CaptureRequest> waitForNextRequestLocked();

        // Return buffers, etc, for a request that couldn't be fully
        // constructed. The buffers will be returned in the ERROR state
        // to mark them as not having valid data.
        // All arguments will be modified.
        void cleanUpFailedRequest(camera3_capture_request_t &request,
                sp<CaptureRequest> &nextRequest,
                Vector<camera3_stream_buffer_t> &outputBuffers);
        // Prepare a HAL request and output buffers. Return TIMED_OUT if getting any output buffer
        // timed out. If an error is returned, the caller should clean up the pending request batch.
        status_t prepareHalRequests(Vector<NextRequest> *nextRequests);

        // Return buffers, etc, for a request that couldn't be fully constructed and send request
        // errors if sendRequestError is true. The buffers will be returned in the ERROR state
        // to mark them as not having valid data. nextRequests will be modified.
        void cleanUpFailedRequests(Vector<NextRequest> *nextRequests, bool sendRequestError);

        // Pause handling
        bool               waitIfPaused();
@@ -539,10 +561,13 @@ class Camera3Device :
        Condition          mRequestSignal;
        RequestList        mRequestQueue;
        RequestList        mRepeatingRequests;
        // The next request being prepped for submission to the HAL, no longer
        // The next requests being prepped for submission to the HAL, no longer
        // on the request queue. Read-only even with mRequestLock held, outside
        // of threadLoop
        sp<const CaptureRequest> mNextRequest;
        RequestList        mNextRequests;

        // To protect flush() and sending a request batch to HAL.
        Mutex              mFlushLock;

        bool               mReconfigured;

+4 −0
Original line number Diff line number Diff line
@@ -92,6 +92,10 @@ status_t Camera3DummyStream::getEndpointUsage(uint32_t *usage) const {
    return OK;
}

bool Camera3DummyStream::isVideoStream() const {
    return false;
}

}; // namespace camera3

}; // namespace android
+5 −0
Original line number Diff line number Diff line
@@ -54,6 +54,11 @@ class Camera3DummyStream :

    status_t         setTransform(int transform);

    /**
     * Return if this output stream is for video encoding.
     */
    bool isVideoStream() const;

  protected:

    /**
+11 −0

File changed.

Preview size limit exceeded, changes collapsed.

Loading