Camera: Fix passing video native handle for 64-bit app
Add new binder calls to pass video native handle so the video native
handle can be passed between 32-bit and 64-bit processes.
Remove problematic code that used IMemory to pass video native
handle because the sizes of VideoNativeMetadata are different in
32-bit and 64-bit processes.
Bug: 28403412
Change-Id: I3341b1812ecc41d61846bb72ca926ecb1674c9ec
diff --git a/camera/Camera.cpp b/camera/Camera.cpp
index c52e581..bf9904c 100644
--- a/camera/Camera.cpp
+++ b/camera/Camera.cpp
@@ -232,6 +232,14 @@
c->releaseRecordingFrame(mem);
}
+void Camera::releaseRecordingFrameHandle(native_handle_t* handle)
+{
+ ALOGV("releaseRecordingFrameHandle");
+ sp <::android::hardware::ICamera> c = mCamera;
+ if (c == 0) return;
+ c->releaseRecordingFrameHandle(handle);
+}
+
// get preview state
bool Camera::previewEnabled()
{
@@ -381,6 +389,35 @@
}
}
+void Camera::recordingFrameHandleCallbackTimestamp(nsecs_t timestamp, native_handle_t* handle)
+{
+ // If recording proxy listener is registered, forward the frame and return.
+ // The other listener (mListener) is ignored because the receiver needs to
+ // call releaseRecordingFrameHandle.
+ sp<ICameraRecordingProxyListener> proxylistener;
+ {
+ Mutex::Autolock _l(mLock);
+ proxylistener = mRecordingProxyListener;
+ }
+ if (proxylistener != NULL) {
+ proxylistener->recordingFrameHandleCallbackTimestamp(timestamp, handle);
+ return;
+ }
+
+ sp<CameraListener> listener;
+ {
+ Mutex::Autolock _l(mLock);
+ listener = mListener;
+ }
+
+ if (listener != NULL) {
+ listener->postRecordingFrameHandleTimestamp(timestamp, handle);
+ } else {
+ ALOGW("No listener was set. Drop a recording frame.");
+ releaseRecordingFrameHandle(handle);
+ }
+}
+
sp<ICameraRecordingProxy> Camera::getRecordingProxy() {
ALOGV("getProxy");
return new RecordingProxy(this);
@@ -406,6 +443,11 @@
mCamera->releaseRecordingFrame(mem);
}
+void Camera::RecordingProxy::releaseRecordingFrameHandle(native_handle_t* handle) {
+ ALOGV("RecordingProxy::releaseRecordingFrameHandle");
+ mCamera->releaseRecordingFrameHandle(handle);
+}
+
Camera::RecordingProxy::RecordingProxy(const sp<Camera>& camera)
{
mCamera = camera;
diff --git a/camera/CameraUtils.cpp b/camera/CameraUtils.cpp
index 26eebe3..1676be1 100644
--- a/camera/CameraUtils.cpp
+++ b/camera/CameraUtils.cpp
@@ -122,19 +122,4 @@
return OK;
}
-// Return whether the image data contains a native handle.
-bool CameraUtils::isNativeHandleMetadata(const sp<IMemory>& imageData) {
- if (imageData == nullptr) {
- return false;
- }
-
- if (imageData->size() == sizeof(VideoNativeHandleMetadata)) {
- VideoNativeHandleMetadata *metadata =
- (VideoNativeHandleMetadata*)(imageData->pointer());
- return metadata->eType == kMetadataBufferTypeNativeHandleSource;
- }
-
- return false;
-}
-
} /* namespace android */
diff --git a/camera/ICamera.cpp b/camera/ICamera.cpp
index 37b0a10..0680d7c 100644
--- a/camera/ICamera.cpp
+++ b/camera/ICamera.cpp
@@ -54,6 +54,7 @@
RELEASE_RECORDING_FRAME,
SET_VIDEO_BUFFER_MODE,
SET_VIDEO_BUFFER_TARGET,
+ RELEASE_RECORDING_FRAME_HANDLE,
};
class BpCamera: public BpInterface<ICamera>
@@ -155,21 +156,20 @@
data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
data.writeStrongBinder(IInterface::asBinder(mem));
- native_handle_t *nh = nullptr;
- if (CameraUtils::isNativeHandleMetadata(mem)) {
- VideoNativeHandleMetadata *metadata =
- (VideoNativeHandleMetadata*)(mem->pointer());
- nh = metadata->pHandle;
- data.writeNativeHandle(nh);
- }
-
remote()->transact(RELEASE_RECORDING_FRAME, data, &reply);
+ }
- if (nh) {
- // Close the native handle because camera received a dup copy.
- native_handle_close(nh);
- native_handle_delete(nh);
- }
+ void releaseRecordingFrameHandle(native_handle_t *handle) {
+ ALOGV("releaseRecordingFrameHandle");
+ Parcel data, reply;
+ data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+ data.writeNativeHandle(handle);
+
+ remote()->transact(RELEASE_RECORDING_FRAME_HANDLE, data, &reply);
+
+ // Close the native handle because camera received a dup copy.
+ native_handle_close(handle);
+ native_handle_delete(handle);
}
status_t setVideoBufferMode(int32_t videoBufferMode)
@@ -368,17 +368,16 @@
ALOGV("RELEASE_RECORDING_FRAME");
CHECK_INTERFACE(ICamera, data, reply);
sp<IMemory> mem = interface_cast<IMemory>(data.readStrongBinder());
-
- if (CameraUtils::isNativeHandleMetadata(mem)) {
- VideoNativeHandleMetadata *metadata =
- (VideoNativeHandleMetadata*)(mem->pointer());
- metadata->pHandle = data.readNativeHandle();
- // releaseRecordingFrame will be responsble to close the native handle.
- }
-
releaseRecordingFrame(mem);
return NO_ERROR;
} break;
+ case RELEASE_RECORDING_FRAME_HANDLE: {
+ ALOGV("RELEASE_RECORDING_FRAME_HANDLE");
+ CHECK_INTERFACE(ICamera, data, reply);
+ // releaseRecordingFrameHandle will be responsble to close the native handle.
+ releaseRecordingFrameHandle(data.readNativeHandle());
+ return NO_ERROR;
+ } break;
case SET_VIDEO_BUFFER_MODE: {
ALOGV("SET_VIDEO_BUFFER_MODE");
CHECK_INTERFACE(ICamera, data, reply);
diff --git a/camera/ICameraClient.cpp b/camera/ICameraClient.cpp
index d058138..68cbfb8 100644
--- a/camera/ICameraClient.cpp
+++ b/camera/ICameraClient.cpp
@@ -31,6 +31,7 @@
NOTIFY_CALLBACK = IBinder::FIRST_CALL_TRANSACTION,
DATA_CALLBACK,
DATA_CALLBACK_TIMESTAMP,
+ RECORDING_FRAME_HANDLE_CALLBACK_TIMESTAMP,
};
class BpCameraClient: public BpInterface<ICameraClient>
@@ -78,15 +79,18 @@
data.writeInt64(timestamp);
data.writeInt32(msgType);
data.writeStrongBinder(IInterface::asBinder(imageData));
- // If imageData is metadata and it contains a native handle, write the native handle to
- // parcel.
- if (CameraUtils::isNativeHandleMetadata(imageData)) {
- VideoNativeHandleMetadata *metadata =
- (VideoNativeHandleMetadata*)(imageData->pointer());
- data.writeNativeHandle(metadata->pHandle);
- }
remote()->transact(DATA_CALLBACK_TIMESTAMP, data, &reply, IBinder::FLAG_ONEWAY);
}
+
+ void recordingFrameHandleCallbackTimestamp(nsecs_t timestamp, native_handle_t* handle) {
+ ALOGV("recordingFrameHandleCallbackTimestamp");
+ Parcel data, reply;
+ data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
+ data.writeInt64(timestamp);
+ data.writeNativeHandle(handle);
+ remote()->transact(RECORDING_FRAME_HANDLE_CALLBACK_TIMESTAMP, data, &reply,
+ IBinder::FLAG_ONEWAY);
+ }
};
IMPLEMENT_META_INTERFACE(CameraClient, "android.hardware.ICameraClient");
@@ -128,20 +132,26 @@
nsecs_t timestamp = data.readInt64();
int32_t msgType = data.readInt32();
sp<IMemory> imageData = interface_cast<IMemory>(data.readStrongBinder());
-
- // If the image data contains a native handle, read the native handle from the parcel
- // and replace the native handle in the image data. (The native handle in image data is
- // not serielized/deserialized so it's not valid in the process.)
- if (CameraUtils::isNativeHandleMetadata(imageData)) {
- VideoNativeHandleMetadata *metadata =
- (VideoNativeHandleMetadata*)(imageData->pointer());
- metadata->pHandle = data.readNativeHandle();
-
- // The native handle will be freed in
- // BpCameraRecordingProxyListener::releaseRecordingFrame.
+ dataCallbackTimestamp(timestamp, msgType, imageData);
+ return NO_ERROR;
+ } break;
+ case RECORDING_FRAME_HANDLE_CALLBACK_TIMESTAMP: {
+ ALOGV("RECORDING_FRAME_HANDLE_CALLBACK_TIMESTAMP");
+ CHECK_INTERFACE(ICameraClient, data, reply);
+ nsecs_t timestamp;
+ status_t res = data.readInt64(×tamp);
+ if (res != OK) {
+ ALOGE("%s: Failed to read timestamp: %s (%d)", __FUNCTION__, strerror(-res), res);
+ return BAD_VALUE;
+ }
+ native_handle_t* handle = data.readNativeHandle();
+ if (handle == nullptr) {
+ ALOGE("%s: Received a null native handle", __FUNCTION__);
+ return BAD_VALUE;
}
- dataCallbackTimestamp(timestamp, msgType, imageData);
+ // The native handle will be freed in BpCamera::releaseRecordingFrameHandle.
+ recordingFrameHandleCallbackTimestamp(timestamp, handle);
return NO_ERROR;
} break;
default:
diff --git a/camera/ICameraRecordingProxy.cpp b/camera/ICameraRecordingProxy.cpp
index d128f5b..63c4b1d 100644
--- a/camera/ICameraRecordingProxy.cpp
+++ b/camera/ICameraRecordingProxy.cpp
@@ -31,6 +31,7 @@
START_RECORDING = IBinder::FIRST_CALL_TRANSACTION,
STOP_RECORDING,
RELEASE_RECORDING_FRAME,
+ RELEASE_RECORDING_FRAME_HANDLE,
};
@@ -66,22 +67,20 @@
Parcel data, reply;
data.writeInterfaceToken(ICameraRecordingProxy::getInterfaceDescriptor());
data.writeStrongBinder(IInterface::asBinder(mem));
-
- native_handle_t *nh = nullptr;
- if (CameraUtils::isNativeHandleMetadata(mem)) {
- VideoNativeHandleMetadata *metadata =
- (VideoNativeHandleMetadata*)(mem->pointer());
- nh = metadata->pHandle;
- data.writeNativeHandle(nh);
- }
-
remote()->transact(RELEASE_RECORDING_FRAME, data, &reply);
+ }
- if (nh) {
- // Close the native handle because camera received a dup copy.
- native_handle_close(nh);
- native_handle_delete(nh);
- }
+ void releaseRecordingFrameHandle(native_handle_t *handle) {
+ ALOGV("releaseRecordingFrameHandle");
+ Parcel data, reply;
+ data.writeInterfaceToken(ICameraRecordingProxy::getInterfaceDescriptor());
+ data.writeNativeHandle(handle);
+
+ remote()->transact(RELEASE_RECORDING_FRAME_HANDLE, data, &reply);
+
+ // Close the native handle because camera received a dup copy.
+ native_handle_close(handle);
+ native_handle_delete(handle);
}
};
@@ -111,19 +110,17 @@
ALOGV("RELEASE_RECORDING_FRAME");
CHECK_INTERFACE(ICameraRecordingProxy, data, reply);
sp<IMemory> mem = interface_cast<IMemory>(data.readStrongBinder());
-
- if (CameraUtils::isNativeHandleMetadata(mem)) {
- VideoNativeHandleMetadata *metadata =
- (VideoNativeHandleMetadata*)(mem->pointer());
- metadata->pHandle = data.readNativeHandle();
-
- // releaseRecordingFrame will be responsble to close the native handle.
- }
releaseRecordingFrame(mem);
-
return NO_ERROR;
} break;
+ case RELEASE_RECORDING_FRAME_HANDLE: {
+ ALOGV("RELEASE_RECORDING_FRAME_HANDLE");
+ CHECK_INTERFACE(ICameraRecordingProxy, data, reply);
+ // releaseRecordingFrameHandle will be responsble to close the native handle.
+ releaseRecordingFrameHandle(data.readNativeHandle());
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/camera/ICameraRecordingProxyListener.cpp b/camera/ICameraRecordingProxyListener.cpp
index 447174e..fa4dfd8 100644
--- a/camera/ICameraRecordingProxyListener.cpp
+++ b/camera/ICameraRecordingProxyListener.cpp
@@ -27,6 +27,7 @@
enum {
DATA_CALLBACK_TIMESTAMP = IBinder::FIRST_CALL_TRANSACTION,
+ RECORDING_FRAME_HANDLE_CALLBACK_TIMESTAMP,
};
class BpCameraRecordingProxyListener: public BpInterface<ICameraRecordingProxyListener>
@@ -45,22 +46,21 @@
data.writeInt64(timestamp);
data.writeInt32(msgType);
data.writeStrongBinder(IInterface::asBinder(imageData));
- native_handle_t* nh = nullptr;
-
- if (CameraUtils::isNativeHandleMetadata(imageData)) {
- VideoNativeHandleMetadata *metadata =
- (VideoNativeHandleMetadata*)(imageData->pointer());
- nh = metadata->pHandle;
- data.writeNativeHandle(nh);
- }
-
remote()->transact(DATA_CALLBACK_TIMESTAMP, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+
+ void recordingFrameHandleCallbackTimestamp(nsecs_t timestamp, native_handle_t* handle) {
+ ALOGV("recordingFrameHandleCallbackTimestamp");
+ Parcel data, reply;
+ data.writeInterfaceToken(ICameraRecordingProxyListener::getInterfaceDescriptor());
+ data.writeInt64(timestamp);
+ data.writeNativeHandle(handle);
+ remote()->transact(RECORDING_FRAME_HANDLE_CALLBACK_TIMESTAMP, data, &reply,
+ IBinder::FLAG_ONEWAY);
// The native handle is dupped in ICameraClient so we need to free it here.
- if (nh) {
- native_handle_close(nh);
- native_handle_delete(nh);
- }
+ native_handle_close(handle);
+ native_handle_delete(handle);
}
};
@@ -78,16 +78,27 @@
nsecs_t timestamp = data.readInt64();
int32_t msgType = data.readInt32();
sp<IMemory> imageData = interface_cast<IMemory>(data.readStrongBinder());
-
- if (CameraUtils::isNativeHandleMetadata(imageData)) {
- VideoNativeHandleMetadata *meta = (VideoNativeHandleMetadata*)(imageData->pointer());
- meta->pHandle = data.readNativeHandle();
-
- // The native handle will be freed in
- // BpCameraRecordingProxyListener::releaseRecordingFrame.
+ dataCallbackTimestamp(timestamp, msgType, imageData);
+ return NO_ERROR;
+ } break;
+ case RECORDING_FRAME_HANDLE_CALLBACK_TIMESTAMP: {
+ ALOGV("RECORDING_FRAME_HANDLE_CALLBACK_TIMESTAMP");
+ CHECK_INTERFACE(ICameraRecordingProxyListener, data, reply);
+ nsecs_t timestamp;
+ status_t res = data.readInt64(×tamp);
+ if (res != OK) {
+ ALOGE("%s: Failed to read timestamp: %s (%d)", __FUNCTION__, strerror(-res), res);
+ return BAD_VALUE;
}
- dataCallbackTimestamp(timestamp, msgType, imageData);
+ native_handle_t* handle = data.readNativeHandle();
+ if (handle == nullptr) {
+ ALOGE("%s: Received a null native handle", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ // The native handle will be freed in
+ // BpCameraRecordingProxy::releaseRecordingFrameHandle.
+ recordingFrameHandleCallbackTimestamp(timestamp, handle);
return NO_ERROR;
} break;
default:
diff --git a/include/camera/Camera.h b/include/camera/Camera.h
index b45bbfc..be793a2 100644
--- a/include/camera/Camera.h
+++ b/include/camera/Camera.h
@@ -43,6 +43,7 @@
virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr,
camera_frame_metadata_t *metadata) = 0;
virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) = 0;
+ virtual void postRecordingFrameHandleTimestamp(nsecs_t timestamp, native_handle_t* handle) = 0;
};
class Camera;
@@ -114,6 +115,9 @@
// release a recording frame
void releaseRecordingFrame(const sp<IMemory>& mem);
+ // release a recording frame handle
+ void releaseRecordingFrameHandle(native_handle_t *handle);
+
// autoFocus - status returned from callback
status_t autoFocus();
@@ -161,6 +165,7 @@
virtual void dataCallback(int32_t msgType, const sp<IMemory>& dataPtr,
camera_frame_metadata_t *metadata);
virtual void dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
+ virtual void recordingFrameHandleCallbackTimestamp(nsecs_t timestamp, native_handle_t* handle);
class RecordingProxy : public BnCameraRecordingProxy
{
@@ -171,6 +176,7 @@
virtual status_t startRecording(const sp<ICameraRecordingProxyListener>& listener);
virtual void stopRecording();
virtual void releaseRecordingFrame(const sp<IMemory>& mem);
+ virtual void releaseRecordingFrameHandle(native_handle_t* handle);
private:
sp<Camera> mCamera;
diff --git a/include/camera/ICameraRecordingProxy.h b/include/camera/ICameraRecordingProxy.h
index 2aac284..cb6824a 100644
--- a/include/camera/ICameraRecordingProxy.h
+++ b/include/camera/ICameraRecordingProxy.h
@@ -18,6 +18,7 @@
#define ANDROID_HARDWARE_ICAMERA_RECORDING_PROXY_H
#include <binder/IInterface.h>
+#include <cutils/native_handle.h>
#include <utils/RefBase.h>
namespace android {
@@ -83,6 +84,7 @@
virtual status_t startRecording(const sp<ICameraRecordingProxyListener>& listener) = 0;
virtual void stopRecording() = 0;
virtual void releaseRecordingFrame(const sp<IMemory>& mem) = 0;
+ virtual void releaseRecordingFrameHandle(native_handle_t *handle) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/camera/ICameraRecordingProxyListener.h b/include/camera/ICameraRecordingProxyListener.h
index b6c0624..1fee5b9 100644
--- a/include/camera/ICameraRecordingProxyListener.h
+++ b/include/camera/ICameraRecordingProxyListener.h
@@ -18,6 +18,7 @@
#define ANDROID_HARDWARE_ICAMERA_RECORDING_PROXY_LISTENER_H
#include <binder/IInterface.h>
+#include <cutils/native_handle.h>
#include <stdint.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>
@@ -34,6 +35,9 @@
virtual void dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType,
const sp<IMemory>& data) = 0;
+
+ virtual void recordingFrameHandleCallbackTimestamp(nsecs_t timestamp,
+ native_handle_t* handle) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/camera/android/hardware/ICamera.h b/include/camera/android/hardware/ICamera.h
index 322b741..3b12afe 100644
--- a/include/camera/android/hardware/ICamera.h
+++ b/include/camera/android/hardware/ICamera.h
@@ -94,9 +94,13 @@
// get recording state
virtual bool recordingEnabled() = 0;
- // release a recording frame
+ // Release a recording frame that was received via ICameraClient::dataCallbackTimestamp.
virtual void releaseRecordingFrame(const sp<IMemory>& mem) = 0;
+ // Release a recording frame handle that was received via
+ // ICameraClient::recordingFrameHandleCallbackTimestamp.
+ virtual void releaseRecordingFrameHandle(native_handle_t *handle) = 0;
+
// auto focus
virtual status_t autoFocus() = 0;
diff --git a/include/camera/android/hardware/ICameraClient.h b/include/camera/android/hardware/ICameraClient.h
index d7f9a75..3f835a9 100644
--- a/include/camera/android/hardware/ICameraClient.h
+++ b/include/camera/android/hardware/ICameraClient.h
@@ -36,6 +36,11 @@
virtual void dataCallback(int32_t msgType, const sp<IMemory>& data,
camera_frame_metadata_t *metadata) = 0;
virtual void dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& data) = 0;
+
+ // Invoked to send a recording frame handle with a timestamp. Call
+ // ICamera::releaseRecordingFrameHandle to release the frame handle.
+ virtual void recordingFrameHandleCallbackTimestamp(nsecs_t timestamp,
+ native_handle_t* handle) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h
index c732b41..399f363 100644
--- a/include/media/stagefright/CameraSource.h
+++ b/include/media/stagefright/CameraSource.h
@@ -138,6 +138,8 @@
ProxyListener(const sp<CameraSource>& source);
virtual void dataCallbackTimestamp(int64_t timestampUs, int32_t msgType,
const sp<IMemory> &data);
+ virtual void recordingFrameHandleCallbackTimestamp(int64_t timestampUs,
+ native_handle_t* handle);
private:
sp<CameraSource> mSource;
@@ -209,6 +211,7 @@
virtual status_t startCameraRecording();
virtual void releaseRecordingFrame(const sp<IMemory>& frame);
+ virtual void releaseRecordingFrameHandle(native_handle_t* handle);
// Returns true if need to skip the current frame.
// Called from dataCallbackTimestamp.
@@ -220,6 +223,9 @@
virtual void dataCallbackTimestamp(int64_t timestampUs, int32_t msgType,
const sp<IMemory> &data);
+ virtual void recordingFrameHandleCallbackTimestamp(int64_t timestampUs,
+ native_handle_t* handle);
+
// Process a buffer item received in BufferQueueListener.
virtual void processBufferQueueFrame(BufferItem& buffer);
@@ -244,6 +250,8 @@
// The mode video buffers are received from camera. One of VIDEO_BUFFER_MODE_*.
int32_t mVideoBufferMode;
+ static const uint32_t kDefaultVideoBufferCount = 32;
+
/**
* The following variables are used in VIDEO_BUFFER_MODE_BUFFER_QUEUE mode.
*/
@@ -264,6 +272,7 @@
void releaseQueuedFrames();
void releaseOneRecordingFrame(const sp<IMemory>& frame);
+ void createVideoBufferMemoryHeap(size_t size, uint32_t bufferCount);
status_t init(const sp<hardware::ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
int32_t cameraId, const String16& clientName, uid_t clientUid, pid_t clientPid,
diff --git a/include/media/stagefright/CameraSourceTimeLapse.h b/include/media/stagefright/CameraSourceTimeLapse.h
index f17ec51..871c1d9 100644
--- a/include/media/stagefright/CameraSourceTimeLapse.h
+++ b/include/media/stagefright/CameraSourceTimeLapse.h
@@ -145,6 +145,14 @@
virtual void dataCallbackTimestamp(int64_t timestampUs, int32_t msgType,
const sp<IMemory> &data);
+ // In the video camera case calls skipFrameAndModifyTimeStamp() to modify
+ // timestamp and set mSkipCurrentFrame.
+ // Then it calls the base CameraSource::recordingFrameHandleCallbackTimestamp()
+ // This will be called in VIDEO_BUFFER_MODE_DATA_CALLBACK_METADATA mode when
+ // the metadata is VideoNativeHandleMetadata.
+ virtual void recordingFrameHandleCallbackTimestamp(int64_t timestampUs,
+ native_handle_t* handle);
+
// Process a buffer item received in CameraSource::BufferQueueListener.
// This will be called in VIDEO_BUFFER_MODE_BUFFER_QUEUE mode.
virtual void processBufferQueueFrame(BufferItem& buffer);
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index cb974ae..8e9db93 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -56,6 +56,8 @@
virtual void postDataTimestamp(
nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
+ virtual void postRecordingFrameHandleTimestamp(nsecs_t timestamp, native_handle_t* handle);
+
protected:
virtual ~CameraSourceListener();
@@ -100,6 +102,14 @@
}
}
+void CameraSourceListener::postRecordingFrameHandleTimestamp(nsecs_t timestamp,
+ native_handle_t* handle) {
+ sp<CameraSource> source = mSource.promote();
+ if (source.get() != nullptr) {
+ source->recordingFrameHandleCallbackTimestamp(timestamp/1000, handle);
+ }
+}
+
static int32_t getColorFormat(const char* colorFormat) {
if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV420P)) {
return OMX_COLOR_FormatYUV420Planar;
@@ -509,6 +519,14 @@
return err;
}
+void CameraSource::createVideoBufferMemoryHeap(size_t size, uint32_t bufferCount) {
+ mMemoryHeapBase = new MemoryHeapBase(size * bufferCount, 0,
+ "StageFright-CameraSource-BufferHeap");
+ for (uint32_t i = 0; i < bufferCount; i++) {
+ mMemoryBases.push_back(new MemoryBase(mMemoryHeapBase, i * size, size));
+ }
+}
+
status_t CameraSource::initBufferQueue(uint32_t width, uint32_t height,
uint32_t format, android_dataspace dataSpace, uint32_t bufferCount) {
ALOGV("initBufferQueue");
@@ -562,12 +580,7 @@
}
// Create memory heap to store buffers as VideoNativeMetadata.
- size_t bufferSize = sizeof(VideoNativeMetadata);
- mMemoryHeapBase = new MemoryHeapBase(bufferSize * bufferCount, 0,
- "StageFright-CameraSource-BufferHeap");
- for (uint32_t i = 0; i < bufferCount; i++) {
- mMemoryBases.push_back(new MemoryBase(mMemoryHeapBase, i * bufferSize, bufferSize));
- }
+ createVideoBufferMemoryHeap(sizeof(VideoNativeMetadata), bufferCount);
mBufferQueueListener = new BufferQueueListener(mVideoBufferConsumer, this);
res = mBufferQueueListener->run("CameraSource-BufferQueueListener");
@@ -718,6 +731,9 @@
ALOGW("Failed to set video encoder format/dataspace to %d, %d due to %d",
mEncoderFormat, mEncoderDataSpace, err);
}
+
+ // Create memory heap to store buffers as VideoNativeMetadata.
+ createVideoBufferMemoryHeap(sizeof(VideoNativeHandleMetadata), kDefaultVideoBufferCount);
}
err = OK;
@@ -920,12 +936,33 @@
mVideoBufferConsumer->releaseBuffer(buffer);
mMemoryBases.push_back(frame);
mMemoryBaseAvailableCond.signal();
- } else if (mCameraRecordingProxy != NULL) {
- mCameraRecordingProxy->releaseRecordingFrame(frame);
- } else if (mCamera != NULL) {
- int64_t token = IPCThreadState::self()->clearCallingIdentity();
- mCamera->releaseRecordingFrame(frame);
- IPCThreadState::self()->restoreCallingIdentity(token);
+ } else {
+ native_handle_t* handle = nullptr;
+
+ // Check if frame contains a VideoNativeHandleMetadata.
+ if (frame->size() == sizeof(VideoNativeHandleMetadata)) {
+ VideoNativeHandleMetadata *metadata =
+ (VideoNativeHandleMetadata*)(frame->pointer());
+ if (metadata->eType == kMetadataBufferTypeNativeHandleSource) {
+ handle = metadata->pHandle;
+ }
+ }
+
+ if (handle != nullptr) {
+ // Frame contains a VideoNativeHandleMetadata. Send the handle back to camera.
+ releaseRecordingFrameHandle(handle);
+ mMemoryBases.push_back(frame);
+ mMemoryBaseAvailableCond.signal();
+ } else if (mCameraRecordingProxy != nullptr) {
+ // mCamera is created by application. Return the frame back to camera via camera
+ // recording proxy.
+ mCameraRecordingProxy->releaseRecordingFrame(frame);
+ } else if (mCamera != nullptr) {
+ // mCamera is created by CameraSource. Return the frame directly back to camera.
+ int64_t token = IPCThreadState::self()->clearCallingIdentity();
+ mCamera->releaseRecordingFrame(frame);
+ IPCThreadState::self()->restoreCallingIdentity(token);
+ }
}
}
@@ -1073,6 +1110,53 @@
mFrameAvailableCondition.signal();
}
+void CameraSource::releaseRecordingFrameHandle(native_handle_t* handle) {
+ if (mCameraRecordingProxy != nullptr) {
+ mCameraRecordingProxy->releaseRecordingFrameHandle(handle);
+ } else if (mCamera != nullptr) {
+ int64_t token = IPCThreadState::self()->clearCallingIdentity();
+ mCamera->releaseRecordingFrameHandle(handle);
+ IPCThreadState::self()->restoreCallingIdentity(token);
+ }
+}
+
+void CameraSource::recordingFrameHandleCallbackTimestamp(int64_t timestampUs,
+ native_handle_t* handle) {
+ ALOGV("%s: timestamp %lld us", __FUNCTION__, (long long)timestampUs);
+ Mutex::Autolock autoLock(mLock);
+ if (handle == nullptr) return;
+
+ if (shouldSkipFrameLocked(timestampUs)) {
+ releaseRecordingFrameHandle(handle);
+ return;
+ }
+
+ while (mMemoryBases.empty()) {
+ if (mMemoryBaseAvailableCond.waitRelative(mLock, kMemoryBaseAvailableTimeoutNs) ==
+ TIMED_OUT) {
+ ALOGW("Waiting on an available memory base timed out. Dropping a recording frame.");
+ releaseRecordingFrameHandle(handle);
+ return;
+ }
+ }
+
+ ++mNumFramesReceived;
+
+ sp<IMemory> data = *mMemoryBases.begin();
+ mMemoryBases.erase(mMemoryBases.begin());
+
+ // Wrap native handle in sp<IMemory> so it can be pushed to mFramesReceived.
+ VideoNativeHandleMetadata *metadata = (VideoNativeHandleMetadata*)(data->pointer());
+ metadata->eType = kMetadataBufferTypeNativeHandleSource;
+ metadata->pHandle = handle;
+
+ mFramesReceived.push_back(data);
+ int64_t timeUs = mStartTimeUs + (timestampUs - mFirstFrameTimeUs);
+ mFrameTimes.push_back(timeUs);
+ ALOGV("initial delay: %" PRId64 ", current time stamp: %" PRId64, mStartTimeUs, timeUs);
+ mFrameAvailableCondition.signal();
+}
+
CameraSource::BufferQueueListener::BufferQueueListener(const sp<BufferItemConsumer>& consumer,
const sp<CameraSource>& cameraSource) {
mConsumer = consumer;
@@ -1178,6 +1262,11 @@
mSource->dataCallbackTimestamp(timestamp / 1000, msgType, dataPtr);
}
+void CameraSource::ProxyListener::recordingFrameHandleCallbackTimestamp(nsecs_t timestamp,
+ native_handle_t* handle) {
+ mSource->recordingFrameHandleCallbackTimestamp(timestamp / 1000, handle);
+}
+
void CameraSource::DeathNotifier::binderDied(const wp<IBinder>& who __unused) {
ALOGI("Camera recording proxy died");
}
diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp
index d52567c..390c556 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -308,6 +308,13 @@
CameraSource::dataCallbackTimestamp(timestampUs, msgType, data);
}
+void CameraSourceTimeLapse::recordingFrameHandleCallbackTimestamp(int64_t timestampUs,
+ native_handle_t* handle) {
+ ALOGV("recordingFrameHandleCallbackTimestamp");
+ mSkipCurrentFrame = skipFrameAndModifyTimeStamp(×tampUs);
+ CameraSource::recordingFrameHandleCallbackTimestamp(timestampUs, handle);
+}
+
void CameraSourceTimeLapse::processBufferQueueFrame(BufferItem& buffer) {
ALOGV("processBufferQueueFrame");
int64_t timestampUs = buffer.mTimestamp / 1000;
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 4eb7b03..c8e64fe 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -1242,6 +1242,12 @@
ALOGW("%s: Not supported in buffer queue mode.", __FUNCTION__);
}
+void Camera2Client::releaseRecordingFrameHandle(native_handle_t *handle) {
+ (void)handle;
+ ATRACE_CALL();
+ ALOGW("%s: Not supported in buffer queue mode.", __FUNCTION__);
+}
+
status_t Camera2Client::autoFocus() {
ATRACE_CALL();
Mutex::Autolock icl(mBinderSerializationLock);
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index 12ee157..3cb9e4f 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -71,6 +71,7 @@
virtual void stopRecording();
virtual bool recordingEnabled();
virtual void releaseRecordingFrame(const sp<IMemory>& mem);
+ virtual void releaseRecordingFrameHandle(native_handle_t *handle);
virtual status_t autoFocus();
virtual status_t cancelAutoFocus();
virtual status_t takePicture(int msgType);
diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index d2fedf8..266fb03 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -19,6 +19,7 @@
#include <cutils/properties.h>
#include <gui/Surface.h>
+#include <media/hardware/HardwareAPI.h>
#include "api1/CameraClient.h"
#include "device1/CameraHardwareInterface.h"
@@ -488,6 +489,39 @@
mHardware->releaseRecordingFrame(mem);
}
+void CameraClient::releaseRecordingFrameHandle(native_handle_t *handle) {
+ if (handle == nullptr) return;
+
+ sp<IMemory> dataPtr;
+ {
+ Mutex::Autolock l(mAvailableCallbackBuffersLock);
+ if (!mAvailableCallbackBuffers.empty()) {
+ dataPtr = mAvailableCallbackBuffers.back();
+ mAvailableCallbackBuffers.pop_back();
+ }
+ }
+
+ if (dataPtr == nullptr) {
+ ALOGE("%s: %d: No callback buffer available. Dropping a native handle.", __FUNCTION__,
+ __LINE__);
+ native_handle_close(handle);
+ native_handle_delete(handle);
+ return;
+ } else if (dataPtr->size() != sizeof(VideoNativeHandleMetadata)) {
+ ALOGE("%s: %d: Callback buffer size doesn't match VideoNativeHandleMetadata", __FUNCTION__,
+ __LINE__);
+ native_handle_close(handle);
+ native_handle_delete(handle);
+ return;
+ }
+
+ VideoNativeHandleMetadata *metadata = (VideoNativeHandleMetadata*)(dataPtr->pointer());
+ metadata->eType = kMetadataBufferTypeNativeHandleSource;
+ metadata->pHandle = handle;
+
+ mHardware->releaseRecordingFrame(dataPtr);
+}
+
status_t CameraClient::setVideoBufferMode(int32_t videoBufferMode) {
LOG1("setVideoBufferMode: %d", videoBufferMode);
bool enableMetadataInBuffers = false;
@@ -929,8 +963,28 @@
int32_t msgType, const sp<IMemory>& dataPtr) {
sp<hardware::ICameraClient> c = mRemoteCallback;
mLock.unlock();
- if (c != 0) {
- c->dataCallbackTimestamp(timestamp, msgType, dataPtr);
+ if (c != 0 && dataPtr != nullptr) {
+ native_handle_t* handle = nullptr;
+
+ // Check if dataPtr contains a VideoNativeHandleMetadata.
+ if (dataPtr->size() == sizeof(VideoNativeHandleMetadata)) {
+ VideoNativeHandleMetadata *metadata =
+ (VideoNativeHandleMetadata*)(dataPtr->pointer());
+ if (metadata->eType == kMetadataBufferTypeNativeHandleSource) {
+ handle = metadata->pHandle;
+ }
+ }
+
+ // If dataPtr contains a native handle, send it via recordingFrameHandleCallbackTimestamp.
+ if (handle != nullptr) {
+ {
+ Mutex::Autolock l(mAvailableCallbackBuffersLock);
+ mAvailableCallbackBuffers.push_back(dataPtr);
+ }
+ c->recordingFrameHandleCallbackTimestamp(timestamp, handle);
+ } else {
+ c->dataCallbackTimestamp(timestamp, msgType, dataPtr);
+ }
}
}
diff --git a/services/camera/libcameraservice/api1/CameraClient.h b/services/camera/libcameraservice/api1/CameraClient.h
index 603fd17..4f46fc4 100644
--- a/services/camera/libcameraservice/api1/CameraClient.h
+++ b/services/camera/libcameraservice/api1/CameraClient.h
@@ -49,6 +49,7 @@
virtual void stopRecording();
virtual bool recordingEnabled();
virtual void releaseRecordingFrame(const sp<IMemory>& mem);
+ virtual void releaseRecordingFrameHandle(native_handle_t *handle);
virtual status_t autoFocus();
virtual status_t cancelAutoFocus();
virtual status_t takePicture(int msgType);
@@ -148,6 +149,12 @@
// Debugging information
CameraParameters mLatestSetParameters;
+ // mAvailableCallbackBuffers stores sp<IMemory> that HAL uses to send VideoNativeHandleMetadata.
+ // It will be used to send VideoNativeHandleMetadata back to HAL when camera receives the
+ // native handle from releaseRecordingFrameHandle.
+ Mutex mAvailableCallbackBuffersLock;
+ std::vector<sp<IMemory>> mAvailableCallbackBuffers;
+
// We need to avoid the deadlock when the incoming command thread and
// the CameraHardwareInterface callback thread both want to grab mLock.
// An extra flag is used to tell the callback thread that it should stop