media: Update to AU 205 drop

Update to AU_LINUX_ANDROID_LA.HB.1.3.9.06.00.01.213.205

media_hal:
1df75f0 Merge "mm-video-v4l2: venc: Avoid processing ETBs/FTBs in invalid states"
dc623d6 mm-video-v4l2: vdec: Avoid processing ETBs/FTBs in invalid states,
d57cbc1 mm-video-v4l2: venc: Avoid processing ETBs/FTBs in invalid states
2b33b5a Merge "mm-video-v4l2: venc: add support for encoding temporal layers"
815b4be mm-video-v4l2: venc: add support for encoding temporal layers
d450628 mm-video-v4l2: vidc: venc: Fix issues with Hier P
a7ead0c mm-video-v4l2: vidc: Enumerate supported HEVC decoder profiles
9e096e8  mm-video-v4l2: vidc: HEVC Main10 profile support
a42a61d mm-video-v4l2: vdec: Add support for prefetching secure memory

Change-Id: I16f46e6d896e296cb2cf3eab6e6683c93f9daa8c
diff --git a/msm8996/mm-core/inc/OMX_IndexExt.h b/msm8996/mm-core/inc/OMX_IndexExt.h
index 09e3b5b..3e1dcfd 100644
--- a/msm8996/mm-core/inc/OMX_IndexExt.h
+++ b/msm8996/mm-core/inc/OMX_IndexExt.h
@@ -73,6 +73,8 @@
     OMX_IndexParamVideoHevc,                        /**< reference: OMX_VIDEO_PARAM_HEVCTYPE */
     OMX_IndexParamSliceSegments,                    /**< reference: OMX_VIDEO_SLICESEGMENTSTYPE */
     OMX_IndexConfigAndroidIntraRefresh,             /**< reference: OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE */
+    OMX_IndexParamAndroidVideoTemporalLayers,       /**< reference: OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERTYPE */
+    OMX_IndexConfigAndroidVideoTemporalLayers,      /**< reference: OMX_VIDEO_CONFIG_ANDROID_TEMPORALLAYERTYPE */
 
     /* Image & Video common configurations */
     OMX_IndexExtCommonStartUnused = OMX_IndexKhronosExtensions + 0x00700000,
diff --git a/msm8996/mm-core/inc/OMX_QCOMExtns.h b/msm8996/mm-core/inc/OMX_QCOMExtns.h
index 00a532e..ad88a8f 100644
--- a/msm8996/mm-core/inc/OMX_QCOMExtns.h
+++ b/msm8996/mm-core/inc/OMX_QCOMExtns.h
@@ -512,7 +512,7 @@
     /* "OMX.QCOM.index.param.video.InputBatch" */
     OMX_QcomIndexParamBatchSize = 0x7F00004A,
 
-    OMX_QcomIndexConfigMaxHierPLayers = 0x7F00004B,
+    OMX_QcomIndexConfigNumHierPLayers = 0x7F00004B,
 
     OMX_QcomIndexConfigRectType = 0x7F00004C,
 
@@ -582,16 +582,16 @@
 *
 * nSize         : Size of Structure in bytes
 * nVersion      : OpenMAX IL specification version information
-* nMaxHierLayers: Set the max number of Hier-p layers for the session
-*                  - This should be less than the Hier-P layers set
-*                    for the session.
+* nNumHierLayers: Set the number of Hier-p layers for the session
+*                  - This should be less than the MAX Hier-P
+*                    layers set for the session.
 */
 
-typedef struct QOMX_EXTNINDEX_VIDEO_MAX_HIER_P_LAYERS {
+typedef struct QOMX_EXTNINDEX_VIDEO_HIER_P_LAYERS {
    OMX_U32 nSize;
    OMX_VERSIONTYPE nVersion;
-   OMX_U32 nMaxHierLayers;
-} QOMX_EXTNINDEX_VIDEO_MAX_HIER_P_LAYERS;
+   OMX_U32 nNumHierLayers;
+} QOMX_EXTNINDEX_VIDEO_HIER_P_LAYERS;
 
 
 /**
@@ -1601,7 +1601,6 @@
 #define OMX_QCOM_INDEX_PARAM_VIDEO_LTRPERIOD "OMX.QCOM.index.param.video.LTRPeriod"
 #define OMX_QCOM_INDEX_CONFIG_VIDEO_LTRUSE "OMX.QCOM.index.config.video.LTRUse"
 #define OMX_QCOM_INDEX_CONFIG_VIDEO_LTRMARK "OMX.QCOM.index.config.video.LTRMark"
-#define OMX_QCOM_INDEX_CONFIG_VIDEO_MAX_HIER_P_LAYERS "OMX.QCOM.index.config.video.hierplayers"
 #define OMX_QCOM_INDEX_CONFIG_RECTANGLE_TYPE "OMX.QCOM.index.config.video.rectangle"
 #define OMX_QCOM_INDEX_PARAM_VIDEO_BASE_LAYER_ID "OMX.QCOM.index.param.video.baselayerid"
 #define OMX_QCOM_INDEX_PARAM_VIDEO_DRIVERVERSION "OMX.QCOM.index.param.video.FramePackingInfo"
@@ -1614,7 +1613,7 @@
 #define OMX_QCOM_INDEX_PARAM_VIDEO_LTRPERIOD "OMX.QCOM.index.param.video.LTRPeriod"
 #define OMX_QCOM_INDEX_CONFIG_VIDEO_LTRUSE "OMX.QCOM.index.config.video.LTRUse"
 #define OMX_QCOM_INDEX_CONFIG_VIDEO_LTRMARK "OMX.QCOM.index.config.video.LTRMark"
-#define OMX_QCOM_INDEX_CONFIG_VIDEO_MAX_HIER_P_LAYERS "OMX.QCOM.index.config.video.hierplayers"
+#define OMX_QCOM_INDEX_CONFIG_VIDEO_HIER_P_LAYERS "OMX.QCOM.index.config.video.hierplayers"
 #define OMX_QCOM_INDEX_CONFIG_RECTANGLE_TYPE "OMX.QCOM.index.config.video.rectangle"
 #define OMX_QCOM_INDEX_PARAM_VIDEO_BASE_LAYER_ID "OMX.QCOM.index.param.video.baselayerid"
 #define OMX_QCOM_INDEX_CONFIG_VIDEO_QP "OMX.QCOM.index.config.video.qp"
diff --git a/msm8996/mm-core/inc/OMX_VideoExt.h b/msm8996/mm-core/inc/OMX_VideoExt.h
index 92d360a..31ab510 100644
--- a/msm8996/mm-core/inc/OMX_VideoExt.h
+++ b/msm8996/mm-core/inc/OMX_VideoExt.h
@@ -173,6 +173,68 @@
     OMX_U32 nRefreshPeriod;
 } OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE;
 
+/** Maximum number of temporal layers supported by AVC/HEVC */
+#define OMX_VIDEO_ANDROID_MAXTEMPORALLAYERS 8
+
+/**
+ * Android specific param for configuration of temporal layering
+ *
+ *  nSize                      : Size of the structure in bytes
+ *  nVersion                   : OMX specification version information
+ *  nPortIndex                 : Port that this structure applies to
+ *  nTemporalLayerCountMax     : Max number of temporal coding layers supported
+ *                               by the encoder
+ *  nTemporalBLayerCountMax    : Max number of layers that can contain B frames
+ *                               (0 to nTemporalLayerCountMax)
+ *  nTemporalPLayerCountActual : Number of temporal layers to be coded with non-B frames,
+ *                               starting from and including the base-layer.
+ *                               (1 to nTemporalLayerCountMax - nTemporalBLayerCountActual)
+ *  nTemporalBLayerCountActual : Number of temporal layers to be coded with B frames,
+ *                               starting after non-B layers.
+ *                               (0 to nTemporalBLayerCountMax)
+ *  bTemporalLayerBitrateRatioSpecified : Flag to indicate if layer-wise bitrate
+ *                               distribution is specified.
+ *  nTemporalLayerBitrateRatio : Bitrate ratio (100 based) per layer. Honored if
+ *                               bTemporalLayerBitrateRatioSpecified is set.
+ *                               i.e for 4 layers with desired distribution (25% 25% 25% 25%),
+ *                               BitrateRatio = {25, 50, 75, 100, 100, 100, 100, 100}
+*/
+typedef struct OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_U32 nTemporalLayerCountMax;
+    OMX_U32 nTemporalBLayerCountMax;
+    OMX_U32 nTemporalPLayerCountActual;
+    OMX_U32 nTemporalBLayerCountActual;
+    OMX_BOOL bTemporalLayerBitrateRatioSpecified;
+    OMX_U32 nTemporalLayerBitrateRatio[OMX_VIDEO_ANDROID_MAXTEMPORALLAYERS];
+} OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERTYPE;
+
+/**
+ * Android specific config for changing the temporal-layer count or
+ * bitrate-distribution at run-time
+ *
+ *  nSize                      : Size of the structure in bytes
+ *  nVersion                   : OMX specification version information
+ *  nPortIndex                 : Port that this structure applies to
+ *  nTemporalPLayerCountActual : Number of temporal layers to be coded with non-B frames,
+ *  nTemporalBLayerCountActual : Number of temporal layers to be coded with B frames,
+ *  bTemporalLayerBitrateRatioSpecified : Flag to indicate if layer-wise bitrate
+ *                               distribution is specified.
+ *  nTemporalLayerBitrateRatio : Bitrate ratio (100 based) per layer. Honored if
+ *                               bTemporalLayerBitrateRatioSpecified is set.
+ */
+typedef struct OMX_VIDEO_CONFIG_ANDROID_TEMPORALLAYERTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_U32 nTemporalPLayerCountActual;
+    OMX_U32 nTemporalBLayerCountActual;
+    OMX_BOOL bTemporalLayerBitrateRatioSpecified;
+    OMX_U32 nTemporalLayerBitrateRatio[OMX_VIDEO_ANDROID_MAXTEMPORALLAYERS];
+} OMX_VIDEO_CONFIG_ANDROID_TEMPORALLAYERTYPE;
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/msm8996/mm-video-v4l2/vidc/vdec/inc/omx_vdec.h b/msm8996/mm-video-v4l2/vidc/vdec/inc/omx_vdec.h
index 037bba3..a5e9647 100644
--- a/msm8996/mm-video-v4l2/vidc/vdec/inc/omx_vdec.h
+++ b/msm8996/mm-video-v4l2/vidc/vdec/inc/omx_vdec.h
@@ -1155,6 +1155,7 @@
         }
 
         static OMX_ERRORTYPE describeColorFormat(OMX_PTR params);
+        void prefetchNewBuffers();
 
 };
 
diff --git a/msm8996/mm-video-v4l2/vidc/vdec/src/omx_vdec_v4l2.cpp b/msm8996/mm-video-v4l2/vidc/vdec/src/omx_vdec_v4l2.cpp
index 05eb885..24b4ae9 100644
--- a/msm8996/mm-video-v4l2/vidc/vdec/src/omx_vdec_v4l2.cpp
+++ b/msm8996/mm-video-v4l2/vidc/vdec/src/omx_vdec_v4l2.cpp
@@ -1664,6 +1664,10 @@
                                             pThis->m_debug.out_uvmeta_file = NULL;
                                         }
 
+                                        if (pThis->secure_mode && pThis->m_cb.EventHandler && pThis->in_reconfig) {
+                                            pThis->prefetchNewBuffers();
+                                        }
+
                                         if (pThis->m_cb.EventHandler) {
                                             uint32_t frame_data[2];
                                             frame_data[0] = (p2 == OMX_IndexParamPortDefinition) ?
@@ -3351,6 +3355,9 @@
             if (profileLevelType->nProfileIndex == 0) {
                 profileLevelType->eProfile = OMX_VIDEO_HEVCProfileMain;
                 profileLevelType->eLevel   = OMX_VIDEO_HEVCMainTierLevel51;
+            } else if (profileLevelType->nProfileIndex == 1) {
+                profileLevelType->eProfile = OMX_VIDEO_HEVCProfileMain10;
+                profileLevelType->eLevel   = OMX_VIDEO_HEVCMainTierLevel51;
             } else {
                 DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %u",
                         (unsigned int)profileLevelType->nProfileIndex);
@@ -7174,6 +7181,7 @@
         //We'll restore this size later on, so that it's transparent to client
         buffer->nFilledLen = 0;
         buffer->nAllocLen = handle->size;
+        drv_ctx.op_buf.buffer_size = handle->size;
     }
 
     nPortIndex = buffer - client_buffers.get_il_buf_hdr();
@@ -11779,3 +11787,105 @@
 #endif //FLEXYUV_SUPPORTED
 }
 
+void omx_vdec::prefetchNewBuffers() {
+
+    struct v4l2_decoder_cmd dec;
+    uint32_t prefetch_count;
+    uint32_t prefetch_size;
+    uint32_t want_size;
+    uint32_t have_size;
+    int color_fmt, rc;
+    uint32_t new_calculated_size;
+    uint32_t new_buffer_size;
+    uint32_t new_buffer_count;
+    uint32_t old_buffer_size;
+    uint32_t old_buffer_count;
+
+    memset((void *)&dec, 0 , sizeof(dec));
+    DEBUG_PRINT_LOW("Old size : %d, count : %d, width : %u, height : %u\n",
+            (int)drv_ctx.op_buf.buffer_size, drv_ctx.op_buf.actualcount,
+            drv_ctx.video_resolution.frame_width,
+            drv_ctx.video_resolution.frame_height);
+    dec.cmd = V4L2_DEC_QCOM_CMD_RECONFIG_HINT;
+    if (ioctl(drv_ctx.video_driver_fd, VIDIOC_DECODER_CMD, &dec)) {
+        DEBUG_PRINT_ERROR("Buffer info cmd failed : %d\n", errno);
+    } else {
+        DEBUG_PRINT_LOW("From driver, new size is %d, count is %d\n",
+                dec.raw.data[0], dec.raw.data[1]);
+    }
+
+    switch ((int)drv_ctx.output_format) {
+    case VDEC_YUV_FORMAT_NV12:
+        color_fmt = COLOR_FMT_NV12;
+        break;
+    case VDEC_YUV_FORMAT_NV12_UBWC:
+        color_fmt = COLOR_FMT_NV12_UBWC;
+        break;
+    default:
+        color_fmt = -1;
+    }
+
+    new_calculated_size = VENUS_BUFFER_SIZE(color_fmt, m_reconfig_width, m_reconfig_height);
+    DEBUG_PRINT_LOW("New calculated size for width : %d, height : %d, is %d\n",
+            m_reconfig_width, m_reconfig_height, new_calculated_size);
+    new_buffer_size = (dec.raw.data[0] > new_calculated_size) ? dec.raw.data[0] : new_calculated_size;
+    new_buffer_count = dec.raw.data[1];
+    old_buffer_size = drv_ctx.op_buf.buffer_size;
+    old_buffer_count = drv_ctx.op_buf.actualcount;
+
+    new_buffer_count = old_buffer_count > new_buffer_count ? old_buffer_count : new_buffer_count;
+
+    prefetch_count = new_buffer_count;
+    prefetch_size = new_buffer_size - old_buffer_size;
+    want_size = new_buffer_size * new_buffer_count;
+    have_size = old_buffer_size * old_buffer_count;
+
+    if (want_size > have_size) {
+        DEBUG_PRINT_LOW("Want: %d, have : %d\n", want_size, have_size);
+        DEBUG_PRINT_LOW("prefetch_count: %d, prefetch_size : %d\n", prefetch_count, prefetch_size);
+
+        int ion_fd = open(MEM_DEVICE, O_RDONLY);
+        if (ion_fd < 0) {
+            DEBUG_PRINT_ERROR("Ion fd open failed : %d\n", ion_fd);
+            return;
+        }
+
+        struct ion_custom_data *custom_data = (struct ion_custom_data*) malloc(sizeof(*custom_data));
+        struct ion_prefetch_data *prefetch_data = (struct ion_prefetch_data*) malloc(sizeof(*prefetch_data));
+        struct ion_prefetch_regions *regions = (struct ion_prefetch_regions*) malloc(sizeof(*regions));
+        size_t *sizes = (size_t*) malloc(sizeof(size_t) * prefetch_count);
+
+        if (custom_data == NULL || prefetch_data == NULL || regions == NULL || sizes == NULL) {
+            DEBUG_PRINT_ERROR("prefetch data allocation failed");
+            goto prefetch_exit;
+        }
+
+        for (uint32_t i = 0; i < prefetch_count; i++) {
+            sizes[i] = prefetch_size;
+        }
+
+        regions[0].nr_sizes = prefetch_count;
+        regions[0].sizes = sizes;
+        regions[0].vmid = ION_FLAG_CP_PIXEL;
+
+        prefetch_data->nr_regions = 1;
+        prefetch_data->regions = regions;
+        prefetch_data->heap_id = ION_HEAP(ION_SECURE_HEAP_ID);
+
+        custom_data->cmd = ION_IOC_PREFETCH;
+        custom_data->arg = (unsigned long )prefetch_data;
+
+        rc = ioctl(ion_fd, ION_IOC_CUSTOM, custom_data);
+        if (rc) {
+            DEBUG_PRINT_ERROR("Custom prefetch ioctl failed rc : %d, errno : %d\n", rc, errno);
+        }
+
+prefetch_exit:
+        close(ion_fd);
+        free(sizes);
+        free(regions);
+        free(prefetch_data);
+        free(custom_data);
+    }
+}
+
diff --git a/msm8996/mm-video-v4l2/vidc/venc/inc/omx_video_base.h b/msm8996/mm-video-v4l2/vidc/venc/inc/omx_video_base.h
index fd88eca..43fc43e 100644
--- a/msm8996/mm-video-v4l2/vidc/venc/inc/omx_video_base.h
+++ b/msm8996/mm-video-v4l2/vidc/venc/inc/omx_video_base.h
@@ -245,6 +245,8 @@
         virtual bool dev_get_vqzip_sei_info(OMX_U32 *) = 0;
         virtual bool dev_get_peak_bitrate(OMX_U32 *) = 0;
         virtual bool dev_get_batch_size(OMX_U32 *) = 0;
+        virtual bool dev_get_temporal_layer_caps(OMX_U32 * /*nMaxLayers*/,
+                OMX_U32 * /*nMaxBLayers*/) = 0;
 #ifdef _ANDROID_ICS_
         void omx_release_meta_buffer(OMX_BUFFERHEADERTYPE *buffer);
 #endif
@@ -627,7 +629,7 @@
         QOMX_VIDEO_HIERARCHICALLAYERS m_sHierLayers;
         OMX_QOMX_VIDEO_MBI_STATISTICS m_sMBIStatistics;
         QOMX_EXTNINDEX_VIDEO_INITIALQP m_sParamInitqp;
-        QOMX_EXTNINDEX_VIDEO_MAX_HIER_P_LAYERS m_sMaxHPlayers;
+        QOMX_EXTNINDEX_VIDEO_HIER_P_LAYERS m_sHPlayers;
         OMX_SKYPE_VIDEO_CONFIG_BASELAYERPID m_sBaseLayerID;
         OMX_SKYPE_VIDEO_PARAM_DRIVERVER m_sDriverVer;
         OMX_SKYPE_VIDEO_CONFIG_QP m_sConfigQP;
@@ -636,6 +638,8 @@
         OMX_U32 m_sExtraData;
         OMX_U32 m_input_msg_id;
         OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE m_sConfigIntraRefresh;
+        OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERTYPE m_sParamTemporalLayers;
+        OMX_VIDEO_CONFIG_ANDROID_TEMPORALLAYERTYPE m_sConfigTemporalLayers;
 
         // fill this buffer queue
         omx_cmd_queue m_ftb_q;
diff --git a/msm8996/mm-video-v4l2/vidc/venc/inc/omx_video_encoder.h b/msm8996/mm-video-v4l2/vidc/venc/inc/omx_video_encoder.h
index 8ccd678..7c51294 100644
--- a/msm8996/mm-video-v4l2/vidc/venc/inc/omx_video_encoder.h
+++ b/msm8996/mm-video-v4l2/vidc/venc/inc/omx_video_encoder.h
@@ -89,6 +89,8 @@
         bool dev_get_vqzip_sei_info(OMX_U32 *);
         bool dev_get_peak_bitrate(OMX_U32 *);
         bool dev_get_batch_size(OMX_U32 *);
+        bool dev_get_temporal_layer_caps(OMX_U32 * /*nMaxLayers*/,
+                OMX_U32 * /*nMaxBLayers*/);
         bool dev_is_video_session_supported(OMX_U32 width, OMX_U32 height);
         bool dev_color_align(OMX_BUFFERHEADERTYPE *buffer, OMX_U32 width,
                         OMX_U32 height);
diff --git a/msm8996/mm-video-v4l2/vidc/venc/inc/video_encoder_device_v4l2.h b/msm8996/mm-video-v4l2/vidc/venc/inc/video_encoder_device_v4l2.h
index ca97fc1..d4cd92c 100644
--- a/msm8996/mm-video-v4l2/vidc/venc/inc/video_encoder_device_v4l2.h
+++ b/msm8996/mm-video-v4l2/vidc/venc/inc/video_encoder_device_v4l2.h
@@ -47,6 +47,7 @@
 #define TIMEOUT 5*60*1000
 #define BIT(num) (1 << (num))
 #define MAX_HYB_HIERP_LAYERS 6
+#define MAX_AVC_HP_LAYERS (4)
 #define MAX_V4L2_BUFS 64 //VB2_MAX_FRAME
 
 enum hier_type {
@@ -237,6 +238,19 @@
    unsigned int nHpLayers;
 };
 
+struct msm_venc_temporal_layers {
+    enum hier_type hier_mode;
+    OMX_U32 nMaxLayers;
+    OMX_U32 nMaxBLayers;
+    OMX_U32 nPLayers;
+    OMX_U32 nBLayers;
+    OMX_BOOL bIsBitrateRatioValid;
+    // cumulative ratio: eg [25, 50, 75, 100] means [L0=25%, L1=25%, L2=25%, L3=25%]
+    OMX_U32 nTemporalLayerBitrateRatio[OMX_VIDEO_ANDROID_MAXTEMPORALLAYERS];
+    // Layerwise ratio: eg [L0=25%, L1=25%, L2=25%, L3=25%]
+    OMX_U32 nTemporalLayerBitrateFraction[OMX_VIDEO_ANDROID_MAXTEMPORALLAYERS];
+};
+
 enum v4l2_ports {
     CAPTURE_PORT,
     OUTPUT_PORT,
@@ -347,6 +361,8 @@
         bool venc_get_vqzip_sei_info(OMX_U32 *enabled);
         bool venc_get_peak_bitrate(OMX_U32 *peakbitrate);
         bool venc_get_batch_size(OMX_U32 *size);
+        bool venc_get_temporal_layer_caps(OMX_U32 * /*nMaxLayers*/,
+                OMX_U32 * /*nMaxBLayers*/);
         bool venc_get_output_log_flag();
         bool venc_check_valid_config();
         int venc_output_log_buffers(const char *buffer_addr, int buffer_len);
@@ -455,6 +471,7 @@
         OMX_U32                             operating_rate;
         int rc_off_level;
         struct msm_venc_hybrid_hp           hybrid_hp;
+        msm_venc_temporal_layers            temporal_layers_config;
 
         bool venc_set_profile_level(OMX_U32 eProfile,OMX_U32 eLevel);
         bool venc_set_intra_period(OMX_U32 nPFrames, OMX_U32 nBFrames);
@@ -499,16 +516,17 @@
         bool venc_calibrate_gop();
         bool venc_set_vqzip_defaults();
         bool venc_validate_hybridhp_params(OMX_U32 layers, OMX_U32 bFrames, OMX_U32 count, int mode);
-        bool venc_set_max_hierp(OMX_U32 hierp_layers);
+        bool venc_set_hierp_layers(OMX_U32 hierp_layers);
         bool venc_set_baselayerid(OMX_U32 baseid);
         bool venc_set_qp(OMX_U32 nQp);
         bool venc_set_aspectratio(void *nSar);
         bool venc_set_priority(OMX_U32 priority);
         bool venc_set_session_priority(OMX_U32 priority);
         bool venc_set_operatingrate(OMX_U32 rate);
-        bool venc_set_layer_bitrates(QOMX_EXTNINDEX_VIDEO_HYBRID_HP_MODE* hpmode);
+        bool venc_set_layer_bitrates(OMX_U32 *pLayerBitrates, OMX_U32 numLayers);
         bool venc_set_roi_qp_info(OMX_QTI_VIDEO_CONFIG_ROIINFO *roiInfo);
-
+        OMX_ERRORTYPE venc_set_temporal_layers(OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERTYPE *pTemporalParams);
+        OMX_ERRORTYPE venc_set_temporal_layers_internal();
 #ifdef MAX_RES_1080P
         OMX_U32 pmem_free();
         OMX_U32 pmem_allocate(OMX_U32 size, OMX_U32 alignment, OMX_U32 count);
diff --git a/msm8996/mm-video-v4l2/vidc/venc/src/omx_video_base.cpp b/msm8996/mm-video-v4l2/vidc/venc/src/omx_video_base.cpp
index fcaaa99..b95fabd 100644
--- a/msm8996/mm-video-v4l2/vidc/venc/src/omx_video_base.cpp
+++ b/msm8996/mm-video-v4l2/vidc/venc/src/omx_video_base.cpp
@@ -2068,6 +2068,19 @@
                 memcpy(pParam, &m_sSar, sizeof(m_sSar));
                 break;
             }
+        case OMX_IndexParamAndroidVideoTemporalLayers:
+            {
+                VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERTYPE);
+                OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERTYPE *pLayerInfo =
+                        reinterpret_cast<OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERTYPE*>(paramData);
+                if (!dev_get_temporal_layer_caps(&m_sParamTemporalLayers.nTemporalLayerCountMax,
+                        &m_sParamTemporalLayers.nTemporalBLayerCountMax)) {
+                    DEBUG_PRINT_ERROR("Failed to get temporal layer capabilities");
+                    eRet = OMX_ErrorHardware;
+                }
+                memcpy(pLayerInfo, &m_sParamTemporalLayers, sizeof(m_sParamTemporalLayers));
+                break;
+            }
         case OMX_IndexParamVideoSliceFMO:
         default:
             {
@@ -2191,13 +2204,13 @@
                 }
                 break;
             }
-       case OMX_QcomIndexConfigMaxHierPLayers:
+       case OMX_QcomIndexConfigNumHierPLayers:
            {
-                VALIDATE_OMX_PARAM_DATA(configData, QOMX_EXTNINDEX_VIDEO_MAX_HIER_P_LAYERS);
-               QOMX_EXTNINDEX_VIDEO_MAX_HIER_P_LAYERS* pParam =
-                   reinterpret_cast<QOMX_EXTNINDEX_VIDEO_MAX_HIER_P_LAYERS*>(configData);
-               DEBUG_PRINT_LOW("get_config: OMX_QcomIndexConfigMaxHierPLayers");
-               memcpy(pParam, &m_sMaxHPlayers, sizeof(m_sMaxHPlayers));
+                VALIDATE_OMX_PARAM_DATA(configData, QOMX_EXTNINDEX_VIDEO_HIER_P_LAYERS);
+               QOMX_EXTNINDEX_VIDEO_HIER_P_LAYERS* pParam =
+                   reinterpret_cast<QOMX_EXTNINDEX_VIDEO_HIER_P_LAYERS*>(configData);
+               DEBUG_PRINT_LOW("get_config: OMX_QcomIndexConfigNumHierPLayers");
+               memcpy(pParam, &m_sHPlayers, sizeof(m_sHPlayers));
                break;
            }
        case OMX_QcomIndexConfigQp:
@@ -2227,6 +2240,16 @@
                memcpy(pParam, &m_sConfigIntraRefresh, sizeof(m_sConfigIntraRefresh));
                break;
            }
+        case OMX_IndexConfigAndroidVideoTemporalLayers:
+            {
+                VALIDATE_OMX_PARAM_DATA(configData, OMX_VIDEO_CONFIG_ANDROID_TEMPORALLAYERTYPE);
+                OMX_VIDEO_CONFIG_ANDROID_TEMPORALLAYERTYPE *layerConfig =
+                        (OMX_VIDEO_CONFIG_ANDROID_TEMPORALLAYERTYPE *)configData;
+                DEBUG_PRINT_LOW("get_config: OMX_IndexConfigAndroidVideoTemporalLayers");
+                memcpy(configData, &m_sConfigTemporalLayers, sizeof(m_sConfigTemporalLayers));
+                break;
+            }
+
         default:
             DEBUG_PRINT_ERROR("ERROR: unsupported index %d", (int) configIndex);
             return OMX_ErrorUnsupportedIndex;
@@ -2303,7 +2326,7 @@
     }
 
     if (extn_equals(paramName, "OMX.QCOM.index.config.video.hierplayers")) {
-        *indexType = (OMX_INDEXTYPE)OMX_QcomIndexConfigMaxHierPLayers;
+        *indexType = (OMX_INDEXTYPE)OMX_QcomIndexConfigNumHierPLayers;
         return OMX_ErrorNone;
     }
 
diff --git a/msm8996/mm-video-v4l2/vidc/venc/src/omx_video_encoder.cpp b/msm8996/mm-video-v4l2/vidc/venc/src/omx_video_encoder.cpp
index fb9ec59..b023bbd 100644
--- a/msm8996/mm-video-v4l2/vidc/venc/src/omx_video_encoder.cpp
+++ b/msm8996/mm-video-v4l2/vidc/venc/src/omx_video_encoder.cpp
@@ -1,5 +1,5 @@
 /*--------------------------------------------------------------------------
-Copyright (c) 2010-2015, The Linux Foundation. All rights reserved.
+Copyright (c) 2010-2016, The Linux Foundation. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
@@ -544,6 +544,9 @@
     m_sMBIStatistics.nPortIndex = (OMX_U32) PORT_INDEX_OUT;
     m_sMBIStatistics.eMBIStatisticsType = QOMX_MBI_STATISTICS_MODE_DEFAULT;
 
+    OMX_INIT_STRUCT(&m_sParamTemporalLayers, OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERTYPE);
+    OMX_INIT_STRUCT(&m_sConfigTemporalLayers, OMX_VIDEO_CONFIG_ANDROID_TEMPORALLAYERTYPE);
+
     m_state                   = OMX_StateLoaded;
     m_sExtraData = 0;
 
@@ -1613,6 +1616,25 @@
                 }
                 break;
             }
+        case OMX_IndexParamAndroidVideoTemporalLayers:
+            {
+                VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERTYPE);
+                if (!handle->venc_set_param(paramData,
+                        (OMX_INDEXTYPE)OMX_IndexParamAndroidVideoTemporalLayers)) {
+                    DEBUG_PRINT_ERROR("Failed to configure temporal layers");
+                    return OMX_ErrorUnsupportedSetting;
+                }
+                // save the actual configuration applied
+                memcpy(&m_sParamTemporalLayers, paramData, sizeof(m_sParamTemporalLayers));
+                // keep the config data in sync
+                m_sConfigTemporalLayers.nTemporalBLayerCountActual = m_sParamTemporalLayers.nTemporalBLayerCountActual;
+                m_sConfigTemporalLayers.nTemporalPLayerCountActual = m_sParamTemporalLayers.nTemporalPLayerCountActual;
+                m_sConfigTemporalLayers.bTemporalLayerBitrateRatioSpecified = m_sParamTemporalLayers.bTemporalLayerBitrateRatioSpecified;
+                memcpy(&m_sConfigTemporalLayers.nTemporalLayerBitrateRatio[0],
+                        &m_sParamTemporalLayers.nTemporalLayerBitrateRatio[0],
+                        OMX_VIDEO_ANDROID_MAXTEMPORALLAYERS * sizeof(OMX_U32));
+                break;
+            }
         case OMX_IndexParamVideoSliceFMO:
         default:
             {
@@ -1971,16 +1993,16 @@
                 }
                 break;
             }
-        case OMX_QcomIndexConfigMaxHierPLayers:
+        case OMX_QcomIndexConfigNumHierPLayers:
         {
-            VALIDATE_OMX_PARAM_DATA(configData, QOMX_EXTNINDEX_VIDEO_MAX_HIER_P_LAYERS);
-            QOMX_EXTNINDEX_VIDEO_MAX_HIER_P_LAYERS* pParam =
-                (QOMX_EXTNINDEX_VIDEO_MAX_HIER_P_LAYERS*)configData;
-            if (!handle->venc_set_config(pParam, (OMX_INDEXTYPE)OMX_QcomIndexConfigMaxHierPLayers)) {
-                DEBUG_PRINT_ERROR("ERROR: Setting OMX_QcomIndexConfigMaxHierPLayers failed");
+            VALIDATE_OMX_PARAM_DATA(configData, QOMX_EXTNINDEX_VIDEO_HIER_P_LAYERS);
+            QOMX_EXTNINDEX_VIDEO_HIER_P_LAYERS* pParam =
+                (QOMX_EXTNINDEX_VIDEO_HIER_P_LAYERS*)configData;
+            if (!handle->venc_set_config(pParam, (OMX_INDEXTYPE)OMX_QcomIndexConfigNumHierPLayers)) {
+                DEBUG_PRINT_ERROR("ERROR: Setting OMX_QcomIndexConfigNumHierPLayers failed");
                 return OMX_ErrorUnsupportedSetting;
             }
-            memcpy(&m_sMaxHPlayers, pParam, sizeof(m_sMaxHPlayers));
+            memcpy(&m_sHPlayers, pParam, sizeof(m_sHPlayers));
             break;
         }
         case OMX_QcomIndexConfigBaseLayerId:
@@ -2054,6 +2076,12 @@
                 }
                break;
            }
+        case OMX_IndexConfigAndroidVideoTemporalLayers:
+            {
+                VALIDATE_OMX_PARAM_DATA(configData, OMX_VIDEO_CONFIG_ANDROID_TEMPORALLAYERTYPE);
+                DEBUG_PRINT_ERROR("Setting/modifying Temporal layers at run-time is not supported !");
+                return OMX_ErrorUnsupportedSetting;
+            }
         default:
             DEBUG_PRINT_ERROR("ERROR: unsupported index %d", (int) configIndex);
             break;
@@ -2270,6 +2298,11 @@
 #endif
 }
 
+bool omx_venc::dev_get_temporal_layer_caps(OMX_U32 *nMaxLayers,
+        OMX_U32 *nMaxBLayers) {
+    return handle->venc_get_temporal_layer_caps(nMaxLayers, nMaxBLayers);
+}
+
 bool omx_venc::dev_loaded_start()
 {
     return handle->venc_loaded_start();
diff --git a/msm8996/mm-video-v4l2/vidc/venc/src/video_encoder_device_v4l2.cpp b/msm8996/mm-video-v4l2/vidc/venc/src/video_encoder_device_v4l2.cpp
index c5ca471..ff47ab7 100644
--- a/msm8996/mm-video-v4l2/vidc/venc/src/video_encoder_device_v4l2.cpp
+++ b/msm8996/mm-video-v4l2/vidc/venc/src/video_encoder_device_v4l2.cpp
@@ -266,6 +266,7 @@
     memset(&hybrid_hp, 0, sizeof(hybrid_hp));
     sess_priority.priority = 1;
     operating_rate = 0;
+    memset(&temporal_layers_config, 0x0, sizeof(temporal_layers_config));
 
     char property_value[PROPERTY_VALUE_MAX] = {0};
     property_get("vidc.enc.log.in", property_value, "0");
@@ -2284,6 +2285,15 @@
                 }
                 break;
             }
+        case OMX_IndexParamAndroidVideoTemporalLayers:
+            {
+                if (venc_set_temporal_layers(
+                        (OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERTYPE*)paramData) != OMX_ErrorNone) {
+                    DEBUG_PRINT_ERROR("set_param: Failed to configure temporal layers");
+                    return false;
+                }
+                break;
+            }
         case OMX_IndexParamVideoSliceFMO:
         default:
             DEBUG_PRINT_ERROR("ERROR: Unsupported parameter in venc_set_param: %u",
@@ -2514,13 +2524,13 @@
                 }
                 break;
             }
-        case OMX_QcomIndexConfigMaxHierPLayers:
+        case OMX_QcomIndexConfigNumHierPLayers:
             {
-                QOMX_EXTNINDEX_VIDEO_MAX_HIER_P_LAYERS *pParam =
-                    (QOMX_EXTNINDEX_VIDEO_MAX_HIER_P_LAYERS *) configData;
-                DEBUG_PRINT_LOW("venc_set_config: OMX_QcomIndexConfigMaxHierPLayers");
-                if (venc_set_max_hierp(pParam->nMaxHierLayers) == false) {
-                    DEBUG_PRINT_ERROR("Failed to set OMX_QcomIndexConfigMaxHierPLayers");
+                QOMX_EXTNINDEX_VIDEO_HIER_P_LAYERS *pParam =
+                    (QOMX_EXTNINDEX_VIDEO_HIER_P_LAYERS *) configData;
+                DEBUG_PRINT_LOW("venc_set_config: OMX_QcomIndexConfigNumHierPLayers");
+                if (venc_set_hierp_layers(pParam->nNumHierLayers) == false) {
+                    DEBUG_PRINT_ERROR("Failed to set OMX_QcomIndexConfigNumHierPLayers");
                     return false;
                 }
                 break;
@@ -2535,6 +2545,11 @@
                 }
                 break;
             }
+        case OMX_IndexParamAndroidVideoTemporalLayers:
+            {
+                DEBUG_PRINT_ERROR("TemporalLayer: Changing layer-configuration dynamically is not supported!");
+                return false;
+            }
         case OMX_QcomIndexConfigQp:
             {
                 OMX_SKYPE_VIDEO_CONFIG_QP* pParam =
@@ -2785,6 +2800,26 @@
     if (vqzip_sei_info.enabled && !venc_set_vqzip_defaults())
         return 1;
 
+    // re-configure the temporal layers as RC-mode and key-frame interval
+    // might have changed since the client last configured the layers.
+    if (temporal_layers_config.nPLayers) {
+        if (venc_set_temporal_layers_internal() != OMX_ErrorNone) {
+            DEBUG_PRINT_ERROR("Re-configuring temporal layers failed !");
+        } else {
+            // request buffers on capture port again since internal (scratch)-
+            // buffer requirements may change (i.e if we switch from non-hybrid
+            // to hybrid mode and vice-versa)
+            struct v4l2_requestbuffers bufreq;
+
+            bufreq.memory = V4L2_MEMORY_USERPTR;
+            bufreq.count = m_sOutput_buff_property.actualcount;
+            bufreq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+            if (ioctl(m_nDriver_fd, VIDIOC_REQBUFS, &bufreq)) {
+                DEBUG_PRINT_ERROR("Request bufs failed while reconfiguring layers");
+            }
+        }
+    }
+
     venc_config_print();
 
     if(resume_in_stopped){
@@ -2854,11 +2889,28 @@
     }
 }
 
+static const char *codec_as_string(unsigned long codec) {
+    switch (codec) {
+    case V4L2_PIX_FMT_H264:
+        return "H264";
+    case V4L2_PIX_FMT_MPEG4:
+        return "MPEG4";
+    case V4L2_PIX_FMT_H263:
+        return "H263";
+    case V4L2_PIX_FMT_HEVC:
+        return "HEVC";
+    case V4L2_PIX_FMT_VP8:
+        return "VP8";
+    default:
+        return "UNKOWN";
+    }
+}
+
 void venc_dev::venc_config_print()
 {
 
-    DEBUG_PRINT_HIGH("ENC_CONFIG: Codec: %ld, Profile %ld, level : %ld",
-            m_sVenc_cfg.codectype, codec_profile.profile, profile_level.level);
+    DEBUG_PRINT_HIGH("ENC_CONFIG: Codec: %s, Profile %ld, level : %ld",
+            codec_as_string(m_sVenc_cfg.codectype), codec_profile.profile, profile_level.level);
 
     DEBUG_PRINT_HIGH("ENC_CONFIG: Input Width: %ld, Height:%ld, Fps: %ld",
             m_sVenc_cfg.input_width, m_sVenc_cfg.input_height,
@@ -2897,16 +2949,29 @@
     DEBUG_PRINT_HIGH("ENC_CONFIG: LTR Enabled: %d, Count: %d",
             ltrinfo.enabled, ltrinfo.count);
 
-    DEBUG_PRINT_HIGH("ENC_CONFIG: Hier layers: %d, Hier Mode: %s VPX_ErrorResilience: %d",
-            hier_layers.numlayers, hiermode_string(hier_layers.hier_mode), vpx_err_resilience.enable);
+    if (temporal_layers_config.nPLayers) {
+        DEBUG_PRINT_HIGH("ENC_CONFIG: Temporal layers: P-layers: %u, B-layers: %u, Adjusted I-frame-interval: %lu",
+                temporal_layers_config.nPLayers, temporal_layers_config.nBLayers,
+                intra_period.num_pframes + intra_period.num_bframes + 1);
 
-    DEBUG_PRINT_HIGH("ENC_CONFIG: Hybrid_HP PARAMS: Layers: %d, Frame Interval : %d, MinQP: %d, Max_QP: %d",
-            hybrid_hp.nHpLayers, hybrid_hp.nKeyFrameInterval, hybrid_hp.nMinQuantizer, hybrid_hp.nMaxQuantizer);
+        for (OMX_U32 l = 0; temporal_layers_config.bIsBitrateRatioValid
+                && (l < temporal_layers_config.nPLayers + temporal_layers_config.nBLayers); ++l) {
+            DEBUG_PRINT_HIGH("ENC_CONFIG: Temporal layers: layer[%d] bitrate %% = %u%%",
+                    l, temporal_layers_config.nTemporalLayerBitrateFraction[l]);
+        }
+    } else {
 
-    DEBUG_PRINT_HIGH("ENC_CONFIG: Hybrid_HP PARAMS: Layer0: %d, Layer1: %d, Later2: %d, Layer3: %d, Layer4: %d, Layer5: %d",
-            hybrid_hp.nTemporalLayerBitrateRatio[0], hybrid_hp.nTemporalLayerBitrateRatio[1],
-            hybrid_hp.nTemporalLayerBitrateRatio[2], hybrid_hp.nTemporalLayerBitrateRatio[3],
-            hybrid_hp.nTemporalLayerBitrateRatio[4], hybrid_hp.nTemporalLayerBitrateRatio[5]);
+        DEBUG_PRINT_HIGH("ENC_CONFIG: Hier layers: %d, Hier Mode: %s VPX_ErrorResilience: %d",
+                hier_layers.numlayers, hiermode_string(hier_layers.hier_mode), vpx_err_resilience.enable);
+
+        DEBUG_PRINT_HIGH("ENC_CONFIG: Hybrid_HP PARAMS: Layers: %d, Frame Interval : %d, MinQP: %d, Max_QP: %d",
+                hybrid_hp.nHpLayers, hybrid_hp.nKeyFrameInterval, hybrid_hp.nMinQuantizer, hybrid_hp.nMaxQuantizer);
+
+        DEBUG_PRINT_HIGH("ENC_CONFIG: Hybrid_HP PARAMS: Layer0: %d, Layer1: %d, Later2: %d, Layer3: %d, Layer4: %d, Layer5: %d",
+                hybrid_hp.nTemporalLayerBitrateRatio[0], hybrid_hp.nTemporalLayerBitrateRatio[1],
+                hybrid_hp.nTemporalLayerBitrateRatio[2], hybrid_hp.nTemporalLayerBitrateRatio[3],
+                hybrid_hp.nTemporalLayerBitrateRatio[4], hybrid_hp.nTemporalLayerBitrateRatio[5]);
+    }
 
     DEBUG_PRINT_HIGH("ENC_CONFIG: Performace level: %d", performance_level.perflevel);
 
@@ -3735,6 +3800,13 @@
     if (type == QOMX_HIERARCHICALCODING_P) {
         // Reduce layer count by 1 before sending to driver. This avoids
         // driver doing the same in multiple places.
+        control.id = V4L2_CID_MPEG_VIDC_VIDEO_MAX_HIERP_LAYERS;
+        control.value = num_layers - 1;
+        DEBUG_PRINT_HIGH("Set MAX Hier P num layers: %u", (unsigned int)num_layers);
+        if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) {
+            DEBUG_PRINT_ERROR("Request to set MAX Hier P num layers failed");
+            return false;
+        }
         control.id = V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS;
         control.value = num_layers - 1;
         DEBUG_PRINT_HIGH("Set Hier P num layers: %u", (unsigned int)num_layers);
@@ -4855,6 +4927,25 @@
         }
     }
 
+    // Configure layer-wise bitrate if temporal layers are enabled and layer-wise distribution
+    //  has been specified
+    if (temporal_layers_config.bIsBitrateRatioValid && temporal_layers_config.nPLayers) {
+        OMX_U32 layerBitrates[OMX_VIDEO_MAX_HP_LAYERS] = {0},
+                numLayers = temporal_layers_config.nPLayers + temporal_layers_config.nBLayers;
+
+        DEBUG_PRINT_LOW("TemporalLayer: configuring layerwise bitrate");
+        for (OMX_U32 i = 0; i < numLayers; ++i) {
+            layerBitrates[i] =
+                    (temporal_layers_config.nTemporalLayerBitrateFraction[i] * bitrate.target_bitrate) / 100;
+            DEBUG_PRINT_LOW("TemporalLayer: layer[%u] ratio=%u%% bitrate=%u(of %ld)",
+                    i, temporal_layers_config.nTemporalLayerBitrateFraction[i],
+                    layerBitrates[i], bitrate.target_bitrate);
+        }
+        if (!venc_set_layer_bitrates((OMX_U32 *)layerBitrates, numLayers)) {
+            return false;
+        }
+    }
+
     return true;
 }
 
@@ -4987,6 +5078,9 @@
     nPframes = intra_period.num_pframes;
     nBframes = intra_period.num_bframes;
     nLayers = hier_layers.numlayers;
+    if (temporal_layers_config.nPLayers) {
+        nLayers = temporal_layers_config.nPLayers + temporal_layers_config.nBLayers;
+    }
 
     if (!nPframes && nLayers) {
         DEBUG_PRINT_ERROR("nPframes should be non-zero when nLayers are present\n");
@@ -5071,10 +5165,10 @@
     return true;
 }
 
-bool venc_dev::venc_set_layer_bitrates(QOMX_EXTNINDEX_VIDEO_HYBRID_HP_MODE* hpmode)
+bool venc_dev::venc_set_layer_bitrates(OMX_U32 *layerBitrate, OMX_U32 numLayers)
 {
     DEBUG_PRINT_LOW("venc_set_layer_bitrates");
-    struct v4l2_ext_control ctrl[MAX_HYB_HIERP_LAYERS];
+    struct v4l2_ext_control ctrl[OMX_VIDEO_ANDROID_MAXTEMPORALLAYERS];
     struct v4l2_ext_controls controls;
     int rc = 0;
     OMX_U32 i;
@@ -5084,17 +5178,16 @@
         return false;
     }
 
-    for (i = 0; i < hpmode->nHpLayers; i++) {
-        if (!hpmode->nTemporalLayerBitrateRatio[i]) {
-            DEBUG_PRINT_ERROR("invalid bitrate settings for layer %d\n", i);
+    for (OMX_U32 i = 0; i < numLayers && i < OMX_VIDEO_ANDROID_MAXTEMPORALLAYERS; ++i) {
+        if (!layerBitrate[i]) {
+            DEBUG_PRINT_ERROR("Invalid bitrate settings for layer %d", i);
             return false;
         } else {
             ctrl[i].id = V4L2_CID_MPEG_VIDC_VENC_PARAM_LAYER_BITRATE;
-            ctrl[i].value = hpmode->nTemporalLayerBitrateRatio[i];
-            hybrid_hp.nTemporalLayerBitrateRatio[i] =  hpmode->nTemporalLayerBitrateRatio[i];
+            ctrl[i].value = layerBitrate[i];
         }
     }
-    controls.count = hpmode->nHpLayers;
+    controls.count = numLayers;
     controls.ctrl_class = V4L2_CTRL_CLASS_MPEG;
     controls.controls = ctrl;
 
@@ -5104,13 +5197,7 @@
         return false;
     }
 
-    hybrid_hp.nHpLayers = hpmode->nHpLayers;
-
-    DEBUG_PRINT_LOW("Success in setting Layer wise bitrate: %d, %d, %d, %d, %d, %d",
-        hpmode->nTemporalLayerBitrateRatio[0],hpmode->nTemporalLayerBitrateRatio[1],
-        hpmode->nTemporalLayerBitrateRatio[2],hpmode->nTemporalLayerBitrateRatio[3],
-        hpmode->nTemporalLayerBitrateRatio[4],hpmode->nTemporalLayerBitrateRatio[5]);
-
+    DEBUG_PRINT_LOW("Layerwise bitrate configured successfully");
     return true;
 }
 
@@ -5210,13 +5297,21 @@
         session_qp_values.maxqp = hhp->nMaxQuantizer;
     }
 
-    if (!venc_set_layer_bitrates(hhp)) {
+    OMX_U32 layerBitrates[OMX_VIDEO_MAX_HP_LAYERS] = {0};
+    for (OMX_U32 i = 0; i < hhp->nHpLayers; i++) {
+        layerBitrates[i] = hhp->nTemporalLayerBitrateRatio[i];
+        hybrid_hp.nTemporalLayerBitrateRatio[i] = hhp->nTemporalLayerBitrateRatio[i];
+        DEBUG_PRINT_LOW("Setting Layer[%u] bitrate = %u", i, layerBitrates[i]);
+    }
+    if (!venc_set_layer_bitrates((OMX_U32 *)layerBitrates, hhp->nHpLayers)) {
        DEBUG_PRINT_ERROR("Failed to set Layer wise bitrate: %d, %d, %d, %d, %d, %d",
             hhp->nTemporalLayerBitrateRatio[0],hhp->nTemporalLayerBitrateRatio[1],
             hhp->nTemporalLayerBitrateRatio[2],hhp->nTemporalLayerBitrateRatio[3],
             hhp->nTemporalLayerBitrateRatio[4],hhp->nTemporalLayerBitrateRatio[5]);
        return false;
     }
+    hybrid_hp.nHpLayers = hhp->nHpLayers;
+
     // Set this or else the layer0 bitrate will be overwritten by
     // default value in component
     m_sVenc_cfg.targetbitrate  = bitrate.target_bitrate = hhp->nTemporalLayerBitrateRatio[0];
@@ -5625,21 +5720,21 @@
     return true;
 }
 
-bool venc_dev::venc_set_max_hierp(OMX_U32 hierp_layers)
+bool venc_dev::venc_set_hierp_layers(OMX_U32 hierp_layers)
 {
     struct v4l2_control control;
     if (hierp_layers && (hier_layers.hier_mode == HIER_P) &&
             (hierp_layers <= hier_layers.numlayers)) {
-        control.id = V4L2_CID_MPEG_VIDC_VIDEO_MAX_HIERP_LAYERS;
-        control.value = hierp_layers;
-        DEBUG_PRINT_LOW("Going to set V4L2_CID_MPEG_VIDC_VIDEO_MAX_HIERP_LAYERS");
+        control.id = V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS;
+        control.value = hierp_layers - 1;
+        DEBUG_PRINT_LOW("Going to set V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS");
         if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) {
-            DEBUG_PRINT_ERROR("Failed to set MAX_HIERP_LAYERS");
+            DEBUG_PRINT_ERROR("Failed to set HIERP_LAYERS");
             return false;
         }
         return true;
     } else {
-        DEBUG_PRINT_ERROR("Invalid layers set for MAX_HIERP_LAYERS: %d",
+        DEBUG_PRINT_ERROR("Invalid layers set for HIERP_LAYERS: %d",
                 hierp_layers);
         return false;
     }
@@ -5815,6 +5910,216 @@
     return true;
 }
 
+bool venc_dev::venc_get_temporal_layer_caps(OMX_U32 *nMaxLayers,
+        OMX_U32 *nMaxBLayers) {
+
+    // no B-layers for all cases
+    temporal_layers_config.nMaxBLayers = 0;
+    temporal_layers_config.nMaxLayers = 1;
+
+    if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264
+            || m_sVenc_cfg.codectype == V4L2_PIX_FMT_HEVC) {
+        temporal_layers_config.nMaxLayers = MAX_HYB_HIERP_LAYERS; // TODO: get this count from codec
+    } else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_VP8) {
+        temporal_layers_config.nMaxLayers = 4; // TODO: get this count from codec
+    }
+
+    *nMaxLayers = temporal_layers_config.nMaxLayers;
+    *nMaxBLayers = temporal_layers_config.nMaxBLayers;
+    return true;
+}
+
+OMX_ERRORTYPE venc_dev::venc_set_temporal_layers(
+        OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERTYPE *pTemporalParams) {
+
+    if (!(m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264
+            || m_sVenc_cfg.codectype == V4L2_PIX_FMT_HEVC
+            || m_sVenc_cfg.codectype == V4L2_PIX_FMT_VP8)) {
+        DEBUG_PRINT_ERROR("Temporal layers not supported for %s", codec_as_string(m_sVenc_cfg.codectype));
+        return OMX_ErrorUnsupportedSetting;
+    }
+
+    if (pTemporalParams->nTemporalBLayerCountActual > temporal_layers_config.nMaxBLayers) {
+        DEBUG_PRINT_ERROR("TemporalLayer: Requested B-layers(%u) exceeds supported max(%u)",
+                pTemporalParams->nTemporalBLayerCountActual, temporal_layers_config.nMaxBLayers);
+        return OMX_ErrorBadParameter;
+    } else if (pTemporalParams->nTemporalPLayerCountActual + pTemporalParams->nTemporalBLayerCountActual >
+             temporal_layers_config.nMaxLayers) {
+        DEBUG_PRINT_ERROR("TemporalLayer: Requested layers(%u) exceeds supported max(%u)",
+                pTemporalParams->nTemporalPLayerCountActual + pTemporalParams->nTemporalBLayerCountActual,
+                temporal_layers_config.nMaxLayers);
+        return OMX_ErrorBadParameter;
+    }
+
+    // For AVC, if B-layer has not been configured and RC mode is VBR (camcorder),
+    // use hybrid-HP for best results
+    bool isAvc = m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264;
+    bool isVBR = rate_ctrl.rcmode == RC_VBR_CFR || rate_ctrl.rcmode == RC_VBR_VFR;
+    bool bUseHybridMode = isAvc && pTemporalParams->nTemporalBLayerCountActual == 0 && isVBR;
+
+    // If there are more than 3 layers configured for AVC, normal HP will not work. force hybrid
+    bUseHybridMode |= (isAvc && pTemporalParams->nTemporalPLayerCountActual > MAX_AVC_HP_LAYERS);
+
+    DEBUG_PRINT_LOW("TemporalLayer: RC-mode = %ld : %s hybrid-HP",
+            rate_ctrl.rcmode, bUseHybridMode ? "enable" : "disable");
+
+    if (bUseHybridMode &&
+            !venc_validate_hybridhp_params(pTemporalParams->nTemporalPLayerCountActual,
+                pTemporalParams->nTemporalBLayerCountActual,
+                0 /* LTR count */, (int) HIER_P_HYBRID)) {
+        bUseHybridMode = false;
+        DEBUG_PRINT_ERROR("Failed to validate Hybrid HP. Will try fallback to normal HP");
+    }
+
+    if (intra_period.num_bframes) {
+        DEBUG_PRINT_ERROR("TemporalLayer: B frames are not supported with layers");
+        return OMX_ErrorUnsupportedSetting;
+    }
+
+    if (!venc_set_intra_period(intra_period.num_pframes, intra_period.num_bframes)) {
+        DEBUG_PRINT_ERROR("TemporalLayer : Failed to set Intra-period nP(%lu)/pB(%lu)",
+                intra_period.num_pframes, intra_period.num_bframes);
+        return OMX_ErrorUnsupportedSetting;
+    }
+
+    struct v4l2_control control;
+    // Num enhancements layers does not include the base-layer
+    control.value = pTemporalParams->nTemporalPLayerCountActual - 1;
+
+    if (bUseHybridMode) {
+        DEBUG_PRINT_LOW("TemporalLayer: Try enabling hybrid HP with %u layers", control.value);
+        control.id = V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE;
+        if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) {
+            bUseHybridMode = false;
+            DEBUG_PRINT_ERROR("Failed to set hybrid HP");
+        } else {
+            // Disable normal HP if Hybrid mode is being enabled
+            control.id = V4L2_CID_MPEG_VIDC_VIDEO_MAX_HIERP_LAYERS;
+            control.value = 0;
+            if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) {
+                DEBUG_PRINT_ERROR("Failed to set max HP layers to %u", control.value);
+                return OMX_ErrorUnsupportedSetting;
+            }
+            control.id = V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS;
+            control.value = 0;
+            if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) {
+                DEBUG_PRINT_ERROR("Failed to set HP layers to %u", control.value);
+                return OMX_ErrorUnsupportedSetting;
+            }
+        }
+    }
+
+    if (!bUseHybridMode) {
+
+        // in case of normal HP, avc encoder cannot support more than MAX_AVC_HP_LAYERS
+        if (isAvc && pTemporalParams->nTemporalPLayerCountActual > MAX_AVC_HP_LAYERS) {
+            DEBUG_PRINT_ERROR("AVC supports only up to %d layers", MAX_AVC_HP_LAYERS);
+            return OMX_ErrorUnsupportedSetting;
+        }
+
+        DEBUG_PRINT_LOW("TemporalLayer: Try enabling HP with %u layers", control.value);
+        control.id = V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS;
+        if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) {
+            DEBUG_PRINT_ERROR("Failed to set hybrid hierp/hierp");
+            return OMX_ErrorUnsupportedSetting;
+        }
+
+        // configure max layers for a session.. Okay to use current num-layers as max
+        //  since we do not plan to support dynamic changes to number of layers
+        control.id = V4L2_CID_MPEG_VIDC_VIDEO_MAX_HIERP_LAYERS;
+        control.value = pTemporalParams->nTemporalPLayerCountActual - 1;
+        if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) {
+            DEBUG_PRINT_ERROR("Failed to set max HP layers to %u", control.value);
+            return OMX_ErrorUnsupportedSetting;
+
+        } else if (temporal_layers_config.hier_mode == HIER_P_HYBRID) {
+            // Disable hybrid mode if it was enabled already
+            DEBUG_PRINT_LOW("TemporalLayer: disable hybrid HP (normal-HP preferred)");
+            control.id = V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE;
+            control.value = 0;
+            if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) {
+                DEBUG_PRINT_ERROR("Failed to disable hybrid HP !");
+                return OMX_ErrorUnsupportedSetting;
+            }
+        }
+    }
+
+    // SVC-NALs to indicate layer-id in case of H264 needs explicit enablement..
+    if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264) {
+        DEBUG_PRINT_LOW("TemporalLayer: Enable H264_SVC_NAL");
+        control.id = V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC;
+        control.value = V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC_ENABLED;
+        if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) {
+            DEBUG_PRINT_ERROR("Failed to enable SVC_NAL");
+            return OMX_ErrorUnsupportedSetting;
+        }
+    }
+
+    temporal_layers_config.hier_mode = bUseHybridMode ? HIER_P_HYBRID : HIER_P;
+    temporal_layers_config.nPLayers = pTemporalParams->nTemporalPLayerCountActual;
+    temporal_layers_config.nBLayers = 0;
+
+    temporal_layers_config.bIsBitrateRatioValid = OMX_FALSE;
+    if (pTemporalParams->bTemporalLayerBitrateRatioSpecified == OMX_FALSE) {
+        DEBUG_PRINT_LOW("TemporalLayer: layerwise bitrate ratio not specified. Will use cumulative..");
+        return OMX_ErrorNone;
+    }
+    DEBUG_PRINT_LOW("TemporalLayer: layerwise bitrate ratio specified");
+
+    OMX_U32 layerBitrates[OMX_VIDEO_MAX_HP_LAYERS] = {0},
+            numLayers = pTemporalParams->nTemporalPLayerCountActual + pTemporalParams->nTemporalBLayerCountActual;
+
+    OMX_U32 i = 0;
+    for (; i < numLayers; ++i) {
+        OMX_U32 previousLayersAccumulatedBitrateRatio = i == 0 ? 0 : pTemporalParams->nTemporalLayerBitrateRatio[i-1];
+        OMX_U32 currentLayerBitrateRatio = pTemporalParams->nTemporalLayerBitrateRatio[i] - previousLayersAccumulatedBitrateRatio;
+        if (previousLayersAccumulatedBitrateRatio > pTemporalParams->nTemporalLayerBitrateRatio[i]) {
+            DEBUG_PRINT_ERROR("invalid bitrate ratio for layer %d.. Will fallback to cumulative", i);
+            return OMX_ErrorBadParameter;
+        } else {
+            layerBitrates[i] = (currentLayerBitrateRatio * bitrate.target_bitrate) / 100;
+            temporal_layers_config.nTemporalLayerBitrateRatio[i] = pTemporalParams->nTemporalLayerBitrateRatio[i];
+            temporal_layers_config.nTemporalLayerBitrateFraction[i] = currentLayerBitrateRatio;
+            DEBUG_PRINT_LOW("TemporalLayer: layer[%u] ratio=%u%% bitrate=%u(of %ld)",
+                    i, currentLayerBitrateRatio, layerBitrates[i], bitrate.target_bitrate);
+        }
+    }
+
+    temporal_layers_config.bIsBitrateRatioValid = OMX_TRUE;
+
+    // Setting layerwise bitrate makes sense only if target bitrate is configured, else defer until later..
+    if (bitrate.target_bitrate > 0) {
+        if (!venc_set_layer_bitrates((OMX_U32 *)layerBitrates, numLayers)) {
+            return OMX_ErrorUnsupportedSetting;
+        }
+    } else {
+        DEBUG_PRINT_HIGH("Defer setting layerwise bitrate since target bitrate is not yet set");
+    }
+
+    return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE venc_dev::venc_set_temporal_layers_internal() {
+    OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERTYPE pTemporalParams;
+    memset(&pTemporalParams, 0x0, sizeof(OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERTYPE));
+
+    if (!temporal_layers_config.nPLayers) {
+        return OMX_ErrorNone;
+    }
+    pTemporalParams.nTemporalLayerCountMax = temporal_layers_config.nMaxLayers;
+    pTemporalParams.nTemporalBLayerCountActual = temporal_layers_config.nMaxBLayers;
+    pTemporalParams.nTemporalPLayerCountActual = temporal_layers_config.nPLayers;
+    pTemporalParams.nTemporalBLayerCountActual = temporal_layers_config.nBLayers;
+    pTemporalParams.bTemporalLayerBitrateRatioSpecified = temporal_layers_config.bIsBitrateRatioValid;
+    if (temporal_layers_config.bIsBitrateRatioValid == OMX_TRUE) {
+        for (OMX_U32 i = 0; i < temporal_layers_config.nPLayers + temporal_layers_config.nBLayers; ++i) {
+            pTemporalParams.nTemporalLayerBitrateRatio[i] =
+                    temporal_layers_config.nTemporalLayerBitrateRatio[i];
+        }
+    }
+    return venc_set_temporal_layers(&pTemporalParams);
+}
+
 bool venc_dev::venc_get_profile_level(OMX_U32 *eProfile,OMX_U32 *eLevel)
 {
     bool status = true;