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