1
2 #ifdef HAVE_CONFIG_H
3 #include "config.h"
4 #endif
5 #include <schroedinger/schro.h>
6 #include "schroorc.h"
7 #include <string.h>
8
9
10 int
schro_metric_absdiff_u8(uint8_t * a,int a_stride,uint8_t * b,int b_stride,int width,int height)11 schro_metric_absdiff_u8 (uint8_t * a, int a_stride, uint8_t * b, int b_stride,
12 int width, int height)
13 {
14 uint32_t metric = 0;
15
16 if (height == 8 && width == 8) {
17 orc_sad_8x8_u8 (&metric, a, a_stride, b, b_stride);
18 } else if (height == 12 && width == 12) {
19 orc_sad_12x12_u8 (&metric, a, a_stride, b, b_stride);
20 } else if (width == 16) {
21 orc_sad_16xn_u8 (&metric, a, a_stride, b, b_stride, height);
22 } else if (width == 32) {
23 orc_sad_32xn_u8 (&metric, a, a_stride, b, b_stride, height);
24 } else {
25 orc_sad_nxm_u8 (&metric, a, a_stride, b, b_stride, width, height);
26 }
27
28 return metric;
29 }
30
31 void
schro_metric_scan_do_scan(SchroMetricScan * scan)32 schro_metric_scan_do_scan (SchroMetricScan * scan)
33 {
34 SchroFrameData *fd;
35 SchroFrameData *fd_ref;
36 int i, j;
37
38 SCHRO_ASSERT (scan->ref_x + scan->block_width + scan->scan_width - 1 <=
39 scan->frame->width + scan->frame->extension);
40 SCHRO_ASSERT (scan->ref_y + scan->block_height + scan->scan_height - 1 <=
41 scan->frame->height + scan->frame->extension);
42 SCHRO_ASSERT (scan->ref_x >= -scan->frame->extension);
43 SCHRO_ASSERT (scan->ref_y >= -scan->frame->extension);
44 SCHRO_ASSERT (scan->scan_width > 0);
45 SCHRO_ASSERT (scan->scan_height > 0);
46
47 /* do luma first */
48 fd = scan->frame->components + 0;
49 fd_ref = scan->ref_frame->components + 0;
50
51 if (scan->block_width == 8 && scan->block_height == 8) {
52 for (j = 0; j < scan->scan_height; j++) {
53 for (i = 0; i < scan->scan_width; i++) {
54 orc_sad_8x8_u8 (scan->metrics + i * scan->scan_height + j,
55 SCHRO_FRAME_DATA_GET_PIXEL_U8 (fd, scan->x, scan->y),
56 fd->stride,
57 SCHRO_FRAME_DATA_GET_PIXEL_U8 (fd_ref, scan->ref_x + i,
58 scan->ref_y + j), fd_ref->stride);
59 }
60 }
61 } else {
62 for (i = 0; i < scan->scan_width; i++) {
63 for (j = 0; j < scan->scan_height; j++) {
64 scan->metrics[i * scan->scan_height + j] =
65 schro_metric_absdiff_u8 (SCHRO_FRAME_DATA_GET_PIXEL_U8 (fd, scan->x,
66 scan->y), fd->stride, SCHRO_FRAME_DATA_GET_PIXEL_U8 (fd_ref,
67 scan->ref_x + i, scan->ref_y + j), fd_ref->stride,
68 scan->block_width, scan->block_height);
69 }
70 }
71 }
72 memset (scan->chroma_metrics, 0, sizeof (scan->chroma_metrics));
73 if (scan->use_chroma) {
74 /* now do chroma ME */
75 int skip_h = 1 << SCHRO_FRAME_FORMAT_H_SHIFT (scan->frame->format)
76 , skip_v = 1 << SCHRO_FRAME_FORMAT_V_SHIFT (scan->frame->format);
77 int x = scan->x / skip_h, y = scan->y / skip_v, ref_x =
78 scan->ref_x / skip_h, ref_y = scan->ref_y / skip_v;
79 int block_width = scan->block_width / skip_h, block_height =
80 scan->block_height / skip_v;
81 int scan_width = (scan->scan_width / skip_h) + (scan->scan_width % skip_h)
82 , scan_height =
83 (scan->scan_height / skip_v) + (scan->scan_height % skip_v);
84 uint32_t metrics[SCHRO_LIMIT_METRIC_SCAN * SCHRO_LIMIT_METRIC_SCAN];
85 int k;
86 for (k = 1; 3 > k; ++k) {
87 fd = scan->frame->components + k;
88 fd_ref = scan->ref_frame->components + k;
89 for (i = 0; i < scan_width; ++i) {
90 for (j = 0; j < scan_height; ++j) {
91 metrics[i * 2 * scan->scan_height + j * 2] =
92 schro_metric_absdiff_u8 (SCHRO_FRAME_DATA_GET_PIXEL_U8 (fd, x, y),
93 fd->stride, SCHRO_FRAME_DATA_GET_PIXEL_U8 (fd_ref, ref_x + i,
94 ref_y + j)
95 , fd_ref->stride, block_width, block_height);
96 if (skip_v > 1) {
97 metrics[i * 2 * scan->scan_height + 1 + j * 2] =
98 metrics[i * 2 * scan->scan_height + j * 2];
99 }
100 }
101 if (skip_h > 1) {
102 for (j = 0; j < scan->scan_height; ++j) {
103 metrics[(i * 2 + 1) * scan->scan_height + j] =
104 metrics[i * 2 * scan->scan_height + j];
105 }
106 }
107 }
108 for (j = 0; j < scan->scan_height; ++j) {
109 for (i = 0; i < scan->scan_width; ++i) {
110 scan->chroma_metrics[i * scan->scan_height + j] +=
111 metrics[i * scan->scan_height + j];
112 }
113 }
114 }
115 }
116 }
117
118
119 /* note that gravity_x and gravity_y should contain the seed MV
120 * we use to bias our search */
121 int
schro_metric_scan_get_min(SchroMetricScan * scan,int * dx,int * dy,uint32_t * chroma_error)122 schro_metric_scan_get_min (SchroMetricScan * scan, int *dx, int *dy,
123 uint32_t * chroma_error)
124 {
125 int i, j;
126 uint32_t min_metric;
127 uint32_t metric;
128 uint32_t chroma_metric;
129 uint32_t min_chroma_metric = 0;
130 uint32_t min_total_metric = 0;
131 uint32_t tmp;
132 int x, y;
133
134 SCHRO_ASSERT (scan->scan_width > 0);
135 SCHRO_ASSERT (scan->scan_height > 0);
136
137 i = scan->gravity_x + scan->x - scan->ref_x;
138 j = scan->gravity_y + scan->y - scan->ref_y;
139 min_metric = scan->metrics[j + i * scan->scan_height];
140 if (scan->use_chroma) {
141 min_chroma_metric = scan->chroma_metrics[j + i * scan->scan_height];
142 min_total_metric = min_metric + min_chroma_metric;
143 }
144
145 for (i = 0; i < scan->scan_width; i++) {
146 for (j = 0; j < scan->scan_height; j++) {
147 metric = scan->metrics[i * scan->scan_height + j];
148 chroma_metric = scan->chroma_metrics[i * scan->scan_height + j];
149 x = scan->ref_x + i - scan->x;
150 y = scan->ref_y + j - scan->y;
151 if (scan->use_chroma) {
152 tmp = metric + chroma_metric;
153 if (tmp < min_total_metric) {
154 min_total_metric = tmp;
155 min_metric = metric;
156 min_chroma_metric = chroma_metric;
157 *dx = x;
158 *dy = y;
159 }
160 } else {
161 if (metric < min_metric) {
162 min_metric = metric;
163 *dx = x;
164 *dy = y;
165 }
166 }
167 }
168 }
169 *chroma_error = min_chroma_metric;
170 return min_metric;
171 }
172
173
174 void
schro_metric_scan_setup(SchroMetricScan * scan,int dx,int dy,int dist,int use_chroma)175 schro_metric_scan_setup (SchroMetricScan * scan, int dx, int dy, int dist,
176 int use_chroma)
177 {
178 int xmin;
179 int xmax;
180 int ymin;
181 int ymax;
182 int xrange;
183 int yrange;
184
185 SCHRO_ASSERT (scan && scan->frame && scan->ref_frame && dist > 0);
186
187 xmin = MAX (-scan->block_width, scan->x + dx - dist);
188 xmax = MIN (scan->frame->width, scan->x + dx + dist);
189 ymin = MAX (-scan->block_height, scan->y + dy - dist);
190 ymax = MIN (scan->frame->height, scan->y + dy + dist);
191 xmin = MAX (xmin, -scan->frame->extension);
192 ymin = MAX (ymin, -scan->frame->extension);
193 xmax =
194 MIN (xmax,
195 scan->frame->width - scan->block_width + scan->frame->extension);
196 ymax =
197 MIN (ymax,
198 scan->frame->height - scan->block_height + scan->frame->extension);
199
200 xrange = xmax - xmin;
201 yrange = ymax - ymin;
202
203 /* sets ref_x and ref_y */
204 scan->ref_x = xmin;
205 scan->ref_y = ymin;
206
207 scan->scan_width = xrange + 1;
208 scan->scan_height = yrange + 1;
209
210 scan->use_chroma = use_chroma;
211
212 SCHRO_ASSERT (scan->scan_width <= SCHRO_LIMIT_METRIC_SCAN);
213 SCHRO_ASSERT (scan->scan_height <= SCHRO_LIMIT_METRIC_SCAN);
214 }
215
216
217
218 int
schro_metric_get(SchroFrameData * src1,SchroFrameData * src2,int width,int height)219 schro_metric_get (SchroFrameData * src1, SchroFrameData * src2, int width,
220 int height)
221 {
222 uint32_t metric = 0;
223
224 #if 0
225 SCHRO_ASSERT (src1->width >= width);
226 SCHRO_ASSERT (src1->height >= height);
227 SCHRO_ASSERT (src2->width >= width);
228 SCHRO_ASSERT (src2->height >= height);
229 #endif
230
231 if (height == 8 && width == 8) {
232 orc_sad_8x8_u8 (&metric,
233 src1->data, src1->stride, src2->data, src2->stride);
234 } else if (height == 12 && width == 12) {
235 orc_sad_12x12_u8 (&metric,
236 src1->data, src1->stride, src2->data, src2->stride);
237 } else if (width == 16) {
238 orc_sad_16xn_u8 (&metric,
239 src1->data, src1->stride, src2->data, src2->stride, height);
240 #if 0
241 } else if (width == 32) {
242 orc_sad_32xn_u8 (&metric,
243 src1->data, src1->stride, src2->data, src2->stride, height);
244 #endif
245 } else {
246 orc_sad_nxm_u8 (&metric,
247 src1->data, src1->stride, src2->data, src2->stride, width, height);
248 }
249
250 return metric;
251 }
252
253 int
schro_metric_get_dc(SchroFrameData * src,int value,int width,int height)254 schro_metric_get_dc (SchroFrameData * src, int value, int width, int height)
255 {
256 int i, j;
257 int metric = 0;
258 uint8_t *line;
259
260 SCHRO_ASSERT (src->width >= width);
261 SCHRO_ASSERT (src->height >= height);
262
263 for (j = 0; j < height; j++) {
264 line = SCHRO_FRAME_DATA_GET_LINE (src, j);
265 for (i = 0; i < width; i++) {
266 metric += abs (value - line[i]);
267 }
268 }
269 return metric;
270 }
271
272 int
schro_metric_get_biref(SchroFrameData * fd,SchroFrameData * src1,int weight1,SchroFrameData * src2,int weight2,int shift,int width,int height)273 schro_metric_get_biref (SchroFrameData * fd, SchroFrameData * src1,
274 int weight1, SchroFrameData * src2, int weight2, int shift, int width,
275 int height)
276 {
277 int i, j;
278 int metric = 0;
279 uint8_t *line;
280 uint8_t *src1_line;
281 uint8_t *src2_line;
282 int offset = (1 << (shift - 1));
283 int x;
284
285 #if 0
286 SCHRO_ASSERT (fd->width >= width);
287 SCHRO_ASSERT (fd->height >= height);
288 SCHRO_ASSERT (src1->width >= width);
289 SCHRO_ASSERT (src1->height >= height);
290 SCHRO_ASSERT (src2->width >= width);
291 SCHRO_ASSERT (src2->height >= height);
292 #endif
293
294 for (j = 0; j < height; j++) {
295 line = SCHRO_FRAME_DATA_GET_LINE (fd, j);
296 src1_line = SCHRO_FRAME_DATA_GET_LINE (src1, j);
297 src2_line = SCHRO_FRAME_DATA_GET_LINE (src2, j);
298 for (i = 0; i < width; i++) {
299 x = (src1_line[i] * weight1 + src2_line[i] * weight2 + offset) >> shift;
300 metric += abs (line[i] - x);
301 }
302 }
303 return metric;
304 }
305
306
307 static int
schro_frame_block_is_valid(SchroFrame * frame,int x,int y,int sx,int sy)308 schro_frame_block_is_valid (SchroFrame *frame, int x, int y, int sx, int sy)
309 {
310 #if 0
311 SCHRO_ERROR("block %d %d %d %d, frame %d %d %d %d",
312 x, y, x + sx, y + sy,
313 -frame->extension, -frame->extension,
314 frame->width + frame->extension,
315 frame->height + frame->extension);
316 #endif
317
318 if (x < -frame->extension || y < -frame->extension ||
319 x + sx > frame->width + frame->extension ||
320 y + sy > frame->height + frame->extension) {
321 SCHRO_ERROR("block %d %d %d %d, frame %d %d %d %d",
322 x, y, x + sx, y + sy,
323 -frame->extension, -frame->extension,
324 frame->width + frame->extension,
325 frame->height + frame->extension);
326 return FALSE;
327 }
328
329 return TRUE;
330 }
331
332 static int
schro_metric_block_sad_slow(SchroMetricInfo * info,int x,int y,int dx,int dy)333 schro_metric_block_sad_slow (SchroMetricInfo *info, int x, int y,
334 int dx, int dy)
335 {
336 int i,j;
337 int k;
338 SchroFrameData fd;
339 SchroFrameData fd_ref;
340 int metric = 0;
341
342 #if 0
343 SCHRO_ASSERT (schro_frame_block_is_valid (info->frame, x, y,
344 info->block_width, info->block_height));
345 SCHRO_ASSERT (schro_frame_block_is_valid (info->ref_frame, x + dx, y + dy,
346 info->block_width, info->block_height));
347 #endif
348 if (!schro_frame_block_is_valid (info->frame, x, y,
349 info->block_width[0], info->block_height[0])) return INT_MAX;
350 if (!schro_frame_block_is_valid (info->ref_frame, x + dx, y + dy,
351 info->block_width[0], info->block_height[0])) return INT_MAX;
352
353 for(k=0;k<3;k++){
354 int width, height;
355
356 schro_frame_get_subdata (info->frame, &fd, k,
357 x>>info->h_shift[k], y>>info->v_shift[k]);
358 schro_frame_get_subdata (info->ref_frame, &fd_ref, k,
359 (x + dx)>>info->h_shift[k], (y + dy)>>info->v_shift[k]);
360
361 width = MIN(fd.width, info->block_width[k]);
362 height = MIN(fd.height, info->block_height[k]);
363
364 for(j=0;j<height;j++){
365 uint8_t *line = SCHRO_FRAME_DATA_GET_LINE (&fd, j);
366 uint8_t *line_ref = SCHRO_FRAME_DATA_GET_LINE (&fd_ref, j);
367
368 for(i=0;i<width;i++){
369 metric += abs (line[i] - line_ref[i]);
370 }
371 }
372 }
373
374 return metric;
375 }
376
377
378
379
380 void
schro_metric_info_init(SchroMetricInfo * info,SchroFrame * frame,SchroFrame * ref_frame,int block_width,int block_height)381 schro_metric_info_init (SchroMetricInfo *info, SchroFrame *frame,
382 SchroFrame *ref_frame, int block_width, int block_height)
383 {
384 memset (info, 0, sizeof(*info));
385
386 info->frame = frame;
387 info->ref_frame = ref_frame;
388
389 info->block_width[0] = block_width;
390 info->block_height[0] = block_height;
391 info->h_shift[0] = 0;
392 info->v_shift[0] = 0;
393 info->h_shift[1] = SCHRO_FRAME_FORMAT_H_SHIFT (frame->format);
394 info->v_shift[1] = SCHRO_FRAME_FORMAT_V_SHIFT (frame->format);
395 info->block_width[1] = block_width >>
396 SCHRO_FRAME_FORMAT_H_SHIFT (frame->format);
397 info->block_height[1] = block_height >>
398 SCHRO_FRAME_FORMAT_V_SHIFT (frame->format);
399 info->h_shift[2] = SCHRO_FRAME_FORMAT_H_SHIFT (frame->format);
400 info->v_shift[2] = SCHRO_FRAME_FORMAT_V_SHIFT (frame->format);
401 info->block_width[2] = info->block_width[1];
402 info->block_height[2] = info->block_height[1];
403
404 info->metric = schro_metric_block_sad_slow;
405 info->metric_right = schro_metric_block_sad_slow;
406 info->metric_bottom = schro_metric_block_sad_slow;
407 info->metric_corner = schro_metric_block_sad_slow;
408 }
409
schro_metric_fast_block(SchroMetricInfo * info,int x,int y,int dx,int dy)410 int schro_metric_fast_block (SchroMetricInfo *info, int x, int y,
411 int dx, int dy)
412 {
413 return info->metric (info, x, y, dx, dy);
414 }
415
416