Enable the support of setting video bit rate
bug 1993400
diff --git a/android/author/authordriver.cpp b/android/author/authordriver.cpp
index 322ab8e..3b9f481 100644
--- a/android/author/authordriver.cpp
+++ b/android/author/authordriver.cpp
@@ -22,6 +22,7 @@
 #include <media/thread_init.h>
 #include <ui/ISurface.h>
 #include <ui/ICamera.h>
+#include <cutils/properties.h> // for property_get
 #include "authordriver.h"
 #include "pv_omxcore.h"
 #include <sys/prctl.h>
@@ -114,6 +115,7 @@
     mSamplingRate(0),
     mNumberOfChannels(0),
     mAudio_bitrate_setting(0),
+    mVideo_bitrate_setting(0),
     ifpOutput(NULL)
 {
     mSyncSem = new OsclSemaphore();
@@ -841,6 +843,11 @@
         if (safe_strtoi64(value.string(), &audio_bitrate)) {
             return setParamAudioEncodingBitrate(audio_bitrate);
         }
+    } else if (key == "video-param-encoding-bitrate") {
+        int64_t video_bitrate;
+        if (safe_strtoi64(value.string(), &video_bitrate)) {
+            return setParamVideoEncodingBitrate(video_bitrate);
+        }
     }
 
     // Return error if the key wasnt found
@@ -848,6 +855,19 @@
     return PVMFErrArgument;
 }
 
+PVMFStatus AuthorDriver::setParamVideoEncodingBitrate(int64_t aVideoBitrate)
+{
+    if (aVideoBitrate <= 0)
+    {
+        LOGE("setParamVideoEncodingBitrate() invalid video bitrate (%lld).  Set call ignored.", aVideoBitrate);
+        return PVMFErrArgument;
+    }
+
+    mVideo_bitrate_setting = aVideoBitrate;
+    LOGD("setParamVideoEncodingBitrate() %d", mVideo_bitrate_setting);
+    return PVMFSuccess;
+}
+
 // Applies the requested parameters, completes either successfully or stops
 // application of parameters upon encountering the first error, finishing the
 // transaction with the failure result of that initial failure.
@@ -1097,6 +1117,106 @@
     ed->mSyncSem->Signal();
 }
 
+// Backward compatible hardcoded video bit rate setting
+// These bit rate settings are from the original work with
+// QCOM's hardware encoders. Originally, anything above
+// 420000 bps is not stable, and default low quality bit
+// rate it set to 192000 bps. For those devices with
+// media capabilities specified as system properties, these
+// bit rate settings will not be used.
+static int setVideoBitrateHeuristically(int videoWidth)
+{
+    int bitrate_setting = 192000;
+    if (videoWidth >= 480) {
+        bitrate_setting = 420000;
+    } else if (videoWidth >= 352) {
+        bitrate_setting = 360000;
+    } else if (videoWidth >= 320) {
+        bitrate_setting = 320000;
+    }
+    return bitrate_setting;
+}
+
+
+// Returns true on success
+static bool getMinAndMaxValuesOfProperty(const char*propertyKey, int64& minValue, int64& maxValue)
+{
+    char value[PROPERTY_VALUE_MAX];
+    int rc = property_get(propertyKey, value, 0);
+    LOGV("property_get(): rc = %d, value=%s", rc, value);
+    if (rc > 0) {
+        char* b = strchr(value, ',');
+        if (b == 0) {  // A pair of values separated by ","?
+            return false;
+        } else {
+            String8 key(value, b - value);
+            if (!safe_strtoi64(key.string(), &minValue) || !safe_strtoi64(b + 1, &maxValue)) {
+                return false;
+            }
+        }
+        return true;
+    }
+    return false;
+}
+
+// Maps the given encoder to a system property key
+// Returns true on success
+static bool getPropertyKeyForVideoEncoder(video_encoder encoder, char* name, size_t len)
+{
+    switch(encoder) {
+        case VIDEO_ENCODER_MPEG_4_SP:
+            strncpy(name, "ro.media.enc.vid.m4v", len);
+            return true;
+        case VIDEO_ENCODER_H264:
+            strncpy(name, "ro.media.enc.vid.h264", len);
+            return true;
+        case VIDEO_ENCODER_H263:
+            strncpy(name, "ro.media.enc.vid.h263", len);
+            return true;
+        default:
+            LOGE("Failed to get system property key for video encoder(%d)", encoder);
+            return false;
+    }
+}
+
+// Retrieves the advertised video bit rate range from system properties for the given encoder.
+// If the encoder is not found, or the bit rate range is not listed as a system property,
+// default hardcoded min and max bit rate will be used.
+static void getSupportedVideoBitRateRange(video_encoder encoder, int64& minBitRateBps, int64& maxBitRateBps)
+{
+    char videoEncoderName[PROPERTY_KEY_MAX];
+    bool propertyKeyExists = getPropertyKeyForVideoEncoder(encoder, videoEncoderName, PROPERTY_KEY_MAX - 1);
+    if (propertyKeyExists) {
+        const char* bps = ".bps";  // Specify the specific property for the given video encoder
+        if ((strlen(videoEncoderName) + strlen(bps) + 1) < PROPERTY_KEY_MAX) {  // Valid key length
+            strcat(videoEncoderName, bps);
+        } else {
+            propertyKeyExists = false;
+        }
+    }
+    if (!propertyKeyExists || !getMinAndMaxValuesOfProperty(videoEncoderName, minBitRateBps, maxBitRateBps)) {
+        minBitRateBps = MIN_VIDEO_BITRATE_SETTING;
+        maxBitRateBps = MAX_VIDEO_BITRATE_SETTING;
+        LOGW("Use default video bit rate range [%lld %lld]", minBitRateBps, maxBitRateBps);
+    }
+}
+
+// Clips the intented video encoding rate so that it is
+// within the advertised support range. Logs a warning if
+// the intended bit rate is out of the range.
+void AuthorDriver::clipVideoBitrate()
+{
+    int64 minBitrate, maxBitrate;
+    getSupportedVideoBitRateRange(mVideoEncoder, minBitrate, maxBitrate);
+    if (mVideo_bitrate_setting < minBitrate) {
+        LOGW("Intended video encoding bit rate (%d bps) is too small and will be set to (%lld bps)", mVideo_bitrate_setting, minBitrate);
+        mVideo_bitrate_setting = minBitrate;
+    } else if (mVideo_bitrate_setting > maxBitrate) {
+        LOGW("Intended video encoding bit rate (%d bps) is too large and will be set to (%lld bps)", mVideo_bitrate_setting, maxBitrate);
+        mVideo_bitrate_setting = maxBitrate;
+    }
+}
+
 void AuthorDriver::CommandCompleted(const PVCmdResponse& aResponse)
 {
     author_command *ac = (author_command *)aResponse.GetContext();
@@ -1118,19 +1238,14 @@
         case VIDEO_ENCODER_H264: {
             PVMp4H263EncExtensionInterface *config = OSCL_STATIC_CAST(PVMp4H263EncExtensionInterface*,
                                                                       mVideoEncoderConfig);
-            // TODO:
-            // fix the hardcoded bit rate settings.
             if (config) {
-                int bitrate_setting = 192000;
-                if (mVideoWidth >= 480) {
-                    bitrate_setting = 420000; // unstable
-                } else if (mVideoWidth >= 352) {
-                    bitrate_setting = 360000;
-                } else if (mVideoWidth >= 320) {
-                    bitrate_setting = 320000;
+                if (mVideo_bitrate_setting == 0) {
+                    mVideo_bitrate_setting = setVideoBitrateHeuristically(mVideoWidth);
+                    LOGW("Video encoding bit rate is set to %d bps", mVideo_bitrate_setting);
                 }
+                clipVideoBitrate();
                 config->SetNumLayers(1);
-                config->SetOutputBitRate(0, bitrate_setting);
+                config->SetOutputBitRate(0, mVideo_bitrate_setting);
                 config->SetOutputFrameSize(0, mVideoWidth, mVideoHeight);
                 config->SetOutputFrameRate(0, mVideoFrameRate);
                 config->SetIFrameInterval(ANDROID_DEFAULT_I_FRAME_INTERVAL);
diff --git a/android/author/authordriver.h b/android/author/authordriver.h
index 22f4f6a..2337b75 100644
--- a/android/author/authordriver.h
+++ b/android/author/authordriver.h
@@ -73,6 +73,8 @@
 #define ANDROID_MIN_FRAME_RATE_FPS                 5
 #define ANDROID_MAX_FRAME_RATE_FPS                 20
 
+static const int32 MIN_VIDEO_BITRATE_SETTING = 192000;
+static const int32 MAX_VIDEO_BITRATE_SETTING = 420000;
 static const int32 MAX_AUDIO_BITRATE_SETTING = 320000; // Max bitrate??
 static const int32 MIN_AUDIO_BITRATE_SETTING = 1;      // Min bitrate??
 static const int32 DEFAULT_AUDIO_BITRATE_SETTING = 64000; // Default for all the other audio
@@ -315,6 +317,13 @@
 
     PVMFStatus setParameter(const String8 &key, const String8 &value);
 
+    // Has no effect if called after video encoder is set
+    PVMFStatus setParamVideoEncodingBitrate(int64_t aVideoBitrate);
+
+    // Clips the intended video encoding bit rate so that it is within the
+    // supported range.
+    void clipVideoBitrate();
+
     // Used to map the incoming bitrate to the closest AMR bitrate
     bool MapAMRBitrate(int32 aAudioBitrate, PVMF_GSMAMR_Rate &anAMRBitrate);
 
@@ -355,6 +364,7 @@
     int32            mSamplingRate;
     int32            mNumberOfChannels;
     int32            mAudio_bitrate_setting;
+    int32            mVideo_bitrate_setting;
 
     FILE*       ifpOutput;
 };