summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWu-cheng Li <wuchengli@google.com>2011-06-01 17:22:24 +0800
committerWu-cheng Li <wuchengli@google.com>2011-06-27 15:44:57 +0800
commit42419ce28a09eb63e29a8fef87e6f5534f41902f (patch)
treef4c758095b56ee9257e90acc4050da046783663d
parent14f14863c508ff38fb2fe925c89e2bb2228fcffe (diff)
downloadframeworks_base-42419ce28a09eb63e29a8fef87e6f5534f41902f.zip
frameworks_base-42419ce28a09eb63e29a8fef87e6f5534f41902f.tar.gz
frameworks_base-42419ce28a09eb63e29a8fef87e6f5534f41902f.tar.bz2
Add framework support for camcorder zoom.
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(). bug:2644213 Change-Id: I15269397defc25cbbcae16abc071c8349c123122
-rw-r--r--core/java/android/hardware/Camera.java19
-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--libs/camera/Android.mk4
-rw-r--r--libs/camera/Camera.cpp56
-rw-r--r--libs/camera/ICameraRecordingProxy.cpp109
-rw-r--r--libs/camera/ICameraRecordingProxyListener.cpp75
-rw-r--r--media/java/android/media/MediaRecorder.java15
-rw-r--r--media/jni/android_media_MediaRecorder.cpp2
-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
24 files changed, 604 insertions, 98 deletions
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 0be1776..8a42693 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -288,7 +288,8 @@ public class Camera {
* you can call {@link #reconnect()} to reclaim the camera.
*
* <p>This must be done before calling
- * {@link android.media.MediaRecorder#setCamera(Camera)}.
+ * {@link android.media.MediaRecorder#setCamera(Camera)}. This cannot be
+ * called after recording starts.
*
* <p>If you are not recording video, you probably do not need this method.
*
@@ -301,6 +302,11 @@ public class Camera {
* Camera objects are locked by default unless {@link #unlock()} is
* called. Normally {@link #reconnect()} is used instead.
*
+ * <p>Since API level 13, camera is automatically locked for applications in
+ * {@link android.media.MediaRecorder#start()}. Applications can use the
+ * camera (ex: zoom) after recording starts. There is no need to call this
+ * after recording starts or stops.
+ *
* <p>If you are not recording video, you probably do not need this method.
*
* @throws RuntimeException if the camera cannot be re-locked (for
@@ -315,9 +321,10 @@ public class Camera {
* which will re-acquire the lock and allow you to continue using the
* camera.
*
- * <p>This must be done after {@link android.media.MediaRecorder} is
- * done recording if {@link android.media.MediaRecorder#setCamera(Camera)}
- * was used.
+ * <p>Since API level 13, camera is automatically locked for applications in
+ * {@link android.media.MediaRecorder#start()}. Applications can use the
+ * camera (ex: zoom) after recording starts. There is no need to call this
+ * after recording starts or stops.
*
* <p>If you are not recording video, you probably do not need this method.
*
@@ -827,7 +834,9 @@ public class Camera {
* <p>This method is only valid when preview is active (after
* {@link #startPreview()}). Preview will be stopped after the image is
* taken; callers must call {@link #startPreview()} again if they want to
- * re-start preview or take more pictures.
+ * re-start preview or take more pictures. This should not be called between
+ * {@link android.media.MediaRecorder#start()} and
+ * {@link android.media.MediaRecorder#stop()}.
*
* <p>After calling this method, you must not call {@link #startPreview()}
* or take another picture until the JPEG callback has returned.
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/libs/camera/Android.mk b/libs/camera/Android.mk
index b17b3d2..dc00957 100644
--- a/libs/camera/Android.mk
+++ b/libs/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/libs/camera/Camera.cpp b/libs/camera/Camera.cpp
index 5eb48da..3c00db5 100644
--- a/libs/camera/Camera.cpp
+++ b/libs/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/libs/camera/ICameraRecordingProxy.cpp b/libs/camera/ICameraRecordingProxy.cpp
new file mode 100644
index 0000000..64b6a5c
--- /dev/null
+++ b/libs/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/libs/camera/ICameraRecordingProxyListener.cpp b/libs/camera/ICameraRecordingProxyListener.cpp
new file mode 100644
index 0000000..f8cece5
--- /dev/null
+++ b/libs/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/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index dd45111..6f42596 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -16,17 +16,16 @@
package android.media;
-import android.media.CamcorderProfile;
import android.hardware.Camera;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.Surface;
-import java.io.IOException;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
+
import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
import java.lang.ref.WeakReference;
/**
@@ -112,7 +111,8 @@ public class MediaRecorder
/**
* Sets a Camera to use for recording. Use this function to switch
* quickly between preview and capture mode without a teardown of
- * the camera object. Must call before prepare().
+ * the camera object. {@link android.hardware.Camera#unlock()} should be
+ * called before this. Must call before prepare().
*
* @param c the Camera to use for recording
*/
@@ -718,6 +718,11 @@ public class MediaRecorder
* Begins capturing and encoding data to the file specified with
* setOutputFile(). Call this after prepare().
*
+ * <p>Since API level 13, if applications set a camera via
+ * {@link #setCamera(Camera)}, the apps can use the camera after this method
+ * call. The apps do not need to lock the camera again. The apps should not
+ * start another recording session during recording.
+ *
* @throws IllegalStateException if it is called before
* prepare().
*/
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 2f7d7ee..12391c8 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -158,7 +158,7 @@ static void android_media_MediaRecorder_setCamera(JNIEnv* env, jobject thiz, job
}
sp<Camera> c = get_native_camera(env, camera, NULL);
sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
- process_media_recorder_call(env, mr->setCamera(c->remote()),
+ process_media_recorder_call(env, mr->setCamera(c->remote(), c->getRecordingProxy()),
"java/lang/RuntimeException", "setCamera failed.");
}
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"