Camera2: Revamp recording support to allow opaque formats.
- Avoid memcpy of buffer data by using metadata mode
- Temporarily add MediaConsumer BufferQueue class
Bug: 6243944
Change-Id: I7a8c4222b7dbd14f1b1d86fda06d38eb640e87c1
diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp
index f21a518..2e1940a 100644
--- a/services/camera/libcameraservice/Camera2Client.cpp
+++ b/services/camera/libcameraservice/Camera2Client.cpp
@@ -24,6 +24,7 @@
#include <cutils/properties.h>
#include <gui/SurfaceTextureClient.h>
#include <gui/Surface.h>
+#include <media/hardware/MetadataBufferType.h>
#include <math.h>
@@ -611,7 +612,21 @@
status_t Camera2Client::storeMetaDataInBuffers(bool enabled) {
ATRACE_CALL();
Mutex::Autolock icl(mICameraLock);
- return BAD_VALUE;
+ switch (mState) {
+ case RECORD:
+ case VIDEO_SNAPSHOT:
+ ALOGE("%s: Camera %d: Can't be called in state %s",
+ __FUNCTION__, mCameraId, getStateName(mState));
+ return INVALID_OPERATION;
+ default:
+ // OK
+ break;
+ }
+ Mutex::Autolock pl(mParamsLock);
+
+ mParameters.storeMetadataInBuffers = enabled;
+
+ return OK;
}
status_t Camera2Client::startRecording() {
@@ -640,6 +655,13 @@
Mutex::Autolock pl(mParamsLock);
+ if (!mParameters.storeMetadataInBuffers) {
+ ALOGE("%s: Camera %d: Recording only supported in metadata mode, but "
+ "non-metadata recording mode requested!", __FUNCTION__,
+ mCameraId);
+ return INVALID_OPERATION;
+ }
+
res = updateRecordingStream();
if (res != OK) {
ALOGE("%s: Camera %d: Unable to update recording stream: %s (%d)",
@@ -730,6 +752,7 @@
// Make sure this is for the current heap
ssize_t offset;
size_t size;
+ status_t res;
sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
if (heap->getHeapID() != mRecordingHeap->mHeap->getHeapID()) {
ALOGW("%s: Camera %d: Mismatched heap ID, ignoring release "
@@ -737,6 +760,24 @@
heap->getHeapID(), mRecordingHeap->mHeap->getHeapID());
return;
}
+ uint8_t *data = (uint8_t*)heap->getBase() + offset;
+ uint32_t type = *(uint32_t*)data;
+ if (type != kMetadataBufferTypeGrallocSource) {
+ ALOGE("%s: Camera %d: Recording frame type invalid (got %x, expected %x)",
+ __FUNCTION__, mCameraId, type, kMetadataBufferTypeGrallocSource);
+ return;
+ }
+ buffer_handle_t imgBuffer = *(buffer_handle_t*)(data + 4);
+ ALOGV("%s: Camera %d: Freeing buffer_handle_t %p", __FUNCTION__, mCameraId,
+ imgBuffer, *(uint32_t*)(data + 4));
+ res = mRecordingConsumer->freeBuffer(imgBuffer);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to free recording frame (buffer_handle_t: %p):"
+ "%s (%d)",
+ __FUNCTION__, mCameraId, imgBuffer, strerror(-res), res);
+ return;
+ }
+
mRecordingHeapFree++;
}
@@ -1519,30 +1560,21 @@
discardData = true;
}
- CpuConsumer::LockedBuffer imgBuffer;
- res = mRecordingConsumer->lockNextBuffer(&imgBuffer);
+ buffer_handle_t imgBuffer;
+ res = mRecordingConsumer->getNextBuffer(&imgBuffer, ×tamp);
if (res != OK) {
ALOGE("%s: Camera %d: Error receiving recording buffer: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
return;
}
- if (imgBuffer.format != (int)kRecordingFormat) {
- ALOGE("%s: Camera %d: Unexpected recording format: %x",
- __FUNCTION__, mCameraId, imgBuffer.format);
- discardData = true;
- }
-
if (discardData) {
- mRecordingConsumer->unlockBuffer(imgBuffer);
+ mRecordingConsumer->freeBuffer(imgBuffer);
return;
}
- size_t bufferSize = imgBuffer.width * imgBuffer.height * 3 / 2;
-
- if (mRecordingHeap == 0 ||
- bufferSize >
- mRecordingHeap->mHeap->getSize() / kRecordingHeapCount) {
+ if (mRecordingHeap == 0) {
+ const size_t bufferSize = 4 + sizeof(buffer_handle_t);
ALOGV("%s: Camera %d: Creating recording heap with %d buffers of "
"size %d bytes", __FUNCTION__, mCameraId,
kRecordingHeapCount, bufferSize);
@@ -1560,22 +1592,20 @@
if (mRecordingHeap->mHeap->getSize() == 0) {
ALOGE("%s: Camera %d: Unable to allocate memory for recording",
__FUNCTION__, mCameraId);
- mRecordingConsumer->unlockBuffer(imgBuffer);
+ mRecordingConsumer->freeBuffer(imgBuffer);
return;
}
mRecordingHeapHead = 0;
mRecordingHeapFree = kRecordingHeapCount;
}
- // TODO: Optimize this to avoid memcopy
if ( mRecordingHeapFree == 0) {
ALOGE("%s: Camera %d: No free recording buffers, dropping frame",
__FUNCTION__, mCameraId);
- mRecordingConsumer->unlockBuffer(imgBuffer);
+ mRecordingConsumer->freeBuffer(imgBuffer);
return;
}
heapIdx = mRecordingHeapHead;
- timestamp = imgBuffer.timestamp;
mRecordingHeapHead = (mRecordingHeapHead + 1) % kRecordingHeapCount;
mRecordingHeapFree--;
@@ -1588,10 +1618,12 @@
mRecordingHeap->mBuffers[heapIdx]->getMemory(&offset,
&size);
- memcpy((uint8_t*)heap->getBase() + offset, imgBuffer.data, size);
-
- mRecordingConsumer->unlockBuffer(imgBuffer);
-
+ uint8_t *data = (uint8_t*)heap->getBase() + offset;
+ uint32_t type = kMetadataBufferTypeGrallocSource;
+ memcpy(data, &type, 4);
+ memcpy(data + 4, &imgBuffer, sizeof(buffer_handle_t));
+ ALOGV("%s: Camera %d: Sending out buffer_handle_t %p",
+ __FUNCTION__, mCameraId, imgBuffer, *(uint32_t*)(data + 4));
currentClient = mCameraClient;
}
// Call outside mICameraLock to allow re-entrancy from notification
@@ -2306,7 +2338,7 @@
0);
params.set(CameraParameters::KEY_VIDEO_FRAME_FORMAT,
- formatEnumToString(kRecordingFormat));
+ CameraParameters::PIXEL_FORMAT_ANDROID_OPAQUE);
params.set(CameraParameters::KEY_RECORDING_HINT,
CameraParameters::FALSE);
@@ -2329,6 +2361,9 @@
CameraParameters::FALSE);
}
+ // Always use metadata mode for recording
+ mParameters.storeMetadataInBuffers = true;
+
mParamsFlattened = params.flatten();
return OK;
@@ -2580,7 +2615,7 @@
if (mRecordingConsumer == 0) {
// Create CPU buffer queue endpoint
- mRecordingConsumer = new CpuConsumer(1);
+ mRecordingConsumer = new MediaConsumer(4);
mRecordingConsumer->setFrameAvailableListener(new RecordingWaiter(this));
mRecordingConsumer->setName(String8("Camera2Client::RecordingConsumer"));
mRecordingWindow = new SurfaceTextureClient(
@@ -2615,7 +2650,7 @@
if (mRecordingStreamId == NO_STREAM) {
res = mDevice->createStream(mRecordingWindow,
mParameters.videoWidth, mParameters.videoHeight,
- kRecordingFormat, 0, &mRecordingStreamId);
+ CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, 0, &mRecordingStreamId);
if (res != OK) {
ALOGE("%s: Camera %d: Can't create output stream for recording: "
"%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);