Merge "Move Camera specific logic out from StagefrightRecorder to CameraSource"
This commit is contained in:
@@ -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 &);
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
Size size;
|
||||
size.width = -1;
|
||||
size.height = -1;
|
||||
|
||||
if (camera.get() == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
return new CameraSource(camera);
|
||||
CameraSource *source = new CameraSource(camera, cameraId,
|
||||
videoSize, frameRate, surface);
|
||||
|
||||
if (source != NULL) {
|
||||
if (source->initCheck() != OK) {
|
||||
delete source;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
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();
|
||||
|
||||
if ((err = isCameraAvailable(camera, cameraId)) != OK) {
|
||||
return err;
|
||||
}
|
||||
CameraParameters params(mCamera->getParameters());
|
||||
if ((err = isCameraColorFormatSupported(params)) != OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
printf("params: \"%s\"\n", s.string());
|
||||
|
||||
int32_t width, height, stride, sliceHeight;
|
||||
CameraParameters params(s);
|
||||
params.getPreviewSize(&width, &height);
|
||||
|
||||
// Calculate glitch duraton threshold based on frame rate
|
||||
int32_t frameRate = params.getPreviewFrameRate();
|
||||
int64_t glitchDurationUs = (1000000LL / frameRate);
|
||||
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) {
|
||||
|
||||
@@ -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);
|
||||
CameraSourceTimeLapse *CameraSourceTimeLapse::CreateFromCamera(
|
||||
const sp<ICamera> &camera,
|
||||
int32_t cameraId,
|
||||
Size videoSize,
|
||||
int32_t videoFrameRate,
|
||||
const sp<Surface>& surface,
|
||||
int64_t timeBetweenTimeLapseFrameCaptureUs) {
|
||||
|
||||
if (camera.get() == NULL) {
|
||||
return NULL;
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
return new CameraSourceTimeLapse(camera, timeBetweenTimeLapseFrameCaptureUs,
|
||||
width, height, videoFrameRate);
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
Reference in New Issue
Block a user