1 /*****************************************************************************
2  * Copyright (C) 2013-2020 MulticoreWare, Inc
3  *
4  * Authors: Steve Borho <steve@borho.org>
5  *          Deepthi Devaki <deepthidevaki@multicorewareinc.com>
6  *          Min Chen <chenm003@163.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
21  *
22  * This program is also available under a commercial proprietary license.
23  * For more information, contact us at license @ x265.com.
24  *****************************************************************************/
25 
26 #include "common.h"
27 #include "primitives.h"
28 #include "slice.h"
29 #include "picyuv.h"
30 
31 #include "reference.h"
32 
33 using namespace X265_NS;
34 
MotionReference()35 MotionReference::MotionReference()
36 {
37     weightBuffer[0] = NULL;
38     weightBuffer[1] = NULL;
39     weightBuffer[2] = NULL;
40     numSliceWeightedRows = NULL;
41 }
42 
~MotionReference()43 MotionReference::~MotionReference()
44 {
45     X265_FREE(numSliceWeightedRows);
46     X265_FREE(weightBuffer[0]);
47     X265_FREE(weightBuffer[1]);
48     X265_FREE(weightBuffer[2]);
49 }
50 
init(PicYuv * recPic,WeightParam * wp,const x265_param & p)51 int MotionReference::init(PicYuv* recPic, WeightParam *wp, const x265_param& p)
52 {
53     reconPic = recPic;
54     lumaStride = recPic->m_stride;
55     chromaStride = recPic->m_strideC;
56     numInterpPlanes = p.subpelRefine > 2 ? 3 : 1; /* is chroma satd possible? */
57 
58     if (numSliceWeightedRows)
59     {
60         // Unnecessary, but avoid risk on parameters dynamic modify in future.
61         X265_FREE(numSliceWeightedRows);
62         numSliceWeightedRows = NULL;
63     }
64     numSliceWeightedRows = X265_MALLOC(uint32_t, p.maxSlices);
65     memset(numSliceWeightedRows, 0, p.maxSlices * sizeof(uint32_t));
66 
67     /* directly reference the extended integer pel planes */
68     fpelPlane[0] = recPic->m_picOrg[0];
69     fpelPlane[1] = recPic->m_picOrg[1];
70     fpelPlane[2] = recPic->m_picOrg[2];
71     isWeighted = false;
72 
73     if (wp)
74     {
75         uint32_t numCUinHeight = (reconPic->m_picHeight + p.maxCUSize - 1) / p.maxCUSize;
76 
77         int marginX = reconPic->m_lumaMarginX;
78         int marginY = reconPic->m_lumaMarginY;
79         intptr_t stride = reconPic->m_stride;
80         int cuHeight = p.maxCUSize;
81 
82         for (int c = 0; c < (p.internalCsp != X265_CSP_I400 && recPic->m_picCsp != X265_CSP_I400 ? numInterpPlanes : 1); c++)
83         {
84             if (c == 1)
85             {
86                 marginX = reconPic->m_chromaMarginX;
87                 marginY = reconPic->m_chromaMarginY;
88                 stride  = reconPic->m_strideC;
89                 cuHeight >>= reconPic->m_vChromaShift;
90             }
91 
92             if (wp[c].wtPresent)
93             {
94                 if (!weightBuffer[c])
95                 {
96                     size_t padheight = (numCUinHeight * cuHeight) + marginY * 2;
97                     weightBuffer[c] = X265_MALLOC(pixel, stride * padheight);
98                     if (!weightBuffer[c])
99                         return -1;
100                 }
101 
102                 /* use our buffer which will have weighted pixels written to it */
103                 fpelPlane[c] = weightBuffer[c] + marginY * stride + marginX;
104                 X265_CHECK(recPic->m_picOrg[c] - recPic->m_picBuf[c] == marginY * stride + marginX, "PicYuv pad calculation mismatch\n");
105 
106                 w[c].weight = wp[c].inputWeight;
107                 w[c].offset = wp[c].inputOffset * (1 << (X265_DEPTH - 8));
108                 w[c].shift = wp[c].log2WeightDenom;
109                 w[c].round = w[c].shift ? 1 << (w[c].shift - 1) : 0;
110             }
111         }
112 
113         isWeighted = true;
114     }
115 
116     return 0;
117 }
118 
applyWeight(uint32_t finishedRows,uint32_t maxNumRows,uint32_t maxNumRowsInSlice,uint32_t sliceId)119 void MotionReference::applyWeight(uint32_t finishedRows, uint32_t maxNumRows, uint32_t maxNumRowsInSlice, uint32_t sliceId)
120 {
121     const uint32_t numWeightedRows = numSliceWeightedRows[sliceId];
122     finishedRows = X265_MIN(finishedRows, maxNumRowsInSlice);
123     if (numWeightedRows >= finishedRows)
124         return;
125 
126     int marginX = reconPic->m_lumaMarginX;
127     int marginY = reconPic->m_lumaMarginY;
128     intptr_t stride = reconPic->m_stride;
129     int width   = reconPic->m_picWidth;
130     int height  = (finishedRows - numWeightedRows) * reconPic->m_param->maxCUSize;
131     /* the last row may be partial height */
132     if (finishedRows == maxNumRows - 1)
133     {
134         const int leftRows = (reconPic->m_picHeight & (reconPic->m_param->maxCUSize - 1));
135 
136         height += leftRows ? leftRows : reconPic->m_param->maxCUSize;
137     }
138     int cuHeight = reconPic->m_param->maxCUSize;
139 
140     for (int c = 0; c < numInterpPlanes; c++)
141     {
142         if (c == 1)
143         {
144             marginX = reconPic->m_chromaMarginX;
145             marginY = reconPic->m_chromaMarginY;
146             stride  = reconPic->m_strideC;
147             width    >>= reconPic->m_hChromaShift;
148             height   >>= reconPic->m_vChromaShift;
149             cuHeight >>= reconPic->m_vChromaShift;
150         }
151 
152         /* Do not generate weighted predictions if using original picture */
153         if (fpelPlane[c] == reconPic->m_picOrg[c])
154             continue;
155 
156         const pixel* src = reconPic->m_picOrg[c] + numWeightedRows * cuHeight * stride;
157         pixel* dst = fpelPlane[c] + numWeightedRows * cuHeight * stride;
158         // Computing weighted CU rows
159         int correction = IF_INTERNAL_PREC - X265_DEPTH; // intermediate interpolation depth
160         int padwidth = (width + 31) & ~31;              // weightp assembly needs even 32 byte widths
161         primitives.weight_pp(src, dst, stride, padwidth, height, w[c].weight, w[c].round << correction, w[c].shift + correction, w[c].offset);
162         // Extending Left & Right
163         primitives.extendRowBorder(dst, stride, width, height, marginX);
164 
165         // Extending Above
166         if (numWeightedRows == 0)
167         {
168             pixel *pixY = fpelPlane[c] - marginX;
169             for (int y = 0; y < marginY; y++)
170                 memcpy(pixY - (y + 1) * stride, pixY, stride * sizeof(pixel));
171         }
172 
173         // Extending Bottom
174         if (finishedRows == maxNumRows - 1)
175         {
176             int picHeight = reconPic->m_picHeight;
177             if (c) picHeight >>= reconPic->m_vChromaShift;
178             pixel *pixY = fpelPlane[c] - marginX + (picHeight - 1) * stride;
179             for (int y = 0; y < marginY; y++)
180                 memcpy(pixY + (y + 1) * stride, pixY, stride * sizeof(pixel));
181         }
182     }
183 
184     numSliceWeightedRows[sliceId] = finishedRows;
185 }
186