OSDN Git Service

Add filterpacks' native base library.
authorWei Hua <whua@google.com>
Wed, 25 May 2011 16:39:04 +0000 (09:39 -0700)
committerWei Hua <whua@google.com>
Wed, 25 May 2011 16:39:04 +0000 (09:39 -0700)
Change-Id: Ia83f68dee76eb9c5684f760380b48de9e146c3c5

mca/filterpacks/base/Android.mk [new file with mode: 0644]
mca/filterpacks/base/native/basictypes.h [new file with mode: 0644]
mca/filterpacks/base/native/geometry.cpp [new file with mode: 0644]
mca/filterpacks/base/native/geometry.h [new file with mode: 0644]
mca/filterpacks/base/native/time_util.cpp [new file with mode: 0644]
mca/filterpacks/base/native/time_util.h [new file with mode: 0644]
mca/filterpacks/base/native/utilities.h [new file with mode: 0644]
mca/filterpacks/base/native/vec_types.h [new file with mode: 0644]

diff --git a/mca/filterpacks/base/Android.mk b/mca/filterpacks/base/Android.mk
new file mode 100644 (file)
index 0000000..32deab9
--- /dev/null
@@ -0,0 +1,35 @@
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+##
+# Build native code
+##
+
+#Build base library
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE := libfilterpack_base
+LOCAL_SRC_FILES := native/geometry.cpp \
+                   native/time_util.cpp
+
+LOCAL_CFLAGS := -DANDROID
+
+include external/stlport/libstlport.mk
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/mca/filterpacks/base/native/basictypes.h b/mca/filterpacks/base/native/basictypes.h
new file mode 100644 (file)
index 0000000..9bddc82
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BASE_BASIC_TYPES_H_
+#define BASE_BASIC_TYPES_H_
+
+#include <stdint.h>
+
+// STL containers
+#include <vector>
+using std::vector;
+#include <map>
+using std::map;
+#include <string>
+using std::string;
+#include <sstream>
+using std::stringstream;
+using std::istringstream;
+using std::ostringstream;
+#include <utility>
+using std::pair;
+#include <list>
+using std::list;
+#include <set>
+using std::set;
+#include <stack>
+using std::stack;
+
+#include <memory>
+using std::auto_ptr;
+
+// Integral types
+typedef int8_t   int8;
+typedef uint8_t  uint8;
+typedef int16_t  int16;
+typedef uint16_t uint16;
+typedef int32_t  int32;
+typedef uint32_t uint32;
+typedef int64_t  int64;
+typedef uint64_t uint64;
+
+#endif // BASE_BASIC_TYPES_H_
+
diff --git a/mca/filterpacks/base/native/geometry.cpp b/mca/filterpacks/base/native/geometry.cpp
new file mode 100644 (file)
index 0000000..d1591c2
--- /dev/null
@@ -0,0 +1,149 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#include <assert.h>
+#include <cutils/log.h>
+#include <math.h>
+
+#include "geometry.h"
+
+#define ASSERT(x) assert(x)
+
+namespace android {
+namespace mff {
+
+float Point::Length() const {
+  return sqrtf(x_ * x_ + y_ * y_);
+}
+
+bool Point::ScaleTo(float new_length) {
+  float length = Length();
+  if (length == 0.0f) {
+    return false;
+  }
+  x_ *= new_length / length;
+  y_ *= new_length / length;
+  return true;
+}
+
+float Point::Distance(const Point& p0, const Point& p1) {
+  Point diff = p1 - p0;
+  return diff.Length();
+}
+
+Point Point::operator+(const Point& other) const {
+  Point out;
+  out.x_ = x_ + other.x_;
+  out.y_ = y_ + other.y_;
+  return out;
+}
+
+Point Point::operator-(const Point& other) const {
+  Point out;
+  out.x_ = x_ - other.x_;
+  out.y_ = y_ - other.y_;
+  return out;
+}
+
+Point Point::operator*(float factor) const {
+  Point out;
+  out.x_ = factor * x_;
+  out.y_ = factor * y_;
+  return out;
+}
+
+void Point::Rotate90Clockwise() {
+  const float x = x_;
+  x_ = y_;
+  y_ = -x;
+}
+
+bool Rect::ExpandToAspectRatio(float ratio) {
+  if (width <= 0.0f || height <= 0.0f || ratio <= 0.0f) {
+    return false;
+  }
+
+  const float current_ratio = width / height;
+  if (current_ratio < ratio) {
+    const float dx = width * (ratio / current_ratio - 1.0f);
+    x -= dx / 2.0f;
+    width += dx;
+  } else {
+    const float dy = height * (current_ratio / ratio - 1.0f);
+    y -= dy / 2.0f;
+    height += dy;
+  }
+  return true;
+}
+
+bool Rect::ExpandToMinLength(float length) {
+  if (width <= 0.0f || height <= 0.0f || length <= 0.0f) {
+    return false;
+  }
+
+  const float current_length = width > height ? width : height;
+  if (length > current_length) {
+    const float dx = width * (length / current_length - 1.0f);
+    x -= dx / 2.0f;
+    width += dx;
+    const float dy = height * (length / current_length - 1.0f);
+    y -= dy / 2.0f;
+    height += dy;
+  }
+  return true;
+}
+
+bool Rect::ScaleWithLengthLimit(float factor, float max_length) {
+  if (width <= 0.0f || height <= 0.0f || factor <= 0.0f) {
+    return false;
+  }
+
+  const float current_length = width > height ? width : height;
+  if (current_length >= max_length) {
+    return true;
+  }
+
+  float f = factor;
+  if (current_length * f > max_length) {
+    f *= max_length / (current_length * f);
+  }
+
+  const float dx = width * (f - 1.0f);
+  x -= dx / 2.0f;
+  width += dx;
+  const float dy = height * (f - 1.0f);
+  y -= dy / 2.0f;
+  height += dy;
+  return true;
+}
+
+const Point& Quad::point(int ix) const {
+  ASSERT(ix < static_cast<int>(points_.size()));
+  return points_[ix];
+}
+
+bool SlantedRect::FromCenterAxisAndLengths(const Point& center,
+                                           const Point& vert_axis,
+                                           const Point& lengths) {
+  Point dy = vert_axis;
+  if (!dy.ScaleTo(lengths.y() / 2.0f)) {
+    LOGE("Illegal axis: %f %f", vert_axis.x(), vert_axis.y());
+    return false;
+  }
+
+  Point dx = dy;
+  dx.Rotate90Clockwise();
+  dx.ScaleTo(lengths.x() / 2.0f);
+
+  points_[0] = center - dx - dy;
+  points_[1] = center + dx - dy;
+  points_[2] = center - dx + dy;
+  points_[3] = center + dx + dy;
+
+  width_ = lengths.x();
+  height_ = lengths.y();
+
+  return true;
+}
+
+} // namespace mff
+} // namespace android
diff --git a/mca/filterpacks/base/native/geometry.h b/mca/filterpacks/base/native/geometry.h
new file mode 100644 (file)
index 0000000..3d5b4b6
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VIDEO_FILTER_GEOMETRY_H__
+#define VIDEO_FILTER_GEOMETRY_H__
+
+#include "basictypes.h"
+
+namespace android {
+namespace mff {
+
+// This is an initial implementation of some geometrical structures. This is
+// likely to grow and become more sophisticated in the future.
+
+class Point {
+  public:
+    Point() : x_(0.0f), y_(0.0f) {}
+    Point(float x, float y) : x_(x), y_(y) {}
+
+    float x() const { return x_; }
+    float y() const { return y_; }
+
+    float Length() const;
+    bool ScaleTo(float new_length);
+    static float Distance(const Point& p0, const Point& p1);
+
+    // Add more of these as needed:
+    Point operator+(const Point& other) const;
+    Point operator-(const Point& other) const;
+    Point operator*(float factor) const;
+
+    void Rotate90Clockwise();
+
+  private:
+    float x_, y_;
+};
+
+class Quad {
+  public:
+    Quad() : points_(4) {}
+    virtual ~Quad() {}
+
+    Quad(const Point& p0, const Point& p1, const Point& p2, const Point& p3)
+        : points_(4) {
+      points_[0] = p0;
+      points_[1] = p1;
+      points_[2] = p2;
+      points_[3] = p3;
+    }
+
+    const vector<Point>& points() const { return points_; }
+    const Point& point(int ix) const;
+
+  protected:
+    vector<Point> points_;
+};
+
+class SlantedRect : public Quad {
+  public:
+    SlantedRect() : width_(0.0f), height_(0.0f) {}
+    virtual ~SlantedRect() {}
+
+    bool FromCenterAxisAndLengths(const Point& center,
+                                  const Point& vert_axis,
+                                  const Point& lenghts);
+
+    float width() const { return width_; }
+    float height() const { return height_; }
+
+  private:
+    float width_;
+    float height_;
+};
+
+struct Rect {
+  float x, y, width, height;
+
+  Rect() {
+    x = y = 0.0f;
+    width = height = 1.0f;
+  }
+
+  Rect(float x, float y, float width, float height) {
+    this->x = x;
+    this->y = y;
+    this->width = width;
+    this->height = height;
+  }
+
+  bool ExpandToAspectRatio(float ratio);
+  bool ExpandToMinLength(float length);
+  bool ScaleWithLengthLimit(float factor, float max_length);
+};
+
+} // namespace mff
+} // namespace android
+
+#endif
diff --git a/mca/filterpacks/base/native/time_util.cpp b/mca/filterpacks/base/native/time_util.cpp
new file mode 100644 (file)
index 0000000..2a76ecb
--- /dev/null
@@ -0,0 +1,77 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#include "time_util.h"
+
+#include <map>
+#include <sys/time.h>
+
+#include <cutils/log.h>
+#include "utilities.h"
+
+namespace android {
+namespace mff {
+
+uint64_t getTimeUs() {
+    static long basesec;
+    struct timeval tv;
+    uint64_t nowtime;
+    gettimeofday(&tv, 0);
+    if (basesec == 0) {
+        basesec = tv.tv_sec;
+    }
+    nowtime = (uint64_t)(tv.tv_sec - basesec) * (uint64_t)1000000 +
+              (uint64_t)tv.tv_usec;
+    return nowtime;
+}
+
+const uint64_t NamedStopWatch::kDefaultLoggingPeriodInFrames = 100;
+
+NamedStopWatch::NamedStopWatch(const std::string& name)
+      : mName(name),
+        mLoggingPeriodInFrames(kDefaultLoggingPeriodInFrames),
+        mStartUSec(0),
+        mNumCalls(0),
+        mTotalUSec(0) {
+}
+
+void NamedStopWatch::Start() {
+    mStartUSec = getTimeUs();
+}
+
+void NamedStopWatch::Stop() {
+    if (!mStartUSec) {
+        return;
+    }
+    uint64_t stopUSec = getTimeUs();
+    if (stopUSec > mStartUSec) {
+        ++mNumCalls;
+        mTotalUSec += stopUSec - mStartUSec;
+        if (mNumCalls % mLoggingPeriodInFrames == 0) {
+            const float mSec = TotalUSec() * 1.0E-3f / NumCalls();
+            LOGE("%s: %f ms", Name().c_str(), mSec);
+        }
+    }
+    mStartUSec = 0;
+}
+
+namespace {
+static NamedStopWatch* GetWatchForName(const string& watch_name) {
+    // TODO: this leaks the NamedStopWatch objects. Replace it with a
+    // singleton to avoid that and make it thread safe.
+    static map<string, NamedStopWatch*> watches;
+    NamedStopWatch* watch = FindPtrOrNull(watches, watch_name);
+    if (!watch) {
+        watch = new NamedStopWatch(watch_name);
+        watches[watch_name] = watch;
+    }
+    return watch;
+};
+}  // namespace
+
+ScopedTimer::ScopedTimer(const string& stop_watch_name) {
+    mWatch = GetWatchForName(stop_watch_name);
+    mWatch->Start();
+}
+
+} // namespace mff
+} // namespace android
diff --git a/mca/filterpacks/base/native/time_util.h b/mca/filterpacks/base/native/time_util.h
new file mode 100644 (file)
index 0000000..78f5cac
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#ifndef VIDEO_FILTER_TIME_UTIL_H_
+#define VIDEO_FILTER_TIME_UTIL_H_
+
+#include <string>
+#include <utils/RefBase.h>
+
+#include "basictypes.h"
+
+#define LOG_MFF_RUNNING_TIMES 0
+
+namespace android {
+namespace mff {
+
+uint64_t getTimeUs();
+
+class NamedStopWatch : public RefBase {
+  public:
+    static const uint64_t kDefaultLoggingPeriodInFrames;
+
+    explicit NamedStopWatch(const string& name);
+    void Start();
+    void Stop();
+
+    void SetName(const string& name) { mName = name; }
+    void SetLoggingPeriodInFrames(uint64_t numFrames) {
+        mLoggingPeriodInFrames = numFrames;
+    }
+
+    const string& Name() const { return mName; }
+    uint64_t NumCalls() const { return mNumCalls; }
+    uint64_t TotalUSec() const { return mTotalUSec; }
+
+  private:
+    string mName;
+    uint64_t mLoggingPeriodInFrames;
+    uint64_t mStartUSec;
+    uint64_t mNumCalls;
+    uint64_t mTotalUSec;
+};
+
+class ScopedTimer {
+  public:
+    explicit ScopedTimer(const string& stop_watch_name);
+    explicit ScopedTimer(NamedStopWatch* watch)
+        : mWatch(watch) { mWatch->Start(); }
+    ~ScopedTimer() { mWatch->Stop(); }
+
+  private:
+    NamedStopWatch* mWatch;
+};
+
+} // namespace mff
+} // namespace android
+
+#endif  // VIDEO_FILTER_TIME_UTIL_H_
diff --git a/mca/filterpacks/base/native/utilities.h b/mca/filterpacks/base/native/utilities.h
new file mode 100644 (file)
index 0000000..cd776c1
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BASE_UTILTIES_H_
+#define BASE_UTILTIES_H_
+
+#include "basictypes.h"
+
+// Convenience Macro to make copy constructor and assignment operator private
+// (thereby disallowing copying and assigning).
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+  TypeName(const TypeName&);               \
+  void operator=(const TypeName&)
+
+// A macro to disallow all the implicit constructors, namely the
+// default constructor, copy constructor and operator= functions.
+#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+  TypeName();                                    \
+  DISALLOW_COPY_AND_ASSIGN(TypeName)
+
+// STLDeleteContainerPointers()
+//  For a range within a container of pointers, calls delete
+//  (non-array version) on these pointers.
+// NOTE: for these three functions, we could just implement a DeleteObject
+// functor and then call for_each() on the range and functor, but this
+// requires us to pull in all of algorithm.h, which seems expensive.
+// For hash_[multi]set, it is important that this deletes behind the iterator
+// because the hash_set may call the hash function on the iterator when it is
+// advanced, which could result in the hash function trying to deference a
+// stale pointer.
+template <class ForwardIterator>
+void STLDeleteContainerPointers(ForwardIterator begin,
+                                ForwardIterator end) {
+  while (begin != end) {
+    ForwardIterator temp = begin;
+    ++begin;
+    delete *temp;
+  }
+}
+
+// Given an STL container consisting of (key, value) pairs, STLDeleteValues
+// deletes all the "value" components and clears the container.  Does nothing
+// in the case it's given a NULL pointer.
+template <class T>
+void STLDeleteValues(T *v) {
+  if (!v) return;
+  for (typename T::iterator i = v->begin(); i != v->end(); ++i) {
+    delete i->second;
+  }
+  v->clear();
+}
+
+// Perform a lookup in a map or hash_map.
+// If the key is present a const pointer to the associated value is returned,
+// otherwise a NULL pointer is returned.
+template <class Collection>
+const typename Collection::value_type::second_type*
+FindOrNull(const Collection& collection,
+           const typename Collection::value_type::first_type& key) {
+  typename Collection::const_iterator it = collection.find(key);
+  if (it == collection.end()) {
+    return 0;
+  }
+  return &it->second;
+}
+
+// A simple class that gives checklist functionality: There are essemtially two
+// operations defined on a CheckList:
+//  - Adding a new (unchecked) item.
+//  - Checking off an item.
+// When checking off the last remaining item CheckItem() returns true.
+template<typename T>
+class CheckList {
+  public:
+    // Add a new unchecked item. Does nothing if item is already in checklist.
+    void AddItem(const T& item);
+
+    // Check off an item in the checklist. Returns true if all items have been
+    // checked.
+    bool CheckItem(const T& item);
+
+    // Clear the checklist.
+    void Clear() {
+      items_.clear();
+    }
+
+  private:
+    set<T> items_;
+};
+
+template<typename T>
+void CheckList<T>::AddItem(const T& item) {
+  if (!ContainsKey(items_, item))
+    items_.insert(item);
+}
+
+template<typename T>
+bool CheckList<T>::CheckItem(const T& item) {
+  typename set<T>::iterator iter = items_.find(item);
+  if (iter != items_.end())
+    items_.erase(iter);
+  return items_.empty();
+}
+
+// Perform a lookup in a map or hash_map whose values are pointers.
+// If the key is present a const pointer to the associated value is returned,
+// otherwise a NULL pointer is returned.
+// This function does not distinguish between a missing key and a key mapped
+// to a NULL value.
+template <class Collection>
+const typename Collection::value_type::second_type
+FindPtrOrNull(const Collection& collection,
+              const typename Collection::value_type::first_type& key) {
+  typename Collection::const_iterator it = collection.find(key);
+  if (it == collection.end()) {
+    return 0;
+  }
+  return it->second;
+}
+
+// Test to see if a set, map, hash_set or hash_map contains a particular key.
+// Returns true if the key is in the collection.
+template <typename Collection, typename Key>
+bool ContainsKey(const Collection& collection, const Key& key) {
+  return collection.find(key) != collection.end();
+}
+
+// Insert a new key and value into a map or hash_map.
+// If the key is not present in the map the key and value are
+// inserted, otherwise nothing happens. True indicates that an insert
+// took place, false indicates the key was already present.
+template <class Collection, class Key, class Value>
+bool InsertIfNotPresent(Collection * const collection,
+                        const Key& key, const Value& value) {
+  pair<typename Collection::iterator, bool> ret =
+    collection->insert(typename Collection::value_type(key, value));
+  return ret.second;
+}
+
+#endif // BASE_UTILTIES_H_
+
diff --git a/mca/filterpacks/base/native/vec_types.h b/mca/filterpacks/base/native/vec_types.h
new file mode 100644 (file)
index 0000000..620c719
--- /dev/null
@@ -0,0 +1,163 @@
+#ifndef FILTERFW_CORE_VEC_TYPES_
+#define FILTERFW_CORE_VEC_TYPES_
+
+#include "basictypes.h"
+
+namespace android {
+namespace mff {
+
+template < class T, int dim>
+class VecBase {
+ public:
+  T data[dim];
+  VecBase() {}
+  VecBase<T,dim>& operator = (const VecBase<T, dim> &x) {
+    memcpy(data, x.data, sizeof(T)*dim);
+    return *this;
+  }
+  T & operator [] (int i) {
+    // out of boundary not checked
+    return data[i];
+  }
+  const T & operator [] (int i) const {
+    // out of boundary not checked
+    return data[i];
+  }
+  T Length() {
+    double sum = 0;
+    for (int i = 0; i < dim; ++i)
+      sum += static_cast<double> (data[i] * data[i]);
+    return static_cast<T>(sqrt(sum));
+  }
+};
+
+template < class T, int dim>
+class Vec : public VecBase<T,dim> {
+ public:
+  Vec() {}
+  Vec<T,dim>& operator = (const Vec<T, dim> &x) {
+    memcpy(this->data, x.data, sizeof(T)*dim);
+    return *this;
+  }
+};
+
+template <class T, int dim>
+Vec<T, dim> operator + (const Vec<T,dim> &x, const Vec<T,dim> &y) {
+  Vec<T, dim> out;
+  for (int i = 0; i < dim; i++)
+    out.data[i] = x.data[i] + y.data[i];
+  return out;
+}
+
+template <class T, int dim>
+Vec<T, dim> operator - (const Vec<T,dim> &x, const Vec<T,dim> &y) {
+  Vec<T, dim> out;
+  for (int i = 0; i < dim; i++)
+    out.data[i] = x.data[i] - y.data[i];
+  return out;
+}
+
+template <class T, int dim>
+Vec<T, dim> operator * (const Vec<T,dim> &x, const Vec<T,dim> &y) {
+  Vec<T, dim> out;
+  for (int i = 0; i < dim; i++)
+    out.data[i] = x.data[i] * y.data[i];
+  return out;
+}
+
+template <class T, int dim>
+Vec<T, dim> operator / (const Vec<T,dim> &x, const Vec<T,dim> &y) {
+  Vec<T, dim> out;
+  for (int i = 0; i < dim; i++)
+    out.data[i] = x.data[i] / y.data[i];
+  return out;
+}
+
+template <class T, int dim>
+T dot(const Vec<T,dim> &x, const Vec<T,dim> &y) {
+  T out = 0;
+  for (int i = 0; i < dim; i++)
+    out += x.data[i] * y.data[i];
+  return out;
+}
+
+template <class T, int dim>
+Vec<T, dim> operator * (const Vec<T,dim> &x, T scale) {
+  Vec<T, dim> out;
+  for (int i = 0; i < dim; i++)
+    out.data[i] = x.data[i] * scale;
+  return out;
+}
+
+template <class T, int dim>
+Vec<T, dim> operator / (const Vec<T,dim> &x, T scale) {
+  Vec<T, dim> out;
+  for (int i = 0; i < dim; i++)
+    out.data[i] = x.data[i] / scale;
+  return out;
+}
+
+template <class T, int dim>
+Vec<T, dim> operator + (const Vec<T,dim> &x, T val) {
+  Vec<T, dim> out;
+  for (int i = 0; i < dim; i++)
+    out.data[i] = x.data[i] + val;
+  return out;
+}
+
+// specialization for vec2, vec3, vec4 float
+template<>
+class Vec<float, 2> : public VecBase<float, 2> {
+public:
+  Vec() {}
+  Vec(float x, float y) {
+    data[0] = x;
+    data[1] = y;
+  }
+  Vec<float, 2>& operator = (const Vec<float, 2> &x) {
+    memcpy(data, x.data, sizeof(float)*2);
+    return *this;
+  }
+};
+
+template<>
+class Vec<float, 3> {
+public:
+  float data[3];
+  Vec() {}
+  Vec(float x, float y, float z) {
+    data[0] = x;
+    data[1] = y;
+    data[2] = z;
+  }
+  Vec<float, 3>& operator = (const Vec<float, 3> &x) {
+    memcpy(data, x.data, sizeof(float)*3);
+    return *this;
+  }
+};
+
+template<>
+class Vec<float, 4> {
+public:
+  float data[4];
+  Vec() {}
+  Vec(float x, float y, float z, float w) {
+    data[0] = x;
+    data[1] = y;
+    data[2] = z;
+    data[3] = w;
+  }
+  Vec<float, 4>& operator = (const Vec<float, 4> &x) {
+    memcpy(data, x.data, sizeof(float)*4);
+    return *this;
+  }
+};
+
+typedef Vec<float,2> Vec2f;
+typedef Vec<float,3> Vec3f;
+typedef Vec<float,4> Vec4f;
+
+} // namespace filterfw
+} // namespace android
+
+#endif