(1)如何添加Mirror的Vendor Tag以及App如何调用
可参考如下文章进行自定义Vendor Tag添加MTK Camera自定义Vendor Tag。
(2)前摄对预览,拍照,录像,缩列图进行Mirror处理
可参考如下文章初步了解哪些地方可以进行Mirror 和 Flip处理Mtk Camera 对预览和拍照做Flip + Mirror。
(A)预览的Mirror效果
前摄预览的Mirror效果是Google在Framework自行添加的,无需自行添加,具体可参考上面的文章。
(B)拍照的Mirror效果
//vendor/mediatek/proprietary/hardware/mtkcam3/pipeline/policy/request/CaptureStreamUpdaterPolicy.cpp
static auto createRotationStreamInfoLocked_Main_YUV(
RequestOutputParams& out __unused,
RequestInputParams const& in __unused
) -> int
{
auto const pMetadata = in.pRequest_AppControl;
auto const pCfgMainYUV = *(in.pConfiguration_HalImage_Jpeg_YUV);
if ( CC_UNLIKELY( ! pMetadata || ! pCfgMainYUV.get() ) ) {
MY_LOGE("invlaid input params");
return NO_INIT;
}
IMetadata::IEntry const& entryJpegOrientation = pMetadata->entryFor(MTK_JPEG_ORIENTATION);
if ( entryJpegOrientation.isEmpty() ) {
MY_LOGW("No tag: MTK_JPEG_ORIENTATION");
return -EINVAL;
}
int32_t jpegFlip = 0;
//jpegFlip:Jpeg的Flip效果
IMetadata::IEntry const& entryJpegFlip = pMetadata->entryFor(MTK_CONTROL_CAPTURE_JPEG_FLIP_MODE);
if (entryJpegFlip.isEmpty()) {
MY_LOGD("No tag: MTK_CONTROL_CAPTURE_JPEG_FLIP_MODE");
} else {
jpegFlip = entryJpegFlip.itemAt(0, Type2Type<MINT32>());
}
int32_t jpegFlipProp = ::property_get_int32("vendor.debug.camera.Jpeg.flip", 0);
int32_t const jpegOrientation = (in.isSupportJpegPack) ? 0 :
entryJpegOrientation.itemAt(0, Type2Type<MINT32>());
uint32_t reqTransform = 0;
if (jpegFlip || jpegFlipProp) {
if ( 0==jpegOrientation )
reqTransform = eTransform_FLIP_H;
else if ( 90==jpegOrientation )
reqTransform = eTransform_ROT_90 | eTransform_FLIP_V;
else if ( 180==jpegOrientation )
reqTransform = eTransform_FLIP_V;
else if ( 270==jpegOrientation )
reqTransform = eTransform_ROT_90 | eTransform_FLIP_H;
else
MY_LOGW("Invalid Jpeg Orientation value: %d", jpegOrientation);
} else {
if ( 0==jpegOrientation )
reqTransform = 0;
else if ( 90==jpegOrientation )
reqTransform = eTransform_ROT_90;
else if ( 180==jpegOrientation )
reqTransform = eTransform_ROT_180;
else if ( 270==jpegOrientation )
reqTransform = eTransform_ROT_270;
else
MY_LOGW("Invalid Jpeg Orientation value: %d", jpegOrientation);
}
//...
}
(C)缩列图的Mirror效果
(a)普通的缩列图
//vendor/mediatek/proprietary/hardware/mtkcam3/pipeline/hwnode/JpegNode/v2.0/JpegNode.cpp
MVOID
JpegNodeImp::
encodeThumbnailJpeg(
sp<encode_frame>& pEncodeFrame)
{
{
// set thread naming
pthread_setname_np(pthread_self(), THUMBTHREAD_NAME);
}
MSize thumbsize = pEncodeFrame->mParams.size_thumbnail;
MUINT32 transform = (pEncodeFrame->mpYUV_MainStreamInfo.get()) ? pEncodeFrame->mpYUV_MainStreamInfo->getTransform() : 0;
// do encode
{
my_encode_params params;
params.frameNo = pEncodeFrame->mpFrame->getFrameNo();
params.requestNo = pEncodeFrame->mpFrame->getRequestNo();
params.pSrc = pEncodeFrame->mpYUV_Thumbnail.get();
params.pDst = pEncodeFrame->mpJpeg_Thumbnail.get();
//pEncodeFrame->mParams.flipMode : 普通缩列图的Flip
if (pEncodeFrame->mParams.flipMode || info.mFlip) {
if( pEncodeFrame->mParams.orientation == 90 && transform & eTransform_ROT_90)
{
params.transform = eTransform_ROT_90 | eTransform_FLIP_V;
std::swap(thumbsize.w, thumbsize.h);
} else if (pEncodeFrame->mParams.orientation == 180 && transform & eTransform_ROT_180)
{
params.transform = eTransform_FLIP_V;
} else if (pEncodeFrame->mParams.orientation == 270 && transform & eTransform_ROT_270)
{
params.transform = eTransform_ROT_90 | eTransform_FLIP_H;
std::swap(thumbsize.w, thumbsize.h);
} else
{
params.transform = eTransform_FLIP_H;
}
#if MTKCAM_EARLY_FLIP_SUPPORT == 1
// has flipped in P2A, need to un-flip
auto doUnflip= [&](MUINT32& trans, MINT32 dvOri) -> MVOID {
if (dvOri == 270) {
MY_LOGD("dvOri %d, Capture vertical", dvOri);
trans |= eTransform_FLIP_V;
} else if (dvOri == 90) {
MY_LOGD("dvOri %d, Capture vertical", dvOri);
trans &= ~eTransform_FLIP_V;
} else if (dvOri == 180) {
MY_LOGD("dvOri %d, Capture horizontal",dvOri);
trans |= eTransform_FLIP_H;
} else if (dvOri == 0) {
MY_LOGD("dvOri %d, Capture horizontal",dvOri);
trans &= ~eTransform_FLIP_H;
}
};
if (pEncodeFrame->mParams.isFlipped) {
MY_LOGD("before trans 0x%" PRIx64, params.transform);
doUnflip(params.transform, pEncodeFrame->mParams.orientation);
MY_LOGD("after trans 0x%" PRIx64, params.transform);
}
#endif
} else {
if( pEncodeFrame->mParams.orientation == 90 && transform & eTransform_ROT_90)
{
params.transform = eTransform_ROT_90;
std::swap(thumbsize.w, thumbsize.h);
} else if (pEncodeFrame->mParams.orientation == 180 && transform & eTransform_ROT_180)
{
params.transform = eTransform_ROT_180;
} else if (pEncodeFrame->mParams.orientation == 270 && transform & eTransform_ROT_270)
{
params.transform = eTransform_ROT_270;
std::swap(thumbsize.w, thumbsize.h);
} else
{
params.transform = 0;
}
}
params.crop =
calCropAspect(pEncodeFrame->mpYUV_Thumbnail->getImgSize(), thumbsize);
params.isSOI = 1;
params.quality = pEncodeFrame->mParams.quality_thumbnail;
params.codecType = NSSImager::JPEGENC_SW;
params.bsOffset = pEncodeFrame->exif.getStdExifSize();
//
MINT32 quality = params.quality;
//...
}
(b)postview方式
由于postview方式是通过在Preview预览中来获取buffer的,所以可以参考如下FAQ修改Postview Flip。
相当于在提交Preview的request时将其添加Mirror能力。
//vendor/mediatek/proprietary/hardware/mtkcam3/pipeline/model/session/PipelineModelSessionBasic.cpp
auto
ThisNamespace::
submitOneRequest(
std::shared_ptr<ParsedAppRequest>const& request __unused
) -> int
{
CAM_TRACE_CALL();
auto const requestNo = request->requestNo;
CAM_ULOG_ENTER(MOD_DEFAULT_PIPELINE_MODEL, REQ_APP_REQUEST, requestNo);
// On this function, use this local variable to serve the request.
auto pConfigInfo2 = getCurrentConfigInfo2();
// Evaluate a result for a request.
auto pReqOutputParams = std::make_shared<pipelinesetting::RequestOutputParams>();
MY_LOGF_IF(pReqOutputParams==nullptr, "[requestNo:%u] Fail on make_shared" , requestNo);
RETURN_ERROR_IF_NOT_OK( onRequest_EvaluateRequest(*pReqOutputParams, request, pConfigInfo2),
"[requestNo:%u] onRequest_EvaluateRequest", requestNo );
// pConfigInfo2 could change after this call.
RETURN_ERROR_IF_NOT_OK( onRequest_Reconfiguration(pConfigInfo2, *pReqOutputParams, request),
"[requestNo:%u] onRequest_Reconfiguration", requestNo );
RETURN_ERROR_IF_NOT_OK( onRequest_ProcessEvaluatedFrame(pReqOutputParams, request, pConfigInfo2),
"[requestNo:%u] onRequest_ProcessEvaluatedFrame", requestNo );
RETURN_ERROR_IF_NOT_OK( onRequest_Ending(*pReqOutputParams),
"[requestNo:%u] onRequest_Ending", requestNo );
return OK;
}
(D) Recording + Vss的Mirror效果
可先参考MTK平台的FAQRecording + Vss Flip。
可大致参考如下修改:
//vendor/mediatek/proprietary/hardware/mtkcam3/pipeline/model/session/PipelineModelSessionBase.cpp
auto
PipelineModelSessionBase::
submitRequest(
std::vector<std::shared_ptr<UserRequestParams>>const& requests,
uint32_t& numRequestProcessed
) -> int
{
//...
//Submit ParsedAppRequest one by one
for (size_t i = 0; i < reqs.size(); i++, numRequestProcessed++) {
// add start
int SensorID = mStaticInfo.pPipelineStaticInfo->sensorId[i];
if(SensorID == 1){
auto const& pAppControl = reqs[i]->pAppMetaControlStreamBuffer;
IMetadata* pMetadata = pAppControl->tryReadLock(LOG_TAG);
if ( CC_UNLIKELY( ! pMetadata ) ) {
MY_LOGE("bad metadata(%p) SBuffer(%p)", pMetadata, pAppControl.get() );
pAppControl->unlock(LOG_TAG, pMetadata);
return -EINVAL;
}
MINT32 videoFlip = 0;
int32_t videoOrientation = 90;
//这里进行读取videoFlip
IMetadata::getEntry(pMetadata, MTK_CONTROL_CAPTURE_JPEG_FLIP_MODE, videoFlip);
IMetadata::getEntry(pMetadata, MTK_STREAMING_FEATURE_XAPI_ROTATION, videoOrientation);
pAppControl->unlock(LOG_TAG, pMetadata);
MY_LOGD("%s:videoFlip = %d videoOrientation = %d\n",__FUNCTION__,videoFlip,videoOrientation);
auto OpRequest_AppImageStreamInfo = reqs[i]->pParsedAppImageStreamInfo.get();
for (auto & it : OpRequest_AppImageStreamInfo->vAppImage_Output_Proc) {
if (it.second->getUsageForConsumer() & GRALLOC_USAGE_HW_VIDEO_ENCODER ){
uint32_t reqTransform = 0;
if (videoFlip) {
if ( 0 == videoOrientation ) {
reqTransform = eTransform_FLIP_H;
}else if ( 90 == videoOrientation ) {
reqTransform = eTransform_FLIP_V;
}else if ( 180 == videoOrientation ) {
reqTransform = eTransform_FLIP_H;
}else if ( 270 == videoOrientation ) {
reqTransform = eTransform_FLIP_V;}
}else {
MY_LOGW("Invalid videoOrientation value: %d", videoOrientation);
}
MY_LOGD("set video flip reqTransform: %d", reqTransform);
it.second->setTransform(reqTransform);
}
}
}
// add end
RETURN_ERROR_IF_NOT_OK( submitOneRequest(reqs[i]),
"submitOneRequest fail on requestNo:%u - %u/%zu requests submitted sucessfully",
reqs[i]->requestNo, numRequestProcessed, reqs.size() );
}
return OK;
}