Use timestamp from camera driver for CameraSource

Change-Id: I09ddec69997c43b8f17fdd21304c76cb4c5ab8cf
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index 00bd54e..53c77da 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 <utils/Log.h>
 
@@ -247,7 +248,7 @@
 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 ea435de..5f9d982 100644
--- a/include/media/stagefright/CameraSource.h
+++ b/include/media/stagefright/CameraSource.h
@@ -34,7 +34,7 @@
 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 @@
 
     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 &);
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index cf97b23..3b678cb 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -37,6 +37,7 @@
 	libvorbisidec         			\
 	libsonivox            			\
 	libmedia              			\
+	libcamera_client      			\
 	libandroid_runtime    			\
 	libstagefright        			\
 	libstagefright_omx    			\
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 531fd11..a63d94b 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -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::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 @@
         CHECK(mCamera != NULL);
 
         sp<CameraSource> cameraSource =
-            CameraSource::CreateFromICamera(mCamera);
+            CameraSource::CreateFromCamera(mCamera);
 
         CHECK(cameraSource != NULL);
 
@@ -314,6 +336,17 @@
 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 @@
     mVideoHeight = -1;
     mFrameRate = -1;
     mOutputFd = -1;
+    mFlags = 0;
 
     return OK;
 }
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index 7ec412d..2f2f748 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 @@
     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 @@
     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 f57ddc1..b07bd0e 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -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::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 @@
 }
 
 // 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 @@
       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 @@
 }
 
 status_t CameraSource::start(MetaData *) {
+    LOGV("start");
     CHECK(!mStarted);
 
     mCamera->setListener(new CameraSourceListener(this));
@@ -169,11 +161,7 @@
                 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::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 @@
 
 status_t CameraSource::read(
         MediaBuffer **buffer, const ReadOptions *options) {
-    CHECK(mStarted);
+    LOGV("read");
 
     *buffer = NULL;
 
@@ -217,20 +220,24 @@
 
     {
         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 @@
     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();
 }
 
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 9cdf96e..41be9ac 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -711,21 +711,46 @@
         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 @@
             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:
         {