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