mbgraph.c 13.7 KB
Newer Older
Jingning Han's avatar
Jingning Han committed
1
/*
Yaowu Xu's avatar
Yaowu Xu committed
2
 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
Jingning Han's avatar
Jingning Han committed
3
 *
Yaowu Xu's avatar
Yaowu Xu committed
4
5
6
7
8
9
 * This source code is subject to the terms of the BSD 2 Clause License and
 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
 * was not distributed with this source code in the LICENSE file, you can
 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
 * Media Patent License 1.0 was not distributed with this source code in the
 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
Jingning Han's avatar
Jingning Han committed
10
11
12
13
 */

#include <limits.h>

Yaowu Xu's avatar
Yaowu Xu committed
14
15
#include "./av1_rtcd.h"
#include "./aom_dsp_rtcd.h"
Jingning Han's avatar
Jingning Han committed
16

Yaowu Xu's avatar
Yaowu Xu committed
17
18
#include "aom_dsp/aom_dsp_common.h"
#include "aom_mem/aom_mem.h"
19
20
21
22
23
24
#include "aom_ports/system_state.h"
#include "av1/encoder/segmentation.h"
#include "av1/encoder/mcomp.h"
#include "av1/common/blockd.h"
#include "av1/common/reconinter.h"
#include "av1/common/reconintra.h"
Jingning Han's avatar
Jingning Han committed
25

Yaowu Xu's avatar
Yaowu Xu committed
26
static unsigned int do_16x16_motion_iteration(AV1_COMP *cpi, const MV *ref_mv,
27
                                              int mb_row, int mb_col) {
Jingning Han's avatar
Jingning Han committed
28
29
30
  MACROBLOCK *const x = &cpi->td.mb;
  MACROBLOCKD *const xd = &x->e_mbd;
  const MV_SPEED_FEATURES *const mv_sf = &cpi->sf.mv;
Yaowu Xu's avatar
Yaowu Xu committed
31
  const aom_variance_fn_ptr_t v_fn_ptr = cpi->fn_ptr[BLOCK_16X16];
Jingning Han's avatar
Jingning Han committed
32
33
34
35
36
37
38
39
40
41

  const int tmp_col_min = x->mv_col_min;
  const int tmp_col_max = x->mv_col_max;
  const int tmp_row_min = x->mv_row_min;
  const int tmp_row_max = x->mv_row_max;
  MV ref_full;
  int cost_list[5];

  // Further step/diamond searches as necessary
  int step_param = mv_sf->reduce_first_step_size;
Yaowu Xu's avatar
Yaowu Xu committed
42
  step_param = AOMMIN(step_param, MAX_MVSEARCH_STEPS - 2);
Jingning Han's avatar
Jingning Han committed
43

Yaowu Xu's avatar
Yaowu Xu committed
44
  av1_set_mv_search_range(x, ref_mv);
Jingning Han's avatar
Jingning Han committed
45
46
47
48
49

  ref_full.col = ref_mv->col >> 3;
  ref_full.row = ref_mv->row >> 3;

  /*cpi->sf.search_method == HEX*/
Yaowu Xu's avatar
Yaowu Xu committed
50
51
  av1_hex_search(x, &ref_full, step_param, x->errorperbit, 0,
                 cond_cost_list(cpi, cost_list), &v_fn_ptr, 0, ref_mv);
Jingning Han's avatar
Jingning Han committed
52
53
54
55
56
57

  // Try sub-pixel MC
  // if (bestsme > error_thresh && bestsme < INT_MAX)
  {
    int distortion;
    unsigned int sse;
58
59
60
61
62
    cpi->find_fractional_mv_step(x, ref_mv, cpi->common.allow_high_precision_mv,
                                 x->errorperbit, &v_fn_ptr, 0,
                                 mv_sf->subpel_iters_per_step,
                                 cond_cost_list(cpi, cost_list), NULL, NULL,
                                 &distortion, &sse, NULL, 0, 0, 0);
Jingning Han's avatar
Jingning Han committed
63
64
  }

65
66
67
68
69
#if CONFIG_EXT_INTER
  if (has_second_ref(&xd->mi[0]->mbmi))
    xd->mi[0]->mbmi.mode = NEW_NEWMV;
  else
#endif  // CONFIG_EXT_INTER
70
    xd->mi[0]->mbmi.mode = NEWMV;
71

hui su's avatar
hui su committed
72
  xd->mi[0]->mbmi.mv[0] = x->best_mv;
73
74
75
#if CONFIG_EXT_INTER
  xd->mi[0]->mbmi.ref_frame[1] = NONE;
#endif  // CONFIG_EXT_INTER
Jingning Han's avatar
Jingning Han committed
76

Yaowu Xu's avatar
Yaowu Xu committed
77
  av1_build_inter_predictors_sby(xd, mb_row, mb_col, BLOCK_16X16);
Jingning Han's avatar
Jingning Han committed
78
79
80
81
82
83
84

  /* restore UMV window */
  x->mv_col_min = tmp_col_min;
  x->mv_col_max = tmp_col_max;
  x->mv_row_min = tmp_row_min;
  x->mv_row_max = tmp_row_max;

Yaowu Xu's avatar
Yaowu Xu committed
85
  return aom_sad16x16(x->plane[0].src.buf, x->plane[0].src.stride,
Jingning Han's avatar
Jingning Han committed
86
87
88
                      xd->plane[0].dst.buf, xd->plane[0].dst.stride);
}

Yaowu Xu's avatar
Yaowu Xu committed
89
static int do_16x16_motion_search(AV1_COMP *cpi, const MV *ref_mv, int mb_row,
90
                                  int mb_col) {
Jingning Han's avatar
Jingning Han committed
91
92
93
  MACROBLOCK *const x = &cpi->td.mb;
  MACROBLOCKD *const xd = &x->e_mbd;
  unsigned int err, tmp_err;
hui su's avatar
hui su committed
94
  MV best_mv;
Jingning Han's avatar
Jingning Han committed
95
96
97

  // Try zero MV first
  // FIXME should really use something like near/nearest MV and/or MV prediction
Yaowu Xu's avatar
Yaowu Xu committed
98
  err = aom_sad16x16(x->plane[0].src.buf, x->plane[0].src.stride,
Jingning Han's avatar
Jingning Han committed
99
                     xd->plane[0].pre[0].buf, xd->plane[0].pre[0].stride);
hui su's avatar
hui su committed
100
  best_mv.col = best_mv.row = 0;
Jingning Han's avatar
Jingning Han committed
101
102
103

  // Test last reference frame using the previous best mv as the
  // starting point (best reference) for the search
hui su's avatar
hui su committed
104
  tmp_err = do_16x16_motion_iteration(cpi, ref_mv, mb_row, mb_col);
Jingning Han's avatar
Jingning Han committed
105
106
  if (tmp_err < err) {
    err = tmp_err;
hui su's avatar
hui su committed
107
    best_mv = x->best_mv.as_mv;
Jingning Han's avatar
Jingning Han committed
108
109
110
111
112
  }

  // If the current best reference mv is not centered on 0,0 then do a 0,0
  // based search as well.
  if (ref_mv->row != 0 || ref_mv->col != 0) {
113
    MV zero_ref_mv = { 0, 0 };
Jingning Han's avatar
Jingning Han committed
114

hui su's avatar
hui su committed
115
    tmp_err = do_16x16_motion_iteration(cpi, &zero_ref_mv, mb_row, mb_col);
Jingning Han's avatar
Jingning Han committed
116
117
    if (tmp_err < err) {
      err = tmp_err;
hui su's avatar
hui su committed
118
      best_mv = x->best_mv.as_mv;
Jingning Han's avatar
Jingning Han committed
119
120
121
    }
  }

hui su's avatar
hui su committed
122
  x->best_mv.as_mv = best_mv;
Jingning Han's avatar
Jingning Han committed
123
124
125
  return err;
}

Yaowu Xu's avatar
Yaowu Xu committed
126
static int do_16x16_zerozero_search(AV1_COMP *cpi, int_mv *dst_mv) {
Jingning Han's avatar
Jingning Han committed
127
128
129
130
131
132
  MACROBLOCK *const x = &cpi->td.mb;
  MACROBLOCKD *const xd = &x->e_mbd;
  unsigned int err;

  // Try zero MV first
  // FIXME should really use something like near/nearest MV and/or MV prediction
Yaowu Xu's avatar
Yaowu Xu committed
133
  err = aom_sad16x16(x->plane[0].src.buf, x->plane[0].src.stride,
Jingning Han's avatar
Jingning Han committed
134
135
136
137
138
139
                     xd->plane[0].pre[0].buf, xd->plane[0].pre[0].stride);

  dst_mv->as_int = 0;

  return err;
}
Yaowu Xu's avatar
Yaowu Xu committed
140
static int find_best_16x16_intra(AV1_COMP *cpi, PREDICTION_MODE *pbest_mode) {
141
  MACROBLOCK *const x = &cpi->td.mb;
Jingning Han's avatar
Jingning Han committed
142
143
144
145
146
147
148
149
150
151
  MACROBLOCKD *const xd = &x->e_mbd;
  PREDICTION_MODE best_mode = -1, mode;
  unsigned int best_err = INT_MAX;

  // calculate SATD for each intra prediction mode;
  // we're intentionally not doing 4x4, we just want a rough estimate
  for (mode = DC_PRED; mode <= TM_PRED; mode++) {
    unsigned int err;

    xd->mi[0]->mbmi.mode = mode;
152
    av1_predict_intra_block(xd, 16, 16, TX_16X16, mode, x->plane[0].src.buf,
Yaowu Xu's avatar
Yaowu Xu committed
153
154
155
                            x->plane[0].src.stride, xd->plane[0].dst.buf,
                            xd->plane[0].dst.stride, 0, 0, 0);
    err = aom_sad16x16(x->plane[0].src.buf, x->plane[0].src.stride,
Jingning Han's avatar
Jingning Han committed
156
157
158
159
                       xd->plane[0].dst.buf, xd->plane[0].dst.stride);

    // find best
    if (err < best_err) {
160
      best_err = err;
Jingning Han's avatar
Jingning Han committed
161
162
163
164
      best_mode = mode;
    }
  }

165
  if (pbest_mode) *pbest_mode = best_mode;
Jingning Han's avatar
Jingning Han committed
166
167
168
169

  return best_err;
}

Yaowu Xu's avatar
Yaowu Xu committed
170
static void update_mbgraph_mb_stats(AV1_COMP *cpi, MBGRAPH_MB_STATS *stats,
171
172
173
174
175
                                    YV12_BUFFER_CONFIG *buf, int mb_y_offset,
                                    YV12_BUFFER_CONFIG *golden_ref,
                                    const MV *prev_golden_ref_mv,
                                    YV12_BUFFER_CONFIG *alt_ref, int mb_row,
                                    int mb_col) {
Jingning Han's avatar
Jingning Han committed
176
177
178
  MACROBLOCK *const x = &cpi->td.mb;
  MACROBLOCKD *const xd = &x->e_mbd;
  int intra_error;
Yaowu Xu's avatar
Yaowu Xu committed
179
  AV1_COMMON *cm = &cpi->common;
Jingning Han's avatar
Jingning Han committed
180
181
182
183
184
185
186
187
188

  // FIXME in practice we're completely ignoring chroma here
  x->plane[0].src.buf = buf->y_buffer + mb_y_offset;
  x->plane[0].src.stride = buf->y_stride;

  xd->plane[0].dst.buf = get_frame_new_buffer(cm)->y_buffer + mb_y_offset;
  xd->plane[0].dst.stride = get_frame_new_buffer(cm)->y_stride;

  // do intra 16x16 prediction
189
190
  intra_error = find_best_16x16_intra(cpi, &stats->ref[INTRA_FRAME].m.mode);
  if (intra_error <= 0) intra_error = 1;
Jingning Han's avatar
Jingning Han committed
191
192
193
194
195
196
197
  stats->ref[INTRA_FRAME].err = intra_error;

  // Golden frame MV search, if it exists and is different than last frame
  if (golden_ref) {
    int g_motion_error;
    xd->plane[0].pre[0].buf = golden_ref->y_buffer + mb_y_offset;
    xd->plane[0].pre[0].stride = golden_ref->y_stride;
198
199
    g_motion_error =
        do_16x16_motion_search(cpi, prev_golden_ref_mv, mb_row, mb_col);
hui su's avatar
hui su committed
200
    stats->ref[GOLDEN_FRAME].m.mv = x->best_mv;
Jingning Han's avatar
Jingning Han committed
201
202
203
204
205
206
207
208
209
210
211
212
    stats->ref[GOLDEN_FRAME].err = g_motion_error;
  } else {
    stats->ref[GOLDEN_FRAME].err = INT_MAX;
    stats->ref[GOLDEN_FRAME].m.mv.as_int = 0;
  }

  // Do an Alt-ref frame MV search, if it exists and is different than
  // last/golden frame.
  if (alt_ref) {
    int a_motion_error;
    xd->plane[0].pre[0].buf = alt_ref->y_buffer + mb_y_offset;
    xd->plane[0].pre[0].stride = alt_ref->y_stride;
213
214
    a_motion_error =
        do_16x16_zerozero_search(cpi, &stats->ref[ALTREF_FRAME].m.mv);
Jingning Han's avatar
Jingning Han committed
215
216
217
218
219
220
221
222

    stats->ref[ALTREF_FRAME].err = a_motion_error;
  } else {
    stats->ref[ALTREF_FRAME].err = INT_MAX;
    stats->ref[ALTREF_FRAME].m.mv.as_int = 0;
  }
}

Yaowu Xu's avatar
Yaowu Xu committed
223
static void update_mbgraph_frame_stats(AV1_COMP *cpi,
Jingning Han's avatar
Jingning Han committed
224
225
226
227
228
229
                                       MBGRAPH_FRAME_STATS *stats,
                                       YV12_BUFFER_CONFIG *buf,
                                       YV12_BUFFER_CONFIG *golden_ref,
                                       YV12_BUFFER_CONFIG *alt_ref) {
  MACROBLOCK *const x = &cpi->td.mb;
  MACROBLOCKD *const xd = &x->e_mbd;
Yaowu Xu's avatar
Yaowu Xu committed
230
  AV1_COMMON *const cm = &cpi->common;
Jingning Han's avatar
Jingning Han committed
231
232
233

  int mb_col, mb_row, offset = 0;
  int mb_y_offset = 0, arf_y_offset = 0, gld_y_offset = 0;
234
  MV gld_top_mv = { 0, 0 };
Jingning Han's avatar
Jingning Han committed
235
236
  MODE_INFO mi_local;

Yaowu Xu's avatar
Yaowu Xu committed
237
  av1_zero(mi_local);
Jingning Han's avatar
Jingning Han committed
238
239
  // Set up limit values for motion vectors to prevent them extending outside
  // the UMV borders.
240
241
242
243
244
  x->mv_row_min = -BORDER_MV_PIXELS_B16;
  x->mv_row_max = (cm->mb_rows - 1) * 8 + BORDER_MV_PIXELS_B16;
  xd->up_available = 0;
  xd->plane[0].dst.stride = buf->y_stride;
  xd->plane[0].pre[0].stride = buf->y_stride;
Jingning Han's avatar
Jingning Han committed
245
246
247
248
249
250
251
252
  xd->plane[1].dst.stride = buf->uv_stride;
  xd->mi[0] = &mi_local;
  mi_local.mbmi.sb_type = BLOCK_16X16;
  mi_local.mbmi.ref_frame[0] = LAST_FRAME;
  mi_local.mbmi.ref_frame[1] = NONE;

  for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) {
    MV gld_left_mv = gld_top_mv;
253
    int mb_y_in_offset = mb_y_offset;
Jingning Han's avatar
Jingning Han committed
254
255
256
257
258
    int arf_y_in_offset = arf_y_offset;
    int gld_y_in_offset = gld_y_offset;

    // Set up limit values for motion vectors to prevent them extending outside
    // the UMV borders.
259
260
    x->mv_col_min = -BORDER_MV_PIXELS_B16;
    x->mv_col_max = (cm->mb_cols - 1) * 8 + BORDER_MV_PIXELS_B16;
Jingning Han's avatar
Jingning Han committed
261
262
263
264
265
    xd->left_available = 0;

    for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) {
      MBGRAPH_MB_STATS *mb_stats = &stats->mb_stats[offset + mb_col];

266
267
      update_mbgraph_mb_stats(cpi, mb_stats, buf, mb_y_in_offset, golden_ref,
                              &gld_left_mv, alt_ref, mb_row, mb_col);
Jingning Han's avatar
Jingning Han committed
268
269
270
271
272
      gld_left_mv = mb_stats->ref[GOLDEN_FRAME].m.mv.as_mv;
      if (mb_col == 0) {
        gld_top_mv = gld_left_mv;
      }
      xd->left_available = 1;
273
274
275
276
277
      mb_y_in_offset += 16;
      gld_y_in_offset += 16;
      arf_y_in_offset += 16;
      x->mv_col_min -= 16;
      x->mv_col_max -= 16;
Jingning Han's avatar
Jingning Han committed
278
279
    }
    xd->up_available = 1;
280
281
282
283
284
285
    mb_y_offset += buf->y_stride * 16;
    gld_y_offset += golden_ref->y_stride * 16;
    if (alt_ref) arf_y_offset += alt_ref->y_stride * 16;
    x->mv_row_min -= 16;
    x->mv_row_max -= 16;
    offset += cm->mb_cols;
Jingning Han's avatar
Jingning Han committed
286
287
288
289
  }
}

// void separate_arf_mbs_byzz
Yaowu Xu's avatar
Yaowu Xu committed
290
291
static void separate_arf_mbs(AV1_COMP *cpi) {
  AV1_COMMON *const cm = &cpi->common;
Jingning Han's avatar
Jingning Han committed
292
293
294
295
296
297
298
  int mb_col, mb_row, offset, i;
  int mi_row, mi_col;
  int ncnt[4] = { 0 };
  int n_frames = cpi->mbgraph_n_frames;

  int *arf_not_zz;

299
300
  CHECK_MEM_ERROR(
      cm, arf_not_zz,
Yaowu Xu's avatar
Yaowu Xu committed
301
      aom_calloc(cm->mb_rows * cm->mb_cols * sizeof(*arf_not_zz), 1));
Jingning Han's avatar
Jingning Han committed
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316

  // We are not interested in results beyond the alt ref itself.
  if (n_frames > cpi->rc.frames_till_gf_update_due)
    n_frames = cpi->rc.frames_till_gf_update_due;

  // defer cost to reference frames
  for (i = n_frames - 1; i >= 0; i--) {
    MBGRAPH_FRAME_STATS *frame_stats = &cpi->mbgraph_stats[i];

    for (offset = 0, mb_row = 0; mb_row < cm->mb_rows;
         offset += cm->mb_cols, mb_row++) {
      for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) {
        MBGRAPH_MB_STATS *mb_stats = &frame_stats->mb_stats[offset + mb_col];

        int altref_err = mb_stats->ref[ALTREF_FRAME].err;
317
        int intra_err = mb_stats->ref[INTRA_FRAME].err;
Jingning Han's avatar
Jingning Han committed
318
319
320
        int golden_err = mb_stats->ref[GOLDEN_FRAME].err;

        // Test for altref vs intra and gf and that its mv was 0,0.
321
        if (altref_err > 1000 || altref_err > intra_err ||
Jingning Han's avatar
Jingning Han committed
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
            altref_err > golden_err) {
          arf_not_zz[offset + mb_col]++;
        }
      }
    }
  }

  // arf_not_zz is indexed by MB, but this loop is indexed by MI to avoid out
  // of bound access in segmentation_map
  for (mi_row = 0; mi_row < cm->mi_rows; mi_row++) {
    for (mi_col = 0; mi_col < cm->mi_cols; mi_col++) {
      // If any of the blocks in the sequence failed then the MB
      // goes in segment 0
      if (arf_not_zz[mi_row / 2 * cm->mb_cols + mi_col / 2]) {
        ncnt[0]++;
        cpi->segmentation_map[mi_row * cm->mi_cols + mi_col] = 0;
      } else {
        cpi->segmentation_map[mi_row * cm->mi_cols + mi_col] = 1;
        ncnt[1]++;
      }
    }
  }

  // Only bother with segmentation if over 10% of the MBs in static segment
  // if ( ncnt[1] && (ncnt[0] / ncnt[1] < 10) )
  if (1) {
    // Note % of blocks that are marked as static
    if (cm->MBs)
      cpi->static_mb_pct = (ncnt[1] * 100) / (cm->mi_rows * cm->mi_cols);

    // This error case should not be reachable as this function should
    // never be called with the common data structure uninitialized.
    else
      cpi->static_mb_pct = 0;

Yaowu Xu's avatar
Yaowu Xu committed
357
    av1_enable_segmentation(&cm->seg);
Jingning Han's avatar
Jingning Han committed
358
359
  } else {
    cpi->static_mb_pct = 0;
Yaowu Xu's avatar
Yaowu Xu committed
360
    av1_disable_segmentation(&cm->seg);
Jingning Han's avatar
Jingning Han committed
361
362
363
  }

  // Free localy allocated storage
Yaowu Xu's avatar
Yaowu Xu committed
364
  aom_free(arf_not_zz);
Jingning Han's avatar
Jingning Han committed
365
366
}

Yaowu Xu's avatar
Yaowu Xu committed
367
368
369
void av1_update_mbgraph_stats(AV1_COMP *cpi) {
  AV1_COMMON *const cm = &cpi->common;
  int i, n_frames = av1_lookahead_depth(cpi->lookahead);
Jingning Han's avatar
Jingning Han committed
370
371
372
373
374
375
  YV12_BUFFER_CONFIG *golden_ref = get_ref_frame_buffer(cpi, GOLDEN_FRAME);

  assert(golden_ref != NULL);

  // we need to look ahead beyond where the ARF transitions into
  // being a GF - so exit if we don't look ahead beyond that
376
  if (n_frames <= cpi->rc.frames_till_gf_update_due) return;
Jingning Han's avatar
Jingning Han committed
377

378
  if (n_frames > MAX_LAG_BUFFERS) n_frames = MAX_LAG_BUFFERS;
Jingning Han's avatar
Jingning Han committed
379
380
381
382
383
384
385
386
387
388
389
390
391
392

  cpi->mbgraph_n_frames = n_frames;
  for (i = 0; i < n_frames; i++) {
    MBGRAPH_FRAME_STATS *frame_stats = &cpi->mbgraph_stats[i];
    memset(frame_stats->mb_stats, 0,
           cm->mb_rows * cm->mb_cols * sizeof(*cpi->mbgraph_stats[i].mb_stats));
  }

  // do motion search to find contribution of each reference to data
  // later on in this GF group
  // FIXME really, the GF/last MC search should be done forward, and
  // the ARF MC search backwards, to get optimal results for MV caching
  for (i = 0; i < n_frames; i++) {
    MBGRAPH_FRAME_STATS *frame_stats = &cpi->mbgraph_stats[i];
Yaowu Xu's avatar
Yaowu Xu committed
393
    struct lookahead_entry *q_cur = av1_lookahead_peek(cpi->lookahead, i);
Jingning Han's avatar
Jingning Han committed
394
395
396

    assert(q_cur != NULL);

397
398
    update_mbgraph_frame_stats(cpi, frame_stats, &q_cur->img, golden_ref,
                               cpi->Source);
Jingning Han's avatar
Jingning Han committed
399
400
  }

Yaowu Xu's avatar
Yaowu Xu committed
401
  aom_clear_system_state();
Jingning Han's avatar
Jingning Han committed
402
403
404

  separate_arf_mbs(cpi);
}