1*c0909341SAndroid Build Coastguard Worker /*
2*c0909341SAndroid Build Coastguard Worker * Copyright © 2018, VideoLAN and dav1d authors
3*c0909341SAndroid Build Coastguard Worker * Copyright © 2018, Two Orioles, LLC
4*c0909341SAndroid Build Coastguard Worker * All rights reserved.
5*c0909341SAndroid Build Coastguard Worker *
6*c0909341SAndroid Build Coastguard Worker * Redistribution and use in source and binary forms, with or without
7*c0909341SAndroid Build Coastguard Worker * modification, are permitted provided that the following conditions are met:
8*c0909341SAndroid Build Coastguard Worker *
9*c0909341SAndroid Build Coastguard Worker * 1. Redistributions of source code must retain the above copyright notice, this
10*c0909341SAndroid Build Coastguard Worker * list of conditions and the following disclaimer.
11*c0909341SAndroid Build Coastguard Worker *
12*c0909341SAndroid Build Coastguard Worker * 2. Redistributions in binary form must reproduce the above copyright notice,
13*c0909341SAndroid Build Coastguard Worker * this list of conditions and the following disclaimer in the documentation
14*c0909341SAndroid Build Coastguard Worker * and/or other materials provided with the distribution.
15*c0909341SAndroid Build Coastguard Worker *
16*c0909341SAndroid Build Coastguard Worker * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17*c0909341SAndroid Build Coastguard Worker * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18*c0909341SAndroid Build Coastguard Worker * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19*c0909341SAndroid Build Coastguard Worker * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20*c0909341SAndroid Build Coastguard Worker * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21*c0909341SAndroid Build Coastguard Worker * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22*c0909341SAndroid Build Coastguard Worker * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23*c0909341SAndroid Build Coastguard Worker * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24*c0909341SAndroid Build Coastguard Worker * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25*c0909341SAndroid Build Coastguard Worker * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*c0909341SAndroid Build Coastguard Worker */
27*c0909341SAndroid Build Coastguard Worker
28*c0909341SAndroid Build Coastguard Worker #include "config.h"
29*c0909341SAndroid Build Coastguard Worker
30*c0909341SAndroid Build Coastguard Worker #include <stdint.h>
31*c0909341SAndroid Build Coastguard Worker #include <string.h>
32*c0909341SAndroid Build Coastguard Worker
33*c0909341SAndroid Build Coastguard Worker #include "common/intops.h"
34*c0909341SAndroid Build Coastguard Worker
35*c0909341SAndroid Build Coastguard Worker #include "src/ipred_prepare.h"
36*c0909341SAndroid Build Coastguard Worker
37*c0909341SAndroid Build Coastguard Worker static const uint8_t av1_mode_conv[N_INTRA_PRED_MODES]
38*c0909341SAndroid Build Coastguard Worker [2 /* have_left */][2 /* have_top */] =
39*c0909341SAndroid Build Coastguard Worker {
40*c0909341SAndroid Build Coastguard Worker [DC_PRED] = { { DC_128_PRED, TOP_DC_PRED },
41*c0909341SAndroid Build Coastguard Worker { LEFT_DC_PRED, DC_PRED } },
42*c0909341SAndroid Build Coastguard Worker [PAETH_PRED] = { { DC_128_PRED, VERT_PRED },
43*c0909341SAndroid Build Coastguard Worker { HOR_PRED, PAETH_PRED } },
44*c0909341SAndroid Build Coastguard Worker };
45*c0909341SAndroid Build Coastguard Worker
46*c0909341SAndroid Build Coastguard Worker static const uint8_t av1_mode_to_angle_map[8] = {
47*c0909341SAndroid Build Coastguard Worker 90, 180, 45, 135, 113, 157, 203, 67
48*c0909341SAndroid Build Coastguard Worker };
49*c0909341SAndroid Build Coastguard Worker
50*c0909341SAndroid Build Coastguard Worker static const struct {
51*c0909341SAndroid Build Coastguard Worker uint8_t needs_left:1;
52*c0909341SAndroid Build Coastguard Worker uint8_t needs_top:1;
53*c0909341SAndroid Build Coastguard Worker uint8_t needs_topleft:1;
54*c0909341SAndroid Build Coastguard Worker uint8_t needs_topright:1;
55*c0909341SAndroid Build Coastguard Worker uint8_t needs_bottomleft:1;
56*c0909341SAndroid Build Coastguard Worker } av1_intra_prediction_edges[N_IMPL_INTRA_PRED_MODES] = {
57*c0909341SAndroid Build Coastguard Worker [DC_PRED] = { .needs_top = 1, .needs_left = 1 },
58*c0909341SAndroid Build Coastguard Worker [VERT_PRED] = { .needs_top = 1 },
59*c0909341SAndroid Build Coastguard Worker [HOR_PRED] = { .needs_left = 1 },
60*c0909341SAndroid Build Coastguard Worker [LEFT_DC_PRED] = { .needs_left = 1 },
61*c0909341SAndroid Build Coastguard Worker [TOP_DC_PRED] = { .needs_top = 1 },
62*c0909341SAndroid Build Coastguard Worker [DC_128_PRED] = { 0 },
63*c0909341SAndroid Build Coastguard Worker [Z1_PRED] = { .needs_top = 1, .needs_topright = 1,
64*c0909341SAndroid Build Coastguard Worker .needs_topleft = 1 },
65*c0909341SAndroid Build Coastguard Worker [Z2_PRED] = { .needs_left = 1, .needs_top = 1, .needs_topleft = 1 },
66*c0909341SAndroid Build Coastguard Worker [Z3_PRED] = { .needs_left = 1, .needs_bottomleft = 1,
67*c0909341SAndroid Build Coastguard Worker .needs_topleft = 1 },
68*c0909341SAndroid Build Coastguard Worker [SMOOTH_PRED] = { .needs_left = 1, .needs_top = 1 },
69*c0909341SAndroid Build Coastguard Worker [SMOOTH_V_PRED] = { .needs_left = 1, .needs_top = 1 },
70*c0909341SAndroid Build Coastguard Worker [SMOOTH_H_PRED] = { .needs_left = 1, .needs_top = 1 },
71*c0909341SAndroid Build Coastguard Worker [PAETH_PRED] = { .needs_left = 1, .needs_top = 1, .needs_topleft = 1 },
72*c0909341SAndroid Build Coastguard Worker [FILTER_PRED] = { .needs_left = 1, .needs_top = 1, .needs_topleft = 1 },
73*c0909341SAndroid Build Coastguard Worker };
74*c0909341SAndroid Build Coastguard Worker
75*c0909341SAndroid Build Coastguard Worker enum IntraPredMode
bytefn(dav1d_prepare_intra_edges)76*c0909341SAndroid Build Coastguard Worker bytefn(dav1d_prepare_intra_edges)(const int x, const int have_left,
77*c0909341SAndroid Build Coastguard Worker const int y, const int have_top,
78*c0909341SAndroid Build Coastguard Worker const int w, const int h,
79*c0909341SAndroid Build Coastguard Worker const enum EdgeFlags edge_flags,
80*c0909341SAndroid Build Coastguard Worker const pixel *const dst,
81*c0909341SAndroid Build Coastguard Worker const ptrdiff_t stride,
82*c0909341SAndroid Build Coastguard Worker const pixel *prefilter_toplevel_sb_edge,
83*c0909341SAndroid Build Coastguard Worker enum IntraPredMode mode, int *const angle,
84*c0909341SAndroid Build Coastguard Worker const int tw, const int th, const int filter_edge,
85*c0909341SAndroid Build Coastguard Worker pixel *const topleft_out HIGHBD_DECL_SUFFIX)
86*c0909341SAndroid Build Coastguard Worker {
87*c0909341SAndroid Build Coastguard Worker const int bitdepth = bitdepth_from_max(bitdepth_max);
88*c0909341SAndroid Build Coastguard Worker assert(y < h && x < w);
89*c0909341SAndroid Build Coastguard Worker
90*c0909341SAndroid Build Coastguard Worker switch (mode) {
91*c0909341SAndroid Build Coastguard Worker case VERT_PRED:
92*c0909341SAndroid Build Coastguard Worker case HOR_PRED:
93*c0909341SAndroid Build Coastguard Worker case DIAG_DOWN_LEFT_PRED:
94*c0909341SAndroid Build Coastguard Worker case DIAG_DOWN_RIGHT_PRED:
95*c0909341SAndroid Build Coastguard Worker case VERT_RIGHT_PRED:
96*c0909341SAndroid Build Coastguard Worker case HOR_DOWN_PRED:
97*c0909341SAndroid Build Coastguard Worker case HOR_UP_PRED:
98*c0909341SAndroid Build Coastguard Worker case VERT_LEFT_PRED: {
99*c0909341SAndroid Build Coastguard Worker *angle = av1_mode_to_angle_map[mode - VERT_PRED] + 3 * *angle;
100*c0909341SAndroid Build Coastguard Worker
101*c0909341SAndroid Build Coastguard Worker if (*angle <= 90)
102*c0909341SAndroid Build Coastguard Worker mode = *angle < 90 && have_top ? Z1_PRED : VERT_PRED;
103*c0909341SAndroid Build Coastguard Worker else if (*angle < 180)
104*c0909341SAndroid Build Coastguard Worker mode = Z2_PRED;
105*c0909341SAndroid Build Coastguard Worker else
106*c0909341SAndroid Build Coastguard Worker mode = *angle > 180 && have_left ? Z3_PRED : HOR_PRED;
107*c0909341SAndroid Build Coastguard Worker break;
108*c0909341SAndroid Build Coastguard Worker }
109*c0909341SAndroid Build Coastguard Worker case DC_PRED:
110*c0909341SAndroid Build Coastguard Worker case PAETH_PRED:
111*c0909341SAndroid Build Coastguard Worker mode = av1_mode_conv[mode][have_left][have_top];
112*c0909341SAndroid Build Coastguard Worker break;
113*c0909341SAndroid Build Coastguard Worker default:
114*c0909341SAndroid Build Coastguard Worker break;
115*c0909341SAndroid Build Coastguard Worker }
116*c0909341SAndroid Build Coastguard Worker
117*c0909341SAndroid Build Coastguard Worker const pixel *dst_top;
118*c0909341SAndroid Build Coastguard Worker if (have_top &&
119*c0909341SAndroid Build Coastguard Worker (av1_intra_prediction_edges[mode].needs_top ||
120*c0909341SAndroid Build Coastguard Worker av1_intra_prediction_edges[mode].needs_topleft ||
121*c0909341SAndroid Build Coastguard Worker (av1_intra_prediction_edges[mode].needs_left && !have_left)))
122*c0909341SAndroid Build Coastguard Worker {
123*c0909341SAndroid Build Coastguard Worker if (prefilter_toplevel_sb_edge) {
124*c0909341SAndroid Build Coastguard Worker dst_top = &prefilter_toplevel_sb_edge[x * 4];
125*c0909341SAndroid Build Coastguard Worker } else {
126*c0909341SAndroid Build Coastguard Worker dst_top = &dst[-PXSTRIDE(stride)];
127*c0909341SAndroid Build Coastguard Worker }
128*c0909341SAndroid Build Coastguard Worker }
129*c0909341SAndroid Build Coastguard Worker
130*c0909341SAndroid Build Coastguard Worker if (av1_intra_prediction_edges[mode].needs_left) {
131*c0909341SAndroid Build Coastguard Worker const int sz = th << 2;
132*c0909341SAndroid Build Coastguard Worker pixel *const left = &topleft_out[-sz];
133*c0909341SAndroid Build Coastguard Worker
134*c0909341SAndroid Build Coastguard Worker if (have_left) {
135*c0909341SAndroid Build Coastguard Worker const int px_have = imin(sz, (h - y) << 2);
136*c0909341SAndroid Build Coastguard Worker
137*c0909341SAndroid Build Coastguard Worker for (int i = 0; i < px_have; i++)
138*c0909341SAndroid Build Coastguard Worker left[sz - 1 - i] = dst[PXSTRIDE(stride) * i - 1];
139*c0909341SAndroid Build Coastguard Worker if (px_have < sz)
140*c0909341SAndroid Build Coastguard Worker pixel_set(left, left[sz - px_have], sz - px_have);
141*c0909341SAndroid Build Coastguard Worker } else {
142*c0909341SAndroid Build Coastguard Worker pixel_set(left, have_top ? *dst_top : ((1 << bitdepth) >> 1) + 1, sz);
143*c0909341SAndroid Build Coastguard Worker }
144*c0909341SAndroid Build Coastguard Worker
145*c0909341SAndroid Build Coastguard Worker if (av1_intra_prediction_edges[mode].needs_bottomleft) {
146*c0909341SAndroid Build Coastguard Worker const int have_bottomleft = (!have_left || y + th >= h) ? 0 :
147*c0909341SAndroid Build Coastguard Worker (edge_flags & EDGE_I444_LEFT_HAS_BOTTOM);
148*c0909341SAndroid Build Coastguard Worker
149*c0909341SAndroid Build Coastguard Worker if (have_bottomleft) {
150*c0909341SAndroid Build Coastguard Worker const int px_have = imin(sz, (h - y - th) << 2);
151*c0909341SAndroid Build Coastguard Worker
152*c0909341SAndroid Build Coastguard Worker for (int i = 0; i < px_have; i++)
153*c0909341SAndroid Build Coastguard Worker left[-(i + 1)] = dst[(sz + i) * PXSTRIDE(stride) - 1];
154*c0909341SAndroid Build Coastguard Worker if (px_have < sz)
155*c0909341SAndroid Build Coastguard Worker pixel_set(left - sz, left[-px_have], sz - px_have);
156*c0909341SAndroid Build Coastguard Worker } else {
157*c0909341SAndroid Build Coastguard Worker pixel_set(left - sz, left[0], sz);
158*c0909341SAndroid Build Coastguard Worker }
159*c0909341SAndroid Build Coastguard Worker }
160*c0909341SAndroid Build Coastguard Worker }
161*c0909341SAndroid Build Coastguard Worker
162*c0909341SAndroid Build Coastguard Worker if (av1_intra_prediction_edges[mode].needs_top) {
163*c0909341SAndroid Build Coastguard Worker const int sz = tw << 2;
164*c0909341SAndroid Build Coastguard Worker pixel *const top = &topleft_out[1];
165*c0909341SAndroid Build Coastguard Worker
166*c0909341SAndroid Build Coastguard Worker if (have_top) {
167*c0909341SAndroid Build Coastguard Worker const int px_have = imin(sz, (w - x) << 2);
168*c0909341SAndroid Build Coastguard Worker pixel_copy(top, dst_top, px_have);
169*c0909341SAndroid Build Coastguard Worker if (px_have < sz)
170*c0909341SAndroid Build Coastguard Worker pixel_set(top + px_have, top[px_have - 1], sz - px_have);
171*c0909341SAndroid Build Coastguard Worker } else {
172*c0909341SAndroid Build Coastguard Worker pixel_set(top, have_left ? dst[-1] : ((1 << bitdepth) >> 1) - 1, sz);
173*c0909341SAndroid Build Coastguard Worker }
174*c0909341SAndroid Build Coastguard Worker
175*c0909341SAndroid Build Coastguard Worker if (av1_intra_prediction_edges[mode].needs_topright) {
176*c0909341SAndroid Build Coastguard Worker const int have_topright = (!have_top || x + tw >= w) ? 0 :
177*c0909341SAndroid Build Coastguard Worker (edge_flags & EDGE_I444_TOP_HAS_RIGHT);
178*c0909341SAndroid Build Coastguard Worker
179*c0909341SAndroid Build Coastguard Worker if (have_topright) {
180*c0909341SAndroid Build Coastguard Worker const int px_have = imin(sz, (w - x - tw) << 2);
181*c0909341SAndroid Build Coastguard Worker
182*c0909341SAndroid Build Coastguard Worker pixel_copy(top + sz, &dst_top[sz], px_have);
183*c0909341SAndroid Build Coastguard Worker if (px_have < sz)
184*c0909341SAndroid Build Coastguard Worker pixel_set(top + sz + px_have, top[sz + px_have - 1],
185*c0909341SAndroid Build Coastguard Worker sz - px_have);
186*c0909341SAndroid Build Coastguard Worker } else {
187*c0909341SAndroid Build Coastguard Worker pixel_set(top + sz, top[sz - 1], sz);
188*c0909341SAndroid Build Coastguard Worker }
189*c0909341SAndroid Build Coastguard Worker }
190*c0909341SAndroid Build Coastguard Worker }
191*c0909341SAndroid Build Coastguard Worker
192*c0909341SAndroid Build Coastguard Worker if (av1_intra_prediction_edges[mode].needs_topleft) {
193*c0909341SAndroid Build Coastguard Worker if (have_left)
194*c0909341SAndroid Build Coastguard Worker *topleft_out = have_top ? dst_top[-1] : dst[-1];
195*c0909341SAndroid Build Coastguard Worker else
196*c0909341SAndroid Build Coastguard Worker *topleft_out = have_top ? *dst_top : (1 << bitdepth) >> 1;
197*c0909341SAndroid Build Coastguard Worker
198*c0909341SAndroid Build Coastguard Worker if (mode == Z2_PRED && tw + th >= 6 && filter_edge)
199*c0909341SAndroid Build Coastguard Worker *topleft_out = ((topleft_out[-1] + topleft_out[1]) * 5 +
200*c0909341SAndroid Build Coastguard Worker topleft_out[0] * 6 + 8) >> 4;
201*c0909341SAndroid Build Coastguard Worker }
202*c0909341SAndroid Build Coastguard Worker
203*c0909341SAndroid Build Coastguard Worker return mode;
204*c0909341SAndroid Build Coastguard Worker }
205