/src/libvpx/vpx_scale/generic/vpx_scale.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2010 The WebM project authors. All Rights Reserved. |
3 | | * |
4 | | * Use of this source code is governed by a BSD-style license |
5 | | * that can be found in the LICENSE file in the root of the source |
6 | | * tree. An additional intellectual property rights grant can be found |
7 | | * in the file PATENTS. All contributing project authors may |
8 | | * be found in the AUTHORS file in the root of the source tree. |
9 | | */ |
10 | | |
11 | | /**************************************************************************** |
12 | | * |
13 | | * Module Title : scale.c |
14 | | * |
15 | | * Description : Image scaling functions. |
16 | | * |
17 | | ***************************************************************************/ |
18 | | |
19 | | /**************************************************************************** |
20 | | * Header Files |
21 | | ****************************************************************************/ |
22 | | #include <assert.h> |
23 | | |
24 | | #include "./vpx_scale_rtcd.h" |
25 | | #include "vpx_mem/vpx_mem.h" |
26 | | #include "vpx_scale/vpx_scale.h" |
27 | | #include "vpx_scale/yv12config.h" |
28 | | |
29 | | typedef struct { |
30 | | int expanded_frame_width; |
31 | | int expanded_frame_height; |
32 | | |
33 | | int HScale; |
34 | | int HRatio; |
35 | | int VScale; |
36 | | int VRatio; |
37 | | |
38 | | YV12_BUFFER_CONFIG *src_yuv_config; |
39 | | YV12_BUFFER_CONFIG *dst_yuv_config; |
40 | | |
41 | | } SCALE_VARS; |
42 | | |
43 | | /**************************************************************************** |
44 | | * |
45 | | * ROUTINE : scale1d_2t1_i |
46 | | * |
47 | | * INPUTS : const unsigned char *source : Pointer to data to be scaled. |
48 | | * int source_step : Number of pixels to step on in |
49 | | * source. |
50 | | * unsigned int source_scale : Scale for source (UNUSED). |
51 | | * unsigned int source_length : Length of source (UNUSED). |
52 | | * unsigned char *dest : Pointer to output data array. |
53 | | * int dest_step : Number of pixels to step on in |
54 | | * destination. |
55 | | * unsigned int dest_scale : Scale for destination |
56 | | * (UNUSED). |
57 | | * unsigned int dest_length : Length of destination. |
58 | | * |
59 | | * OUTPUTS : None. |
60 | | * |
61 | | * RETURNS : void |
62 | | * |
63 | | * FUNCTION : Performs 2-to-1 interpolated scaling. |
64 | | * |
65 | | * SPECIAL NOTES : None. |
66 | | * |
67 | | ****************************************************************************/ |
68 | | static void scale1d_2t1_i(const unsigned char *source, int source_step, |
69 | | unsigned int source_scale, unsigned int source_length, |
70 | | unsigned char *dest, int dest_step, |
71 | 0 | unsigned int dest_scale, unsigned int dest_length) { |
72 | 0 | unsigned int i, j; |
73 | 0 | unsigned int temp; |
74 | 0 | int source_pitch = source_step; |
75 | 0 | (void)source_length; |
76 | 0 | (void)source_scale; |
77 | 0 | (void)dest_scale; |
78 | |
|
79 | 0 | source_step *= 2; |
80 | 0 | dest[0] = source[0]; |
81 | |
|
82 | 0 | for (i = dest_step, j = source_step; i < dest_length * dest_step; |
83 | 0 | i += dest_step, j += source_step) { |
84 | 0 | temp = 8; |
85 | 0 | temp += 3 * source[j - source_pitch]; |
86 | 0 | temp += 10 * source[j]; |
87 | 0 | temp += 3 * source[j + source_pitch]; |
88 | 0 | temp >>= 4; |
89 | 0 | dest[i] = (char)(temp); |
90 | 0 | } |
91 | 0 | } |
92 | | |
93 | | /**************************************************************************** |
94 | | * |
95 | | * ROUTINE : scale1d_2t1_ps |
96 | | * |
97 | | * INPUTS : const unsigned char *source : Pointer to data to be scaled. |
98 | | * int source_step : Number of pixels to step on in |
99 | | * source. |
100 | | * unsigned int source_scale : Scale for source (UNUSED). |
101 | | * unsigned int source_length : Length of source (UNUSED). |
102 | | * unsigned char *dest : Pointer to output data array. |
103 | | * int dest_step : Number of pixels to step on in |
104 | | * destination. |
105 | | * unsigned int dest_scale : Scale for destination |
106 | | * (UNUSED). |
107 | | * unsigned int dest_length : Length of destination. |
108 | | * |
109 | | * OUTPUTS : None. |
110 | | * |
111 | | * RETURNS : void |
112 | | * |
113 | | * FUNCTION : Performs 2-to-1 point subsampled scaling. |
114 | | * |
115 | | * SPECIAL NOTES : None. |
116 | | * |
117 | | ****************************************************************************/ |
118 | | static void scale1d_2t1_ps(const unsigned char *source, int source_step, |
119 | | unsigned int source_scale, |
120 | | unsigned int source_length, unsigned char *dest, |
121 | | int dest_step, unsigned int dest_scale, |
122 | 0 | unsigned int dest_length) { |
123 | 0 | unsigned int i, j; |
124 | |
|
125 | 0 | (void)source_length; |
126 | 0 | (void)source_scale; |
127 | 0 | (void)dest_scale; |
128 | |
|
129 | 0 | source_step *= 2; |
130 | 0 | j = 0; |
131 | |
|
132 | 0 | for (i = 0; i < dest_length * dest_step; i += dest_step, j += source_step) |
133 | 0 | dest[i] = source[j]; |
134 | 0 | } |
135 | | /**************************************************************************** |
136 | | * |
137 | | * ROUTINE : scale1d_c |
138 | | * |
139 | | * INPUTS : const unsigned char *source : Pointer to data to be scaled. |
140 | | * int source_step : Number of pixels to step on in |
141 | | * source. |
142 | | * unsigned int source_scale : Scale for source. |
143 | | * unsigned int source_length : Length of source (UNUSED). |
144 | | * unsigned char *dest : Pointer to output data array. |
145 | | * int dest_step : Number of pixels to step on in |
146 | | * destination. |
147 | | * unsigned int dest_scale : Scale for destination. |
148 | | * unsigned int dest_length : Length of destination. |
149 | | * |
150 | | * OUTPUTS : None. |
151 | | * |
152 | | * RETURNS : void |
153 | | * |
154 | | * FUNCTION : Performs linear interpolation in one dimension. |
155 | | * |
156 | | * SPECIAL NOTES : None. |
157 | | * |
158 | | ****************************************************************************/ |
159 | | static void scale1d_c(const unsigned char *source, int source_step, |
160 | | unsigned int source_scale, unsigned int source_length, |
161 | | unsigned char *dest, int dest_step, |
162 | 0 | unsigned int dest_scale, unsigned int dest_length) { |
163 | 0 | unsigned int i; |
164 | 0 | unsigned int round_value = dest_scale / 2; |
165 | 0 | unsigned int left_modifier = dest_scale; |
166 | 0 | unsigned int right_modifier = 0; |
167 | 0 | unsigned char left_pixel = *source; |
168 | 0 | unsigned char right_pixel = *(source + source_step); |
169 | |
|
170 | 0 | (void)source_length; |
171 | | |
172 | | /* These asserts are needed if there are boundary issues... */ |
173 | | /*assert ( dest_scale > source_scale );*/ |
174 | | /*assert ( (source_length-1) * dest_scale >= (dest_length-1) * source_scale |
175 | | * );*/ |
176 | |
|
177 | 0 | assert(dest_scale != 0); |
178 | 0 | for (i = 0; i < dest_length * dest_step; i += dest_step) { |
179 | 0 | dest[i] = (char)((left_modifier * left_pixel + |
180 | 0 | right_modifier * right_pixel + round_value) / |
181 | 0 | dest_scale); |
182 | |
|
183 | 0 | right_modifier += source_scale; |
184 | |
|
185 | 0 | while (right_modifier > dest_scale) { |
186 | 0 | right_modifier -= dest_scale; |
187 | 0 | source += source_step; |
188 | 0 | left_pixel = *source; |
189 | 0 | right_pixel = *(source + source_step); |
190 | 0 | } |
191 | |
|
192 | 0 | left_modifier = dest_scale - right_modifier; |
193 | 0 | } |
194 | 0 | } |
195 | | |
196 | | /**************************************************************************** |
197 | | * |
198 | | * ROUTINE : Scale2D |
199 | | * |
200 | | * INPUTS : const unsigned char *source : Pointer to data to be |
201 | | * scaled. |
202 | | * int source_pitch : Stride of source image. |
203 | | * unsigned int source_width : Width of input image. |
204 | | * unsigned int source_height : Height of input image. |
205 | | * unsigned char *dest : Pointer to output data |
206 | | * array. |
207 | | * int dest_pitch : Stride of destination |
208 | | * image. |
209 | | * unsigned int dest_width : Width of destination image. |
210 | | * unsigned int dest_height : Height of destination |
211 | | * image. |
212 | | * unsigned char *temp_area : Pointer to temp work area. |
213 | | * unsigned char temp_area_height : Height of temp work area. |
214 | | * unsigned int hscale : Horizontal scale factor |
215 | | * numerator. |
216 | | * unsigned int hratio : Horizontal scale factor |
217 | | * denominator. |
218 | | * unsigned int vscale : Vertical scale factor |
219 | | * numerator. |
220 | | * unsigned int vratio : Vertical scale factor |
221 | | * denominator. |
222 | | * unsigned int interlaced : Interlace flag. |
223 | | * |
224 | | * OUTPUTS : None. |
225 | | * |
226 | | * RETURNS : void |
227 | | * |
228 | | * FUNCTION : Performs 2-tap linear interpolation in two dimensions. |
229 | | * |
230 | | * SPECIAL NOTES : Expansion is performed one band at a time to help with |
231 | | * caching. |
232 | | * |
233 | | ****************************************************************************/ |
234 | | static void Scale2D( |
235 | | /*const*/ |
236 | | unsigned char *source, int source_pitch, unsigned int source_width, |
237 | | unsigned int source_height, unsigned char *dest, int dest_pitch, |
238 | | unsigned int dest_width, unsigned int dest_height, unsigned char *temp_area, |
239 | | unsigned char temp_area_height, unsigned int hscale, unsigned int hratio, |
240 | 0 | unsigned int vscale, unsigned int vratio, unsigned int interlaced) { |
241 | | /*unsigned*/ |
242 | 0 | int i, j, k; |
243 | 0 | int bands; |
244 | 0 | int dest_band_height; |
245 | 0 | int source_band_height; |
246 | |
|
247 | 0 | typedef void (*Scale1D)(const unsigned char *source, int source_step, |
248 | 0 | unsigned int source_scale, unsigned int source_length, |
249 | 0 | unsigned char *dest, int dest_step, |
250 | 0 | unsigned int dest_scale, unsigned int dest_length); |
251 | |
|
252 | 0 | Scale1D Scale1Dv = scale1d_c; |
253 | 0 | Scale1D Scale1Dh = scale1d_c; |
254 | |
|
255 | 0 | void (*horiz_line_scale)(const unsigned char *, unsigned int, unsigned char *, |
256 | 0 | unsigned int) = NULL; |
257 | 0 | void (*vert_band_scale)(unsigned char *, unsigned int, unsigned char *, |
258 | 0 | unsigned int, unsigned int) = NULL; |
259 | |
|
260 | 0 | int ratio_scalable = 1; |
261 | 0 | int interpolation = 0; |
262 | |
|
263 | 0 | unsigned char *source_base; |
264 | 0 | unsigned char *line_src; |
265 | |
|
266 | 0 | source_base = (unsigned char *)source; |
267 | |
|
268 | 0 | if (source_pitch < 0) { |
269 | 0 | int offset; |
270 | |
|
271 | 0 | offset = (source_height - 1); |
272 | 0 | offset *= source_pitch; |
273 | |
|
274 | 0 | source_base += offset; |
275 | 0 | } |
276 | | |
277 | | /* find out the ratio for each direction */ |
278 | 0 | switch (hratio * 10 / hscale) { |
279 | 0 | case 8: |
280 | | /* 4-5 Scale in Width direction */ |
281 | 0 | horiz_line_scale = vp8_horizontal_line_5_4_scale; |
282 | 0 | break; |
283 | 0 | case 6: |
284 | | /* 3-5 Scale in Width direction */ |
285 | 0 | horiz_line_scale = vp8_horizontal_line_5_3_scale; |
286 | 0 | break; |
287 | 0 | case 5: |
288 | | /* 1-2 Scale in Width direction */ |
289 | 0 | horiz_line_scale = vp8_horizontal_line_2_1_scale; |
290 | 0 | break; |
291 | 0 | default: |
292 | | /* The ratio is not acceptable now */ |
293 | | /* throw("The ratio is not acceptable for now!"); */ |
294 | 0 | ratio_scalable = 0; |
295 | 0 | break; |
296 | 0 | } |
297 | | |
298 | 0 | switch (vratio * 10 / vscale) { |
299 | 0 | case 8: |
300 | | /* 4-5 Scale in vertical direction */ |
301 | 0 | vert_band_scale = vp8_vertical_band_5_4_scale; |
302 | 0 | source_band_height = 5; |
303 | 0 | dest_band_height = 4; |
304 | 0 | break; |
305 | 0 | case 6: |
306 | | /* 3-5 Scale in vertical direction */ |
307 | 0 | vert_band_scale = vp8_vertical_band_5_3_scale; |
308 | 0 | source_band_height = 5; |
309 | 0 | dest_band_height = 3; |
310 | 0 | break; |
311 | 0 | case 5: |
312 | | /* 1-2 Scale in vertical direction */ |
313 | |
|
314 | 0 | if (interlaced) { |
315 | | /* if the content is interlaced, point sampling is used */ |
316 | 0 | vert_band_scale = vp8_vertical_band_2_1_scale; |
317 | 0 | } else { |
318 | 0 | interpolation = 1; |
319 | | /* if the content is progressive, interplo */ |
320 | 0 | vert_band_scale = vp8_vertical_band_2_1_scale_i; |
321 | 0 | } |
322 | |
|
323 | 0 | source_band_height = 2; |
324 | 0 | dest_band_height = 1; |
325 | 0 | break; |
326 | 0 | default: |
327 | | /* The ratio is not acceptable now */ |
328 | | /* throw("The ratio is not acceptable for now!"); */ |
329 | 0 | ratio_scalable = 0; |
330 | 0 | break; |
331 | 0 | } |
332 | | |
333 | 0 | if (ratio_scalable) { |
334 | 0 | if (source_height == dest_height) { |
335 | | /* for each band of the image */ |
336 | 0 | for (k = 0; k < (int)dest_height; k++) { |
337 | 0 | horiz_line_scale(source, source_width, dest, dest_width); |
338 | 0 | source += source_pitch; |
339 | 0 | dest += dest_pitch; |
340 | 0 | } |
341 | |
|
342 | 0 | return; |
343 | 0 | } |
344 | | |
345 | 0 | if (interpolation) { |
346 | 0 | if (source < source_base) source = source_base; |
347 | |
|
348 | 0 | horiz_line_scale(source, source_width, temp_area, dest_width); |
349 | 0 | } |
350 | |
|
351 | 0 | for (k = 0; |
352 | 0 | k < (int)(dest_height + dest_band_height - 1) / dest_band_height; |
353 | 0 | k++) { |
354 | | /* scale one band horizontally */ |
355 | 0 | for (i = 0; i < source_band_height; i++) { |
356 | | /* Trap case where we could read off the base of the source buffer */ |
357 | |
|
358 | 0 | line_src = (unsigned char *)source + i * source_pitch; |
359 | |
|
360 | 0 | if (line_src < source_base) line_src = source_base; |
361 | |
|
362 | 0 | horiz_line_scale(line_src, source_width, |
363 | 0 | temp_area + (i + 1) * dest_pitch, dest_width); |
364 | 0 | } |
365 | | |
366 | | /* Vertical scaling is in place */ |
367 | 0 | vert_band_scale(temp_area + dest_pitch, dest_pitch, dest, dest_pitch, |
368 | 0 | dest_width); |
369 | |
|
370 | 0 | if (interpolation) |
371 | 0 | memcpy(temp_area, temp_area + source_band_height * dest_pitch, |
372 | 0 | dest_width); |
373 | | |
374 | | /* Next band... */ |
375 | 0 | source += (unsigned long)source_band_height * source_pitch; |
376 | 0 | dest += (unsigned long)dest_band_height * dest_pitch; |
377 | 0 | } |
378 | |
|
379 | 0 | return; |
380 | 0 | } |
381 | | |
382 | 0 | if (hscale == 2 && hratio == 1) Scale1Dh = scale1d_2t1_ps; |
383 | |
|
384 | 0 | if (vscale == 2 && vratio == 1) { |
385 | 0 | if (interlaced) |
386 | 0 | Scale1Dv = scale1d_2t1_ps; |
387 | 0 | else |
388 | 0 | Scale1Dv = scale1d_2t1_i; |
389 | 0 | } |
390 | |
|
391 | 0 | if (source_height == dest_height) { |
392 | | /* for each band of the image */ |
393 | 0 | for (k = 0; k < (int)dest_height; k++) { |
394 | 0 | Scale1Dh(source, 1, hscale, source_width + 1, dest, 1, hratio, |
395 | 0 | dest_width); |
396 | 0 | source += source_pitch; |
397 | 0 | dest += dest_pitch; |
398 | 0 | } |
399 | |
|
400 | 0 | return; |
401 | 0 | } |
402 | | |
403 | 0 | if (dest_height > source_height) { |
404 | 0 | dest_band_height = temp_area_height - 1; |
405 | 0 | source_band_height = dest_band_height * source_height / dest_height; |
406 | 0 | } else { |
407 | 0 | source_band_height = temp_area_height - 1; |
408 | 0 | dest_band_height = source_band_height * vratio / vscale; |
409 | 0 | } |
410 | | |
411 | | /* first row needs to be done so that we can stay one row ahead for vertical |
412 | | * zoom */ |
413 | 0 | Scale1Dh(source, 1, hscale, source_width + 1, temp_area, 1, hratio, |
414 | 0 | dest_width); |
415 | | |
416 | | /* for each band of the image */ |
417 | 0 | bands = (dest_height + dest_band_height - 1) / dest_band_height; |
418 | |
|
419 | 0 | for (k = 0; k < bands; k++) { |
420 | | /* scale one band horizontally */ |
421 | 0 | for (i = 1; i < source_band_height + 1; i++) { |
422 | 0 | if (k * source_band_height + i < (int)source_height) { |
423 | 0 | Scale1Dh(source + i * source_pitch, 1, hscale, source_width + 1, |
424 | 0 | temp_area + i * dest_pitch, 1, hratio, dest_width); |
425 | 0 | } else { /* Duplicate the last row */ |
426 | | /* copy temp_area row 0 over from last row in the past */ |
427 | 0 | memcpy(temp_area + i * dest_pitch, temp_area + (i - 1) * dest_pitch, |
428 | 0 | dest_pitch); |
429 | 0 | } |
430 | 0 | } |
431 | | |
432 | | /* scale one band vertically */ |
433 | 0 | for (j = 0; j < (int)dest_width; j++) { |
434 | 0 | Scale1Dv(&temp_area[j], dest_pitch, vscale, source_band_height + 1, |
435 | 0 | &dest[j], dest_pitch, vratio, dest_band_height); |
436 | 0 | } |
437 | | |
438 | | /* copy temp_area row 0 over from last row in the past */ |
439 | 0 | memcpy(temp_area, temp_area + source_band_height * dest_pitch, dest_pitch); |
440 | | |
441 | | /* move to the next band */ |
442 | 0 | source += source_band_height * source_pitch; |
443 | 0 | dest += dest_band_height * dest_pitch; |
444 | 0 | } |
445 | 0 | } |
446 | | |
447 | | /**************************************************************************** |
448 | | * |
449 | | * ROUTINE : vpx_scale_frame |
450 | | * |
451 | | * INPUTS : YV12_BUFFER_CONFIG *src : Pointer to frame to be |
452 | | * scaled. |
453 | | * YV12_BUFFER_CONFIG *dst : Pointer to buffer to hold |
454 | | * scaled frame. |
455 | | * unsigned char *temp_area : Pointer to temp work area. |
456 | | * unsigned char temp_area_height : Height of temp work area. |
457 | | * unsigned int hscale : Horizontal scale factor |
458 | | * numerator. |
459 | | * unsigned int hratio : Horizontal scale factor |
460 | | * denominator. |
461 | | * unsigned int vscale : Vertical scale factor |
462 | | * numerator. |
463 | | * unsigned int vratio : Vertical scale factor |
464 | | * denominator. |
465 | | * unsigned int interlaced : Interlace flag. |
466 | | * |
467 | | * OUTPUTS : None. |
468 | | * |
469 | | * RETURNS : void |
470 | | * |
471 | | * FUNCTION : Performs 2-tap linear interpolation in two dimensions. |
472 | | * |
473 | | * SPECIAL NOTES : Expansion is performed one band at a time to help with |
474 | | * caching. |
475 | | * |
476 | | ****************************************************************************/ |
477 | | void vpx_scale_frame(YV12_BUFFER_CONFIG *src, YV12_BUFFER_CONFIG *dst, |
478 | | unsigned char *temp_area, unsigned char temp_height, |
479 | | unsigned int hscale, unsigned int hratio, |
480 | | unsigned int vscale, unsigned int vratio, |
481 | 0 | unsigned int interlaced) { |
482 | 0 | int i; |
483 | 0 | int dw = (hscale - 1 + src->y_width * hratio) / hscale; |
484 | 0 | int dh = (vscale - 1 + src->y_height * vratio) / vscale; |
485 | | |
486 | | /* call our internal scaling routines!! */ |
487 | 0 | Scale2D((unsigned char *)src->y_buffer, src->y_stride, src->y_width, |
488 | 0 | src->y_height, (unsigned char *)dst->y_buffer, dst->y_stride, dw, dh, |
489 | 0 | temp_area, temp_height, hscale, hratio, vscale, vratio, interlaced); |
490 | |
|
491 | 0 | if (dw < (int)dst->y_width) |
492 | 0 | for (i = 0; i < dh; i++) |
493 | 0 | memset(dst->y_buffer + i * dst->y_stride + dw - 1, |
494 | 0 | dst->y_buffer[i * dst->y_stride + dw - 2], dst->y_width - dw + 1); |
495 | |
|
496 | 0 | if (dh < (int)dst->y_height) |
497 | 0 | for (i = dh - 1; i < (int)dst->y_height; i++) |
498 | 0 | memcpy(dst->y_buffer + i * dst->y_stride, |
499 | 0 | dst->y_buffer + (dh - 2) * dst->y_stride, dst->y_width + 1); |
500 | |
|
501 | 0 | Scale2D((unsigned char *)src->u_buffer, src->uv_stride, src->uv_width, |
502 | 0 | src->uv_height, (unsigned char *)dst->u_buffer, dst->uv_stride, |
503 | 0 | dw / 2, dh / 2, temp_area, temp_height, hscale, hratio, vscale, |
504 | 0 | vratio, interlaced); |
505 | |
|
506 | 0 | if (dw / 2 < (int)dst->uv_width) |
507 | 0 | for (i = 0; i < dst->uv_height; i++) |
508 | 0 | memset(dst->u_buffer + i * dst->uv_stride + dw / 2 - 1, |
509 | 0 | dst->u_buffer[i * dst->uv_stride + dw / 2 - 2], |
510 | 0 | dst->uv_width - dw / 2 + 1); |
511 | |
|
512 | 0 | if (dh / 2 < (int)dst->uv_height) |
513 | 0 | for (i = dh / 2 - 1; i < (int)dst->y_height / 2; i++) |
514 | 0 | memcpy(dst->u_buffer + i * dst->uv_stride, |
515 | 0 | dst->u_buffer + (dh / 2 - 2) * dst->uv_stride, dst->uv_width); |
516 | |
|
517 | 0 | Scale2D((unsigned char *)src->v_buffer, src->uv_stride, src->uv_width, |
518 | 0 | src->uv_height, (unsigned char *)dst->v_buffer, dst->uv_stride, |
519 | 0 | dw / 2, dh / 2, temp_area, temp_height, hscale, hratio, vscale, |
520 | 0 | vratio, interlaced); |
521 | |
|
522 | 0 | if (dw / 2 < (int)dst->uv_width) |
523 | 0 | for (i = 0; i < dst->uv_height; i++) |
524 | 0 | memset(dst->v_buffer + i * dst->uv_stride + dw / 2 - 1, |
525 | 0 | dst->v_buffer[i * dst->uv_stride + dw / 2 - 2], |
526 | 0 | dst->uv_width - dw / 2 + 1); |
527 | |
|
528 | 0 | if (dh / 2 < (int)dst->uv_height) |
529 | 0 | for (i = dh / 2 - 1; i < (int)dst->y_height / 2; i++) |
530 | 0 | memcpy(dst->v_buffer + i * dst->uv_stride, |
531 | 0 | dst->v_buffer + (dh / 2 - 2) * dst->uv_stride, dst->uv_width); |
532 | 0 | } |