diff options
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" |