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