diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp index 00bd54eb59758..53c77da1e1b72 100644 --- a/camera/libcameraservice/CameraService.cpp +++ b/camera/libcameraservice/CameraService.cpp @@ -16,6 +16,7 @@ ** limitations under the License. */ +//#define LOG_NDEBUG 0 #define LOG_TAG "CameraService" #include @@ -247,7 +248,7 @@ CameraService::Client::Client(const sp& cameraService, status_t CameraService::Client::checkPid() { int callingPid = getCallingPid(); - if (mClientPid == callingPid) return NO_ERROR; + if (mClientPid == callingPid || callingPid == getpid()) return NO_ERROR; LOGW("Attempt to use locked camera (client %p) from different process " " (old pid %d, new pid %d)", getCameraClient()->asBinder().get(), mClientPid, callingPid); diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h index ea435de82719e..5f9d98270c1d2 100644 --- a/include/media/stagefright/CameraSource.h +++ b/include/media/stagefright/CameraSource.h @@ -34,7 +34,7 @@ class Camera; class CameraSource : public MediaSource { public: static CameraSource *Create(); - static CameraSource *CreateFromICamera(const sp &icamera); + static CameraSource *CreateFromCamera(const sp &camera); virtual ~CameraSource(); @@ -61,12 +61,17 @@ private: int mWidth, mHeight; int64_t mFirstFrameTimeUs; + int64_t mLastFrameTimestampUs; int32_t mNumFrames; + int32_t mNumFramesReleased; bool mStarted; CameraSource(const sp &camera); - void dataCallback(int32_t msgType, const sp &data); + void dataCallbackTimestamp( + int64_t timestampUs, int32_t msgType, const sp &data); + + void releaseQueuedFrames(); CameraSource(const CameraSource &); CameraSource &operator=(const CameraSource &); diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk index cf97b2344ebaf..3b678cbe991e1 100644 --- a/media/libmediaplayerservice/Android.mk +++ b/media/libmediaplayerservice/Android.mk @@ -37,6 +37,7 @@ LOCAL_SHARED_LIBRARIES := \ libvorbisidec \ libsonivox \ libmedia \ + libcamera_client \ libandroid_runtime \ libstagefright \ libstagefright_omx \ diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index 531fd11730689..a63d94bbe66c3 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -20,6 +20,7 @@ #include "StagefrightRecorder.h" +#include #include #include #include @@ -30,8 +31,11 @@ #include #include #include +#include #include #include +#include +#include namespace android { @@ -96,7 +100,25 @@ status_t StagefrightRecorder::setVideoFrameRate(int frames_per_second) { } status_t StagefrightRecorder::setCamera(const sp &camera) { - mCamera = camera; + LOGV("setCamera: pid %d pid %d", IPCThreadState::self()->getCallingPid(), getpid()); + if (camera == 0) { + LOGE("camera is NULL"); + return UNKNOWN_ERROR; + } + + mFlags &= ~ FLAGS_SET_CAMERA | FLAGS_HOT_CAMERA; + mCamera = Camera::create(camera); + if (mCamera == 0) { + LOGE("Unable to connect to camera"); + return UNKNOWN_ERROR; + } + + LOGV("Connected to camera"); + mFlags |= FLAGS_SET_CAMERA; + if (mCamera->previewEnabled()) { + LOGV("camera is hot"); + mFlags |= FLAGS_HOT_CAMERA; + } return OK; } @@ -240,7 +262,7 @@ status_t StagefrightRecorder::startMPEG4Recording() { CHECK(mCamera != NULL); sp cameraSource = - CameraSource::CreateFromICamera(mCamera); + CameraSource::CreateFromCamera(mCamera); CHECK(cameraSource != NULL); @@ -314,6 +336,17 @@ status_t StagefrightRecorder::stop() { status_t StagefrightRecorder::close() { stop(); + if (mCamera != 0) { + if ((mFlags & FLAGS_HOT_CAMERA) == 0) { + LOGV("Camera was cold when we started, stopping preview"); + mCamera->stopPreview(); + } + if (mFlags & FLAGS_SET_CAMERA) { + LOGV("Unlocking camera"); + mCamera->unlock(); + } + mFlags = 0; + } return OK; } @@ -329,6 +362,7 @@ status_t StagefrightRecorder::reset() { mVideoHeight = -1; mFrameRate = -1; mOutputFd = -1; + mFlags = 0; return OK; } diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h index 7ec412dce3d4f..2f2f74857d430 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.h +++ b/media/libmediaplayerservice/StagefrightRecorder.h @@ -23,6 +23,7 @@ namespace android { +class Camera; struct MediaSource; struct MediaWriter; @@ -52,7 +53,12 @@ struct StagefrightRecorder : public MediaRecorderBase { virtual status_t getMaxAmplitude(int *max); private: - sp mCamera; + enum CameraFlags { + FLAGS_SET_CAMERA = 1L << 0, + FLAGS_HOT_CAMERA = 1L << 1, + }; + + sp mCamera; sp mPreviewSurface; sp mListener; sp mWriter; @@ -66,6 +72,7 @@ private: int mFrameRate; String8 mParams; int mOutputFd; + int32_t mFlags; status_t startMPEG4Recording(); status_t startAMRRecording(); diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp index f57ddc1f48a93..b07bd0e360a4f 100644 --- a/media/libstagefright/CameraSource.cpp +++ b/media/libstagefright/CameraSource.cpp @@ -14,12 +14,12 @@ * limitations under the License. */ -#include +//#define LOG_NDEBUG 0 +#define LOG_TAG "CameraSource" +#include #include -#include -#include // for property_get #include #include #include @@ -34,13 +34,6 @@ namespace android { -static int64_t getNowUs() { - struct timeval tv; - gettimeofday(&tv, NULL); - - return (int64_t)tv.tv_usec + tv.tv_sec * 1000000; -} - struct DummySurface : public BnSurface { DummySurface() {} @@ -100,17 +93,15 @@ void CameraSourceListener::notify(int32_t msgType, int32_t ext1, int32_t ext2) { void CameraSourceListener::postData(int32_t msgType, const sp &dataPtr) { LOGV("postData(%d, ptr:%p, size:%d)", msgType, dataPtr->pointer(), dataPtr->size()); - - sp source = mSource.promote(); - if (source.get() != NULL) { - source->dataCallback(msgType, dataPtr); - } } void CameraSourceListener::postDataTimestamp( nsecs_t timestamp, int32_t msgType, const sp& dataPtr) { - LOGV("postDataTimestamp(%lld, %d, ptr:%p, size:%d)", - timestamp, msgType, dataPtr->pointer(), dataPtr->size()); + + sp source = mSource.promote(); + if (source.get() != NULL) { + source->dataCallbackTimestamp(timestamp/1000, msgType, dataPtr); + } } // static @@ -125,9 +116,7 @@ CameraSource *CameraSource::Create() { } // static -CameraSource *CameraSource::CreateFromICamera(const sp &icamera) { - sp camera = Camera::create(icamera); - +CameraSource *CameraSource::CreateFromCamera(const sp &camera) { if (camera.get() == NULL) { return NULL; } @@ -140,7 +129,9 @@ CameraSource::CameraSource(const sp &camera) mWidth(0), mHeight(0), mFirstFrameTimeUs(0), + mLastFrameTimestampUs(0), mNumFrames(0), + mNumFramesReleased(0), mStarted(false) { String8 s = mCamera->getParameters(); printf("params: \"%s\"\n", s.string()); @@ -160,6 +151,7 @@ void CameraSource::setPreviewSurface(const sp &surface) { } status_t CameraSource::start(MetaData *) { + LOGV("start"); CHECK(!mStarted); mCamera->setListener(new CameraSourceListener(this)); @@ -169,11 +161,7 @@ status_t CameraSource::start(MetaData *) { mPreviewSurface != NULL ? mPreviewSurface : new DummySurface); CHECK_EQ(err, OK); - mCamera->setPreviewCallbackFlags( - FRAME_CALLBACK_FLAG_ENABLE_MASK - | FRAME_CALLBACK_FLAG_COPY_OUT_MASK); - - err = mCamera->startPreview(); + err = mCamera->startRecording(); CHECK_EQ(err, OK); mStarted = true; @@ -182,15 +170,30 @@ status_t CameraSource::start(MetaData *) { } status_t CameraSource::stop() { - CHECK(mStarted); - - mCamera->stopPreview(); - + LOGV("stop"); + Mutex::Autolock autoLock(mLock); mStarted = false; + mFrameAvailableCondition.signal(); + mCamera->setListener(NULL); + mCamera->stopRecording(); + releaseQueuedFrames(); + LOGI("Frames received/released: %d/%d, timestamp (us) last/first: %lld/%lld", + mNumFrames, mNumFramesReleased, + mLastFrameTimestampUs, mFirstFrameTimeUs); return OK; } +void CameraSource::releaseQueuedFrames() { + List >::iterator it; + while (!mFrames.empty()) { + it = mFrames.begin(); + mCamera->releaseRecordingFrame(*it); + mFrames.erase(it); + ++mNumFramesReleased; + } +} + sp CameraSource::getFormat() { sp meta = new MetaData; meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW); @@ -203,7 +206,7 @@ sp CameraSource::getFormat() { status_t CameraSource::read( MediaBuffer **buffer, const ReadOptions *options) { - CHECK(mStarted); + LOGV("read"); *buffer = NULL; @@ -217,20 +220,24 @@ status_t CameraSource::read( { Mutex::Autolock autoLock(mLock); - while (mFrames.empty()) { + while (mStarted && mFrames.empty()) { mFrameAvailableCondition.wait(mLock); } - + if (!mStarted) { + return OK; + } frame = *mFrames.begin(); mFrames.erase(mFrames.begin()); frameTime = *mFrameTimes.begin(); mFrameTimes.erase(mFrameTimes.begin()); + ++mNumFramesReleased; } *buffer = new MediaBuffer(frame->size()); memcpy((*buffer)->data(), frame->pointer(), frame->size()); (*buffer)->set_range(0, frame->size()); + mCamera->releaseRecordingFrame(frame); (*buffer)->meta_data()->clear(); (*buffer)->meta_data()->setInt64(kKeyTime, frameTime); @@ -238,17 +245,25 @@ status_t CameraSource::read( return OK; } -void CameraSource::dataCallback(int32_t msgType, const sp &data) { +void CameraSource::dataCallbackTimestamp(int64_t timestampUs, + int32_t msgType, const sp &data) { + LOGV("dataCallbackTimestamp: timestamp %lld us", timestampUs); + mLastFrameTimestampUs = timestampUs; Mutex::Autolock autoLock(mLock); + if (!mStarted) { + mCamera->releaseRecordingFrame(data); + ++mNumFrames; + ++mNumFramesReleased; + return; + } - int64_t nowUs = getNowUs(); if (mNumFrames == 0) { - mFirstFrameTimeUs = nowUs; + mFirstFrameTimeUs = timestampUs; } ++mNumFrames; mFrames.push_back(data); - mFrameTimes.push_back(nowUs - mFirstFrameTimeUs); + mFrameTimes.push_back(timestampUs - mFirstFrameTimeUs); mFrameAvailableCondition.signal(); } diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 9cdf96e9375a4..41be9ac4446c3 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -711,21 +711,46 @@ void OMXCodec::setVideoInputFormat( colorFormat = OMX_COLOR_FormatYUV420Planar; } + + + status_t err; + OMX_PARAM_PORTDEFINITIONTYPE def; + OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video; + + //////////////////////// Input port ///////////////////////// CHECK_EQ(setVideoPortFormatType( kPortIndexInput, OMX_VIDEO_CodingUnused, colorFormat), OK); + InitOMXParams(&def); + def.nPortIndex = kPortIndexInput; + err = mOMX->getParameter( + mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); + CHECK_EQ(err, OK); + + def.nBufferSize = getFrameSize(colorFormat, width, height); + + CHECK_EQ(def.eDomain, OMX_PortDomainVideo); + + video_def->nFrameWidth = width; + video_def->nFrameHeight = height; + video_def->eCompressionFormat = OMX_VIDEO_CodingUnused; + video_def->eColorFormat = colorFormat; + + video_def->xFramerate = (24 << 16); // Q16 format + + err = mOMX->setParameter( + mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); + CHECK_EQ(err, OK); + + //////////////////////// Output port ///////////////////////// CHECK_EQ(setVideoPortFormatType( kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused), OK); - - OMX_PARAM_PORTDEFINITIONTYPE def; InitOMXParams(&def); def.nPortIndex = kPortIndexOutput; - OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video; - - status_t err = mOMX->getParameter( + err = mOMX->getParameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); CHECK_EQ(err, OK); @@ -741,39 +766,7 @@ void OMXCodec::setVideoInputFormat( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); CHECK_EQ(err, OK); - //////////////////////////////////////////////////////////////////////////// - - InitOMXParams(&def); - def.nPortIndex = kPortIndexInput; - - err = mOMX->getParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - CHECK_EQ(err, OK); - - def.nBufferSize = getFrameSize(colorFormat, width, height); - CODEC_LOGV("Setting nBufferSize = %ld", def.nBufferSize); - - CHECK_EQ(def.eDomain, OMX_PortDomainVideo); - - video_def->nFrameWidth = width; - video_def->nFrameHeight = height; - video_def->eCompressionFormat = OMX_VIDEO_CodingUnused; - video_def->eColorFormat = colorFormat; - - video_def->xFramerate = 24 << 16; // XXX crucial! - - err = mOMX->setParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - CHECK_EQ(err, OK); - - err = mOMX->getParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - CHECK_EQ(err, OK); - - err = mOMX->setParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - CHECK_EQ(err, OK); - + /////////////////// Codec-specific //////////////////////// switch (compressionFormat) { case OMX_VIDEO_CodingMPEG4: {