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 #include <assert.h>
12 #include "./vpx_config.h"
13 #include "./vpx_scale_rtcd.h"
14 #include "vpx/vpx_integer.h"
15 #include "vpx_mem/vpx_mem.h"
16 #include "vpx_ports/mem.h"
17 #include "vpx_scale/yv12config.h"
18 #if CONFIG_VP9_HIGHBITDEPTH
19 #include "vp9/common/vp9_common.h"
20 #endif
21 
extend_plane(uint8_t * const src,int src_stride,int width,int height,int extend_top,int extend_left,int extend_bottom,int extend_right)22 static void extend_plane(uint8_t *const src, int src_stride,
23                          int width, int height,
24                          int extend_top, int extend_left,
25                          int extend_bottom, int extend_right) {
26   int i;
27   const int linesize = extend_left + extend_right + width;
28 
29   /* copy the left and right most columns out */
30   uint8_t *src_ptr1 = src;
31   uint8_t *src_ptr2 = src + width - 1;
32   uint8_t *dst_ptr1 = src - extend_left;
33   uint8_t *dst_ptr2 = src + width;
34 
35   for (i = 0; i < height; ++i) {
36     memset(dst_ptr1, src_ptr1[0], extend_left);
37     memset(dst_ptr2, src_ptr2[0], extend_right);
38     src_ptr1 += src_stride;
39     src_ptr2 += src_stride;
40     dst_ptr1 += src_stride;
41     dst_ptr2 += src_stride;
42   }
43 
44   /* Now copy the top and bottom lines into each line of the respective
45    * borders
46    */
47   src_ptr1 = src - extend_left;
48   src_ptr2 = src + src_stride * (height - 1) - extend_left;
49   dst_ptr1 = src + src_stride * -extend_top - extend_left;
50   dst_ptr2 = src + src_stride * height - extend_left;
51 
52   for (i = 0; i < extend_top; ++i) {
53     memcpy(dst_ptr1, src_ptr1, linesize);
54     dst_ptr1 += src_stride;
55   }
56 
57   for (i = 0; i < extend_bottom; ++i) {
58     memcpy(dst_ptr2, src_ptr2, linesize);
59     dst_ptr2 += src_stride;
60   }
61 }
62 
63 #if CONFIG_VP9_HIGHBITDEPTH
extend_plane_high(uint8_t * const src8,int src_stride,int width,int height,int extend_top,int extend_left,int extend_bottom,int extend_right)64 static void extend_plane_high(uint8_t *const src8, int src_stride,
65                               int width, int height,
66                               int extend_top, int extend_left,
67                               int extend_bottom, int extend_right) {
68   int i;
69   const int linesize = extend_left + extend_right + width;
70   uint16_t *src = CONVERT_TO_SHORTPTR(src8);
71 
72   /* copy the left and right most columns out */
73   uint16_t *src_ptr1 = src;
74   uint16_t *src_ptr2 = src + width - 1;
75   uint16_t *dst_ptr1 = src - extend_left;
76   uint16_t *dst_ptr2 = src + width;
77 
78   for (i = 0; i < height; ++i) {
79     vpx_memset16(dst_ptr1, src_ptr1[0], extend_left);
80     vpx_memset16(dst_ptr2, src_ptr2[0], extend_right);
81     src_ptr1 += src_stride;
82     src_ptr2 += src_stride;
83     dst_ptr1 += src_stride;
84     dst_ptr2 += src_stride;
85   }
86 
87   /* Now copy the top and bottom lines into each line of the respective
88    * borders
89    */
90   src_ptr1 = src - extend_left;
91   src_ptr2 = src + src_stride * (height - 1) - extend_left;
92   dst_ptr1 = src + src_stride * -extend_top - extend_left;
93   dst_ptr2 = src + src_stride * height - extend_left;
94 
95   for (i = 0; i < extend_top; ++i) {
96     memcpy(dst_ptr1, src_ptr1, linesize * sizeof(uint16_t));
97     dst_ptr1 += src_stride;
98   }
99 
100   for (i = 0; i < extend_bottom; ++i) {
101     memcpy(dst_ptr2, src_ptr2, linesize * sizeof(uint16_t));
102     dst_ptr2 += src_stride;
103   }
104 }
105 #endif
106 
vp8_yv12_extend_frame_borders_c(YV12_BUFFER_CONFIG * ybf)107 void vp8_yv12_extend_frame_borders_c(YV12_BUFFER_CONFIG *ybf) {
108   const int uv_border = ybf->border / 2;
109 
110   assert(ybf->border % 2 == 0);
111   assert(ybf->y_height - ybf->y_crop_height < 16);
112   assert(ybf->y_width - ybf->y_crop_width < 16);
113   assert(ybf->y_height - ybf->y_crop_height >= 0);
114   assert(ybf->y_width - ybf->y_crop_width >= 0);
115 
116 #if CONFIG_VP9_HIGHBITDEPTH
117   if (ybf->flags & YV12_FLAG_HIGHBITDEPTH) {
118     extend_plane_high(
119         ybf->y_buffer, ybf->y_stride,
120         ybf->y_crop_width, ybf->y_crop_height,
121         ybf->border, ybf->border,
122         ybf->border + ybf->y_height - ybf->y_crop_height,
123         ybf->border + ybf->y_width - ybf->y_crop_width);
124 
125     extend_plane_high(
126         ybf->u_buffer, ybf->uv_stride,
127         ybf->uv_crop_width, ybf->uv_crop_height,
128         uv_border, uv_border,
129         uv_border + ybf->uv_height - ybf->uv_crop_height,
130         uv_border + ybf->uv_width - ybf->uv_crop_width);
131 
132     extend_plane_high(
133         ybf->v_buffer, ybf->uv_stride,
134         ybf->uv_crop_width, ybf->uv_crop_height,
135         uv_border, uv_border,
136         uv_border + ybf->uv_height - ybf->uv_crop_height,
137         uv_border + ybf->uv_width - ybf->uv_crop_width);
138     return;
139   }
140 #endif
141   extend_plane(ybf->y_buffer, ybf->y_stride,
142                ybf->y_crop_width, ybf->y_crop_height,
143                ybf->border, ybf->border,
144                ybf->border + ybf->y_height - ybf->y_crop_height,
145                ybf->border + ybf->y_width - ybf->y_crop_width);
146 
147   extend_plane(ybf->u_buffer, ybf->uv_stride,
148                ybf->uv_crop_width, ybf->uv_crop_height,
149                uv_border, uv_border,
150                uv_border + ybf->uv_height - ybf->uv_crop_height,
151                uv_border + ybf->uv_width - ybf->uv_crop_width);
152 
153   extend_plane(ybf->v_buffer, ybf->uv_stride,
154                ybf->uv_crop_width, ybf->uv_crop_height,
155                uv_border, uv_border,
156                uv_border + ybf->uv_height - ybf->uv_crop_height,
157                uv_border + ybf->uv_width - ybf->uv_crop_width);
158 }
159 
160 #if CONFIG_VP9 || CONFIG_VP10
extend_frame(YV12_BUFFER_CONFIG * const ybf,int ext_size)161 static void extend_frame(YV12_BUFFER_CONFIG *const ybf, int ext_size) {
162   const int c_w = ybf->uv_crop_width;
163   const int c_h = ybf->uv_crop_height;
164   const int ss_x = ybf->uv_width < ybf->y_width;
165   const int ss_y = ybf->uv_height < ybf->y_height;
166   const int c_et = ext_size >> ss_y;
167   const int c_el = ext_size >> ss_x;
168   const int c_eb = c_et + ybf->uv_height - ybf->uv_crop_height;
169   const int c_er = c_el + ybf->uv_width - ybf->uv_crop_width;
170 
171   assert(ybf->y_height - ybf->y_crop_height < 16);
172   assert(ybf->y_width - ybf->y_crop_width < 16);
173   assert(ybf->y_height - ybf->y_crop_height >= 0);
174   assert(ybf->y_width - ybf->y_crop_width >= 0);
175 
176 #if CONFIG_VP9_HIGHBITDEPTH
177   if (ybf->flags & YV12_FLAG_HIGHBITDEPTH) {
178     extend_plane_high(ybf->y_buffer, ybf->y_stride,
179                       ybf->y_crop_width, ybf->y_crop_height,
180                       ext_size, ext_size,
181                       ext_size + ybf->y_height - ybf->y_crop_height,
182                       ext_size + ybf->y_width - ybf->y_crop_width);
183     extend_plane_high(ybf->u_buffer, ybf->uv_stride,
184                       c_w, c_h, c_et, c_el, c_eb, c_er);
185     extend_plane_high(ybf->v_buffer, ybf->uv_stride,
186                       c_w, c_h, c_et, c_el, c_eb, c_er);
187     return;
188   }
189 #endif
190   extend_plane(ybf->y_buffer, ybf->y_stride,
191                ybf->y_crop_width, ybf->y_crop_height,
192                ext_size, ext_size,
193                ext_size + ybf->y_height - ybf->y_crop_height,
194                ext_size + ybf->y_width - ybf->y_crop_width);
195 
196   extend_plane(ybf->u_buffer, ybf->uv_stride,
197                c_w, c_h, c_et, c_el, c_eb, c_er);
198 
199   extend_plane(ybf->v_buffer, ybf->uv_stride,
200                c_w, c_h, c_et, c_el, c_eb, c_er);
201 }
202 
vpx_extend_frame_borders_c(YV12_BUFFER_CONFIG * ybf)203 void vpx_extend_frame_borders_c(YV12_BUFFER_CONFIG *ybf) {
204   extend_frame(ybf, ybf->border);
205 }
206 
vpx_extend_frame_inner_borders_c(YV12_BUFFER_CONFIG * ybf)207 void vpx_extend_frame_inner_borders_c(YV12_BUFFER_CONFIG *ybf) {
208   const int inner_bw = (ybf->border > VP9INNERBORDERINPIXELS) ?
209                        VP9INNERBORDERINPIXELS : ybf->border;
210   extend_frame(ybf, inner_bw);
211 }
212 
213 #if CONFIG_VP9_HIGHBITDEPTH
memcpy_short_addr(uint8_t * dst8,const uint8_t * src8,int num)214 void memcpy_short_addr(uint8_t *dst8, const uint8_t *src8, int num) {
215   uint16_t *dst = CONVERT_TO_SHORTPTR(dst8);
216   uint16_t *src = CONVERT_TO_SHORTPTR(src8);
217   memcpy(dst, src, num * sizeof(uint16_t));
218 }
219 #endif  // CONFIG_VP9_HIGHBITDEPTH
220 #endif  // CONFIG_VP9 || CONFIG_VP10
221 
222 // Copies the source image into the destination image and updates the
223 // destination's UMV borders.
224 // Note: The frames are assumed to be identical in size.
vp8_yv12_copy_frame_c(const YV12_BUFFER_CONFIG * src_ybc,YV12_BUFFER_CONFIG * dst_ybc)225 void vp8_yv12_copy_frame_c(const YV12_BUFFER_CONFIG *src_ybc,
226                            YV12_BUFFER_CONFIG *dst_ybc) {
227   int row;
228   const uint8_t *src = src_ybc->y_buffer;
229   uint8_t *dst = dst_ybc->y_buffer;
230 
231 #if 0
232   /* These assertions are valid in the codec, but the libvpx-tester uses
233    * this code slightly differently.
234    */
235   assert(src_ybc->y_width == dst_ybc->y_width);
236   assert(src_ybc->y_height == dst_ybc->y_height);
237 #endif
238 
239 #if CONFIG_VP9_HIGHBITDEPTH
240   if (src_ybc->flags & YV12_FLAG_HIGHBITDEPTH) {
241     assert(dst_ybc->flags & YV12_FLAG_HIGHBITDEPTH);
242     for (row = 0; row < src_ybc->y_height; ++row) {
243       memcpy_short_addr(dst, src, src_ybc->y_width);
244       src += src_ybc->y_stride;
245       dst += dst_ybc->y_stride;
246     }
247 
248     src = src_ybc->u_buffer;
249     dst = dst_ybc->u_buffer;
250 
251     for (row = 0; row < src_ybc->uv_height; ++row) {
252       memcpy_short_addr(dst, src, src_ybc->uv_width);
253       src += src_ybc->uv_stride;
254       dst += dst_ybc->uv_stride;
255     }
256 
257     src = src_ybc->v_buffer;
258     dst = dst_ybc->v_buffer;
259 
260     for (row = 0; row < src_ybc->uv_height; ++row) {
261       memcpy_short_addr(dst, src, src_ybc->uv_width);
262       src += src_ybc->uv_stride;
263       dst += dst_ybc->uv_stride;
264     }
265 
266     vp8_yv12_extend_frame_borders_c(dst_ybc);
267     return;
268   } else {
269     assert(!(dst_ybc->flags & YV12_FLAG_HIGHBITDEPTH));
270   }
271 #endif
272 
273   for (row = 0; row < src_ybc->y_height; ++row) {
274     memcpy(dst, src, src_ybc->y_width);
275     src += src_ybc->y_stride;
276     dst += dst_ybc->y_stride;
277   }
278 
279   src = src_ybc->u_buffer;
280   dst = dst_ybc->u_buffer;
281 
282   for (row = 0; row < src_ybc->uv_height; ++row) {
283     memcpy(dst, src, src_ybc->uv_width);
284     src += src_ybc->uv_stride;
285     dst += dst_ybc->uv_stride;
286   }
287 
288   src = src_ybc->v_buffer;
289   dst = dst_ybc->v_buffer;
290 
291   for (row = 0; row < src_ybc->uv_height; ++row) {
292     memcpy(dst, src, src_ybc->uv_width);
293     src += src_ybc->uv_stride;
294     dst += dst_ybc->uv_stride;
295   }
296 
297   vp8_yv12_extend_frame_borders_c(dst_ybc);
298 }
299 
vpx_yv12_copy_y_c(const YV12_BUFFER_CONFIG * src_ybc,YV12_BUFFER_CONFIG * dst_ybc)300 void vpx_yv12_copy_y_c(const YV12_BUFFER_CONFIG *src_ybc,
301                        YV12_BUFFER_CONFIG *dst_ybc) {
302   int row;
303   const uint8_t *src = src_ybc->y_buffer;
304   uint8_t *dst = dst_ybc->y_buffer;
305 
306 #if CONFIG_VP9_HIGHBITDEPTH
307   if (src_ybc->flags & YV12_FLAG_HIGHBITDEPTH) {
308     const uint16_t *src16 = CONVERT_TO_SHORTPTR(src);
309     uint16_t *dst16 = CONVERT_TO_SHORTPTR(dst);
310     for (row = 0; row < src_ybc->y_height; ++row) {
311       memcpy(dst16, src16, src_ybc->y_width * sizeof(uint16_t));
312       src16 += src_ybc->y_stride;
313       dst16 += dst_ybc->y_stride;
314     }
315     return;
316   }
317 #endif
318 
319   for (row = 0; row < src_ybc->y_height; ++row) {
320     memcpy(dst, src, src_ybc->y_width);
321     src += src_ybc->y_stride;
322     dst += dst_ybc->y_stride;
323   }
324 }
325