1 /*
2  * Copyright (C) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "crop_efilter.h"
17 
18 #include "common_utils.h"
19 #include "efilter_factory.h"
20 #include "colorspace_helper.h"
21 
22 namespace OHOS {
23 namespace Media {
24 namespace Effect {
25 using namespace OHOS::HDI::Display::Graphic::Common::V1_0;
26 
27 REGISTER_EFILTER_FACTORY(CropEFilter, "Crop");
28 const std::string CropEFilter::Parameter::KEY_REGION = "FilterRegion";
29 std::shared_ptr<EffectInfo> CropEFilter::info_ = nullptr;
30 namespace {
31     constexpr int32_t PIXEL_BYTES = 4;
32 }
33 
34 struct AreaInfo {
35     int32_t x0;
36     int32_t y0;
37     int32_t x1;
38     int32_t y1;
39 };
40 
41 struct Region {
42     int32_t left;
43     int32_t top;
44     int32_t width;
45     int32_t height;
46 };
47 
CalculateCropRegion(int32_t srcWidth,int32_t srcHeight,std::map<std::string,Plugin::Any> & values,Region * region)48 void CalculateCropRegion(int32_t srcWidth, int32_t srcHeight, std::map<std::string, Plugin::Any> &values,
49     Region *region)
50 {
51     AreaInfo areaInfo = { 0, 0, srcWidth, srcHeight };
52     void *area = nullptr;
53     ErrorCode res = CommonUtils::GetValue(CropEFilter::Parameter::KEY_REGION, values, area);
54     if (res != ErrorCode::SUCCESS || area == nullptr) {
55         // allow developer not set para, not execute crop. execute copy.
56         EFFECT_LOGW("CropEFilter::CalculateCropRegion get value fail! res=%{public}d. "
57             "use default value, not execute crop!", res);
58     } else {
59         areaInfo = *(static_cast<AreaInfo *>(area));
60     }
61 
62     EFFECT_LOGI("CropEFilter x0=%{public}d, y0=%{public}d, x1=%{public}d, y1=%{public}d",
63         areaInfo.x0, areaInfo.y0, areaInfo.x1, areaInfo.y1);
64 
65     int32_t leftTopX = areaInfo.x0 > areaInfo.x1 ? areaInfo.x1 : areaInfo.x0;
66     int32_t leftTopY = areaInfo.y0 > areaInfo.y1 ? areaInfo.y1 : areaInfo.y0;
67     leftTopX = leftTopX < 0 ? 0 : leftTopX;
68     leftTopY = leftTopY < 0 ? 0 : leftTopY;
69 
70     int32_t rightBottomX = areaInfo.x0 > areaInfo.x1 ? areaInfo.x0 : areaInfo.x1;
71     int32_t rightBottomY = areaInfo.y0 > areaInfo.y1 ? areaInfo.y0 : areaInfo.y1;
72     rightBottomX = rightBottomX > srcWidth ? srcWidth : rightBottomX;
73     rightBottomY = rightBottomY > srcHeight ? srcHeight : rightBottomY;
74 
75     int32_t cropWidth = rightBottomX - leftTopX;
76     int32_t cropHeight = rightBottomY - leftTopY;
77 
78     region->left = leftTopX;
79     region->top = leftTopY;
80     region->width = cropWidth;
81     region->height = cropHeight;
82 }
83 
Crop(EffectBuffer * src,EffectBuffer * dst,Region * region)84 void Crop(EffectBuffer *src, EffectBuffer *dst, Region *region)
85 {
86     int32_t cropLeft = region->left;
87     int32_t cropTop = region->top;
88     int32_t cropWidth = region->width;
89     int32_t cropHeight = region->height;
90     int32_t dstWidth = static_cast<int32_t>(dst->bufferInfo_->width_);
91     int32_t dstHeight = static_cast<int32_t>(dst->bufferInfo_->height_);
92 
93     int32_t rowCount = cropHeight > dstHeight ? dstHeight : cropHeight;
94     int32_t pixelCount = cropWidth > dstWidth ? dstWidth : cropWidth;
95     int32_t count = pixelCount * PIXEL_BYTES;
96 
97     auto *srcBuffer = static_cast<char *>(src->buffer_);
98     auto *dstBuffer = static_cast<char *>(dst->buffer_);
99     uint32_t srcRowStride = src->bufferInfo_->rowStride_;
100     uint32_t dstRowStride = dst->bufferInfo_->rowStride_;
101     char *srcStart = srcBuffer + cropTop * static_cast<int32_t>(srcRowStride) + cropLeft * PIXEL_BYTES;
102     EFFECT_LOGD("Crop: srcBuffer=%{public}p, dstBuffer=%{public}p, srcStart=%{public}p, srcRowStride=%{public}d, "
103         "dstRowStride=%{public}d, rowCount=%{public}d, count=%{public}d",
104         srcBuffer, dstBuffer, srcStart, srcRowStride, dstRowStride, rowCount, count);
105     for (int32_t i = 0; i < rowCount; ++i) {
106         errno_t ret = memcpy_s(dstBuffer + i * dstRowStride, dstRowStride, srcStart + i * srcRowStride, count);
107         if (ret != 0) {
108             EFFECT_LOGE("CropEFilter::Render memcpy_s failed. ret=%{public}d, i=%{public}d", ret, i);
109             continue;
110         }
111     }
112 }
113 
Render(EffectBuffer * src,EffectBuffer * dst,std::shared_ptr<EffectContext> & context)114 ErrorCode CropEFilter::Render(EffectBuffer *src, EffectBuffer *dst, std::shared_ptr<EffectContext> &context)
115 {
116     CHECK_AND_RETURN_RET_LOG(src != nullptr && dst != nullptr, ErrorCode::ERR_INPUT_NULL, "input error!");
117     CHECK_AND_RETURN_RET_LOG(src->bufferInfo_ != nullptr && dst->bufferInfo_ != nullptr, ErrorCode::ERR_INPUT_NULL,
118         "input error! src->bufferInfo_=%{public}d, dst->bufferInfo_=%{public}d",
119         src->bufferInfo_ == nullptr, dst->bufferInfo_ == nullptr);
120 
121     // only support RGBA for now.
122     IEffectFormat format = src->bufferInfo_->formatType_;
123     CHECK_AND_RETURN_RET_LOG(format == IEffectFormat::RGBA8888 || format == IEffectFormat::RGBA_1010102,
124         ErrorCode::ERR_UNSUPPORTED_FORMAT_TYPE, "crop not support format! format=%{public}d", format);
125 
126     Region region = { 0, 0, 0, 0 };
127     CalculateCropRegion(static_cast<int32_t>(src->bufferInfo_->width_), static_cast<int32_t>(src->bufferInfo_->height_),
128         values_, &region);
129     Crop(src, dst, &region);
130     return ErrorCode::SUCCESS;
131 }
132 
UpdateDstEffectBufferIfNeed(EffectBuffer * src,EffectBuffer * dst)133 void UpdateDstEffectBufferIfNeed(EffectBuffer *src, EffectBuffer *dst)
134 {
135     SurfaceBuffer *srcSurfaceBuffer = src->extraInfo_->surfaceBuffer;
136     SurfaceBuffer *dstSurfaceBuffer = dst->extraInfo_->surfaceBuffer;
137     if (srcSurfaceBuffer == nullptr || dstSurfaceBuffer == nullptr ||
138         !ColorSpaceHelper::IsHdrColorSpace(src->bufferInfo_->colorSpace_)) {
139         return;
140     }
141 
142     CM_HDR_Metadata_Type type;
143     ColorSpaceHelper::GetSurfaceBufferMetadataType(srcSurfaceBuffer, type);
144     ColorSpaceHelper::SetSurfaceBufferMetadataType(dstSurfaceBuffer, type);
145 
146     CM_ColorSpaceType colorSpaceType;
147     ColorSpaceHelper::GetSurfaceBufferColorSpaceType(srcSurfaceBuffer, colorSpaceType);
148     ColorSpaceHelper::SetSurfaceBufferColorSpaceType(dstSurfaceBuffer, colorSpaceType);
149 }
150 
CropToOutputBuffer(EffectBuffer * src,std::shared_ptr<EffectContext> & context,std::shared_ptr<EffectBuffer> & output)151 ErrorCode CropEFilter::CropToOutputBuffer(EffectBuffer *src, std::shared_ptr<EffectContext> &context,
152     std::shared_ptr<EffectBuffer> &output)
153 {
154     CHECK_AND_RETURN_RET_LOG(src != nullptr, ErrorCode::ERR_INPUT_NULL, "input src is null!");
155     CHECK_AND_RETURN_RET_LOG(src->bufferInfo_ != nullptr, ErrorCode::ERR_INPUT_NULL,
156         "input error! src->bufferInfo_=%{public}d", src->bufferInfo_ == nullptr);
157 
158     Region region = { 0, 0, 0, 0 };
159     CalculateCropRegion(static_cast<int32_t>(src->bufferInfo_->width_), static_cast<int32_t>(src->bufferInfo_->height_),
160         values_, &region);
161     int32_t cropLeft = region.left;
162     int32_t cropTop = region.top;
163     int32_t cropWidth = region.width;
164     int32_t cropHeight = region.height;
165 
166     EFFECT_LOGI("CropEFilter cropLeft=%{public}d, cropTop=%{public}d, cropWidth=%{public}d, cropHeight=%{public}d",
167         cropLeft, cropTop, cropWidth, cropHeight);
168 
169     MemoryInfo allocMemInfo = {
170         .bufferInfo = {
171             .width_ = static_cast<uint32_t>(cropWidth),
172             .height_ = static_cast<uint32_t>(cropHeight),
173             .len_ = static_cast<uint32_t>(cropWidth * cropHeight * PIXEL_BYTES),
174             .formatType_ = src->bufferInfo_->formatType_,
175             .colorSpace_ = src->bufferInfo_->colorSpace_,
176         },
177         .extra = src->extraInfo_->surfaceBuffer,
178         .bufferType = ColorSpaceHelper::IsHdrColorSpace(src->bufferInfo_->colorSpace_) ?
179             BufferType::DMA_BUFFER : BufferType::DEFAULT,
180     };
181     MemoryData *memData = context->memoryManager_->AllocMemory(src->buffer_, allocMemInfo);
182     CHECK_AND_RETURN_RET_LOG(memData != nullptr, ErrorCode::ERR_ALLOC_MEMORY_FAIL, "alloc memory fail!");
183     std::shared_ptr<BufferInfo> bufferInfo = std::make_unique<BufferInfo>();
184     *bufferInfo = memData->memoryInfo.bufferInfo;
185     std::shared_ptr<ExtraInfo> extraInfo = std::make_unique<ExtraInfo>();
186     *extraInfo = *src->extraInfo_;
187     extraInfo->bufferType = memData->memoryInfo.bufferType;
188     extraInfo->surfaceBuffer = (memData->memoryInfo.bufferType == BufferType::DMA_BUFFER) ?
189         static_cast<OHOS::SurfaceBuffer *>(memData->memoryInfo.extra) : nullptr;
190     output = std::make_shared<EffectBuffer>(bufferInfo, memData->data, extraInfo);
191     UpdateDstEffectBufferIfNeed(src, output.get());
192     return Render(src, output.get(), context);
193 }
194 
Render(EffectBuffer * buffer,std::shared_ptr<EffectContext> & context)195 ErrorCode CropEFilter::Render(EffectBuffer *buffer, std::shared_ptr<EffectContext> &context)
196 {
197     DataType dataType = buffer->extraInfo_->dataType;
198     CHECK_AND_RETURN_RET_LOG(dataType == DataType::PIXEL_MAP || dataType == DataType::URI || dataType == DataType::PATH,
199         ErrorCode::ERR_UNSUPPORTED_DATA_TYPE, "crop only support pixelMap uri path! dataType=%{public}d", dataType);
200 
201     // only support RGBA for now.
202     IEffectFormat format = buffer->bufferInfo_->formatType_;
203     CHECK_AND_RETURN_RET_LOG(format == IEffectFormat::RGBA8888 || format == IEffectFormat::RGBA_1010102,
204         ErrorCode::ERR_UNSUPPORTED_FORMAT_TYPE, "crop not support format! format=%{public}d", format);
205 
206     std::shared_ptr<EffectBuffer> output;
207     ErrorCode res = CropToOutputBuffer(buffer, context, output);
208     CHECK_AND_RETURN_RET_LOG(res == ErrorCode::SUCCESS, res, "filter(%{public}s) render fail", name_.c_str());
209 
210     return PushData(output.get(), context);
211 }
212 
Negotiate(const std::shared_ptr<MemNegotiatedCap> & input,std::shared_ptr<EffectContext> & context)213 std::shared_ptr<MemNegotiatedCap> CropEFilter::Negotiate(const std::shared_ptr<MemNegotiatedCap> &input,
214     std::shared_ptr<EffectContext> &context)
215 {
216     Region region = { 0, 0, 0, 0 };
217     CalculateCropRegion(static_cast<int32_t>(input->width), static_cast<int32_t>(input->height), values_, &region);
218 
219     std::shared_ptr<MemNegotiatedCap> current = std::make_shared<MemNegotiatedCap>();
220     current->width = static_cast<uint32_t>(region.width);
221     current->height = static_cast<uint32_t>(region.height);
222     current->format = input->format;
223     return current;
224 }
225 
GetEffectInfo(const std::string & name)226 std::shared_ptr<EffectInfo> CropEFilter::GetEffectInfo(const std::string &name)
227 {
228     if (info_ != nullptr) {
229         return info_;
230     }
231     info_ = std::make_unique<EffectInfo>();
232     info_->formats_.emplace(IEffectFormat::RGBA8888, std::vector<IPType>{ IPType::CPU });
233     info_->formats_.emplace(IEffectFormat::RGBA_1010102, std::vector<IPType>{ IPType::CPU });
234     info_->category_ = Category::SHAPE_ADJUST;
235     info_->colorSpaces_ = {
236         EffectColorSpace::SRGB,
237         EffectColorSpace::SRGB_LIMIT,
238         EffectColorSpace::DISPLAY_P3,
239         EffectColorSpace::DISPLAY_P3_LIMIT,
240         EffectColorSpace::BT2020_HLG,
241         EffectColorSpace::BT2020_HLG_LIMIT,
242         EffectColorSpace::BT2020_PQ,
243         EffectColorSpace::BT2020_PQ_LIMIT
244     };
245     return info_;
246 }
247 
Restore(const EffectJsonPtr & values)248 ErrorCode CropEFilter::Restore(const EffectJsonPtr &values)
249 {
250     return ErrorCode::SUCCESS;
251 }
252 } // namespace Effect
253 } // namespace Media
254 } // namespace OHOS