blob: aa6b6d356d21190fd5704c9aab180bffeccc44d7 [file] [log] [blame]
/*
* Copyright (C) 2019 MediaTek Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define SUPPORT_LMV_MV_API 0
#include "camera/hal/mediatek/mtkcam/pipeline/hwnode/p2/P2_Cropper.h"
#include "P2_Common.h"
#include <mtkcam/utils/debug/P2_DebugControl.h>
#define P2_CLASS_TAG Cropper
#define P2_TRACE TRACE_CROPPER
#include "P2_LogHeader.h"
#include <algorithm>
#define TRACE_S_CROP(log, name, p, s) \
TRACE_S_FUNC(log, name " = (%dx%d)@(%d,%d)", s.w, s.h, p.x, p.y)
#define TRACE_S_CROPF(log, name, p, s) \
TRACE_S_FUNC(log, name " = (%fx%f)@(%f,%f)", s.w, s.h, p.x, p.y)
#define USE_SENSOR_DOMAIN_VIEW_ANGLE 1
namespace P2 {
MCropRect transform(const simpleTransform& trans, const MCropRect& src) {
MCropRect dst;
vector_f fracOffset;
fracOffset = transform(trans, vector_f(src.p_integral, src.p_fractional));
dst.p_integral = fracOffset.p + transform(trans, MPoint(0, 0));
dst.p_fractional = fracOffset.pf;
dst.s = transform(trans, src.s);
TRACE_FUNC("src(%dx%d)=>dst(%dx%d)", src.s.w, src.s.h, dst.s.w, dst.s.h);
return dst;
}
P2Cropper::P2Cropper() {}
P2Cropper::P2Cropper(const ILog& log,
const P2SensorInfo* sensorInfo,
const P2SensorData* sensorData,
const LMVInfo& lmvInfo)
: mLog(log),
mLMVInfo(lmvInfo),
mSensorID(sensorInfo ? sensorInfo->mSensorID : INVALID_SENSOR_ID) {
TRACE_S_FUNC_ENTER(mLog);
if (sensorInfo && sensorData) {
mActiveSize = sensorInfo->mActiveArray.s;
mIsValid =
initAppInfo(sensorData) && initHalInfo(sensorData) && initTransform();
initLMV();
if (TRACE_CROPPER || mLog.getLogLevel() >= 1) {
this->dump(mLog);
}
}
TRACE_S_FUNC_EXIT(mLog);
}
P2Cropper::~P2Cropper() {
TRACE_S_FUNC_ENTER(mLog);
TRACE_S_FUNC_EXIT(mLog);
}
MBOOL P2Cropper::isValid() const {
TRACE_S_FUNC_ENTER(mLog);
TRACE_S_FUNC_EXIT(mLog);
return mIsValid;
}
MSize P2Cropper::getSensorSize() const {
TRACE_S_FUNC_ENTER(mLog);
TRACE_S_FUNC_EXIT(mLog);
return mSensorSize;
}
MRect P2Cropper::getResizedCrop() const {
TRACE_S_FUNC_ENTER(mLog);
TRACE_S_FUNC_EXIT(mLog);
return mResizedCrop;
}
MRect P2Cropper::getP1Crop() const {
TRACE_S_FUNC_ENTER(mLog);
TRACE_S_FUNC_EXIT(mLog);
return mP1Crop;
}
MSize P2Cropper::getP1OutSize() const {
TRACE_S_FUNC_ENTER(mLog);
TRACE_S_FUNC_EXIT(mLog);
return mP1OutSize;
}
MRect P2Cropper::getP1BinCrop() const {
TRACE_S_FUNC_ENTER(mLog);
TRACE_S_FUNC_EXIT(mLog);
return mP1BinCrop;
}
MSize P2Cropper::getP1BinSize() const {
TRACE_S_FUNC_ENTER(mLog);
TRACE_S_FUNC_EXIT(mLog);
return mP1BinSize;
}
const LMVInfo& P2Cropper::getLMVInfo() const {
TRACE_S_FUNC_ENTER(mLog);
TRACE_S_FUNC_EXIT(mLog);
return mLMVInfo;
}
MCropRect P2Cropper::calcViewAngle(const ILog& log,
const MSize& size,
MUINT32 cropFlag) const {
return calcViewAngle(log, size, cropFlag, 1.0f);
}
MCropRect P2Cropper::calcViewAngle(const ILog& log,
const MSize& size,
MUINT32 cropFlag,
const float cropRatio) const {
MRectF retRectF =
calcViewAngleF(log, size, cropFlag, cropRatio,
(DMACONSTRAIN_2BYTEALIGN | DMACONSTRAIN_NOSUBPIXEL));
MCropRect cropRect = getCropRect(retRectF);
MBOOL useResize = !!(cropFlag & Cropper::USE_RESIZED);
if (refineBoundary(log, useResize ? mP1OutSize : mSensorSize, &cropRect)) {
TRACE_S_CROP(log, "with refine", cropRect.p_integral, cropRect.s);
this->dump(log);
}
return cropRect;
}
MRectF P2Cropper::calcViewAngleF(const ILog& log,
const MSize& size,
MUINT32 cropFlag,
const float cropRatio,
const MINT32 dmaConstrainFlag) const {
TRACE_S_FUNC_ENTER(log);
MBOOL useResize = !!(cropFlag & Cropper::USE_RESIZED);
MBOOL useEIS12 = !!(cropFlag & Cropper::USE_EIS_12);
MBOOL useCropRatio = !!(cropFlag & Cropper::USE_CROP_RATIO);
MBOOL useRrzoDomainView = useResize && !USE_SENSOR_DOMAIN_VIEW_ANGLE;
MBOOL needSensorToRrzo = useResize && !useRrzoDomainView;
TRACE_S_FUNC(
log,
"size=%dx%d flag=0x%x useResize=%d useEIS12=%d useCropRatio=%d(%f), "
"dmaConstrain(%d), validCropper=%d, useRrzoDomainView=%d",
size.w, size.h, cropFlag, useResize, useEIS12, useCropRatio, cropRatio,
dmaConstrainFlag, mIsValid, useRrzoDomainView);
MRectF view(size.w, size.h);
if (mIsValid) {
TRACE_S_CROP(log, "activeCrop", mActiveCrop.p, mActiveCrop.s);
TRACE_S_CROP(log, "sensorCrop", mSensorCrop.p, mSensorCrop.s);
TRACE_S_CROP(log, "resizedCrop", mResizedCrop.p, mResizedCrop.s);
view = useRrzoDomainView ? mResizedCrop : mSensorCrop;
TRACE_S_CROPF(log, "original", view.p, view.s);
if (useCropRatio) {
view = applyCropRatio(log, view, cropRatio);
}
view = applyViewRatio(log, view, size);
if (needSensorToRrzo) {
MRectF sensorDomainView = view;
view = transform(mSensor2Resized, sensorDomainView);
TRACE_S_CROPF(log, "with sensor2Resized", view.p, view.s);
}
MSizeF boundary = useResize ? MSizeF(mP1OutSize.w, mP1OutSize.h)
: MSizeF(mSensorSize.w, mSensorSize.h);
if (refineBoundaryF(log, boundary, &view)) {
this->dump(log);
}
if ((dmaConstrainFlag & DMACONSTRAIN_NOSUBPIXEL) ||
(dmaConstrainFlag & DMACONSTRAIN_2BYTEALIGN)) {
view.p = MPoint(view.p.x, view.p.y);
MSize viewSizeI(view.s.w, view.s.h);
if (dmaConstrainFlag & DMACONSTRAIN_2BYTEALIGN) {
viewSizeI.w &= ~(0x01);
viewSizeI.h &= ~(0x01);
}
view.s = viewSizeI;
}
TRACE_S_CROPF(log, "result", view.p, view.s);
}
TRACE_S_FUNC_EXIT(log);
return view;
}
MBOOL P2Cropper::refineBoundaryF(const ILog& log,
const MSizeF& size,
MRectF* crop) const {
MBOOL isRefined = MFALSE;
if (mIsValid) {
MRectF refined = *crop;
if (crop->p.x < 0) {
refined.p.x = 0;
isRefined = MTRUE;
}
if (crop->p.y < 0) {
refined.p.y = 0;
isRefined = MTRUE;
}
if ((refined.p.x + crop->s.w) > size.w) {
refined.s.w = size.w - refined.p.x;
isRefined = MTRUE;
}
if ((refined.p.y + crop->s.h) > size.h) {
refined.s.h = size.h - refined.p.y;
isRefined = MTRUE;
}
if (isRefined) {
MY_S_LOGW(log,
"apply refine: boundary(%.0fx%.0f), crop:(%f,%f,%f,%f) -> "
"crop:(%f,%f,%f,%f)",
size.w, size.h, crop->p.x, crop->p.y, crop->s.w, crop->s.h,
refined.p.x, refined.p.y, refined.s.w, refined.s.h);
*crop = refined;
}
}
return isRefined;
}
MBOOL P2Cropper::refineBoundary(const ILog& log,
const MSize& size,
MCropRect* crop) const {
TRACE_S_FUNC_ENTER(log);
MBOOL isRefined = MFALSE;
if (mIsValid) {
MCropRect refined = *crop;
if (crop->p_integral.x < 0) {
refined.p_integral.x = 0;
isRefined = MTRUE;
}
if (crop->p_integral.y < 0) {
refined.p_integral.y = 0;
isRefined = MTRUE;
}
int carry_x = (crop->p_fractional.x != 0) ? 1 : 0;
int carry_y = (crop->p_fractional.y != 0) ? 1 : 0;
int carry_w = (crop->w_fractional != 0) ? 1 : 0;
int carry_h = (crop->h_fractional != 0) ? 1 : 0;
if ((refined.p_integral.x + crop->s.w + carry_x + carry_w) > size.w) {
refined.s.w = size.w - carry_w - refined.p_integral.x - carry_x;
isRefined = MTRUE;
}
if ((refined.p_integral.y + crop->s.h + carry_y + carry_h) > size.h) {
refined.s.h = size.h - carry_h - refined.p_integral.y - carry_y;
isRefined = MTRUE;
}
if (isRefined) {
refined.s.w &= ~(0x01);
refined.s.h &= ~(0x01);
MY_S_LOGW(log,
"size:(%dx%d), crop:(%d.%d,%d.%d)(%dx%d) -> "
"crop:(%d.%d,%d.%d)(%dx%d)",
size.w, size.h, crop->p_integral.x, crop->p_fractional.x,
crop->p_integral.y, crop->p_fractional.y, crop->s.w, crop->s.h,
refined.p_integral.x, refined.p_fractional.x,
refined.p_integral.y, refined.p_fractional.y, refined.s.w,
refined.s.h);
*crop = refined;
}
}
TRACE_S_FUNC_EXIT(log);
return isRefined;
}
MRect P2Cropper::getCropRegion() const {
TRACE_S_FUNC_ENTER(mLog);
MRect cropRegion;
if (mIsValid) {
cropRegion = mActiveCrop;
}
TRACE_S_FUNC_EXIT(mLog);
return cropRegion;
}
MRect P2Cropper::getActiveCrop() const {
return mActiveCrop;
}
MRect P2Cropper::toActive(const MRectF& cropF, MBOOL resize) const {
MRect crop = cropF.toMRect();
return toActive(crop, resize);
}
MRect P2Cropper::toActive(const MCropRect& cropRect, MBOOL resize) const {
MRect crop = MRect(cropRect.p_integral, cropRect.s);
return toActive(crop, resize);
}
MRect P2Cropper::toActive(const MRect& crop, MBOOL resize) const {
MRect s_crop, a_crop;
if (resize) {
s_crop.p = inv_transform(mSensor2Resized, crop.p);
s_crop.s = inv_transform(mSensor2Resized, crop.s);
} else {
s_crop.p = crop.p;
s_crop.s = crop.s;
}
mSensor2Active.transform(s_crop, &a_crop);
TRACE_S_CROP(mLog, "ViewCrop", crop.p, crop.s);
TRACE_S_CROP(mLog, "sensorViewCrop", s_crop.p, s_crop.s);
TRACE_S_CROP(mLog, "activeViewCrop", a_crop.p, a_crop.s);
return a_crop;
}
MVOID P2Cropper::dump(const ILog& log) const {
TRACE_S_FUNC_ENTER(log);
MY_S_LOGD(log, "sensorID=%d isValid=%d sensorMode=%d", mSensorID, mIsValid,
mSensorMode);
MY_S_LOGD(log, "sensorSize(%dx%d)", mSensorSize.w, mSensorSize.h);
MY_S_LOGD(log, "p1 crop(%dx%d)@(%d,%d) size(%dx%d) dma(%dx%d)@(%d,%d)",
mP1Crop.s.w, mP1Crop.s.h, mP1Crop.p.x, mP1Crop.p.y, mP1OutSize.w,
mP1OutSize.h, mP1DMA.s.w, mP1DMA.s.h, mP1DMA.p.x, mP1DMA.p.y);
MY_S_LOGD(log, "sensor to resized (%d,%d) size(%dx%d)->(%dx%d)",
mSensor2Resized.tarOrigin.x, mSensor2Resized.tarOrigin.y,
mSensor2Resized.oldScale.w, mSensor2Resized.oldScale.h,
mSensor2Resized.newScale.w, mSensor2Resized.newScale.h);
MY_S_LOGD(log, "Active crop (%dx%d)@(%d,%d)", mActiveCrop.s.w,
mActiveCrop.s.h, mActiveCrop.p.x, mActiveCrop.p.y);
MY_S_LOGD(log, "active mv (%d,%d)(%d,%d)", mActiveLMV.p.x, mActiveLMV.pf.x,
mActiveLMV.p.y, mActiveLMV.pf.y);
MY_S_LOGD(log, "sensor mv (%d,%d)(%d,%d)", mSensorLMV.p.x, mSensorLMV.pf.x,
mSensorLMV.p.y, mSensorLMV.pf.y);
MY_S_LOGD(log, "resized mv (%d,%d)(%d,%d)", mResizedLMV.p.x, mResizedLMV.pf.x,
mResizedLMV.p.y, mResizedLMV.pf.y);
TRACE_S_FUNC_EXIT(log);
}
MBOOL P2Cropper::initAppInfo(const P2SensorData* data) {
TRACE_S_FUNC_ENTER(mLog);
MBOOL ret = MFALSE;
if (data) {
mActiveCrop = data->mAppCrop;
ret = MTRUE;
}
TRACE_S_FUNC_EXIT(mLog);
return ret;
}
MBOOL P2Cropper::initHalInfo(const P2SensorData* data) {
TRACE_S_FUNC_ENTER(mLog);
MBOOL ret = MFALSE;
if (data) {
mSensorMode = data->mSensorMode;
mSensorSize = data->mSensorSize;
mP1Crop = data->mP1Crop;
mP1DMA = data->mP1DMA;
mP1OutSize = data->mP1OutSize;
mP1BinCrop = data->mP1BinCrop;
mP1BinSize = data->mP1BinSize;
ret = MTRUE;
}
TRACE_S_FUNC_EXIT(mLog);
return ret;
}
MBOOL P2Cropper::initTransform() {
TRACE_S_FUNC_ENTER(mLog);
MBOOL ret = MTRUE;
HwTransHelper trans(mSensorID);
if (!trans.getMatrixToActive(mSensorMode, &mSensor2Active) ||
!trans.getMatrixFromActive(mSensorMode, &mActive2Sensor)) {
MY_S_LOGW(mLog, "cannot get active matrix");
ret = MFALSE;
} else {
mSensor2Resized = simpleTransform(mP1Crop.p, mP1Crop.s, mP1OutSize);
mActive2Sensor.transform(mActiveCrop, &mSensorCrop);
mSensorCrop = clip(mSensorCrop, mP1Crop);
mResizedCrop = transform(mSensor2Resized, mSensorCrop);
}
TRACE_S_FUNC_EXIT(mLog);
return ret;
}
MBOOL P2Cropper::initLMV() {
TRACE_S_FUNC_ENTER(mLog);
MBOOL ret = MTRUE;
prepareLMV();
TRACE_S_FUNC_EXIT(mLog);
return ret;
}
MVOID P2Cropper::prepareLMV() {
TRACE_S_FUNC_ENTER(mLog);
#if SUPPORT_LMV_MV_API
if (mLMVInfo.is_from_zzr) {
mResizedLMV.p.x = mLMVInfo.x_mv_int;
mResizedLMV.pf.x = mLMVInfo.x_mv_float;
mResizedLMV.p.y = mLMVInfo.y_mv_int;
mResizedLMV.pf.y = mLMVInfo.y_mv_float;
mSensorLMV = inv_transform(mSensor2Resized, mResizedLMV);
} else {
mSensorLMV.p.x = mLMVInfo.x_mv_int;
mSensorLMV.pf.x = mLMVInfo.x_mv_int;
mSensorLMV.p.y = mLMVInfo.y_mv_int;
mSensorLMV.pf.y = mLMVInfo.y_mv_float;
mResizedLMV = transform(mSensor2Resized, mSensorLMV);
}
#else
mResizedLMV.p.x = mLMVInfo.x_int;
mResizedLMV.pf.x = mLMVInfo.x_float;
mResizedLMV.p.y = mLMVInfo.y_int;
mResizedLMV.pf.y = mLMVInfo.y_float;
mSensorLMV = inv_transform(mSensor2Resized, mResizedLMV);
#endif
mSensor2Active.transform(mSensorLMV.p, &mActiveLMV.p);
TRACE_S_FUNC_EXIT(mLog);
}
MRect P2Cropper::clip(const MRect& src, const MRect& box) const {
TRACE_S_FUNC_ENTER(mLog);
MRect result = src;
if (src.p.x < box.p.x) {
result.p.x = box.p.x;
}
if (src.p.y < box.p.y) {
result.p.y = box.p.y;
}
MINT32 maxW = box.p.x + box.s.w - result.p.x;
if (maxW && (result.s.w > maxW)) {
result.s.w = maxW;
}
MINT32 maxH = box.p.y + box.s.h - result.p.y;
if (maxH && (result.s.h > maxH)) {
result.s.h = maxH;
}
TRACE_S_FUNC_EXIT(mLog);
return result;
}
MRectF P2Cropper::applyEIS12(const ILog& log,
const MRectF& src,
MBOOL useResize) const {
#define LMV_FRACTION_MAX (0x100000000)
MRectF view = src;
MSize viewSizeI(view.s.w, view.s.h);
view.s = viewSizeI * 100 / mEISFactor;
vector_f lmvVector = useResize ? mResizedLMV : mSensorLMV;
MPointF lmvPointF(lmvVector.pf.x, lmvVector.pf.y);
view.p += lmvVector.p;
view.p.x += (lmvPointF.x / LMV_FRACTION_MAX);
view.p.y += (lmvPointF.y / LMV_FRACTION_MAX);
TRACE_S_FUNC(log, " lmv vector xy(%d,%d) subpixel(%d,%d) = (%f,%f)",
lmvVector.p.x, lmvVector.p.y, lmvVector.pf.x, lmvVector.pf.y,
lmvPointF.x / LMV_FRACTION_MAX, lmvPointF.y / LMV_FRACTION_MAX);
if (!mLMVInfo.is_valid) {
MY_S_LOGD(log,
"invalid LMVInfo, use latest result = lmv vector xy(%d,%d) "
"subpixel(%d,%d) = (%f,%f)",
lmvVector.p.x, lmvVector.p.y, lmvVector.pf.x, lmvVector.pf.y,
lmvPointF.x / LMV_FRACTION_MAX, lmvPointF.y / LMV_FRACTION_MAX);
}
TRACE_S_CROPF(log, "applyEIS12: src", src.p, src.s);
TRACE_S_CROPF(log, "with EIS1.2", view.p, view.s);
return view;
}
MRectF P2Cropper::applyCropRatio(const ILog& log,
const MRectF& src,
const float ratio) const {
MRectF view = src;
if (ratio > 1.0f) {
MY_S_LOGW(log, "skip invalid ratio(%f) for view(%fx%f)", ratio, src.s.w,
src.s.h);
} else {
view.p.x += (view.s.w * (1.0f - ratio) / 2);
view.p.y += (view.s.h * (1.0f - ratio) / 2);
view.s = (view.s * ratio);
}
TRACE_S_FUNC(log, "applyCropRatio: src(%fx%f) ratio(%f)", src.s.w, src.s.h,
ratio);
TRACE_S_CROPF(log, "with crop ratio", view.p, view.s);
return view;
}
MRectF P2Cropper::applyViewRatio(const ILog& log,
const MRectF& src,
const MSize& size) const {
MRectF view = src;
if (src.s.w * size.h > size.w * src.s.h) {
view.s.w = (src.s.h * size.w / size.h);
view.p.x += (src.s.w - view.s.w) / 2;
} else {
view.s.h = (src.s.w * size.h / size.w);
view.p.y += (src.s.h - view.s.h) / 2;
}
TRACE_S_CROPF(log, "with aspect ratio", view.p, view.s);
return view;
}
} // namespace P2