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

Commit 30e65e7e authored by Eino-Ville Talvala's avatar Eino-Ville Talvala Committed by Android (Google) Code Review
Browse files

Camera2: Replace MediaConsumer with BufferItemConsumer.

Get rid of MediaConsumer, which was largely duplicated code, and
replace it with the simpler BufferItemConsumer.

Bug: 6243944
Change-Id: I242d80c5fe39f2ee581ec8bb46f362997d994b0a
parent 76dc8dac
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -10,8 +10,7 @@ LOCAL_SRC_FILES:= \
    CameraService.cpp \
    CameraClient.cpp \
    Camera2Client.cpp \
    Camera2Device.cpp \
    MediaConsumer.cpp
    Camera2Device.cpp

LOCAL_SHARED_LIBRARIES:= \
    libui \
+52 −13
Original line number Diff line number Diff line
@@ -920,6 +920,9 @@ void Camera2Client::releaseRecordingFrame(const sp<IMemory>& mem) {
    Mutex::Autolock icl(mICameraLock);
    status_t res;
    if ( checkPid(__FUNCTION__) != OK) return;

    LockedParameters::Key k(mParameters);

    // Make sure this is for the current heap
    ssize_t offset;
    size_t size;
@@ -937,16 +940,36 @@ void Camera2Client::releaseRecordingFrame(const sp<IMemory>& mem) {
                __FUNCTION__, mCameraId, type, kMetadataBufferTypeGrallocSource);
        return;
    }
    buffer_handle_t imgBuffer = *(buffer_handle_t*)(data + 4);

    // Release the buffer back to the recording queue

    buffer_handle_t imgHandle = *(buffer_handle_t*)(data + 4);

    size_t itemIndex;
    for (itemIndex = 0; itemIndex < mRecordingBuffers.size(); itemIndex++) {
        const BufferItemConsumer::BufferItem item = mRecordingBuffers[itemIndex];
        if (item.mBuf != BufferItemConsumer::INVALID_BUFFER_SLOT &&
                item.mGraphicBuffer->handle == imgHandle) {
            break;
        }
    }
    if (itemIndex == mRecordingBuffers.size()) {
        ALOGE("%s: Camera %d: Can't find buffer_handle_t %p in list of "
                "outstanding buffers", __FUNCTION__, mCameraId, imgHandle);
        return;
    }

    ALOGV("%s: Camera %d: Freeing buffer_handle_t %p", __FUNCTION__, mCameraId,
            imgBuffer);
    res = mRecordingConsumer->freeBuffer(imgBuffer);
            imgHandle);

    res = mRecordingConsumer->releaseBuffer(mRecordingBuffers[itemIndex]);
    if (res != OK) {
        ALOGE("%s: Camera %d: Unable to free recording frame (buffer_handle_t: %p):"
                "%s (%d)",
                __FUNCTION__, mCameraId, imgBuffer, strerror(-res), res);
                __FUNCTION__, mCameraId, imgHandle, strerror(-res), res);
        return;
    }
    mRecordingBuffers.replaceAt(itemIndex);

    mRecordingHeapFree++;
}
@@ -2313,13 +2336,14 @@ void Camera2Client::onRecordingFrameAvailable() {
    {
        LockedParameters::Key k(mParameters);

        buffer_handle_t imgBuffer;
        res = mRecordingConsumer->getNextBuffer(&imgBuffer, &timestamp);
        BufferItemConsumer::BufferItem imgBuffer;
        res = mRecordingConsumer->acquireBuffer(&imgBuffer);
        if (res != OK) {
            ALOGE("%s: Camera %d: Error receiving recording buffer: %s (%d)",
                    __FUNCTION__, mCameraId, strerror(-res), res);
            return;
        }
        timestamp = imgBuffer.mTimestamp;

        mRecordingFrameCount++;
        ALOGV("OnRecordingFrame: Frame %d", mRecordingFrameCount);
@@ -2330,7 +2354,7 @@ void Camera2Client::onRecordingFrameAvailable() {
            ALOGV("%s: Camera %d: Discarding recording image buffers received after "
                    "recording done",
                    __FUNCTION__, mCameraId);
            mRecordingConsumer->freeBuffer(imgBuffer);
            mRecordingConsumer->releaseBuffer(imgBuffer);
            return;
        }

@@ -2345,9 +2369,20 @@ void Camera2Client::onRecordingFrameAvailable() {
            if (mRecordingHeap->mHeap->getSize() == 0) {
                ALOGE("%s: Camera %d: Unable to allocate memory for recording",
                        __FUNCTION__, mCameraId);
                mRecordingConsumer->freeBuffer(imgBuffer);
                mRecordingConsumer->releaseBuffer(imgBuffer);
                return;
            }
            for (size_t i = 0; i < mRecordingBuffers.size(); i++) {
                if (mRecordingBuffers[i].mBuf !=
                        BufferItemConsumer::INVALID_BUFFER_SLOT) {
                    ALOGE("%s: Camera %d: Non-empty recording buffers list!",
                            __FUNCTION__, mCameraId);
                }
            }
            mRecordingBuffers.clear();
            mRecordingBuffers.setCapacity(mRecordingHeapCount);
            mRecordingBuffers.insertAt(0, mRecordingHeapCount);

            mRecordingHeapHead = 0;
            mRecordingHeapFree = mRecordingHeapCount;
        }
@@ -2355,7 +2390,7 @@ void Camera2Client::onRecordingFrameAvailable() {
        if ( mRecordingHeapFree == 0) {
            ALOGE("%s: Camera %d: No free recording buffers, dropping frame",
                    __FUNCTION__, mCameraId);
            mRecordingConsumer->freeBuffer(imgBuffer);
            mRecordingConsumer->releaseBuffer(imgBuffer);
            return;
        }

@@ -2374,10 +2409,11 @@ void Camera2Client::onRecordingFrameAvailable() {

        uint8_t *data = (uint8_t*)heap->getBase() + offset;
        uint32_t type = kMetadataBufferTypeGrallocSource;
        memcpy(data, &type, 4);
        memcpy(data + 4, &imgBuffer, sizeof(buffer_handle_t));
        *((uint32_t*)data) = type;
        *((buffer_handle_t*)(data + 4)) = imgBuffer.mGraphicBuffer->handle;
        ALOGV("%s: Camera %d: Sending out buffer_handle_t %p",
                __FUNCTION__, mCameraId, imgBuffer);
                __FUNCTION__, mCameraId, imgBuffer.mGraphicBuffer->handle);
        mRecordingBuffers.replaceAt(imgBuffer, heapIdx);
        recordingHeap = mRecordingHeap;
    }

@@ -3530,7 +3566,10 @@ status_t Camera2Client::updateRecordingStream(const Parameters &params) {
        // Create CPU buffer queue endpoint. We need one more buffer here so that we can
        // always acquire and free a buffer when the heap is full; otherwise the consumer
        // will have buffers in flight we'll never clear out.
        mRecordingConsumer = new MediaConsumer(mRecordingHeapCount + 1);
        mRecordingConsumer = new BufferItemConsumer(
                GRALLOC_USAGE_HW_VIDEO_ENCODER,
                mRecordingHeapCount + 1,
                true);
        mRecordingConsumer->setFrameAvailableListener(new RecordingWaiter(this));
        mRecordingConsumer->setName(String8("Camera2Client::RecordingConsumer"));
        mRecordingWindow = new SurfaceTextureClient(
+7 −6
Original line number Diff line number Diff line
@@ -23,7 +23,7 @@
#include <binder/MemoryBase.h>
#include <binder/MemoryHeapBase.h>
#include <gui/CpuConsumer.h>
#include "MediaConsumer.h"
#include <gui/BufferItemConsumer.h>

namespace android {

@@ -363,11 +363,11 @@ private:

    int mRecordingStreamId;
    int mRecordingFrameCount;
    sp<MediaConsumer>    mRecordingConsumer;
    sp<BufferItemConsumer>    mRecordingConsumer;
    sp<ANativeWindow>  mRecordingWindow;
    // Simple listener that forwards frame available notifications from
    // a CPU consumer to the recording notification
    class RecordingWaiter: public MediaConsumer::FrameAvailableListener {
    class RecordingWaiter: public BufferItemConsumer::FrameAvailableListener {
      public:
        RecordingWaiter(Camera2Client *parent) : mParent(parent) {}
        void onFrameAvailable() { mParent->onRecordingFrameAvailable(); }
@@ -380,6 +380,7 @@ private:

    static const size_t kDefaultRecordingHeapCount = 8;
    size_t mRecordingHeapCount;
    Vector<BufferItemConsumer::BufferItem> mRecordingBuffers;
    size_t mRecordingHeapHead, mRecordingHeapFree;
    // Handle new recording image buffers
    void onRecordingFrameAvailable();
@@ -442,9 +443,9 @@ private:
    // Update parameters all requests use, based on mParameters
    status_t updateRequestCommon(camera_metadata_t *request, const Parameters &params);

    // Map from sensor active array pixel coordinates to normalized camera parameter coordinates
    // The former are (0,0)-(array width - 1, array height - 1), the latter from
    // (-1000,-1000)-(1000,1000)
    // Map from sensor active array pixel coordinates to normalized camera
    // parameter coordinates. The former are (0,0)-(array width - 1, array height
    // - 1), the latter from (-1000,-1000)-(1000,1000)
    int arrayXToNormalized(int width) const;
    int arrayYToNormalized(int height) const;

+0 −198
Original line number Diff line number Diff line
/*
 * Copyright (C) 2012 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.
 */

//#define LOG_NDEBUG 0
#define LOG_TAG "MediaConsumer"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <utils/Log.h>

#include "MediaConsumer.h"

#define MC_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
#define MC_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__)
#define MC_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__)
#define MC_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__)
#define MC_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__)

namespace android {

// Get an ID that's unique within this process.
static int32_t createProcessUniqueId() {
    static volatile int32_t globalCounter = 0;
    return android_atomic_inc(&globalCounter);
}

MediaConsumer::MediaConsumer(uint32_t maxLockedBuffers) :
    mMaxLockedBuffers(maxLockedBuffers),
    mCurrentLockedBuffers(0)
{
    mName = String8::format("mc-unnamed-%d-%d", getpid(),
            createProcessUniqueId());

    mBufferQueue = new BufferQueue(true);

    wp<BufferQueue::ConsumerListener> listener;
    sp<BufferQueue::ConsumerListener> proxy;
    listener = static_cast<BufferQueue::ConsumerListener*>(this);
    proxy = new BufferQueue::ProxyConsumerListener(listener);

    status_t err = mBufferQueue->consumerConnect(proxy);
    if (err != NO_ERROR) {
        ALOGE("MediaConsumer: error connecting to BufferQueue: %s (%d)",
                strerror(-err), err);
    } else {
        mBufferQueue->setSynchronousMode(true);
        mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER);
        mBufferQueue->setConsumerName(mName);
    }
}

MediaConsumer::~MediaConsumer()
{
    Mutex::Autolock _l(mMutex);
    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
        freeBufferLocked(i);
    }
    mBufferQueue->consumerDisconnect();
    mBufferQueue.clear();
}

void MediaConsumer::setName(const String8& name) {
    Mutex::Autolock _l(mMutex);
    mName = name;
    mBufferQueue->setConsumerName(name);
}

status_t MediaConsumer::getNextBuffer(buffer_handle_t *buffer, nsecs_t *timestamp) {
    status_t err;

    if (!buffer) return BAD_VALUE;
    if (mCurrentLockedBuffers == mMaxLockedBuffers) {
        MC_LOGV("Too many buffers (max %d)", mCurrentLockedBuffers);
        return INVALID_OPERATION;
    }

    BufferQueue::BufferItem b;

    Mutex::Autolock _l(mMutex);

    err = mBufferQueue->acquireBuffer(&b);
    if (err != OK) {
        if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
            MC_LOGV("No buffer available");
            return BAD_VALUE;
        } else {
            MC_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
            return err;
        }
    }

    int buf = b.mBuf;

    if (b.mGraphicBuffer != NULL) {
        mBufferSlot[buf] = b.mGraphicBuffer;
    }

    if (b.mFence.get()) {
        err = b.mFence->wait(Fence::TIMEOUT_NEVER);
        if (err != OK) {
            MC_LOGE("Failed to wait for fence of acquired buffer: %s (%d)",
                    strerror(-err), err);
            return err;
        }
    }

    *buffer = mBufferSlot[buf]->handle;
    *timestamp = b.mTimestamp;

    mCurrentLockedBuffers++;
    MC_LOGV("getNextBuffer: %d buffers in use", mCurrentLockedBuffers);
    return OK;
}

status_t MediaConsumer::freeBuffer(buffer_handle_t buffer) {
    Mutex::Autolock _l(mMutex);
    int buf = 0;
    status_t err;

    for (; buf < BufferQueue::NUM_BUFFER_SLOTS; buf++) {
        if (buffer == mBufferSlot[buf]->handle) break;
    }
    if (buf == BufferQueue::NUM_BUFFER_SLOTS) {
        MC_LOGE("%s: Can't find buffer to free", __FUNCTION__);
        return BAD_VALUE;
    }

    err = mBufferQueue->releaseBuffer(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR,
            Fence::NO_FENCE);
    if (err == BufferQueue::STALE_BUFFER_SLOT) {
        freeBufferLocked(buf);
    } else if (err != OK) {
        MC_LOGE("%s: Unable to release graphic buffer %d to queue", __FUNCTION__,
                buf);
        return err;
    }
    mCurrentLockedBuffers--;
    MC_LOGV("freeBuffer: %d buffers in use", mCurrentLockedBuffers);

    return OK;
}

void MediaConsumer::setFrameAvailableListener(
        const sp<FrameAvailableListener>& listener) {
    MC_LOGV("setFrameAvailableListener");
    Mutex::Autolock lock(mMutex);
    mFrameAvailableListener = listener;
}


void MediaConsumer::onFrameAvailable() {
    MC_LOGV("onFrameAvailable");
    sp<FrameAvailableListener> listener;
    { // scope for the lock
        Mutex::Autolock _l(mMutex);
        listener = mFrameAvailableListener;
    }

    if (listener != NULL) {
        MC_LOGV("actually calling onFrameAvailable");
        listener->onFrameAvailable();
    }
}

void MediaConsumer::onBuffersReleased() {
    MC_LOGV("onBuffersReleased");

    Mutex::Autolock lock(mMutex);

    uint32_t mask = 0;
    mBufferQueue->getReleasedBuffers(&mask);
    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
        if (mask & (1 << i)) {
            freeBufferLocked(i);
        }
    }

}

status_t MediaConsumer::freeBufferLocked(int buf) {
    status_t err = OK;

    mBufferSlot[buf] = NULL;
    return err;
}

} // namespace android
+0 −126
Original line number Diff line number Diff line
/*
 * Copyright (C) 2012 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.
 */

#ifndef ANDROID_SERVERS_CAMERA_MEDIACONSUMER_H
#define ANDROID_SERVERS_CAMERA_MEDIACONSUMER_H

#include <gui/BufferQueue.h>

#include <ui/GraphicBuffer.h>

#include <utils/String8.h>
#include <utils/Vector.h>
#include <utils/threads.h>

#define ANDROID_GRAPHICS_MEDIACONSUMER_JNI_ID "mMediaConsumer"

namespace android {

/**
 * MediaConsumer is a BufferQueue consumer endpoint that makes it
 * straightforward to bridge Camera 2 to the existing media recording framework.
 * This queue is synchronous by default.
 *
 * TODO: This is a temporary replacement for the full camera->media recording
 * path using SurfaceMediaEncoder or equivalent.
 */

class MediaConsumer: public virtual RefBase,
                     protected BufferQueue::ConsumerListener
{
  public:
    struct FrameAvailableListener : public virtual RefBase {
        // onFrameAvailable() is called each time an additional frame becomes
        // available for consumption. A new frame queued will always trigger the
        // callback, whether the queue is empty or not.
        //
        // This is called without any lock held and can be called concurrently
        // by multiple threads.
        virtual void onFrameAvailable() = 0;
    };

    // Create a new media consumer. The maxBuffers parameter specifies
    // how many buffers can be locked for user access at the same time.
    MediaConsumer(uint32_t maxBuffers);

    virtual ~MediaConsumer();

    // set the name of the MediaConsumer that will be used to identify it in
    // log messages.
    void setName(const String8& name);

    // Gets the next graphics buffer from the producer. Returns BAD_VALUE if no
    // new buffer is available, and INVALID_OPERATION if the maximum number of
    // buffers is already in use.
    //
    // Only a fixed number of buffers can be available at a time, determined by
    // the construction-time maxBuffers parameter. If INVALID_OPERATION is
    // returned by getNextBuffer, then old buffers must be returned to the
    // queue by calling freeBuffer before more buffers can be acquired.
    status_t getNextBuffer(buffer_handle_t *buffer, nsecs_t *timestamp);

    // Returns a buffer to the queue, allowing it to be reused. Since
    // only a fixed number of buffers may be locked at a time, old buffers must
    // be released by calling unlockBuffer to ensure new buffers can be acquired by
    // lockNextBuffer.
    status_t freeBuffer(buffer_handle_t buffer);

    // setFrameAvailableListener sets the listener object that will be notified
    // when a new frame becomes available.
    void setFrameAvailableListener(const sp<FrameAvailableListener>& listener);

    sp<ISurfaceTexture> getProducerInterface() const { return mBufferQueue; }
  protected:

    // Implementation of the BufferQueue::ConsumerListener interface.  These
    // calls are used to notify the MediaConsumer of asynchronous events in the
    // BufferQueue.
    virtual void onFrameAvailable();
    virtual void onBuffersReleased();

  private:
    // Free local buffer state
    status_t freeBufferLocked(int buf);

    // Maximum number of buffers that can be locked at a time
    uint32_t mMaxLockedBuffers;

    // mName is a string used to identify the SurfaceTexture in log messages.
    // It can be set by the setName method.
    String8 mName;

    // mFrameAvailableListener is the listener object that will be called when a
    // new frame becomes available. If it is not NULL it will be called from
    // queueBuffer.
    sp<FrameAvailableListener> mFrameAvailableListener;

    // Underlying buffer queue
    sp<BufferQueue> mBufferQueue;

    // Array for caching buffers from the buffer queue
    sp<GraphicBuffer> mBufferSlot[BufferQueue::NUM_BUFFER_SLOTS];
    // Count of currently outstanding buffers
    uint32_t mCurrentLockedBuffers;

    // mMutex is the mutex used to prevent concurrent access to the member
    // variables of MediaConsumer objects. It must be locked whenever the
    // member variables are accessed.
    mutable Mutex mMutex;
};

} // namespace android

#endif // ANDROID_SERVERS_CAMERA_MEDIACONSUMER_H