summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--camera/Android.mk4
-rw-r--r--camera/Camera.cpp56
-rw-r--r--camera/ICameraRecordingProxy.cpp109
-rw-r--r--camera/ICameraRecordingProxyListener.cpp75
-rw-r--r--include/camera/Camera.h25
-rw-r--r--include/camera/ICameraRecordingProxy.h101
-rw-r--r--include/camera/ICameraRecordingProxyListener.h52
-rw-r--r--include/media/IMediaRecorder.h46
-rw-r--r--include/media/MediaRecorderBase.h4
-rw-r--r--include/media/mediarecorder.h3
-rw-r--r--include/media/stagefright/CameraSource.h34
-rw-r--r--include/media/stagefright/CameraSourceTimeLapse.h2
-rw-r--r--media/libmedia/IMediaRecorder.cpp9
-rw-r--r--media/libmedia/mediarecorder.cpp6
-rw-r--r--media/libmediaplayerservice/MediaRecorderClient.cpp5
-rw-r--r--media/libmediaplayerservice/MediaRecorderClient.h4
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.cpp14
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.h4
-rw-r--r--media/libstagefright/CameraSource.cpp88
-rw-r--r--media/libstagefright/CameraSourceTimeLapse.cpp16
-rw-r--r--services/camera/libcameraservice/CameraService.cpp9
21 files changed, 579 insertions, 87 deletions
diff --git a/camera/Android.mk b/camera/Android.mk
index b17b3d2..dc00957 100644
--- a/camera/Android.mk
+++ b/camera/Android.mk
@@ -6,7 +6,9 @@ LOCAL_SRC_FILES:= \
CameraParameters.cpp \
ICamera.cpp \
ICameraClient.cpp \
- ICameraService.cpp
+ ICameraService.cpp \
+ ICameraRecordingProxy.cpp \
+ ICameraRecordingProxyListener.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
diff --git a/camera/Camera.cpp b/camera/Camera.cpp
index 5eb48da..3c00db5 100644
--- a/camera/Camera.cpp
+++ b/camera/Camera.cpp
@@ -19,11 +19,12 @@
#define LOG_TAG "Camera"
#include <utils/Log.h>
#include <utils/threads.h>
-
+#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/IMemory.h>
#include <camera/Camera.h>
+#include <camera/ICameraRecordingProxyListener.h>
#include <camera/ICameraService.h>
#include <surfaceflinger/Surface.h>
@@ -236,6 +237,10 @@ void Camera::stopPreview()
void Camera::stopRecording()
{
LOGV("stopRecording");
+ {
+ Mutex::Autolock _l(mLock);
+ mRecordingProxyListener.clear();
+ }
sp <ICamera> c = mCamera;
if (c == 0) return;
c->stopRecording();
@@ -327,6 +332,12 @@ void Camera::setListener(const sp<CameraListener>& listener)
mListener = listener;
}
+void Camera::setRecordingProxyListener(const sp<ICameraRecordingProxyListener>& listener)
+{
+ Mutex::Autolock _l(mLock);
+ mRecordingProxyListener = listener;
+}
+
void Camera::setPreviewCallbackFlags(int flag)
{
LOGV("setPreviewCallbackFlags");
@@ -364,6 +375,19 @@ void Camera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr)
// callback from camera service when timestamped frame is ready
void Camera::dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr)
{
+ // If recording proxy listener is registered, forward the frame and return.
+ // The other listener (mListener) is ignored because the receiver needs to
+ // call releaseRecordingFrame.
+ sp<ICameraRecordingProxyListener> proxylistener;
+ {
+ Mutex::Autolock _l(mLock);
+ proxylistener = mRecordingProxyListener;
+ }
+ if (proxylistener != NULL) {
+ proxylistener->dataCallbackTimestamp(timestamp, msgType, dataPtr);
+ return;
+ }
+
sp<CameraListener> listener;
{
Mutex::Autolock _l(mLock);
@@ -389,4 +413,34 @@ void Camera::DeathNotifier::binderDied(const wp<IBinder>& who) {
LOGW("Camera server died!");
}
+sp<ICameraRecordingProxy> Camera::getRecordingProxy() {
+ LOGV("getProxy");
+ return new RecordingProxy(this);
+}
+
+status_t Camera::RecordingProxy::startRecording(const sp<ICameraRecordingProxyListener>& listener)
+{
+ LOGV("RecordingProxy::startRecording");
+ mCamera->setRecordingProxyListener(listener);
+ mCamera->reconnect();
+ return mCamera->startRecording();
+}
+
+void Camera::RecordingProxy::stopRecording()
+{
+ LOGV("RecordingProxy::stopRecording");
+ mCamera->stopRecording();
+}
+
+void Camera::RecordingProxy::releaseRecordingFrame(const sp<IMemory>& mem)
+{
+ LOGV("RecordingProxy::releaseRecordingFrame");
+ mCamera->releaseRecordingFrame(mem);
+}
+
+Camera::RecordingProxy::RecordingProxy(const sp<Camera>& camera)
+{
+ mCamera = camera;
+}
+
}; // namespace android
diff --git a/camera/ICameraRecordingProxy.cpp b/camera/ICameraRecordingProxy.cpp
new file mode 100644
index 0000000..64b6a5c
--- /dev/null
+++ b/camera/ICameraRecordingProxy.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2011 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 "ICameraRecordingProxy"
+#include <camera/ICameraRecordingProxy.h>
+#include <camera/ICameraRecordingProxyListener.h>
+#include <binder/IMemory.h>
+#include <binder/Parcel.h>
+#include <stdint.h>
+#include <utils/Log.h>
+
+namespace android {
+
+enum {
+ START_RECORDING = IBinder::FIRST_CALL_TRANSACTION,
+ STOP_RECORDING,
+ RELEASE_RECORDING_FRAME,
+};
+
+
+class BpCameraRecordingProxy: public BpInterface<ICameraRecordingProxy>
+{
+public:
+ BpCameraRecordingProxy(const sp<IBinder>& impl)
+ : BpInterface<ICameraRecordingProxy>(impl)
+ {
+ }
+
+ status_t startRecording(const sp<ICameraRecordingProxyListener>& listener)
+ {
+ LOGV("startRecording");
+ Parcel data, reply;
+ data.writeInterfaceToken(ICameraRecordingProxy::getInterfaceDescriptor());
+ data.writeStrongBinder(listener->asBinder());
+ remote()->transact(START_RECORDING, data, &reply);
+ return reply.readInt32();
+ }
+
+ void stopRecording()
+ {
+ LOGV("stopRecording");
+ Parcel data, reply;
+ data.writeInterfaceToken(ICameraRecordingProxy::getInterfaceDescriptor());
+ remote()->transact(STOP_RECORDING, data, &reply);
+ }
+
+ void releaseRecordingFrame(const sp<IMemory>& mem)
+ {
+ LOGV("releaseRecordingFrame");
+ Parcel data, reply;
+ data.writeInterfaceToken(ICameraRecordingProxy::getInterfaceDescriptor());
+ data.writeStrongBinder(mem->asBinder());
+ remote()->transact(RELEASE_RECORDING_FRAME, data, &reply);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(CameraRecordingProxy, "android.hardware.ICameraRecordingProxy");
+
+// ----------------------------------------------------------------------
+
+status_t BnCameraRecordingProxy::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case START_RECORDING: {
+ LOGV("START_RECORDING");
+ CHECK_INTERFACE(ICameraRecordingProxy, data, reply);
+ sp<ICameraRecordingProxyListener> listener =
+ interface_cast<ICameraRecordingProxyListener>(data.readStrongBinder());
+ reply->writeInt32(startRecording(listener));
+ return NO_ERROR;
+ } break;
+ case STOP_RECORDING: {
+ LOGV("STOP_RECORDING");
+ CHECK_INTERFACE(ICameraRecordingProxy, data, reply);
+ stopRecording();
+ return NO_ERROR;
+ } break;
+ case RELEASE_RECORDING_FRAME: {
+ LOGV("RELEASE_RECORDING_FRAME");
+ CHECK_INTERFACE(ICameraRecordingProxy, data, reply);
+ sp<IMemory> mem = interface_cast<IMemory>(data.readStrongBinder());
+ releaseRecordingFrame(mem);
+ return NO_ERROR;
+ } break;
+
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/camera/ICameraRecordingProxyListener.cpp b/camera/ICameraRecordingProxyListener.cpp
new file mode 100644
index 0000000..f8cece5
--- /dev/null
+++ b/camera/ICameraRecordingProxyListener.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2011 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 "ICameraRecordingProxyListener"
+#include <camera/ICameraRecordingProxyListener.h>
+#include <binder/IMemory.h>
+#include <binder/Parcel.h>
+#include <utils/Log.h>
+
+namespace android {
+
+enum {
+ DATA_CALLBACK_TIMESTAMP = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+class BpCameraRecordingProxyListener: public BpInterface<ICameraRecordingProxyListener>
+{
+public:
+ BpCameraRecordingProxyListener(const sp<IBinder>& impl)
+ : BpInterface<ICameraRecordingProxyListener>(impl)
+ {
+ }
+
+ void dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& imageData)
+ {
+ LOGV("dataCallback");
+ Parcel data, reply;
+ data.writeInterfaceToken(ICameraRecordingProxyListener::getInterfaceDescriptor());
+ data.writeInt64(timestamp);
+ data.writeInt32(msgType);
+ data.writeStrongBinder(imageData->asBinder());
+ remote()->transact(DATA_CALLBACK_TIMESTAMP, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(CameraRecordingProxyListener, "android.hardware.ICameraRecordingProxyListener");
+
+// ----------------------------------------------------------------------
+
+status_t BnCameraRecordingProxyListener::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case DATA_CALLBACK_TIMESTAMP: {
+ LOGV("DATA_CALLBACK_TIMESTAMP");
+ CHECK_INTERFACE(ICameraRecordingProxyListener, data, reply);
+ nsecs_t timestamp = data.readInt64();
+ int32_t msgType = data.readInt32();
+ sp<IMemory> imageData = interface_cast<IMemory>(data.readStrongBinder());
+ dataCallbackTimestamp(timestamp, msgType, imageData);
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/include/camera/Camera.h b/include/camera/Camera.h
index 7106bfa..f701280 100644
--- a/include/camera/Camera.h
+++ b/include/camera/Camera.h
@@ -18,9 +18,11 @@
#define ANDROID_HARDWARE_CAMERA_H
#include <utils/Timers.h>
-#include <camera/ICameraClient.h>
#include <gui/ISurfaceTexture.h>
#include <system/camera.h>
+#include <camera/ICameraClient.h>
+#include <camera/ICameraRecordingProxy.h>
+#include <camera/ICameraRecordingProxyListener.h>
namespace android {
@@ -70,7 +72,7 @@ public:
static status_t getCameraInfo(int cameraId,
struct CameraInfo* cameraInfo);
static sp<Camera> connect(int cameraId);
- ~Camera();
+ virtual ~Camera();
void init();
status_t reconnect();
@@ -129,8 +131,11 @@ public:
status_t storeMetaDataInBuffers(bool enabled);
void setListener(const sp<CameraListener>& listener);
+ void setRecordingProxyListener(const sp<ICameraRecordingProxyListener>& listener);
void setPreviewCallbackFlags(int preview_callback_flag);
+ sp<ICameraRecordingProxy> getRecordingProxy();
+
// ICameraClient interface
virtual void notifyCallback(int32_t msgType, int32_t ext, int32_t ext2);
virtual void dataCallback(int32_t msgType, const sp<IMemory>& dataPtr);
@@ -138,6 +143,20 @@ public:
sp<ICamera> remote();
+ class RecordingProxy : public BnCameraRecordingProxy
+ {
+ public:
+ RecordingProxy(const sp<Camera>& camera);
+
+ // ICameraRecordingProxy interface
+ virtual status_t startRecording(const sp<ICameraRecordingProxyListener>& listener);
+ virtual void stopRecording();
+ virtual void releaseRecordingFrame(const sp<IMemory>& mem);
+
+ private:
+ sp<Camera> mCamera;
+ };
+
private:
Camera();
Camera(const Camera&);
@@ -162,12 +181,12 @@ private:
status_t mStatus;
sp<CameraListener> mListener;
+ sp<ICameraRecordingProxyListener> mRecordingProxyListener;
friend class DeathNotifier;
static Mutex mLock;
static sp<ICameraService> mCameraService;
-
};
}; // namespace android
diff --git a/include/camera/ICameraRecordingProxy.h b/include/camera/ICameraRecordingProxy.h
new file mode 100644
index 0000000..2aac284
--- /dev/null
+++ b/include/camera/ICameraRecordingProxy.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2011 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_HARDWARE_ICAMERA_RECORDING_PROXY_H
+#define ANDROID_HARDWARE_ICAMERA_RECORDING_PROXY_H
+
+#include <binder/IInterface.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+class ICameraRecordingProxyListener;
+class IMemory;
+class Parcel;
+
+/*
+ * The purpose of ICameraRecordingProxy and ICameraRecordingProxyListener is to
+ * allow applications using the camera during recording.
+ *
+ * Camera service allows only one client at a time. Since camcorder application
+ * needs to own the camera to do things like zoom, the media recorder cannot
+ * access the camera directly during recording. So ICameraRecordingProxy is a
+ * proxy of ICamera, which allows the media recorder to start/stop the recording
+ * and release recording frames. ICameraRecordingProxyListener is an interface
+ * that allows the recorder to receive video frames during recording.
+ *
+ * ICameraRecordingProxy
+ * startRecording()
+ * stopRecording()
+ * releaseRecordingFrame()
+ *
+ * ICameraRecordingProxyListener
+ * dataCallbackTimestamp()
+
+ * The camcorder app opens the camera and starts the preview. The app passes
+ * ICamera and ICameraRecordingProxy to the media recorder by
+ * MediaRecorder::setCamera(). The recorder uses ICamera to setup the camera in
+ * MediaRecorder::start(). After setup, the recorder disconnects from camera
+ * service. The recorder calls ICameraRecordingProxy::startRecording() and
+ * passes a ICameraRecordingProxyListener to the app. The app connects back to
+ * camera service and starts the recording. The app owns the camera and can do
+ * things like zoom. The media recorder receives the video frames from the
+ * listener and releases them by ICameraRecordingProxy::releaseRecordingFrame.
+ * The recorder calls ICameraRecordingProxy::stopRecording() to stop the
+ * recording.
+ *
+ * The call sequences are as follows:
+ * 1. The app: Camera.unlock().
+ * 2. The app: MediaRecorder.setCamera().
+ * 3. Start recording
+ * (1) The app: MediaRecorder.start().
+ * (2) The recorder: ICamera.unlock() and ICamera.disconnect().
+ * (3) The recorder: ICameraRecordingProxy.startRecording().
+ * (4) The app: ICamera.reconnect().
+ * (5) The app: ICamera.startRecording().
+ * 4. During recording
+ * (1) The recorder: receive frames from ICameraRecordingProxyListener.dataCallbackTimestamp()
+ * (2) The recorder: release frames by ICameraRecordingProxy.releaseRecordingFrame().
+ * 5. Stop recording
+ * (1) The app: MediaRecorder.stop()
+ * (2) The recorder: ICameraRecordingProxy.stopRecording().
+ * (3) The app: ICamera.stopRecording().
+ */
+
+class ICameraRecordingProxy: public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(CameraRecordingProxy);
+
+ virtual status_t startRecording(const sp<ICameraRecordingProxyListener>& listener) = 0;
+ virtual void stopRecording() = 0;
+ virtual void releaseRecordingFrame(const sp<IMemory>& mem) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnCameraRecordingProxy: public BnInterface<ICameraRecordingProxy>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif
diff --git a/include/camera/ICameraRecordingProxyListener.h b/include/camera/ICameraRecordingProxyListener.h
new file mode 100644
index 0000000..b6c0624
--- /dev/null
+++ b/include/camera/ICameraRecordingProxyListener.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2011 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_HARDWARE_ICAMERA_RECORDING_PROXY_LISTENER_H
+#define ANDROID_HARDWARE_ICAMERA_RECORDING_PROXY_LISTENER_H
+
+#include <binder/IInterface.h>
+#include <stdint.h>
+#include <utils/RefBase.h>
+#include <utils/Timers.h>
+
+namespace android {
+
+class Parcel;
+class IMemory;
+
+class ICameraRecordingProxyListener: public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(CameraRecordingProxyListener);
+
+ virtual void dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType,
+ const sp<IMemory>& data) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnCameraRecordingProxyListener: public BnInterface<ICameraRecordingProxyListener>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif
diff --git a/include/media/IMediaRecorder.h b/include/media/IMediaRecorder.h
index 28be7c1..a73267d 100644
--- a/include/media/IMediaRecorder.h
+++ b/include/media/IMediaRecorder.h
@@ -24,6 +24,7 @@ namespace android {
class Surface;
class ICamera;
+class ICameraRecordingProxy;
class IMediaRecorderClient;
class IMediaRecorder: public IInterface
@@ -31,28 +32,29 @@ class IMediaRecorder: public IInterface
public:
DECLARE_META_INTERFACE(MediaRecorder);
- virtual status_t setCamera(const sp<ICamera>& camera) = 0;
- virtual status_t setPreviewSurface(const sp<Surface>& surface) = 0;
- virtual status_t setVideoSource(int vs) = 0;
- virtual status_t setAudioSource(int as) = 0;
- virtual status_t setOutputFormat(int of) = 0;
- virtual status_t setVideoEncoder(int ve) = 0;
- virtual status_t setAudioEncoder(int ae) = 0;
- virtual status_t setOutputFile(const char* path) = 0;
- virtual status_t setOutputFile(int fd, int64_t offset, int64_t length) = 0;
- virtual status_t setOutputFileAuxiliary(int fd) = 0;
- virtual status_t setVideoSize(int width, int height) = 0;
- virtual status_t setVideoFrameRate(int frames_per_second) = 0;
- virtual status_t setParameters(const String8& params) = 0;
- virtual status_t setListener(const sp<IMediaRecorderClient>& listener) = 0;
- virtual status_t prepare() = 0;
- virtual status_t getMaxAmplitude(int* max) = 0;
- virtual status_t start() = 0;
- virtual status_t stop() = 0;
- virtual status_t reset() = 0;
- virtual status_t init() = 0;
- virtual status_t close() = 0;
- virtual status_t release() = 0;
+ virtual status_t setCamera(const sp<ICamera>& camera,
+ const sp<ICameraRecordingProxy>& proxy) = 0;
+ virtual status_t setPreviewSurface(const sp<Surface>& surface) = 0;
+ virtual status_t setVideoSource(int vs) = 0;
+ virtual status_t setAudioSource(int as) = 0;
+ virtual status_t setOutputFormat(int of) = 0;
+ virtual status_t setVideoEncoder(int ve) = 0;
+ virtual status_t setAudioEncoder(int ae) = 0;
+ virtual status_t setOutputFile(const char* path) = 0;
+ virtual status_t setOutputFile(int fd, int64_t offset, int64_t length) = 0;
+ virtual status_t setOutputFileAuxiliary(int fd) = 0;
+ virtual status_t setVideoSize(int width, int height) = 0;
+ virtual status_t setVideoFrameRate(int frames_per_second) = 0;
+ virtual status_t setParameters(const String8& params) = 0;
+ virtual status_t setListener(const sp<IMediaRecorderClient>& listener) = 0;
+ virtual status_t prepare() = 0;
+ virtual status_t getMaxAmplitude(int* max) = 0;
+ virtual status_t start() = 0;
+ virtual status_t stop() = 0;
+ virtual status_t reset() = 0;
+ virtual status_t init() = 0;
+ virtual status_t close() = 0;
+ virtual status_t release() = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/media/MediaRecorderBase.h b/include/media/MediaRecorderBase.h
index 7e22a24..1c08969 100644
--- a/include/media/MediaRecorderBase.h
+++ b/include/media/MediaRecorderBase.h
@@ -24,6 +24,7 @@
namespace android {
+class ICameraRecordingProxy;
class Surface;
struct MediaRecorderBase {
@@ -38,7 +39,8 @@ struct MediaRecorderBase {
virtual status_t setVideoEncoder(video_encoder ve) = 0;
virtual status_t setVideoSize(int width, int height) = 0;
virtual status_t setVideoFrameRate(int frames_per_second) = 0;
- virtual status_t setCamera(const sp<ICamera>& camera) = 0;
+ virtual status_t setCamera(const sp<ICamera>& camera,
+ const sp<ICameraRecordingProxy>& proxy) = 0;
virtual status_t setPreviewSurface(const sp<Surface>& surface) = 0;
virtual status_t setOutputFile(const char *path) = 0;
virtual status_t setOutputFile(int fd, int64_t offset, int64_t length) = 0;
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index 36bf34e..af12d3c 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -30,6 +30,7 @@ namespace android {
class Surface;
class IMediaRecorder;
class ICamera;
+class ICameraRecordingProxy;
typedef void (*media_completion_f)(status_t status, void *cookie);
@@ -202,7 +203,7 @@ public:
void died();
status_t initCheck();
- status_t setCamera(const sp<ICamera>& camera);
+ status_t setCamera(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy);
status_t setPreviewSurface(const sp<Surface>& surface);
status_t setVideoSource(int vs);
status_t setAudioSource(int as);
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h
index bb25bae..80b7c1c 100644
--- a/include/media/stagefright/CameraSource.h
+++ b/include/media/stagefright/CameraSource.h
@@ -21,6 +21,7 @@
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaSource.h>
#include <camera/ICamera.h>
+#include <camera/ICameraRecordingProxyListener.h>
#include <camera/CameraParameters.h>
#include <utils/List.h>
#include <utils/RefBase.h>
@@ -68,6 +69,7 @@ public:
* @return NULL on error.
*/
static CameraSource *CreateFromCamera(const sp<ICamera> &camera,
+ const sp<ICameraRecordingProxy> &proxy,
int32_t cameraId,
Size videoSize,
int32_t frameRate,
@@ -111,6 +113,23 @@ public:
virtual void signalBufferReturned(MediaBuffer* buffer);
protected:
+ class ProxyListener: public BnCameraRecordingProxyListener {
+ public:
+ ProxyListener(const sp<CameraSource>& source);
+ virtual void dataCallbackTimestamp(int64_t timestampUs, int32_t msgType,
+ const sp<IMemory> &data);
+
+ private:
+ sp<CameraSource> mSource;
+ };
+
+ // isBinderAlive needs linkToDeath to work.
+ class DeathNotifier: public IBinder::DeathRecipient {
+ public:
+ DeathNotifier() {}
+ virtual void binderDied(const wp<IBinder>& who);
+ };
+
enum CameraFlags {
FLAGS_SET_CAMERA = 1L << 0,
FLAGS_HOT_CAMERA = 1L << 1,
@@ -123,6 +142,8 @@ protected:
status_t mInitCheck;
sp<Camera> mCamera;
+ sp<ICameraRecordingProxy> mCameraRecordingProxy;
+ sp<DeathNotifier> mDeathNotifier;
sp<Surface> mSurface;
sp<MetaData> mMeta;
@@ -132,7 +153,8 @@ protected:
bool mStarted;
int32_t mNumFramesEncoded;
- CameraSource(const sp<ICamera>& camera, int32_t cameraId,
+ CameraSource(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
+ int32_t cameraId,
Size videoSize, int32_t frameRate,
const sp<Surface>& surface,
bool storeMetaDataInVideoBuffers);
@@ -172,10 +194,12 @@ private:
void releaseOneRecordingFrame(const sp<IMemory>& frame);
- status_t init(const sp<ICamera>& camera, int32_t cameraId,
- Size videoSize, int32_t frameRate,
- bool storeMetaDataInVideoBuffers);
- status_t isCameraAvailable(const sp<ICamera>& camera, int32_t cameraId);
+ status_t init(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
+ int32_t cameraId, Size videoSize, int32_t frameRate,
+ bool storeMetaDataInVideoBuffers);
+ status_t isCameraAvailable(const sp<ICamera>& camera,
+ const sp<ICameraRecordingProxy>& proxy,
+ int32_t cameraId);
status_t isCameraColorFormatSupported(const CameraParameters& params);
status_t configureCamera(CameraParameters* params,
int32_t width, int32_t height,
diff --git a/include/media/stagefright/CameraSourceTimeLapse.h b/include/media/stagefright/CameraSourceTimeLapse.h
index 0e5d534..f07ebba 100644
--- a/include/media/stagefright/CameraSourceTimeLapse.h
+++ b/include/media/stagefright/CameraSourceTimeLapse.h
@@ -33,6 +33,7 @@ class CameraSourceTimeLapse : public CameraSource {
public:
static CameraSourceTimeLapse *CreateFromCamera(
const sp<ICamera> &camera,
+ const sp<ICameraRecordingProxy> &proxy,
int32_t cameraId,
Size videoSize,
int32_t videoFrameRate,
@@ -132,6 +133,7 @@ private:
CameraSourceTimeLapse(
const sp<ICamera> &camera,
+ const sp<ICameraRecordingProxy> &proxy,
int32_t cameraId,
Size videoSize,
int32_t videoFrameRate,
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index 59cd1b7..a44ef5a 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -60,12 +60,13 @@ public:
{
}
- status_t setCamera(const sp<ICamera>& camera)
+ status_t setCamera(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy)
{
- LOGV("setCamera(%p)", camera.get());
+ LOGV("setCamera(%p,%p)", camera.get(), proxy.get());
Parcel data, reply;
data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
data.writeStrongBinder(camera->asBinder());
+ data.writeStrongBinder(proxy->asBinder());
remote()->transact(SET_CAMERA, data, &reply);
return reply.readInt32();
}
@@ -434,7 +435,9 @@ status_t BnMediaRecorder::onTransact(
LOGV("SET_CAMERA");
CHECK_INTERFACE(IMediaRecorder, data, reply);
sp<ICamera> camera = interface_cast<ICamera>(data.readStrongBinder());
- reply->writeInt32(setCamera(camera));
+ sp<ICameraRecordingProxy> proxy =
+ interface_cast<ICameraRecordingProxy>(data.readStrongBinder());
+ reply->writeInt32(setCamera(camera, proxy));
return NO_ERROR;
} break;
default:
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index 0100a17..9e4edd0 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -28,9 +28,9 @@
namespace android {
-status_t MediaRecorder::setCamera(const sp<ICamera>& camera)
+status_t MediaRecorder::setCamera(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy)
{
- LOGV("setCamera(%p)", camera.get());
+ LOGV("setCamera(%p,%p)", camera.get(), proxy.get());
if(mMediaRecorder == NULL) {
LOGE("media recorder is not initialized yet");
return INVALID_OPERATION;
@@ -40,7 +40,7 @@ status_t MediaRecorder::setCamera(const sp<ICamera>& camera)
return INVALID_OPERATION;
}
- status_t ret = mMediaRecorder->setCamera(camera);
+ status_t ret = mMediaRecorder->setCamera(camera, proxy);
if (OK != ret) {
LOGV("setCamera failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 29cc019..115db1a 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -57,7 +57,8 @@ static bool checkPermission(const char* permissionString) {
return ok;
}
-status_t MediaRecorderClient::setCamera(const sp<ICamera>& camera)
+status_t MediaRecorderClient::setCamera(const sp<ICamera>& camera,
+ const sp<ICameraRecordingProxy>& proxy)
{
LOGV("setCamera");
Mutex::Autolock lock(mLock);
@@ -65,7 +66,7 @@ status_t MediaRecorderClient::setCamera(const sp<ICamera>& camera)
LOGE("recorder is not initialized");
return NO_INIT;
}
- return mRecorder->setCamera(camera);
+ return mRecorder->setCamera(camera, proxy);
}
status_t MediaRecorderClient::setPreviewSurface(const sp<Surface>& surface)
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index fded98e..bbca529 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -24,11 +24,13 @@ namespace android {
class MediaRecorderBase;
class MediaPlayerService;
+class ICameraRecordingProxy;
class MediaRecorderClient : public BnMediaRecorder
{
public:
- virtual status_t setCamera(const sp<ICamera>& camera);
+ virtual status_t setCamera(const sp<ICamera>& camera,
+ const sp<ICameraRecordingProxy>& proxy);
virtual status_t setPreviewSurface(const sp<Surface>& surface);
virtual status_t setVideoSource(int vs);
virtual status_t setAudioSource(int as);
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 978571c..b003476 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -198,14 +198,20 @@ status_t StagefrightRecorder::setVideoFrameRate(int frames_per_second) {
return OK;
}
-status_t StagefrightRecorder::setCamera(const sp<ICamera> &camera) {
+status_t StagefrightRecorder::setCamera(const sp<ICamera> &camera,
+ const sp<ICameraRecordingProxy> &proxy) {
LOGV("setCamera");
if (camera == 0) {
LOGE("camera is NULL");
return BAD_VALUE;
}
+ if (proxy == 0) {
+ LOGE("camera proxy is NULL");
+ return BAD_VALUE;
+ }
mCamera = camera;
+ mCameraProxy = proxy;
return OK;
}
@@ -1235,15 +1241,17 @@ status_t StagefrightRecorder::setupCameraSource(
videoSize.height = mVideoHeight;
if (mCaptureTimeLapse) {
mCameraSourceTimeLapse = CameraSourceTimeLapse::CreateFromCamera(
- mCamera, mCameraId,
+ mCamera, mCameraProxy, mCameraId,
videoSize, mFrameRate, mPreviewSurface,
mTimeBetweenTimeLapseFrameCaptureUs);
*cameraSource = mCameraSourceTimeLapse;
} else {
*cameraSource = CameraSource::CreateFromCamera(
- mCamera, mCameraId, videoSize, mFrameRate,
+ mCamera, mCameraProxy, mCameraId, videoSize, mFrameRate,
mPreviewSurface, true /*storeMetaDataInVideoBuffers*/);
}
+ mCamera.clear();
+ mCameraProxy.clear();
if (*cameraSource == NULL) {
return UNKNOWN_ERROR;
}
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index aa67aa7..cb9c406 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -27,6 +27,7 @@
namespace android {
class Camera;
+class ICameraRecordingProxy;
class CameraSource;
class CameraSourceTimeLapse;
class MediaSourceSplitter;
@@ -48,7 +49,7 @@ struct StagefrightRecorder : public MediaRecorderBase {
virtual status_t setVideoEncoder(video_encoder ve);
virtual status_t setVideoSize(int width, int height);
virtual status_t setVideoFrameRate(int frames_per_second);
- virtual status_t setCamera(const sp<ICamera>& camera);
+ virtual status_t setCamera(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy);
virtual status_t setPreviewSurface(const sp<Surface>& surface);
virtual status_t setOutputFile(const char *path);
virtual status_t setOutputFile(int fd, int64_t offset, int64_t length);
@@ -66,6 +67,7 @@ struct StagefrightRecorder : public MediaRecorderBase {
private:
sp<ICamera> mCamera;
+ sp<ICameraRecordingProxy> mCameraProxy;
sp<Surface> mPreviewSurface;
sp<IMediaRecorderClient> mListener;
sp<MediaWriter> mWriter, mWriterAux;
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 61bb2a8..bdffce9 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -115,19 +115,20 @@ CameraSource *CameraSource::Create() {
size.height = -1;
sp<ICamera> camera;
- return new CameraSource(camera, 0, size, -1, NULL, false);
+ return new CameraSource(camera, NULL, 0, size, -1, NULL, false);
}
// static
CameraSource *CameraSource::CreateFromCamera(
const sp<ICamera>& camera,
+ const sp<ICameraRecordingProxy>& proxy,
int32_t cameraId,
Size videoSize,
int32_t frameRate,
const sp<Surface>& surface,
bool storeMetaDataInVideoBuffers) {
- CameraSource *source = new CameraSource(camera, cameraId,
+ CameraSource *source = new CameraSource(camera, proxy, cameraId,
videoSize, frameRate, surface,
storeMetaDataInVideoBuffers);
return source;
@@ -135,6 +136,7 @@ CameraSource *CameraSource::CreateFromCamera(
CameraSource::CameraSource(
const sp<ICamera>& camera,
+ const sp<ICameraRecordingProxy>& proxy,
int32_t cameraId,
Size videoSize,
int32_t frameRate,
@@ -153,11 +155,10 @@ CameraSource::CameraSource(
mNumGlitches(0),
mGlitchDurationThresholdUs(200000),
mCollectStats(false) {
-
mVideoSize.width = -1;
mVideoSize.height = -1;
- mInitCheck = init(camera, cameraId,
+ mInitCheck = init(camera, proxy, cameraId,
videoSize, frameRate,
storeMetaDataInVideoBuffers);
}
@@ -167,24 +168,32 @@ status_t CameraSource::initCheck() const {
}
status_t CameraSource::isCameraAvailable(
- const sp<ICamera>& camera, int32_t cameraId) {
+ const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
+ int32_t cameraId) {
if (camera == 0) {
mCamera = Camera::connect(cameraId);
+ if (mCamera == 0) return -EBUSY;
+ // If proxy is not passed in by applications, still use the proxy of
+ // our own Camera to simplify the code.
+ mCameraRecordingProxy = mCamera->getRecordingProxy();
mCameraFlags &= ~FLAGS_HOT_CAMERA;
} else {
+ // We get the proxy from Camera, not ICamera. We need to get the proxy
+ // to the remote Camera owned by the application. Here mCamera is a
+ // local Camera object created by us. We cannot use the proxy from
+ // mCamera here.
mCamera = Camera::create(camera);
+ if (mCamera == 0) return -EBUSY;
+ mCameraRecordingProxy = proxy;
mCameraFlags |= FLAGS_HOT_CAMERA;
}
- // Is camera available?
- if (mCamera == 0) {
- LOGE("Camera connection could not be established.");
- return -EBUSY;
- }
- if (!(mCameraFlags & FLAGS_HOT_CAMERA)) {
- mCamera->lock();
- }
+ mCamera->lock();
+ mDeathNotifier = new DeathNotifier();
+ // isBinderAlive needs linkToDeath to work.
+ mCameraRecordingProxy->asBinder()->linkToDeath(mDeathNotifier);
+
return OK;
}
@@ -447,6 +456,7 @@ status_t CameraSource::checkFrameRate(
*/
status_t CameraSource::init(
const sp<ICamera>& camera,
+ const sp<ICameraRecordingProxy>& proxy,
int32_t cameraId,
Size videoSize,
int32_t frameRate,
@@ -455,7 +465,8 @@ status_t CameraSource::init(
status_t err = OK;
int64_t token = IPCThreadState::self()->clearCallingIdentity();
- if ((err = isCameraAvailable(camera, cameraId)) != OK) {
+ if ((err = isCameraAvailable(camera, proxy, cameraId)) != OK) {
+ LOGE("Camera connection could not be established.");
return err;
}
CameraParameters params(mCamera->getParameters());
@@ -521,8 +532,14 @@ CameraSource::~CameraSource() {
}
void CameraSource::startCameraRecording() {
- CHECK_EQ(OK, mCamera->startRecording());
- CHECK(mCamera->recordingEnabled());
+ // Reset the identity to the current thread because media server owns the
+ // camera and recording is started by the applications. The applications
+ // will connect to the camera in ICameraRecordingProxy::startRecording.
+ int64_t token = IPCThreadState::self()->clearCallingIdentity();
+ mCamera->unlock();
+ mCamera.clear();
+ IPCThreadState::self()->restoreCallingIdentity(token);
+ CHECK_EQ(OK, mCameraRecordingProxy->startRecording(new ProxyListener(this)));
}
status_t CameraSource::start(MetaData *meta) {
@@ -544,20 +561,14 @@ status_t CameraSource::start(MetaData *meta) {
mStartTimeUs = startTimeUs;
}
- // Call setListener first before calling startCameraRecording()
- // to avoid recording frames being dropped.
- int64_t token = IPCThreadState::self()->clearCallingIdentity();
- mCamera->setListener(new CameraSourceListener(this));
startCameraRecording();
- IPCThreadState::self()->restoreCallingIdentity(token);
mStarted = true;
return OK;
}
void CameraSource::stopCameraRecording() {
- mCamera->setListener(NULL);
- mCamera->stopRecording();
+ mCameraRecordingProxy->stopRecording();
}
void CameraSource::releaseCamera() {
@@ -566,9 +577,9 @@ void CameraSource::releaseCamera() {
LOGV("Camera was cold when we started, stopping preview");
mCamera->stopPreview();
}
- mCamera->unlock();
mCamera.clear();
- mCamera = 0;
+ mCameraRecordingProxy->asBinder()->unlinkToDeath(mDeathNotifier);
+ mCameraRecordingProxy.clear();
mCameraFlags = 0;
}
@@ -578,7 +589,6 @@ status_t CameraSource::stop() {
mStarted = false;
mFrameAvailableCondition.signal();
- int64_t token = IPCThreadState::self()->clearCallingIdentity();
releaseQueuedFrames();
while (!mFramesBeingEncoded.empty()) {
if (NO_ERROR !=
@@ -589,7 +599,6 @@ status_t CameraSource::stop() {
}
stopCameraRecording();
releaseCamera();
- IPCThreadState::self()->restoreCallingIdentity(token);
if (mCollectStats) {
LOGI("Frames received/encoded/dropped: %d/%d/%d in %lld us",
@@ -607,8 +616,8 @@ status_t CameraSource::stop() {
}
void CameraSource::releaseRecordingFrame(const sp<IMemory>& frame) {
- if (mCamera != NULL) {
- mCamera->releaseRecordingFrame(frame);
+ if (mCameraRecordingProxy != NULL) {
+ mCameraRecordingProxy->releaseRecordingFrame(frame);
}
}
@@ -627,9 +636,7 @@ sp<MetaData> CameraSource::getFormat() {
}
void CameraSource::releaseOneRecordingFrame(const sp<IMemory>& frame) {
- int64_t token = IPCThreadState::self()->clearCallingIdentity();
releaseRecordingFrame(frame);
- IPCThreadState::self()->restoreCallingIdentity(token);
}
void CameraSource::signalBufferReturned(MediaBuffer *buffer) {
@@ -669,7 +676,11 @@ status_t CameraSource::read(
Mutex::Autolock autoLock(mLock);
while (mStarted && mFramesReceived.empty()) {
if (NO_ERROR !=
- mFrameAvailableCondition.waitRelative(mLock, 3000000000LL)) {
+ mFrameAvailableCondition.waitRelative(mLock, 1000000000LL)) {
+ if (!mCameraRecordingProxy->asBinder()->isBinderAlive()) {
+ LOGW("camera recording proxy is gone");
+ return ERROR_END_OF_STREAM;
+ }
LOGW("Timed out waiting for incoming camera video frames: %lld us",
mLastFrameTimestampUs);
}
@@ -745,4 +756,17 @@ bool CameraSource::isMetaDataStoredInVideoBuffers() const {
return mIsMetaDataStoredInVideoBuffers;
}
+CameraSource::ProxyListener::ProxyListener(const sp<CameraSource>& source) {
+ mSource = source;
+}
+
+void CameraSource::ProxyListener::dataCallbackTimestamp(
+ nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) {
+ mSource->dataCallbackTimestamp(timestamp / 1000, msgType, dataPtr);
+}
+
+void CameraSource::DeathNotifier::binderDied(const wp<IBinder>& who) {
+ LOGI("Camera recording proxy died");
+}
+
} // namespace android
diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp
index cc22574..fe78c46 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -39,6 +39,7 @@ namespace android {
// static
CameraSourceTimeLapse *CameraSourceTimeLapse::CreateFromCamera(
const sp<ICamera> &camera,
+ const sp<ICameraRecordingProxy> &proxy,
int32_t cameraId,
Size videoSize,
int32_t videoFrameRate,
@@ -46,7 +47,7 @@ CameraSourceTimeLapse *CameraSourceTimeLapse::CreateFromCamera(
int64_t timeBetweenTimeLapseFrameCaptureUs) {
CameraSourceTimeLapse *source = new
- CameraSourceTimeLapse(camera, cameraId,
+ CameraSourceTimeLapse(camera, proxy, cameraId,
videoSize, videoFrameRate, surface,
timeBetweenTimeLapseFrameCaptureUs);
@@ -61,12 +62,13 @@ CameraSourceTimeLapse *CameraSourceTimeLapse::CreateFromCamera(
CameraSourceTimeLapse::CameraSourceTimeLapse(
const sp<ICamera>& camera,
+ const sp<ICameraRecordingProxy>& proxy,
int32_t cameraId,
Size videoSize,
int32_t videoFrameRate,
const sp<Surface>& surface,
int64_t timeBetweenTimeLapseFrameCaptureUs)
- : CameraSource(camera, cameraId, videoSize, videoFrameRate, surface, true),
+ : CameraSource(camera, proxy, cameraId, videoSize, videoFrameRate, surface, true),
mTimeBetweenTimeLapseFrameCaptureUs(timeBetweenTimeLapseFrameCaptureUs),
mTimeBetweenTimeLapseVideoFramesUs(1E6/videoFrameRate),
mLastTimeLapseFrameRealTimestampUs(0),
@@ -315,7 +317,7 @@ void CameraSourceTimeLapse::startCameraRecording() {
pthread_attr_destroy(&attr);
} else {
LOGV("start time lapse recording using video camera");
- CHECK_EQ(OK, mCamera->startRecording());
+ CameraSource::startCameraRecording();
}
}
@@ -337,8 +339,7 @@ void CameraSourceTimeLapse::stopCameraRecording() {
// play the recording sound.
mCamera->sendCommand(CAMERA_CMD_PLAY_RECORDING_SOUND, 0, 0);
} else {
- mCamera->setListener(NULL);
- mCamera->stopRecording();
+ CameraSource::stopCameraRecording();
}
if (mLastReadBufferCopy) {
mLastReadBufferCopy->release();
@@ -347,9 +348,8 @@ void CameraSourceTimeLapse::stopCameraRecording() {
}
void CameraSourceTimeLapse::releaseRecordingFrame(const sp<IMemory>& frame) {
- if (!mUseStillCameraForTimeLapse &&
- mCamera != NULL) {
- mCamera->releaseRecordingFrame(frame);
+ if (!mUseStillCameraForTimeLapse) {
+ CameraSource::releaseRecordingFrame(frame);
}
}
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index a011ae2..9b09983 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -420,6 +420,10 @@ status_t CameraService::Client::unlock() {
// allow anyone to use camera (after they lock the camera)
status_t result = checkPid();
if (result == NO_ERROR) {
+ if (mHardware->recordingEnabled()) {
+ LOGE("Not allowed to unlock camera during recording.");
+ return INVALID_OPERATION;
+ }
mClientPid = 0;
LOG1("clear mCameraClient (pid %d)", callingPid);
// we need to remove the reference to ICameraClient so that when the app
@@ -756,6 +760,11 @@ status_t CameraService::Client::takePicture(int msgType) {
status_t result = checkPidAndHardware();
if (result != NO_ERROR) return result;
+ if (mHardware->recordingEnabled()) {
+ LOGE("Cannot take picture during recording.");
+ return INVALID_OPERATION;
+ }
+
if ((msgType & CAMERA_MSG_RAW_IMAGE) &&
(msgType & CAMERA_MSG_RAW_IMAGE_NOTIFY)) {
LOGE("CAMERA_MSG_RAW_IMAGE and CAMERA_MSG_RAW_IMAGE_NOTIFY"