/work/libde265/libde265/motion.cc
Line | Count | Source |
1 | | /* |
2 | | * H.265 video codec. |
3 | | * Copyright (c) 2013-2014 struktur AG, Dirk Farin <farin@struktur.de> |
4 | | * |
5 | | * This file is part of libde265. |
6 | | * |
7 | | * libde265 is free software: you can redistribute it and/or modify |
8 | | * it under the terms of the GNU Lesser General Public License as |
9 | | * published by the Free Software Foundation, either version 3 of |
10 | | * the License, or (at your option) any later version. |
11 | | * |
12 | | * libde265 is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | | * GNU Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public License |
18 | | * along with libde265. If not, see <http://www.gnu.org/licenses/>. |
19 | | */ |
20 | | |
21 | | #include "motion.h" |
22 | | #include "decctx.h" |
23 | | #include "util.h" |
24 | | #include "dpb.h" |
25 | | |
26 | | #include <assert.h> |
27 | | |
28 | | |
29 | | #include <sys/types.h> |
30 | | #include <signal.h> |
31 | | #include <string.h> |
32 | | |
33 | | #if defined(_MSC_VER) || defined(__MINGW32__) |
34 | | # include <malloc.h> |
35 | | #elif defined(HAVE_ALLOCA_H) |
36 | | # include <alloca.h> |
37 | | #endif |
38 | | |
39 | | |
40 | 194M | #define MAX_CU_SIZE 64 |
41 | | |
42 | | |
43 | | static int extra_before[4] = { 0,3,3,2 }; |
44 | | static int extra_after [4] = { 0,3,4,4 }; |
45 | | |
46 | | |
47 | | |
48 | | // Luma sample interpolation process (8.5.3.3.3.2). |
49 | | // inter_t is the type of the intermediate prediction samples (see |
50 | | // generate_inter_prediction_samples_plane below). |
51 | | template <class pixel_t, class inter_t> |
52 | | void mc_luma(const base_context* ctx, |
53 | | const seq_parameter_set* sps, int mv_x, int mv_y, |
54 | | int xP,int yP, |
55 | | inter_t* out, int out_stride, |
56 | | const pixel_t* ref, ptrdiff_t ref_stride, |
57 | | int nPbW, int nPbH, int bitDepth_L) |
58 | 1.31M | { |
59 | 1.31M | int xFracL = mv_x & 3; |
60 | 1.31M | int yFracL = mv_y & 3; |
61 | | |
62 | 1.31M | int xIntOffsL = xP + (mv_x>>2); |
63 | 1.31M | int yIntOffsL = yP + (mv_y>>2); |
64 | | |
65 | | //const int shift1 = std::min(4, sps->BitDepth_Y-8); |
66 | | //const int shift2 = 6; |
67 | 1.31M | const int shift3 = std::max(2, 14 - sps->BitDepth_Y); |
68 | | |
69 | 1.31M | int w = sps->pic_width_in_luma_samples; |
70 | 1.31M | int h = sps->pic_height_in_luma_samples; |
71 | | |
72 | 1.31M | ALIGNED_16(inter_t) mcbuffer[MAX_CU_SIZE * (MAX_CU_SIZE+7)]; |
73 | | |
74 | 1.31M | if (xFracL==0 && yFracL==0) { |
75 | | |
76 | 698k | if (xIntOffsL >= 0 && yIntOffsL >= 0 && |
77 | 690k | nPbW+xIntOffsL <= w && nPbH+yIntOffsL <= h) { |
78 | | |
79 | 666k | ctx->acceleration.put_hevc_qpel(out, out_stride, |
80 | 666k | &ref[yIntOffsL*ref_stride + xIntOffsL], |
81 | 666k | ref_stride /* sizeof(pixel_t)*/, |
82 | 666k | nPbW,nPbH, mcbuffer, 0,0, bitDepth_L); |
83 | 666k | } |
84 | 31.5k | else { |
85 | 350k | for (int y=0;y<nPbH;y++) |
86 | 4.83M | for (int x=0;x<nPbW;x++) { |
87 | | |
88 | 4.51M | int xA = Clip3(0,w-1,x + xIntOffsL); |
89 | 4.51M | int yA = Clip3(0,h-1,y + yIntOffsL); |
90 | | |
91 | 4.51M | out[y*out_stride+x] = ref[ xA + yA*ref_stride ] << shift3; |
92 | 4.51M | } |
93 | 31.5k | } |
94 | | |
95 | | #ifdef DE265_LOG_TRACE |
96 | | logtrace(LogMotion,"---MC luma %d %d = direct---\n",xFracL,yFracL); |
97 | | |
98 | | for (int y=0;y<nPbH;y++) { |
99 | | for (int x=0;x<nPbW;x++) { |
100 | | |
101 | | int xA = Clip3(0,w-1,x + xIntOffsL); |
102 | | int yA = Clip3(0,h-1,y + yIntOffsL); |
103 | | |
104 | | logtrace(LogMotion,"%02x ", ref[ xA + yA*ref_stride ]); |
105 | | } |
106 | | logtrace(LogMotion,"\n"); |
107 | | } |
108 | | |
109 | | logtrace(LogMotion," -> \n"); |
110 | | |
111 | | for (int y=0;y<nPbH;y++) { |
112 | | for (int x=0;x<nPbW;x++) { |
113 | | |
114 | | logtrace(LogMotion,"%02x ",out[y*out_stride+x] >> 6); // 6 will be used when summing predictions |
115 | | } |
116 | | logtrace(LogMotion,"\n"); |
117 | | } |
118 | | #endif |
119 | 698k | } |
120 | 619k | else { |
121 | 619k | int extra_left = extra_before[xFracL]; |
122 | 619k | int extra_right = extra_after [xFracL]; |
123 | 619k | int extra_top = extra_before[yFracL]; |
124 | 619k | int extra_bottom = extra_after [yFracL]; |
125 | | |
126 | | //int nPbW_extra = extra_left + nPbW + extra_right; |
127 | | //int nPbH_extra = extra_top + nPbH + extra_bottom; |
128 | | |
129 | | |
130 | 619k | pixel_t padbuf[(MAX_CU_SIZE+16)*(MAX_CU_SIZE+7)]; |
131 | | |
132 | 619k | const pixel_t* src_ptr; |
133 | 619k | ptrdiff_t src_stride; |
134 | | |
135 | 619k | if (-extra_left + xIntOffsL >= 0 && |
136 | 600k | -extra_top + yIntOffsL >= 0 && |
137 | 546k | nPbW+extra_right + xIntOffsL < w && |
138 | 523k | nPbH+extra_bottom + yIntOffsL < h) { |
139 | 401k | src_ptr = &ref[xIntOffsL + yIntOffsL*ref_stride]; |
140 | 401k | src_stride = ref_stride; |
141 | 401k | } |
142 | 218k | else { |
143 | | // Extend fill width to a multiple of 16 so that SIMD over-reads |
144 | | // in qpel interpolation hit valid (edge-clamped) data. |
145 | 218k | int fill_width = ((extra_left + nPbW + extra_right + 15) & ~15); |
146 | 218k | if (fill_width > MAX_CU_SIZE+16) fill_width = MAX_CU_SIZE+16; |
147 | | |
148 | 3.96M | for (int y=-extra_top;y<nPbH+extra_bottom;y++) { |
149 | 104M | for (int x=-extra_left;x<fill_width - extra_left;x++) { |
150 | | |
151 | 100M | int xA = Clip3(0,w-1,x + xIntOffsL); |
152 | 100M | int yA = Clip3(0,h-1,y + yIntOffsL); |
153 | | |
154 | 100M | padbuf[x+extra_left + (y+extra_top)*(MAX_CU_SIZE+16)] = ref[ xA + yA*ref_stride ]; |
155 | 100M | } |
156 | 3.74M | } |
157 | | |
158 | 218k | src_ptr = &padbuf[extra_top*(MAX_CU_SIZE+16) + extra_left]; |
159 | 218k | src_stride = MAX_CU_SIZE+16; |
160 | 218k | } |
161 | | |
162 | 619k | ctx->acceleration.put_hevc_qpel(out, out_stride, |
163 | 619k | src_ptr, src_stride /* sizeof(pixel_t) */, |
164 | 619k | nPbW,nPbH, mcbuffer, xFracL,yFracL, bitDepth_L); |
165 | | |
166 | | |
167 | 619k | logtrace(LogMotion,"---V---\n"); |
168 | 6.71M | for (int y=0;y<nPbH;y++) { |
169 | 94.0M | for (int x=0;x<nPbW;x++) { |
170 | 88.0M | logtrace(LogMotion,"%04x ",out[x+y*out_stride]); |
171 | 88.0M | } |
172 | 6.09M | logtrace(LogMotion,"\n"); |
173 | 6.09M | } |
174 | 619k | } |
175 | 1.31M | } void mc_luma<unsigned short, short>(base_context const*, seq_parameter_set const*, int, int, int, int, short*, int, unsigned short const*, long, int, int, int) Line | Count | Source | 58 | 161k | { | 59 | 161k | int xFracL = mv_x & 3; | 60 | 161k | int yFracL = mv_y & 3; | 61 | | | 62 | 161k | int xIntOffsL = xP + (mv_x>>2); | 63 | 161k | int yIntOffsL = yP + (mv_y>>2); | 64 | | | 65 | | //const int shift1 = std::min(4, sps->BitDepth_Y-8); | 66 | | //const int shift2 = 6; | 67 | 161k | const int shift3 = std::max(2, 14 - sps->BitDepth_Y); | 68 | | | 69 | 161k | int w = sps->pic_width_in_luma_samples; | 70 | 161k | int h = sps->pic_height_in_luma_samples; | 71 | | | 72 | 161k | ALIGNED_16(inter_t) mcbuffer[MAX_CU_SIZE * (MAX_CU_SIZE+7)]; | 73 | | | 74 | 161k | if (xFracL==0 && yFracL==0) { | 75 | | | 76 | 78.3k | if (xIntOffsL >= 0 && yIntOffsL >= 0 && | 77 | 77.1k | nPbW+xIntOffsL <= w && nPbH+yIntOffsL <= h) { | 78 | | | 79 | 71.5k | ctx->acceleration.put_hevc_qpel(out, out_stride, | 80 | 71.5k | &ref[yIntOffsL*ref_stride + xIntOffsL], | 81 | 71.5k | ref_stride /* sizeof(pixel_t)*/, | 82 | 71.5k | nPbW,nPbH, mcbuffer, 0,0, bitDepth_L); | 83 | 71.5k | } | 84 | 6.86k | else { | 85 | 66.0k | for (int y=0;y<nPbH;y++) | 86 | 787k | for (int x=0;x<nPbW;x++) { | 87 | | | 88 | 728k | int xA = Clip3(0,w-1,x + xIntOffsL); | 89 | 728k | int yA = Clip3(0,h-1,y + yIntOffsL); | 90 | | | 91 | 728k | out[y*out_stride+x] = ref[ xA + yA*ref_stride ] << shift3; | 92 | 728k | } | 93 | 6.86k | } | 94 | | | 95 | | #ifdef DE265_LOG_TRACE | 96 | | logtrace(LogMotion,"---MC luma %d %d = direct---\n",xFracL,yFracL); | 97 | | | 98 | | for (int y=0;y<nPbH;y++) { | 99 | | for (int x=0;x<nPbW;x++) { | 100 | | | 101 | | int xA = Clip3(0,w-1,x + xIntOffsL); | 102 | | int yA = Clip3(0,h-1,y + yIntOffsL); | 103 | | | 104 | | logtrace(LogMotion,"%02x ", ref[ xA + yA*ref_stride ]); | 105 | | } | 106 | | logtrace(LogMotion,"\n"); | 107 | | } | 108 | | | 109 | | logtrace(LogMotion," -> \n"); | 110 | | | 111 | | for (int y=0;y<nPbH;y++) { | 112 | | for (int x=0;x<nPbW;x++) { | 113 | | | 114 | | logtrace(LogMotion,"%02x ",out[y*out_stride+x] >> 6); // 6 will be used when summing predictions | 115 | | } | 116 | | logtrace(LogMotion,"\n"); | 117 | | } | 118 | | #endif | 119 | 78.3k | } | 120 | 83.3k | else { | 121 | 83.3k | int extra_left = extra_before[xFracL]; | 122 | 83.3k | int extra_right = extra_after [xFracL]; | 123 | 83.3k | int extra_top = extra_before[yFracL]; | 124 | 83.3k | int extra_bottom = extra_after [yFracL]; | 125 | | | 126 | | //int nPbW_extra = extra_left + nPbW + extra_right; | 127 | | //int nPbH_extra = extra_top + nPbH + extra_bottom; | 128 | | | 129 | | | 130 | 83.3k | pixel_t padbuf[(MAX_CU_SIZE+16)*(MAX_CU_SIZE+7)]; | 131 | | | 132 | 83.3k | const pixel_t* src_ptr; | 133 | 83.3k | ptrdiff_t src_stride; | 134 | | | 135 | 83.3k | if (-extra_left + xIntOffsL >= 0 && | 136 | 80.3k | -extra_top + yIntOffsL >= 0 && | 137 | 74.9k | nPbW+extra_right + xIntOffsL < w && | 138 | 68.7k | nPbH+extra_bottom + yIntOffsL < h) { | 139 | 50.4k | src_ptr = &ref[xIntOffsL + yIntOffsL*ref_stride]; | 140 | 50.4k | src_stride = ref_stride; | 141 | 50.4k | } | 142 | 32.8k | else { | 143 | | // Extend fill width to a multiple of 16 so that SIMD over-reads | 144 | | // in qpel interpolation hit valid (edge-clamped) data. | 145 | 32.8k | int fill_width = ((extra_left + nPbW + extra_right + 15) & ~15); | 146 | 32.8k | if (fill_width > MAX_CU_SIZE+16) fill_width = MAX_CU_SIZE+16; | 147 | | | 148 | 534k | for (int y=-extra_top;y<nPbH+extra_bottom;y++) { | 149 | 12.1M | for (int x=-extra_left;x<fill_width - extra_left;x++) { | 150 | | | 151 | 11.6M | int xA = Clip3(0,w-1,x + xIntOffsL); | 152 | 11.6M | int yA = Clip3(0,h-1,y + yIntOffsL); | 153 | | | 154 | 11.6M | padbuf[x+extra_left + (y+extra_top)*(MAX_CU_SIZE+16)] = ref[ xA + yA*ref_stride ]; | 155 | 11.6M | } | 156 | 501k | } | 157 | | | 158 | 32.8k | src_ptr = &padbuf[extra_top*(MAX_CU_SIZE+16) + extra_left]; | 159 | 32.8k | src_stride = MAX_CU_SIZE+16; | 160 | 32.8k | } | 161 | | | 162 | 83.3k | ctx->acceleration.put_hevc_qpel(out, out_stride, | 163 | 83.3k | src_ptr, src_stride /* sizeof(pixel_t) */, | 164 | 83.3k | nPbW,nPbH, mcbuffer, xFracL,yFracL, bitDepth_L); | 165 | | | 166 | | | 167 | 83.3k | logtrace(LogMotion,"---V---\n"); | 168 | 852k | for (int y=0;y<nPbH;y++) { | 169 | 11.7M | for (int x=0;x<nPbW;x++) { | 170 | 11.0M | logtrace(LogMotion,"%04x ",out[x+y*out_stride]); | 171 | 11.0M | } | 172 | 769k | logtrace(LogMotion,"\n"); | 173 | 769k | } | 174 | 83.3k | } | 175 | 161k | } |
void mc_luma<unsigned char, short>(base_context const*, seq_parameter_set const*, int, int, int, int, short*, int, unsigned char const*, long, int, int, int) Line | Count | Source | 58 | 785k | { | 59 | 785k | int xFracL = mv_x & 3; | 60 | 785k | int yFracL = mv_y & 3; | 61 | | | 62 | 785k | int xIntOffsL = xP + (mv_x>>2); | 63 | 785k | int yIntOffsL = yP + (mv_y>>2); | 64 | | | 65 | | //const int shift1 = std::min(4, sps->BitDepth_Y-8); | 66 | | //const int shift2 = 6; | 67 | 785k | const int shift3 = std::max(2, 14 - sps->BitDepth_Y); | 68 | | | 69 | 785k | int w = sps->pic_width_in_luma_samples; | 70 | 785k | int h = sps->pic_height_in_luma_samples; | 71 | | | 72 | 785k | ALIGNED_16(inter_t) mcbuffer[MAX_CU_SIZE * (MAX_CU_SIZE+7)]; | 73 | | | 74 | 785k | if (xFracL==0 && yFracL==0) { | 75 | | | 76 | 393k | if (xIntOffsL >= 0 && yIntOffsL >= 0 && | 77 | 388k | nPbW+xIntOffsL <= w && nPbH+yIntOffsL <= h) { | 78 | | | 79 | 377k | ctx->acceleration.put_hevc_qpel(out, out_stride, | 80 | 377k | &ref[yIntOffsL*ref_stride + xIntOffsL], | 81 | 377k | ref_stride /* sizeof(pixel_t)*/, | 82 | 377k | nPbW,nPbH, mcbuffer, 0,0, bitDepth_L); | 83 | 377k | } | 84 | 16.2k | else { | 85 | 203k | for (int y=0;y<nPbH;y++) | 86 | 3.24M | for (int x=0;x<nPbW;x++) { | 87 | | | 88 | 3.05M | int xA = Clip3(0,w-1,x + xIntOffsL); | 89 | 3.05M | int yA = Clip3(0,h-1,y + yIntOffsL); | 90 | | | 91 | 3.05M | out[y*out_stride+x] = ref[ xA + yA*ref_stride ] << shift3; | 92 | 3.05M | } | 93 | 16.2k | } | 94 | | | 95 | | #ifdef DE265_LOG_TRACE | 96 | | logtrace(LogMotion,"---MC luma %d %d = direct---\n",xFracL,yFracL); | 97 | | | 98 | | for (int y=0;y<nPbH;y++) { | 99 | | for (int x=0;x<nPbW;x++) { | 100 | | | 101 | | int xA = Clip3(0,w-1,x + xIntOffsL); | 102 | | int yA = Clip3(0,h-1,y + yIntOffsL); | 103 | | | 104 | | logtrace(LogMotion,"%02x ", ref[ xA + yA*ref_stride ]); | 105 | | } | 106 | | logtrace(LogMotion,"\n"); | 107 | | } | 108 | | | 109 | | logtrace(LogMotion," -> \n"); | 110 | | | 111 | | for (int y=0;y<nPbH;y++) { | 112 | | for (int x=0;x<nPbW;x++) { | 113 | | | 114 | | logtrace(LogMotion,"%02x ",out[y*out_stride+x] >> 6); // 6 will be used when summing predictions | 115 | | } | 116 | | logtrace(LogMotion,"\n"); | 117 | | } | 118 | | #endif | 119 | 393k | } | 120 | 391k | else { | 121 | 391k | int extra_left = extra_before[xFracL]; | 122 | 391k | int extra_right = extra_after [xFracL]; | 123 | 391k | int extra_top = extra_before[yFracL]; | 124 | 391k | int extra_bottom = extra_after [yFracL]; | 125 | | | 126 | | //int nPbW_extra = extra_left + nPbW + extra_right; | 127 | | //int nPbH_extra = extra_top + nPbH + extra_bottom; | 128 | | | 129 | | | 130 | 391k | pixel_t padbuf[(MAX_CU_SIZE+16)*(MAX_CU_SIZE+7)]; | 131 | | | 132 | 391k | const pixel_t* src_ptr; | 133 | 391k | ptrdiff_t src_stride; | 134 | | | 135 | 391k | if (-extra_left + xIntOffsL >= 0 && | 136 | 376k | -extra_top + yIntOffsL >= 0 && | 137 | 339k | nPbW+extra_right + xIntOffsL < w && | 138 | 327k | nPbH+extra_bottom + yIntOffsL < h) { | 139 | 252k | src_ptr = &ref[xIntOffsL + yIntOffsL*ref_stride]; | 140 | 252k | src_stride = ref_stride; | 141 | 252k | } | 142 | 139k | else { | 143 | | // Extend fill width to a multiple of 16 so that SIMD over-reads | 144 | | // in qpel interpolation hit valid (edge-clamped) data. | 145 | 139k | int fill_width = ((extra_left + nPbW + extra_right + 15) & ~15); | 146 | 139k | if (fill_width > MAX_CU_SIZE+16) fill_width = MAX_CU_SIZE+16; | 147 | | | 148 | 2.62M | for (int y=-extra_top;y<nPbH+extra_bottom;y++) { | 149 | 71.0M | for (int x=-extra_left;x<fill_width - extra_left;x++) { | 150 | | | 151 | 68.5M | int xA = Clip3(0,w-1,x + xIntOffsL); | 152 | 68.5M | int yA = Clip3(0,h-1,y + yIntOffsL); | 153 | | | 154 | 68.5M | padbuf[x+extra_left + (y+extra_top)*(MAX_CU_SIZE+16)] = ref[ xA + yA*ref_stride ]; | 155 | 68.5M | } | 156 | 2.48M | } | 157 | | | 158 | 139k | src_ptr = &padbuf[extra_top*(MAX_CU_SIZE+16) + extra_left]; | 159 | 139k | src_stride = MAX_CU_SIZE+16; | 160 | 139k | } | 161 | | | 162 | 391k | ctx->acceleration.put_hevc_qpel(out, out_stride, | 163 | 391k | src_ptr, src_stride /* sizeof(pixel_t) */, | 164 | 391k | nPbW,nPbH, mcbuffer, xFracL,yFracL, bitDepth_L); | 165 | | | 166 | | | 167 | 391k | logtrace(LogMotion,"---V---\n"); | 168 | 4.34M | for (int y=0;y<nPbH;y++) { | 169 | 59.0M | for (int x=0;x<nPbW;x++) { | 170 | 55.0M | logtrace(LogMotion,"%04x ",out[x+y*out_stride]); | 171 | 55.0M | } | 172 | 3.95M | logtrace(LogMotion,"\n"); | 173 | 3.95M | } | 174 | 391k | } | 175 | 785k | } |
void mc_luma<unsigned short, int>(base_context const*, seq_parameter_set const*, int, int, int, int, int*, int, unsigned short const*, long, int, int, int) Line | Count | Source | 58 | 370k | { | 59 | 370k | int xFracL = mv_x & 3; | 60 | 370k | int yFracL = mv_y & 3; | 61 | | | 62 | 370k | int xIntOffsL = xP + (mv_x>>2); | 63 | 370k | int yIntOffsL = yP + (mv_y>>2); | 64 | | | 65 | | //const int shift1 = std::min(4, sps->BitDepth_Y-8); | 66 | | //const int shift2 = 6; | 67 | 370k | const int shift3 = std::max(2, 14 - sps->BitDepth_Y); | 68 | | | 69 | 370k | int w = sps->pic_width_in_luma_samples; | 70 | 370k | int h = sps->pic_height_in_luma_samples; | 71 | | | 72 | 370k | ALIGNED_16(inter_t) mcbuffer[MAX_CU_SIZE * (MAX_CU_SIZE+7)]; | 73 | | | 74 | 370k | if (xFracL==0 && yFracL==0) { | 75 | | | 76 | 226k | if (xIntOffsL >= 0 && yIntOffsL >= 0 && | 77 | 225k | nPbW+xIntOffsL <= w && nPbH+yIntOffsL <= h) { | 78 | | | 79 | 217k | ctx->acceleration.put_hevc_qpel(out, out_stride, | 80 | 217k | &ref[yIntOffsL*ref_stride + xIntOffsL], | 81 | 217k | ref_stride /* sizeof(pixel_t)*/, | 82 | 217k | nPbW,nPbH, mcbuffer, 0,0, bitDepth_L); | 83 | 217k | } | 84 | 8.36k | else { | 85 | 80.4k | for (int y=0;y<nPbH;y++) | 86 | 801k | for (int x=0;x<nPbW;x++) { | 87 | | | 88 | 729k | int xA = Clip3(0,w-1,x + xIntOffsL); | 89 | 729k | int yA = Clip3(0,h-1,y + yIntOffsL); | 90 | | | 91 | 729k | out[y*out_stride+x] = ref[ xA + yA*ref_stride ] << shift3; | 92 | 729k | } | 93 | 8.36k | } | 94 | | | 95 | | #ifdef DE265_LOG_TRACE | 96 | | logtrace(LogMotion,"---MC luma %d %d = direct---\n",xFracL,yFracL); | 97 | | | 98 | | for (int y=0;y<nPbH;y++) { | 99 | | for (int x=0;x<nPbW;x++) { | 100 | | | 101 | | int xA = Clip3(0,w-1,x + xIntOffsL); | 102 | | int yA = Clip3(0,h-1,y + yIntOffsL); | 103 | | | 104 | | logtrace(LogMotion,"%02x ", ref[ xA + yA*ref_stride ]); | 105 | | } | 106 | | logtrace(LogMotion,"\n"); | 107 | | } | 108 | | | 109 | | logtrace(LogMotion," -> \n"); | 110 | | | 111 | | for (int y=0;y<nPbH;y++) { | 112 | | for (int x=0;x<nPbW;x++) { | 113 | | | 114 | | logtrace(LogMotion,"%02x ",out[y*out_stride+x] >> 6); // 6 will be used when summing predictions | 115 | | } | 116 | | logtrace(LogMotion,"\n"); | 117 | | } | 118 | | #endif | 119 | 226k | } | 120 | 144k | else { | 121 | 144k | int extra_left = extra_before[xFracL]; | 122 | 144k | int extra_right = extra_after [xFracL]; | 123 | 144k | int extra_top = extra_before[yFracL]; | 124 | 144k | int extra_bottom = extra_after [yFracL]; | 125 | | | 126 | | //int nPbW_extra = extra_left + nPbW + extra_right; | 127 | | //int nPbH_extra = extra_top + nPbH + extra_bottom; | 128 | | | 129 | | | 130 | 144k | pixel_t padbuf[(MAX_CU_SIZE+16)*(MAX_CU_SIZE+7)]; | 131 | | | 132 | 144k | const pixel_t* src_ptr; | 133 | 144k | ptrdiff_t src_stride; | 134 | | | 135 | 144k | if (-extra_left + xIntOffsL >= 0 && | 136 | 143k | -extra_top + yIntOffsL >= 0 && | 137 | 131k | nPbW+extra_right + xIntOffsL < w && | 138 | 127k | nPbH+extra_bottom + yIntOffsL < h) { | 139 | 98.7k | src_ptr = &ref[xIntOffsL + yIntOffsL*ref_stride]; | 140 | 98.7k | src_stride = ref_stride; | 141 | 98.7k | } | 142 | 45.4k | else { | 143 | | // Extend fill width to a multiple of 16 so that SIMD over-reads | 144 | | // in qpel interpolation hit valid (edge-clamped) data. | 145 | 45.4k | int fill_width = ((extra_left + nPbW + extra_right + 15) & ~15); | 146 | 45.4k | if (fill_width > MAX_CU_SIZE+16) fill_width = MAX_CU_SIZE+16; | 147 | | | 148 | 810k | for (int y=-extra_top;y<nPbH+extra_bottom;y++) { | 149 | 21.0M | for (int x=-extra_left;x<fill_width - extra_left;x++) { | 150 | | | 151 | 20.2M | int xA = Clip3(0,w-1,x + xIntOffsL); | 152 | 20.2M | int yA = Clip3(0,h-1,y + yIntOffsL); | 153 | | | 154 | 20.2M | padbuf[x+extra_left + (y+extra_top)*(MAX_CU_SIZE+16)] = ref[ xA + yA*ref_stride ]; | 155 | 20.2M | } | 156 | 764k | } | 157 | | | 158 | 45.4k | src_ptr = &padbuf[extra_top*(MAX_CU_SIZE+16) + extra_left]; | 159 | 45.4k | src_stride = MAX_CU_SIZE+16; | 160 | 45.4k | } | 161 | | | 162 | 144k | ctx->acceleration.put_hevc_qpel(out, out_stride, | 163 | 144k | src_ptr, src_stride /* sizeof(pixel_t) */, | 164 | 144k | nPbW,nPbH, mcbuffer, xFracL,yFracL, bitDepth_L); | 165 | | | 166 | | | 167 | 144k | logtrace(LogMotion,"---V---\n"); | 168 | 1.51M | for (int y=0;y<nPbH;y++) { | 169 | 23.2M | for (int x=0;x<nPbW;x++) { | 170 | 21.8M | logtrace(LogMotion,"%04x ",out[x+y*out_stride]); | 171 | 21.8M | } | 172 | 1.37M | logtrace(LogMotion,"\n"); | 173 | 1.37M | } | 174 | 144k | } | 175 | 370k | } |
Unexecuted instantiation: void mc_luma<unsigned char, int>(base_context const*, seq_parameter_set const*, int, int, int, int, int*, int, unsigned char const*, long, int, int, int) |
176 | | |
177 | | |
178 | | |
179 | | // Chroma sample interpolation process (8.5.3.3.3.3). |
180 | | template <class pixel_t, class inter_t> |
181 | | void mc_chroma(const base_context* ctx, |
182 | | const seq_parameter_set* sps, |
183 | | int mv_x, int mv_y, |
184 | | int xP,int yP, |
185 | | inter_t* out, int out_stride, |
186 | | const pixel_t* ref, ptrdiff_t ref_stride, |
187 | | int nPbWC, int nPbHC, int bit_depth_C) |
188 | 2.63M | { |
189 | | //const int shift1 = std::min(4, sps->BitDepth_C-8); |
190 | | //const int shift2 = 6; |
191 | 2.63M | const int shift3 = std::max(2, 14 - sps->BitDepth_C); |
192 | | |
193 | 2.63M | int wC = sps->pic_width_in_luma_samples /sps->SubWidthC; |
194 | 2.63M | int hC = sps->pic_height_in_luma_samples/sps->SubHeightC; |
195 | | |
196 | 2.63M | mv_x *= 2 / sps->SubWidthC; |
197 | 2.63M | mv_y *= 2 / sps->SubHeightC; |
198 | | |
199 | 2.63M | int xFracC = mv_x & 7; |
200 | 2.63M | int yFracC = mv_y & 7; |
201 | | |
202 | 2.63M | int xIntOffsC = xP/sps->SubWidthC + (mv_x>>3); |
203 | 2.63M | int yIntOffsC = yP/sps->SubHeightC + (mv_y>>3); |
204 | | |
205 | 2.63M | ALIGNED_32(inter_t mcbuffer[MAX_CU_SIZE*(MAX_CU_SIZE+7)]); |
206 | | |
207 | 2.63M | if (xFracC == 0 && yFracC == 0) { |
208 | 1.30M | if (xIntOffsC>=0 && nPbWC+xIntOffsC<=wC && |
209 | 1.30M | yIntOffsC>=0 && nPbHC+yIntOffsC<=hC) { |
210 | 1.28M | ctx->acceleration.put_hevc_epel(out, out_stride, |
211 | 1.28M | &ref[xIntOffsC + yIntOffsC*ref_stride], ref_stride, |
212 | 1.28M | nPbWC,nPbHC, 0,0, nullptr, bit_depth_C); |
213 | 1.28M | } |
214 | 25.1k | else |
215 | 25.1k | { |
216 | 149k | for (int y=0;y<nPbHC;y++) |
217 | 960k | for (int x=0;x<nPbWC;x++) { |
218 | | |
219 | 836k | int xB = Clip3(0,wC-1,x + xIntOffsC); |
220 | 836k | int yB = Clip3(0,hC-1,y + yIntOffsC); |
221 | | |
222 | 836k | out[y*out_stride+x] = ref[ xB + yB*ref_stride ] << shift3; |
223 | 836k | } |
224 | 25.1k | } |
225 | 1.30M | } |
226 | 1.32M | else { |
227 | 1.32M | pixel_t padbuf[(MAX_CU_SIZE+16)*(MAX_CU_SIZE+3)]; |
228 | | |
229 | 1.32M | const pixel_t* src_ptr; |
230 | 1.32M | ptrdiff_t src_stride; |
231 | | |
232 | 1.32M | int extra_top = 1; |
233 | 1.32M | int extra_left = 1; |
234 | 1.32M | int extra_right = 2; |
235 | 1.32M | int extra_bottom = 2; |
236 | | |
237 | 1.32M | if (xIntOffsC>=1 && nPbWC+xIntOffsC<=wC-2 && |
238 | 1.22M | yIntOffsC>=1 && nPbHC+yIntOffsC<=hC-2) { |
239 | 830k | src_ptr = &ref[xIntOffsC + yIntOffsC*ref_stride]; |
240 | 830k | src_stride = ref_stride; |
241 | 830k | } |
242 | 495k | else { |
243 | | // Extend fill width to a multiple of 16 so that SIMD over-reads |
244 | | // in epel interpolation hit valid (edge-clamped) data. |
245 | 495k | int fill_width = ((extra_left + nPbWC + extra_right + 15) & ~15); |
246 | 495k | if (fill_width > MAX_CU_SIZE+16) fill_width = MAX_CU_SIZE+16; |
247 | | |
248 | 4.93M | for (int y=-extra_top;y<nPbHC+extra_bottom;y++) { |
249 | 95.8M | for (int x=-extra_left;x<fill_width - extra_left;x++) { |
250 | | |
251 | 91.3M | int xA = Clip3(0,wC-1,x + xIntOffsC); |
252 | 91.3M | int yA = Clip3(0,hC-1,y + yIntOffsC); |
253 | | |
254 | 91.3M | padbuf[x+extra_left + (y+extra_top)*(MAX_CU_SIZE+16)] = ref[ xA + yA*ref_stride ]; |
255 | 91.3M | } |
256 | 4.44M | } |
257 | | |
258 | 495k | src_ptr = &padbuf[extra_left + extra_top*(MAX_CU_SIZE+16)]; |
259 | 495k | src_stride = MAX_CU_SIZE+16; |
260 | 495k | } |
261 | | |
262 | | |
263 | 1.32M | if (xFracC && yFracC) { |
264 | 879k | ctx->acceleration.put_hevc_epel_hv(out, out_stride, |
265 | 879k | src_ptr, src_stride, |
266 | 879k | nPbWC,nPbHC, xFracC,yFracC, mcbuffer, bit_depth_C); |
267 | 879k | } |
268 | 446k | else if (xFracC) { |
269 | 202k | ctx->acceleration.put_hevc_epel_h(out, out_stride, |
270 | 202k | src_ptr, src_stride, |
271 | 202k | nPbWC,nPbHC, xFracC,yFracC, mcbuffer, bit_depth_C); |
272 | 202k | } |
273 | 244k | else if (yFracC) { |
274 | 244k | ctx->acceleration.put_hevc_epel_v(out, out_stride, |
275 | 244k | src_ptr, src_stride, |
276 | 244k | nPbWC,nPbHC, xFracC,yFracC, mcbuffer, bit_depth_C); |
277 | 244k | } |
278 | 0 | else { |
279 | 0 | assert(false); // full-pel shifts are handled above |
280 | 0 | } |
281 | 1.32M | } |
282 | 2.63M | } void mc_chroma<unsigned short, short>(base_context const*, seq_parameter_set const*, int, int, int, int, short*, int, unsigned short const*, long, int, int, int) Line | Count | Source | 188 | 339k | { | 189 | | //const int shift1 = std::min(4, sps->BitDepth_C-8); | 190 | | //const int shift2 = 6; | 191 | 339k | const int shift3 = std::max(2, 14 - sps->BitDepth_C); | 192 | | | 193 | 339k | int wC = sps->pic_width_in_luma_samples /sps->SubWidthC; | 194 | 339k | int hC = sps->pic_height_in_luma_samples/sps->SubHeightC; | 195 | | | 196 | 339k | mv_x *= 2 / sps->SubWidthC; | 197 | 339k | mv_y *= 2 / sps->SubHeightC; | 198 | | | 199 | 339k | int xFracC = mv_x & 7; | 200 | 339k | int yFracC = mv_y & 7; | 201 | | | 202 | 339k | int xIntOffsC = xP/sps->SubWidthC + (mv_x>>3); | 203 | 339k | int yIntOffsC = yP/sps->SubHeightC + (mv_y>>3); | 204 | | | 205 | 339k | ALIGNED_32(inter_t mcbuffer[MAX_CU_SIZE*(MAX_CU_SIZE+7)]); | 206 | | | 207 | 339k | if (xFracC == 0 && yFracC == 0) { | 208 | 182k | if (xIntOffsC>=0 && nPbWC+xIntOffsC<=wC && | 209 | 181k | yIntOffsC>=0 && nPbHC+yIntOffsC<=hC) { | 210 | 176k | ctx->acceleration.put_hevc_epel(out, out_stride, | 211 | 176k | &ref[xIntOffsC + yIntOffsC*ref_stride], ref_stride, | 212 | 176k | nPbWC,nPbHC, 0,0, nullptr, bit_depth_C); | 213 | 176k | } | 214 | 5.84k | else | 215 | 5.84k | { | 216 | 33.5k | for (int y=0;y<nPbHC;y++) | 217 | 207k | for (int x=0;x<nPbWC;x++) { | 218 | | | 219 | 180k | int xB = Clip3(0,wC-1,x + xIntOffsC); | 220 | 180k | int yB = Clip3(0,hC-1,y + yIntOffsC); | 221 | | | 222 | 180k | out[y*out_stride+x] = ref[ xB + yB*ref_stride ] << shift3; | 223 | 180k | } | 224 | 5.84k | } | 225 | 182k | } | 226 | 157k | else { | 227 | 157k | pixel_t padbuf[(MAX_CU_SIZE+16)*(MAX_CU_SIZE+3)]; | 228 | | | 229 | 157k | const pixel_t* src_ptr; | 230 | 157k | ptrdiff_t src_stride; | 231 | | | 232 | 157k | int extra_top = 1; | 233 | 157k | int extra_left = 1; | 234 | 157k | int extra_right = 2; | 235 | 157k | int extra_bottom = 2; | 236 | | | 237 | 157k | if (xIntOffsC>=1 && nPbWC+xIntOffsC<=wC-2 && | 238 | 145k | yIntOffsC>=1 && nPbHC+yIntOffsC<=hC-2) { | 239 | 91.6k | src_ptr = &ref[xIntOffsC + yIntOffsC*ref_stride]; | 240 | 91.6k | src_stride = ref_stride; | 241 | 91.6k | } | 242 | 66.1k | else { | 243 | | // Extend fill width to a multiple of 16 so that SIMD over-reads | 244 | | // in epel interpolation hit valid (edge-clamped) data. | 245 | 66.1k | int fill_width = ((extra_left + nPbWC + extra_right + 15) & ~15); | 246 | 66.1k | if (fill_width > MAX_CU_SIZE+16) fill_width = MAX_CU_SIZE+16; | 247 | | | 248 | 608k | for (int y=-extra_top;y<nPbHC+extra_bottom;y++) { | 249 | 10.6M | for (int x=-extra_left;x<fill_width - extra_left;x++) { | 250 | | | 251 | 10.1M | int xA = Clip3(0,wC-1,x + xIntOffsC); | 252 | 10.1M | int yA = Clip3(0,hC-1,y + yIntOffsC); | 253 | | | 254 | 10.1M | padbuf[x+extra_left + (y+extra_top)*(MAX_CU_SIZE+16)] = ref[ xA + yA*ref_stride ]; | 255 | 10.1M | } | 256 | 542k | } | 257 | | | 258 | 66.1k | src_ptr = &padbuf[extra_left + extra_top*(MAX_CU_SIZE+16)]; | 259 | 66.1k | src_stride = MAX_CU_SIZE+16; | 260 | 66.1k | } | 261 | | | 262 | | | 263 | 157k | if (xFracC && yFracC) { | 264 | 122k | ctx->acceleration.put_hevc_epel_hv(out, out_stride, | 265 | 122k | src_ptr, src_stride, | 266 | 122k | nPbWC,nPbHC, xFracC,yFracC, mcbuffer, bit_depth_C); | 267 | 122k | } | 268 | 35.5k | else if (xFracC) { | 269 | 16.5k | ctx->acceleration.put_hevc_epel_h(out, out_stride, | 270 | 16.5k | src_ptr, src_stride, | 271 | 16.5k | nPbWC,nPbHC, xFracC,yFracC, mcbuffer, bit_depth_C); | 272 | 16.5k | } | 273 | 19.0k | else if (yFracC) { | 274 | 19.0k | ctx->acceleration.put_hevc_epel_v(out, out_stride, | 275 | 19.0k | src_ptr, src_stride, | 276 | 19.0k | nPbWC,nPbHC, xFracC,yFracC, mcbuffer, bit_depth_C); | 277 | 19.0k | } | 278 | 0 | else { | 279 | | assert(false); // full-pel shifts are handled above | 280 | 0 | } | 281 | 157k | } | 282 | 339k | } |
void mc_chroma<unsigned char, short>(base_context const*, seq_parameter_set const*, int, int, int, int, short*, int, unsigned char const*, long, int, int, int) Line | Count | Source | 188 | 2.25M | { | 189 | | //const int shift1 = std::min(4, sps->BitDepth_C-8); | 190 | | //const int shift2 = 6; | 191 | 2.25M | const int shift3 = std::max(2, 14 - sps->BitDepth_C); | 192 | | | 193 | 2.25M | int wC = sps->pic_width_in_luma_samples /sps->SubWidthC; | 194 | 2.25M | int hC = sps->pic_height_in_luma_samples/sps->SubHeightC; | 195 | | | 196 | 2.25M | mv_x *= 2 / sps->SubWidthC; | 197 | 2.25M | mv_y *= 2 / sps->SubHeightC; | 198 | | | 199 | 2.25M | int xFracC = mv_x & 7; | 200 | 2.25M | int yFracC = mv_y & 7; | 201 | | | 202 | 2.25M | int xIntOffsC = xP/sps->SubWidthC + (mv_x>>3); | 203 | 2.25M | int yIntOffsC = yP/sps->SubHeightC + (mv_y>>3); | 204 | | | 205 | 2.25M | ALIGNED_32(inter_t mcbuffer[MAX_CU_SIZE*(MAX_CU_SIZE+7)]); | 206 | | | 207 | 2.25M | if (xFracC == 0 && yFracC == 0) { | 208 | 1.10M | if (xIntOffsC>=0 && nPbWC+xIntOffsC<=wC && | 209 | 1.10M | yIntOffsC>=0 && nPbHC+yIntOffsC<=hC) { | 210 | 1.08M | ctx->acceleration.put_hevc_epel(out, out_stride, | 211 | 1.08M | &ref[xIntOffsC + yIntOffsC*ref_stride], ref_stride, | 212 | 1.08M | nPbWC,nPbHC, 0,0, nullptr, bit_depth_C); | 213 | 1.08M | } | 214 | 18.2k | else | 215 | 18.2k | { | 216 | 109k | for (int y=0;y<nPbHC;y++) | 217 | 714k | for (int x=0;x<nPbWC;x++) { | 218 | | | 219 | 623k | int xB = Clip3(0,wC-1,x + xIntOffsC); | 220 | 623k | int yB = Clip3(0,hC-1,y + yIntOffsC); | 221 | | | 222 | 623k | out[y*out_stride+x] = ref[ xB + yB*ref_stride ] << shift3; | 223 | 623k | } | 224 | 18.2k | } | 225 | 1.10M | } | 226 | 1.14M | else { | 227 | 1.14M | pixel_t padbuf[(MAX_CU_SIZE+16)*(MAX_CU_SIZE+3)]; | 228 | | | 229 | 1.14M | const pixel_t* src_ptr; | 230 | 1.14M | ptrdiff_t src_stride; | 231 | | | 232 | 1.14M | int extra_top = 1; | 233 | 1.14M | int extra_left = 1; | 234 | 1.14M | int extra_right = 2; | 235 | 1.14M | int extra_bottom = 2; | 236 | | | 237 | 1.14M | if (xIntOffsC>=1 && nPbWC+xIntOffsC<=wC-2 && | 238 | 1.06M | yIntOffsC>=1 && nPbHC+yIntOffsC<=hC-2) { | 239 | 727k | src_ptr = &ref[xIntOffsC + yIntOffsC*ref_stride]; | 240 | 727k | src_stride = ref_stride; | 241 | 727k | } | 242 | 417k | else { | 243 | | // Extend fill width to a multiple of 16 so that SIMD over-reads | 244 | | // in epel interpolation hit valid (edge-clamped) data. | 245 | 417k | int fill_width = ((extra_left + nPbWC + extra_right + 15) & ~15); | 246 | 417k | if (fill_width > MAX_CU_SIZE+16) fill_width = MAX_CU_SIZE+16; | 247 | | | 248 | 4.21M | for (int y=-extra_top;y<nPbHC+extra_bottom;y++) { | 249 | 83.3M | for (int x=-extra_left;x<fill_width - extra_left;x++) { | 250 | | | 251 | 79.5M | int xA = Clip3(0,wC-1,x + xIntOffsC); | 252 | 79.5M | int yA = Clip3(0,hC-1,y + yIntOffsC); | 253 | | | 254 | 79.5M | padbuf[x+extra_left + (y+extra_top)*(MAX_CU_SIZE+16)] = ref[ xA + yA*ref_stride ]; | 255 | 79.5M | } | 256 | 3.80M | } | 257 | | | 258 | 417k | src_ptr = &padbuf[extra_left + extra_top*(MAX_CU_SIZE+16)]; | 259 | 417k | src_stride = MAX_CU_SIZE+16; | 260 | 417k | } | 261 | | | 262 | | | 263 | 1.14M | if (xFracC && yFracC) { | 264 | 743k | ctx->acceleration.put_hevc_epel_hv(out, out_stride, | 265 | 743k | src_ptr, src_stride, | 266 | 743k | nPbWC,nPbHC, xFracC,yFracC, mcbuffer, bit_depth_C); | 267 | 743k | } | 268 | 401k | else if (xFracC) { | 269 | 181k | ctx->acceleration.put_hevc_epel_h(out, out_stride, | 270 | 181k | src_ptr, src_stride, | 271 | 181k | nPbWC,nPbHC, xFracC,yFracC, mcbuffer, bit_depth_C); | 272 | 181k | } | 273 | 219k | else if (yFracC) { | 274 | 219k | ctx->acceleration.put_hevc_epel_v(out, out_stride, | 275 | 219k | src_ptr, src_stride, | 276 | 219k | nPbWC,nPbHC, xFracC,yFracC, mcbuffer, bit_depth_C); | 277 | 219k | } | 278 | 0 | else { | 279 | | assert(false); // full-pel shifts are handled above | 280 | 0 | } | 281 | 1.14M | } | 282 | 2.25M | } |
void mc_chroma<unsigned short, int>(base_context const*, seq_parameter_set const*, int, int, int, int, int*, int, unsigned short const*, long, int, int, int) Line | Count | Source | 188 | 42.5k | { | 189 | | //const int shift1 = std::min(4, sps->BitDepth_C-8); | 190 | | //const int shift2 = 6; | 191 | 42.5k | const int shift3 = std::max(2, 14 - sps->BitDepth_C); | 192 | | | 193 | 42.5k | int wC = sps->pic_width_in_luma_samples /sps->SubWidthC; | 194 | 42.5k | int hC = sps->pic_height_in_luma_samples/sps->SubHeightC; | 195 | | | 196 | 42.5k | mv_x *= 2 / sps->SubWidthC; | 197 | 42.5k | mv_y *= 2 / sps->SubHeightC; | 198 | | | 199 | 42.5k | int xFracC = mv_x & 7; | 200 | 42.5k | int yFracC = mv_y & 7; | 201 | | | 202 | 42.5k | int xIntOffsC = xP/sps->SubWidthC + (mv_x>>3); | 203 | 42.5k | int yIntOffsC = yP/sps->SubHeightC + (mv_y>>3); | 204 | | | 205 | 42.5k | ALIGNED_32(inter_t mcbuffer[MAX_CU_SIZE*(MAX_CU_SIZE+7)]); | 206 | | | 207 | 42.5k | if (xFracC == 0 && yFracC == 0) { | 208 | 19.4k | if (xIntOffsC>=0 && nPbWC+xIntOffsC<=wC && | 209 | 19.0k | yIntOffsC>=0 && nPbHC+yIntOffsC<=hC) { | 210 | 18.5k | ctx->acceleration.put_hevc_epel(out, out_stride, | 211 | 18.5k | &ref[xIntOffsC + yIntOffsC*ref_stride], ref_stride, | 212 | 18.5k | nPbWC,nPbHC, 0,0, nullptr, bit_depth_C); | 213 | 18.5k | } | 214 | 990 | else | 215 | 990 | { | 216 | 6.13k | for (int y=0;y<nPbHC;y++) | 217 | 37.8k | for (int x=0;x<nPbWC;x++) { | 218 | | | 219 | 32.7k | int xB = Clip3(0,wC-1,x + xIntOffsC); | 220 | 32.7k | int yB = Clip3(0,hC-1,y + yIntOffsC); | 221 | | | 222 | 32.7k | out[y*out_stride+x] = ref[ xB + yB*ref_stride ] << shift3; | 223 | 32.7k | } | 224 | 990 | } | 225 | 19.4k | } | 226 | 23.0k | else { | 227 | 23.0k | pixel_t padbuf[(MAX_CU_SIZE+16)*(MAX_CU_SIZE+3)]; | 228 | | | 229 | 23.0k | const pixel_t* src_ptr; | 230 | 23.0k | ptrdiff_t src_stride; | 231 | | | 232 | 23.0k | int extra_top = 1; | 233 | 23.0k | int extra_left = 1; | 234 | 23.0k | int extra_right = 2; | 235 | 23.0k | int extra_bottom = 2; | 236 | | | 237 | 23.0k | if (xIntOffsC>=1 && nPbWC+xIntOffsC<=wC-2 && | 238 | 16.4k | yIntOffsC>=1 && nPbHC+yIntOffsC<=hC-2) { | 239 | 11.6k | src_ptr = &ref[xIntOffsC + yIntOffsC*ref_stride]; | 240 | 11.6k | src_stride = ref_stride; | 241 | 11.6k | } | 242 | 11.3k | else { | 243 | | // Extend fill width to a multiple of 16 so that SIMD over-reads | 244 | | // in epel interpolation hit valid (edge-clamped) data. | 245 | 11.3k | int fill_width = ((extra_left + nPbWC + extra_right + 15) & ~15); | 246 | 11.3k | if (fill_width > MAX_CU_SIZE+16) fill_width = MAX_CU_SIZE+16; | 247 | | | 248 | 108k | for (int y=-extra_top;y<nPbHC+extra_bottom;y++) { | 249 | 1.86M | for (int x=-extra_left;x<fill_width - extra_left;x++) { | 250 | | | 251 | 1.76M | int xA = Clip3(0,wC-1,x + xIntOffsC); | 252 | 1.76M | int yA = Clip3(0,hC-1,y + yIntOffsC); | 253 | | | 254 | 1.76M | padbuf[x+extra_left + (y+extra_top)*(MAX_CU_SIZE+16)] = ref[ xA + yA*ref_stride ]; | 255 | 1.76M | } | 256 | 97.4k | } | 257 | | | 258 | 11.3k | src_ptr = &padbuf[extra_left + extra_top*(MAX_CU_SIZE+16)]; | 259 | 11.3k | src_stride = MAX_CU_SIZE+16; | 260 | 11.3k | } | 261 | | | 262 | | | 263 | 23.0k | if (xFracC && yFracC) { | 264 | 13.8k | ctx->acceleration.put_hevc_epel_hv(out, out_stride, | 265 | 13.8k | src_ptr, src_stride, | 266 | 13.8k | nPbWC,nPbHC, xFracC,yFracC, mcbuffer, bit_depth_C); | 267 | 13.8k | } | 268 | 9.23k | else if (xFracC) { | 269 | 3.77k | ctx->acceleration.put_hevc_epel_h(out, out_stride, | 270 | 3.77k | src_ptr, src_stride, | 271 | 3.77k | nPbWC,nPbHC, xFracC,yFracC, mcbuffer, bit_depth_C); | 272 | 3.77k | } | 273 | 5.45k | else if (yFracC) { | 274 | 5.45k | ctx->acceleration.put_hevc_epel_v(out, out_stride, | 275 | 5.45k | src_ptr, src_stride, | 276 | 5.45k | nPbWC,nPbHC, xFracC,yFracC, mcbuffer, bit_depth_C); | 277 | 5.45k | } | 278 | 0 | else { | 279 | | assert(false); // full-pel shifts are handled above | 280 | 0 | } | 281 | 23.0k | } | 282 | 42.5k | } |
Unexecuted instantiation: void mc_chroma<unsigned char, int>(base_context const*, seq_parameter_set const*, int, int, int, int, int*, int, unsigned char const*, long, int, int, int) |
283 | | |
284 | | |
285 | | |
286 | | // Fractional sample interpolation (8.5.3.3.3) and weighted sample prediction |
287 | | // (8.5.3.3.4) for one colour plane. |
288 | | // |
289 | | // inter_t is the type of the intermediate prediction samples predSamplesLX. |
290 | | // The spec keeps them at max(14, BitDepth+2) bits plus the overshoot of the |
291 | | // interpolation filters, which fits into int16_t only up to |
292 | | // MC_MAX_BIT_DEPTH_INT16. Above that, int32_t is used (see acceleration.h). |
293 | | // |
294 | | // refPic[l] is NULL when list l is not used or when its reference picture is |
295 | | // unusable. The caller has already reported the latter; the prediction is then |
296 | | // filled with mid-grey. |
297 | | // |
298 | | // Forced inline: called once per colour plane from a hot loop, and inlining lets |
299 | | // the compiler set up the prediction sample buffer once per PB instead of once |
300 | | // per plane. |
301 | | template <class inter_t> |
302 | | static LIBDE265_ALWAYS_INLINE void generate_inter_prediction_samples_plane(base_context* ctx, |
303 | | const slice_segment_header* shdr, |
304 | | de265_image* img, |
305 | | int cIdx, |
306 | | int xP,int yP, |
307 | | int nCS, int nPbW,int nPbH, |
308 | | const PBMotion* vi, |
309 | | const int predFlag[2], |
310 | | const de265_image* const refPic[2]) |
311 | 3.27M | { |
312 | 3.27M | const pic_parameter_set* pps = shdr->pps.get(); |
313 | 3.27M | const seq_parameter_set* sps = pps->sps.get(); |
314 | | |
315 | 3.27M | const int bit_depth = sps->get_bit_depth(cIdx); |
316 | | |
317 | 3.27M | const int SubWidthC = (cIdx==0 ? 1 : sps->SubWidthC); |
318 | 3.27M | const int SubHeightC = (cIdx==0 ? 1 : sps->SubHeightC); |
319 | 3.27M | const int w = nPbW / SubWidthC; |
320 | 3.27M | const int h = nPbH / SubHeightC; |
321 | | |
322 | 3.27M | void* pixels = img->get_image_plane_at_pos_any_depth(cIdx, xP/SubWidthC, yP/SubHeightC); |
323 | 3.27M | const ptrdiff_t stride = img->get_image_stride(cIdx); |
324 | | |
325 | | // TODO: must predSamples stride really be nCS or can it be something smaller like nPbW? |
326 | 3.27M | ALIGNED_16(inter_t) predSamples[2 /* LX */][MAX_CU_SIZE* MAX_CU_SIZE]; |
327 | | |
328 | | |
329 | | // --- fractional sample interpolation (8.5.3.3.3) --- |
330 | | |
331 | 9.82M | for (int l=0;l<2;l++) { |
332 | 6.54M | if (!predFlag[l]) continue; |
333 | | |
334 | 3.95M | if (!refPic[l]) { |
335 | | // Fill with mid-grey in intermediate precision: (1 << (bit_depth-1)) << shift3. |
336 | 0 | const inter_t fill = inter_t(1) << (bit_depth-1 + std::max(2, 14-bit_depth)); |
337 | |
|
338 | 0 | for (int y=0;y<h;y++) |
339 | 0 | for (int x=0;x<w;x++) |
340 | 0 | predSamples[l][y*nCS+x] = fill; |
341 | |
|
342 | 0 | continue; |
343 | 0 | } |
344 | | |
345 | 3.95M | if (cIdx==0) { |
346 | 1.31M | if (img->high_bit_depth(0)) { |
347 | 532k | mc_luma(ctx, sps, vi->mv[l].x, vi->mv[l].y, xP,yP, |
348 | 532k | predSamples[l],nCS, |
349 | 532k | (const uint16_t*)refPic[l]->get_image_plane(0), |
350 | 532k | refPic[l]->get_luma_stride(), nPbW,nPbH, bit_depth); |
351 | 532k | } |
352 | 785k | else { |
353 | 785k | mc_luma(ctx, sps, vi->mv[l].x, vi->mv[l].y, xP,yP, |
354 | 785k | predSamples[l],nCS, |
355 | 785k | (const uint8_t*)refPic[l]->get_image_plane(0), |
356 | 785k | refPic[l]->get_luma_stride(), nPbW,nPbH, bit_depth); |
357 | 785k | } |
358 | 1.31M | } |
359 | 2.63M | else { |
360 | 2.63M | if (img->high_bit_depth(cIdx)) { |
361 | 382k | mc_chroma(ctx, sps, vi->mv[l].x, vi->mv[l].y, xP,yP, |
362 | 382k | predSamples[l],nCS, |
363 | 382k | (const uint16_t*)refPic[l]->get_image_plane(cIdx), |
364 | 382k | refPic[l]->get_chroma_stride(), w,h, bit_depth); |
365 | 382k | } |
366 | 2.25M | else { |
367 | 2.25M | mc_chroma(ctx, sps, vi->mv[l].x, vi->mv[l].y, xP,yP, |
368 | 2.25M | predSamples[l],nCS, |
369 | 2.25M | (const uint8_t*)refPic[l]->get_image_plane(cIdx), |
370 | 2.25M | refPic[l]->get_chroma_stride(), w,h, bit_depth); |
371 | 2.25M | } |
372 | 2.63M | } |
373 | 3.95M | } |
374 | | |
375 | | |
376 | | // --- weighted sample prediction (8.5.3.3.4) --- |
377 | | |
378 | 3.27M | const bool weightedPredFlag = (shdr->slice_type == SLICE_TYPE_P ? |
379 | 2.00M | pps->weighted_pred_flag : pps->weighted_bipred_flag); |
380 | | |
381 | | // explicit weighted prediction parameters (8.5.3.3.4.3) |
382 | | |
383 | 3.27M | const int shift1 = std::max(2, 14-bit_depth); |
384 | 3.27M | const int log2WD = (cIdx==0 ? shdr->luma_log2_weight_denom : shdr->ChromaLog2WeightDenom) + shift1; |
385 | 3.27M | const int offsetShift = (cIdx==0 ? sps->WpOffsetBdShiftY : sps->WpOffsetBdShiftC); |
386 | | |
387 | 3.27M | auto weight = [&](int l) -> int { |
388 | 2.38M | const int refIdx = vi->refIdx[l]; |
389 | 2.38M | return (cIdx==0 ? shdr->LumaWeight[l][refIdx] : shdr->ChromaWeight[l][refIdx][cIdx-1]); |
390 | 2.38M | }; motion.cc:generate_inter_prediction_samples_plane<short>(base_context*, slice_segment_header const*, de265_image*, int, int, int, int, int, int, PBMotion const*, int const*, de265_image const* const*)::{lambda(int)#1}::operator()(int) constLine | Count | Source | 387 | 2.19M | auto weight = [&](int l) -> int { | 388 | 2.19M | const int refIdx = vi->refIdx[l]; | 389 | 2.19M | return (cIdx==0 ? shdr->LumaWeight[l][refIdx] : shdr->ChromaWeight[l][refIdx][cIdx-1]); | 390 | 2.19M | }; |
motion.cc:generate_inter_prediction_samples_plane<int>(base_context*, slice_segment_header const*, de265_image*, int, int, int, int, int, int, PBMotion const*, int const*, de265_image const* const*)::{lambda(int)#1}::operator()(int) constLine | Count | Source | 387 | 182k | auto weight = [&](int l) -> int { | 388 | 182k | const int refIdx = vi->refIdx[l]; | 389 | 182k | return (cIdx==0 ? shdr->LumaWeight[l][refIdx] : shdr->ChromaWeight[l][refIdx][cIdx-1]); | 390 | 182k | }; |
|
391 | | |
392 | 3.27M | auto offset = [&](int l) -> int { |
393 | 2.38M | const int refIdx = vi->refIdx[l]; |
394 | 2.38M | const int o = (cIdx==0 ? shdr->luma_offset[l][refIdx] : shdr->ChromaOffset[l][refIdx][cIdx-1]); |
395 | 2.38M | return o * (1<<offsetShift); |
396 | 2.38M | }; motion.cc:generate_inter_prediction_samples_plane<short>(base_context*, slice_segment_header const*, de265_image*, int, int, int, int, int, int, PBMotion const*, int const*, de265_image const* const*)::{lambda(int)#2}::operator()(int) constLine | Count | Source | 392 | 2.19M | auto offset = [&](int l) -> int { | 393 | 2.19M | const int refIdx = vi->refIdx[l]; | 394 | 2.19M | const int o = (cIdx==0 ? shdr->luma_offset[l][refIdx] : shdr->ChromaOffset[l][refIdx][cIdx-1]); | 395 | 2.19M | return o * (1<<offsetShift); | 396 | 2.19M | }; |
motion.cc:generate_inter_prediction_samples_plane<int>(base_context*, slice_segment_header const*, de265_image*, int, int, int, int, int, int, PBMotion const*, int const*, de265_image const* const*)::{lambda(int)#2}::operator()(int) constLine | Count | Source | 392 | 182k | auto offset = [&](int l) -> int { | 393 | 182k | const int refIdx = vi->refIdx[l]; | 394 | 182k | const int o = (cIdx==0 ? shdr->luma_offset[l][refIdx] : shdr->ChromaOffset[l][refIdx][cIdx-1]); | 395 | 182k | return o * (1<<offsetShift); | 396 | 182k | }; |
|
397 | | |
398 | | |
399 | 3.27M | if (predFlag[0] && predFlag[1]) { |
400 | 678k | if (!weightedPredFlag) { |
401 | 127k | ctx->acceleration.put_weighted_pred_avg(pixels, stride, |
402 | 127k | predSamples[0], predSamples[1], nCS, |
403 | 127k | w,h, bit_depth); |
404 | 127k | } |
405 | 550k | else { |
406 | 550k | logtrace(LogMotion,"weighted-BI-0 [%d] %d %d %d %dx%d\n", vi->refIdx[0], log2WD-6,weight(0),offset(0),w,h); |
407 | 550k | logtrace(LogMotion,"weighted-BI-1 [%d] %d %d %d %dx%d\n", vi->refIdx[1], log2WD-6,weight(1),offset(1),w,h); |
408 | | |
409 | 550k | ctx->acceleration.put_weighted_bipred(pixels, stride, |
410 | 550k | predSamples[0], predSamples[1], nCS, |
411 | 550k | w,h, |
412 | 550k | weight(0),offset(0), |
413 | 550k | weight(1),offset(1), |
414 | 550k | log2WD, bit_depth); |
415 | 550k | } |
416 | 678k | } |
417 | 2.59M | else { |
418 | 2.59M | const int l = (predFlag[0] ? 0 : 1); // the caller ensures that one list is used |
419 | | |
420 | 2.59M | if (!weightedPredFlag) { |
421 | 1.31M | ctx->acceleration.put_unweighted_pred(pixels, stride, |
422 | 1.31M | predSamples[l], nCS, |
423 | 1.31M | w,h, bit_depth); |
424 | 1.31M | } |
425 | 1.28M | else { |
426 | 1.28M | logtrace(LogMotion,"weighted-L%d [%d] %d %d %d %dx%d\n", l, vi->refIdx[l], log2WD-6,weight(l),offset(l),w,h); |
427 | | |
428 | 1.28M | ctx->acceleration.put_weighted_pred(pixels, stride, |
429 | 1.28M | predSamples[l], nCS, |
430 | 1.28M | w,h, |
431 | 1.28M | weight(l),offset(l), |
432 | 1.28M | log2WD, bit_depth); |
433 | 1.28M | } |
434 | 2.59M | } |
435 | 3.27M | } motion.cc:void generate_inter_prediction_samples_plane<short>(base_context*, slice_segment_header const*, de265_image*, int, int, int, int, int, int, PBMotion const*, int const*, de265_image const* const*) Line | Count | Source | 311 | 2.89M | { | 312 | 2.89M | const pic_parameter_set* pps = shdr->pps.get(); | 313 | 2.89M | const seq_parameter_set* sps = pps->sps.get(); | 314 | | | 315 | 2.89M | const int bit_depth = sps->get_bit_depth(cIdx); | 316 | | | 317 | 2.89M | const int SubWidthC = (cIdx==0 ? 1 : sps->SubWidthC); | 318 | 2.89M | const int SubHeightC = (cIdx==0 ? 1 : sps->SubHeightC); | 319 | 2.89M | const int w = nPbW / SubWidthC; | 320 | 2.89M | const int h = nPbH / SubHeightC; | 321 | | | 322 | 2.89M | void* pixels = img->get_image_plane_at_pos_any_depth(cIdx, xP/SubWidthC, yP/SubHeightC); | 323 | 2.89M | const ptrdiff_t stride = img->get_image_stride(cIdx); | 324 | | | 325 | | // TODO: must predSamples stride really be nCS or can it be something smaller like nPbW? | 326 | 2.89M | ALIGNED_16(inter_t) predSamples[2 /* LX */][MAX_CU_SIZE* MAX_CU_SIZE]; | 327 | | | 328 | | | 329 | | // --- fractional sample interpolation (8.5.3.3.3) --- | 330 | | | 331 | 8.67M | for (int l=0;l<2;l++) { | 332 | 5.78M | if (!predFlag[l]) continue; | 333 | | | 334 | 3.53M | if (!refPic[l]) { | 335 | | // Fill with mid-grey in intermediate precision: (1 << (bit_depth-1)) << shift3. | 336 | 0 | const inter_t fill = inter_t(1) << (bit_depth-1 + std::max(2, 14-bit_depth)); | 337 | |
| 338 | 0 | for (int y=0;y<h;y++) | 339 | 0 | for (int x=0;x<w;x++) | 340 | 0 | predSamples[l][y*nCS+x] = fill; | 341 | |
| 342 | 0 | continue; | 343 | 0 | } | 344 | | | 345 | 3.53M | if (cIdx==0) { | 346 | 947k | if (img->high_bit_depth(0)) { | 347 | 161k | mc_luma(ctx, sps, vi->mv[l].x, vi->mv[l].y, xP,yP, | 348 | 161k | predSamples[l],nCS, | 349 | 161k | (const uint16_t*)refPic[l]->get_image_plane(0), | 350 | 161k | refPic[l]->get_luma_stride(), nPbW,nPbH, bit_depth); | 351 | 161k | } | 352 | 785k | else { | 353 | 785k | mc_luma(ctx, sps, vi->mv[l].x, vi->mv[l].y, xP,yP, | 354 | 785k | predSamples[l],nCS, | 355 | 785k | (const uint8_t*)refPic[l]->get_image_plane(0), | 356 | 785k | refPic[l]->get_luma_stride(), nPbW,nPbH, bit_depth); | 357 | 785k | } | 358 | 947k | } | 359 | 2.59M | else { | 360 | 2.59M | if (img->high_bit_depth(cIdx)) { | 361 | 339k | mc_chroma(ctx, sps, vi->mv[l].x, vi->mv[l].y, xP,yP, | 362 | 339k | predSamples[l],nCS, | 363 | 339k | (const uint16_t*)refPic[l]->get_image_plane(cIdx), | 364 | 339k | refPic[l]->get_chroma_stride(), w,h, bit_depth); | 365 | 339k | } | 366 | 2.25M | else { | 367 | 2.25M | mc_chroma(ctx, sps, vi->mv[l].x, vi->mv[l].y, xP,yP, | 368 | 2.25M | predSamples[l],nCS, | 369 | 2.25M | (const uint8_t*)refPic[l]->get_image_plane(cIdx), | 370 | 2.25M | refPic[l]->get_chroma_stride(), w,h, bit_depth); | 371 | 2.25M | } | 372 | 2.59M | } | 373 | 3.53M | } | 374 | | | 375 | | | 376 | | // --- weighted sample prediction (8.5.3.3.4) --- | 377 | | | 378 | 2.89M | const bool weightedPredFlag = (shdr->slice_type == SLICE_TYPE_P ? | 379 | 1.93M | pps->weighted_pred_flag : pps->weighted_bipred_flag); | 380 | | | 381 | | // explicit weighted prediction parameters (8.5.3.3.4.3) | 382 | | | 383 | 2.89M | const int shift1 = std::max(2, 14-bit_depth); | 384 | 2.89M | const int log2WD = (cIdx==0 ? shdr->luma_log2_weight_denom : shdr->ChromaLog2WeightDenom) + shift1; | 385 | 2.89M | const int offsetShift = (cIdx==0 ? sps->WpOffsetBdShiftY : sps->WpOffsetBdShiftC); | 386 | | | 387 | 2.89M | auto weight = [&](int l) -> int { | 388 | 2.89M | const int refIdx = vi->refIdx[l]; | 389 | 2.89M | return (cIdx==0 ? shdr->LumaWeight[l][refIdx] : shdr->ChromaWeight[l][refIdx][cIdx-1]); | 390 | 2.89M | }; | 391 | | | 392 | 2.89M | auto offset = [&](int l) -> int { | 393 | 2.89M | const int refIdx = vi->refIdx[l]; | 394 | 2.89M | const int o = (cIdx==0 ? shdr->luma_offset[l][refIdx] : shdr->ChromaOffset[l][refIdx][cIdx-1]); | 395 | 2.89M | return o * (1<<offsetShift); | 396 | 2.89M | }; | 397 | | | 398 | | | 399 | 2.89M | if (predFlag[0] && predFlag[1]) { | 400 | 647k | if (!weightedPredFlag) { | 401 | 125k | ctx->acceleration.put_weighted_pred_avg(pixels, stride, | 402 | 125k | predSamples[0], predSamples[1], nCS, | 403 | 125k | w,h, bit_depth); | 404 | 125k | } | 405 | 522k | else { | 406 | 522k | logtrace(LogMotion,"weighted-BI-0 [%d] %d %d %d %dx%d\n", vi->refIdx[0], log2WD-6,weight(0),offset(0),w,h); | 407 | 522k | logtrace(LogMotion,"weighted-BI-1 [%d] %d %d %d %dx%d\n", vi->refIdx[1], log2WD-6,weight(1),offset(1),w,h); | 408 | | | 409 | 522k | ctx->acceleration.put_weighted_bipred(pixels, stride, | 410 | 522k | predSamples[0], predSamples[1], nCS, | 411 | 522k | w,h, | 412 | 522k | weight(0),offset(0), | 413 | 522k | weight(1),offset(1), | 414 | 522k | log2WD, bit_depth); | 415 | 522k | } | 416 | 647k | } | 417 | 2.24M | else { | 418 | 2.24M | const int l = (predFlag[0] ? 0 : 1); // the caller ensures that one list is used | 419 | | | 420 | 2.24M | if (!weightedPredFlag) { | 421 | 1.08M | ctx->acceleration.put_unweighted_pred(pixels, stride, | 422 | 1.08M | predSamples[l], nCS, | 423 | 1.08M | w,h, bit_depth); | 424 | 1.08M | } | 425 | 1.15M | else { | 426 | 1.15M | logtrace(LogMotion,"weighted-L%d [%d] %d %d %d %dx%d\n", l, vi->refIdx[l], log2WD-6,weight(l),offset(l),w,h); | 427 | | | 428 | 1.15M | ctx->acceleration.put_weighted_pred(pixels, stride, | 429 | 1.15M | predSamples[l], nCS, | 430 | 1.15M | w,h, | 431 | 1.15M | weight(l),offset(l), | 432 | 1.15M | log2WD, bit_depth); | 433 | 1.15M | } | 434 | 2.24M | } | 435 | 2.89M | } |
motion.cc:void generate_inter_prediction_samples_plane<int>(base_context*, slice_segment_header const*, de265_image*, int, int, int, int, int, int, PBMotion const*, int const*, de265_image const* const*) Line | Count | Source | 311 | 382k | { | 312 | 382k | const pic_parameter_set* pps = shdr->pps.get(); | 313 | 382k | const seq_parameter_set* sps = pps->sps.get(); | 314 | | | 315 | 382k | const int bit_depth = sps->get_bit_depth(cIdx); | 316 | | | 317 | 382k | const int SubWidthC = (cIdx==0 ? 1 : sps->SubWidthC); | 318 | 382k | const int SubHeightC = (cIdx==0 ? 1 : sps->SubHeightC); | 319 | 382k | const int w = nPbW / SubWidthC; | 320 | 382k | const int h = nPbH / SubHeightC; | 321 | | | 322 | 382k | void* pixels = img->get_image_plane_at_pos_any_depth(cIdx, xP/SubWidthC, yP/SubHeightC); | 323 | 382k | const ptrdiff_t stride = img->get_image_stride(cIdx); | 324 | | | 325 | | // TODO: must predSamples stride really be nCS or can it be something smaller like nPbW? | 326 | 382k | ALIGNED_16(inter_t) predSamples[2 /* LX */][MAX_CU_SIZE* MAX_CU_SIZE]; | 327 | | | 328 | | | 329 | | // --- fractional sample interpolation (8.5.3.3.3) --- | 330 | | | 331 | 1.14M | for (int l=0;l<2;l++) { | 332 | 764k | if (!predFlag[l]) continue; | 333 | | | 334 | 413k | if (!refPic[l]) { | 335 | | // Fill with mid-grey in intermediate precision: (1 << (bit_depth-1)) << shift3. | 336 | 0 | const inter_t fill = inter_t(1) << (bit_depth-1 + std::max(2, 14-bit_depth)); | 337 | |
| 338 | 0 | for (int y=0;y<h;y++) | 339 | 0 | for (int x=0;x<w;x++) | 340 | 0 | predSamples[l][y*nCS+x] = fill; | 341 | |
| 342 | 0 | continue; | 343 | 0 | } | 344 | | | 345 | 413k | if (cIdx==0) { | 346 | 370k | if (img->high_bit_depth(0)) { | 347 | 370k | mc_luma(ctx, sps, vi->mv[l].x, vi->mv[l].y, xP,yP, | 348 | 370k | predSamples[l],nCS, | 349 | 370k | (const uint16_t*)refPic[l]->get_image_plane(0), | 350 | 370k | refPic[l]->get_luma_stride(), nPbW,nPbH, bit_depth); | 351 | 370k | } | 352 | 0 | else { | 353 | 0 | mc_luma(ctx, sps, vi->mv[l].x, vi->mv[l].y, xP,yP, | 354 | 0 | predSamples[l],nCS, | 355 | 0 | (const uint8_t*)refPic[l]->get_image_plane(0), | 356 | 0 | refPic[l]->get_luma_stride(), nPbW,nPbH, bit_depth); | 357 | 0 | } | 358 | 370k | } | 359 | 42.5k | else { | 360 | 42.5k | if (img->high_bit_depth(cIdx)) { | 361 | 42.5k | mc_chroma(ctx, sps, vi->mv[l].x, vi->mv[l].y, xP,yP, | 362 | 42.5k | predSamples[l],nCS, | 363 | 42.5k | (const uint16_t*)refPic[l]->get_image_plane(cIdx), | 364 | 42.5k | refPic[l]->get_chroma_stride(), w,h, bit_depth); | 365 | 42.5k | } | 366 | 0 | else { | 367 | 0 | mc_chroma(ctx, sps, vi->mv[l].x, vi->mv[l].y, xP,yP, | 368 | 0 | predSamples[l],nCS, | 369 | 0 | (const uint8_t*)refPic[l]->get_image_plane(cIdx), | 370 | 0 | refPic[l]->get_chroma_stride(), w,h, bit_depth); | 371 | 0 | } | 372 | 42.5k | } | 373 | 413k | } | 374 | | | 375 | | | 376 | | // --- weighted sample prediction (8.5.3.3.4) --- | 377 | | | 378 | 382k | const bool weightedPredFlag = (shdr->slice_type == SLICE_TYPE_P ? | 379 | 314k | pps->weighted_pred_flag : pps->weighted_bipred_flag); | 380 | | | 381 | | // explicit weighted prediction parameters (8.5.3.3.4.3) | 382 | | | 383 | 382k | const int shift1 = std::max(2, 14-bit_depth); | 384 | 382k | const int log2WD = (cIdx==0 ? shdr->luma_log2_weight_denom : shdr->ChromaLog2WeightDenom) + shift1; | 385 | 382k | const int offsetShift = (cIdx==0 ? sps->WpOffsetBdShiftY : sps->WpOffsetBdShiftC); | 386 | | | 387 | 382k | auto weight = [&](int l) -> int { | 388 | 382k | const int refIdx = vi->refIdx[l]; | 389 | 382k | return (cIdx==0 ? shdr->LumaWeight[l][refIdx] : shdr->ChromaWeight[l][refIdx][cIdx-1]); | 390 | 382k | }; | 391 | | | 392 | 382k | auto offset = [&](int l) -> int { | 393 | 382k | const int refIdx = vi->refIdx[l]; | 394 | 382k | const int o = (cIdx==0 ? shdr->luma_offset[l][refIdx] : shdr->ChromaOffset[l][refIdx][cIdx-1]); | 395 | 382k | return o * (1<<offsetShift); | 396 | 382k | }; | 397 | | | 398 | | | 399 | 382k | if (predFlag[0] && predFlag[1]) { | 400 | 30.8k | if (!weightedPredFlag) { | 401 | 2.52k | ctx->acceleration.put_weighted_pred_avg(pixels, stride, | 402 | 2.52k | predSamples[0], predSamples[1], nCS, | 403 | 2.52k | w,h, bit_depth); | 404 | 2.52k | } | 405 | 28.3k | else { | 406 | 28.3k | logtrace(LogMotion,"weighted-BI-0 [%d] %d %d %d %dx%d\n", vi->refIdx[0], log2WD-6,weight(0),offset(0),w,h); | 407 | 28.3k | logtrace(LogMotion,"weighted-BI-1 [%d] %d %d %d %dx%d\n", vi->refIdx[1], log2WD-6,weight(1),offset(1),w,h); | 408 | | | 409 | 28.3k | ctx->acceleration.put_weighted_bipred(pixels, stride, | 410 | 28.3k | predSamples[0], predSamples[1], nCS, | 411 | 28.3k | w,h, | 412 | 28.3k | weight(0),offset(0), | 413 | 28.3k | weight(1),offset(1), | 414 | 28.3k | log2WD, bit_depth); | 415 | 28.3k | } | 416 | 30.8k | } | 417 | 351k | else { | 418 | 351k | const int l = (predFlag[0] ? 0 : 1); // the caller ensures that one list is used | 419 | | | 420 | 351k | if (!weightedPredFlag) { | 421 | 225k | ctx->acceleration.put_unweighted_pred(pixels, stride, | 422 | 225k | predSamples[l], nCS, | 423 | 225k | w,h, bit_depth); | 424 | 225k | } | 425 | 126k | else { | 426 | 126k | logtrace(LogMotion,"weighted-L%d [%d] %d %d %d %dx%d\n", l, vi->refIdx[l], log2WD-6,weight(l),offset(l),w,h); | 427 | | | 428 | 126k | ctx->acceleration.put_weighted_pred(pixels, stride, | 429 | 126k | predSamples[l], nCS, | 430 | 126k | w,h, | 431 | 126k | weight(l),offset(l), | 432 | 126k | log2WD, bit_depth); | 433 | 126k | } | 434 | 351k | } | 435 | 382k | } |
|
436 | | |
437 | | |
438 | | |
439 | | // Decoding process for inter prediction samples (8.5.3.3). |
440 | | // NOTE: for full-pel shifts, we can introduce a fast path, simply copying without shifts |
441 | | void generate_inter_prediction_samples(base_context* ctx, |
442 | | const slice_segment_header* shdr, |
443 | | de265_image* img, |
444 | | int xC,int yC, |
445 | | int xB,int yB, |
446 | | int nCS, int nPbW,int nPbH, |
447 | | const PBMotion* vi) |
448 | 1.09M | { |
449 | 1.09M | const int xP = xC+xB; |
450 | 1.09M | const int yP = yC+yB; |
451 | | |
452 | 1.09M | const pic_parameter_set* pps = shdr->pps.get(); |
453 | 1.09M | const seq_parameter_set* sps = pps->sps.get(); |
454 | | |
455 | 1.09M | if (sps->BitDepth_Y != img->get_bit_depth(0) || |
456 | 1.09M | sps->BitDepth_C != img->get_bit_depth(1)) { |
457 | 0 | img->integrity = INTEGRITY_DECODING_ERRORS; |
458 | 0 | ctx->add_warning(DE265_WARNING_BIT_DEPTH_OF_CURRENT_IMAGE_DOES_NOT_MATCH_SPS, false); |
459 | 0 | return; |
460 | 0 | } |
461 | | |
462 | 1.09M | if (sps->chroma_format_idc != img->get_chroma_format()) { |
463 | 0 | img->integrity = INTEGRITY_DECODING_ERRORS; |
464 | 0 | ctx->add_warning(DE265_WARNING_CHROMA_OF_CURRENT_IMAGE_DOES_NOT_MATCH_SPS, false); |
465 | 0 | return; |
466 | 0 | } |
467 | | |
468 | | |
469 | 1.09M | int predFlag[2]; |
470 | 1.09M | predFlag[0] = vi->predFlag[0]; |
471 | 1.09M | predFlag[1] = vi->predFlag[1]; |
472 | | |
473 | | // Some encoders use bi-prediction with two identical MVs onto the same picture. |
474 | | // Identify this case and use only one MV. This is not possible with explicit |
475 | | // weighted prediction, where the two lists may have different weights/offsets. |
476 | | |
477 | 1.09M | const bool weightedPredFlag = (shdr->slice_type == SLICE_TYPE_P ? |
478 | 667k | pps->weighted_pred_flag : pps->weighted_bipred_flag); |
479 | | |
480 | 1.09M | if (!weightedPredFlag) { |
481 | 480k | if (predFlag[0] && predFlag[1]) { |
482 | 69.5k | if (vi->mv[0].x == vi->mv[1].x && |
483 | 50.0k | vi->mv[0].y == vi->mv[1].y && |
484 | 46.4k | shdr->RefPicList[0][vi->refIdx[0]] == |
485 | 46.4k | shdr->RefPicList[1][vi->refIdx[1]]) { |
486 | 26.9k | predFlag[1] = 0; |
487 | 26.9k | } |
488 | 69.5k | } |
489 | 480k | } |
490 | | |
491 | 1.09M | logtrace(LogMotion,"predFlags (modified): %d %d\n", predFlag[0], predFlag[1]); |
492 | | |
493 | 1.09M | if (!predFlag[0] && !predFlag[1]) { |
494 | | // TODO: check why it can actually happen that both predFlags[] are false. |
495 | | // For now, we ignore this and continue decoding. |
496 | |
|
497 | 0 | ctx->add_warning(DE265_WARNING_BOTH_PREDFLAGS_ZERO, false); |
498 | 0 | img->integrity = INTEGRITY_DECODING_ERRORS; |
499 | 0 | return; |
500 | 0 | } |
501 | | |
502 | | |
503 | | // --- reference picture selection (8.5.3.3.2) --- |
504 | | |
505 | | // refPic[l] stays NULL when the reference picture cannot be used. |
506 | | |
507 | 1.09M | const de265_image* refPic[2] = { nullptr, nullptr }; |
508 | | |
509 | 3.27M | for (int l=0;l<2;l++) { |
510 | 2.18M | if (!predFlag[l]) continue; |
511 | | |
512 | 1.31M | const de265_image* ref = ctx->get_image(shdr->RefPicList[l][vi->refIdx[l]]); |
513 | | |
514 | 1.31M | logtrace(LogMotion, "refIdx: %d -> dpb[%d]\n", vi->refIdx[l], shdr->RefPicList[l][vi->refIdx[l]]); |
515 | | |
516 | 1.31M | if (!ref || ref->PicState == UnusedForReference) { |
517 | 0 | img->integrity = INTEGRITY_DECODING_ERRORS; |
518 | 0 | ctx->add_warning(DE265_WARNING_NONEXISTING_REFERENCE_PICTURE_ACCESSED, false); |
519 | 0 | } |
520 | 1.31M | else if (ref->get_width(0) != sps->pic_width_in_luma_samples || |
521 | 1.31M | ref->get_height(0) != sps->pic_height_in_luma_samples) { |
522 | 0 | img->integrity = INTEGRITY_DECODING_ERRORS; |
523 | 0 | ctx->add_warning(DE265_WARNING_REFERENCE_IMAGE_SIZE_DOES_NOT_MATCH_SPS, false); |
524 | 0 | } |
525 | 1.31M | else if (img->get_bit_depth(0) != ref->get_bit_depth(0) || |
526 | 1.31M | img->get_bit_depth(1) != ref->get_bit_depth(1)) { |
527 | 0 | img->integrity = INTEGRITY_DECODING_ERRORS; |
528 | 0 | ctx->add_warning(DE265_WARNING_REFERENCE_IMAGE_BIT_DEPTH_DOES_NOT_MATCH, false); |
529 | 0 | } |
530 | 1.31M | else if (img->get_chroma_format() != ref->get_chroma_format()) { |
531 | 0 | img->integrity = INTEGRITY_DECODING_ERRORS; |
532 | 0 | ctx->add_warning(DE265_WARNING_REFERENCE_IMAGE_CHROMA_FORMAT_DOES_NOT_MATCH, false); |
533 | 0 | } |
534 | 1.31M | else { |
535 | 1.31M | logtrace(LogMotion,"do MC: L%d,MV=%d;%d RefPOC=%d\n", |
536 | 1.31M | l,vi->mv[l].x,vi->mv[l].y,ref->PicOrderCntVal); |
537 | | |
538 | 1.31M | refPic[l] = ref; |
539 | 1.31M | } |
540 | 1.31M | } |
541 | | |
542 | | |
543 | | // --- prediction, per colour plane --- |
544 | | |
545 | | // Up to MC_MAX_BIT_DEPTH_INT16, the intermediate prediction samples fit |
546 | | // into int16_t. Above that, int32_t is needed. |
547 | | |
548 | 1.09M | const int nPlanes = (img->get_chroma_format() == de265_chroma_mono ? 1 : 3); |
549 | | |
550 | 4.36M | for (int cIdx=0;cIdx<nPlanes;cIdx++) { |
551 | 3.27M | if (sps->get_bit_depth(cIdx) <= MC_MAX_BIT_DEPTH_INT16) { |
552 | 2.89M | generate_inter_prediction_samples_plane<int16_t>(ctx,shdr,img, cIdx, xP,yP, nCS,nPbW,nPbH, vi, predFlag, refPic); |
553 | 2.89M | } |
554 | 382k | else { |
555 | 382k | generate_inter_prediction_samples_plane<int32_t>(ctx,shdr,img, cIdx, xP,yP, nCS,nPbW,nPbH, vi, predFlag, refPic); |
556 | 382k | } |
557 | 3.27M | } |
558 | 1.09M | } |
559 | | |
560 | | #ifdef DE265_LOG_TRACE |
561 | | void logmvcand(const PBMotion& p) |
562 | | { |
563 | | for (int v=0;v<2;v++) { |
564 | | if (p.predFlag[v]) { |
565 | | logtrace(LogMotion," %d: %s %d;%d ref=%d\n", v, p.predFlag[v] ? "yes":"no ", |
566 | | p.mv[v].x,p.mv[v].y, p.refIdx[v]); |
567 | | } else { |
568 | | logtrace(LogMotion," %d: %s --;-- ref=--\n", v, p.predFlag[v] ? "yes":"no "); |
569 | | } |
570 | | } |
571 | | } |
572 | | #else |
573 | | #define logmvcand(p) |
574 | | #endif |
575 | | |
576 | | |
577 | | bool PBMotion::operator==(const PBMotion& b) const |
578 | 277k | { |
579 | 277k | const PBMotion& a = *this; |
580 | | |
581 | | // TODO: is this really correct? no check for predFlag? Standard says so... (p.127) |
582 | | |
583 | 704k | for (int i=0;i<2;i++) { |
584 | 502k | if (a.predFlag[i] != b.predFlag[i]) return false; |
585 | | |
586 | 478k | if (a.predFlag[i]) { |
587 | 316k | if (a.mv[i].x != b.mv[i].x) return false; |
588 | 286k | if (a.mv[i].y != b.mv[i].y) return false; |
589 | 270k | if (a.refIdx[i] != b.refIdx[i]) return false; |
590 | 270k | } |
591 | 478k | } |
592 | | |
593 | 201k | return true; |
594 | 277k | } |
595 | | |
596 | | |
597 | | class MotionVectorAccess_de265_image : public MotionVectorAccess |
598 | | { |
599 | | public: |
600 | 802k | MotionVectorAccess_de265_image(const de265_image* i) : img(i) { } |
601 | | |
602 | 802k | enum PartMode get_PartMode(int x,int y) const override { return img->get_PartMode(x,y); } |
603 | 758k | const PBMotion& get_mv_info(int x,int y) const override { return img->get_mv_info(x,y); } |
604 | | |
605 | | private: |
606 | | const de265_image* img; |
607 | | }; |
608 | | |
609 | | |
610 | | |
611 | | /* |
612 | | +--+ +--+--+ |
613 | | |B2| |B1|B0| |
614 | | +--+----------------+--+--+ |
615 | | | | |
616 | | | | |
617 | | | | |
618 | | | | |
619 | | | PB | |
620 | | | | |
621 | | | | |
622 | | +--+ | |
623 | | |A1| | |
624 | | +--+-------------------+ |
625 | | |A0| |
626 | | +--+ |
627 | | */ |
628 | | |
629 | | |
630 | | // 8.5.3.1.2 |
631 | | // TODO: check: can we fill the candidate list directly in this function and omit to copy later |
632 | | /* |
633 | | xC/yC: CB position |
634 | | nCS: CB size (probably modified because of singleMCLFlag) |
635 | | xP/yP: PB position (absolute) (probably modified because of singleMCLFlag) |
636 | | singleMCLFlag |
637 | | nPbW/nPbH: PB size |
638 | | partIdx |
639 | | out_cand: merging candidate vectors |
640 | | |
641 | | Add these candidates: |
642 | | - A1 |
643 | | - B1 (if != A1) |
644 | | - B0 (if != B1) |
645 | | - A0 (if != A1) |
646 | | - B2 (if != A1 and != B1) |
647 | | |
648 | | A maximum of 4 candidates are generated. |
649 | | |
650 | | Note 1: For a CB split into two PBs, it does not make sense to merge the |
651 | | second part to the parameters of the first part, since then, we could use 2Nx2N |
652 | | right away. -> Exclude this candidate. |
653 | | */ |
654 | | int derive_spatial_merging_candidates(//const de265_image* img, |
655 | | const MotionVectorAccess& mvaccess, |
656 | | const de265_image* img, |
657 | | int xC, int yC, int nCS, int xP, int yP, |
658 | | uint8_t singleMCLFlag, |
659 | | int nPbW, int nPbH, |
660 | | int partIdx, |
661 | | PBMotion* out_cand, |
662 | | int maxCandidates) |
663 | 802k | { |
664 | 802k | const pic_parameter_set* pps = &img->get_pps(); |
665 | 802k | const int log2_parallel_merge_level = pps->log2_parallel_merge_level; |
666 | | |
667 | 802k | enum PartMode PartMode = mvaccess.get_PartMode(xC,yC); |
668 | | |
669 | | /* |
670 | | const int A0 = SpatialMergingCandidates::PRED_A0; |
671 | | const int A1 = SpatialMergingCandidates::PRED_A1; |
672 | | const int B0 = SpatialMergingCandidates::PRED_B0; |
673 | | const int B1 = SpatialMergingCandidates::PRED_B1; |
674 | | const int B2 = SpatialMergingCandidates::PRED_B2; |
675 | | */ |
676 | | |
677 | | // --- A1 --- |
678 | | |
679 | | // a pixel within A1 (bottom right of A1) |
680 | 802k | int xA1 = xP-1; |
681 | 802k | int yA1 = yP+nPbH-1; |
682 | | |
683 | 802k | bool availableA1; |
684 | 802k | int idxA1; |
685 | | |
686 | 802k | int computed_candidates = 0; |
687 | | |
688 | | // check if candidate is in same motion-estimation region (MER) -> discard |
689 | 802k | if ((xP>>log2_parallel_merge_level) == (xA1>>log2_parallel_merge_level) && |
690 | 15.1k | (yP>>log2_parallel_merge_level) == (yA1>>log2_parallel_merge_level)) { |
691 | 12.0k | availableA1 = false; |
692 | 12.0k | logtrace(LogMotion,"spatial merging candidate A1: below parallel merge level\n"); |
693 | 12.0k | } |
694 | | // redundant candidate? (Note 1) -> discard |
695 | 790k | else if (// !singleMCLFlag && automatically true when partIdx==1 |
696 | 790k | partIdx==1 && |
697 | 23.3k | (PartMode==PART_Nx2N || |
698 | 16.8k | PartMode==PART_nLx2N || |
699 | 13.0k | PartMode==PART_nRx2N)) { |
700 | 11.3k | availableA1 = false; |
701 | 11.3k | logtrace(LogMotion,"spatial merging candidate A1: second part ignore\n"); |
702 | 11.3k | } |
703 | | // MV available in A1 |
704 | 778k | else { |
705 | 778k | availableA1 = img->available_pred_blk(xC,yC, nCS, xP,yP, nPbW,nPbH,partIdx, xA1,yA1); |
706 | 778k | if (!availableA1) logtrace(LogMotion,"spatial merging candidate A1: unavailable\n"); |
707 | 778k | } |
708 | | |
709 | 802k | if (availableA1) { |
710 | 758k | idxA1 = computed_candidates++; |
711 | 758k | out_cand[idxA1] = mvaccess.get_mv_info(xA1,yA1); |
712 | | |
713 | 758k | logtrace(LogMotion,"spatial merging candidate A1:\n"); |
714 | 758k | logmvcand(out_cand[idxA1]); |
715 | 758k | } |
716 | | |
717 | 802k | if (computed_candidates>=maxCandidates) return computed_candidates; |
718 | | |
719 | | |
720 | | // --- B1 --- |
721 | | |
722 | 172k | int xB1 = xP+nPbW-1; |
723 | 172k | int yB1 = yP-1; |
724 | | |
725 | 172k | bool availableB1; |
726 | 172k | int idxB1; |
727 | | |
728 | | // same MER -> discard |
729 | 172k | if ((xP>>log2_parallel_merge_level) == (xB1>>log2_parallel_merge_level) && |
730 | 135k | (yP>>log2_parallel_merge_level) == (yB1>>log2_parallel_merge_level)) { |
731 | 9.15k | availableB1 = false; |
732 | 9.15k | logtrace(LogMotion,"spatial merging candidate B1: below parallel merge level\n"); |
733 | 9.15k | } |
734 | | // redundant candidate (Note 1) -> discard |
735 | 162k | else if (// !singleMCLFlag && automatically true when partIdx==1 |
736 | 162k | partIdx==1 && |
737 | 16.1k | (PartMode==PART_2NxN || |
738 | 12.9k | PartMode==PART_2NxnU || |
739 | 11.9k | PartMode==PART_2NxnD)) { |
740 | 4.52k | availableB1 = false; |
741 | 4.52k | logtrace(LogMotion,"spatial merging candidate B1: second part ignore\n"); |
742 | 4.52k | } |
743 | | // MV available in B1 |
744 | 158k | else { |
745 | 158k | availableB1 = img->available_pred_blk(xC,yC, nCS, xP,yP, nPbW,nPbH,partIdx, xB1,yB1); |
746 | 158k | if (!availableB1) logtrace(LogMotion,"spatial merging candidate B1: unavailable\n"); |
747 | 158k | } |
748 | | |
749 | 172k | if (availableB1) { |
750 | 133k | const PBMotion& b1 = img->get_mv_info(xB1,yB1); |
751 | | |
752 | | // B1 == A1 -> discard B1 |
753 | 133k | if (availableA1 && out_cand[idxA1] == b1) { |
754 | 73.5k | idxB1 = idxA1; |
755 | 73.5k | logtrace(LogMotion,"spatial merging candidate B1: redundant to A1\n"); |
756 | 73.5k | } |
757 | 60.1k | else { |
758 | 60.1k | idxB1 = computed_candidates++; |
759 | 60.1k | out_cand[idxB1] = b1; |
760 | | |
761 | 60.1k | logtrace(LogMotion,"spatial merging candidate B1:\n"); |
762 | 60.1k | logmvcand(out_cand[idxB1]); |
763 | 60.1k | } |
764 | 133k | } |
765 | | |
766 | 172k | if (computed_candidates>=maxCandidates) return computed_candidates; |
767 | | |
768 | | |
769 | | // --- B0 --- |
770 | | |
771 | 122k | int xB0 = xP+nPbW; |
772 | 122k | int yB0 = yP-1; |
773 | | |
774 | 122k | bool availableB0; |
775 | 122k | int idxB0; |
776 | | |
777 | 122k | if ((xP>>log2_parallel_merge_level) == (xB0>>log2_parallel_merge_level) && |
778 | 7.93k | (yP>>log2_parallel_merge_level) == (yB0>>log2_parallel_merge_level)) { |
779 | 5.56k | availableB0 = false; |
780 | 5.56k | logtrace(LogMotion,"spatial merging candidate B0: below parallel merge level\n"); |
781 | 5.56k | } |
782 | 117k | else { |
783 | 117k | availableB0 = img->available_pred_blk(xC,yC, nCS, xP,yP, nPbW,nPbH,partIdx, xB0,yB0); |
784 | 117k | if (!availableB0) logtrace(LogMotion,"spatial merging candidate B0: unavailable\n"); |
785 | 117k | } |
786 | | |
787 | 122k | if (availableB0) { |
788 | 60.5k | const PBMotion& b0 = img->get_mv_info(xB0,yB0); |
789 | | |
790 | | // B0 == B1 -> discard B0 |
791 | 60.5k | if (availableB1 && out_cand[idxB1]==b0) { |
792 | 45.3k | idxB0 = idxB1; |
793 | 45.3k | logtrace(LogMotion,"spatial merging candidate B0: redundant to B1\n"); |
794 | 45.3k | } |
795 | 15.1k | else { |
796 | 15.1k | idxB0 = computed_candidates++; |
797 | 15.1k | out_cand[idxB0] = b0; |
798 | 15.1k | logtrace(LogMotion,"spatial merging candidate B0:\n"); |
799 | 15.1k | logmvcand(out_cand[idxB0]); |
800 | 15.1k | } |
801 | 60.5k | } |
802 | | |
803 | 122k | if (computed_candidates>=maxCandidates) return computed_candidates; |
804 | | |
805 | | |
806 | | // --- A0 --- |
807 | | |
808 | 109k | int xA0 = xP-1; |
809 | 109k | int yA0 = yP+nPbH; |
810 | | |
811 | 109k | bool availableA0; |
812 | 109k | int idxA0; |
813 | | |
814 | 109k | if ((xP>>log2_parallel_merge_level) == (xA0>>log2_parallel_merge_level) && |
815 | 10.3k | (yP>>log2_parallel_merge_level) == (yA0>>log2_parallel_merge_level)) { |
816 | 5.62k | availableA0 = false; |
817 | 5.62k | logtrace(LogMotion,"spatial merging candidate A0: below parallel merge level\n"); |
818 | 5.62k | } |
819 | 103k | else { |
820 | 103k | availableA0 = img->available_pred_blk(xC,yC, nCS, xP,yP, nPbW,nPbH,partIdx, xA0,yA0); |
821 | 103k | if (!availableA0) logtrace(LogMotion,"spatial merging candidate A0: unavailable\n"); |
822 | 103k | } |
823 | | |
824 | 109k | if (availableA0) { |
825 | 26.2k | const PBMotion& a0 = img->get_mv_info(xA0,yA0); |
826 | | |
827 | | // A0 == A1 -> discard A0 |
828 | 26.2k | if (availableA1 && out_cand[idxA1]==a0) { |
829 | 20.4k | idxA0 = idxA1; |
830 | 20.4k | logtrace(LogMotion,"spatial merging candidate A0: redundant to A1\n"); |
831 | 20.4k | } |
832 | 5.83k | else { |
833 | 5.83k | idxA0 = computed_candidates++; |
834 | 5.83k | out_cand[idxA0] = a0; |
835 | 5.83k | logtrace(LogMotion,"spatial merging candidate A0:\n"); |
836 | 5.83k | logmvcand(out_cand[idxA0]); |
837 | 5.83k | } |
838 | 26.2k | } |
839 | | |
840 | 109k | if (computed_candidates>=maxCandidates) return computed_candidates; |
841 | | |
842 | | |
843 | | // --- B2 --- |
844 | | |
845 | 104k | int xB2 = xP-1; |
846 | 104k | int yB2 = yP-1; |
847 | | |
848 | 104k | bool availableB2; |
849 | 104k | int idxB2; |
850 | | |
851 | | // if we already have four candidates, do not consider B2 anymore |
852 | 104k | if (computed_candidates==4) { |
853 | 17 | availableB2 = false; |
854 | 17 | logtrace(LogMotion,"spatial merging candidate B2: ignore\n"); |
855 | 17 | } |
856 | 104k | else if ((xP>>log2_parallel_merge_level) == (xB2>>log2_parallel_merge_level) && |
857 | 10.3k | (yP>>log2_parallel_merge_level) == (yB2>>log2_parallel_merge_level)) { |
858 | 7.27k | availableB2 = false; |
859 | 7.27k | logtrace(LogMotion,"spatial merging candidate B2: below parallel merge level\n"); |
860 | 7.27k | } |
861 | 97.3k | else { |
862 | 97.3k | availableB2 = img->available_pred_blk(xC,yC, nCS, xP,yP, nPbW,nPbH,partIdx, xB2,yB2); |
863 | 97.3k | if (!availableB2) logtrace(LogMotion,"spatial merging candidate B2: unavailable\n"); |
864 | 97.3k | } |
865 | | |
866 | 104k | if (availableB2) { |
867 | 73.3k | const PBMotion& b2 = img->get_mv_info(xB2,yB2); |
868 | | |
869 | | // B2 == B1 -> discard B2 |
870 | 73.3k | if (availableB1 && out_cand[idxB1]==b2) { |
871 | 58.0k | idxB2 = idxB1; |
872 | 58.0k | logtrace(LogMotion,"spatial merging candidate B2: redundant to B1\n"); |
873 | 58.0k | } |
874 | | // B2 == A1 -> discard B2 |
875 | 15.3k | else if (availableA1 && out_cand[idxA1]==b2) { |
876 | 4.42k | idxB2 = idxA1; |
877 | 4.42k | logtrace(LogMotion,"spatial merging candidate B2: redundant to A1\n"); |
878 | 4.42k | } |
879 | 10.8k | else { |
880 | 10.8k | idxB2 = computed_candidates++; |
881 | 10.8k | out_cand[idxB2] = b2; |
882 | 10.8k | logtrace(LogMotion,"spatial merging candidate B2:\n"); |
883 | 10.8k | logmvcand(out_cand[idxB2]); |
884 | 10.8k | } |
885 | 73.3k | } |
886 | | |
887 | 104k | return computed_candidates; |
888 | 109k | } |
889 | | |
890 | | |
891 | | // 8.5.3.1.4 |
892 | | void derive_zero_motion_vector_candidates(const slice_segment_header* shdr, |
893 | | PBMotion* out_mergeCandList, |
894 | | int* inout_numCurrMergeCand, |
895 | | int maxCandidates) |
896 | 802k | { |
897 | 802k | logtrace(LogMotion,"derive_zero_motion_vector_candidates\n"); |
898 | | |
899 | 802k | int numRefIdx; |
900 | | |
901 | 802k | if (shdr->slice_type==SLICE_TYPE_P) { |
902 | 355k | numRefIdx = shdr->num_ref_idx_l0_active; |
903 | 355k | } |
904 | 446k | else { |
905 | 446k | numRefIdx = std::min(shdr->num_ref_idx_l0_active, |
906 | 446k | shdr->num_ref_idx_l1_active); |
907 | 446k | } |
908 | | |
909 | | |
910 | | //int numInputMergeCand = *inout_numMergeCand; |
911 | 802k | int zeroIdx = 0; |
912 | | |
913 | 908k | while (*inout_numCurrMergeCand < maxCandidates) { |
914 | | // 1. |
915 | | |
916 | 106k | logtrace(LogMotion,"zeroIdx:%d numRefIdx:%d\n", zeroIdx, numRefIdx); |
917 | | |
918 | 106k | PBMotion* newCand = &out_mergeCandList[*inout_numCurrMergeCand]; |
919 | | |
920 | 106k | const int refIdx = (zeroIdx < numRefIdx) ? zeroIdx : 0; |
921 | | |
922 | 106k | if (shdr->slice_type==SLICE_TYPE_P) { |
923 | 55.3k | newCand->refIdx[0] = refIdx; |
924 | 55.3k | newCand->refIdx[1] = 0; |
925 | 55.3k | newCand->predFlag[0] = 1; |
926 | 55.3k | newCand->predFlag[1] = 0; |
927 | 55.3k | } |
928 | 51.4k | else { |
929 | 51.4k | newCand->refIdx[0] = refIdx; |
930 | 51.4k | newCand->refIdx[1] = refIdx; |
931 | 51.4k | newCand->predFlag[0] = 1; |
932 | 51.4k | newCand->predFlag[1] = 1; |
933 | 51.4k | } |
934 | | |
935 | 106k | newCand->mv[0].x = 0; |
936 | 106k | newCand->mv[0].y = 0; |
937 | 106k | newCand->mv[1].x = 0; |
938 | 106k | newCand->mv[1].y = 0; |
939 | | |
940 | 106k | (*inout_numCurrMergeCand)++; |
941 | | |
942 | | // 2. |
943 | | |
944 | 106k | zeroIdx++; |
945 | 106k | } |
946 | 802k | } |
947 | | |
948 | | |
949 | | bool scale_mv(MotionVector* out_mv, MotionVector mv, int colDist, int currDist) |
950 | 5.07k | { |
951 | 5.07k | int td = Clip3(-128,127, colDist); |
952 | 5.07k | int tb = Clip3(-128,127, currDist); |
953 | | |
954 | 5.07k | if (td==0) { |
955 | 0 | *out_mv = mv; |
956 | 0 | return false; |
957 | 0 | } |
958 | 5.07k | else { |
959 | 5.07k | int tx = (16384 + (std::abs(td)>>1)) / td; |
960 | 5.07k | int distScaleFactor = Clip3(-4096,4095, (tb*tx+32)>>6); |
961 | 5.07k | out_mv->x = Clip3(-32768,32767, |
962 | 5.07k | Sign(distScaleFactor*mv.x)*((std::abs(distScaleFactor*mv.x)+127)>>8)); |
963 | 5.07k | out_mv->y = Clip3(-32768,32767, |
964 | 5.07k | Sign(distScaleFactor*mv.y)*((std::abs(distScaleFactor*mv.y)+127)>>8)); |
965 | 5.07k | return true; |
966 | 5.07k | } |
967 | 5.07k | } |
968 | | |
969 | | |
970 | | // (L1003) 8.5.3.2.8 |
971 | | |
972 | | void derive_collocated_motion_vectors(base_context* ctx, |
973 | | de265_image* img, |
974 | | const slice_segment_header* shdr, |
975 | | int xP,int yP, |
976 | | int colPic, |
977 | | int xColPb,int yColPb, |
978 | | int refIdxLX, // (always 0 for merge mode) |
979 | | int X, |
980 | | MotionVector* out_mvLXCol, |
981 | | uint8_t* out_availableFlagLXCol) |
982 | 96.1k | { |
983 | 96.1k | logtrace(LogMotion,"derive_collocated_motion_vectors %d;%d\n",xP,yP); |
984 | | |
985 | | |
986 | | // get collocated image and the prediction mode at the collocated position |
987 | | |
988 | 96.1k | assert(ctx->has_image(colPic)); |
989 | 96.1k | const de265_image* colImg = ctx->get_image(colPic); |
990 | | |
991 | | // check for access outside image area |
992 | | |
993 | 96.1k | if (xColPb >= colImg->get_width() || |
994 | 96.1k | yColPb >= colImg->get_height()) { |
995 | 0 | ctx->add_warning(DE265_WARNING_COLLOCATED_MOTION_VECTOR_OUTSIDE_IMAGE_AREA, false); |
996 | 0 | *out_availableFlagLXCol = 0; |
997 | 0 | return; |
998 | 0 | } |
999 | | |
1000 | 96.1k | enum PredMode predMode = colImg->get_pred_mode(xColPb,yColPb); |
1001 | | |
1002 | | |
1003 | | // collocated block is Intra -> no collocated MV |
1004 | | |
1005 | 96.1k | if (predMode == MODE_INTRA) { |
1006 | 77.2k | out_mvLXCol->x = 0; |
1007 | 77.2k | out_mvLXCol->y = 0; |
1008 | 77.2k | *out_availableFlagLXCol = 0; |
1009 | 77.2k | return; |
1010 | 77.2k | } |
1011 | | |
1012 | | |
1013 | 18.9k | logtrace(LogMotion,"colPic:%d (POC=%d) X:%d refIdxLX:%d refpiclist:%d\n", |
1014 | 18.9k | colPic, |
1015 | 18.9k | colImg->PicOrderCntVal, |
1016 | 18.9k | X,refIdxLX,shdr->RefPicList[X][refIdxLX]); |
1017 | | |
1018 | | |
1019 | | // collocated reference image is unavailable -> no collocated MV |
1020 | | |
1021 | 18.9k | if (colImg->integrity == INTEGRITY_UNAVAILABLE_REFERENCE) { |
1022 | 0 | out_mvLXCol->x = 0; |
1023 | 0 | out_mvLXCol->y = 0; |
1024 | 0 | *out_availableFlagLXCol = 0; |
1025 | 0 | return; |
1026 | 0 | } |
1027 | | |
1028 | | |
1029 | | // get the collocated MV |
1030 | | |
1031 | 18.9k | const PBMotion& mvi = colImg->get_mv_info(xColPb,yColPb); |
1032 | 18.9k | int listCol; |
1033 | 18.9k | int refIdxCol; |
1034 | 18.9k | MotionVector mvCol; |
1035 | | |
1036 | 18.9k | logtrace(LogMotion,"read MVI %d;%d:\n",xColPb,yColPb); |
1037 | 18.9k | logmvcand(mvi); |
1038 | | |
1039 | | |
1040 | | // collocated MV uses only L1 -> use L1 |
1041 | 18.9k | if (mvi.predFlag[0]==0) { |
1042 | 8.15k | mvCol = mvi.mv[1]; |
1043 | 8.15k | refIdxCol = mvi.refIdx[1]; |
1044 | 8.15k | listCol = 1; |
1045 | 8.15k | } |
1046 | | // collocated MV uses only L0 -> use L0 |
1047 | 10.7k | else if (mvi.predFlag[1]==0) { |
1048 | 9.13k | mvCol = mvi.mv[0]; |
1049 | 9.13k | refIdxCol = mvi.refIdx[0]; |
1050 | 9.13k | listCol = 0; |
1051 | 9.13k | } |
1052 | | // collocated MV uses L0 and L1 |
1053 | 1.63k | else { |
1054 | 1.63k | bool allRefFramesBeforeCurrentFrame = true; |
1055 | | |
1056 | 1.63k | const int currentPOC = img->PicOrderCntVal; |
1057 | | |
1058 | | // all reference POCs earlier than current POC (list 1) |
1059 | | // Test L1 first, because there is a higher change to find a future reference frame. |
1060 | | |
1061 | 7.56k | for (int rIdx=0; rIdx<shdr->num_ref_idx_l1_active && allRefFramesBeforeCurrentFrame; rIdx++) |
1062 | 5.93k | { |
1063 | 5.93k | const de265_image* refimg = ctx->get_image(shdr->RefPicList[1][rIdx]); |
1064 | 5.93k | int refPOC = refimg->PicOrderCntVal; |
1065 | | |
1066 | 5.93k | if (refPOC > currentPOC) { |
1067 | 555 | allRefFramesBeforeCurrentFrame = false; |
1068 | 555 | } |
1069 | 5.93k | } |
1070 | | |
1071 | | // all reference POCs earlier than current POC (list 0) |
1072 | | |
1073 | 4.04k | for (int rIdx=0; rIdx<shdr->num_ref_idx_l0_active && allRefFramesBeforeCurrentFrame; rIdx++) |
1074 | 2.41k | { |
1075 | 2.41k | const de265_image* refimg = ctx->get_image(shdr->RefPicList[0][rIdx]); |
1076 | 2.41k | int refPOC = refimg->PicOrderCntVal; |
1077 | | |
1078 | 2.41k | if (refPOC > currentPOC) { |
1079 | 124 | allRefFramesBeforeCurrentFrame = false; |
1080 | 124 | } |
1081 | 2.41k | } |
1082 | | |
1083 | | |
1084 | | /* TODO: What is the rationale behind this ??? |
1085 | | |
1086 | | My guess: |
1087 | | when there are images before the current frame (most probably in L0) and images after |
1088 | | the current frame (most probably in L1), we take the reference in the opposite |
1089 | | direction than where the collocated frame is positioned in the hope that the distance |
1090 | | to the current frame will be smaller and thus give a better prediction. |
1091 | | |
1092 | | If all references point into the past, we cannot say much about the temporal order or |
1093 | | L0,L1 and thus take over both parts. |
1094 | | */ |
1095 | | |
1096 | 1.63k | if (allRefFramesBeforeCurrentFrame) { |
1097 | 952 | mvCol = mvi.mv[X]; |
1098 | 952 | refIdxCol = mvi.refIdx[X]; |
1099 | 952 | listCol = X; |
1100 | 952 | } |
1101 | 679 | else { |
1102 | 679 | int N = shdr->collocated_from_l0_flag; |
1103 | 679 | mvCol = mvi.mv[N]; |
1104 | 679 | refIdxCol = mvi.refIdx[N]; |
1105 | 679 | listCol = N; |
1106 | 679 | } |
1107 | 1.63k | } |
1108 | | |
1109 | | |
1110 | | |
1111 | 18.9k | uint16_t slice_hdr_idx = colImg->get_SliceHeaderIndex(xColPb,yColPb); |
1112 | 18.9k | if (slice_hdr_idx >= colImg->slices.size()) { |
1113 | 0 | ctx->add_warning(DE265_WARNING_INVALID_SLICE_HEADER_INDEX_ACCESS, false); |
1114 | |
|
1115 | 0 | *out_availableFlagLXCol = 0; |
1116 | 0 | out_mvLXCol->x = 0; |
1117 | 0 | out_mvLXCol->y = 0; |
1118 | 0 | return; |
1119 | 0 | } |
1120 | | |
1121 | 18.9k | const slice_segment_header* colShdr = colImg->slices[ colImg->get_SliceHeaderIndex(xColPb,yColPb) ]; |
1122 | | |
1123 | 18.9k | if (shdr->LongTermRefPic[X][refIdxLX] != |
1124 | 18.9k | colShdr->LongTermRefPic[listCol][refIdxCol]) { |
1125 | 5.85k | *out_availableFlagLXCol = 0; |
1126 | 5.85k | out_mvLXCol->x = 0; |
1127 | 5.85k | out_mvLXCol->y = 0; |
1128 | 5.85k | } |
1129 | 13.0k | else { |
1130 | 13.0k | *out_availableFlagLXCol = 1; |
1131 | | |
1132 | 13.0k | const bool isLongTerm = shdr->LongTermRefPic[X][refIdxLX]; |
1133 | | |
1134 | 13.0k | int colDist = colImg->PicOrderCntVal - colShdr->RefPicList_POC[listCol][refIdxCol]; |
1135 | 13.0k | int currDist = img->PicOrderCntVal - shdr->RefPicList_POC[X][refIdxLX]; |
1136 | | |
1137 | 13.0k | logtrace(LogMotion,"COLPOCDIFF %d %d [%d %d / %d %d]\n",colDist, currDist, |
1138 | 13.0k | colImg->PicOrderCntVal, colShdr->RefPicList_POC[listCol][refIdxCol], |
1139 | 13.0k | img->PicOrderCntVal, shdr->RefPicList_POC[X][refIdxLX] |
1140 | 13.0k | ); |
1141 | | |
1142 | 13.0k | if (isLongTerm || colDist == currDist) { |
1143 | 12.5k | *out_mvLXCol = mvCol; |
1144 | 12.5k | } |
1145 | 536 | else { |
1146 | 536 | if (!scale_mv(out_mvLXCol, mvCol, colDist, currDist)) { |
1147 | 0 | ctx->add_warning(DE265_WARNING_INCORRECT_MOTION_VECTOR_SCALING, false); |
1148 | 0 | img->integrity = INTEGRITY_DECODING_ERRORS; |
1149 | 0 | } |
1150 | | |
1151 | 536 | logtrace(LogMotion,"scale: %d;%d to %d;%d\n", |
1152 | 536 | mvCol.x,mvCol.y, out_mvLXCol->x,out_mvLXCol->y); |
1153 | 536 | } |
1154 | 13.0k | } |
1155 | 18.9k | } |
1156 | | |
1157 | | |
1158 | | // 8.5.3.1.7 |
1159 | | void derive_temporal_luma_vector_prediction(base_context* ctx, |
1160 | | de265_image* img, |
1161 | | const slice_segment_header* shdr, |
1162 | | int xP,int yP, |
1163 | | int nPbW,int nPbH, |
1164 | | int refIdxL, |
1165 | | int X, // which MV (L0/L1) to get |
1166 | | MotionVector* out_mvLXCol, |
1167 | | uint8_t* out_availableFlagLXCol) |
1168 | 299k | { |
1169 | | // --- no temporal MVP -> exit --- |
1170 | | |
1171 | 299k | if (shdr->slice_temporal_mvp_enabled_flag == 0) { |
1172 | 243k | out_mvLXCol->x = 0; |
1173 | 243k | out_mvLXCol->y = 0; |
1174 | 243k | *out_availableFlagLXCol = 0; |
1175 | 243k | return; |
1176 | 243k | } |
1177 | | |
1178 | | |
1179 | | // --- find collocated reference image --- |
1180 | | |
1181 | 56.8k | int Log2CtbSizeY = img->get_sps().Log2CtbSizeY; |
1182 | | |
1183 | 56.8k | int colPic; // TODO: this is the same for the whole slice. We can precompute it. |
1184 | | |
1185 | 56.8k | if (shdr->slice_type == SLICE_TYPE_B && |
1186 | 28.6k | shdr->collocated_from_l0_flag == 0) |
1187 | 8.49k | { |
1188 | 8.49k | logtrace(LogMotion,"collocated L1 ref_idx=%d\n",shdr->collocated_ref_idx); |
1189 | | |
1190 | 8.49k | colPic = shdr->RefPicList[1][ shdr->collocated_ref_idx ]; |
1191 | 8.49k | } |
1192 | 48.3k | else |
1193 | 48.3k | { |
1194 | 48.3k | logtrace(LogMotion,"collocated L0 ref_idx=%d\n",shdr->collocated_ref_idx); |
1195 | | |
1196 | 48.3k | colPic = shdr->RefPicList[0][ shdr->collocated_ref_idx ]; |
1197 | 48.3k | } |
1198 | | |
1199 | | |
1200 | | // check whether collocated reference picture exists |
1201 | | |
1202 | 56.8k | if (!ctx->has_image(colPic)) { |
1203 | 0 | out_mvLXCol->x = 0; |
1204 | 0 | out_mvLXCol->y = 0; |
1205 | 0 | *out_availableFlagLXCol = 0; |
1206 | |
|
1207 | 0 | ctx->add_warning(DE265_WARNING_NONEXISTING_REFERENCE_PICTURE_ACCESSED, false); |
1208 | 0 | return; |
1209 | 0 | } |
1210 | | |
1211 | | |
1212 | | // --- get collocated MV either at bottom-right corner or from center of PB --- |
1213 | | |
1214 | 56.8k | int xColPb,yColPb; |
1215 | 56.8k | int yColBr = yP + nPbH; // bottom right collocated motion vector position |
1216 | 56.8k | int xColBr = xP + nPbW; |
1217 | | |
1218 | | /* If neighboring pixel at bottom-right corner is in the same CTB-row and inside the image, |
1219 | | use this (reduced down to 16 pixels resolution) as collocated MV position. |
1220 | | |
1221 | | Note: see 2014, Sze, Sect. 5.2.1.2 why candidate C0 is excluded when on another CTB-row. |
1222 | | This is to reduce the memory bandwidth requirements. |
1223 | | */ |
1224 | 56.8k | if ((yP>>Log2CtbSizeY) == (yColBr>>Log2CtbSizeY) && |
1225 | 47.6k | xColBr < img->get_sps().pic_width_in_luma_samples && |
1226 | 45.9k | yColBr < img->get_sps().pic_height_in_luma_samples) |
1227 | 41.1k | { |
1228 | 41.1k | xColPb = xColBr & ~0x0F; // reduce resolution of collocated motion-vectors to 16 pixels grid |
1229 | 41.1k | yColPb = yColBr & ~0x0F; |
1230 | | |
1231 | 41.1k | derive_collocated_motion_vectors(ctx,img,shdr, xP,yP, colPic, xColPb,yColPb, refIdxL, X, |
1232 | 41.1k | out_mvLXCol, out_availableFlagLXCol); |
1233 | 41.1k | } |
1234 | 15.6k | else |
1235 | 15.6k | { |
1236 | 15.6k | out_mvLXCol->x = 0; |
1237 | 15.6k | out_mvLXCol->y = 0; |
1238 | 15.6k | *out_availableFlagLXCol = 0; |
1239 | 15.6k | } |
1240 | | |
1241 | | |
1242 | 56.8k | if (*out_availableFlagLXCol==0) { |
1243 | | |
1244 | 55.0k | int xColCtr = xP+(nPbW>>1); |
1245 | 55.0k | int yColCtr = yP+(nPbH>>1); |
1246 | | |
1247 | 55.0k | xColPb = xColCtr & ~0x0F; // reduce resolution of collocated motion-vectors to 16 pixels grid |
1248 | 55.0k | yColPb = yColCtr & ~0x0F; |
1249 | | |
1250 | 55.0k | derive_collocated_motion_vectors(ctx,img,shdr, xP,yP, colPic, xColPb,yColPb, refIdxL, X, |
1251 | 55.0k | out_mvLXCol, out_availableFlagLXCol); |
1252 | 55.0k | } |
1253 | 56.8k | } |
1254 | | |
1255 | | |
1256 | | static int table_8_19[2][12] = { |
1257 | | { 0,1,0,2,1,2,0,3,1,3,2,3 }, |
1258 | | { 1,0,2,0,2,1,3,0,3,1,3,2 } |
1259 | | }; |
1260 | | |
1261 | | // 8.5.3.1.3 |
1262 | | /* Note (TODO): during decoding, we know which of the candidates we will select. |
1263 | | + Hence, we do not really have to generate the other ones... |
1264 | | + */ |
1265 | | void derive_combined_bipredictive_merging_candidates(const base_context* ctx, |
1266 | | const slice_segment_header* shdr, |
1267 | | PBMotion* inout_mergeCandList, |
1268 | | int* inout_numMergeCand, |
1269 | | int maxCandidates) |
1270 | 446k | { |
1271 | 446k | if (*inout_numMergeCand>1 && *inout_numMergeCand < maxCandidates) { |
1272 | 4.84k | int numOrigMergeCand = *inout_numMergeCand; |
1273 | | |
1274 | 4.84k | int numInputMergeCand = *inout_numMergeCand; |
1275 | 4.84k | int combIdx = 0; |
1276 | 4.84k | uint8_t combStop = false; |
1277 | | |
1278 | 16.2k | while (!combStop) { |
1279 | 11.3k | int l0CandIdx = table_8_19[0][combIdx]; |
1280 | 11.3k | int l1CandIdx = table_8_19[1][combIdx]; |
1281 | | |
1282 | 11.3k | if (l0CandIdx >= numInputMergeCand || |
1283 | 11.3k | l1CandIdx >= numInputMergeCand) { |
1284 | 0 | assert(false); // bitstream error -> TODO: conceal error |
1285 | 0 | } |
1286 | | |
1287 | 11.3k | PBMotion& l0Cand = inout_mergeCandList[l0CandIdx]; |
1288 | 11.3k | PBMotion& l1Cand = inout_mergeCandList[l1CandIdx]; |
1289 | | |
1290 | 11.3k | logtrace(LogMotion,"add bipredictive merging candidate (combIdx:%d)\n",combIdx); |
1291 | 11.3k | logtrace(LogMotion,"l0Cand:\n"); logmvcand(l0Cand); |
1292 | 11.3k | logtrace(LogMotion,"l1Cand:\n"); logmvcand(l1Cand); |
1293 | | |
1294 | 11.3k | const de265_image* img0 = l0Cand.predFlag[0] ? ctx->get_image(shdr->RefPicList[0][l0Cand.refIdx[0]]) : nullptr; |
1295 | 11.3k | const de265_image* img1 = l1Cand.predFlag[1] ? ctx->get_image(shdr->RefPicList[1][l1Cand.refIdx[1]]) : nullptr; |
1296 | | |
1297 | 11.3k | if (l0Cand.predFlag[0] && !img0) { |
1298 | 0 | return; // TODO error |
1299 | 0 | } |
1300 | | |
1301 | 11.3k | if (l1Cand.predFlag[1] && !img1) { |
1302 | 0 | return; // TODO error |
1303 | 0 | } |
1304 | | |
1305 | 11.3k | if (l0Cand.predFlag[0] && l1Cand.predFlag[1] && |
1306 | 5.43k | (img0->PicOrderCntVal != img1->PicOrderCntVal || |
1307 | 4.46k | l0Cand.mv[0].x != l1Cand.mv[1].x || |
1308 | 3.41k | l0Cand.mv[0].y != l1Cand.mv[1].y)) { |
1309 | 3.41k | PBMotion& p = inout_mergeCandList[ *inout_numMergeCand ]; |
1310 | 3.41k | p.refIdx[0] = l0Cand.refIdx[0]; |
1311 | 3.41k | p.refIdx[1] = l1Cand.refIdx[1]; |
1312 | 3.41k | p.predFlag[0] = l0Cand.predFlag[0]; |
1313 | 3.41k | p.predFlag[1] = l1Cand.predFlag[1]; |
1314 | 3.41k | p.mv[0] = l0Cand.mv[0]; |
1315 | 3.41k | p.mv[1] = l1Cand.mv[1]; |
1316 | 3.41k | (*inout_numMergeCand)++; |
1317 | | |
1318 | 3.41k | logtrace(LogMotion,"result:\n"); |
1319 | 3.41k | logmvcand(p); |
1320 | 3.41k | } |
1321 | | |
1322 | 11.3k | combIdx++; |
1323 | 11.3k | if (combIdx == numOrigMergeCand*(numOrigMergeCand-1) || |
1324 | 7.80k | *inout_numMergeCand == maxCandidates) { |
1325 | 4.84k | combStop = true; |
1326 | 4.84k | } |
1327 | 11.3k | } |
1328 | 4.84k | } |
1329 | 446k | } |
1330 | | |
1331 | | |
1332 | | // 8.5.3.1.1 |
1333 | | |
1334 | | void get_merge_candidate_list_without_step_9(base_context* ctx, |
1335 | | const slice_segment_header* shdr, |
1336 | | const MotionVectorAccess& mvaccess, |
1337 | | de265_image* img, |
1338 | | int xC,int yC, int xP,int yP, |
1339 | | int nCS, int nPbW,int nPbH, int partIdx, |
1340 | | int max_merge_idx, |
1341 | | PBMotion* mergeCandList) |
1342 | 802k | { |
1343 | | |
1344 | | //int xOrigP = xP; |
1345 | | //int yOrigP = yP; |
1346 | | //int nOrigPbW = nPbW; |
1347 | | //int nOrigPbH = nPbH; |
1348 | | |
1349 | 802k | int singleMCLFlag; // single merge-candidate-list (MCL) flag |
1350 | | |
1351 | | /* Use single MCL for CBs of size 8x8, except when parallel-merge-level is at 4x4. |
1352 | | Without this flag, PBs smaller than 8x8 would not receive as much merging candidates. |
1353 | | Having additional candidates might have these advantages: |
1354 | | - coding MVs for these small PBs is expensive, and |
1355 | | - since the PBs are not far away from a proper (neighboring) merging candidate, |
1356 | | the quality of the candidates will still be good. |
1357 | | */ |
1358 | 802k | singleMCLFlag = (img->get_pps().log2_parallel_merge_level > 2 && nCS==8); |
1359 | | |
1360 | 802k | if (singleMCLFlag) { |
1361 | 639k | xP=xC; |
1362 | 639k | yP=yC; |
1363 | 639k | nPbW=nCS; |
1364 | 639k | nPbH=nCS; |
1365 | 639k | partIdx=0; |
1366 | 639k | } |
1367 | | |
1368 | 802k | int maxCandidates = max_merge_idx+1; |
1369 | | //MotionVectorSpec mergeCandList[5]; |
1370 | 802k | int numMergeCand=0; |
1371 | | |
1372 | | // --- spatial merge candidates |
1373 | | |
1374 | 802k | numMergeCand = derive_spatial_merging_candidates(mvaccess, |
1375 | 802k | img, xC,yC, nCS, xP,yP, singleMCLFlag, |
1376 | 802k | nPbW,nPbH,partIdx, mergeCandList, |
1377 | 802k | maxCandidates); |
1378 | | |
1379 | | // --- collocated merge candidate |
1380 | 802k | if (numMergeCand < maxCandidates) { |
1381 | 95.3k | int refIdxCol[2] = { 0,0 }; |
1382 | | |
1383 | 95.3k | MotionVector mvCol[2]; |
1384 | 95.3k | uint8_t predFlagLCol[2]; |
1385 | 95.3k | derive_temporal_luma_vector_prediction(ctx,img,shdr, xP,yP,nPbW,nPbH, |
1386 | 95.3k | refIdxCol[0],0, &mvCol[0], |
1387 | 95.3k | &predFlagLCol[0]); |
1388 | | |
1389 | 95.3k | uint8_t availableFlagCol = predFlagLCol[0]; |
1390 | 95.3k | predFlagLCol[1] = 0; |
1391 | | |
1392 | 95.3k | if (shdr->slice_type == SLICE_TYPE_B) { |
1393 | 40.7k | derive_temporal_luma_vector_prediction(ctx,img,shdr, |
1394 | 40.7k | xP,yP,nPbW,nPbH, refIdxCol[1],1, &mvCol[1], |
1395 | 40.7k | &predFlagLCol[1]); |
1396 | 40.7k | availableFlagCol |= predFlagLCol[1]; |
1397 | 40.7k | } |
1398 | | |
1399 | | |
1400 | 95.3k | if (availableFlagCol) { |
1401 | 7.20k | PBMotion* colVec = &mergeCandList[numMergeCand++]; |
1402 | | |
1403 | 7.20k | colVec->mv[0] = mvCol[0]; |
1404 | 7.20k | colVec->mv[1] = mvCol[1]; |
1405 | 7.20k | colVec->predFlag[0] = predFlagLCol[0]; |
1406 | 7.20k | colVec->predFlag[1] = predFlagLCol[1]; |
1407 | 7.20k | colVec->refIdx[0] = refIdxCol[0]; |
1408 | 7.20k | colVec->refIdx[1] = refIdxCol[1]; |
1409 | 7.20k | } |
1410 | 95.3k | } |
1411 | | |
1412 | | |
1413 | | // --- bipredictive merge candidates --- |
1414 | | |
1415 | 802k | if (shdr->slice_type == SLICE_TYPE_B) { |
1416 | 446k | derive_combined_bipredictive_merging_candidates(ctx, shdr, |
1417 | 446k | mergeCandList, &numMergeCand, maxCandidates); |
1418 | 446k | } |
1419 | | |
1420 | | |
1421 | | // --- zero-vector merge candidates --- |
1422 | | |
1423 | 802k | derive_zero_motion_vector_candidates(shdr, mergeCandList, &numMergeCand, maxCandidates); |
1424 | | |
1425 | | |
1426 | 802k | logtrace(LogMotion,"mergeCandList:\n"); |
1427 | 3.72M | for (int i=0;i<shdr->MaxNumMergeCand;i++) |
1428 | 2.92M | { |
1429 | | //logtrace(LogMotion, " %d:%s\n", i, i==merge_idx ? " SELECTED":""); |
1430 | 2.92M | logmvcand(mergeCandList[i]); |
1431 | 2.92M | } |
1432 | 802k | } |
1433 | | |
1434 | | |
1435 | | |
1436 | | void get_merge_candidate_list(base_context* ctx, |
1437 | | const slice_segment_header* shdr, |
1438 | | de265_image* img, |
1439 | | int xC,int yC, int xP,int yP, |
1440 | | int nCS, int nPbW,int nPbH, int partIdx, |
1441 | | PBMotion* mergeCandList) |
1442 | 0 | { |
1443 | 0 | int max_merge_idx = 5-shdr->five_minus_max_num_merge_cand -1; |
1444 | |
|
1445 | 0 | get_merge_candidate_list_without_step_9(ctx, shdr, |
1446 | 0 | MotionVectorAccess_de265_image(img), img, |
1447 | 0 | xC,yC,xP,yP,nCS,nPbW,nPbH, partIdx, |
1448 | 0 | max_merge_idx, mergeCandList); |
1449 | | |
1450 | | // 9. for encoder: modify all merge candidates |
1451 | |
|
1452 | 0 | for (int i=0;i<=max_merge_idx;i++) { |
1453 | 0 | if (mergeCandList[i].predFlag[0] && |
1454 | 0 | mergeCandList[i].predFlag[1] && |
1455 | 0 | nPbW+nPbH==12) |
1456 | 0 | { |
1457 | 0 | mergeCandList[i].refIdx[1] = 0; |
1458 | 0 | mergeCandList[i].predFlag[1] = 0; |
1459 | 0 | } |
1460 | 0 | } |
1461 | 0 | } |
1462 | | |
1463 | | |
1464 | | void derive_luma_motion_merge_mode(base_context* ctx, |
1465 | | const slice_segment_header* shdr, |
1466 | | de265_image* img, |
1467 | | int xC,int yC, int xP,int yP, |
1468 | | int nCS, int nPbW,int nPbH, int partIdx, |
1469 | | int merge_idx, |
1470 | | PBMotion* out_vi) |
1471 | 802k | { |
1472 | 802k | PBMotion mergeCandList[5]; |
1473 | | |
1474 | 802k | get_merge_candidate_list_without_step_9(ctx, shdr, |
1475 | 802k | MotionVectorAccess_de265_image(img), img, |
1476 | 802k | xC,yC,xP,yP,nCS,nPbW,nPbH, partIdx, |
1477 | 802k | merge_idx, mergeCandList); |
1478 | | |
1479 | | |
1480 | 802k | *out_vi = mergeCandList[merge_idx]; |
1481 | | |
1482 | | // 8.5.3.1.1 / 9. |
1483 | | |
1484 | 802k | if (out_vi->predFlag[0] && out_vi->predFlag[1] && nPbW+nPbH==12) { |
1485 | 20.9k | out_vi->refIdx[1] = 0; |
1486 | 20.9k | out_vi->predFlag[1] = 0; |
1487 | 20.9k | } |
1488 | 802k | } |
1489 | | |
1490 | | |
1491 | | // 8.5.3.1.6 |
1492 | | void derive_spatial_luma_vector_prediction(base_context* ctx, |
1493 | | de265_image* img, |
1494 | | const slice_segment_header* shdr, |
1495 | | int xC,int yC,int nCS,int xP,int yP, |
1496 | | int nPbW,int nPbH, int X, |
1497 | | int refIdxLX, int partIdx, |
1498 | | uint8_t out_availableFlagLXN[2], |
1499 | | MotionVector out_mvLXN[2]) |
1500 | 331k | { |
1501 | 331k | if (refIdxLX >= MAX_NUM_REF_PICS) { |
1502 | 0 | ctx->add_warning(DE265_WARNING_INCORRECT_MOTION_VECTOR_SCALING, false); |
1503 | 0 | img->integrity = INTEGRITY_DECODING_ERRORS; |
1504 | |
|
1505 | 0 | out_availableFlagLXN[0] = false; |
1506 | 0 | out_availableFlagLXN[1] = false; |
1507 | 0 | out_mvLXN[0] = MotionVector(); |
1508 | 0 | out_mvLXN[1] = MotionVector(); |
1509 | 0 | return; |
1510 | 0 | } |
1511 | | |
1512 | 331k | int isScaledFlagLX = 0; |
1513 | | |
1514 | 331k | const int A=0; |
1515 | 331k | const int B=1; |
1516 | | |
1517 | 331k | out_availableFlagLXN[A] = 0; |
1518 | 331k | out_availableFlagLXN[B] = 0; |
1519 | | |
1520 | | |
1521 | | // --- A --- |
1522 | | |
1523 | | // 1. |
1524 | | |
1525 | 331k | int xA[2], yA[2]; |
1526 | 331k | xA[0] = xP-1; |
1527 | 331k | yA[0] = yP + nPbH; |
1528 | 331k | xA[1] = xA[0]; |
1529 | 331k | yA[1] = yA[0]-1; |
1530 | | |
1531 | | // 2. |
1532 | | |
1533 | 331k | out_availableFlagLXN[A] = 0; |
1534 | 331k | out_mvLXN[A].x = 0; |
1535 | 331k | out_mvLXN[A].y = 0; |
1536 | | |
1537 | | // 3. / 4. |
1538 | | |
1539 | 331k | bool availableA[2]; |
1540 | 331k | availableA[0] = img->available_pred_blk(xC,yC, nCS, xP,yP, nPbW,nPbH,partIdx, xA[0],yA[0]); |
1541 | 331k | availableA[1] = img->available_pred_blk(xC,yC, nCS, xP,yP, nPbW,nPbH,partIdx, xA[1],yA[1]); |
1542 | | |
1543 | | // 5. |
1544 | | |
1545 | 331k | if (availableA[0] || availableA[1]) { |
1546 | 319k | isScaledFlagLX = 1; |
1547 | 319k | } |
1548 | | |
1549 | | // 6. test A0 and A1 (Ak) |
1550 | | |
1551 | 331k | int refIdxA=-1; |
1552 | | |
1553 | | // the POC we want to reference in this PB |
1554 | 331k | const de265_image* tmpimg = ctx->get_image(shdr->RefPicList[X][ refIdxLX ]); |
1555 | 331k | if (tmpimg==nullptr) { return; } |
1556 | 331k | const int referenced_POC = tmpimg->PicOrderCntVal; |
1557 | | |
1558 | 993k | for (int k=0;k<=1;k++) { |
1559 | | |
1560 | 662k | if (availableA[k] && |
1561 | 420k | out_availableFlagLXN[A]==0 && // no A?-predictor so far |
1562 | 321k | img->get_pred_mode(xA[k],yA[k]) != MODE_INTRA) { |
1563 | | |
1564 | 321k | int Y=1-X; |
1565 | | |
1566 | 321k | const PBMotion& vi = img->get_mv_info(xA[k],yA[k]); |
1567 | 321k | logtrace(LogMotion,"MVP A%d=\n",k); |
1568 | 321k | logmvcand(vi); |
1569 | | |
1570 | 321k | const de265_image* imgX = nullptr; |
1571 | 321k | if (vi.predFlag[X]) { |
1572 | 308k | imgX = ctx->get_image(shdr->RefPicList[X][ vi.refIdx[X] ]); |
1573 | 308k | } |
1574 | | |
1575 | 321k | const de265_image* imgY = nullptr; |
1576 | 321k | if (vi.predFlag[Y]) { |
1577 | 93.6k | imgY = ctx->get_image(shdr->RefPicList[Y][ vi.refIdx[Y] ]); |
1578 | 93.6k | } |
1579 | | |
1580 | | // check whether the predictor X is available and references the same POC |
1581 | 321k | if (vi.predFlag[X] && imgX && imgX->PicOrderCntVal == referenced_POC) { |
1582 | | |
1583 | 304k | logtrace(LogMotion,"take A%d/L%d as A candidate with same POC\n",k,X); |
1584 | | |
1585 | 304k | out_availableFlagLXN[A]=1; |
1586 | 304k | out_mvLXN[A] = vi.mv[X]; |
1587 | 304k | refIdxA = vi.refIdx[X]; |
1588 | 304k | } |
1589 | | // check whether the other predictor (Y) is available and references the same POC |
1590 | 16.5k | else if (vi.predFlag[Y] && imgY && imgY->PicOrderCntVal == referenced_POC) { |
1591 | | |
1592 | 8.72k | logtrace(LogMotion,"take A%d/L%d as A candidate with same POC\n",k,Y); |
1593 | | |
1594 | 8.72k | out_availableFlagLXN[A]=1; |
1595 | 8.72k | out_mvLXN[A] = vi.mv[Y]; |
1596 | 8.72k | refIdxA = vi.refIdx[Y]; |
1597 | 8.72k | } |
1598 | 321k | } |
1599 | 662k | } |
1600 | | |
1601 | | // 7. If there is no predictor referencing the same POC, we take any other reference as |
1602 | | // long as it is the same type of reference (long-term / short-term) |
1603 | | |
1604 | 364k | for (int k=0 ; k<=1 && out_availableFlagLXN[A]==0 ; k++) { |
1605 | 33.6k | int refPicList=-1; |
1606 | | |
1607 | 33.6k | if (availableA[k] && |
1608 | | // TODO: we could remove this call by storing the result of the similar computation above |
1609 | 5.56k | img->get_pred_mode(xA[k],yA[k]) != MODE_INTRA) { |
1610 | | |
1611 | 5.56k | int Y=1-X; |
1612 | | |
1613 | 5.56k | const PBMotion& vi = img->get_mv_info(xA[k],yA[k]); |
1614 | 5.56k | if (vi.predFlag[X]==1 && |
1615 | 2.42k | shdr->LongTermRefPic[X][refIdxLX] == shdr->LongTermRefPic[X][ vi.refIdx[X] ]) { |
1616 | | |
1617 | 2.18k | logtrace(LogMotion,"take A%D/L%d as A candidate with different POCs\n",k,X); |
1618 | | |
1619 | 2.18k | out_availableFlagLXN[A]=1; |
1620 | 2.18k | out_mvLXN[A] = vi.mv[X]; |
1621 | 2.18k | refIdxA = vi.refIdx[X]; |
1622 | 2.18k | refPicList = X; |
1623 | 2.18k | } |
1624 | 3.38k | else if (vi.predFlag[Y]==1 && |
1625 | 3.20k | shdr->LongTermRefPic[X][refIdxLX] == shdr->LongTermRefPic[Y][ vi.refIdx[Y] ]) { |
1626 | | |
1627 | 3.02k | logtrace(LogMotion,"take A%d/L%d as A candidate with different POCs\n",k,Y); |
1628 | | |
1629 | 3.02k | out_availableFlagLXN[A]=1; |
1630 | 3.02k | out_mvLXN[A] = vi.mv[Y]; |
1631 | 3.02k | refIdxA = vi.refIdx[Y]; |
1632 | 3.02k | refPicList = Y; |
1633 | 3.02k | } |
1634 | 5.56k | } |
1635 | | |
1636 | 33.6k | if (out_availableFlagLXN[A]==1) { |
1637 | 5.21k | if (refIdxA<0) { |
1638 | 0 | out_availableFlagLXN[0] = out_availableFlagLXN[1] = false; |
1639 | 0 | return; // error |
1640 | 0 | } |
1641 | | |
1642 | 5.21k | assert(refIdxA>=0); |
1643 | 5.21k | assert(refPicList>=0); |
1644 | | |
1645 | 5.21k | const de265_image* refPicA = ctx->get_image(shdr->RefPicList[refPicList][refIdxA ]); |
1646 | | |
1647 | | #ifdef DE265_LOG_TRACE |
1648 | | const de265_image* refPicX = ctx->get_image(shdr->RefPicList[X][refIdxLX]); |
1649 | | #endif |
1650 | | |
1651 | | //int picStateA = shdr->RefPicList_PicState[refPicList][refIdxA ]; |
1652 | | //int picStateX = shdr->RefPicList_PicState[X ][refIdxLX]; |
1653 | | |
1654 | 5.21k | int isLongTermA = shdr->LongTermRefPic[refPicList][refIdxA ]; |
1655 | 5.21k | int isLongTermX = shdr->LongTermRefPic[X ][refIdxLX]; |
1656 | | |
1657 | 5.21k | logtrace(LogMotion,"scale MVP A: A-POC:%d X-POC:%d\n", |
1658 | 5.21k | refPicA->PicOrderCntVal,refPicX->PicOrderCntVal); |
1659 | | |
1660 | 5.21k | if (!isLongTermA && !isLongTermX) |
1661 | | /* |
1662 | | if (picStateA == UsedForShortTermReference && |
1663 | | picStateX == UsedForShortTermReference) |
1664 | | */ |
1665 | 4.06k | { |
1666 | 4.06k | int distA = img->PicOrderCntVal - refPicA->PicOrderCntVal; |
1667 | 4.06k | int distX = img->PicOrderCntVal - referenced_POC; |
1668 | | |
1669 | 4.06k | if (!scale_mv(&out_mvLXN[A], out_mvLXN[A], distA, distX)) { |
1670 | 0 | ctx->add_warning(DE265_WARNING_INCORRECT_MOTION_VECTOR_SCALING, false); |
1671 | 0 | img->integrity = INTEGRITY_DECODING_ERRORS; |
1672 | 0 | } |
1673 | 4.06k | } |
1674 | 5.21k | } |
1675 | 33.6k | } |
1676 | | |
1677 | | // --- B --- |
1678 | | |
1679 | | // 1. |
1680 | | |
1681 | 331k | int xB[3], yB[3]; |
1682 | 331k | xB[0] = xP+nPbW; |
1683 | 331k | yB[0] = yP-1; |
1684 | 331k | xB[1] = xB[0]-1; |
1685 | 331k | yB[1] = yP-1; |
1686 | 331k | xB[2] = xP-1; |
1687 | 331k | yB[2] = yP-1; |
1688 | | |
1689 | | // 2. |
1690 | | |
1691 | 331k | out_availableFlagLXN[B] = 0; |
1692 | 331k | out_mvLXN[B].x = 0; |
1693 | 331k | out_mvLXN[B].y = 0; |
1694 | | |
1695 | | // 3. test B0,B1,B2 (Bk) |
1696 | | |
1697 | 331k | int refIdxB=-1; |
1698 | | |
1699 | 331k | bool availableB[3]; |
1700 | 1.32M | for (int k=0;k<3;k++) { |
1701 | 993k | availableB[k] = img->available_pred_blk(xC,yC, nCS, xP,yP, nPbW,nPbH,partIdx, xB[k],yB[k]); |
1702 | | |
1703 | 993k | if (availableB[k] && out_availableFlagLXN[B]==0) { |
1704 | | |
1705 | 264k | int Y=1-X; |
1706 | | |
1707 | 264k | const PBMotion& vi = img->get_mv_info(xB[k],yB[k]); |
1708 | 264k | logtrace(LogMotion,"MVP B%d=\n",k); |
1709 | 264k | logmvcand(vi); |
1710 | | |
1711 | 264k | const de265_image* imgX = nullptr; |
1712 | 264k | if (vi.predFlag[X]) { |
1713 | 254k | imgX = ctx->get_image(shdr->RefPicList[X][ vi.refIdx[X] ]); |
1714 | 254k | } |
1715 | | |
1716 | 264k | const de265_image* imgY = nullptr; |
1717 | 264k | if (vi.predFlag[Y]) { |
1718 | 71.0k | imgY = ctx->get_image(shdr->RefPicList[Y][ vi.refIdx[Y] ]); |
1719 | 71.0k | } |
1720 | | |
1721 | 264k | if (vi.predFlag[X] && imgX && imgX->PicOrderCntVal == referenced_POC) { |
1722 | 249k | logtrace(LogMotion,"a) take B%d/L%d as B candidate with same POC\n",k,X); |
1723 | | |
1724 | 249k | out_availableFlagLXN[B]=1; |
1725 | 249k | out_mvLXN[B] = vi.mv[X]; |
1726 | 249k | refIdxB = vi.refIdx[X]; |
1727 | 249k | } |
1728 | 14.9k | else if (vi.predFlag[Y] && imgY && imgY->PicOrderCntVal == referenced_POC) { |
1729 | 6.21k | logtrace(LogMotion,"b) take B%d/L%d as B candidate with same POC\n",k,Y); |
1730 | | |
1731 | 6.21k | out_availableFlagLXN[B]=1; |
1732 | 6.21k | out_mvLXN[B] = vi.mv[Y]; |
1733 | 6.21k | refIdxB = vi.refIdx[Y]; |
1734 | 6.21k | } |
1735 | 264k | } |
1736 | 993k | } |
1737 | | |
1738 | | // 4. |
1739 | | |
1740 | 331k | if (isScaledFlagLX==0 && // no A predictor, |
1741 | 12.0k | out_availableFlagLXN[B]) // but an unscaled B predictor |
1742 | 8.91k | { |
1743 | | // use unscaled B predictor as A predictor |
1744 | | |
1745 | 8.91k | logtrace(LogMotion,"copy the same-POC B candidate as additional A candidate\n"); |
1746 | | |
1747 | 8.91k | out_availableFlagLXN[A]=1; |
1748 | 8.91k | out_mvLXN[A] = out_mvLXN[B]; |
1749 | 8.91k | refIdxA = refIdxB; |
1750 | 8.91k | } |
1751 | | |
1752 | | // 5. |
1753 | | |
1754 | | // If no A predictor, we output the unscaled B as the A predictor (above) |
1755 | | // and also add a scaled B predictor here. |
1756 | | // If there is (probably) an A predictor, no differing-POC B predictor is generated. |
1757 | 331k | if (isScaledFlagLX==0) { |
1758 | 12.0k | out_availableFlagLXN[B]=0; |
1759 | | |
1760 | 32.8k | for (int k=0 ; k<=2 && out_availableFlagLXN[B]==0 ; k++) { |
1761 | 20.7k | int refPicList=-1; |
1762 | | |
1763 | 20.7k | if (availableB[k]) { |
1764 | 9.46k | int Y=1-X; |
1765 | | |
1766 | 9.46k | const PBMotion& vi = img->get_mv_info(xB[k],yB[k]); |
1767 | | |
1768 | 9.46k | if (vi.predFlag[X]==1 && |
1769 | 8.34k | shdr->LongTermRefPic[X][refIdxLX] == shdr->LongTermRefPic[X][ vi.refIdx[X] ]) { |
1770 | 8.26k | out_availableFlagLXN[B]=1; |
1771 | 8.26k | out_mvLXN[B] = vi.mv[X]; |
1772 | 8.26k | refIdxB = vi.refIdx[X]; |
1773 | 8.26k | refPicList = X; |
1774 | 8.26k | } |
1775 | 1.20k | else if (vi.predFlag[Y]==1 && |
1776 | 1.13k | shdr->LongTermRefPic[X][refIdxLX] == shdr->LongTermRefPic[Y][ vi.refIdx[Y] ]) { |
1777 | 1.08k | out_availableFlagLXN[B]=1; |
1778 | 1.08k | out_mvLXN[B] = vi.mv[Y]; |
1779 | 1.08k | refIdxB = vi.refIdx[Y]; |
1780 | 1.08k | refPicList = Y; |
1781 | 1.08k | } |
1782 | 9.46k | } |
1783 | | |
1784 | 20.7k | if (out_availableFlagLXN[B]==1) { |
1785 | 9.35k | if (refIdxB<0) { |
1786 | 0 | out_availableFlagLXN[0] = out_availableFlagLXN[1] = false; |
1787 | 0 | return; // error |
1788 | 0 | } |
1789 | | |
1790 | 9.35k | assert(refPicList>=0); |
1791 | 9.35k | assert(refIdxB>=0); |
1792 | | |
1793 | 9.35k | const de265_image* refPicB=ctx->get_image(shdr->RefPicList[refPicList][refIdxB ]); |
1794 | 9.35k | const de265_image* refPicX=ctx->get_image(shdr->RefPicList[X ][refIdxLX]); |
1795 | | |
1796 | 9.35k | int isLongTermB = shdr->LongTermRefPic[refPicList][refIdxB ]; |
1797 | 9.35k | int isLongTermX = shdr->LongTermRefPic[X ][refIdxLX]; |
1798 | | |
1799 | 9.35k | if (refPicB==nullptr || refPicX==nullptr) { |
1800 | 0 | img->decctx->add_warning(DE265_WARNING_NONEXISTING_REFERENCE_PICTURE_ACCESSED,false); |
1801 | 0 | img->integrity = INTEGRITY_DECODING_ERRORS; |
1802 | 0 | } |
1803 | 9.35k | else if (refPicB->PicOrderCntVal != refPicX->PicOrderCntVal && |
1804 | 567 | !isLongTermB && !isLongTermX) { |
1805 | 472 | int distB = img->PicOrderCntVal - refPicB->PicOrderCntVal; |
1806 | 472 | int distX = img->PicOrderCntVal - referenced_POC; |
1807 | | |
1808 | 472 | logtrace(LogMotion,"scale MVP B: B-POC:%d X-POC:%d\n",refPicB->PicOrderCntVal,refPicX->PicOrderCntVal); |
1809 | | |
1810 | 472 | if (!scale_mv(&out_mvLXN[B], out_mvLXN[B], distB, distX)) { |
1811 | 0 | ctx->add_warning(DE265_WARNING_INCORRECT_MOTION_VECTOR_SCALING, false); |
1812 | 0 | img->integrity = INTEGRITY_DECODING_ERRORS; |
1813 | 0 | } |
1814 | 472 | } |
1815 | 9.35k | } |
1816 | 20.7k | } |
1817 | 12.0k | } |
1818 | 331k | } |
1819 | | |
1820 | | |
1821 | | // 8.5.3.1.5 |
1822 | | void fill_luma_motion_vector_predictors(base_context* ctx, |
1823 | | const slice_segment_header* shdr, |
1824 | | de265_image* img, |
1825 | | int xC,int yC,int nCS,int xP,int yP, |
1826 | | int nPbW,int nPbH, int l, |
1827 | | int refIdx, int partIdx, |
1828 | | MotionVector out_mvpList[2]) |
1829 | 331k | { |
1830 | | // 8.5.3.1.6: derive two spatial vector predictors A (0) and B (1) |
1831 | | |
1832 | 331k | uint8_t availableFlagLXN[2]; |
1833 | 331k | MotionVector mvLXN[2]; |
1834 | | |
1835 | 331k | derive_spatial_luma_vector_prediction(ctx, img, shdr, xC,yC, nCS, xP,yP, |
1836 | 331k | nPbW,nPbH, l, refIdx, partIdx, |
1837 | 331k | availableFlagLXN, mvLXN); |
1838 | | |
1839 | | // 8.5.3.1.7: if we only have one spatial vector or both spatial vectors are the same, |
1840 | | // derive a temporal predictor |
1841 | | |
1842 | 331k | uint8_t availableFlagLXCol; |
1843 | 331k | MotionVector mvLXCol; |
1844 | | |
1845 | | |
1846 | 331k | if (availableFlagLXN[0] && |
1847 | 327k | availableFlagLXN[1] && |
1848 | 255k | (mvLXN[0].x != mvLXN[1].x || mvLXN[0].y != mvLXN[1].y)) { |
1849 | 167k | availableFlagLXCol = 0; |
1850 | 167k | } |
1851 | 163k | else { |
1852 | 163k | derive_temporal_luma_vector_prediction(ctx, img, shdr, |
1853 | 163k | xP,yP, nPbW,nPbH, refIdx,l, |
1854 | 163k | &mvLXCol, &availableFlagLXCol); |
1855 | 163k | } |
1856 | | |
1857 | | |
1858 | | // --- build candidate vector list with exactly two entries --- |
1859 | | |
1860 | 331k | int numMVPCandLX=0; |
1861 | | |
1862 | | // spatial predictor A |
1863 | | |
1864 | 331k | if (availableFlagLXN[0]) |
1865 | 327k | { |
1866 | 327k | out_mvpList[numMVPCandLX++] = mvLXN[0]; |
1867 | 327k | } |
1868 | | |
1869 | | // spatial predictor B (if not same as A) |
1870 | | |
1871 | 331k | if (availableFlagLXN[1] && |
1872 | 255k | (!availableFlagLXN[0] || // in case A in not available, but mvLXA initialized to same as mvLXB |
1873 | 255k | (mvLXN[0].x != mvLXN[1].x || mvLXN[0].y != mvLXN[1].y))) |
1874 | 168k | { |
1875 | 168k | out_mvpList[numMVPCandLX++] = mvLXN[1]; |
1876 | 168k | } |
1877 | | |
1878 | | // temporal predictor |
1879 | | |
1880 | 331k | if (availableFlagLXCol) |
1881 | 5.25k | { |
1882 | 5.25k | out_mvpList[numMVPCandLX++] = mvLXCol; |
1883 | 5.25k | } |
1884 | | |
1885 | | // fill with zero predictors |
1886 | | |
1887 | 492k | while (numMVPCandLX<2) { |
1888 | 161k | out_mvpList[numMVPCandLX].x = 0; |
1889 | 161k | out_mvpList[numMVPCandLX].y = 0; |
1890 | 161k | numMVPCandLX++; |
1891 | 161k | } |
1892 | | |
1893 | | |
1894 | 331k | assert(numMVPCandLX==2); |
1895 | 331k | } |
1896 | | |
1897 | | |
1898 | | MotionVector luma_motion_vector_prediction(base_context* ctx, |
1899 | | const slice_segment_header* shdr, |
1900 | | de265_image* img, |
1901 | | const PBMotionCoding& motion, |
1902 | | int xC,int yC,int nCS,int xP,int yP, |
1903 | | int nPbW,int nPbH, int l, |
1904 | | int refIdx, int partIdx) |
1905 | 331k | { |
1906 | 331k | MotionVector mvpList[2]; |
1907 | | |
1908 | 331k | fill_luma_motion_vector_predictors(ctx, shdr, img, |
1909 | 331k | xC,yC,nCS,xP,yP, |
1910 | 331k | nPbW, nPbH, l, refIdx, partIdx, |
1911 | 331k | mvpList); |
1912 | | |
1913 | | // select predictor according to mvp_lX_flag |
1914 | | |
1915 | 331k | return mvpList[ l ? motion.mvp_l1_flag : motion.mvp_l0_flag ]; |
1916 | 331k | } |
1917 | | |
1918 | | |
1919 | | #if DE265_LOG_TRACE |
1920 | | void logMV(int x0,int y0,int nPbW,int nPbH, const char* mode,const PBMotion* mv) |
1921 | | { |
1922 | | int pred0 = mv->predFlag[0]; |
1923 | | int pred1 = mv->predFlag[1]; |
1924 | | |
1925 | | logtrace(LogMotion, |
1926 | | "*MV %d;%d [%d;%d] %s: (%d) %d;%d @%d (%d) %d;%d @%d\n", x0,y0,nPbW,nPbH,mode, |
1927 | | pred0, |
1928 | | pred0 ? mv->mv[0].x : 0,pred0 ? mv->mv[0].y : 0, pred0 ? mv->refIdx[0] : 0, |
1929 | | pred1, |
1930 | | pred1 ? mv->mv[1].x : 0,pred1 ? mv->mv[1].y : 0, pred1 ? mv->refIdx[1] : 0); |
1931 | | } |
1932 | | #else |
1933 | | #define logMV(x0,y0,nPbW,nPbH,mode,mv) |
1934 | | #endif |
1935 | | |
1936 | | |
1937 | | |
1938 | | // 8.5.3.1 |
1939 | | void motion_vectors_and_ref_indices(base_context* ctx, |
1940 | | const slice_segment_header* shdr, |
1941 | | de265_image* img, |
1942 | | const PBMotionCoding& motion, |
1943 | | int xC,int yC, int xB,int yB, int nCS, int nPbW,int nPbH, |
1944 | | int partIdx, |
1945 | | PBMotion* out_vi) |
1946 | 1.09M | { |
1947 | | //slice_segment_header* shdr = tctx->shdr; |
1948 | | |
1949 | 1.09M | int xP = xC+xB; |
1950 | 1.09M | int yP = yC+yB; |
1951 | | |
1952 | 1.09M | enum PredMode predMode = img->get_pred_mode(xC,yC); |
1953 | | |
1954 | 1.09M | if (predMode == MODE_SKIP || |
1955 | 568k | (predMode == MODE_INTER && motion.merge_flag)) |
1956 | 802k | { |
1957 | 802k | derive_luma_motion_merge_mode(ctx,shdr,img, |
1958 | 802k | xC,yC, xP,yP, nCS,nPbW,nPbH, partIdx, |
1959 | 802k | motion.merge_idx, out_vi); |
1960 | | |
1961 | 802k | logMV(xP,yP,nPbW,nPbH, "merge_mode", out_vi); |
1962 | 802k | } |
1963 | 289k | else { |
1964 | 289k | int mvdL[2][2]; |
1965 | 289k | MotionVector mvpL[2]; |
1966 | | |
1967 | 867k | for (int l=0;l<2;l++) { |
1968 | | // 1. |
1969 | | |
1970 | 578k | enum InterPredIdc inter_pred_idc = (enum InterPredIdc)motion.inter_pred_idc; |
1971 | | |
1972 | 578k | if (inter_pred_idc == PRED_BI || |
1973 | 494k | (inter_pred_idc == PRED_L0 && l==0) || |
1974 | 331k | (inter_pred_idc == PRED_L1 && l==1)) { |
1975 | 331k | out_vi->refIdx[l] = motion.refIdx[l]; |
1976 | 331k | out_vi->predFlag[l] = 1; |
1977 | 331k | } |
1978 | 247k | else { |
1979 | 247k | out_vi->refIdx[l] = 0; |
1980 | 247k | out_vi->predFlag[l] = 0; |
1981 | 247k | } |
1982 | | |
1983 | | // 2. |
1984 | | |
1985 | 578k | mvdL[l][0] = motion.mvd[l][0]; |
1986 | 578k | mvdL[l][1] = motion.mvd[l][1]; |
1987 | | |
1988 | | |
1989 | 578k | if (out_vi->predFlag[l]) { |
1990 | | // 3. |
1991 | | |
1992 | 331k | mvpL[l] = luma_motion_vector_prediction(ctx,shdr,img,motion, |
1993 | 331k | xC,yC,nCS,xP,yP, nPbW,nPbH, l, |
1994 | 331k | out_vi->refIdx[l], partIdx); |
1995 | | |
1996 | | // 4. |
1997 | | |
1998 | 331k | int32_t x = (mvpL[l].x + mvdL[l][0] + 0x10000) & 0xFFFF; |
1999 | 331k | int32_t y = (mvpL[l].y + mvdL[l][1] + 0x10000) & 0xFFFF; |
2000 | | |
2001 | 331k | out_vi->mv[l].x = (x>=0x8000) ? x-0x10000 : x; |
2002 | 331k | out_vi->mv[l].y = (y>=0x8000) ? y-0x10000 : y; |
2003 | 331k | } |
2004 | 578k | } |
2005 | | |
2006 | 289k | logMV(xP,yP,nPbW,nPbH, "mvp", out_vi); |
2007 | 289k | } |
2008 | 1.09M | } |
2009 | | |
2010 | | |
2011 | | // 8.5.3 |
2012 | | |
2013 | | /* xC/yC : CB position |
2014 | | xB/yB : position offset of the PB |
2015 | | nPbW/nPbH : size of PB |
2016 | | nCS : CB size |
2017 | | */ |
2018 | | void decode_prediction_unit(base_context* ctx, |
2019 | | const slice_segment_header* shdr, |
2020 | | de265_image* img, |
2021 | | const PBMotionCoding& motion, |
2022 | | int xC,int yC, int xB,int yB, int nCS, int nPbW,int nPbH, int partIdx) |
2023 | 1.09M | { |
2024 | 1.09M | logtrace(LogMotion,"decode_prediction_unit POC=%d %d;%d %dx%d\n", |
2025 | 1.09M | img->PicOrderCntVal, xC+xB,yC+yB, nPbW,nPbH); |
2026 | | |
2027 | | //slice_segment_header* shdr = tctx->shdr; |
2028 | | |
2029 | | // 1. |
2030 | | |
2031 | 1.09M | PBMotion vi; |
2032 | 1.09M | motion_vectors_and_ref_indices(ctx, shdr, img, motion, |
2033 | 1.09M | xC,yC, xB,yB, nCS, nPbW,nPbH, partIdx, &vi); |
2034 | | |
2035 | | // 2. |
2036 | | |
2037 | 1.09M | generate_inter_prediction_samples(ctx,shdr, img, xC,yC, xB,yB, nCS, nPbW,nPbH, &vi); |
2038 | | |
2039 | | |
2040 | 1.09M | img->set_mv_info(xC+xB,yC+yB,nPbW,nPbH, vi); |
2041 | 1.09M | } |