/src/libvpx/vp9/encoder/vp9_frame_scale.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2017 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 "./vp9_rtcd.h" |
12 | | #include "./vpx_config.h" |
13 | | #include "./vpx_dsp_rtcd.h" |
14 | | #include "./vpx_scale_rtcd.h" |
15 | | #include "vp9/common/vp9_blockd.h" |
16 | | #include "vp9/encoder/vp9_encoder.h" |
17 | | #include "vpx/vpx_codec.h" |
18 | | #include "vpx_dsp/vpx_filter.h" |
19 | | #include "vpx_scale/yv12config.h" |
20 | | |
21 | | void vp9_scale_and_extend_frame_c(const YV12_BUFFER_CONFIG *src, |
22 | | YV12_BUFFER_CONFIG *dst, |
23 | 0 | INTERP_FILTER filter_type, int phase_scaler) { |
24 | 0 | const int src_w = src->y_crop_width; |
25 | 0 | const int src_h = src->y_crop_height; |
26 | 0 | const uint8_t *const srcs[3] = { src->y_buffer, src->u_buffer, |
27 | 0 | src->v_buffer }; |
28 | 0 | const int src_strides[3] = { src->y_stride, src->uv_stride, src->uv_stride }; |
29 | 0 | uint8_t *const dsts[3] = { dst->y_buffer, dst->u_buffer, dst->v_buffer }; |
30 | 0 | const int dst_strides[3] = { dst->y_stride, dst->uv_stride, dst->uv_stride }; |
31 | 0 | const InterpKernel *const kernel = vp9_filter_kernels[filter_type]; |
32 | 0 | int x, y, i; |
33 | |
|
34 | 0 | #if HAVE_SSSE3 || HAVE_NEON |
35 | | // TODO(linfengz): The 4:3 specialized C code is disabled by default since |
36 | | // it's much slower than the general version which calls vpx_scaled_2d() even |
37 | | // if vpx_scaled_2d() is not optimized. It will only be enabled as a reference |
38 | | // for the platforms which have faster optimization. |
39 | 0 | if (4 * dst->y_crop_width == 3 * src_w && |
40 | 0 | 4 * dst->y_crop_height == 3 * src_h) { |
41 | | // Specialize 4 to 3 scaling. |
42 | | // Example pixel locations. |
43 | | // (O: Original pixel. S: Scaled pixel. X: Overlapped pixel.) |
44 | | // phase_scaler = 0 | phase_scaler = 8 |
45 | | // | |
46 | | // X O S O S O X | O O O O O |
47 | | // | |
48 | | // | |
49 | | // | S S S |
50 | | // | |
51 | | // | |
52 | | // O O O O O | O O O O O |
53 | | // | |
54 | | // S S S S | |
55 | | // | |
56 | | // | |
57 | | // | S S S |
58 | | // O O O O O | O O O O O |
59 | | // | |
60 | | // | |
61 | | // | |
62 | | // S S S S | |
63 | | // | |
64 | | // O O O O O | O O O O O |
65 | | // | S S S |
66 | | // | |
67 | | // | |
68 | | // | |
69 | | // | |
70 | | // X O S O S O X | O O O O O |
71 | |
|
72 | 0 | const int dst_ws[3] = { dst->y_crop_width, dst->uv_crop_width, |
73 | 0 | dst->uv_crop_width }; |
74 | 0 | const int dst_hs[3] = { dst->y_crop_height, dst->uv_crop_height, |
75 | 0 | dst->uv_crop_height }; |
76 | 0 | for (i = 0; i < MAX_MB_PLANE; ++i) { |
77 | 0 | const int dst_w = dst_ws[i]; |
78 | 0 | const int dst_h = dst_hs[i]; |
79 | 0 | const int src_stride = src_strides[i]; |
80 | 0 | const int dst_stride = dst_strides[i]; |
81 | 0 | for (y = 0; y < dst_h; y += 3) { |
82 | 0 | for (x = 0; x < dst_w; x += 3) { |
83 | 0 | const uint8_t *src_ptr = srcs[i] + 4 * y / 3 * src_stride + 4 * x / 3; |
84 | 0 | uint8_t *dst_ptr = dsts[i] + y * dst_stride + x; |
85 | | |
86 | | // Must call c function because its optimization doesn't support 3x3. |
87 | 0 | vpx_scaled_2d_c(src_ptr, src_stride, dst_ptr, dst_stride, kernel, |
88 | 0 | phase_scaler, 64 / 3, phase_scaler, 64 / 3, 3, 3); |
89 | 0 | } |
90 | 0 | } |
91 | 0 | } |
92 | 0 | } else |
93 | 0 | #endif |
94 | 0 | { |
95 | 0 | const int dst_w = dst->y_crop_width; |
96 | 0 | const int dst_h = dst->y_crop_height; |
97 | | |
98 | | // The issue b/311394513 reveals a corner case bug. vpx_scaled_2d() requires |
99 | | // both x_step_q4 and y_step_q4 are less than or equal to 64. Otherwise, it |
100 | | // needs to call vp9_scale_and_extend_frame_nonnormative() that supports |
101 | | // arbitrary scaling. |
102 | 0 | const int x_step_q4 = 16 * src_w / dst_w; |
103 | 0 | const int y_step_q4 = 16 * src_h / dst_h; |
104 | 0 | if (x_step_q4 > 64 || y_step_q4 > 64) { |
105 | | // This function is only called while cm->bit_depth is VPX_BITS_8. |
106 | 0 | #if CONFIG_VP9_HIGHBITDEPTH |
107 | 0 | vp9_scale_and_extend_frame_nonnormative(src, dst, (int)VPX_BITS_8); |
108 | | #else |
109 | | vp9_scale_and_extend_frame_nonnormative(src, dst); |
110 | | #endif // CONFIG_VP9_HIGHBITDEPTH |
111 | 0 | return; |
112 | 0 | } |
113 | | |
114 | 0 | for (i = 0; i < MAX_MB_PLANE; ++i) { |
115 | 0 | const int factor = (i == 0 || i == 3 ? 1 : 2); |
116 | 0 | const int src_stride = src_strides[i]; |
117 | 0 | const int dst_stride = dst_strides[i]; |
118 | 0 | for (y = 0; y < dst_h; y += 16) { |
119 | 0 | const int y_q4 = y * (16 / factor) * src_h / dst_h + phase_scaler; |
120 | 0 | for (x = 0; x < dst_w; x += 16) { |
121 | 0 | const int x_q4 = x * (16 / factor) * src_w / dst_w + phase_scaler; |
122 | 0 | const uint8_t *src_ptr = srcs[i] + |
123 | 0 | (y / factor) * src_h / dst_h * src_stride + |
124 | 0 | (x / factor) * src_w / dst_w; |
125 | 0 | uint8_t *dst_ptr = dsts[i] + (y / factor) * dst_stride + (x / factor); |
126 | |
|
127 | 0 | vpx_scaled_2d(src_ptr, src_stride, dst_ptr, dst_stride, kernel, |
128 | 0 | x_q4 & 0xf, 16 * src_w / dst_w, y_q4 & 0xf, |
129 | 0 | 16 * src_h / dst_h, 16 / factor, 16 / factor); |
130 | 0 | } |
131 | 0 | } |
132 | 0 | } |
133 | 0 | } |
134 | | |
135 | 0 | vpx_extend_frame_borders(dst); |
136 | 0 | } |