aboutsummaryrefslogtreecommitdiff
path: root/android_bench_suite/panorama.diff
diff options
context:
space:
mode:
Diffstat (limited to 'android_bench_suite/panorama.diff')
-rw-r--r--android_bench_suite/panorama.diff763
1 files changed, 763 insertions, 0 deletions
diff --git a/android_bench_suite/panorama.diff b/android_bench_suite/panorama.diff
new file mode 100644
index 00000000..fcd214e2
--- /dev/null
+++ b/android_bench_suite/panorama.diff
@@ -0,0 +1,763 @@
+diff --git a/jni/Android.mk b/jni/Android.mk
+index 8b816270..d48e0d8e 100755
+--- a/jni/Android.mk
++++ b/jni/Android.mk
+@@ -1,50 +1,53 @@
++local_target_dir := $(TARGET_OUT_DATA)/local/tmp
++
+ LOCAL_PATH:= $(call my-dir)
+
+ include $(CLEAR_VARS)
+
+ LOCAL_C_INCLUDES := \
+- $(LOCAL_PATH)/feature_stab/db_vlvm \
+- $(LOCAL_PATH)/feature_stab/src \
+- $(LOCAL_PATH)/feature_stab/src/dbreg \
+- $(LOCAL_PATH)/feature_mos/src \
+- $(LOCAL_PATH)/feature_mos/src/mosaic
+-
+-LOCAL_CFLAGS := -O3 -DNDEBUG
+-LOCAL_CPPFLAGS := -std=gnu++98
+-
+-LOCAL_SRC_FILES := \
+- feature_mos_jni.cpp \
+- mosaic_renderer_jni.cpp \
+- feature_mos/src/mosaic/trsMatrix.cpp \
+- feature_mos/src/mosaic/AlignFeatures.cpp \
+- feature_mos/src/mosaic/Blend.cpp \
+- feature_mos/src/mosaic/Delaunay.cpp \
+- feature_mos/src/mosaic/ImageUtils.cpp \
+- feature_mos/src/mosaic/Mosaic.cpp \
+- feature_mos/src/mosaic/Pyramid.cpp \
+- feature_mos/src/mosaic_renderer/Renderer.cpp \
+- feature_mos/src/mosaic_renderer/WarpRenderer.cpp \
+- feature_mos/src/mosaic_renderer/SurfaceTextureRenderer.cpp \
+- feature_mos/src/mosaic_renderer/YVURenderer.cpp \
+- feature_mos/src/mosaic_renderer/FrameBuffer.cpp \
+- feature_stab/db_vlvm/db_feature_detection.cpp \
+- feature_stab/db_vlvm/db_feature_matching.cpp \
+- feature_stab/db_vlvm/db_framestitching.cpp \
+- feature_stab/db_vlvm/db_image_homography.cpp \
+- feature_stab/db_vlvm/db_rob_image_homography.cpp \
+- feature_stab/db_vlvm/db_utilities.cpp \
+- feature_stab/db_vlvm/db_utilities_camera.cpp \
+- feature_stab/db_vlvm/db_utilities_indexing.cpp \
+- feature_stab/db_vlvm/db_utilities_linalg.cpp \
+- feature_stab/db_vlvm/db_utilities_poly.cpp \
+- feature_stab/src/dbreg/dbreg.cpp \
+- feature_stab/src/dbreg/dbstabsmooth.cpp \
+- feature_stab/src/dbreg/vp_motionmodel.c
++ $(LOCAL_PATH)/feature_mos/src \
++ $(LOCAL_PATH)/feature_stab/src \
++ $(LOCAL_PATH)/feature_stab/db_vlvm
+
+-LOCAL_SHARED_LIBRARIES := liblog libnativehelper libGLESv2
+-#LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -ldl -llog -lGLESv2 -L$(TARGET_OUT)
++LOCAL_SRC_FILES := benchmark.cpp \
++ feature_mos/src/mosaic/ImageUtils.cpp \
++ feature_mos/src/mosaic/Mosaic.cpp \
++ feature_mos/src/mosaic/AlignFeatures.cpp \
++ feature_mos/src/mosaic/Blend.cpp \
++ feature_mos/src/mosaic/Pyramid.cpp \
++ feature_mos/src/mosaic/trsMatrix.cpp \
++ feature_mos/src/mosaic/Delaunay.cpp \
++ feature_mos/src/mosaic_renderer/Renderer.cpp \
++ feature_mos/src/mosaic_renderer/WarpRenderer.cpp \
++ feature_mos/src/mosaic_renderer/SurfaceTextureRenderer.cpp \
++ feature_mos/src/mosaic_renderer/YVURenderer.cpp \
++ feature_mos/src/mosaic_renderer/FrameBuffer.cpp \
++ feature_stab/db_vlvm/db_rob_image_homography.cpp \
++ feature_stab/db_vlvm/db_feature_detection.cpp \
++ feature_stab/db_vlvm/db_image_homography.cpp \
++ feature_stab/db_vlvm/db_framestitching.cpp \
++ feature_stab/db_vlvm/db_feature_matching.cpp \
++ feature_stab/db_vlvm/db_utilities.cpp \
++ feature_stab/db_vlvm/db_utilities_camera.cpp \
++ feature_stab/db_vlvm/db_utilities_indexing.cpp \
++ feature_stab/db_vlvm/db_utilities_linalg.cpp \
++ feature_stab/db_vlvm/db_utilities_poly.cpp \
++ feature_stab/src/dbreg/dbstabsmooth.cpp \
++ feature_stab/src/dbreg/dbreg.cpp \
++ feature_stab/src/dbreg/vp_motionmodel.c
+
+-LOCAL_MODULE_TAGS := optional
++LOCAL_CFLAGS := -O3 -DNDEBUG -Wno-unused-parameter -Wno-maybe-uninitialized
++LOCAL_CFLAGS += $(CFLAGS_FOR_BENCH_SUITE)
++LOCAL_LDFLAGS := $(LDFLAGS_FOR_BENCH_SUITE)
++LOCAL_CPPFLAGS := -std=c++98
++LOCAL_MODULE_TAGS := tests
++LOCAL_MODULE := panorama_bench
++LOCAL_MODULE_STEM_32 := panorama_bench
++LOCAL_MODULE_STEM_64 := panorama_bench64
++LOCAL_MULTILIB := both
++LOCAL_MODULE_PATH := $(local_target_dir)
++LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
++LOCAL_FORCE_STATIC_EXECUTABLE := true
++LOCAL_STATIC_LIBRARIES := libc libm
+
+-LOCAL_MODULE := libjni_legacymosaic
+-include $(BUILD_SHARED_LIBRARY)
++include $(BUILD_EXECUTABLE)
+diff --git a/jni/benchmark.cpp b/jni/benchmark.cpp
+new file mode 100755
+index 00000000..2a6440f4
+--- /dev/null
++++ b/jni/benchmark.cpp
+@@ -0,0 +1,131 @@
++/*
++ * Copyright (C) 2012 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.
++ */
++
++#include <time.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <unistd.h>
++
++#include "mosaic/Mosaic.h"
++#include "mosaic/ImageUtils.h"
++
++#define MAX_FRAMES 200
++#define KERNEL_ITERATIONS 10
++
++const int blendingType = Blend::BLEND_TYPE_HORZ;
++const int stripType = Blend::STRIP_TYPE_WIDE;
++
++ImageType yvuFrames[MAX_FRAMES];
++
++int loadImages(const char* basename, int &width, int &height)
++{
++ char filename[512];
++ struct stat filestat;
++ int i;
++
++ for (i = 0; i < MAX_FRAMES; i++) {
++ sprintf(filename, "%s_%03d.ppm", basename, i + 1);
++ if (stat(filename, &filestat) != 0) break;
++ ImageType rgbFrame = ImageUtils::readBinaryPPM(filename, width, height);
++ yvuFrames[i] = ImageUtils::allocateImage(width, height,
++ ImageUtils::IMAGE_TYPE_NUM_CHANNELS);
++ ImageUtils::rgb2yvu(yvuFrames[i], rgbFrame, width, height);
++ ImageUtils::freeImage(rgbFrame);
++ }
++ return i;
++}
++
++int main(int argc, char **argv)
++{
++ struct timespec t1, t2, t3;
++
++ int width, height;
++ float totalElapsedTime = 0;
++
++ const char *basename;
++ const char *filename;
++
++ if (argc != 3) {
++ printf("Usage: %s input_dir output_filename\n", argv[0]);
++ return 0;
++ } else {
++ basename = argv[1];
++ filename = argv[2];
++ }
++
++ // Load the images outside the computational kernel
++ int totalFrames = loadImages(basename, width, height);
++
++ if (totalFrames == 0) {
++ printf("Image files not found. Make sure %s exists.\n",
++ basename);
++ return 1;
++ }
++
++ printf("%d frames loaded\n", totalFrames);
++
++
++ // Interesting stuff is here
++ for (int iteration = 0; iteration < KERNEL_ITERATIONS; iteration++) {
++ Mosaic mosaic;
++
++ mosaic.initialize(blendingType, stripType, width, height, -1, false, 0);
++
++ clock_gettime(CLOCK_MONOTONIC, &t1);
++ for (int i = 0; i < totalFrames; i++) {
++ mosaic.addFrame(yvuFrames[i]);
++ }
++ clock_gettime(CLOCK_MONOTONIC, &t2);
++
++ float progress = 0.0;
++ bool cancelComputation = false;
++
++ mosaic.createMosaic(progress, cancelComputation);
++
++ int mosaicWidth, mosaicHeight;
++ ImageType resultYVU = mosaic.getMosaic(mosaicWidth, mosaicHeight);
++
++ ImageType imageRGB = ImageUtils::allocateImage(
++ mosaicWidth, mosaicHeight, ImageUtils::IMAGE_TYPE_NUM_CHANNELS);
++
++ clock_gettime(CLOCK_MONOTONIC, &t3);
++
++ float elapsedTime =
++ (t3.tv_sec - t1.tv_sec) + (t3.tv_nsec - t1.tv_nsec)/1e9;
++ float addImageTime =
++ (t2.tv_sec - t1.tv_sec) + (t2.tv_nsec - t1.tv_nsec)/1e9;
++ float stitchImageTime =
++ (t3.tv_sec - t2.tv_sec) + (t3.tv_nsec - t2.tv_nsec)/1e9;
++
++ totalElapsedTime += elapsedTime;
++
++ printf("Iteration %d: %dx%d moasic created: "
++ "%.2f seconds (%.2f + %.2f)\n",
++ iteration, mosaicWidth, mosaicHeight,
++ elapsedTime, addImageTime, stitchImageTime);
++
++ // Write the output only once for correctness check
++ if (iteration == 0) {
++ ImageUtils::yvu2rgb(imageRGB, resultYVU, mosaicWidth,
++ mosaicHeight);
++ ImageUtils::writeBinaryPPM(imageRGB, filename, mosaicWidth,
++ mosaicHeight);
++ }
++ }
++ printf("Total elapsed time: %.2f seconds\n", totalElapsedTime);
++
++ return 0;
++}
+diff --git a/jni/feature_mos/src/mosaic/AlignFeatures.cpp b/jni/feature_mos/src/mosaic/AlignFeatures.cpp
+index aeabf8f9..703a5ea5 100644
+--- a/jni/feature_mos/src/mosaic/AlignFeatures.cpp
++++ b/jni/feature_mos/src/mosaic/AlignFeatures.cpp
+@@ -30,6 +30,8 @@
+
+ #define LOG_TAG "AlignFeatures"
+
++const double Align::DEFAULT_MAX_DISPARITY = 0.1;
++
+ Align::Align()
+ {
+ width = height = 0;
+diff --git a/jni/feature_mos/src/mosaic/AlignFeatures.h b/jni/feature_mos/src/mosaic/AlignFeatures.h
+index 19f39051..9999f575 100644
+--- a/jni/feature_mos/src/mosaic/AlignFeatures.h
++++ b/jni/feature_mos/src/mosaic/AlignFeatures.h
+@@ -44,7 +44,7 @@ public:
+ ///// Settings for feature-based alignment
+ // Number of features to use from corner detection
+ static const int DEFAULT_NR_CORNERS=750;
+- static const double DEFAULT_MAX_DISPARITY=0.1;//0.4;
++ static const double DEFAULT_MAX_DISPARITY;//0.4;
+ // Type of homography to model
+ static const int DEFAULT_MOTION_MODEL=DB_HOMOGRAPHY_TYPE_R_T;
+ // static const int DEFAULT_MOTION_MODEL=DB_HOMOGRAPHY_TYPE_PROJECTIVE;
+diff --git a/jni/feature_mos/src/mosaic/Blend.cpp b/jni/feature_mos/src/mosaic/Blend.cpp
+index e37755de..b6a843a2 100644
+--- a/jni/feature_mos/src/mosaic/Blend.cpp
++++ b/jni/feature_mos/src/mosaic/Blend.cpp
+@@ -26,8 +26,8 @@
+ #include "Geometry.h"
+ #include "trsMatrix.h"
+
+-#include "Log.h"
+-#define LOG_TAG "BLEND"
++const float Blend::LIMIT_SIZE_MULTIPLIER = 50.f * 2.0f;
++const float Blend::LIMIT_HEIGHT_MULTIPLIER = 2.5f;
+
+ Blend::Blend()
+ {
+@@ -67,7 +67,6 @@ int Blend::initialize(int blendingType, int stripType, int frame_width, int fram
+
+ if (!m_pFrameYPyr || !m_pFrameUPyr || !m_pFrameVPyr)
+ {
+- LOGE("Error: Could not allocate pyramids for blending");
+ return BLEND_RET_ERROR_MEMORY;
+ }
+
+@@ -122,7 +121,6 @@ int Blend::runBlend(MosaicFrame **oframes, MosaicFrame **rframes,
+
+ if (numCenters == 0)
+ {
+- LOGE("Error: No frames to blend");
+ return BLEND_RET_ERROR;
+ }
+
+@@ -228,9 +226,6 @@ int Blend::runBlend(MosaicFrame **oframes, MosaicFrame **rframes,
+
+ if (xRightMost <= xLeftMost || yBottomMost <= yTopMost)
+ {
+- LOGE("RunBlend: aborting -consistency check failed,"
+- "(xLeftMost, xRightMost, yTopMost, yBottomMost): (%d, %d, %d, %d)",
+- xLeftMost, xRightMost, yTopMost, yBottomMost);
+ return BLEND_RET_ERROR;
+ }
+
+@@ -241,17 +236,12 @@ int Blend::runBlend(MosaicFrame **oframes, MosaicFrame **rframes,
+ ret = MosaicSizeCheck(LIMIT_SIZE_MULTIPLIER, LIMIT_HEIGHT_MULTIPLIER);
+ if (ret != BLEND_RET_OK)
+ {
+- LOGE("RunBlend: aborting - mosaic size check failed, "
+- "(frame_width, frame_height) vs (mosaic_width, mosaic_height): "
+- "(%d, %d) vs (%d, %d)", width, height, Mwidth, Mheight);
+ return ret;
+ }
+
+- LOGI("Allocate mosaic image for blending - size: %d x %d", Mwidth, Mheight);
+ YUVinfo *imgMos = YUVinfo::allocateImage(Mwidth, Mheight);
+ if (imgMos == NULL)
+ {
+- LOGE("RunBlend: aborting - couldn't alloc %d x %d mosaic image", Mwidth, Mheight);
+ return BLEND_RET_ERROR_MEMORY;
+ }
+
+@@ -362,7 +352,6 @@ int Blend::FillFramePyramid(MosaicFrame *mb)
+ !PyramidShort::BorderReduce(m_pFrameUPyr, m_wb.nlevsC) || !PyramidShort::BorderExpand(m_pFrameUPyr, m_wb.nlevsC, -1) ||
+ !PyramidShort::BorderReduce(m_pFrameVPyr, m_wb.nlevsC) || !PyramidShort::BorderExpand(m_pFrameVPyr, m_wb.nlevsC, -1))
+ {
+- LOGE("Error: Could not generate Laplacian pyramids");
+ return BLEND_RET_ERROR;
+ }
+ else
+@@ -384,7 +373,6 @@ int Blend::DoMergeAndBlend(MosaicFrame **frames, int nsite,
+ m_pMosaicVPyr = PyramidShort::allocatePyramidPacked(m_wb.nlevsC,(unsigned short)rect.Width(),(unsigned short)rect.Height(),BORDER);
+ if (!m_pMosaicYPyr || !m_pMosaicUPyr || !m_pMosaicVPyr)
+ {
+- LOGE("Error: Could not allocate pyramids for blending");
+ return BLEND_RET_ERROR_MEMORY;
+ }
+
+@@ -579,6 +567,11 @@ int Blend::DoMergeAndBlend(MosaicFrame **frames, int nsite,
+ // Blend
+ PerformFinalBlending(imgMos, cropping_rect);
+
++ if (cropping_rect.Width() <= 0 || cropping_rect.Height() <= 0)
++ {
++ return BLEND_RET_ERROR;
++ }
++
+ if (m_pMosaicVPyr) free(m_pMosaicVPyr);
+ if (m_pMosaicUPyr) free(m_pMosaicUPyr);
+ if (m_pMosaicYPyr) free(m_pMosaicYPyr);
+@@ -632,7 +625,6 @@ int Blend::PerformFinalBlending(YUVinfo &imgMos, MosaicRect &cropping_rect)
+ if (!PyramidShort::BorderExpand(m_pMosaicYPyr, m_wb.nlevs, 1) || !PyramidShort::BorderExpand(m_pMosaicUPyr, m_wb.nlevsC, 1) ||
+ !PyramidShort::BorderExpand(m_pMosaicVPyr, m_wb.nlevsC, 1))
+ {
+- LOGE("Error: Could not BorderExpand!");
+ return BLEND_RET_ERROR;
+ }
+
+@@ -785,18 +777,31 @@ int Blend::PerformFinalBlending(YUVinfo &imgMos, MosaicRect &cropping_rect)
+ break;
+ }
+ }
++
+ }
+
++ RoundingCroppingSizeToMultipleOf8(cropping_rect);
++
+ for(int j=0; j<imgMos.Y.height; j++)
+ {
+ delete b[j];
+ }
+
+- delete b;
++ delete[] b;
+
+ return BLEND_RET_OK;
+ }
+
++void Blend::RoundingCroppingSizeToMultipleOf8(MosaicRect &rect) {
++ int height = rect.bottom - rect.top + 1;
++ int residue = height & 7;
++ rect.bottom -= residue;
++
++ int width = rect.right - rect.left + 1;
++ residue = width & 7;
++ rect.right -= residue;
++}
++
+ void Blend::ComputeMask(CSite *csite, BlendRect &vcrect, BlendRect &brect, MosaicRect &rect, YUVinfo &imgMos, int site_idx)
+ {
+ PyramidShort *dptr = m_pMosaicYPyr;
+diff --git a/jni/feature_mos/src/mosaic/Blend.h b/jni/feature_mos/src/mosaic/Blend.h
+index 6371fdeb..175eacd4 100644
+--- a/jni/feature_mos/src/mosaic/Blend.h
++++ b/jni/feature_mos/src/mosaic/Blend.h
+@@ -119,9 +119,10 @@ protected:
+ void CropFinalMosaic(YUVinfo &imgMos, MosaicRect &cropping_rect);
+
+ private:
+- static const float LIMIT_SIZE_MULTIPLIER = 5.0f * 2.0f;
+- static const float LIMIT_HEIGHT_MULTIPLIER = 2.5f;
++ static const float LIMIT_SIZE_MULTIPLIER;
++ static const float LIMIT_HEIGHT_MULTIPLIER;
+ int MosaicSizeCheck(float sizeMultiplier, float heightMultiplier);
++ void RoundingCroppingSizeToMultipleOf8(MosaicRect& rect);
+ };
+
+ #endif
+diff --git a/jni/feature_mos/src/mosaic/Delaunay.cpp b/jni/feature_mos/src/mosaic/Delaunay.cpp
+index 82f5d203..0ce09fc5 100644
+--- a/jni/feature_mos/src/mosaic/Delaunay.cpp
++++ b/jni/feature_mos/src/mosaic/Delaunay.cpp
+@@ -24,7 +24,7 @@
+
+ #define QQ 9 // Optimal value as determined by testing
+ #define DM 38 // 2^(1+DM/2) element sort capability. DM=38 for >10^6 elements
+-#define NYL (-1)
++#define NYL -1
+ #define valid(l) ccw(orig(basel), dest(l), dest(basel))
+
+
+diff --git a/jni/feature_mos/src/mosaic/ImageUtils.cpp b/jni/feature_mos/src/mosaic/ImageUtils.cpp
+index 6d0aac0c..daa86060 100644
+--- a/jni/feature_mos/src/mosaic/ImageUtils.cpp
++++ b/jni/feature_mos/src/mosaic/ImageUtils.cpp
+@@ -283,7 +283,7 @@ ImageType ImageUtils::readBinaryPPM(const char *filename, int &width, int &heigh
+
+ FILE *imgin = NULL;
+ int mval=0, format=0, eret;
+- ImageType ret = IMAGE_TYPE_NOIMAGE;
++ ImageType ret = NULL;//IMAGE_TYPE_NOIMAGE;
+
+ imgin = fopen(filename, "r");
+ if (imgin == NULL) {
+diff --git a/jni/feature_mos/src/mosaic/ImageUtils.h b/jni/feature_mos/src/mosaic/ImageUtils.h
+index 87782383..92965ca8 100644
+--- a/jni/feature_mos/src/mosaic/ImageUtils.h
++++ b/jni/feature_mos/src/mosaic/ImageUtils.h
+@@ -47,7 +47,7 @@ public:
+ /**
+ * Definition of an empty image.
+ */
+- static const int IMAGE_TYPE_NOIMAGE = NULL;
++ static const int IMAGE_TYPE_NOIMAGE = 0;
+
+ /**
+ * Convert image from BGR (interlaced) to YVU (non-interlaced)
+diff --git a/jni/feature_mos/src/mosaic/Log.h b/jni/feature_mos/src/mosaic/Log.h
+index cf6f14b1..2adfeda9 100644
+--- a/jni/feature_mos/src/mosaic/Log.h
++++ b/jni/feature_mos/src/mosaic/Log.h
+@@ -14,7 +14,7 @@
+ * limitations under the License.
+ */
+ #ifndef LOG_H_
+-#define LOG_H_
++#define LOG_H_
+
+ #include <android/log.h>
+ #define LOGV(...) __android_log_print(ANDROID_LOG_SILENT, LOG_TAG, __VA_ARGS__)
+diff --git a/jni/feature_mos/src/mosaic/Mosaic.cpp b/jni/feature_mos/src/mosaic/Mosaic.cpp
+index f17c030b..4abc6f68 100644
+--- a/jni/feature_mos/src/mosaic/Mosaic.cpp
++++ b/jni/feature_mos/src/mosaic/Mosaic.cpp
+@@ -26,9 +26,6 @@
+ #include "Mosaic.h"
+ #include "trsMatrix.h"
+
+-#include "Log.h"
+-#define LOG_TAG "MOSAIC"
+-
+ Mosaic::Mosaic()
+ {
+ initialized = false;
+@@ -47,6 +44,10 @@ Mosaic::~Mosaic()
+ delete frames;
+ delete rframes;
+
++ for (int j = 0; j < owned_size; j++)
++ delete owned_frames[j];
++ delete owned_frames;
++
+ if (aligner != NULL)
+ delete aligner;
+ if (blender != NULL)
+@@ -88,13 +89,10 @@ int Mosaic::initialize(int blendingType, int stripType, int width, int height, i
+ {
+ frames[i] = NULL;
+ }
+-
+-
+ }
+
+- LOGV("Initialize %d %d", width, height);
+- LOGV("Frame width %d,%d", width, height);
+- LOGV("Max num frames %d", max_frames);
++ owned_frames = new ImageType[max_frames];
++ owned_size = 0;
+
+ aligner = new Align();
+ aligner->initialize(width, height,quarter_res,thresh_still);
+@@ -107,7 +105,6 @@ int Mosaic::initialize(int blendingType, int stripType, int width, int height, i
+ blender->initialize(blendingType, stripType, width, height);
+ } else {
+ blender = NULL;
+- LOGE("Error: Unknown blending type %d",blendingType);
+ return MOSAIC_RET_ERROR;
+ }
+
+@@ -123,7 +120,15 @@ int Mosaic::addFrameRGB(ImageType imageRGB)
+ imageYVU = ImageUtils::allocateImage(this->width, this->height, ImageUtils::IMAGE_TYPE_NUM_CHANNELS);
+ ImageUtils::rgb2yvu(imageYVU, imageRGB, width, height);
+
+- return addFrame(imageYVU);
++ int existing_frames_size = frames_size;
++ int ret = addFrame(imageYVU);
++
++ if (frames_size > existing_frames_size)
++ owned_frames[owned_size++] = imageYVU;
++ else
++ ImageUtils::freeImage(imageYVU);
++
++ return ret;
+ }
+
+ int Mosaic::addFrame(ImageType imageYVU)
+@@ -146,8 +151,6 @@ int Mosaic::addFrame(ImageType imageYVU)
+
+ if (frames_size >= max_frames)
+ {
+- LOGV("WARNING: More frames than preallocated, ignoring."
+- "Increase maximum number of frames (-f <max_frames>) to avoid this");
+ return MOSAIC_RET_ERROR;
+ }
+
+diff --git a/jni/feature_mos/src/mosaic/Mosaic.h b/jni/feature_mos/src/mosaic/Mosaic.h
+index fc6ecd90..9dea6642 100644
+--- a/jni/feature_mos/src/mosaic/Mosaic.h
++++ b/jni/feature_mos/src/mosaic/Mosaic.h
+@@ -181,6 +181,12 @@ protected:
+ int frames_size;
+ int max_frames;
+
++ /**
++ * Implicitly created frames, should be freed by Mosaic.
++ */
++ ImageType *owned_frames;
++ int owned_size;
++
+ /**
+ * Initialization state.
+ */
+diff --git a/jni/feature_mos/src/mosaic/Pyramid.cpp b/jni/feature_mos/src/mosaic/Pyramid.cpp
+index 945eafba..b022d73d 100644
+--- a/jni/feature_mos/src/mosaic/Pyramid.cpp
++++ b/jni/feature_mos/src/mosaic/Pyramid.cpp
+@@ -154,24 +154,30 @@ void PyramidShort::BorderExpandOdd(PyramidShort *in, PyramidShort *out, PyramidS
+ // Vertical Filter
+ for (j = -off; j < in->height + off; j++) {
+ int j2 = j * 2;
+- for (i = -scr->border; i < scr->width + scr->border; i++) {
++ int limit = scr->width + scr->border;
++ for (i = -scr->border; i < limit; i++) {
++ int t1 = in->ptr[j][i];
++ int t2 = in->ptr[j+1][i];
+ scr->ptr[j2][i] = (short)
+- ((6 * in->ptr[j][i] + (in->ptr[j-1][i] + in->ptr[j+1][i]) + 4) >> 3);
+- scr->ptr[j2+1][i] = (short)((in->ptr[j][i] + in->ptr[j+1][i] + 1) >> 1);
++ ((6 * t1 + (in->ptr[j-1][i] + t2) + 4) >> 3);
++ scr->ptr[j2+1][i] = (short)((t1 + t2 + 1) >> 1);
+ }
+ }
+
+ BorderSpread(scr, 0, 0, 3, 3);
+
+ // Horizontal Filter
+- for (i = -off; i < scr->width + off; i++) {
+- int i2 = i * 2;
+- for (j = -out->border; j < out->height + out->border; j++) {
++ int limit = out->height + out->border;
++ for (j = -out->border; j < limit; j++) {
++ for (i = -off; i < scr->width + off; i++) {
++ int i2 = i * 2;
++ int t1 = scr->ptr[j][i];
++ int t2 = scr->ptr[j][i+1];
+ out->ptr[j][i2] = (short) (out->ptr[j][i2] +
+- (mode * ((6 * scr->ptr[j][i] +
+- scr->ptr[j][i-1] + scr->ptr[j][i+1] + 4) >> 3)));
++ (mode * ((6 * t1 +
++ scr->ptr[j][i-1] + t2 + 4) >> 3)));
+ out->ptr[j][i2+1] = (short) (out->ptr[j][i2+1] +
+- (mode * ((scr->ptr[j][i] + scr->ptr[j][i+1] + 1) >> 1)));
++ (mode * ((t1 + t2 + 1) >> 1)));
+ }
+ }
+
+diff --git a/jni/feature_mos/src/mosaic_renderer/FrameBuffer.cpp b/jni/feature_mos/src/mosaic_renderer/FrameBuffer.cpp
+index 9a07e496..a956f23b 100755
+--- a/jni/feature_mos/src/mosaic_renderer/FrameBuffer.cpp
++++ b/jni/feature_mos/src/mosaic_renderer/FrameBuffer.cpp
+@@ -55,6 +55,8 @@ bool FrameBuffer::Init(int width, int height, GLenum format) {
+ GL_TEXTURE_2D,
+ mTextureName,
+ 0);
++ checkFramebufferStatus("FrameBuffer.cpp");
++ checkGlError("framebuffertexture2d");
+
+ if (!checkGlError("texture setup")) {
+ return false;
+@@ -94,6 +96,3 @@ int FrameBuffer::GetWidth() const {
+ int FrameBuffer::GetHeight() const {
+ return mHeight;
+ }
+-
+-
+-
+diff --git a/jni/feature_mos/src/mosaic_renderer/FrameBuffer.h b/jni/feature_mos/src/mosaic_renderer/FrameBuffer.h
+index b6a20ad1..314b1262 100755
+--- a/jni/feature_mos/src/mosaic_renderer/FrameBuffer.h
++++ b/jni/feature_mos/src/mosaic_renderer/FrameBuffer.h
+@@ -4,7 +4,10 @@
+ #include <GLES2/gl2.h>
+ #include <GLES2/gl2ext.h>
+
+-extern bool checkGlError(const char* op);
++#define checkGlError(op) checkGLErrorDetail(__FILE__, __LINE__, (op))
++
++extern bool checkGLErrorDetail(const char* file, int line, const char* op);
++extern void checkFramebufferStatus(const char* name);
+
+ class FrameBuffer {
+ public:
+diff --git a/jni/feature_mos/src/mosaic_renderer/Renderer.cpp b/jni/feature_mos/src/mosaic_renderer/Renderer.cpp
+index c5c143f9..b9938eb6 100755
+--- a/jni/feature_mos/src/mosaic_renderer/Renderer.cpp
++++ b/jni/feature_mos/src/mosaic_renderer/Renderer.cpp
+@@ -87,7 +87,7 @@ GLuint Renderer::createProgram(const char* pVertexSource, const char* pFragmentS
+ GLint linkStatus = GL_FALSE;
+ glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+
+- LOGI("Program Linked!");
++ LOGI("Program Linked (%d)!", program);
+
+ if (linkStatus != GL_TRUE)
+ {
+diff --git a/jni/feature_stab/db_vlvm/db_utilities_constants.h b/jni/feature_stab/db_vlvm/db_utilities_constants.h
+index 612fc783..07565efd 100644
+--- a/jni/feature_stab/db_vlvm/db_utilities_constants.h
++++ b/jni/feature_stab/db_vlvm/db_utilities_constants.h
+@@ -64,7 +64,7 @@
+ #define DB_DEFAULT_ABS_CORNER_THRESHOLD 50000000.0
+ #define DB_DEFAULT_REL_CORNER_THRESHOLD 0.00005
+ #define DB_DEFAULT_MAX_DISPARITY 0.1
+-#define DB_DEFAULT_NO_DISPARITY (-1.0)
++#define DB_DEFAULT_NO_DISPARITY -1.0
+ #define DB_DEFAULT_MAX_TRACK_LENGTH 300
+
+ #define DB_DEFAULT_MAX_NR_CAMERAS 1000
+diff --git a/jni/feature_stab/src/dbreg/dbreg.cpp b/jni/feature_stab/src/dbreg/dbreg.cpp
+index dc7d58fe..da06aa2a 100644
+--- a/jni/feature_stab/src/dbreg/dbreg.cpp
++++ b/jni/feature_stab/src/dbreg/dbreg.cpp
+@@ -485,7 +485,8 @@ int db_FrameToReferenceRegistration::AddFrame(const unsigned char * const * im,
+ if(m_do_motion_smoothing)
+ SmoothMotion();
+
+- db_PrintDoubleMatrix(m_H_ref_to_ins,3,3);
++ // Disable debug printing
++ // db_PrintDoubleMatrix(m_H_ref_to_ins,3,3);
+
+ db_Copy9(H, m_H_ref_to_ins);
+
+diff --git a/jni/feature_stab/src/dbreg/dbstabsmooth.cpp b/jni/feature_stab/src/dbreg/dbstabsmooth.cpp
+index dffff8ab..2bb5d2e5 100644
+--- a/jni/feature_stab/src/dbreg/dbstabsmooth.cpp
++++ b/jni/feature_stab/src/dbreg/dbstabsmooth.cpp
+@@ -136,7 +136,7 @@ bool db_StabilizationSmoother::smoothMotionAdaptive(/*VP_BIMG *bimg,*/int hsize,
+ smoothFactor = minSmoothFactor;
+
+ // Find the amount of motion that must be compensated so that no "border" pixels are seen in the stable video
+- for (smoothFactor = smoothFactor; smoothFactor >= minSmoothFactor; smoothFactor -= 0.01) {
++ for (; smoothFactor >= minSmoothFactor; smoothFactor -= 0.01) {
+ // Compute the smoothed motion
+ if(!smoothMotion(inmot, &tmpMotion, smoothFactor))
+ break;
+diff --git a/jni/feature_stab/src/dbreg/vp_motionmodel.h b/jni/feature_stab/src/dbreg/vp_motionmodel.h
+index 71a7f7e7..a63ac001 100644
+--- a/jni/feature_stab/src/dbreg/vp_motionmodel.h
++++ b/jni/feature_stab/src/dbreg/vp_motionmodel.h
+@@ -120,7 +120,7 @@ enum VP_MOTION_MODEL {
+ VP_VFE_AFFINE=120
+ };
+
+-#define VP_REFID (-1) /* Default ID used for reference frame */
++#define VP_REFID -1 /* Default ID used for reference frame */
+
+ typedef struct {
+ VP_TRS par; /* Contains the motion paramerers.
+@@ -205,16 +205,16 @@ typedef struct {
+ /* Warp a 2d point (assuming the z component is zero) */
+ #define VP_WARP_POINT_2D(inx,iny,m,outx,outy) do {\
+ VP_PAR vpTmpWarpPnt___= MWX(m)*(inx)+MWY(m)*(iny)+MWW(m); \
+- (outx) = (MXX(m)*((VP_PAR)(inx))+MXY(m)*((VP_PAR)(iny))+MXW(m))/vpTmpWarpPnt___; \
+- (outy) = (MYX(m)*((VP_PAR)(inx))+MYY(m)*((VP_PAR)(iny))+MYW(m))/vpTmpWarpPnt___; } while (0)
++ outx = (MXX(m)*((VP_PAR)inx)+MXY(m)*((VP_PAR)iny)+MXW(m))/vpTmpWarpPnt___; \
++ outy = (MYX(m)*((VP_PAR)inx)+MYY(m)*((VP_PAR)iny)+MYW(m))/vpTmpWarpPnt___; } while (0)
+
+ /* Warp a 3d point */
+ #define VP_WARP_POINT_3D(inx,iny,inz,m,outx,outy,outz) do {\
+- VP_PAR vpTmpWarpPnt___= MWX(m)*(inx)+MWY(m)*(iny)+MWZ(m)*((VP_PAR)(inz))+MWW(m); \
+- (outx) = (MXX(m)*((VP_PAR)(inx))+MXY(m)*((VP_PAR)(iny))+MXZ(m)*((VP_PAR)(inz))+MXW(m))/vpTmpWarpPnt___; \
+- (outy) = (MYX(m)*((VP_PAR)(inx))+MYY(m)*((VP_PAR)(iny))+MYZ(m)*((VP_PAR)(inz))+MYW(m))/vpTmpWarpPnt___; \
+- (outz) = MZX(m)*((VP_PAR)(inx))+MZY(m)*((VP_PAR)(iny))+MZZ(m)*((VP_PAR)(inz))+MZW(m); \
+- if ((m).type==VP_MOTION_PROJ_3D) (outz)/=vpTmpWarpPnt___; } while (0)
++ VP_PAR vpTmpWarpPnt___= MWX(m)*(inx)+MWY(m)*(iny)+MWZ(m)*((VP_PAR)inz)+MWW(m); \
++ outx = (MXX(m)*((VP_PAR)inx)+MXY(m)*((VP_PAR)iny)+MXZ(m)*((VP_PAR)inz)+MXW(m))/vpTmpWarpPnt___; \
++ outy = (MYX(m)*((VP_PAR)inx)+MYY(m)*((VP_PAR)iny)+MYZ(m)*((VP_PAR)inz)+MYW(m))/vpTmpWarpPnt___; \
++ outz = MZX(m)*((VP_PAR)inx)+MZY(m)*((VP_PAR)iny)+MZZ(m)*((VP_PAR)inz)+MZW(m); \
++ if ((m).type==VP_MOTION_PROJ_3D) outz/=vpTmpWarpPnt___; } while (0)
+
+ /* Projections of each component */
+ #define VP_PROJW_3D(m,x,y,z,f) ( MWX(m)*(x)+MWY(m)*(y)+MWZ(m)*(z)+MWW(m) )
+@@ -224,15 +224,15 @@ typedef struct {
+
+ /* Scale Down a matrix by Sfactor */
+ #define VP_SCALEDOWN(m,Sfactor) do { \
+- MXW(m) /= (VP_PAR)(Sfactor); MWX(m) *= (VP_PAR)(Sfactor); \
+- MYW(m) /= (VP_PAR)(Sfactor); MWY(m) *= (VP_PAR)(Sfactor); \
+- MZW(m) /= (VP_PAR)(Sfactor); MWZ(m) *= (VP_PAR)(Sfactor); } while (0)
++ MXW(m) /= (VP_PAR)Sfactor; MWX(m) *= (VP_PAR)Sfactor; \
++ MYW(m) /= (VP_PAR)Sfactor; MWY(m) *= (VP_PAR)Sfactor; \
++ MZW(m) /= (VP_PAR)Sfactor; MWZ(m) *= (VP_PAR)Sfactor; } while (0)
+
+ /* Scale Up a matrix by Sfactor */
+ #define VP_SCALEUP(m,Sfactor) do { \
+- MXW(m) *= (VP_PAR)(Sfactor); MWX(m) /= (VP_PAR)(Sfactor); \
+- MYW(m) *= (VP_PAR)(Sfactor); MWY(m) /= (VP_PAR)(Sfactor); \
+- MZW(m) *= (VP_PAR)(Sfactor); MWZ(m) /= (VP_PAR)(Sfactor); } while (0)
++ MXW(m) *= (VP_PAR)Sfactor; MWX(m) /= (VP_PAR)Sfactor; \
++ MYW(m) *= (VP_PAR)Sfactor; MWY(m) /= (VP_PAR)Sfactor; \
++ MZW(m) *= (VP_PAR)Sfactor; MWZ(m) /= (VP_PAR)Sfactor; } while (0)
+
+ /* Normalize the transformation matrix so that MWW is 1 */
+ #define VP_NORMALIZE(m) if (MWW(m)!=(VP_PAR)0.0) do { \
+@@ -253,15 +253,15 @@ typedef struct {
+
+ /* w' projection given a point x,y,0,f */
+ #define VP_PROJZ(m,x,y,f) ( \
+- MWX(m)*((VP_PAR)(x))+MWY(m)*((VP_PAR)(y))+MWW(m)*((VP_PAR)(f)))
++ MWX(m)*((VP_PAR)x)+MWY(m)*((VP_PAR)y)+MWW(m)*((VP_PAR)f))
+
+ /* X Projection given a point x,y,0,f and w' */
+ #define VP_PROJX(m,x,y,w,f) (\
+- (MXX(m)*((VP_PAR)(x))+MXY(m)*((VP_PAR)(y))+MXW(m)*((VP_PAR)(f)))/((VP_PAR)(w)))
++ (MXX(m)*((VP_PAR)x)+MXY(m)*((VP_PAR)y)+MXW(m)*((VP_PAR)f))/((VP_PAR)w))
+
+ /* Y Projection given a point x,y,0,f and the w' */
+ #define VP_PROJY(m,x,y,w,f) (\
+- (MYX(m)*((VP_PAR)(x))+MYY(m)*((VP_PAR)(y))+MYW(m)*((VP_PAR)(f)))/((VP_PAR)(w)))
++ (MYX(m)*((VP_PAR)x)+MYY(m)*((VP_PAR)y)+MYW(m)*((VP_PAR)f))/((VP_PAR)w))
+
+ /* Set the reference id for a motion */
+ #define VP_SET_REFID(m,id) do { (m).refid=id; } while (0)