Merge "Use timestamp from camera driver for CameraSource" into kraken
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
** limitations under the License.
|
||||
*/
|
||||
|
||||
//#define LOG_NDEBUG 0
|
||||
#define LOG_TAG "CameraService"
|
||||
#include <utils/Log.h>
|
||||
|
||||
@@ -247,7 +248,7 @@ CameraService::Client::Client(const sp<CameraService>& 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);
|
||||
|
||||
@@ -34,7 +34,7 @@ class Camera;
|
||||
class CameraSource : public MediaSource {
|
||||
public:
|
||||
static CameraSource *Create();
|
||||
static CameraSource *CreateFromICamera(const sp<ICamera> &icamera);
|
||||
static CameraSource *CreateFromCamera(const sp<Camera> &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> &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 &operator=(const CameraSource &);
|
||||
|
||||
@@ -37,6 +37,7 @@ LOCAL_SHARED_LIBRARIES := \
|
||||
libvorbisidec \
|
||||
libsonivox \
|
||||
libmedia \
|
||||
libcamera_client \
|
||||
libandroid_runtime \
|
||||
libstagefright \
|
||||
libstagefright_omx \
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "StagefrightRecorder.h"
|
||||
|
||||
#include <binder/IPCThreadState.h>
|
||||
#include <media/stagefright/AudioSource.h>
|
||||
#include <media/stagefright/AMRWriter.h>
|
||||
#include <media/stagefright/CameraSource.h>
|
||||
@@ -30,8 +31,11 @@
|
||||
#include <media/stagefright/OMXClient.h>
|
||||
#include <media/stagefright/OMXCodec.h>
|
||||
#include <camera/ICamera.h>
|
||||
#include <camera/Camera.h>
|
||||
#include <surfaceflinger/ISurface.h>
|
||||
#include <utils/Errors.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
@@ -96,7 +100,25 @@ status_t StagefrightRecorder::setVideoFrameRate(int frames_per_second) {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -240,7 +262,7 @@ status_t StagefrightRecorder::startMPEG4Recording() {
|
||||
CHECK(mCamera != NULL);
|
||||
|
||||
sp<CameraSource> 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;
|
||||
}
|
||||
|
||||
@@ -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<ICamera> mCamera;
|
||||
enum CameraFlags {
|
||||
FLAGS_SET_CAMERA = 1L << 0,
|
||||
FLAGS_HOT_CAMERA = 1L << 1,
|
||||
};
|
||||
|
||||
sp<Camera> mCamera;
|
||||
sp<ISurface> mPreviewSurface;
|
||||
sp<IMediaPlayerClient> mListener;
|
||||
sp<MediaWriter> mWriter;
|
||||
@@ -66,6 +72,7 @@ private:
|
||||
int mFrameRate;
|
||||
String8 mParams;
|
||||
int mOutputFd;
|
||||
int32_t mFlags;
|
||||
|
||||
status_t startMPEG4Recording();
|
||||
status_t startAMRRecording();
|
||||
|
||||
@@ -14,12 +14,12 @@
|
||||
* 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 <binder/IServiceManager.h>
|
||||
#include <cutils/properties.h> // for property_get
|
||||
#include <media/stagefright/CameraSource.h>
|
||||
#include <media/stagefright/MediaDebug.h>
|
||||
#include <media/stagefright/MediaDefs.h>
|
||||
@@ -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<IMemory> &dataPtr) {
|
||||
LOGV("postData(%d, ptr:%p, size:%d)",
|
||||
msgType, dataPtr->pointer(), dataPtr->size());
|
||||
|
||||
sp<CameraSource> source = mSource.promote();
|
||||
if (source.get() != NULL) {
|
||||
source->dataCallback(msgType, dataPtr);
|
||||
}
|
||||
}
|
||||
|
||||
void CameraSourceListener::postDataTimestamp(
|
||||
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
|
||||
@@ -125,9 +116,7 @@ CameraSource *CameraSource::Create() {
|
||||
}
|
||||
|
||||
// static
|
||||
CameraSource *CameraSource::CreateFromICamera(const sp<ICamera> &icamera) {
|
||||
sp<Camera> camera = Camera::create(icamera);
|
||||
|
||||
CameraSource *CameraSource::CreateFromCamera(const sp<Camera> &camera) {
|
||||
if (camera.get() == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -140,7 +129,9 @@ CameraSource::CameraSource(const sp<Camera> &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<ISurface> &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<sp<IMemory> >::iterator it;
|
||||
while (!mFrames.empty()) {
|
||||
it = mFrames.begin();
|
||||
mCamera->releaseRecordingFrame(*it);
|
||||
mFrames.erase(it);
|
||||
++mNumFramesReleased;
|
||||
}
|
||||
}
|
||||
|
||||
sp<MetaData> CameraSource::getFormat() {
|
||||
sp<MetaData> meta = new MetaData;
|
||||
meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
|
||||
@@ -203,7 +206,7 @@ sp<MetaData> 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<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);
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user