Remove some hard-coded encoding parameters

Change-Id: I7a8ccd5d57891a6a585c8da2ee53acb094955913
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 572389f..1a684a9 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -287,14 +287,32 @@
 
 status_t StagefrightRecorder::setParamInterleaveDuration(int32_t durationUs) {
     LOGV("setParamInterleaveDuration: %d", durationUs);
-    if (durationUs <= 20000) {  // XXX: 20 ms
+    if (durationUs <= 500000) {           //  500 ms
+        // If interleave duration is too small, it is very inefficient to do
+        // interleaving since the metadata overhead will count for a significant
+        // portion of the saved contents
         LOGE("Audio/video interleave duration is too small: %d us", durationUs);
         return BAD_VALUE;
+    } else if (durationUs >= 10000000) {  // 10 seconds
+        // If interleaving duration is too large, it can cause the recording
+        // session to use too much memory since we have to save the output
+        // data before we write them out
+        LOGE("Audio/video interleave duration is too large: %d us", durationUs);
+        return BAD_VALUE;
     }
     mInterleaveDurationUs = durationUs;
     return OK;
 }
 
+// If interval <  0, only the first frame is I frame, and rest are all P frames
+// If interval == 0, all frames are encoded as I frames. No P frames
+// If interval >  0, it is the time spacing between 2 neighboring I frames
+status_t StagefrightRecorder::setParamIFramesInterval(int32_t interval) {
+    LOGV("setParamIFramesInterval: %d seconds", interval);
+    mIFramesInterval = interval;
+    return OK;
+}
+
 status_t StagefrightRecorder::setParameter(
         const String8 &key, const String8 &value) {
     LOGV("setParameter: key (%s) => value (%s)", key.string(), value.string());
@@ -335,6 +353,11 @@
         if (safe_strtoi32(value.string(), &durationUs)) {
             return setParamInterleaveDuration(durationUs);
         }
+    } else if (key == "param-i-frames-interval") {
+        int32_t interval;
+        if (safe_strtoi32(value.string(), &interval)) {
+            return setParamIFramesInterval(interval);
+        }
     } else {
         LOGE("setParameter: failed to find key %s", key.string());
     }
@@ -619,12 +642,17 @@
 
         sp<MetaData> meta = cameraSource->getFormat();
 
-        int32_t width, height;
+        int32_t width, height, stride, sliceHeight;
         CHECK(meta->findInt32(kKeyWidth, &width));
         CHECK(meta->findInt32(kKeyHeight, &height));
+        CHECK(meta->findInt32(kKeyStride, &stride));
+        CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
 
         enc_meta->setInt32(kKeyWidth, width);
         enc_meta->setInt32(kKeyHeight, height);
+        enc_meta->setInt32(kKeyIFramesInterval, mIFramesInterval);
+        enc_meta->setInt32(kKeyStride, stride);
+        enc_meta->setInt32(kKeySliceHeight, sliceHeight);
 
         OMXClient client;
         CHECK_EQ(client.connect(), OK);
@@ -702,6 +730,7 @@
     mAudioChannels = 1;
     mAudioBitRate  = 12200;
     mInterleaveDurationUs = 0;
+    mIFramesInterval = 1;
 
     mOutputFd = -1;
     mFlags = 0;
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index b7d554b..b491e9f 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -75,6 +75,7 @@
     int32_t mAudioChannels;
     int32_t mSampleRate;
     int32_t mInterleaveDurationUs;
+    int32_t mIFramesInterval;
     int64_t mMaxFileSizeBytes;
     int64_t mMaxFileDurationUs;
 
@@ -92,6 +93,7 @@
     status_t setParamAudioNumberOfChannels(int32_t channles);
     status_t setParamAudioSamplingRate(int32_t sampleRate);
     status_t setParamInterleaveDuration(int32_t durationUs);
+    status_t setParamIFramesInterval(int32_t interval);
     status_t setParamMaxDurationOrFileSize(int64_t limit, bool limit_is_duration);
 
     StagefrightRecorder(const StagefrightRecorder &);
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 416b75c..67759c0 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -128,7 +128,7 @@
     String8 s = mCamera->getParameters();
     printf("params: \"%s\"\n", s.string());
 
-    int32_t width, height;
+    int32_t width, height, stride, sliceHeight;
     CameraParameters params(s);
     params.getPreviewSize(&width, &height);
 
@@ -136,11 +136,19 @@
     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);
+
 }
 
 CameraSource::~CameraSource() {
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 7c3df31..ba35748 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -571,17 +571,14 @@
     }
 
     if (!strncasecmp(mMIME, "video/", 6)) {
-        int32_t width, height;
-        bool success = meta->findInt32(kKeyWidth, &width);
-        success = success && meta->findInt32(kKeyHeight, &height);
-        CHECK(success);
 
         if (mIsEncoder) {
-            int32_t frameRate = 25;  // XXX
-            int32_t bitRate = 3000000;  // bit rate
-            //success = success && meta->findInt32(kKeySampleRate, &frameRate);
-            setVideoInputFormat(mMIME, width, height, frameRate, bitRate);
+            setVideoInputFormat(mMIME, meta);
         } else {
+            int32_t width, height;
+            bool success = meta->findInt32(kKeyWidth, &width);
+            success = success && meta->findInt32(kKeyHeight, &height);
+            CHECK(success);
             status_t err = setVideoOutputFormat(
                     mMIME, width, height);
 
@@ -745,9 +742,17 @@
 }
 
 void OMXCodec::setVideoInputFormat(
-        const char *mime, OMX_U32 width, OMX_U32 height,
-        OMX_U32 frameRate, OMX_U32 bitRate) {
-    CODEC_LOGV("setVideoInputFormat width=%ld, height=%ld", width, height);
+        const char *mime, const sp<MetaData>& meta) {
+
+    int32_t width, height, frameRate, bitRate, stride, sliceHeight;
+    bool success = meta->findInt32(kKeyWidth, &width);
+    success = success && meta->findInt32(kKeyHeight, &height);
+    success = success && meta->findInt32(kKeySampleRate, &frameRate);
+    success = success && meta->findInt32(kKeyBitRate, &bitRate);
+    success = success && meta->findInt32(kKeyStride, &stride);
+    success = success && meta->findInt32(kKeySliceHeight, &sliceHeight);
+    CHECK(success);
+    CHECK(stride != 0);
 
     OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
     if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
@@ -766,8 +771,6 @@
         colorFormat = OMX_COLOR_FormatYCbYCr;
     }
 
-
-
     status_t err;
     OMX_PARAM_PORTDEFINITIONTYPE def;
     OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
@@ -784,12 +787,15 @@
             mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
     CHECK_EQ(err, OK);
 
-    def.nBufferSize = getFrameSize(colorFormat, width, height);
+    def.nBufferSize = getFrameSize(colorFormat,
+            stride > 0? stride: -stride, sliceHeight);
 
     CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
 
     video_def->nFrameWidth = width;
     video_def->nFrameHeight = height;
+    video_def->nStride = stride;
+    video_def->nSliceHeight = sliceHeight;
     video_def->xFramerate = (frameRate << 16);  // Q16 format
     video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
     video_def->eColorFormat = colorFormat;
@@ -826,7 +832,7 @@
     switch (compressionFormat) {
         case OMX_VIDEO_CodingMPEG4:
         {
-            CHECK_EQ(setupMPEG4EncoderParameters(), OK);
+            CHECK_EQ(setupMPEG4EncoderParameters(meta), OK);
             break;
         }
 
@@ -835,7 +841,7 @@
 
         case OMX_VIDEO_CodingAVC:
         {
-            CHECK_EQ(setupAVCEncoderParameters(), OK);
+            CHECK_EQ(setupAVCEncoderParameters(meta), OK);
             break;
         }
 
@@ -845,7 +851,23 @@
     }
 }
 
-status_t OMXCodec::setupMPEG4EncoderParameters() {
+static OMX_U32 setPFramesSpacing(int32_t iFramesInterval, int32_t frameRate) {
+    if (iFramesInterval < 0) {
+        return 0xFFFFFFFF;
+    } else if (iFramesInterval == 0) {
+        return 0;
+    }
+    OMX_U32 ret = frameRate * iFramesInterval;
+    CHECK(ret > 1);
+    return ret;
+}
+
+status_t OMXCodec::setupMPEG4EncoderParameters(const sp<MetaData>& meta) {
+    int32_t iFramesInterval, frameRate, bitRate;
+    bool success = meta->findInt32(kKeyBitRate, &bitRate);
+    success = success && meta->findInt32(kKeySampleRate, &frameRate);
+    success = success && meta->findInt32(kKeyIFramesInterval, &iFramesInterval);
+    CHECK(success);
     OMX_VIDEO_PARAM_MPEG4TYPE mpeg4type;
     InitOMXParams(&mpeg4type);
     mpeg4type.nPortIndex = kPortIndexOutput;
@@ -861,9 +883,11 @@
     mpeg4type.nAllowedPictureTypes =
         OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
 
-    mpeg4type.nPFrames = 23;
+    mpeg4type.nPFrames = setPFramesSpacing(iFramesInterval, frameRate);
+    if (mpeg4type.nPFrames == 0) {
+        mpeg4type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI;
+    }
     mpeg4type.nBFrames = 0;
-
     mpeg4type.nIDCVLCThreshold = 0;
     mpeg4type.bACPred = OMX_TRUE;
     mpeg4type.nMaxPacketSize = 256;
@@ -890,7 +914,7 @@
     CHECK_EQ(err, OK);
 
     bitrateType.eControlRate = OMX_Video_ControlRateVariable;
-    bitrateType.nTargetBitrate = 1000000;
+    bitrateType.nTargetBitrate = bitRate;
 
     err = mOMX->setParameter(
             mNode, OMX_IndexParamVideoBitrate,
@@ -922,7 +946,13 @@
     return OK;
 }
 
-status_t OMXCodec::setupAVCEncoderParameters() {
+status_t OMXCodec::setupAVCEncoderParameters(const sp<MetaData>& meta) {
+    int32_t iFramesInterval, frameRate, bitRate;
+    bool success = meta->findInt32(kKeyBitRate, &bitRate);
+    success = success && meta->findInt32(kKeySampleRate, &frameRate);
+    success = success && meta->findInt32(kKeyIFramesInterval, &iFramesInterval);
+    CHECK(success);
+
     OMX_VIDEO_PARAM_AVCTYPE h264type;
     InitOMXParams(&h264type);
     h264type.nPortIndex = kPortIndexOutput;
@@ -935,8 +965,11 @@
         OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
 
     h264type.nSliceHeaderSpacing = 0;
-    h264type.nBFrames = 0;
-    h264type.nPFrames = 24;  // XXX
+    h264type.nBFrames = 0;   // No B frames support yet
+    h264type.nPFrames = setPFramesSpacing(iFramesInterval, frameRate);
+    if (h264type.nPFrames == 0) {
+        h264type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI;
+    }
     h264type.bUseHadamard = OMX_TRUE;
     h264type.nRefFrames = 1;
     h264type.nRefIdx10ActiveMinus1 = 0;
@@ -969,7 +1002,7 @@
     CHECK_EQ(err, OK);
 
     bitrateType.eControlRate = OMX_Video_ControlRateVariable;
-    bitrateType.nTargetBitrate = 3000000;  // XXX
+    bitrateType.nTargetBitrate = bitRate;
 
     err = mOMX->setParameter(
             mNode, OMX_IndexParamVideoBitrate,