Add optical flow api skeleton only.

Change-Id: I0b1e47c3e4ae4cbc9d7f4284a95a629add7b98cb
diff --git a/av1/av1.cmake b/av1/av1.cmake
index ed4265f..0775040 100644
--- a/av1/av1.cmake
+++ b/av1/av1.cmake
@@ -189,6 +189,8 @@
             "${AOM_ROOT}/av1/encoder/motion_search_facade.h"
             "${AOM_ROOT}/av1/encoder/mv_prec.c"
             "${AOM_ROOT}/av1/encoder/mv_prec.h"
+            "${AOM_ROOT}/av1/encoder/optical_flow.c"
+            "${AOM_ROOT}/av1/encoder/optical_flow.h"
             "${AOM_ROOT}/av1/encoder/palette.c"
             "${AOM_ROOT}/av1/encoder/palette.h"
             "${AOM_ROOT}/av1/encoder/partition_search.h"
diff --git a/av1/encoder/optical_flow.c b/av1/encoder/optical_flow.c
new file mode 100644
index 0000000..90c9a5b
--- /dev/null
+++ b/av1/encoder/optical_flow.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2016, Alliance for Open Media. All rights reserved
+ *
+ * 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.
+ */
+#include <math.h>
+#include <limits.h>
+
+#include "config/aom_config.h"
+#include "av1/common/av1_common_int.h"
+#include "av1/encoder/encoder.h"
+#include "av1/encoder/mathutils.h"
+#include "av1/encoder/optical_flow.h"
+#include "av1/encoder/reconinter_enc.h"
+#include "aom_mem/aom_mem.h"
+
+#if CONFIG_OPTICAL_FLOW_API
+
+typedef struct LOCALMV {
+  double row;
+  double col;
+} LOCALMV;
+
+// Computes optical flow by applying algorithm at
+// multiple pyramid levels of images (lower-resolution, smoothed images)
+// This accounts for larger motions.
+// Inputs:
+//   from_frame Frame buffer.
+//   to_frame: Frame buffer. MVs point from_frame -> to_frame.
+//   from_frame_idx: Index of from_frame.
+//   to_frame_idx: Index of to_frame. Return all zero MVs when idx are equal.
+//   bit_depth:
+//   opfl_params: contains algorithm-specific parameters.
+//   mv_filter: MV_FILTER_NONE, MV_FILTER_SMOOTH, or MV_FILTER_MEDIAN.
+//   method: LUCAS_KANADE,
+//   mvs: pointer to MVs. Contains initialization, and modified
+//   based on optical flow. Must have
+//   dimensions = from_frame->y_crop_width * from_frame->y_crop_height
+void optical_flow(const YV12_BUFFER_CONFIG *from_frame,
+                  const YV12_BUFFER_CONFIG *to_frame, const int from_frame_idx,
+                  const int to_frame_idx, const int bit_depth,
+                  const OPFL_PARAMS *opfl_params,
+                  const MV_FILTER_TYPE mv_filter, const OPTFLOW_METHOD method,
+                  MV *mvs) {
+  const int frame_height = from_frame->y_crop_height;
+  const int frame_width = from_frame->y_crop_width;
+  // TODO(any): deal with the case where frames are not of the same dimensions
+  assert(frame_height == to_frame->y_crop_height &&
+         frame_width == to_frame->y_crop_width);
+  if (from_frame_idx == to_frame_idx) {
+    // immediately return all zero mvs when frame indices are equal
+    for (int yy = 0; yy < frame_height; yy++) {
+      for (int xx = 0; xx < frame_width; xx++) {
+        MV mv = { .row = 0, .col = 0 };
+        mvs[yy * frame_width + xx] = mv;
+      }
+    }
+    return;
+  }
+  // Initialize double mvs based on input parameter mvs array
+  LOCALMV *localmvs = aom_malloc(frame_height * frame_width * sizeof(LOCALMV));
+  for (int i = 0; i < frame_width * frame_height; i++) {
+    MV mv = mvs[i];
+    LOCALMV localmv = { .row = ((double)mv.row) / 8,
+                        .col = ((double)mv.col) / 8 };
+    localmvs[i] = localmv;
+  }
+  // Apply optical flow algorithm
+
+  // Update original mvs array
+  for (int j = 0; j < frame_height; j++) {
+    for (int i = 0; i < frame_width; i++) {
+      int idx = j * frame_width + i;
+      int new_x = localmvs[idx].row + i;
+      int new_y = localmvs[idx].col + j;
+      if ((fabs(localmvs[idx].row) >= 0.125 ||
+           fabs(localmvs[idx].col) >= 0.125)) {
+        // if mv points outside of frame (lost feature), keep old mv.
+        if (new_x < frame_width && new_x >= 0 && new_y < frame_height &&
+            new_y >= 0) {
+          MV mv = { .row = (int16_t)round(8 * localmvs[idx].row),
+                    .col = (int16_t)round(8 * localmvs[idx].col) };
+          mvs[idx] = mv;
+        }
+      }
+    }
+  }
+  aom_free(localmvs);
+}
+#endif
diff --git a/av1/encoder/optical_flow.h b/av1/encoder/optical_flow.h
new file mode 100644
index 0000000..5056af3
--- /dev/null
+++ b/av1/encoder/optical_flow.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2016, Alliance for Open Media. All rights reserved
+ *
+ * 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.
+ */
+
+#ifndef AOM_AV1_ENCODER_OPTICAL_FLOW_H_
+#define AOM_AV1_ENCODER_OPTICAL_FLOW_H_
+
+#include "config/aom_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if CONFIG_OPTICAL_FLOW_API
+
+typedef enum { LUCAS_KANADE } OPTFLOW_METHOD;
+
+typedef enum {
+  MV_FILTER_NONE,
+  MV_FILTER_SMOOTH,
+  MV_FILTER_MEDIAN
+} MV_FILTER_TYPE;
+
+// default options for optical flow
+#define OPFL_WINDOW_SIZE 15
+#define OPFL_PYRAMID_LEVELS 3  // total levels (max is 5)
+
+// parameters specific to Lucas-Kanade
+typedef struct lk_params {
+  int window_size;
+} LK_PARAMS;
+
+// generic structure to contain parameters for all
+// optical flow algorithms
+typedef struct opfl_params {
+  int pyramid_levels;
+  LK_PARAMS *lk_params;
+} OPFL_PARAMS;
+
+void init_opfl_params(OPFL_PARAMS *opfl_params) {
+  opfl_params->pyramid_levels = OPFL_PYRAMID_LEVELS;
+  opfl_params->lk_params = NULL;
+}
+
+void init_lk_params(LK_PARAMS *lk_params) {
+  lk_params->window_size = OPFL_WINDOW_SIZE;
+}
+
+void optical_flow(const YV12_BUFFER_CONFIG *from_frame,
+                  const YV12_BUFFER_CONFIG *to_frame, const int from_frame_idx,
+                  const int to_frame_idx, const int bit_depth,
+                  const OPFL_PARAMS *opfl_params,
+                  const MV_FILTER_TYPE mv_filter, const OPTFLOW_METHOD method,
+                  MV *mvs);
+#endif
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // AOM_AV1_ENCODER_OPTICAL_FLOW_H_
diff --git a/build/cmake/aom_config_defaults.cmake b/build/cmake/aom_config_defaults.cmake
index 3db4f53..2497ff1 100644
--- a/build/cmake/aom_config_defaults.cmake
+++ b/build/cmake/aom_config_defaults.cmake
@@ -107,6 +107,7 @@
 set_aom_config_var(DECODE_HEIGHT_LIMIT 0 "Set limit for decode height.")
 set_aom_config_var(DECODE_WIDTH_LIMIT 0 "Set limit for decode width.")
 set_aom_config_var(CONFIG_TUNE_VMAF 0 "Enable encoding tuning for VMAF.")
+set_aom_config_var(CONFIG_OPTICAL_FLOW_API 0 "Enables optical flow API.")
 
 # AV1 experiment flags.
 set_aom_config_var(CONFIG_SPEED_STATS 0 "AV1 experiment flag.")