Merge "Use timestamp from camera driver for CameraSource" into kraken

This commit is contained in:
James Dong
2010-04-28 12:03:55 -07:00
committed by Android (Google) Code Review
7 changed files with 136 additions and 80 deletions

View File

@@ -16,6 +16,7 @@
** limitations under the License. ** limitations under the License.
*/ */
//#define LOG_NDEBUG 0
#define LOG_TAG "CameraService" #define LOG_TAG "CameraService"
#include <utils/Log.h> #include <utils/Log.h>
@@ -247,7 +248,7 @@ CameraService::Client::Client(const sp<CameraService>& cameraService,
status_t CameraService::Client::checkPid() status_t CameraService::Client::checkPid()
{ {
int callingPid = getCallingPid(); 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 " LOGW("Attempt to use locked camera (client %p) from different process "
" (old pid %d, new pid %d)", " (old pid %d, new pid %d)",
getCameraClient()->asBinder().get(), mClientPid, callingPid); getCameraClient()->asBinder().get(), mClientPid, callingPid);

View File

@@ -34,7 +34,7 @@ class Camera;
class CameraSource : public MediaSource { class CameraSource : public MediaSource {
public: public:
static CameraSource *Create(); static CameraSource *Create();
static CameraSource *CreateFromICamera(const sp<ICamera> &icamera); static CameraSource *CreateFromCamera(const sp<Camera> &camera);
virtual ~CameraSource(); virtual ~CameraSource();
@@ -61,12 +61,17 @@ private:
int mWidth, mHeight; int mWidth, mHeight;
int64_t mFirstFrameTimeUs; int64_t mFirstFrameTimeUs;
int64_t mLastFrameTimestampUs;
int32_t mNumFrames; int32_t mNumFrames;
int32_t mNumFramesReleased;
bool mStarted; bool mStarted;
CameraSource(const sp<Camera> &camera); CameraSource(const sp<Camera> &camera);
void dataCallback(int32_t msgType, const sp<IMemory> &data); void dataCallbackTimestamp(
int64_t timestampUs, int32_t msgType, const sp<IMemory> &data);
void releaseQueuedFrames();
CameraSource(const CameraSource &); CameraSource(const CameraSource &);
CameraSource &operator=(const CameraSource &); CameraSource &operator=(const CameraSource &);

View File

@@ -37,6 +37,7 @@ LOCAL_SHARED_LIBRARIES := \
libvorbisidec \ libvorbisidec \
libsonivox \ libsonivox \
libmedia \ libmedia \
libcamera_client \
libandroid_runtime \ libandroid_runtime \
libstagefright \ libstagefright \
libstagefright_omx \ libstagefright_omx \

View File

@@ -20,6 +20,7 @@
#include "StagefrightRecorder.h" #include "StagefrightRecorder.h"
#include <binder/IPCThreadState.h>
#include <media/stagefright/AudioSource.h> #include <media/stagefright/AudioSource.h>
#include <media/stagefright/AMRWriter.h> #include <media/stagefright/AMRWriter.h>
#include <media/stagefright/CameraSource.h> #include <media/stagefright/CameraSource.h>
@@ -30,8 +31,11 @@
#include <media/stagefright/OMXClient.h> #include <media/stagefright/OMXClient.h>
#include <media/stagefright/OMXCodec.h> #include <media/stagefright/OMXCodec.h>
#include <camera/ICamera.h> #include <camera/ICamera.h>
#include <camera/Camera.h>
#include <surfaceflinger/ISurface.h> #include <surfaceflinger/ISurface.h>
#include <utils/Errors.h> #include <utils/Errors.h>
#include <sys/types.h>
#include <unistd.h>
namespace android { namespace android {
@@ -96,7 +100,25 @@ status_t StagefrightRecorder::setVideoFrameRate(int frames_per_second) {
} }
status_t StagefrightRecorder::setCamera(const sp<ICamera> &camera) { status_t StagefrightRecorder::setCamera(const sp<ICamera> &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; return OK;
} }
@@ -240,7 +262,7 @@ status_t StagefrightRecorder::startMPEG4Recording() {
CHECK(mCamera != NULL); CHECK(mCamera != NULL);
sp<CameraSource> cameraSource = sp<CameraSource> cameraSource =
CameraSource::CreateFromICamera(mCamera); CameraSource::CreateFromCamera(mCamera);
CHECK(cameraSource != NULL); CHECK(cameraSource != NULL);
@@ -314,6 +336,17 @@ status_t StagefrightRecorder::stop() {
status_t StagefrightRecorder::close() { status_t StagefrightRecorder::close() {
stop(); 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; return OK;
} }
@@ -329,6 +362,7 @@ status_t StagefrightRecorder::reset() {
mVideoHeight = -1; mVideoHeight = -1;
mFrameRate = -1; mFrameRate = -1;
mOutputFd = -1; mOutputFd = -1;
mFlags = 0;
return OK; return OK;
} }

View File

@@ -23,6 +23,7 @@
namespace android { namespace android {
class Camera;
struct MediaSource; struct MediaSource;
struct MediaWriter; struct MediaWriter;
@@ -52,7 +53,12 @@ struct StagefrightRecorder : public MediaRecorderBase {
virtual status_t getMaxAmplitude(int *max); virtual status_t getMaxAmplitude(int *max);
private: private:
sp<ICamera> mCamera; enum CameraFlags {
FLAGS_SET_CAMERA = 1L << 0,
FLAGS_HOT_CAMERA = 1L << 1,
};
sp<Camera> mCamera;
sp<ISurface> mPreviewSurface; sp<ISurface> mPreviewSurface;
sp<IMediaPlayerClient> mListener; sp<IMediaPlayerClient> mListener;
sp<MediaWriter> mWriter; sp<MediaWriter> mWriter;
@@ -66,6 +72,7 @@ private:
int mFrameRate; int mFrameRate;
String8 mParams; String8 mParams;
int mOutputFd; int mOutputFd;
int32_t mFlags;
status_t startMPEG4Recording(); status_t startMPEG4Recording();
status_t startAMRRecording(); status_t startAMRRecording();

View File

@@ -14,12 +14,12 @@
* limitations under the License. * limitations under the License.
*/ */
#include <sys/time.h> //#define LOG_NDEBUG 0
#define LOG_TAG "CameraSource"
#include <utils/Log.h>
#include <OMX_Component.h> #include <OMX_Component.h>
#include <binder/IServiceManager.h>
#include <cutils/properties.h> // for property_get
#include <media/stagefright/CameraSource.h> #include <media/stagefright/CameraSource.h>
#include <media/stagefright/MediaDebug.h> #include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h> #include <media/stagefright/MediaDefs.h>
@@ -34,13 +34,6 @@
namespace android { 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 { struct DummySurface : public BnSurface {
DummySurface() {} 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<IMemory> &dataPtr) { void CameraSourceListener::postData(int32_t msgType, const sp<IMemory> &dataPtr) {
LOGV("postData(%d, ptr:%p, size:%d)", LOGV("postData(%d, ptr:%p, size:%d)",
msgType, dataPtr->pointer(), dataPtr->size()); msgType, dataPtr->pointer(), dataPtr->size());
sp<CameraSource> source = mSource.promote();
if (source.get() != NULL) {
source->dataCallback(msgType, dataPtr);
}
} }
void CameraSourceListener::postDataTimestamp( void CameraSourceListener::postDataTimestamp(
nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) { nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) {
LOGV("postDataTimestamp(%lld, %d, ptr:%p, size:%d)",
timestamp, msgType, dataPtr->pointer(), dataPtr->size()); sp<CameraSource> source = mSource.promote();
if (source.get() != NULL) {
source->dataCallbackTimestamp(timestamp/1000, msgType, dataPtr);
}
} }
// static // static
@@ -125,9 +116,7 @@ CameraSource *CameraSource::Create() {
} }
// static // static
CameraSource *CameraSource::CreateFromICamera(const sp<ICamera> &icamera) { CameraSource *CameraSource::CreateFromCamera(const sp<Camera> &camera) {
sp<Camera> camera = Camera::create(icamera);
if (camera.get() == NULL) { if (camera.get() == NULL) {
return NULL; return NULL;
} }
@@ -140,7 +129,9 @@ CameraSource::CameraSource(const sp<Camera> &camera)
mWidth(0), mWidth(0),
mHeight(0), mHeight(0),
mFirstFrameTimeUs(0), mFirstFrameTimeUs(0),
mLastFrameTimestampUs(0),
mNumFrames(0), mNumFrames(0),
mNumFramesReleased(0),
mStarted(false) { mStarted(false) {
String8 s = mCamera->getParameters(); String8 s = mCamera->getParameters();
printf("params: \"%s\"\n", s.string()); printf("params: \"%s\"\n", s.string());
@@ -160,6 +151,7 @@ void CameraSource::setPreviewSurface(const sp<ISurface> &surface) {
} }
status_t CameraSource::start(MetaData *) { status_t CameraSource::start(MetaData *) {
LOGV("start");
CHECK(!mStarted); CHECK(!mStarted);
mCamera->setListener(new CameraSourceListener(this)); mCamera->setListener(new CameraSourceListener(this));
@@ -169,11 +161,7 @@ status_t CameraSource::start(MetaData *) {
mPreviewSurface != NULL ? mPreviewSurface : new DummySurface); mPreviewSurface != NULL ? mPreviewSurface : new DummySurface);
CHECK_EQ(err, OK); CHECK_EQ(err, OK);
mCamera->setPreviewCallbackFlags( err = mCamera->startRecording();
FRAME_CALLBACK_FLAG_ENABLE_MASK
| FRAME_CALLBACK_FLAG_COPY_OUT_MASK);
err = mCamera->startPreview();
CHECK_EQ(err, OK); CHECK_EQ(err, OK);
mStarted = true; mStarted = true;
@@ -182,15 +170,30 @@ status_t CameraSource::start(MetaData *) {
} }
status_t CameraSource::stop() { status_t CameraSource::stop() {
CHECK(mStarted); LOGV("stop");
Mutex::Autolock autoLock(mLock);
mCamera->stopPreview();
mStarted = false; 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; return OK;
} }
void CameraSource::releaseQueuedFrames() {
List<sp<IMemory> >::iterator it;
while (!mFrames.empty()) {
it = mFrames.begin();
mCamera->releaseRecordingFrame(*it);
mFrames.erase(it);
++mNumFramesReleased;
}
}
sp<MetaData> CameraSource::getFormat() { sp<MetaData> CameraSource::getFormat() {
sp<MetaData> meta = new MetaData; sp<MetaData> meta = new MetaData;
meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW); meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
@@ -203,7 +206,7 @@ sp<MetaData> CameraSource::getFormat() {
status_t CameraSource::read( status_t CameraSource::read(
MediaBuffer **buffer, const ReadOptions *options) { MediaBuffer **buffer, const ReadOptions *options) {
CHECK(mStarted); LOGV("read");
*buffer = NULL; *buffer = NULL;
@@ -217,20 +220,24 @@ status_t CameraSource::read(
{ {
Mutex::Autolock autoLock(mLock); Mutex::Autolock autoLock(mLock);
while (mFrames.empty()) { while (mStarted && mFrames.empty()) {
mFrameAvailableCondition.wait(mLock); mFrameAvailableCondition.wait(mLock);
} }
if (!mStarted) {
return OK;
}
frame = *mFrames.begin(); frame = *mFrames.begin();
mFrames.erase(mFrames.begin()); mFrames.erase(mFrames.begin());
frameTime = *mFrameTimes.begin(); frameTime = *mFrameTimes.begin();
mFrameTimes.erase(mFrameTimes.begin()); mFrameTimes.erase(mFrameTimes.begin());
++mNumFramesReleased;
} }
*buffer = new MediaBuffer(frame->size()); *buffer = new MediaBuffer(frame->size());
memcpy((*buffer)->data(), frame->pointer(), frame->size()); memcpy((*buffer)->data(), frame->pointer(), frame->size());
(*buffer)->set_range(0, frame->size()); (*buffer)->set_range(0, frame->size());
mCamera->releaseRecordingFrame(frame);
(*buffer)->meta_data()->clear(); (*buffer)->meta_data()->clear();
(*buffer)->meta_data()->setInt64(kKeyTime, frameTime); (*buffer)->meta_data()->setInt64(kKeyTime, frameTime);
@@ -238,17 +245,25 @@ status_t CameraSource::read(
return OK; return OK;
} }
void CameraSource::dataCallback(int32_t msgType, const sp<IMemory> &data) { void CameraSource::dataCallbackTimestamp(int64_t timestampUs,
int32_t msgType, const sp<IMemory> &data) {
LOGV("dataCallbackTimestamp: timestamp %lld us", timestampUs);
mLastFrameTimestampUs = timestampUs;
Mutex::Autolock autoLock(mLock); Mutex::Autolock autoLock(mLock);
if (!mStarted) {
mCamera->releaseRecordingFrame(data);
++mNumFrames;
++mNumFramesReleased;
return;
}
int64_t nowUs = getNowUs();
if (mNumFrames == 0) { if (mNumFrames == 0) {
mFirstFrameTimeUs = nowUs; mFirstFrameTimeUs = timestampUs;
} }
++mNumFrames; ++mNumFrames;
mFrames.push_back(data); mFrames.push_back(data);
mFrameTimes.push_back(nowUs - mFirstFrameTimeUs); mFrameTimes.push_back(timestampUs - mFirstFrameTimeUs);
mFrameAvailableCondition.signal(); mFrameAvailableCondition.signal();
} }

View File

@@ -711,21 +711,46 @@ void OMXCodec::setVideoInputFormat(
colorFormat = OMX_COLOR_FormatYUV420Planar; colorFormat = OMX_COLOR_FormatYUV420Planar;
} }
status_t err;
OMX_PARAM_PORTDEFINITIONTYPE def;
OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
//////////////////////// Input port /////////////////////////
CHECK_EQ(setVideoPortFormatType( CHECK_EQ(setVideoPortFormatType(
kPortIndexInput, OMX_VIDEO_CodingUnused, kPortIndexInput, OMX_VIDEO_CodingUnused,
colorFormat), OK); 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( CHECK_EQ(setVideoPortFormatType(
kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused), kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused),
OK); OK);
OMX_PARAM_PORTDEFINITIONTYPE def;
InitOMXParams(&def); InitOMXParams(&def);
def.nPortIndex = kPortIndexOutput; def.nPortIndex = kPortIndexOutput;
OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video; err = mOMX->getParameter(
status_t err = mOMX->getParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
CHECK_EQ(err, OK); CHECK_EQ(err, OK);
@@ -741,39 +766,7 @@ void OMXCodec::setVideoInputFormat(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
CHECK_EQ(err, OK); CHECK_EQ(err, OK);
//////////////////////////////////////////////////////////////////////////// /////////////////// Codec-specific ////////////////////////
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);
switch (compressionFormat) { switch (compressionFormat) {
case OMX_VIDEO_CodingMPEG4: case OMX_VIDEO_CodingMPEG4:
{ {