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_, ®ion);
129 Crop(src, dst, ®ion);
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_, ®ion);
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_, ®ion);
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