/*===========================================================================
 * FUNCTION   : UpdateStreamBasedParameters
 *
 * DESCRIPTION: update any stream based settings from parameters
 *
 * PARAMETERS :
 *   @param   : reference to parameters object
 *
 * RETURN     : int32_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
int32_t QCameraChannel::UpdateStreamBasedParameters(QCameraParameters &param)
{
    int32_t rc = NO_ERROR;
    if (param.isPreviewFlipChanged()) {
        // try to find preview stream
        for (int i = 0; i < MAX_STREAM_NUM_IN_BUNDLE; i++) {
            if (mStreams[i] != NULL &&
                (mStreams[i]->isTypeOf(CAM_STREAM_TYPE_PREVIEW) ||
                (mStreams[i]->isOrignalTypeOf(CAM_STREAM_TYPE_PREVIEW))) ) {
                cam_stream_parm_buffer_t param_buf;
                memset(&param_buf, 0, sizeof(cam_stream_parm_buffer_t));
                param_buf.type = CAM_STREAM_PARAM_TYPE_SET_FLIP;
                param_buf.flipInfo.flip_mask = param.getFlipMode(CAM_STREAM_TYPE_PREVIEW);
                rc = mStreams[i]->setParameter(param_buf);
                if (rc != NO_ERROR) {
                    ALOGE("%s: set preview stream flip failed", __func__);
                }
            }
        }
    }
    if (param.isVideoFlipChanged()) {
        // try to find video stream
        for (int i = 0; i < MAX_STREAM_NUM_IN_BUNDLE; i++) {
            if (mStreams[i] != NULL &&
                (mStreams[i]->isTypeOf(CAM_STREAM_TYPE_VIDEO) ||
                (mStreams[i]->isOrignalTypeOf(CAM_STREAM_TYPE_VIDEO))) ) {
                cam_stream_parm_buffer_t param_buf;
                memset(&param_buf, 0, sizeof(cam_stream_parm_buffer_t));
                param_buf.type = CAM_STREAM_PARAM_TYPE_SET_FLIP;
                param_buf.flipInfo.flip_mask = param.getFlipMode(CAM_STREAM_TYPE_VIDEO);
                rc = mStreams[i]->setParameter(param_buf);
                if (rc != NO_ERROR) {
                    ALOGE("%s: set video stream flip failed", __func__);
                }
            }
        }
    }
    if (param.isSnapshotFlipChanged()) {
        // try to find snapshot/postview stream
        for (int i = 0; i < MAX_STREAM_NUM_IN_BUNDLE; i++) {
            if (mStreams[i] != NULL &&
                (mStreams[i]->isTypeOf(CAM_STREAM_TYPE_SNAPSHOT) ||
                 mStreams[i]->isOrignalTypeOf(CAM_STREAM_TYPE_SNAPSHOT) ||
                 mStreams[i]->isTypeOf(CAM_STREAM_TYPE_POSTVIEW) ||
                 mStreams[i]->isOrignalTypeOf(CAM_STREAM_TYPE_POSTVIEW) ) ) {
                cam_stream_parm_buffer_t param_buf;
                memset(&param_buf, 0, sizeof(cam_stream_parm_buffer_t));
                param_buf.type = CAM_STREAM_PARAM_TYPE_SET_FLIP;
                param_buf.flipInfo.flip_mask = param.getFlipMode(CAM_STREAM_TYPE_SNAPSHOT);
                rc = mStreams[i]->setParameter(param_buf);
                if (rc != NO_ERROR) {
                    ALOGE("%s: set snapshot stream flip failed", __func__);
                }
            }
        }
    }
    return rc;
}
/*===========================================================================
 * FUNCTION   : addReprocStreamsFromSource
 *
 * DESCRIPTION: add reprocess streams from input source channel
 *
 * PARAMETERS :
 *   @allocator      : stream related buffer allocator
 *   @config         : pp feature configuration
 *   @pSrcChannel    : ptr to input source channel that needs reprocess
 *   @minStreamBufNum: number of stream buffers needed
 *   @burstNum       : number of burst captures needed
 *   @paddingInfo    : padding information
 *   @param          : reference to parameters
 *   @contStream     : continous streaming mode or burst
 *   @offline        : configure for offline reprocessing
 *
 * RETURN     : int32_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
int32_t QCameraReprocessChannel::addReprocStreamsFromSource(QCameraAllocator& allocator,
                                                            cam_pp_feature_config_t &config,
                                                            QCameraChannel *pSrcChannel,
                                                            uint8_t minStreamBufNum,
                                                            uint32_t burstNum,
                                                            cam_padding_info_t *paddingInfo,
                                                            QCameraParameters &param,
                                                            bool contStream,
                                                            bool offline)
{
    int32_t rc = 0;
    QCameraStream *pStream = NULL;
    QCameraHeapMemory *pStreamInfoBuf = NULL;
    cam_stream_info_t *streamInfo = NULL;

    memset(mSrcStreamHandles, 0, sizeof(mSrcStreamHandles));

    for (int i = 0; i < pSrcChannel->getNumOfStreams(); i++) {
        pStream = pSrcChannel->getStreamByIndex(i);
        if (pStream != NULL) {
            if (pStream->isTypeOf(CAM_STREAM_TYPE_METADATA) ||
                pStream->isTypeOf(CAM_STREAM_TYPE_RAW)) {
                // Skip metadata&raw for reprocess now because PP module cannot handle
                // meta data&raw. May need furthur discussion if Imaginglib need meta data
                continue;
            }

            if (pStream->isTypeOf(CAM_STREAM_TYPE_POSTVIEW) ||
                pStream->isTypeOf(CAM_STREAM_TYPE_PREVIEW)) {
                // Skip postview: in non zsl case, dont want to send
                // thumbnail through reprocess.
                // Skip preview: for same reason for zsl case
                continue;
            }

            if(pStream->isTypeOf(CAM_STREAM_TYPE_PREVIEW) ||
               pStream->isTypeOf(CAM_STREAM_TYPE_POSTVIEW) ||
               pStream->isOrignalTypeOf(CAM_STREAM_TYPE_PREVIEW) ||
               pStream->isOrignalTypeOf(CAM_STREAM_TYPE_POSTVIEW)) {
                  uint32_t feature_mask = config.feature_mask;

                  if ((feature_mask & ~CAM_QCOM_FEATURE_HDR) == 0
                      && param.isHDREnabled()
                      && !param.isHDRThumbnailProcessNeeded()) {

                      // Skip thumbnail stream reprocessing in HDR
                      // if only hdr is enabled
                      continue;
                  }

                  // skip thumbnail reprocessing if not needed
                  if (!param.needThumbnailReprocess(&feature_mask)) {
                      continue;
                  }

                  //Don't do WNR for thumbnail
                  feature_mask &= ~CAM_QCOM_FEATURE_DENOISE2D;
                  if(!feature_mask) {
                    // Skip thumbnail stream reprocessing since no other
                    //reprocessing is enabled.
                      continue;
                  }
            }

            pStreamInfoBuf = allocator.allocateStreamInfoBuf(CAM_STREAM_TYPE_OFFLINE_PROC);
            if (pStreamInfoBuf == NULL) {
                ALOGE("%s: no mem for stream info buf", __func__);
                rc = NO_MEMORY;
                break;
            }

            streamInfo = (cam_stream_info_t *)pStreamInfoBuf->getPtr(0);
            memset(streamInfo, 0, sizeof(cam_stream_info_t));
            streamInfo->stream_type = CAM_STREAM_TYPE_OFFLINE_PROC;
            rc = pStream->getFormat(streamInfo->fmt);
            rc = pStream->getFrameDimension(streamInfo->dim);
            if ( contStream ) {
                streamInfo->streaming_mode = CAM_STREAMING_MODE_CONTINUOUS;
                streamInfo->num_of_burst = 0;
            } else {
                streamInfo->streaming_mode = CAM_STREAMING_MODE_BURST;
                streamInfo->num_of_burst = burstNum;
            }

            cam_stream_reproc_config_t rp_cfg;
            memset(&rp_cfg, 0, sizeof(cam_stream_reproc_config_t));
            if (offline) {
                cam_frame_len_offset_t offset;
                memset(&offset, 0, sizeof(cam_frame_len_offset_t));

                rp_cfg.pp_type = CAM_OFFLINE_REPROCESS_TYPE;
                pStream->getFormat(rp_cfg.offline.input_fmt);
                pStream->getFrameDimension(rp_cfg.offline.input_dim);
                pStream->getFrameOffset(offset);
                rp_cfg.offline.input_buf_planes.plane_info = offset;
                rp_cfg.offline.input_type = pStream->getMyType();
                //For input metadata + input buffer
                rp_cfg.offline.num_of_bufs = 2;
            } else {
                rp_cfg.pp_type = CAM_ONLINE_REPROCESS_TYPE;
                rp_cfg.online.input_stream_id = pStream->getMyServerID();
                rp_cfg.online.input_stream_type = pStream->getMyType();
            }
            streamInfo->reprocess_config = rp_cfg;
            streamInfo->reprocess_config.pp_feature_config = config;

            if (!(pStream->isTypeOf(CAM_STREAM_TYPE_SNAPSHOT) ||
                pStream->isOrignalTypeOf(CAM_STREAM_TYPE_SNAPSHOT))) {
                streamInfo->reprocess_config.pp_feature_config.feature_mask &= ~CAM_QCOM_FEATURE_CAC;
                //Don't do WNR for thumbnail
                streamInfo->reprocess_config.pp_feature_config.feature_mask &= ~CAM_QCOM_FEATURE_DENOISE2D;

                if (param.isHDREnabled()
                  && !param.isHDRThumbnailProcessNeeded()){
                    streamInfo->reprocess_config.pp_feature_config.feature_mask
                      &= ~CAM_QCOM_FEATURE_HDR;
                }
            }

            if (streamInfo->reprocess_config.pp_feature_config.feature_mask & CAM_QCOM_FEATURE_ROTATION) {
                if (streamInfo->reprocess_config.pp_feature_config.rotation == ROTATE_90 ||
                    streamInfo->reprocess_config.pp_feature_config.rotation == ROTATE_270) {
                    // rotated by 90 or 270, need to switch width and height
                    int32_t temp = streamInfo->dim.height;
                    streamInfo->dim.height = streamInfo->dim.width;
                    streamInfo->dim.width = temp;
                }
            }

            if (param.isZSLMode() &&
                (streamInfo->reprocess_config.online.input_stream_type == CAM_STREAM_TYPE_SNAPSHOT)) {
                // ZSL mode snapshot need reprocess to do the flip
                int flipMode =
                    param.getFlipMode(streamInfo->reprocess_config.online.input_stream_type);
                if (flipMode > 0) {
                    streamInfo->reprocess_config.pp_feature_config.feature_mask |= CAM_QCOM_FEATURE_FLIP;
                    streamInfo->reprocess_config.pp_feature_config.flip = flipMode;
                }
            }

            if(streamInfo->reprocess_config.pp_feature_config.feature_mask & CAM_QCOM_FEATURE_SCALE){
                //we only Scale Snapshot frame
                if(pStream->isTypeOf(CAM_STREAM_TYPE_SNAPSHOT)){
                    //also check whether rotation is needed
                    if((streamInfo->reprocess_config.pp_feature_config.feature_mask & CAM_QCOM_FEATURE_ROTATION) &&
                       (streamInfo->reprocess_config.pp_feature_config.rotation == ROTATE_90 ||
                        streamInfo->reprocess_config.pp_feature_config.rotation == ROTATE_270)){
                        //need swap
                        streamInfo->dim.width = streamInfo->reprocess_config.pp_feature_config.scale_param.output_height;
                        streamInfo->dim.height = streamInfo->reprocess_config.pp_feature_config.scale_param.output_width;
                    }else{
                        streamInfo->dim.width = streamInfo->reprocess_config.pp_feature_config.scale_param.output_width;
                        streamInfo->dim.height = streamInfo->reprocess_config.pp_feature_config.scale_param.output_height;
                    }
                }
                CDBG_HIGH("%s: stream width=%d, height=%d.", __func__, streamInfo->dim.width, streamInfo->dim.height);
            }

            // save source stream handler
            mSrcStreamHandles[m_numStreams] = pStream->getMyHandle();

            // add reprocess stream
            rc = addStream(allocator,
                           pStreamInfoBuf, minStreamBufNum,
                           paddingInfo,
                           NULL, NULL, false);
            if (rc != NO_ERROR) {
                ALOGE("%s: add reprocess stream failed, ret = %d", __func__, rc);
                break;
            }
        }
    }

    if (rc == NO_ERROR) {
        m_pSrcChannel = pSrcChannel;
    }
    return rc;
}