| rev |
line source |
|
nengel@2
|
1 #include "h264_types.h"
|
|
nengel@2
|
2 #include "h264_data.h"
|
|
nengel@2
|
3
|
|
nengel@2
|
4 static inline void mc_dir_part(MBRecContext *d, MBRecState *mrs, H264Mb *m, DecodedPicture *pic, int n, int square,
|
|
nengel@2
|
5 int chroma_height, int delta, int list,uint8_t *dest_y,
|
|
nengel@2
|
6 uint8_t *dest_cb, uint8_t *dest_cr, int src_x_offset, int src_y_offset,
|
|
nengel@2
|
7 qpel_mc_func *qpix_op, h264_chroma_mc_func chroma_op){
|
|
nengel@2
|
8 const int mx= mrs->mv_cache[list][ scan8[n] ][0] + src_x_offset*8;
|
|
nengel@2
|
9 const int my= mrs->mv_cache[list][ scan8[n] ][1] + src_y_offset*8;
|
|
nengel@2
|
10 const int luma_xy= (mx&3) + ((my&3)<<2);
|
|
nengel@2
|
11 const int pic_width = 16*d->mb_width;
|
|
nengel@2
|
12 const int pic_height = 16*d->mb_height;
|
|
nengel@2
|
13
|
|
nengel@2
|
14 uint8_t *src_y, *src_cb, *src_cr;
|
|
nengel@2
|
15 int ymx= mx>>2;
|
|
nengel@2
|
16 int ymy= my>>2;
|
|
nengel@2
|
17 int cmy= my>>3;
|
|
nengel@2
|
18 int cmx= mx>>3;
|
|
nengel@2
|
19
|
|
nengel@2
|
20 //truncate the motion vectors references
|
|
nengel@2
|
21 if(ymy>= pic_height+2){
|
|
nengel@2
|
22 ymy=pic_height+1;
|
|
nengel@2
|
23 }else if(ymy <=-19){
|
|
nengel@2
|
24 ymy=-18;
|
|
nengel@2
|
25 }
|
|
nengel@2
|
26 if(ymx>= pic_width+2){
|
|
nengel@2
|
27 ymx= pic_width+1;
|
|
nengel@2
|
28 }else if(ymx<=-19){
|
|
nengel@2
|
29 ymx=-19;
|
|
nengel@2
|
30 }
|
|
nengel@2
|
31
|
|
nengel@2
|
32 src_y = pic->data[0] + ymx + ymy*d->linesize;
|
|
nengel@2
|
33 qpix_op[luma_xy](dest_y, src_y, d->linesize); //FIXME try variable height perhaps?
|
|
nengel@2
|
34 if(!square){
|
|
nengel@2
|
35 qpix_op[luma_xy](dest_y + delta, src_y + delta, d->linesize);
|
|
nengel@2
|
36 }
|
|
nengel@2
|
37
|
|
nengel@2
|
38 if(cmy >= pic_height>>1){
|
|
nengel@2
|
39 cmy = (pic_height>>1) -1;
|
|
nengel@2
|
40 }else if(cmy<=-9){
|
|
nengel@2
|
41 cmy=-8;
|
|
nengel@2
|
42 }
|
|
nengel@2
|
43 if(cmx >= pic_width>>1){
|
|
nengel@2
|
44 cmx = (pic_width>>1) -1;
|
|
nengel@2
|
45 }else if(cmx<=-9){
|
|
nengel@2
|
46 cmx=-8;
|
|
nengel@2
|
47 }
|
|
nengel@2
|
48
|
|
nengel@2
|
49 src_cb= pic->data[1] + cmx + cmy*d->uvlinesize;
|
|
nengel@2
|
50 src_cr= pic->data[2] + cmx + cmy*d->uvlinesize;
|
|
nengel@2
|
51
|
|
nengel@2
|
52 chroma_op(dest_cb, src_cb, d->uvlinesize, chroma_height, mx&7, my&7);
|
|
nengel@2
|
53 chroma_op(dest_cr, src_cr, d->uvlinesize, chroma_height, mx&7, my&7);
|
|
nengel@2
|
54 }
|
|
nengel@2
|
55
|
|
nengel@2
|
56 static inline void mc_part_std(MBRecContext *d, MBRecState *mrs, H264Slice *s, H264Mb *m, int n, int square, int chroma_height, int delta,
|
|
nengel@2
|
57 uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr,
|
|
nengel@2
|
58 int x_offset, int y_offset,
|
|
nengel@2
|
59 qpel_mc_func *qpix_put, h264_chroma_mc_func chroma_put,
|
|
nengel@2
|
60 qpel_mc_func *qpix_avg, h264_chroma_mc_func chroma_avg,
|
|
nengel@2
|
61 int list0, int list1){
|
|
nengel@2
|
62 qpel_mc_func *qpix_op= qpix_put;
|
|
nengel@2
|
63 h264_chroma_mc_func chroma_op= chroma_put;
|
|
nengel@2
|
64
|
|
nengel@2
|
65 dest_y += 2*x_offset + 2*y_offset*d-> linesize;
|
|
nengel@2
|
66 dest_cb += x_offset + y_offset*d->uvlinesize;
|
|
nengel@2
|
67 dest_cr += x_offset + y_offset*d->uvlinesize;
|
|
nengel@2
|
68 x_offset += 8*m->mb_x;
|
|
nengel@2
|
69 y_offset += 8*m->mb_y;
|
|
nengel@2
|
70
|
|
nengel@2
|
71 if(list0){
|
|
nengel@2
|
72 DecodedPicture *ref= s->dp_ref_list[0][ mrs->ref_cache[0][ scan8[n] ] ];
|
|
nengel@2
|
73 mc_dir_part(d, mrs, m, ref, n, square, chroma_height, delta, 0,
|
|
nengel@2
|
74 dest_y, dest_cb, dest_cr, x_offset, y_offset, qpix_op, chroma_op);
|
|
nengel@2
|
75
|
|
nengel@2
|
76 qpix_op= qpix_avg;
|
|
nengel@2
|
77 chroma_op= chroma_avg;
|
|
nengel@2
|
78 }
|
|
nengel@2
|
79
|
|
nengel@2
|
80 if(list1){
|
|
nengel@2
|
81 DecodedPicture *ref= s->dp_ref_list[1][ mrs->ref_cache[1][ scan8[n] ] ];
|
|
nengel@2
|
82 mc_dir_part(d, mrs, m, ref, n, square, chroma_height, delta, 1,
|
|
nengel@2
|
83 dest_y, dest_cb, dest_cr, x_offset, y_offset, qpix_op, chroma_op);
|
|
nengel@2
|
84 }
|
|
nengel@2
|
85 }
|
|
nengel@2
|
86
|
|
nengel@2
|
87 static inline void mc_part_weighted(MBRecContext *d, MBRecState *mrs, H264Slice *s, H264Mb *m, int n, int square, int chroma_height, int delta,
|
|
nengel@2
|
88 uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr,
|
|
nengel@2
|
89 int x_offset, int y_offset,
|
|
nengel@2
|
90 qpel_mc_func *qpix_put, h264_chroma_mc_func chroma_put,
|
|
nengel@2
|
91 h264_weight_func luma_weight_op, h264_weight_func chroma_weight_op,
|
|
nengel@2
|
92 h264_biweight_func luma_weight_avg, h264_biweight_func chroma_weight_avg,
|
|
nengel@2
|
93 int list0, int list1){
|
|
nengel@2
|
94 dest_y += 2*x_offset + 2*y_offset*d-> linesize;
|
|
nengel@2
|
95 dest_cb += x_offset + y_offset*d->uvlinesize;
|
|
nengel@2
|
96 dest_cr += x_offset + y_offset*d->uvlinesize;
|
|
nengel@2
|
97 x_offset += 8*m->mb_x;
|
|
nengel@2
|
98 y_offset += 8*m->mb_y;
|
|
nengel@2
|
99
|
|
nengel@2
|
100 if(list0 && list1){
|
|
nengel@2
|
101 /* don't optimize for luma-only case, since B-frames usually
|
|
nengel@2
|
102 * use implicit weights => chroma too. */
|
|
nengel@2
|
103 uint8_t *tmp_y = d->scratchpad_y + 2*x_offset +16 ;
|
|
nengel@2
|
104 uint8_t *tmp_cb = d->scratchpad_cb + x_offset + 8;
|
|
nengel@2
|
105 uint8_t *tmp_cr = d->scratchpad_cr + x_offset + 8;
|
|
nengel@2
|
106
|
|
nengel@2
|
107 /*
|
|
nengel@2
|
108 uint8_t *tmp_cb = d->scratchpad;
|
|
nengel@2
|
109 uint8_t *tmp_cr = d->scratchpad + 8;
|
|
nengel@2
|
110 uint8_t *tmp_y = d->scratchpad + 8*d->uvlinesize;*/
|
|
nengel@2
|
111 int refn0 = mrs->ref_cache[0][ scan8[n] ];
|
|
nengel@2
|
112 int refn1 = mrs->ref_cache[1][ scan8[n] ];
|
|
nengel@2
|
113
|
|
nengel@2
|
114 mc_dir_part(d, mrs, m, s->dp_ref_list[0][refn0], n, square, chroma_height, delta, 0,
|
|
nengel@2
|
115 dest_y, dest_cb, dest_cr, x_offset, y_offset, qpix_put, chroma_put);
|
|
nengel@2
|
116 mc_dir_part(d, mrs, m, s->dp_ref_list[1][refn1], n, square, chroma_height, delta, 1,
|
|
nengel@2
|
117 tmp_y, tmp_cb, tmp_cr, x_offset, y_offset, qpix_put, chroma_put);
|
|
nengel@2
|
118
|
|
nengel@2
|
119 if(s->use_weight == 2){
|
|
nengel@2
|
120 int weight0 = s->implicit_weight[refn0][refn1][m->mb_y&1];
|
|
nengel@2
|
121 int weight1 = 64 - weight0;
|
|
nengel@2
|
122 luma_weight_avg( dest_y, tmp_y, d-> linesize, 5, weight0, weight1, 0);
|
|
nengel@2
|
123 chroma_weight_avg(dest_cb, tmp_cb, d->uvlinesize, 5, weight0, weight1, 0);
|
|
nengel@2
|
124 chroma_weight_avg(dest_cr, tmp_cr, d->uvlinesize, 5, weight0, weight1, 0);
|
|
nengel@2
|
125 }else{
|
|
nengel@2
|
126 luma_weight_avg(dest_y, tmp_y, d->linesize, s->luma_log2_weight_denom,
|
|
nengel@2
|
127 s->luma_weight[refn0][0][0] , s->luma_weight[refn1][1][0],
|
|
nengel@2
|
128 s->luma_weight[refn0][0][1] + s->luma_weight[refn1][1][1]);
|
|
nengel@2
|
129 chroma_weight_avg(dest_cb, tmp_cb, d->uvlinesize, s->chroma_log2_weight_denom,
|
|
nengel@2
|
130 s->chroma_weight[refn0][0][0][0] , s->chroma_weight[refn1][1][0][0],
|
|
nengel@2
|
131 s->chroma_weight[refn0][0][0][1] + s->chroma_weight[refn1][1][0][1]);
|
|
nengel@2
|
132 chroma_weight_avg(dest_cr, tmp_cr, d->uvlinesize, s->chroma_log2_weight_denom,
|
|
nengel@2
|
133 s->chroma_weight[refn0][0][1][0] , s->chroma_weight[refn1][1][1][0],
|
|
nengel@2
|
134 s->chroma_weight[refn0][0][1][1] + s->chroma_weight[refn1][1][1][1]);
|
|
nengel@2
|
135 }
|
|
nengel@2
|
136 }else{
|
|
nengel@2
|
137 int list = list1 ? 1 : 0;
|
|
nengel@2
|
138 int refn = mrs->ref_cache[list][ scan8[n] ];
|
|
nengel@2
|
139 DecodedPicture *ref= s->dp_ref_list[list][refn];
|
|
nengel@2
|
140 mc_dir_part(d, mrs, m, ref, n, square, chroma_height, delta, list,
|
|
nengel@2
|
141 dest_y, dest_cb, dest_cr, x_offset, y_offset, qpix_put, chroma_put);
|
|
nengel@2
|
142
|
|
nengel@2
|
143 luma_weight_op(dest_y, d->linesize, s->luma_log2_weight_denom,
|
|
nengel@2
|
144 s->luma_weight[refn][list][0], s->luma_weight[refn][list][1]);
|
|
nengel@2
|
145 if(s->use_weight_chroma){
|
|
nengel@2
|
146 chroma_weight_op(dest_cb, d->uvlinesize, s->chroma_log2_weight_denom,
|
|
nengel@2
|
147 s->chroma_weight[refn][list][0][0], s->chroma_weight[refn][list][0][1]);
|
|
nengel@2
|
148 chroma_weight_op(dest_cr, d->uvlinesize, s->chroma_log2_weight_denom,
|
|
nengel@2
|
149 s->chroma_weight[refn][list][1][0], s->chroma_weight[refn][list][1][1]);
|
|
nengel@2
|
150 }
|
|
nengel@2
|
151 }
|
|
nengel@2
|
152 }
|
|
nengel@2
|
153
|
|
nengel@2
|
154 static inline void mc_part(MBRecContext *d, MBRecState *mrs, H264Slice *s, H264Mb *m, int n, int square, int chroma_height, int delta,
|
|
nengel@2
|
155 uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr,
|
|
nengel@2
|
156 int x_offset, int y_offset,
|
|
nengel@2
|
157 qpel_mc_func *qpix_put, h264_chroma_mc_func chroma_put,
|
|
nengel@2
|
158 qpel_mc_func *qpix_avg, h264_chroma_mc_func chroma_avg,
|
|
nengel@2
|
159 h264_weight_func *weight_op, h264_biweight_func *weight_avg,
|
|
nengel@2
|
160 int list0, int list1){
|
|
nengel@2
|
161 if((s->use_weight==2 && list0 && list1
|
|
nengel@2
|
162 && (s->implicit_weight[ mrs->ref_cache[0][scan8[n]] ][ mrs->ref_cache[1][scan8[n]] ][m->mb_y&1] != 32))
|
|
nengel@2
|
163 || s->use_weight==1)
|
|
nengel@2
|
164 mc_part_weighted(d, mrs, s, m, n, square, chroma_height, delta, dest_y, dest_cb, dest_cr,
|
|
nengel@2
|
165 x_offset, y_offset, qpix_put, chroma_put,
|
|
nengel@2
|
166 weight_op[0], weight_op[3], weight_avg[0], weight_avg[3], list0, list1);
|
|
nengel@2
|
167 else
|
|
nengel@2
|
168 mc_part_std(d, mrs, s, m, n, square, chroma_height, delta, dest_y, dest_cb, dest_cr,
|
|
nengel@2
|
169 x_offset, y_offset, qpix_put, chroma_put, qpix_avg, chroma_avg, list0, list1);
|
|
nengel@2
|
170 }
|
|
nengel@2
|
171
|
|
nengel@2
|
172 static inline void prefetch_motion(MBRecContext *d, MBRecState *mrs, H264Slice *s, H264Mb *m, int list){
|
|
nengel@2
|
173 /* fetch pixels for estimated mv 4 macroblocks ahead
|
|
nengel@2
|
174 * optimized for 64byte cache lines */
|
|
nengel@2
|
175 const int refn = mrs->ref_cache[list][scan8[0]];
|
|
nengel@2
|
176
|
|
nengel@2
|
177 if(refn >= 0){
|
|
nengel@2
|
178 const int mx= (mrs->mv_cache[list][scan8[0]][0]>>2) + 16*m->mb_x + 8;
|
|
nengel@2
|
179 const int my= (mrs->mv_cache[list][scan8[0]][1]>>2) + 16*m->mb_y;
|
|
nengel@2
|
180 uint8_t **src= s->dp_ref_list[list][refn]->data;
|
|
nengel@2
|
181 int off= mx + (my + (m->mb_x&3)*4)*d->linesize + 64;
|
|
nengel@2
|
182
|
|
nengel@2
|
183 d->dsp.prefetch(src[0]+off, d->linesize, 4);
|
|
nengel@2
|
184 off= (mx>>1) + ((my>>1) + (m->mb_x&7))*d->uvlinesize + 64;
|
|
nengel@2
|
185 d->dsp.prefetch(src[1]+off, src[2]-src[1], 2);
|
|
nengel@2
|
186 }
|
|
nengel@2
|
187 }
|
|
nengel@2
|
188
|
|
nengel@2
|
189 void hl_motion(MBRecContext *d, MBRecState *mrs, H264Slice *s, H264Mb *m, uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr,
|
|
nengel@2
|
190 qpel_mc_func (*qpix_put)[16], h264_chroma_mc_func (*chroma_put),
|
|
nengel@2
|
191 qpel_mc_func (*qpix_avg)[16], h264_chroma_mc_func (*chroma_avg),
|
|
nengel@2
|
192 h264_weight_func *weight_op, h264_biweight_func *weight_avg){
|
|
nengel@2
|
193 const int mb_type= m->mb_type;
|
|
nengel@2
|
194 assert(IS_INTER(mb_type));
|
|
nengel@2
|
195
|
|
nengel@2
|
196 if (mb_type & MB_TYPE_L0)
|
|
nengel@2
|
197 prefetch_motion(d, mrs, s, m, 0);
|
|
nengel@2
|
198 if (mb_type & MB_TYPE_L1)
|
|
nengel@2
|
199 prefetch_motion(d, mrs, s, m, 1);
|
|
nengel@2
|
200
|
|
nengel@2
|
201 if(IS_16X16(mb_type)){
|
|
nengel@2
|
202 mc_part(d, mrs, s, m, 0, 1, 8, 0, dest_y, dest_cb, dest_cr, 0, 0,
|
|
nengel@2
|
203 qpix_put[0], chroma_put[0], qpix_avg[0], chroma_avg[0],
|
|
nengel@2
|
204 weight_op, weight_avg,
|
|
nengel@2
|
205 IS_DIR(mb_type, 0, 0), IS_DIR(mb_type, 0, 1));
|
|
nengel@2
|
206 }else if(IS_16X8(mb_type)){
|
|
nengel@2
|
207 mc_part(d, mrs, s, m, 0, 0, 4, 8, dest_y, dest_cb, dest_cr, 0, 0,
|
|
nengel@2
|
208 qpix_put[1], chroma_put[0], qpix_avg[1], chroma_avg[0],
|
|
nengel@2
|
209 &weight_op[1], &weight_avg[1],
|
|
nengel@2
|
210 IS_DIR(mb_type, 0, 0), IS_DIR(mb_type, 0, 1));
|
|
nengel@2
|
211 mc_part(d, mrs, s, m, 8, 0, 4, 8, dest_y, dest_cb, dest_cr, 0, 4,
|
|
nengel@2
|
212 qpix_put[1], chroma_put[0], qpix_avg[1], chroma_avg[0],
|
|
nengel@2
|
213 &weight_op[1], &weight_avg[1],
|
|
nengel@2
|
214 IS_DIR(mb_type, 1, 0), IS_DIR(mb_type, 1, 1));
|
|
nengel@2
|
215 }else if(IS_8X16(mb_type)){
|
|
nengel@2
|
216 mc_part(d, mrs, s, m, 0, 0, 8, 8*d->linesize, dest_y, dest_cb, dest_cr, 0, 0,
|
|
nengel@2
|
217 qpix_put[1], chroma_put[1], qpix_avg[1], chroma_avg[1],
|
|
nengel@2
|
218 &weight_op[2], &weight_avg[2],
|
|
nengel@2
|
219 IS_DIR(mb_type, 0, 0), IS_DIR(mb_type, 0, 1));
|
|
nengel@2
|
220 mc_part(d, mrs, s, m, 4, 0, 8, 8*d->linesize, dest_y, dest_cb, dest_cr, 4, 0,
|
|
nengel@2
|
221 qpix_put[1], chroma_put[1], qpix_avg[1], chroma_avg[1],
|
|
nengel@2
|
222 &weight_op[2], &weight_avg[2],
|
|
nengel@2
|
223 IS_DIR(mb_type, 1, 0), IS_DIR(mb_type, 1, 1));
|
|
nengel@2
|
224 }else{
|
|
nengel@2
|
225 int i;
|
|
nengel@2
|
226
|
|
nengel@2
|
227 assert(IS_8X8(mb_type));
|
|
nengel@2
|
228
|
|
nengel@2
|
229 for(i=0; i<4; i++){
|
|
nengel@2
|
230 const int sub_mb_type= m->sub_mb_type[i];
|
|
nengel@2
|
231 const int n= 4*i;
|
|
nengel@2
|
232 int x_offset= (i&1)<<2;
|
|
nengel@2
|
233 int y_offset= (i&2)<<1;
|
|
nengel@2
|
234
|
|
nengel@2
|
235 if(IS_SUB_8X8(sub_mb_type)){
|
|
nengel@2
|
236 mc_part(d, mrs, s, m, n, 1, 4, 0, dest_y, dest_cb, dest_cr, x_offset, y_offset,
|
|
nengel@2
|
237 qpix_put[1], chroma_put[1], qpix_avg[1], chroma_avg[1],
|
|
nengel@2
|
238 &weight_op[3], &weight_avg[3],
|
|
nengel@2
|
239 IS_DIR(sub_mb_type, 0, 0), IS_DIR(sub_mb_type, 0, 1));
|
|
nengel@2
|
240 }else if(IS_SUB_8X4(sub_mb_type)){
|
|
nengel@2
|
241 mc_part(d, mrs, s, m, n, 0, 2, 4, dest_y, dest_cb, dest_cr, x_offset, y_offset,
|
|
nengel@2
|
242 qpix_put[2], chroma_put[1], qpix_avg[2], chroma_avg[1],
|
|
nengel@2
|
243 &weight_op[4], &weight_avg[4],
|
|
nengel@2
|
244 IS_DIR(sub_mb_type, 0, 0), IS_DIR(sub_mb_type, 0, 1));
|
|
nengel@2
|
245 mc_part(d, mrs, s, m, n+2, 0, 2, 4, dest_y, dest_cb, dest_cr, x_offset, y_offset+2,
|
|
nengel@2
|
246 qpix_put[2], chroma_put[1], qpix_avg[2], chroma_avg[1],
|
|
nengel@2
|
247 &weight_op[4], &weight_avg[4],
|
|
nengel@2
|
248 IS_DIR(sub_mb_type, 0, 0), IS_DIR(sub_mb_type, 0, 1));
|
|
nengel@2
|
249 }else if(IS_SUB_4X8(sub_mb_type)){
|
|
nengel@2
|
250 mc_part(d, mrs, s, m, n, 0, 4, 4*d->linesize, dest_y, dest_cb, dest_cr, x_offset, y_offset,
|
|
nengel@2
|
251 qpix_put[2], chroma_put[2], qpix_avg[2], chroma_avg[2],
|
|
nengel@2
|
252 &weight_op[5], &weight_avg[5],
|
|
nengel@2
|
253 IS_DIR(sub_mb_type, 0, 0), IS_DIR(sub_mb_type, 0, 1));
|
|
nengel@2
|
254 mc_part(d, mrs, s, m, n+1, 0, 4, 4*d->linesize, dest_y, dest_cb, dest_cr, x_offset+2, y_offset,
|
|
nengel@2
|
255 qpix_put[2], chroma_put[2], qpix_avg[2], chroma_avg[2],
|
|
nengel@2
|
256 &weight_op[5], &weight_avg[5],
|
|
nengel@2
|
257 IS_DIR(sub_mb_type, 0, 0), IS_DIR(sub_mb_type, 0, 1));
|
|
nengel@2
|
258 }else{
|
|
nengel@2
|
259 int j;
|
|
nengel@2
|
260 assert(IS_SUB_4X4(sub_mb_type));
|
|
nengel@2
|
261 for(j=0; j<4; j++){
|
|
nengel@2
|
262 int sub_x_offset= x_offset + 2*(j&1);
|
|
nengel@2
|
263 int sub_y_offset= y_offset + (j&2);
|
|
nengel@2
|
264 mc_part(d, mrs, s, m, n+j, 1, 2, 0, dest_y, dest_cb, dest_cr, sub_x_offset, sub_y_offset,
|
|
nengel@2
|
265 qpix_put[2], chroma_put[2], qpix_avg[2], chroma_avg[2],
|
|
nengel@2
|
266 &weight_op[6], &weight_avg[6],
|
|
nengel@2
|
267 IS_DIR(sub_mb_type, 0, 0), IS_DIR(sub_mb_type, 0, 1));
|
|
nengel@2
|
268 }
|
|
nengel@2
|
269 }
|
|
nengel@2
|
270 }
|
|
nengel@2
|
271 }
|
|
nengel@2
|
272 }
|