xref: /aosp_15_r20/external/libultrahdr/lib/src/editorhelper.cpp (revision 89a0ef05262152531a00a15832a2d3b1e3990773)
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