diff options
-rw-r--r-- | include/media/stagefright/CameraSource.h | 83 | ||||
-rw-r--r-- | include/media/stagefright/CameraSourceTimeLapse.h | 27 | ||||
-rw-r--r-- | media/libmediaplayerservice/StagefrightRecorder.cpp | 172 | ||||
-rw-r--r-- | media/libmediaplayerservice/StagefrightRecorder.h | 13 | ||||
-rw-r--r-- | media/libstagefright/CameraSource.cpp | 382 | ||||
-rw-r--r-- | media/libstagefright/CameraSourceTimeLapse.cpp | 68 |
6 files changed, 484 insertions, 261 deletions
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h index ed5f09f..b0bce29 100644 --- a/include/media/stagefright/CameraSource.h +++ b/include/media/stagefright/CameraSource.h @@ -20,25 +20,71 @@ #include <media/stagefright/MediaBuffer.h> #include <media/stagefright/MediaSource.h> +#include <camera/ICamera.h> +#include <camera/CameraParameters.h> #include <utils/List.h> #include <utils/RefBase.h> namespace android { -class ICamera; class IMemory; class Camera; +class Surface; class CameraSource : public MediaSource, public MediaBufferObserver { public: + /** + * Factory method to create a new CameraSource using the current + * settings (such as video size, frame rate, color format, etc) + * from the default camera. + * + * @return NULL on error. + */ static CameraSource *Create(); - static CameraSource *CreateFromCamera(const sp<Camera> &camera); + + /** + * Factory method to create a new CameraSource. + * + * @param camera the video input frame data source. If it is NULL, + * we will try to connect to the camera with the given + * cameraId. + * + * @param cameraId the id of the camera that the source will connect + * to if camera is NULL; otherwise ignored. + * + * @param videoSize the dimension (in pixels) of the video frame + * @param frameRate the target frames per second + * @param surface the preview surface for display where preview + * frames are sent to + * + * @return NULL on error. + */ + static CameraSource *CreateFromCamera(const sp<ICamera> &camera, + int32_t cameraId, + Size videoSize, + int32_t frameRate, + const sp<Surface>& surface); virtual ~CameraSource(); virtual status_t start(MetaData *params = NULL); virtual status_t stop(); + /** + * Check whether a CameraSource object is properly initialized. + * Must call this method before stop(). + * @return OK if initialization has successfully completed. + */ + virtual status_t initCheck() const; + + /** + * Returns the MetaData associated with the CameraSource, + * including: + * kKeyColorFormat: YUV color format of the video frames + * kKeyWidth, kKeyHeight: dimension (in pixels) of the video frames + * kKeySampleRate: frame rate in frames per second + * kKeyMimeType: always fixed + */ virtual sp<MetaData> getFormat(); virtual status_t read( @@ -47,7 +93,19 @@ public: virtual void signalBufferReturned(MediaBuffer* buffer); protected: - sp<Camera> mCamera; + enum CameraFlags { + FLAGS_SET_CAMERA = 1L << 0, + FLAGS_HOT_CAMERA = 1L << 1, + }; + + int32_t mCameraFlags; + Size mVideoSize; + int32_t mVideoFrameRate; + int32_t mColorFormat; + status_t mInitCheck; + + sp<Camera> mCamera; + sp<Surface> mSurface; sp<MetaData> mMeta; int64_t mStartTimeUs; @@ -55,7 +113,9 @@ protected: int64_t mLastFrameTimestampUs; bool mStarted; - CameraSource(const sp<Camera> &camera); + CameraSource(const sp<ICamera>& camera, int32_t cameraId, + Size videoSize, int32_t frameRate, + const sp<Surface>& surface); virtual void startCameraRecording(); virtual void stopCameraRecording(); @@ -91,6 +151,21 @@ private: void releaseQueuedFrames(); void releaseOneRecordingFrame(const sp<IMemory>& frame); + + status_t init(const sp<ICamera>& camera, int32_t cameraId, + Size videoSize, int32_t frameRate); + status_t isCameraAvailable(const sp<ICamera>& camera, int32_t cameraId); + status_t isCameraColorFormatSupported(const CameraParameters& params); + status_t configureCamera(CameraParameters* params, + int32_t width, int32_t height, + int32_t frameRate); + + status_t checkVideoSize(const CameraParameters& params, + int32_t width, int32_t height); + + status_t checkFrameRate(const CameraParameters& params, + int32_t frameRate); + CameraSource(const CameraSource &); CameraSource &operator=(const CameraSource &); }; diff --git a/include/media/stagefright/CameraSourceTimeLapse.h b/include/media/stagefright/CameraSourceTimeLapse.h index 3b303f8..afe7287 100644 --- a/include/media/stagefright/CameraSourceTimeLapse.h +++ b/include/media/stagefright/CameraSourceTimeLapse.h @@ -31,15 +31,13 @@ class Camera; class CameraSourceTimeLapse : public CameraSource { public: - static CameraSourceTimeLapse *Create( - int64_t timeBetweenTimeLapseFrameCaptureUs, - int32_t width, int32_t height, - int32_t videoFrameRate); - - static CameraSourceTimeLapse *CreateFromCamera(const sp<Camera> &camera, - int64_t timeBetweenTimeLapseFrameCaptureUs, - int32_t width, int32_t height, - int32_t videoFrameRate); + static CameraSourceTimeLapse *CreateFromCamera( + const sp<ICamera> &camera, + int32_t cameraId, + Size videoSize, + int32_t videoFrameRate, + const sp<Surface>& surface, + int64_t timeBetweenTimeLapseFrameCaptureUs); virtual ~CameraSourceTimeLapse(); @@ -132,10 +130,13 @@ private: // Status code for last read. status_t mLastReadStatus; - CameraSourceTimeLapse(const sp<Camera> &camera, - int64_t timeBetweenTimeLapseFrameCaptureUs, - int32_t width, int32_t height, - int32_t videoFrameRate); + CameraSourceTimeLapse( + const sp<ICamera> &camera, + int32_t cameraId, + Size videoSize, + int32_t videoFrameRate, + const sp<Surface>& surface, + int64_t timeBetweenTimeLapseFrameCaptureUs); // Wrapper over CameraSource::signalBufferReturned() to implement quick stop. // It only handles the case when mLastReadBufferCopy is signalled. Otherwise diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index 7a78185..06d5cd5 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -20,7 +20,6 @@ #include "StagefrightRecorder.h" -#include <binder/IPCThreadState.h> #include <media/stagefright/AudioSource.h> #include <media/stagefright/AMRWriter.h> #include <media/stagefright/CameraSource.h> @@ -35,7 +34,6 @@ #include <media/stagefright/OMXCodec.h> #include <media/MediaProfiles.h> #include <camera/ICamera.h> -#include <camera/Camera.h> #include <camera/CameraParameters.h> #include <surfaceflinger/Surface.h> #include <utils/Errors.h> @@ -184,22 +182,7 @@ status_t StagefrightRecorder::setCamera(const sp<ICamera> &camera) { return BAD_VALUE; } - int64_t token = IPCThreadState::self()->clearCallingIdentity(); - mFlags &= ~FLAGS_HOT_CAMERA; - mCamera = Camera::create(camera); - if (mCamera == 0) { - LOGE("Unable to connect to camera"); - IPCThreadState::self()->restoreCallingIdentity(token); - return -EBUSY; - } - - LOGV("Connected to camera"); - if (mCamera->previewEnabled()) { - LOGV("camera is hot"); - mFlags |= FLAGS_HOT_CAMERA; - } - IPCThreadState::self()->restoreCallingIdentity(token); - + mCamera = camera; return OK; } @@ -966,66 +949,7 @@ void StagefrightRecorder::clipVideoFrameWidth() { } } -/* - * Check to see whether the requested video width and height is one - * of the supported sizes. It returns true if so; otherwise, it - * returns false. - */ -bool StagefrightRecorder::isVideoSizeSupported( - const Vector<Size>& supportedSizes) const { - - LOGV("isVideoSizeSupported"); - for (size_t i = 0; i < supportedSizes.size(); ++i) { - if (mVideoWidth == supportedSizes[i].width && - mVideoHeight == supportedSizes[i].height) { - return true; - } - } - return false; -} - -/* - * If the preview and video output is separate, we only set the - * the video size, and applications should set the preview size - * to some proper value, and the recording framework will not - * change the preview size; otherwise, if the video and preview - * output is the same, we need to set the preview to be the same - * as the requested video size. - * - * On return, it also returns whether the setVideoSize() is - * supported. - */ -status_t StagefrightRecorder::setCameraVideoSize( - CameraParameters* params, - bool* isSetVideoSizeSupported) { - LOGV("setCameraVideoSize: %dx%d", mVideoWidth, mVideoHeight); - - // Check whether the requested video size is supported - Vector<Size> sizes; - params->getSupportedVideoSizes(sizes); - *isSetVideoSizeSupported = true; - if (sizes.size() == 0) { - LOGD("Camera does not support setVideoSize()"); - params->getSupportedPreviewSizes(sizes); - *isSetVideoSizeSupported = false; - } - if (!isVideoSizeSupported(sizes)) { - LOGE("Camera does not support video size (%dx%d)!", - mVideoWidth, mVideoHeight); - return BAD_VALUE; - } - - // Actually set the video size - if (isSetVideoSizeSupported) { - params->setVideoSize(mVideoWidth, mVideoHeight); - } else { - params->setPreviewSize(mVideoWidth, mVideoHeight); - } - - return OK; -} - -status_t StagefrightRecorder::setupCamera() { +status_t StagefrightRecorder::checkVideoEncoderCapabilities() { if (!mCaptureTimeLapse) { // Dont clip for time lapse capture as encoder will have enough // time to encode because of slow capture rate of time lapse. @@ -1034,67 +958,6 @@ status_t StagefrightRecorder::setupCamera() { clipVideoFrameWidth(); clipVideoFrameHeight(); } - - int64_t token = IPCThreadState::self()->clearCallingIdentity(); - if (mCamera == 0) { - mCamera = Camera::connect(mCameraId); - if (mCamera == 0) { - LOGE("Camera connection could not be established."); - return -EBUSY; - } - mFlags &= ~FLAGS_HOT_CAMERA; - mCamera->lock(); - } - - // Set the actual video recording frame size - CameraParameters params(mCamera->getParameters()); - - // dont change the preview size because time lapse may be using still camera - // as mVideoWidth, mVideoHeight may correspond to HD resolution not - // supported by the video camera. - bool isSetVideoSizeSupported = false; - if (!mCaptureTimeLapse) { - if (OK != setCameraVideoSize(¶ms, &isSetVideoSizeSupported)) { - return BAD_VALUE; - } - } - - params.setPreviewFrameRate(mFrameRate); - String8 s = params.flatten(); - if (OK != mCamera->setParameters(s)) { - LOGE("Could not change settings." - " Someone else is using camera %d?", mCameraId); - return -EBUSY; - } - CameraParameters newCameraParams(mCamera->getParameters()); - - // Check on video frame size - int frameWidth = 0, frameHeight = 0; - if (isSetVideoSizeSupported) { - newCameraParams.getVideoSize(&frameWidth, &frameHeight); - } else { - newCameraParams.getPreviewSize(&frameWidth, &frameHeight); - } - if (!mCaptureTimeLapse && - (frameWidth < 0 || frameWidth != mVideoWidth || - frameHeight < 0 || frameHeight != mVideoHeight)) { - LOGE("Failed to set the video frame size to %dx%d", - mVideoWidth, mVideoHeight); - IPCThreadState::self()->restoreCallingIdentity(token); - return UNKNOWN_ERROR; - } - - // Check on video frame rate - int frameRate = newCameraParams.getPreviewFrameRate(); - if (frameRate < 0 || (frameRate - mFrameRate) != 0) { - LOGE("Failed to set frame rate to %d fps. The actual " - "frame rate is %d", mFrameRate, frameRate); - } - - // This CHECK is good, since we just passed the lock/unlock - // check earlier by calling mCamera->setParameters(). - CHECK_EQ(OK, mCamera->setPreviewDisplay(mPreviewSurface)); - IPCThreadState::self()->restoreCallingIdentity(token); return OK; } @@ -1116,15 +979,18 @@ void StagefrightRecorder::clipVideoFrameHeight() { } status_t StagefrightRecorder::setupCameraSource(sp<CameraSource> *cameraSource) { - status_t err = setupCamera(); - if (err != OK) return err; - + Size videoSize; + videoSize.width = mVideoWidth; + videoSize.height = mVideoHeight; if (mCaptureTimeLapse) { - mCameraSourceTimeLapse = CameraSourceTimeLapse::CreateFromCamera(mCamera, - mTimeBetweenTimeLapseFrameCaptureUs, mVideoWidth, mVideoHeight, mFrameRate); + mCameraSourceTimeLapse = CameraSourceTimeLapse::CreateFromCamera( + mCamera, mCameraId, + videoSize, mFrameRate, mPreviewSurface, + mTimeBetweenTimeLapseFrameCaptureUs); *cameraSource = mCameraSourceTimeLapse; } else { - *cameraSource = CameraSource::CreateFromCamera(mCamera); + *cameraSource = CameraSource::CreateFromCamera( + mCamera, mCameraId, videoSize, mFrameRate, mPreviewSurface); } CHECK(*cameraSource != NULL); @@ -1411,19 +1277,6 @@ status_t StagefrightRecorder::stop() { mWriter.clear(); } - if (mCamera != 0) { - LOGV("Disconnect camera"); - int64_t token = IPCThreadState::self()->clearCallingIdentity(); - if ((mFlags & FLAGS_HOT_CAMERA) == 0) { - LOGV("Camera was cold when we started, stopping preview"); - mCamera->stopPreview(); - } - mCamera->unlock(); - mCamera.clear(); - IPCThreadState::self()->restoreCallingIdentity(token); - mFlags = 0; - } - if (mOutputFd >= 0) { ::close(mOutputFd); mOutputFd = -1; @@ -1490,7 +1343,6 @@ status_t StagefrightRecorder::reset() { mOutputFd = -1; mOutputFdAux = -1; - mFlags = 0; return OK; } @@ -1561,8 +1413,6 @@ status_t StagefrightRecorder::dump( result.append(buffer); snprintf(buffer, SIZE, " Camera Id: %d\n", mCameraId); result.append(buffer); - snprintf(buffer, SIZE, " Camera flags: %d\n", mFlags); - result.append(buffer); snprintf(buffer, SIZE, " Encoder: %d\n", mVideoEncoder); result.append(buffer); snprintf(buffer, SIZE, " Encoder profile: %d\n", mVideoEncoderProfile); diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h index f14c704..039bc16 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.h +++ b/media/libmediaplayerservice/StagefrightRecorder.h @@ -63,12 +63,7 @@ struct StagefrightRecorder : public MediaRecorderBase { virtual status_t dump(int fd, const Vector<String16>& args) const; private: - enum CameraFlags { - FLAGS_SET_CAMERA = 1L << 0, - FLAGS_HOT_CAMERA = 1L << 1, - }; - - sp<Camera> mCamera; + sp<ICamera> mCamera; sp<Surface> mPreviewSurface; sp<IMediaRecorderClient> mListener; sp<MediaWriter> mWriter, mWriterAux; @@ -107,7 +102,6 @@ private: String8 mParams; int mOutputFd, mOutputFdAux; - int32_t mFlags; MediaProfiles *mEncoderProfiles; @@ -125,10 +119,7 @@ private: status_t startAACRecording(); status_t startRTPRecording(); sp<MediaSource> createAudioSource(); - status_t setupCamera(); - bool isVideoSizeSupported(const Vector<Size>& supportedSizes) const; - status_t setCameraVideoSize(CameraParameters* params, - bool *isSetVideoSizeSupported); + status_t checkVideoEncoderCapabilities(); status_t setupCameraSource(sp<CameraSource> *cameraSource); status_t setupAudioEncoder(const sp<MediaWriter>& writer); status_t setupVideoEncoder( diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp index 0c9eef4..f7b76f8 100644 --- a/media/libstagefright/CameraSource.cpp +++ b/media/libstagefright/CameraSource.cpp @@ -27,6 +27,7 @@ #include <media/stagefright/MetaData.h> #include <camera/Camera.h> #include <camera/CameraParameters.h> +#include <surfaceflinger/Surface.h> #include <utils/String8.h> #include <cutils/properties.h> @@ -108,28 +109,45 @@ static int32_t getColorFormat(const char* colorFormat) { CHECK_EQ(0, "Unknown color format"); } -// static CameraSource *CameraSource::Create() { - sp<Camera> camera = Camera::connect(0); - - if (camera.get() == NULL) { - return NULL; - } + Size size; + size.width = -1; + size.height = -1; - return new CameraSource(camera); + sp<ICamera> camera; + return new CameraSource(camera, 0, size, -1, NULL); } // static -CameraSource *CameraSource::CreateFromCamera(const sp<Camera> &camera) { - if (camera.get() == NULL) { - return NULL; +CameraSource *CameraSource::CreateFromCamera( + const sp<ICamera>& camera, + int32_t cameraId, + Size videoSize, + int32_t frameRate, + const sp<Surface>& surface) { + + CameraSource *source = new CameraSource(camera, cameraId, + videoSize, frameRate, surface); + + if (source != NULL) { + if (source->initCheck() != OK) { + delete source; + return NULL; + } } - - return new CameraSource(camera); + return source; } -CameraSource::CameraSource(const sp<Camera> &camera) - : mCamera(camera), +CameraSource::CameraSource( + const sp<ICamera>& camera, + int32_t cameraId, + Size videoSize, + int32_t frameRate, + const sp<Surface>& surface) + : mCameraFlags(0), + mVideoFrameRate(-1), + mCamera(0), + mSurface(surface), mNumFramesReceived(0), mLastFrameTimestampUs(0), mStarted(false), @@ -140,39 +158,316 @@ CameraSource::CameraSource(const sp<Camera> &camera) mGlitchDurationThresholdUs(200000), mCollectStats(false) { + mVideoSize.width = -1; + mVideoSize.height = -1; + + mInitCheck = init(camera, cameraId, videoSize, frameRate); +} + +status_t CameraSource::initCheck() const { + return mInitCheck; +} + +status_t CameraSource::isCameraAvailable( + const sp<ICamera>& camera, int32_t cameraId) { + + if (camera == 0) { + mCamera = Camera::connect(cameraId); + mCameraFlags &= ~FLAGS_HOT_CAMERA; + } else { + mCamera = Camera::create(camera); + 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(); + } + return OK; +} + + +/* + * Check to see whether the requested video width and height is one + * of the supported sizes. + * @param width the video frame width in pixels + * @param height the video frame height in pixels + * @param suppportedSizes the vector of sizes that we check against + * @return true if the dimension (width and height) is supported. + */ +static bool isVideoSizeSupported( + int32_t width, int32_t height, + const Vector<Size>& supportedSizes) { + + LOGV("isVideoSizeSupported"); + for (size_t i = 0; i < supportedSizes.size(); ++i) { + if (width == supportedSizes[i].width && + height == supportedSizes[i].height) { + return true; + } + } + return false; +} + +/* + * If the preview and video output is separate, we only set the + * the video size, and applications should set the preview size + * to some proper value, and the recording framework will not + * change the preview size; otherwise, if the video and preview + * output is the same, we need to set the preview to be the same + * as the requested video size. + * + */ +/* + * Query the camera to retrieve the supported video frame sizes + * and also to see whether CameraParameters::setVideoSize() + * is supported or not. + * @param params CameraParameters to retrieve the information + * @@param isSetVideoSizeSupported retunrs whether method + * CameraParameters::setVideoSize() is supported or not. + * @param sizes returns the vector of Size objects for the + * supported video frame sizes advertised by the camera. + */ +static void getSupportedVideoSizes( + const CameraParameters& params, + bool *isSetVideoSizeSupported, + Vector<Size>& sizes) { + + *isSetVideoSizeSupported = true; + params.getSupportedVideoSizes(sizes); + if (sizes.size() == 0) { + LOGD("Camera does not support setVideoSize()"); + params.getSupportedPreviewSizes(sizes); + *isSetVideoSizeSupported = false; + } +} + +/* + * Check whether the camera has the supported color format + * @param params CameraParameters to retrieve the information + * @return OK if no error. + */ +status_t CameraSource::isCameraColorFormatSupported( + const CameraParameters& params) { + mColorFormat = getColorFormat(params.get( + CameraParameters::KEY_VIDEO_FRAME_FORMAT)); + if (mColorFormat == -1) { + return BAD_VALUE; + } + return OK; +} + +/* + * Configure the camera to use the requested video size + * (width and height) and/or frame rate. If both width and + * height are -1, configuration on the video size is skipped. + * if frameRate is -1, configuration on the frame rate + * is skipped. Skipping the configuration allows one to + * use the current camera setting without the need to + * actually know the specific values (see Create() method). + * + * @param params the CameraParameters to be configured + * @param width the target video frame width in pixels + * @param height the target video frame height in pixels + * @param frameRate the target frame rate in frames per second. + * @return OK if no error. + */ +status_t CameraSource::configureCamera( + CameraParameters* params, + int32_t width, int32_t height, + int32_t frameRate) { + + Vector<Size> sizes; + bool isSetVideoSizeSupportedByCamera = true; + getSupportedVideoSizes(*params, &isSetVideoSizeSupportedByCamera, sizes); + bool isCameraParamChanged = false; + if (width != -1 && height != -1) { + if (!isVideoSizeSupported(width, height, sizes)) { + LOGE("Video dimension (%dx%d) is unsupported", width, height); + return BAD_VALUE; + } + if (isSetVideoSizeSupportedByCamera) { + params->setVideoSize(width, height); + } else { + params->setPreviewSize(width, height); + } + isCameraParamChanged = true; + } else if ((width == -1 && height != -1) || + (width != -1 && height == -1)) { + // If one and only one of the width and height is -1 + // we reject such a request. + LOGE("Requested video size (%dx%d) is not supported", width, height); + return BAD_VALUE; + } else { // width == -1 && height == -1 + // Do not configure the camera. + // Use the current width and height value setting from the camera. + } + + if (frameRate != -1) { + params->setPreviewFrameRate(frameRate); + isCameraParamChanged = true; + } else { // frameRate == -1 + // Do not configure the camera. + // Use the current frame rate value setting from the camera + } + + if (isCameraParamChanged) { + // Either frame rate or frame size needs to be changed. + String8 s = params->flatten(); + if (OK != mCamera->setParameters(s)) { + LOGE("Could not change settings." + " Someone else is using camera %p?", mCamera.get()); + return -EBUSY; + } + } + return OK; +} + +/* + * Check whether the requested video frame size + * has been successfully configured or not. If both width and height + * are -1, check on the current width and height value setting + * is performed. + * + * @param params CameraParameters to retrieve the information + * @param the target video frame width in pixels to check against + * @param the target video frame height in pixels to check against + * @return OK if no error + */ +status_t CameraSource::checkVideoSize( + const CameraParameters& params, + int32_t width, int32_t height) { + + int32_t frameWidthActual = -1; + int32_t frameHeightActual = -1; + params.getPreviewSize(&frameWidthActual, &frameHeightActual); + if (frameWidthActual < 0 || frameHeightActual < 0) { + LOGE("Failed to retrieve video frame size (%dx%d)", + frameWidthActual, frameHeightActual); + return UNKNOWN_ERROR; + } + + // Check the actual video frame size against the target/requested + // video frame size. + if (width != -1 && height != -1) { + if (frameWidthActual != width || frameHeightActual != height) { + LOGE("Failed to set video frame size to %dx%d. " + "The actual video size is %dx%d ", width, height, + frameWidthActual, frameHeightActual); + return UNKNOWN_ERROR; + } + } + + // Good now. + mVideoSize.width = frameWidthActual; + mVideoSize.height = frameHeightActual; + return OK; +} + +/* + * Check the requested frame rate has been successfully configured or not. + * If the target frameRate is -1, check on the current frame rate value + * setting is performed. + * + * @param params CameraParameters to retrieve the information + * @param the target video frame rate to check against + * @return OK if no error. + */ +status_t CameraSource::checkFrameRate( + const CameraParameters& params, + int32_t frameRate) { + + int32_t frameRateActual = params.getPreviewFrameRate(); + if (frameRateActual < 0) { + LOGE("Failed to retrieve preview frame rate (%d)", frameRateActual); + return UNKNOWN_ERROR; + } + + // Check the actual video frame rate against the target/requested + // video frame rate. + if (frameRate != -1 && (frameRateActual - frameRate) != 0) { + LOGE("Failed to set preview frame rate to %d fps. The actual " + "frame rate is %d", frameRate, frameRateActual); + return UNKNOWN_ERROR; + } + + // Good now. + mVideoFrameRate = frameRateActual; + return OK; +} + +/* + * Initialize the CameraSource to so that it becomes + * ready for providing the video input streams as requested. + * @param camera the camera object used for the video source + * @param cameraId if camera == 0, use camera with this id + * as the video source + * @param videoSize the target video frame size. If both + * width and height in videoSize is -1, use the current + * width and heigth settings by the camera + * @param frameRate the target frame rate in frames per second. + * if it is -1, use the current camera frame rate setting. + * @return OK if no error. + */ +status_t CameraSource::init( + const sp<ICamera>& camera, + int32_t cameraId, + Size videoSize, + int32_t frameRate) { + + status_t err = OK; int64_t token = IPCThreadState::self()->clearCallingIdentity(); - String8 s = mCamera->getParameters(); - IPCThreadState::self()->restoreCallingIdentity(token); - printf("params: \"%s\"\n", s.string()); + if ((err = isCameraAvailable(camera, cameraId)) != OK) { + return err; + } + CameraParameters params(mCamera->getParameters()); + if ((err = isCameraColorFormatSupported(params)) != OK) { + return err; + } - int32_t width, height, stride, sliceHeight; - CameraParameters params(s); - params.getPreviewSize(&width, &height); + // Set the camera to use the requested video frame size + // and/or frame rate. + if ((err = configureCamera(¶ms, + videoSize.width, videoSize.height, + frameRate))) { + return err; + } - // Calculate glitch duraton threshold based on frame rate - int32_t frameRate = params.getPreviewFrameRate(); - int64_t glitchDurationUs = (1000000LL / frameRate); + // Check on video frame size and frame rate. + CameraParameters newCameraParams(mCamera->getParameters()); + if ((err = checkVideoSize(newCameraParams, + videoSize.width, videoSize.height)) != OK) { + return err; + } + if ((err = checkFrameRate(newCameraParams, frameRate)) != OK) { + return err; + } + + // This CHECK is good, since we just passed the lock/unlock + // check earlier by calling mCamera->setParameters(). + CHECK_EQ(OK, mCamera->setPreviewDisplay(mSurface)); + IPCThreadState::self()->restoreCallingIdentity(token); + + int64_t glitchDurationUs = (1000000LL / mVideoFrameRate); if (glitchDurationUs > mGlitchDurationThresholdUs) { mGlitchDurationThresholdUs = glitchDurationUs; } - const char *colorFormatStr = params.get(CameraParameters::KEY_VIDEO_FRAME_FORMAT); - CHECK(colorFormatStr != NULL); - int32_t colorFormat = getColorFormat(colorFormatStr); - // XXX: query camera for the stride and slice height // when the capability becomes available. - stride = width; - sliceHeight = height; - mMeta = new MetaData; - mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW); - mMeta->setInt32(kKeyColorFormat, colorFormat); - mMeta->setInt32(kKeyWidth, width); - mMeta->setInt32(kKeyHeight, height); - mMeta->setInt32(kKeyStride, stride); - mMeta->setInt32(kKeySliceHeight, sliceHeight); + mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW); + mMeta->setInt32(kKeyColorFormat, mColorFormat); + mMeta->setInt32(kKeyWidth, mVideoSize.width); + mMeta->setInt32(kKeyHeight, mVideoSize.height); + mMeta->setInt32(kKeyStride, mVideoSize.width); + mMeta->setInt32(kKeySliceHeight, mVideoSize.height); + return OK; } CameraSource::~CameraSource() { @@ -187,6 +482,10 @@ void CameraSource::startCameraRecording() { status_t CameraSource::start(MetaData *meta) { CHECK(!mStarted); + if (mInitCheck != OK) { + LOGE("CameraSource is not initialized yet"); + return mInitCheck; + } char value[PROPERTY_VALUE_MAX]; if (property_get("media.stagefright.record-stats", value, NULL) @@ -228,7 +527,16 @@ status_t CameraSource::stop() { mFramesBeingEncoded.size()); mFrameCompleteCondition.wait(mLock); } - mCamera = NULL; + + LOGV("Disconnect camera"); + if ((mCameraFlags & FLAGS_HOT_CAMERA) == 0) { + LOGV("Camera was cold when we started, stopping preview"); + mCamera->stopPreview(); + } + mCamera->unlock(); + mCamera.clear(); + mCamera = 0; + mCameraFlags = 0; IPCThreadState::self()->restoreCallingIdentity(token); if (mCollectStats) { diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp index c1bc433..2f3f20b 100644 --- a/media/libstagefright/CameraSourceTimeLapse.cpp +++ b/media/libstagefright/CameraSourceTimeLapse.cpp @@ -37,57 +37,55 @@ namespace android { // static -CameraSourceTimeLapse *CameraSourceTimeLapse::Create( - int64_t timeBetweenTimeLapseFrameCaptureUs, - int32_t width, int32_t height, - int32_t videoFrameRate) { - sp<Camera> camera = Camera::connect(0); - - if (camera.get() == NULL) { - return NULL; - } - - return new CameraSourceTimeLapse(camera, timeBetweenTimeLapseFrameCaptureUs, - width, height, videoFrameRate); -} - -// static -CameraSourceTimeLapse *CameraSourceTimeLapse::CreateFromCamera(const sp<Camera> &camera, - int64_t timeBetweenTimeLapseFrameCaptureUs, - int32_t width, int32_t height, - int32_t videoFrameRate) { - if (camera.get() == NULL) { - return NULL; +CameraSourceTimeLapse *CameraSourceTimeLapse::CreateFromCamera( + const sp<ICamera> &camera, + int32_t cameraId, + Size videoSize, + int32_t videoFrameRate, + const sp<Surface>& surface, + int64_t timeBetweenTimeLapseFrameCaptureUs) { + + CameraSourceTimeLapse *source = new + CameraSourceTimeLapse(camera, cameraId, + videoSize, videoFrameRate, surface, + timeBetweenTimeLapseFrameCaptureUs); + + if (source != NULL) { + if (source->initCheck() != OK) { + delete source; + return NULL; + } } - - return new CameraSourceTimeLapse(camera, timeBetweenTimeLapseFrameCaptureUs, - width, height, videoFrameRate); + return source; } -CameraSourceTimeLapse::CameraSourceTimeLapse(const sp<Camera> &camera, - int64_t timeBetweenTimeLapseFrameCaptureUs, - int32_t width, int32_t height, - int32_t videoFrameRate) - : CameraSource(camera), +CameraSourceTimeLapse::CameraSourceTimeLapse( + const sp<ICamera>& camera, + int32_t cameraId, + Size videoSize, + int32_t videoFrameRate, + const sp<Surface>& surface, + int64_t timeBetweenTimeLapseFrameCaptureUs) + : CameraSource(camera, cameraId, videoSize, videoFrameRate, surface), mTimeBetweenTimeLapseFrameCaptureUs(timeBetweenTimeLapseFrameCaptureUs), mTimeBetweenTimeLapseVideoFramesUs(1E6/videoFrameRate), mLastTimeLapseFrameRealTimestampUs(0), mSkipCurrentFrame(false) { LOGV("starting time lapse mode"); - mVideoWidth = width; - mVideoHeight = height; + mVideoWidth = videoSize.width; + mVideoHeight = videoSize.height; - if (trySettingPreviewSize(width, height)) { + if (trySettingPreviewSize(videoSize.width, videoSize.height)) { mUseStillCameraForTimeLapse = false; } else { // TODO: Add a check to see that mTimeBetweenTimeLapseFrameCaptureUs is greater // than the fastest rate at which the still camera can take pictures. mUseStillCameraForTimeLapse = true; - CHECK(setPictureSizeToClosestSupported(width, height)); + CHECK(setPictureSizeToClosestSupported(videoSize.width, videoSize.height)); mNeedCropping = computeCropRectangleOffset(); - mMeta->setInt32(kKeyWidth, width); - mMeta->setInt32(kKeyHeight, height); + mMeta->setInt32(kKeyWidth, videoSize.width); + mMeta->setInt32(kKeyHeight, videoSize.height); } // Initialize quick stop variables. |