1 
2 #ifdef HAVE_CONFIG_H
3 #include "config.h"
4 #endif
5 #include <schroedinger/schro.h>
6 #include <string.h>
7 #include <limits.h>
8 
9 /***
10 struct _SchroHierBm {
11   int                ref_count;
12   int                ref;
13   int                hierarchy_levels;
14   SchroParams*       params;
15   SchroFrame**       downsampled_src;
16   SchroFrame**       downsampled_ref;
17   SchroMotionField** downsampled_mf;
18 };
19 ***/
20 
21 static int get_hier_levels (SchroHierBm * schro_hbm);
22 static int schro_hbm_ref_number (SchroHierBm * schro_hbm);
23 
24 
25 SchroHierBm *
schro_hbm_new(SchroEncoderFrame * frame,int ref)26 schro_hbm_new (SchroEncoderFrame * frame, int ref)
27 {
28   int i;
29   SchroEncoderFrame *ref_frame = frame->ref_frame[ref];
30   SchroHierBm *schro_hbm;
31 
32   SCHRO_ASSERT (ref_frame);
33 
34   schro_hbm = schro_malloc0 (sizeof (struct _SchroHierBm));
35   schro_hbm->ref_count = 1;
36   schro_hbm->hierarchy_levels = frame->encoder->downsample_levels;
37   if (frame->encoder->enable_chroma_me)
38     schro_hbm->use_chroma = TRUE;
39   else
40     schro_hbm->use_chroma = FALSE;
41   schro_hbm->hierarchy_levels = frame->encoder->downsample_levels;
42   schro_hbm->params = &frame->params;
43   schro_hbm->ref = ref;
44 
45   schro_hbm->downsampled_src =
46       schro_malloc0 (sizeof (SchroFrame *) * (schro_hbm->hierarchy_levels + 1));
47   schro_hbm->downsampled_ref =
48       schro_malloc0 (sizeof (SchroFrame *) * (schro_hbm->hierarchy_levels + 1));
49   schro_hbm->downsampled_mf =
50       schro_malloc0 (sizeof (SchroMotionField *) *
51       (schro_hbm->hierarchy_levels + 1));
52 
53   schro_hbm->downsampled_src[0] = schro_frame_ref (frame->filtered_frame);
54   schro_hbm->downsampled_ref[0] = schro_frame_ref (ref_frame->filtered_frame);
55   for (i = 0; schro_hbm->hierarchy_levels > i; ++i) {
56     SCHRO_ASSERT (frame->downsampled_frames[i]
57         && ref_frame->downsampled_frames[i]);
58     schro_hbm->downsampled_src[i + 1] =
59         schro_frame_ref (frame->downsampled_frames[i]);
60     schro_hbm->downsampled_ref[i + 1] =
61         schro_frame_ref (ref_frame->downsampled_frames[i]);
62   }
63   return schro_hbm;
64 }
65 
66 SchroHierBm *
schro_hbm_ref(SchroHierBm * src)67 schro_hbm_ref (SchroHierBm * src)
68 {
69   SCHRO_ASSERT (src && src->ref_count > 0);
70   ++src->ref_count;
71   return src;
72 }
73 
74 static void
schro_hbm_free(SchroHierBm * hbm)75 schro_hbm_free (SchroHierBm * hbm)
76 {
77   int i;
78 
79   for (i = 0; hbm->hierarchy_levels + 1 > i; ++i) {
80     if (hbm->downsampled_src[i]) {
81       schro_frame_unref (hbm->downsampled_src[i]);
82     }
83     if (hbm->downsampled_ref[i]) {
84       schro_frame_unref (hbm->downsampled_ref[i]);
85     }
86     if (hbm->downsampled_mf[i]) {
87       schro_motion_field_free (hbm->downsampled_mf[i]);
88     }
89   }
90   schro_free (hbm->downsampled_mf);
91   schro_free (hbm->downsampled_ref);
92   schro_free (hbm->downsampled_src);
93   schro_free (hbm);
94 }
95 
96 /* unreferences a SchroHierBm structure - if it is the last reference
97  * it frees the structure and sets its pointer to NULL
98  * if the pointer was already NULL it's a no-op */
99 void
schro_hbm_unref(SchroHierBm * schro_hbm)100 schro_hbm_unref (SchroHierBm * schro_hbm)
101 {
102   if (0 < --schro_hbm->ref_count)
103     return;
104   schro_hbm_free (schro_hbm);
105 }
106 
107 static SchroFrame *
schro_hbm_src_frame(SchroHierBm * hbm,int level)108 schro_hbm_src_frame (SchroHierBm * hbm, int level)
109 {
110   SCHRO_ASSERT (hbm && 0 < hbm->ref_count && !(get_hier_levels (hbm) < level));
111   return hbm->downsampled_src[level];
112 }
113 
114 static SchroFrame *
schro_hbm_ref_frame(SchroHierBm * hbm,int level)115 schro_hbm_ref_frame (SchroHierBm * hbm, int level)
116 {
117   SCHRO_ASSERT (hbm && 0 < hbm->ref_count && !(get_hier_levels (hbm) < level));
118   return hbm->downsampled_ref[level];
119 }
120 
121 /* Note: it doesn't check whether the requested mf is not NULL */
122 SchroMotionField *
schro_hbm_motion_field(SchroHierBm * schro_hbm,int level)123 schro_hbm_motion_field (SchroHierBm * schro_hbm, int level)
124 {
125   SCHRO_ASSERT (schro_hbm && schro_hbm->ref_count > 0
126       && !(get_hier_levels (schro_hbm) < level));
127   return schro_hbm->downsampled_mf[level];
128 }
129 
130 static void
schro_hbm_set_motion_field(SchroHierBm * hbm,SchroMotionField * mf,int level)131 schro_hbm_set_motion_field (SchroHierBm * hbm, SchroMotionField * mf, int level)
132 {
133   SCHRO_ASSERT (hbm && 0 < hbm->ref_count && !(get_hier_levels (hbm) < level));
134   hbm->downsampled_mf[level] = mf;
135 }
136 
137 static SchroParams *
schro_hbm_params(SchroHierBm * schro_hbm)138 schro_hbm_params (SchroHierBm * schro_hbm)
139 {
140   SCHRO_ASSERT (schro_hbm && 0 < schro_hbm->ref_count);
141   return schro_hbm->params;
142 }
143 
144 static int
schro_hbm_ref_number(SchroHierBm * schro_hbm)145 schro_hbm_ref_number (SchroHierBm * schro_hbm)
146 {
147   SCHRO_ASSERT (schro_hbm && schro_hbm->ref_count > 0);
148   return schro_hbm->ref;
149 }
150 
151 static int
get_hier_levels(SchroHierBm * schro_hbm)152 get_hier_levels (SchroHierBm * schro_hbm)
153 {
154   SCHRO_ASSERT (schro_hbm);
155   return schro_hbm->hierarchy_levels;
156 }
157 
158 void
schro_hbm_scan(SchroHierBm * schro_hbm)159 schro_hbm_scan (SchroHierBm * schro_hbm)
160 {
161   int i;
162   int half_scan_range = 20;
163   int n_levels = get_hier_levels (schro_hbm);
164 
165   SCHRO_ASSERT (n_levels > 0);
166 
167   schro_hierarchical_bm_scan_hint (schro_hbm, n_levels, half_scan_range);
168   half_scan_range >>= 1;
169   for (i = n_levels - 1; 1 <= i; --i, half_scan_range >>= 1) {
170     schro_hierarchical_bm_scan_hint (schro_hbm, i, MAX (3, half_scan_range));
171   }
172 }
173 
174 void
schro_hierarchical_bm_scan_hint(SchroHierBm * schro_hbm,int shift,int h_range)175 schro_hierarchical_bm_scan_hint (SchroHierBm * schro_hbm, int shift,
176     int h_range)
177 {
178   SchroMetricScan scan;
179   SchroMotionVector *mv;
180   SchroMotionField *mf, *hint_mf = NULL;
181   SchroParams *params = schro_hbm_params (schro_hbm);
182   SchroMotionVector zero_mv;
183   SchroMetricInfo info;
184 
185   int xblen = params->xbsep_luma, yblen = params->ybsep_luma;
186   int i;
187   int j;
188   int skip;
189   int shift_w[3], shift_h[3];
190   int split = 1 < shift ? 0 : (1 == shift ? 1 : 2);
191 #define LIST_LENGTH 9
192   SchroMotionVector *temp_hint_mv[LIST_LENGTH], *hint_mv[LIST_LENGTH];
193   unsigned int hint_mask;
194   int ref = schro_hbm_ref_number (schro_hbm);
195   int comp_w[3], comp_h[3];
196 
197   /* sets up for block matching */
198   scan.frame = schro_hbm_src_frame (schro_hbm, shift);
199   scan.ref_frame = schro_hbm_ref_frame (schro_hbm, shift);
200 
201   schro_metric_info_init (&info,
202       schro_hbm_src_frame (schro_hbm, shift),
203       schro_hbm_ref_frame (schro_hbm, shift),
204       xblen, yblen);
205 
206   mf = schro_motion_field_new (params->x_num_blocks, params->y_num_blocks);
207   schro_motion_field_set (mf, split, ref + 1);
208 
209   if (shift < get_hier_levels (schro_hbm)) {
210     hint_mf = schro_hbm_motion_field (schro_hbm, shift + 1);
211   }
212 
213   memset (&zero_mv, 0, sizeof (zero_mv));
214   zero_mv.pred_mode = ref + 1;
215   zero_mv.split = split;
216 
217   hint_mask = ~((1 << (shift + 1)) - 1);
218   skip = 1 << shift;
219 
220   shift_w[0] = shift_h[0] = shift;
221   shift_w[1] = shift_w[2] =
222       shift + SCHRO_FRAME_FORMAT_H_SHIFT (scan.frame->format);
223   shift_h[1] = shift_h[2] =
224       shift + SCHRO_FRAME_FORMAT_V_SHIFT (scan.frame->format);
225   comp_w[0] = xblen;
226   comp_h[0] = yblen;
227   comp_w[1] = comp_w[2] =
228       xblen >> SCHRO_FRAME_FORMAT_H_SHIFT (scan.frame->format);
229   comp_h[1] = comp_h[2] =
230       yblen >> SCHRO_FRAME_FORMAT_V_SHIFT (scan.frame->format);
231 
232   for (j = 0; j < params->y_num_blocks; j += skip) {
233     for (i = 0; i < params->x_num_blocks; i += skip) {
234       SchroFrameData orig[3];
235       int m = 0;
236       int n = 0;
237       int dx, dy;
238       int min_m;
239       int min_metric;
240       int width[3], height[3];
241       int k;
242 
243       /* get source data, if possible */
244       if (!(scan.frame->width > (i * xblen) >> shift)
245           || !(scan.frame->height > (j * yblen) >> shift)) {
246         continue;
247       }
248       for (k = 0; 3 > k; ++k) {
249         schro_frame_get_subdata (scan.frame, &orig[k], k,
250             (i * xblen) >> shift_w[k], (j * yblen) >> shift_h[k]);
251         width[k] = MIN (orig[k].width, comp_w[k]);
252         height[k] = MIN (orig[k].height, comp_h[k]);
253         if (0 == k) {
254           SCHRO_ASSERT (0 < width[k] && 0 < height[k]);
255         }
256       }
257 
258       /* now check all candidates */
259       /* always test the zero vector */
260       temp_hint_mv[n] = &zero_mv;
261       n++;
262 
263       /* inherit from nearby parents (star-like selection) */
264       if (NULL != hint_mf) {
265         int l = i & hint_mask, k = j & hint_mask, ll, kk;
266         int offset[5][2] = { {0, 0}, {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
267         for (m = 0; m < 5; m++) {
268           ll = l + offset[m][0] * skip * 2;
269           kk = k + offset[m][1] * skip * 2;
270           if (ll >= 0 && ll < params->x_num_blocks &&
271               kk >= 0 && kk < params->y_num_blocks) {
272             mv = hint_mf->motion_vectors + kk * params->x_num_blocks + ll;
273             temp_hint_mv[n] = mv;
274             n++;
275           }
276         }
277       }
278 
279       /* inherit from neighbours (only towards SE) */
280       if (i > 0) {
281         mv = mf->motion_vectors + j * params->x_num_blocks + i - skip;
282         temp_hint_mv[n] = mv;
283         n++;
284       }
285       if (j > 0) {
286         mv = mf->motion_vectors + (j - skip) * params->x_num_blocks + i;
287         temp_hint_mv[n] = mv;
288         n++;
289       }
290       if (i > 0 && j > 0) {
291         mv = mf->motion_vectors + (j - skip) * params->x_num_blocks + i - skip;
292         temp_hint_mv[n] = mv;
293         n++;
294       }
295 
296       SCHRO_ASSERT (n <= LIST_LENGTH);
297 
298       /* remove duplicates */
299       m = 0;
300       if (1 < n) {
301         int k, s;
302         SchroMotionVector *mv1, *mv2;
303         for (k = 0; n - 1 > k; ++k) {
304           int skip = 0;
305           mv1 = temp_hint_mv[k];
306           for (s = k + 1; n > s && !skip; ++s) {
307             mv2 = temp_hint_mv[s];
308             if (mv1->u.vec.dx[ref] == mv2->u.vec.dx[ref]
309                 && mv1->u.vec.dy[ref] == mv2->u.vec.dy[ref]) {
310               skip = 1;
311             }
312           }
313           if (!skip) {
314             hint_mv[m++] = mv1;
315           }
316         }
317         hint_mv[m++] = temp_hint_mv[n - 1];
318         n = m;
319       } else {
320         hint_mv[0] = temp_hint_mv[0];
321       }
322 
323       min_m = -1;
324       min_metric = INT_MAX;
325       /* choose best candidate for refinement based on SAD only. */
326       for (m = 0; m < n; m++) {
327         int metric = 0;
328 
329         dx = hint_mv[m]->u.vec.dx[ref];
330         dx >>= shift;
331         dx = CLAMP (dx + ((i*xblen) >> shift), -width[0],
332             (scan.ref_frame->components + 0)->width);
333         dx -= ((i*xblen) >> shift);
334         dy = hint_mv[m]->u.vec.dy[ref];
335         dy >>= shift;
336         dy = CLAMP (dy + ((j*yblen) >> shift), -height[0],
337             (scan.ref_frame->components + 0)->height);
338         dy -= ((j*yblen) >> shift);
339         metric = schro_metric_fast_block (&info, (i*xblen)>>shift,
340             (j*yblen)>>shift, dx, dy);
341 
342         if (metric < min_metric) {
343           min_metric = metric;
344           min_m = m;
345         }
346       }
347       SCHRO_ASSERT (-1 < min_m);
348 
349       /* finally do block-matching around chosen candidate MV */
350       dx = hint_mv[min_m]->u.vec.dx[ref] >> shift;
351       dy = hint_mv[min_m]->u.vec.dy[ref] >> shift;
352 
353       scan.block_width = width[0];
354       scan.block_height = height[0];
355       scan.x = i * xblen >> shift;
356       scan.y = j * yblen >> shift;
357       dx = MAX (-width[0] - scan.x, MIN (scan.ref_frame->width - scan.x, dx));
358       dy = MAX (-height[0] - scan.y, MIN (scan.ref_frame->height - scan.y, dy));
359       scan.gravity_x = dx;
360       scan.gravity_y = dy;
361       schro_metric_scan_setup (&scan, dx, dy, h_range, schro_hbm->use_chroma);
362       SCHRO_ASSERT (!(0 > scan.scan_width) && !(0 > scan.scan_height));
363 
364       mv = mf->motion_vectors + j * params->x_num_blocks + i;
365 
366       schro_metric_scan_do_scan (&scan);
367       mv->metric =
368           schro_metric_scan_get_min (&scan, &dx, &dy, &mv->chroma_metric);
369       dx <<= shift;
370       dy <<= shift;
371 
372       mv->u.vec.dx[ref] = dx;
373       mv->u.vec.dy[ref] = dy;
374 
375       mv->using_global = 0;
376 
377       mv->pred_mode = ref + 1;
378     }
379   }
380 
381   schro_hbm_set_motion_field (schro_hbm, mf, shift);
382 #undef LIST_LENGTH
383 }
384