1 /*
2 * Copyright 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <cstring>
18 #include <cstdint>
19 #include <cmath>
20
21 #include "ultrahdr/editorhelper.h"
22 #include "ultrahdr/gainmapmath.h"
23
24 namespace ultrahdr {
25
26 template <typename T>
rotate_buffer_clockwise(T * src_buffer,T * dst_buffer,int src_w,int src_h,int src_stride,int dst_stride,int degree)27 void rotate_buffer_clockwise(T* src_buffer, T* dst_buffer, int src_w, int src_h, int src_stride,
28 int dst_stride, int degree) {
29 if (degree == 90) {
30 int dst_w = src_h;
31 int dst_h = src_w;
32 for (int i = 0; i < dst_h; i++) {
33 for (int j = 0; j < dst_w; j++) {
34 dst_buffer[i * dst_stride + j] = src_buffer[(src_h - j - 1) * src_stride + i];
35 }
36 }
37 } else if (degree == 180) {
38 int dst_w = src_w;
39 int dst_h = src_h;
40 for (int i = 0; i < dst_h; i++) {
41 for (int j = 0; j < dst_w; j++) {
42 dst_buffer[i * dst_stride + j] = src_buffer[(src_h - i - 1) * src_stride + (src_w - j - 1)];
43 }
44 }
45 } else if (degree == 270) {
46 int dst_w = src_h;
47 int dst_h = src_w;
48 for (int i = 0; i < dst_h; i++) {
49 for (int j = 0; j < dst_w; j++) {
50 dst_buffer[i * dst_stride + j] = src_buffer[j * src_stride + (src_w - i - 1)];
51 }
52 }
53 }
54 }
55
56 template <typename T>
mirror_buffer(T * src_buffer,T * dst_buffer,int src_w,int src_h,int src_stride,int dst_stride,uhdr_mirror_direction_t direction)57 void mirror_buffer(T* src_buffer, T* dst_buffer, int src_w, int src_h, int src_stride,
58 int dst_stride, uhdr_mirror_direction_t direction) {
59 if (direction == UHDR_MIRROR_VERTICAL) {
60 for (int i = 0; i < src_h; i++) {
61 memcpy(&dst_buffer[(src_h - i - 1) * dst_stride], &src_buffer[i * src_stride],
62 src_w * sizeof(T));
63 }
64 } else if (direction == UHDR_MIRROR_HORIZONTAL) {
65 for (int i = 0; i < src_h; i++) {
66 for (int j = 0; j < src_w; j++) {
67 dst_buffer[i * dst_stride + j] = src_buffer[i * src_stride + (src_w - j - 1)];
68 }
69 }
70 }
71 }
72
73 template <typename T>
crop_buffer(T * src_buffer,T * dst_buffer,int src_stride,int dst_stride,int left,int top,int wd,int ht)74 void crop_buffer(T* src_buffer, T* dst_buffer, int src_stride, int dst_stride, int left, int top,
75 int wd, int ht) {
76 for (int row = 0; row < ht; row++) {
77 memcpy(&dst_buffer[row * dst_stride], &src_buffer[(top + row) * src_stride + left],
78 wd * sizeof(T));
79 }
80 }
81
82 // TODO (dichenzhang): legacy method, need to be removed
83 template <typename T>
resize_buffer(T * src_buffer,T * dst_buffer,int src_w,int src_h,int dst_w,int dst_h,int src_stride,int dst_stride)84 void resize_buffer(T* src_buffer, T* dst_buffer, int src_w, int src_h, int dst_w, int dst_h,
85 int src_stride, int dst_stride) {
86 for (int i = 0; i < dst_h; i++) {
87 for (int j = 0; j < dst_w; j++) {
88 dst_buffer[i * dst_stride + j] =
89 src_buffer[i * (src_h / dst_h) * src_stride + j * (src_w / dst_w)];
90 }
91 }
92 }
93
94 // This function performs bicubic interpolation on a 1D signal.
bicubic_interpolate(double p0,double p1,double p2,double p3,double x)95 double bicubic_interpolate(double p0, double p1, double p2, double p3, double x) {
96 // Calculate the weights for the four neighboring points.
97 double w0 = (1 - x) * (1 - x) * (1 - x);
98 double w1 = 3 * x * (1 - x) * (1 - x);
99 double w2 = 3 * x * x * (1 - x);
100 double w3 = x * x * x;
101
102 // Calculate the interpolated value.
103 return w0 * p0 + w1 * p1 + w2 * p2 + w3 * p3;
104 }
105
resize_image(uhdr_raw_image_t * src,int dst_w,int dst_h)106 std::unique_ptr<uhdr_raw_image_ext_t> resize_image(uhdr_raw_image_t* src, int dst_w, int dst_h) {
107 GetPixelFn get_pixel_fn = getPixelFn(src->fmt);
108 if (get_pixel_fn == nullptr) {
109 return nullptr;
110 }
111
112 PutPixelFn put_pixel_fn = putPixelFn(src->fmt);
113 if (put_pixel_fn == nullptr) {
114 return nullptr;
115 }
116
117 std::unique_ptr<uhdr_raw_image_ext_t> dst = std::make_unique<uhdr_raw_image_ext_t>(
118 src->fmt, src->cg, src->ct, src->range, dst_w, dst_h, 64);
119
120 int src_w = src->w;
121 int src_h = src->h;
122 double scale_x = (double)src_w / dst_w;
123 double scale_y = (double)src_h / dst_h;
124 for (int y = 0; y < dst_h; y++) {
125 for (int x = 0; x < dst_w; x++) {
126 double ori_x = x * scale_x;
127 double ori_y = y * scale_y;
128 int p0_x = CLIP3((int)floor(ori_x), 0, src_w - 1);
129 int p0_y = CLIP3((int)floor(ori_y), 0, src_h - 1);
130 int p1_x = CLIP3((p0_x + 1), 0, src_w - 1);
131 int p1_y = p0_y;
132 int p2_x = p0_x;
133 int p2_y = CLIP3((p0_y + 1), 0, src_h - 1);
134 int p3_x = CLIP3((p0_x + 1), 0, src_w - 1);
135 int p3_y = CLIP3((p0_y + 1), 0, src_h - 1);
136
137 Color p0 = get_pixel_fn(src, p0_x, p0_y);
138 Color p1 = get_pixel_fn(src, p1_x, p1_y);
139 Color p2 = get_pixel_fn(src, p2_x, p2_y);
140 Color p3 = get_pixel_fn(src, p3_x, p3_y);
141
142 Color interp;
143 interp.r = (float)bicubic_interpolate(p0.r, p1.r, p2.r, p3.r, ori_x - p0_x);
144 if (src->fmt != UHDR_IMG_FMT_8bppYCbCr400) {
145 interp.g = (float)bicubic_interpolate(p0.g, p1.g, p2.g, p3.g, ori_x - p0_x);
146 interp.b = (float)bicubic_interpolate(p0.b, p1.b, p2.b, p3.b, ori_x - p0_x);
147 }
148 put_pixel_fn(dst.get(), x, y, interp);
149 }
150 }
151 return dst;
152 }
153
154 template void mirror_buffer<uint8_t>(uint8_t*, uint8_t*, int, int, int, int,
155 uhdr_mirror_direction_t);
156 template void mirror_buffer<uint16_t>(uint16_t*, uint16_t*, int, int, int, int,
157 uhdr_mirror_direction_t);
158 template void mirror_buffer<uint32_t>(uint32_t*, uint32_t*, int, int, int, int,
159 uhdr_mirror_direction_t);
160 template void mirror_buffer<uint64_t>(uint64_t*, uint64_t*, int, int, int, int,
161 uhdr_mirror_direction_t);
162
163 template void rotate_buffer_clockwise<uint8_t>(uint8_t*, uint8_t*, int, int, int, int, int);
164 template void rotate_buffer_clockwise<uint16_t>(uint16_t*, uint16_t*, int, int, int, int, int);
165 template void rotate_buffer_clockwise<uint32_t>(uint32_t*, uint32_t*, int, int, int, int, int);
166 template void rotate_buffer_clockwise<uint64_t>(uint64_t*, uint64_t*, int, int, int, int, int);
167
168 template void resize_buffer<uint8_t>(uint8_t*, uint8_t*, int, int, int, int, int, int);
169 template void resize_buffer<uint16_t>(uint16_t*, uint16_t*, int, int, int, int, int, int);
170 template void resize_buffer<uint32_t>(uint32_t*, uint32_t*, int, int, int, int, int, int);
171 template void resize_buffer<uint64_t>(uint64_t*, uint64_t*, int, int, int, int, int, int);
172
uhdr_mirror_effect(uhdr_mirror_direction_t direction)173 uhdr_mirror_effect::uhdr_mirror_effect(uhdr_mirror_direction_t direction) : m_direction{direction} {
174 #if (defined(UHDR_ENABLE_INTRINSICS) && (defined(__ARM_NEON__) || defined(__ARM_NEON)))
175 m_mirror_uint8_t = mirror_buffer_neon<uint8_t>;
176 m_mirror_uint16_t = mirror_buffer_neon<uint16_t>;
177 m_mirror_uint32_t = mirror_buffer_neon<uint32_t>;
178 m_mirror_uint64_t = mirror_buffer_neon<uint64_t>;
179 #else
180 m_mirror_uint8_t = mirror_buffer<uint8_t>;
181 m_mirror_uint16_t = mirror_buffer<uint16_t>;
182 m_mirror_uint32_t = mirror_buffer<uint32_t>;
183 m_mirror_uint64_t = mirror_buffer<uint64_t>;
184 #endif
185 }
186
uhdr_rotate_effect(int degree)187 uhdr_rotate_effect::uhdr_rotate_effect(int degree) : m_degree{degree} {
188 #if (defined(UHDR_ENABLE_INTRINSICS) && (defined(__ARM_NEON__) || defined(__ARM_NEON)))
189 m_rotate_uint8_t = rotate_buffer_clockwise_neon<uint8_t>;
190 m_rotate_uint16_t = rotate_buffer_clockwise_neon<uint16_t>;
191 m_rotate_uint32_t = rotate_buffer_clockwise_neon<uint32_t>;
192 m_rotate_uint64_t = rotate_buffer_clockwise_neon<uint64_t>;
193 #else
194 m_rotate_uint8_t = rotate_buffer_clockwise<uint8_t>;
195 m_rotate_uint16_t = rotate_buffer_clockwise<uint16_t>;
196 m_rotate_uint32_t = rotate_buffer_clockwise<uint32_t>;
197 m_rotate_uint64_t = rotate_buffer_clockwise<uint64_t>;
198 #endif
199 }
200
uhdr_crop_effect(int left,int right,int top,int bottom)201 uhdr_crop_effect::uhdr_crop_effect(int left, int right, int top, int bottom)
202 : m_left(left), m_right(right), m_top(top), m_bottom(bottom) {
203 m_crop_uint8_t = crop_buffer<uint8_t>;
204 m_crop_uint16_t = crop_buffer<uint16_t>;
205 m_crop_uint32_t = crop_buffer<uint32_t>;
206 m_crop_uint64_t = crop_buffer<uint64_t>;
207 }
208
uhdr_resize_effect(int width,int height)209 uhdr_resize_effect::uhdr_resize_effect(int width, int height) : m_width{width}, m_height{height} {
210 m_resize_uint8_t = resize_buffer<uint8_t>;
211 m_resize_uint16_t = resize_buffer<uint16_t>;
212 m_resize_uint32_t = resize_buffer<uint32_t>;
213 m_resize_uint64_t = resize_buffer<uint64_t>;
214 }
215
apply_rotate(ultrahdr::uhdr_rotate_effect_t * desc,uhdr_raw_image_t * src,void * gl_ctxt,void * texture)216 std::unique_ptr<uhdr_raw_image_ext_t> apply_rotate(ultrahdr::uhdr_rotate_effect_t* desc,
217 uhdr_raw_image_t* src,
218 [[maybe_unused]] void* gl_ctxt,
219 [[maybe_unused]] void* texture) {
220 #ifdef UHDR_ENABLE_GLES
221 if ((src->fmt == UHDR_IMG_FMT_32bppRGBA1010102 || src->fmt == UHDR_IMG_FMT_32bppRGBA8888 ||
222 src->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat || src->fmt == UHDR_IMG_FMT_8bppYCbCr400) &&
223 gl_ctxt != nullptr && *static_cast<GLuint*>(texture) != 0) {
224 return apply_rotate_gles(desc, src, static_cast<ultrahdr::uhdr_opengl_ctxt*>(gl_ctxt),
225 static_cast<GLuint*>(texture));
226 }
227 #endif
228 std::unique_ptr<uhdr_raw_image_ext_t> dst;
229
230 if (desc->m_degree == 90 || desc->m_degree == 270) {
231 dst = std::make_unique<uhdr_raw_image_ext_t>(src->fmt, src->cg, src->ct, src->range, src->h,
232 src->w, 64);
233 } else if (desc->m_degree == 180) {
234 dst = std::make_unique<uhdr_raw_image_ext_t>(src->fmt, src->cg, src->ct, src->range, src->w,
235 src->h, 64);
236 } else {
237 return nullptr;
238 }
239
240 if (src->fmt == UHDR_IMG_FMT_24bppYCbCrP010) {
241 uint16_t* src_buffer = static_cast<uint16_t*>(src->planes[UHDR_PLANE_Y]);
242 uint16_t* dst_buffer = static_cast<uint16_t*>(dst->planes[UHDR_PLANE_Y]);
243 desc->m_rotate_uint16_t(src_buffer, dst_buffer, src->w, src->h, src->stride[UHDR_PLANE_Y],
244 dst->stride[UHDR_PLANE_Y], desc->m_degree);
245 uint32_t* src_uv_buffer = static_cast<uint32_t*>(src->planes[UHDR_PLANE_UV]);
246 uint32_t* dst_uv_buffer = static_cast<uint32_t*>(dst->planes[UHDR_PLANE_UV]);
247 desc->m_rotate_uint32_t(src_uv_buffer, dst_uv_buffer, src->w / 2, src->h / 2,
248 src->stride[UHDR_PLANE_UV] / 2, dst->stride[UHDR_PLANE_UV] / 2,
249 desc->m_degree);
250 } else if (src->fmt == UHDR_IMG_FMT_12bppYCbCr420 || src->fmt == UHDR_IMG_FMT_8bppYCbCr400) {
251 uint8_t* src_buffer = static_cast<uint8_t*>(src->planes[UHDR_PLANE_Y]);
252 uint8_t* dst_buffer = static_cast<uint8_t*>(dst->planes[UHDR_PLANE_Y]);
253 desc->m_rotate_uint8_t(src_buffer, dst_buffer, src->w, src->h, src->stride[UHDR_PLANE_Y],
254 dst->stride[UHDR_PLANE_Y], desc->m_degree);
255 if (src->fmt == UHDR_IMG_FMT_12bppYCbCr420) {
256 for (int i = 1; i < 3; i++) {
257 src_buffer = static_cast<uint8_t*>(src->planes[i]);
258 dst_buffer = static_cast<uint8_t*>(dst->planes[i]);
259 desc->m_rotate_uint8_t(src_buffer, dst_buffer, src->w / 2, src->h / 2, src->stride[i],
260 dst->stride[i], desc->m_degree);
261 }
262 }
263 } else if (src->fmt == UHDR_IMG_FMT_32bppRGBA1010102 || src->fmt == UHDR_IMG_FMT_32bppRGBA8888) {
264 uint32_t* src_buffer = static_cast<uint32_t*>(src->planes[UHDR_PLANE_PACKED]);
265 uint32_t* dst_buffer = static_cast<uint32_t*>(dst->planes[UHDR_PLANE_PACKED]);
266 desc->m_rotate_uint32_t(src_buffer, dst_buffer, src->w, src->h, src->stride[UHDR_PLANE_PACKED],
267 dst->stride[UHDR_PLANE_PACKED], desc->m_degree);
268 } else if (src->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat) {
269 uint64_t* src_buffer = static_cast<uint64_t*>(src->planes[UHDR_PLANE_PACKED]);
270 uint64_t* dst_buffer = static_cast<uint64_t*>(dst->planes[UHDR_PLANE_PACKED]);
271 desc->m_rotate_uint64_t(src_buffer, dst_buffer, src->w, src->h, src->stride[UHDR_PLANE_PACKED],
272 dst->stride[UHDR_PLANE_PACKED], desc->m_degree);
273 } else if (src->fmt == UHDR_IMG_FMT_24bppYCbCr444) {
274 for (int i = 0; i < 3; i++) {
275 uint8_t* src_buffer = static_cast<uint8_t*>(src->planes[i]);
276 uint8_t* dst_buffer = static_cast<uint8_t*>(dst->planes[i]);
277 desc->m_rotate_uint8_t(src_buffer, dst_buffer, src->w, src->h, src->stride[i], dst->stride[i],
278 desc->m_degree);
279 }
280 } else if (src->fmt == UHDR_IMG_FMT_30bppYCbCr444) {
281 for (int i = 0; i < 3; i++) {
282 uint16_t* src_buffer = static_cast<uint16_t*>(src->planes[i]);
283 uint16_t* dst_buffer = static_cast<uint16_t*>(dst->planes[i]);
284 desc->m_rotate_uint16_t(src_buffer, dst_buffer, src->w, src->h, src->stride[i],
285 dst->stride[i], desc->m_degree);
286 }
287 }
288 return dst;
289 }
290
apply_mirror(ultrahdr::uhdr_mirror_effect_t * desc,uhdr_raw_image_t * src,void * gl_ctxt,void * texture)291 std::unique_ptr<uhdr_raw_image_ext_t> apply_mirror(ultrahdr::uhdr_mirror_effect_t* desc,
292 uhdr_raw_image_t* src,
293 [[maybe_unused]] void* gl_ctxt,
294 [[maybe_unused]] void* texture) {
295 #ifdef UHDR_ENABLE_GLES
296 if ((src->fmt == UHDR_IMG_FMT_32bppRGBA1010102 || src->fmt == UHDR_IMG_FMT_32bppRGBA8888 ||
297 src->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat || src->fmt == UHDR_IMG_FMT_8bppYCbCr400) &&
298 gl_ctxt != nullptr && *static_cast<GLuint*>(texture) != 0) {
299 return apply_mirror_gles(desc, src, static_cast<ultrahdr::uhdr_opengl_ctxt*>(gl_ctxt),
300 static_cast<GLuint*>(texture));
301 }
302 #endif
303 std::unique_ptr<uhdr_raw_image_ext_t> dst = std::make_unique<uhdr_raw_image_ext_t>(
304 src->fmt, src->cg, src->ct, src->range, src->w, src->h, 64);
305
306 if (src->fmt == UHDR_IMG_FMT_24bppYCbCrP010) {
307 uint16_t* src_buffer = static_cast<uint16_t*>(src->planes[UHDR_PLANE_Y]);
308 uint16_t* dst_buffer = static_cast<uint16_t*>(dst->planes[UHDR_PLANE_Y]);
309 desc->m_mirror_uint16_t(src_buffer, dst_buffer, src->w, src->h, src->stride[UHDR_PLANE_Y],
310 dst->stride[UHDR_PLANE_Y], desc->m_direction);
311 uint32_t* src_uv_buffer = static_cast<uint32_t*>(src->planes[UHDR_PLANE_UV]);
312 uint32_t* dst_uv_buffer = static_cast<uint32_t*>(dst->planes[UHDR_PLANE_UV]);
313 desc->m_mirror_uint32_t(src_uv_buffer, dst_uv_buffer, src->w / 2, src->h / 2,
314 src->stride[UHDR_PLANE_UV] / 2, dst->stride[UHDR_PLANE_UV] / 2,
315 desc->m_direction);
316 } else if (src->fmt == UHDR_IMG_FMT_12bppYCbCr420 || src->fmt == UHDR_IMG_FMT_8bppYCbCr400) {
317 uint8_t* src_buffer = static_cast<uint8_t*>(src->planes[UHDR_PLANE_Y]);
318 uint8_t* dst_buffer = static_cast<uint8_t*>(dst->planes[UHDR_PLANE_Y]);
319 desc->m_mirror_uint8_t(src_buffer, dst_buffer, src->w, src->h, src->stride[UHDR_PLANE_Y],
320 dst->stride[UHDR_PLANE_Y], desc->m_direction);
321 if (src->fmt == UHDR_IMG_FMT_12bppYCbCr420) {
322 for (int i = 1; i < 3; i++) {
323 src_buffer = static_cast<uint8_t*>(src->planes[i]);
324 dst_buffer = static_cast<uint8_t*>(dst->planes[i]);
325 desc->m_mirror_uint8_t(src_buffer, dst_buffer, src->w / 2, src->h / 2, src->stride[i],
326 dst->stride[i], desc->m_direction);
327 }
328 }
329 } else if (src->fmt == UHDR_IMG_FMT_32bppRGBA1010102 || src->fmt == UHDR_IMG_FMT_32bppRGBA8888) {
330 uint32_t* src_buffer = static_cast<uint32_t*>(src->planes[UHDR_PLANE_PACKED]);
331 uint32_t* dst_buffer = static_cast<uint32_t*>(dst->planes[UHDR_PLANE_PACKED]);
332 desc->m_mirror_uint32_t(src_buffer, dst_buffer, src->w, src->h, src->stride[UHDR_PLANE_PACKED],
333 dst->stride[UHDR_PLANE_PACKED], desc->m_direction);
334 } else if (src->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat) {
335 uint64_t* src_buffer = static_cast<uint64_t*>(src->planes[UHDR_PLANE_PACKED]);
336 uint64_t* dst_buffer = static_cast<uint64_t*>(dst->planes[UHDR_PLANE_PACKED]);
337 desc->m_mirror_uint64_t(src_buffer, dst_buffer, src->w, src->h, src->stride[UHDR_PLANE_PACKED],
338 dst->stride[UHDR_PLANE_PACKED], desc->m_direction);
339 } else if (src->fmt == UHDR_IMG_FMT_24bppYCbCr444) {
340 for (int i = 0; i < 3; i++) {
341 uint8_t* src_buffer = static_cast<uint8_t*>(src->planes[i]);
342 uint8_t* dst_buffer = static_cast<uint8_t*>(dst->planes[i]);
343 desc->m_mirror_uint8_t(src_buffer, dst_buffer, src->w, src->h, src->stride[i], dst->stride[i],
344 desc->m_direction);
345 }
346 } else if (src->fmt == UHDR_IMG_FMT_30bppYCbCr444) {
347 for (int i = 0; i < 3; i++) {
348 uint16_t* src_buffer = static_cast<uint16_t*>(src->planes[i]);
349 uint16_t* dst_buffer = static_cast<uint16_t*>(dst->planes[i]);
350 desc->m_mirror_uint16_t(src_buffer, dst_buffer, src->w, src->h, src->stride[i],
351 dst->stride[i], desc->m_direction);
352 }
353 }
354 return dst;
355 }
356
apply_crop(ultrahdr::uhdr_crop_effect_t * desc,uhdr_raw_image_t * src,int left,int top,int wd,int ht,void * gl_ctxt,void * texture)357 std::unique_ptr<uhdr_raw_image_ext_t> apply_crop(ultrahdr::uhdr_crop_effect_t* desc,
358 uhdr_raw_image_t* src, int left, int top, int wd,
359 int ht, [[maybe_unused]] void* gl_ctxt,
360 [[maybe_unused]] void* texture) {
361 #ifdef UHDR_ENABLE_GLES
362 if ((src->fmt == UHDR_IMG_FMT_32bppRGBA1010102 || src->fmt == UHDR_IMG_FMT_32bppRGBA8888 ||
363 src->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat || src->fmt == UHDR_IMG_FMT_8bppYCbCr400) &&
364 gl_ctxt != nullptr && *static_cast<GLuint*>(texture) != 0) {
365 return apply_crop_gles(src, left, top, wd, ht,
366 static_cast<ultrahdr::uhdr_opengl_ctxt*>(gl_ctxt),
367 static_cast<GLuint*>(texture));
368 }
369 #endif
370 std::unique_ptr<uhdr_raw_image_ext_t> dst =
371 std::make_unique<uhdr_raw_image_ext_t>(src->fmt, src->cg, src->ct, src->range, wd, ht, 64);
372
373 if (src->fmt == UHDR_IMG_FMT_24bppYCbCrP010) {
374 uint16_t* src_buffer = static_cast<uint16_t*>(src->planes[UHDR_PLANE_Y]);
375 uint16_t* dst_buffer = static_cast<uint16_t*>(dst->planes[UHDR_PLANE_Y]);
376 desc->m_crop_uint16_t(src_buffer, dst_buffer, src->stride[UHDR_PLANE_Y],
377 dst->stride[UHDR_PLANE_Y], left, top, wd, ht);
378 uint32_t* src_uv_buffer = static_cast<uint32_t*>(src->planes[UHDR_PLANE_UV]);
379 uint32_t* dst_uv_buffer = static_cast<uint32_t*>(dst->planes[UHDR_PLANE_UV]);
380 desc->m_crop_uint32_t(src_uv_buffer, dst_uv_buffer, src->stride[UHDR_PLANE_UV] / 2,
381 dst->stride[UHDR_PLANE_UV] / 2, left / 2, top / 2, wd / 2, ht / 2);
382 } else if (src->fmt == UHDR_IMG_FMT_12bppYCbCr420 || src->fmt == UHDR_IMG_FMT_8bppYCbCr400) {
383 uint8_t* src_buffer = static_cast<uint8_t*>(src->planes[UHDR_PLANE_Y]);
384 uint8_t* dst_buffer = static_cast<uint8_t*>(dst->planes[UHDR_PLANE_Y]);
385 desc->m_crop_uint8_t(src_buffer, dst_buffer, src->stride[UHDR_PLANE_Y],
386 dst->stride[UHDR_PLANE_Y], left, top, wd, ht);
387 if (src->fmt == UHDR_IMG_FMT_12bppYCbCr420) {
388 for (int i = 1; i < 3; i++) {
389 src_buffer = static_cast<uint8_t*>(src->planes[i]);
390 dst_buffer = static_cast<uint8_t*>(dst->planes[i]);
391 desc->m_crop_uint8_t(src_buffer, dst_buffer, src->stride[i], dst->stride[i], left / 2,
392 top / 2, wd / 2, ht / 2);
393 }
394 }
395 } else if (src->fmt == UHDR_IMG_FMT_32bppRGBA1010102 || src->fmt == UHDR_IMG_FMT_32bppRGBA8888) {
396 uint32_t* src_buffer = static_cast<uint32_t*>(src->planes[UHDR_PLANE_PACKED]);
397 uint32_t* dst_buffer = static_cast<uint32_t*>(dst->planes[UHDR_PLANE_PACKED]);
398 desc->m_crop_uint32_t(src_buffer, dst_buffer, src->stride[UHDR_PLANE_PACKED],
399 dst->stride[UHDR_PLANE_PACKED], left, top, wd, ht);
400 } else if (src->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat) {
401 uint64_t* src_buffer = static_cast<uint64_t*>(src->planes[UHDR_PLANE_PACKED]);
402 uint64_t* dst_buffer = static_cast<uint64_t*>(dst->planes[UHDR_PLANE_PACKED]);
403 desc->m_crop_uint64_t(src_buffer, dst_buffer, src->stride[UHDR_PLANE_PACKED],
404 dst->stride[UHDR_PLANE_PACKED], left, top, wd, ht);
405 } else if (src->fmt == UHDR_IMG_FMT_24bppYCbCr444) {
406 for (int i = 0; i < 3; i++) {
407 uint8_t* src_buffer = static_cast<uint8_t*>(src->planes[i]);
408 uint8_t* dst_buffer = static_cast<uint8_t*>(dst->planes[i]);
409 desc->m_crop_uint8_t(src_buffer, dst_buffer, src->stride[i], dst->stride[i], left, top, wd,
410 ht);
411 }
412 } else if (src->fmt == UHDR_IMG_FMT_30bppYCbCr444) {
413 for (int i = 0; i < 3; i++) {
414 uint16_t* src_buffer = static_cast<uint16_t*>(src->planes[i]);
415 uint16_t* dst_buffer = static_cast<uint16_t*>(dst->planes[i]);
416 desc->m_crop_uint16_t(src_buffer, dst_buffer, src->stride[UHDR_PLANE_PACKED],
417 dst->stride[UHDR_PLANE_PACKED], left, top, wd, ht);
418 }
419 }
420 return dst;
421 }
422
apply_resize(ultrahdr::uhdr_resize_effect_t * desc,uhdr_raw_image_t * src,int dst_w,int dst_h,void * gl_ctxt,void * texture)423 std::unique_ptr<uhdr_raw_image_ext_t> apply_resize(ultrahdr::uhdr_resize_effect_t* desc,
424 uhdr_raw_image_t* src, int dst_w, int dst_h,
425 [[maybe_unused]] void* gl_ctxt,
426 [[maybe_unused]] void* texture) {
427 #ifdef UHDR_ENABLE_GLES
428 if ((src->fmt == UHDR_IMG_FMT_32bppRGBA1010102 || src->fmt == UHDR_IMG_FMT_32bppRGBA8888 ||
429 src->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat || src->fmt == UHDR_IMG_FMT_8bppYCbCr400) &&
430 gl_ctxt != nullptr && *static_cast<GLuint*>(texture) != 0) {
431 return apply_resize_gles(src, dst_w, dst_h, static_cast<ultrahdr::uhdr_opengl_ctxt*>(gl_ctxt),
432 static_cast<GLuint*>(texture));
433 }
434 #endif
435 std::unique_ptr<uhdr_raw_image_ext_t> dst = std::make_unique<uhdr_raw_image_ext_t>(
436 src->fmt, src->cg, src->ct, src->range, dst_w, dst_h, 64);
437
438 if (src->fmt == UHDR_IMG_FMT_24bppYCbCrP010) {
439 uint16_t* src_buffer = static_cast<uint16_t*>(src->planes[UHDR_PLANE_Y]);
440 uint16_t* dst_buffer = static_cast<uint16_t*>(dst->planes[UHDR_PLANE_Y]);
441 desc->m_resize_uint16_t(src_buffer, dst_buffer, src->w, src->h, dst->w, dst->h,
442 src->stride[UHDR_PLANE_Y], dst->stride[UHDR_PLANE_Y]);
443 uint32_t* src_uv_buffer = static_cast<uint32_t*>(src->planes[UHDR_PLANE_UV]);
444 uint32_t* dst_uv_buffer = static_cast<uint32_t*>(dst->planes[UHDR_PLANE_UV]);
445 desc->m_resize_uint32_t(src_uv_buffer, dst_uv_buffer, src->w / 2, src->h / 2, dst->w / 2,
446 dst->h / 2, src->stride[UHDR_PLANE_UV] / 2,
447 dst->stride[UHDR_PLANE_UV] / 2);
448 } else if (src->fmt == UHDR_IMG_FMT_12bppYCbCr420 || src->fmt == UHDR_IMG_FMT_8bppYCbCr400) {
449 uint8_t* src_buffer = static_cast<uint8_t*>(src->planes[UHDR_PLANE_Y]);
450 uint8_t* dst_buffer = static_cast<uint8_t*>(dst->planes[UHDR_PLANE_Y]);
451 desc->m_resize_uint8_t(src_buffer, dst_buffer, src->w, src->h, dst->w, dst->h,
452 src->stride[UHDR_PLANE_Y], dst->stride[UHDR_PLANE_Y]);
453 if (src->fmt == UHDR_IMG_FMT_12bppYCbCr420) {
454 for (int i = 1; i < 3; i++) {
455 src_buffer = static_cast<uint8_t*>(src->planes[i]);
456 dst_buffer = static_cast<uint8_t*>(dst->planes[i]);
457 desc->m_resize_uint8_t(src_buffer, dst_buffer, src->w / 2, src->h / 2, dst->w / 2,
458 dst->h / 2, src->stride[i], dst->stride[i]);
459 }
460 }
461 } else if (src->fmt == UHDR_IMG_FMT_32bppRGBA1010102 || src->fmt == UHDR_IMG_FMT_32bppRGBA8888) {
462 uint32_t* src_buffer = static_cast<uint32_t*>(src->planes[UHDR_PLANE_PACKED]);
463 uint32_t* dst_buffer = static_cast<uint32_t*>(dst->planes[UHDR_PLANE_PACKED]);
464 desc->m_resize_uint32_t(src_buffer, dst_buffer, src->w, src->h, dst->w, dst->h,
465 src->stride[UHDR_PLANE_PACKED], dst->stride[UHDR_PLANE_PACKED]);
466 } else if (src->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat) {
467 uint64_t* src_buffer = static_cast<uint64_t*>(src->planes[UHDR_PLANE_PACKED]);
468 uint64_t* dst_buffer = static_cast<uint64_t*>(dst->planes[UHDR_PLANE_PACKED]);
469 desc->m_resize_uint64_t(src_buffer, dst_buffer, src->w, src->h, dst->w, dst->h,
470 src->stride[UHDR_PLANE_PACKED], dst->stride[UHDR_PLANE_PACKED]);
471 } else if (src->fmt == UHDR_IMG_FMT_24bppYCbCr444) {
472 for (int i = 0; i < 3; i++) {
473 uint8_t* src_buffer = static_cast<uint8_t*>(src->planes[i]);
474 uint8_t* dst_buffer = static_cast<uint8_t*>(dst->planes[i]);
475 desc->m_resize_uint8_t(src_buffer, dst_buffer, src->w, src->h, dst->w, dst->h, src->stride[i],
476 dst->stride[i]);
477 }
478 } else if (src->fmt == UHDR_IMG_FMT_30bppYCbCr444) {
479 for (int i = 0; i < 3; i++) {
480 uint16_t* src_buffer = static_cast<uint16_t*>(src->planes[i]);
481 uint16_t* dst_buffer = static_cast<uint16_t*>(dst->planes[i]);
482 desc->m_resize_uint16_t(src_buffer, dst_buffer, src->w, src->h, dst->w, dst->h,
483 src->stride[i], dst->stride[i]);
484 }
485 }
486 return dst;
487 }
488
489 } // namespace ultrahdr
490