[CinCV-commits] CinelerraCV.git (#1209) - master (branch) updated: v2.1.5-166-g0dc2be9

git version control git at cinelerra-cv.org
Sat Jun 21 13:39:10 CEST 2014


The branch, master has been updated
       via  0dc2be98a530abf7e012123902e75a25a26aee85 (commit)
       via  beb06a08be3971022fa2d667f1cda83f8ef1a7a0 (commit)
       via  c34b94e974b6de2deab313660035a5a0a4f2b755 (commit)
       via  c6ca2de5b6f9aa73a9fdd64e7ed952fb2c409848 (commit)
       via  318297b90e29a6d72766ff5be89a6ebb9501160f (commit)
       via  0f5b8037d324179bde3023a90196f19441441c97 (commit)
       via  26d448a8799d62a82824d5df0ffc0e0b9c615c56 (commit)
       via  5218f0d39afbc4c24d995f367e11e42d07db0321 (commit)
       via  c51155e997dc37002551a5aea67d6780065b86fa (commit)
       via  6c9473f6867ead7306295b322aa9b3e0a8377d72 (commit)
      from  3c84ee65a17e2fcee63f15c4b5c17f3875bfa9ed (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 0dc2be98a530abf7e012123902e75a25a26aee85
Author: Petter Reinholdtsen <pere at hungry.com>
Date:   Wed Jun 11 22:38:23 2014 +0200

    Fix some compiler warnings.
    
    Fix format string, drop useless statements and add missing return statement.

commit beb06a08be3971022fa2d667f1cda83f8ef1a7a0
Author: Petter Reinholdtsen <pere at hungry.com>
Date:   Wed May 14 12:08:43 2014 +0200

    Disable the SUFT algorithm in the findobject plugin.
    
    The needed support is not implemented in the Debian Jessie
    OpenCV packages.  Include configure test to check if opencv
    have SURF support

commit c34b94e974b6de2deab313660035a5a0a4f2b755
Author: Petter Reinholdtsen <pere at hungry.com>
Date:   Wed May 14 11:16:35 2014 +0200

    Backport the findobject plugin from HV 4.5, include autoconf rules
    for checking for the opencv library.
    
    Also include the build dependencies to make debs in Debian Jessie.

commit c6ca2de5b6f9aa73a9fdd64e7ed952fb2c409848
Author: Petter Reinholdtsen <pere at hungry.com>
Date:   Wed May 14 11:12:59 2014 +0200

    Add YUV and HSV classes from HV 4.5.
    
    The classes are used by the findobject plugin.

commit 318297b90e29a6d72766ff5be89a6ebb9501160f
Author: Petter Reinholdtsen <pere at hungry.com>
Date:   Wed May 14 11:10:20 2014 +0200

    Add new class AffineMatrix from HV 4.5.
    
    The new class is used by plugins in HV 4.5 and needed by the
    findobject plugin.

commit 0f5b8037d324179bde3023a90196f19441441c97
Author: Petter Reinholdtsen <pere at hungry.com>
Date:   Wed May 14 11:09:03 2014 +0200

    Add new constructor VFrame(int w, int h, int color_model) from HV 4.5.
    
    Adjust bluebanana plugin for new VFrame() constructor.
    Make sure it pick the same ctor as earlier, by making sure the empty
    data argument is interpreted as unsigned char *, not int.
    
    The new constructor is used by plugins and other code, and needed
    by the findobjects plugin.

commit 26d448a8799d62a82824d5df0ffc0e0b9c615c56
Author: Petter Reinholdtsen <pere at hungry.com>
Date:   Wed May 14 11:07:18 2014 +0200

    Add new BC_CModels class from HV 4.5.
    
    The BC_CModels class is used by HV 4.5 plugins and needed
    by the findobject plugin.

commit 5218f0d39afbc4c24d995f367e11e42d07db0321
Author: Petter Reinholdtsen <pere at hungry.com>
Date:   Wed May 14 11:04:14 2014 +0200

    Add new Theme member values window_border and widget_border from HV 4.5.
    
    The values are used by plugins in HV 4.5, and needed to backport
    the findobject plugin.

commit c51155e997dc37002551a5aea67d6780065b86fa
Author: Petter Reinholdtsen <pere at hungry.com>
Date:   Wed May 14 11:03:00 2014 +0200

    Add KeyFrame::get_data() member function from HV 4.5.
    
    The method is used by the findobject and other plugins in
    HV 4.5.

commit 6c9473f6867ead7306295b322aa9b3e0a8377d72
Author: Petter Reinholdtsen <pere at hungry.com>
Date:   Wed May 14 10:48:19 2014 +0200

    Copy findobject plugin from HV 4.5.

-----------------------------------------------------------------------

Summary of changes:
 cinelerra/Makefile.am                    |    4 +
 cinelerra/affine.C                       | 1506 ++++++++++++++++++
 cinelerra/affine.h                       |  158 ++
 {plugins/motion => cinelerra}/affine.inc |    0 
 cinelerra/cicolors.C                     |  269 ++++
 cinelerra/cicolors.h                     |  227 +++
 cinelerra/cicolors.inc                   |   29 +
 cinelerra/keyframe.C                     |    5 +
 cinelerra/keyframe.h                     |    1 +
 cinelerra/theme.C                        |    2 +
 cinelerra/theme.h                        |    2 +
 configure.ac                             |   38 +
 debian/control                           |    1 +
 guicast/Makefile.am                      |    8 +
 guicast/bccmodel_default.C               | 1518 ++++++++++++++++++
 guicast/bccmodel_float.C                 |  746 +++++++++
 guicast/bccmodel_permutation.h           | 2500 ++++++++++++++++++++++++++++++
 guicast/bccmodel_yuv420p.C               | 1395 +++++++++++++++++
 guicast/bccmodel_yuv422.C                |  551 +++++++
 guicast/bccmodels.C                      |  544 +++++++
 guicast/bccmodels.h                      |  216 +++
 guicast/bccmodels.inc                    |   13 +
 guicast/bcwindowbase.h                   |    1 +
 guicast/vframe.C                         |   17 +
 guicast/vframe.h                         |    5 +
 plugins/Makefile.am                      |    1 +
 plugins/bluebanana/bluebananaslider.C    |    6 +-
 plugins/findobject/Makefile.am           |   11 +
 plugins/findobject/findobject.C          | 1423 +++++++++++++++++
 plugins/findobject/findobject.h          |  280 ++++
 plugins/findobject/findobject.inc        |   30 +
 plugins/findobject/findobjectwindow.C    |  613 ++++++++
 plugins/findobject/findobjectwindow.h    |  237 +++
 plugins/findobject/findobjectwindow.inc  |   28 +
 plugins/findobject/surfscan.C            |  268 ++++
 plugins/findobject/surfscan.h            |   46 +
 36 files changed, 12696 insertions(+), 3 deletions(-)
 create mode 100644 cinelerra/affine.C
 create mode 100644 cinelerra/affine.h
 copy {plugins/motion => cinelerra}/affine.inc (100%)
 create mode 100644 cinelerra/cicolors.C
 create mode 100644 cinelerra/cicolors.h
 create mode 100644 cinelerra/cicolors.inc
 create mode 100644 guicast/bccmodel_default.C
 create mode 100644 guicast/bccmodel_float.C
 create mode 100644 guicast/bccmodel_permutation.h
 create mode 100644 guicast/bccmodel_yuv420p.C
 create mode 100644 guicast/bccmodel_yuv422.C
 create mode 100755 guicast/bccmodels.C
 create mode 100644 guicast/bccmodels.h
 create mode 100644 guicast/bccmodels.inc
 create mode 100644 plugins/findobject/Makefile.am
 create mode 100644 plugins/findobject/findobject.C
 create mode 100644 plugins/findobject/findobject.h
 create mode 100644 plugins/findobject/findobject.inc
 create mode 100644 plugins/findobject/findobjectwindow.C
 create mode 100644 plugins/findobject/findobjectwindow.h
 create mode 100644 plugins/findobject/findobjectwindow.inc
 create mode 100644 plugins/findobject/surfscan.C
 create mode 100644 plugins/findobject/surfscan.h

The diff of changes is:
diff --git a/cinelerra/Makefile.am b/cinelerra/Makefile.am
index eae781e..4cbc9a9 100644
--- a/cinelerra/Makefile.am
+++ b/cinelerra/Makefile.am
@@ -59,6 +59,7 @@ cinelerra_SOURCES = aattachmentpoint.C \
 		    adeviceprefs.C \
 		    aedit.C \
 		    aedits.C \
+		    affine.C \
 		    amodule.C \
 		    apatchgui.C \
 		    apluginarray.C \
@@ -97,6 +98,7 @@ cinelerra_SOURCES = aattachmentpoint.C \
 		    cachebase.C \
 		    canvas.C \
 		    canvastools.C \
+		    cicolors.C \
 		    channel.C \
 		    channeldb.C \
 		    channeledit.C \
@@ -359,6 +361,7 @@ noinst_HEADERS = aattachmentpoint.h \
 		 adeviceprefs.h \
 		 aedit.h \
 		 aedits.h \
+		 affine.h \
 		 amodule.h \
 		 apatchgui.h \
 		 apluginarray.h \
@@ -403,6 +406,7 @@ noinst_HEADERS = aattachmentpoint.h \
 		 cameraauto.h \
 		 canvas.h \
 		 canvastools.h \
+		 cicolors.h \
 		 channeledit.h \
 		 channel.h \
 		 channeldb.h \
diff --git a/cinelerra/affine.C b/cinelerra/affine.C
new file mode 100644
index 0000000..cf5a40c
--- /dev/null
+++ b/cinelerra/affine.C
@@ -0,0 +1,1506 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+#ifdef HAVE_GL
+#define GL_GLEXT_PROTOTYPES
+#include <GL/gl.h>
+#endif
+
+#include "affine.h"
+#include "clip.h"
+#include "vframe.h"
+
+
+#include <math.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+AffineMatrix::AffineMatrix()
+{
+	bzero(values, sizeof(values));
+}
+
+void AffineMatrix::identity()
+{
+	bzero(values, sizeof(values));
+	values[0][0] = 1;
+	values[1][1] = 1;
+	values[2][2] = 1;
+}
+
+void AffineMatrix::translate(double x, double y)
+{
+	double g = values[2][0];
+	double h = values[2][1];
+	double i = values[2][2];
+	values[0][0] += x * g;
+	values[0][1] += x * h;
+	values[0][2] += x * i;
+	values[1][0] += y * g;
+	values[1][1] += y * h;
+	values[1][2] += y * i;
+}
+
+void AffineMatrix::scale(double x, double y)
+{
+	values[0][0] *= x;
+	values[0][1] *= x;
+	values[0][2] *= x;
+
+	values[1][0] *= y;
+	values[1][1] *= y;
+	values[1][2] *= y;
+}
+
+void AffineMatrix::multiply(AffineMatrix *dst)
+{
+	int i, j;
+	AffineMatrix tmp;
+	double t1, t2, t3;
+
+  	for (i = 0; i < 3; i++)
+    {
+    	t1 = values[i][0];
+    	t2 = values[i][1];
+    	t3 = values[i][2];
+    	for (j = 0; j < 3; j++)
+		{
+			tmp.values[i][j]  = t1 * dst->values[0][j];
+			tmp.values[i][j] += t2 * dst->values[1][j];
+			tmp.values[i][j] += t3 * dst->values[2][j];
+		}
+    }
+	dst->copy_from(&tmp);
+}
+
+double AffineMatrix::determinant()
+{
+	double determinant;
+
+	determinant  = 
+        values[0][0] * (values[1][1] * values[2][2] - values[1][2] * values[2][1]);
+	determinant -= 
+        values[1][0] * (values[0][1] * values[2][2] - values[0][2] * values[2][1]);
+	determinant += 
+        values[2][0] * (values[0][1] * values[1][2] - values[0][2] * values[1][1]);
+
+	return determinant;
+}
+
+void AffineMatrix::invert(AffineMatrix *dst)
+{
+	double det_1;
+
+	det_1 = determinant();
+
+	if(det_1 == 0.0)
+      	return;
+
+	det_1 = 1.0 / det_1;
+
+	dst->values[0][0] =   
+      (values[1][1] * values[2][2] - values[1][2] * values[2][1]) * det_1;
+
+	dst->values[1][0] = 
+      - (values[1][0] * values[2][2] - values[1][2] * values[2][0]) * det_1;
+
+	dst->values[2][0] =   
+      (values[1][0] * values[2][1] - values[1][1] * values[2][0]) * det_1;
+
+	dst->values[0][1] = 
+      - (values[0][1] * values[2][2] - values[0][2] * values[2][1] ) * det_1;
+
+	dst->values[1][1] = 
+      (values[0][0] * values[2][2] - values[0][2] * values[2][0]) * det_1;
+
+	dst->values[2][1] = 
+      - (values[0][0] * values[2][1] - values[0][1] * values[2][0]) * det_1;
+
+	dst->values[0][2] =
+      (values[0][1] * values[1][2] - values[0][2] * values[1][1]) * det_1;
+
+	dst->values[1][2] = 
+      - (values[0][0] * values[1][2] - values[0][2] * values[1][0]) * det_1;
+
+	dst->values[2][2] = 
+      (values[0][0] * values[1][1] - values[0][1] * values[1][0]) * det_1;
+}
+
+void AffineMatrix::copy_from(AffineMatrix *src)
+{
+	memcpy(&values[0][0], &src->values[0][0], sizeof(values));
+}
+
+void AffineMatrix::transform_point(float x, 
+	float y, 
+	float *newx, 
+	float *newy)
+{
+	double w;
+
+	w = values[2][0] * x + values[2][1] * y + values[2][2];
+
+	if (w == 0.0)
+    	w = 1.0;
+	else
+    	w = 1.0 / w;
+
+	*newx = (values[0][0] * x + values[0][1] * y + values[0][2]) * w;
+	*newy = (values[1][0] * x + values[1][1] * y + values[1][2]) * w;
+}
+
+void AffineMatrix::dump()
+{
+	printf("AffineMatrix::dump\n");
+	printf("%f %f %f\n", values[0][0], values[0][1], values[0][2]);
+	printf("%f %f %f\n", values[1][0], values[1][1], values[1][2]);
+	printf("%f %f %f\n", values[2][0], values[2][1], values[2][2]);
+}
+
+
+
+
+
+AffinePackage::AffinePackage()
+ : LoadPackage()
+{
+}
+
+
+
+
+AffineUnit::AffineUnit(AffineEngine *server)
+ : LoadClient(server)
+{
+	this->server = server;
+}
+
+
+
+
+
+
+
+
+
+void AffineUnit::calculate_matrix(
+	double in_x1,
+	double in_y1,
+	double in_x2,
+	double in_y2,
+	double out_x1,
+	double out_y1,
+	double out_x2,
+	double out_y2,
+	double out_x3,
+	double out_y3,
+	double out_x4,
+	double out_y4,
+	AffineMatrix *result)
+{
+	AffineMatrix matrix;
+	double scalex;
+	double scaley;
+
+	scalex = scaley = 1.0;
+
+	if((in_x2 - in_x1) > 0)
+      	scalex = 1.0 / (double)(in_x2 - in_x1);
+
+	if((in_y2 - in_y1) > 0)
+      	scaley = 1.0 / (double)(in_y2 - in_y1);
+
+/* Determine the perspective transform that maps from
+ * the unit cube to the transformed coordinates
+ */
+    double dx1, dx2, dx3, dy1, dy2, dy3;
+    double det1, det2;
+
+    dx1 = out_x2 - out_x4;
+    dx2 = out_x3 - out_x4;
+    dx3 = out_x1 - out_x2 + out_x4 - out_x3;
+
+    dy1 = out_y2 - out_y4;
+    dy2 = out_y3 - out_y4;
+    dy3 = out_y1 - out_y2 + out_y4 - out_y3;
+// printf("AffineUnit::calculate_matrix %f %f %f %f %f %f\n",
+// dx1,
+// dx2,
+// dx3,
+// dy1,
+// dy2,
+// dy3
+// );
+
+/*  Is the mapping affine?  */
+    if((dx3 == 0.0) && (dy3 == 0.0))
+    {
+        matrix.values[0][0] = out_x2 - out_x1;
+        matrix.values[0][1] = out_x4 - out_x2;
+        matrix.values[0][2] = out_x1;
+        matrix.values[1][0] = out_y2 - out_y1;
+        matrix.values[1][1] = out_y4 - out_y2;
+        matrix.values[1][2] = out_y1;
+        matrix.values[2][0] = 0.0;
+        matrix.values[2][1] = 0.0;
+    }
+    else
+    {
+        det1 = dx3 * dy2 - dy3 * dx2;
+        det2 = dx1 * dy2 - dy1 * dx2;
+        matrix.values[2][0] = det1 / det2;
+        det1 = dx1 * dy3 - dy1 * dx3;
+        det2 = dx1 * dy2 - dy1 * dx2;
+        matrix.values[2][1] = det1 / det2;
+
+        matrix.values[0][0] = out_x2 - out_x1 + matrix.values[2][0] * out_x2;
+        matrix.values[0][1] = out_x3 - out_x1 + matrix.values[2][1] * out_x3;
+        matrix.values[0][2] = out_x1;
+
+        matrix.values[1][0] = out_y2 - out_y1 + matrix.values[2][0] * out_y2;
+        matrix.values[1][1] = out_y3 - out_y1 + matrix.values[2][1] * out_y3;
+        matrix.values[1][2] = out_y1;
+    }
+
+    matrix.values[2][2] = 1.0;
+
+// printf("AffineUnit::calculate_matrix 1 %f %f\n", dx3, dy3);
+// matrix.dump();
+
+	result->identity();
+	result->translate(-in_x1, -in_y1);
+	result->scale(scalex, scaley);
+	matrix.multiply(result);
+// double test[3][3] = { { 0.0896, 0.0, 0.0 },
+// 				  { 0.0, 0.0896, 0.0 },
+// 				  { -0.00126, 0.0, 1.0 } };
+// memcpy(&result->values[0][0], test, sizeof(test));
+// printf("AffineUnit::calculate_matrix 4 %p\n", result);
+// result->dump();
+
+
+}
+
+float AffineUnit::transform_cubic(float dx,
+                               float jm1,
+                               float j,
+                               float jp1,
+                               float jp2)
+{
+/* Catmull-Rom - not bad */
+  	float result = ((( ( - jm1 + 3.0 * j - 3.0 * jp1 + jp2 ) * dx +
+            	       ( 2.0 * jm1 - 5.0 * j + 4.0 * jp1 - jp2 ) ) * dx +
+            	       ( - jm1 + jp1 ) ) * dx + (j + j) ) / 2.0;
+// printf("%f %f %f %f %f\n", 
+// result,
+// jm1,
+// j,
+// jp1,
+// jp2);
+
+
+  	return result;
+}
+
+
+void AffineUnit::process_package(LoadPackage *package)
+{
+	AffinePackage *pkg = (AffinePackage*)package;
+	int min_in_x = server->in_x;
+	int min_in_y = server->in_y;
+	int max_in_x = server->in_x + server->in_w - 1;
+	int max_in_y = server->in_y + server->in_h - 1;
+
+
+// printf("AffineUnit::process_package %d %d %d %d %d\n", 
+// __LINE__, 
+// min_in_x,
+// min_in_y,
+// max_in_x,
+// max_in_y);
+	int min_out_x = server->out_x;
+	int min_out_y = server->out_y;
+	int max_out_x = server->out_x + server->out_w;
+	int max_out_y = server->out_y + server->out_h;
+
+// Amount to shift the input coordinates relative to the output coordinates
+// To get the pivots to line up
+	int pivot_offset_x = server->in_pivot_x - server->out_pivot_x;
+	int pivot_offset_y = server->in_pivot_y - server->out_pivot_y;
+
+// Calculate real coords
+	float out_x1, out_y1, out_x2, out_y2, out_x3, out_y3, out_x4, out_y4;
+	if(server->mode == AffineEngine::STRETCH ||
+		server->mode == AffineEngine::PERSPECTIVE ||
+		server->mode == AffineEngine::ROTATE)
+	{
+		out_x1 = (float)server->in_x + (float)server->x1 * server->in_w / 100;
+		out_y1 = (float)server->in_y + (float)server->y1 * server->in_h / 100;
+		out_x2 = (float)server->in_x + (float)server->x2 * server->in_w / 100;
+		out_y2 = (float)server->in_y + (float)server->y2 * server->in_h / 100;
+		out_x3 = (float)server->in_x + (float)server->x3 * server->in_w / 100;
+		out_y3 = (float)server->in_y + (float)server->y3 * server->in_h / 100;
+		out_x4 = (float)server->in_x + (float)server->x4 * server->in_w / 100;
+		out_y4 = (float)server->in_y + (float)server->y4 * server->in_h / 100;
+	}
+	else
+	{
+		out_x1 = (float)server->in_x + (float)server->x1 * server->in_w / 100;
+		out_y1 = server->in_y;
+		out_x2 = out_x1 + server->in_w;
+		out_y2 = server->in_y;
+		out_x4 = (float)server->in_x + (float)server->x4 * server->in_w / 100;
+		out_y4 = server->in_y + server->in_h;
+		out_x3 = out_x4 + server->in_w;
+		out_y3 = server->in_y + server->in_h;
+	}
+
+
+
+// Rotation with OpenGL uses a simple quad.
+	if(server->mode == AffineEngine::ROTATE &&
+		server->use_opengl)
+	{
+#ifdef HAVE_GL
+		server->output->to_texture();
+		server->output->enable_opengl();
+		server->output->init_screen();
+		server->output->bind_texture(0);
+		server->output->clear_pbuffer();
+
+		int texture_w = server->output->get_texture_w();
+		int texture_h = server->output->get_texture_h();
+		float output_h = server->output->get_h();
+		float in_x1 = (float)server->in_x / texture_w;
+		float in_x2 = (float)(server->in_x + server->in_w) / texture_w;
+		float in_y1 = (float)server->in_y / texture_h;
+		float in_y2 = (float)(server->in_y + server->in_h) / texture_h;
+
+// printf("%f %f %f %f\n%f,%f %f,%f %f,%f %f,%f\n", in_x1, in_y1, in_x2, in_y2,
+// out_x1, out_y1, out_x2, out_y2, out_x3, out_y3, out_x4, out_y4);
+
+		glBegin(GL_QUADS);
+		glNormal3f(0, 0, 1.0);
+
+		glTexCoord2f(in_x1, in_y1);
+		glVertex3f(out_x1, -output_h+out_y1, 0);
+
+		glTexCoord2f(in_x2, in_y1);
+		glVertex3f(out_x2, -output_h+out_y2, 0);
+
+		glTexCoord2f(in_x2, in_y2);
+		glVertex3f(out_x3, -output_h+out_y3, 0);
+
+		glTexCoord2f(in_x1, in_y2);
+		glVertex3f(out_x4, -output_h+out_y4, 0);
+
+
+		glEnd();
+
+		server->output->set_opengl_state(VFrame::SCREEN);
+#endif
+	}
+	else
+	if(server->mode == AffineEngine::PERSPECTIVE ||
+		server->mode == AffineEngine::SHEER ||
+		server->mode == AffineEngine::ROTATE)
+	{
+		AffineMatrix matrix;
+		float temp;
+// swap points 3 & 4
+		temp = out_x4;
+		out_x4 = out_x3;
+		out_x3 = temp;
+		temp = out_y4;
+		out_y4 = out_y3;
+		out_y3 = temp;
+
+
+
+
+
+
+		calculate_matrix(
+			server->in_x,
+			server->in_y,
+			server->in_x + server->in_w,
+			server->in_y + server->in_h,
+			out_x1,
+			out_y1,
+			out_x2,
+			out_y2,
+			out_x3,
+			out_y3,
+			out_x4,
+			out_y4,
+			&matrix);
+
+// printf("AffineUnit::process_package 10 %f %f %f %f %f %f %f %f\n", 
+// out_x1,
+// out_y1,
+// out_x2,
+// out_y2,
+// out_x3,
+// out_y3,
+// out_x4,
+// out_y4);
+		int interpolate = 1;
+		int reverse = !server->forward;
+		float tx, ty, tw;
+		float xinc, yinc, winc;
+		AffineMatrix m, im;
+		float ttx = 0, tty = 0;
+		int itx = 0, ity = 0;
+		int tx1 = 0, ty1 = 0, tx2 = 0, ty2 = 0;
+
+		if(reverse)
+		{
+			m.copy_from(&matrix);
+			m.invert(&im);
+			matrix.copy_from(&im);
+		}
+		else
+		{
+			matrix.invert(&m);
+		}
+
+
+
+
+
+
+		float dx1 = 0, dy1 = 0;
+		float dx2 = 0, dy2 = 0;
+		float dx3 = 0, dy3 = 0;
+		float dx4 = 0, dy4 = 0;
+		matrix.transform_point(server->in_x, server->in_y, &dx1, &dy1);
+		matrix.transform_point(server->in_x + server->in_w, server->in_y, &dx2, &dy2);
+		matrix.transform_point(server->in_x, server->in_y + server->in_h, &dx3, &dy3);
+		matrix.transform_point(server->in_x + server->in_w, server->in_y + server->in_h, &dx4, &dy4);
+
+//printf("AffineUnit::process_package 1 y1=%d y2=%d\n", pkg->y1, pkg->y2);
+//printf("AffineUnit::process_package 1 %f %f %f %f\n", dy1, dy2, dy3, dy4);
+// printf("AffineUnit::process_package %d use_opengl=%d\n",
+// __LINE__, server->use_opengl);
+
+
+
+
+
+		if(server->use_opengl)
+		{
+#ifdef HAVE_GL
+			static char *affine_frag =
+				(char*)"uniform sampler2D tex;\n"
+				"uniform mat3 affine_matrix;\n"
+				"uniform vec2 texture_extents;\n"
+				"uniform vec2 image_extents;\n"
+				"uniform vec4 border_color;\n"
+				"void main()\n"
+				"{\n"
+				"	vec2 outcoord = gl_TexCoord[0].st;\n"
+				"	outcoord *= texture_extents;\n"
+				"	mat3 coord_matrix = mat3(\n"
+				"		outcoord.x, outcoord.y, 1.0, \n"
+				"		outcoord.x, outcoord.y, 1.0, \n"
+				"		outcoord.x, outcoord.y, 1.0);\n"
+				"	mat3 incoord_matrix = affine_matrix * coord_matrix;\n"
+				"	vec2 incoord = vec2(incoord_matrix[0][0], incoord_matrix[0][1]);\n"
+				"	incoord /= incoord_matrix[0][2];\n"
+			 	"	incoord /= texture_extents;\n"
+				"	if(incoord.x > image_extents.x || incoord.y > image_extents.y)\n"
+				"		gl_FragColor = border_color;\n"
+				"	else\n"
+			 	"		gl_FragColor = texture2D(tex, incoord);\n"
+				"}\n";
+
+			float affine_matrix[9] = {
+				m.values[0][0], m.values[1][0], m.values[2][0],
+				m.values[0][1], m.values[1][1], m.values[2][1],
+				m.values[0][2], m.values[1][2], m.values[2][2] 
+			};
+
+
+			server->output->to_texture();
+			server->output->enable_opengl();
+			unsigned int frag_shader = VFrame::make_shader(0,
+					affine_frag,
+					0);
+			if(frag_shader > 0)
+			{
+				glUseProgram(frag_shader);
+				glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
+				glUniformMatrix3fv(glGetUniformLocation(frag_shader, "affine_matrix"), 
+					1,
+					0,
+					affine_matrix);
+				glUniform2f(glGetUniformLocation(frag_shader, "texture_extents"), 
+					(GLfloat)server->output->get_texture_w(),
+					(GLfloat)server->output->get_texture_h());
+				glUniform2f(glGetUniformLocation(frag_shader, "image_extents"), 
+					(GLfloat)server->output->get_w() / server->output->get_texture_w(),
+					(GLfloat)server->output->get_h() / server->output->get_texture_h());
+				float border_color[] = { 0, 0, 0, 0 };
+				if(BC_CModels::is_yuv(server->output->get_color_model()))
+				{
+					border_color[1] = 0.5;
+					border_color[2] = 0.5;
+				}
+				if(!BC_CModels::has_alpha(server->output->get_color_model()))
+				{
+					border_color[3] = 1.0;
+				}
+
+				glUniform4fv(glGetUniformLocation(frag_shader, "border_color"), 
+					1,
+					(GLfloat*)border_color);
+				server->output->init_screen();
+				server->output->bind_texture(0);
+				glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
+				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
+				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+				server->output->draw_texture();
+				glUseProgram(0);
+				server->output->set_opengl_state(VFrame::SCREEN);
+			}
+			return;
+#endif // HAVE_GL
+		}
+
+
+
+
+
+
+#define ROUND(x) ((int)((x > 0) ? (x) + 0.5 : (x) - 0.5))
+#define MIN4(a,b,c,d) MIN(MIN(MIN(a,b),c),d)
+#define MAX4(a,b,c,d) MAX(MAX(MAX(a,b),c),d)
+
+    	tx1 = ROUND(MIN4(dx1 - pivot_offset_x, dx2 - pivot_offset_x, dx3 - pivot_offset_x, dx4 - pivot_offset_x));
+    	ty1 = ROUND(MIN4(dy1 - pivot_offset_y, dy2 - pivot_offset_y, dy3 - pivot_offset_y, dy4 - pivot_offset_y));
+
+    	tx2 = ROUND(MAX4(dx1 - pivot_offset_x, dx2 - pivot_offset_x, dx3 - pivot_offset_x, dx4 - pivot_offset_x));
+    	ty2 = ROUND(MAX4(dy1 - pivot_offset_y, dy2 - pivot_offset_y, dy3 - pivot_offset_y, dy4 - pivot_offset_y));
+
+		CLAMP(ty1, pkg->y1, pkg->y2);
+		CLAMP(ty2, pkg->y1, pkg->y2);
+		CLAMP(tx1, server->out_x, server->out_x + server->out_w);
+		CLAMP(tx2, server->out_x, server->out_x + server->out_w);
+
+
+		xinc = m.values[0][0];
+		yinc = m.values[1][0];
+		winc = m.values[2][0];
+
+//printf("AffineUnit::process_package 2 tx1=%d ty1=%d tx2=%d ty2=%d %f %f\n", tx1, ty1, tx2, ty2, out_x4, out_y4);
+//printf("AffineUnit::process_package %d %d %d %d %d\n", 
+//__LINE__,
+//min_in_x,
+//max_in_x,
+//min_in_y,
+//max_in_y);
+
+#define CUBIC_ROW(in_row, chroma_offset) \
+	transform_cubic(dx, \
+		in_row[col1_offset] - chroma_offset, \
+		in_row[col2_offset] - chroma_offset, \
+		in_row[col3_offset] - chroma_offset, \
+		in_row[col4_offset] - chroma_offset)
+
+
+#define TRANSFORM(components, type, temp_type, chroma_offset, max) \
+{ \
+	type **in_rows = (type**)server->input->get_rows(); \
+	float round_factor = 0.0; \
+	if(sizeof(type) < 4) round_factor = 0.5; \
+	for(int y = ty1; y < ty2; y++) \
+	{ \
+		type *out_row = (type*)server->output->get_rows()[y]; \
+ \
+		if(!interpolate) \
+		{ \
+        	tx = xinc * (tx1 + 0.5) + \
+				m.values[0][1] * (y + pivot_offset_y + 0.5) + \
+				m.values[0][2] + \
+				pivot_offset_x * xinc; \
+        	ty = yinc * (tx1 + 0.5) + \
+				m.values[1][1] * (y + pivot_offset_y + 0.5) + \
+				m.values[1][2] + \
+				pivot_offset_x * yinc; \
+        	tw = winc * (tx1 + 0.5) + \
+				m.values[2][1] * (y + pivot_offset_y + 0.5) + \
+				m.values[2][2] + \
+				pivot_offset_x * winc; \
+		} \
+      	else \
+        { \
+        	tx = xinc * tx1 + \
+				m.values[0][1] * (y + pivot_offset_y) + \
+				m.values[0][2] + \
+				pivot_offset_x * xinc; \
+        	ty = yinc * tx1 + \
+				m.values[1][1] * (y + pivot_offset_y) + \
+				m.values[1][2] + \
+				pivot_offset_x * yinc; \
+        	tw = winc * tx1 + \
+				m.values[2][1] * (y + pivot_offset_y) + \
+				m.values[2][2] + \
+				pivot_offset_x * winc; \
+        } \
+ \
+ \
+		out_row += tx1 * components; \
+		for(int x = tx1; x < tx2; x++) \
+		{ \
+/* Normalize homogeneous coords */ \
+			if(tw == 0.0) \
+			{ \
+				ttx = 0.0; \
+				tty = 0.0; \
+			} \
+			else \
+			if(tw != 1.0) \
+			{ \
+				ttx = tx / tw; \
+				tty = ty / tw; \
+			} \
+			else \
+			{ \
+				ttx = tx; \
+				tty = ty; \
+			} \
+			itx = (int)ttx; \
+			ity = (int)tty; \
+ \
+			int row1 = ity - 1; \
+			int row2 = ity; \
+			int row3 = ity + 1; \
+			int row4 = ity + 2; \
+			CLAMP(row1, min_in_y, max_in_y); \
+			CLAMP(row2, min_in_y, max_in_y); \
+			CLAMP(row3, min_in_y, max_in_y); \
+			CLAMP(row4, min_in_y, max_in_y); \
+ \
+/* Set destination pixels if in clipping region */ \
+			if(!interpolate && \
+				x >= min_out_x && \
+				x < max_out_x) \
+			{ \
+				if(itx >= min_in_x && \
+					itx <= max_in_x && \
+					ity >= min_in_y && \
+					ity <= max_in_y) \
+				{ \
+					type *src = in_rows[ity] + itx * components; \
+					*out_row++ = *src++; \
+					*out_row++ = *src++; \
+					*out_row++ = *src++; \
+					if(components == 4) *out_row++ = *src; \
+				} \
+				else \
+/* Fill with chroma */ \
+				{ \
+					*out_row++ = 0; \
+					*out_row++ = chroma_offset; \
+					*out_row++ = chroma_offset; \
+					if(components == 4) *out_row++ = 0; \
+				} \
+			} \
+			else \
+/* Bicubic algorithm */ \
+			if(interpolate &&  \
+				x >= min_out_x &&  \
+				x < max_out_x) \
+			{ \
+/* clipping region */ \
+				if ((itx + 2) >= min_in_x && \
+					(itx - 1) <= max_in_x && \
+                  	(ity + 2) >= min_in_y && \
+					(ity - 1) <= max_in_y) \
+                { \
+                	float dx, dy; \
+ \
+/* the fractional error */ \
+                	dx = ttx - itx; \
+                	dy = tty - ity; \
+ \
+/* Row and column offsets in cubic block */ \
+					int col1 = itx - 1; \
+					int col2 = itx; \
+					int col3 = itx + 1; \
+					int col4 = itx + 2; \
+					CLAMP(col1, min_in_x, max_in_x); \
+					CLAMP(col2, min_in_x, max_in_x); \
+					CLAMP(col3, min_in_x, max_in_x); \
+					CLAMP(col4, min_in_x, max_in_x); \
+					int col1_offset = col1 * components; \
+					int col2_offset = col2 * components; \
+					int col3_offset = col3 * components; \
+					int col4_offset = col4 * components; \
+ \
+					type *row1_ptr = in_rows[row1]; \
+					type *row2_ptr = in_rows[row2]; \
+					type *row3_ptr = in_rows[row3]; \
+					type *row4_ptr = in_rows[row4]; \
+					temp_type r, g, b, a; \
+ \
+					r = (temp_type)(transform_cubic(dy, \
+                    	CUBIC_ROW(row1_ptr, 0x0), \
+                    	CUBIC_ROW(row2_ptr, 0x0), \
+                    	CUBIC_ROW(row3_ptr, 0x0), \
+                    	CUBIC_ROW(row4_ptr, 0x0)) + \
+						round_factor); \
+ \
+					row1_ptr++; \
+					row2_ptr++; \
+					row3_ptr++; \
+					row4_ptr++; \
+					g = (temp_type)(transform_cubic(dy, \
+                    	CUBIC_ROW(row1_ptr, chroma_offset), \
+                    	CUBIC_ROW(row2_ptr, chroma_offset), \
+                    	CUBIC_ROW(row3_ptr, chroma_offset), \
+                    	CUBIC_ROW(row4_ptr, chroma_offset)) + \
+						round_factor); \
+					g += chroma_offset; \
+ \
+					row1_ptr++; \
+					row2_ptr++; \
+					row3_ptr++; \
+					row4_ptr++; \
+					b = (temp_type)(transform_cubic(dy, \
+                    	CUBIC_ROW(row1_ptr, chroma_offset), \
+                    	CUBIC_ROW(row2_ptr, chroma_offset), \
+                    	CUBIC_ROW(row3_ptr, chroma_offset), \
+                    	CUBIC_ROW(row4_ptr, chroma_offset)) + \
+						round_factor); \
+					b += chroma_offset; \
+ \
+					if(components == 4) \
+					{ \
+						row1_ptr++; \
+						row2_ptr++; \
+						row3_ptr++; \
+						row4_ptr++; \
+						a = (temp_type)(transform_cubic(dy, \
+                    		CUBIC_ROW(row1_ptr, 0x0), \
+                    		CUBIC_ROW(row2_ptr, 0x0), \
+                    		CUBIC_ROW(row3_ptr, 0x0), \
+                    		CUBIC_ROW(row4_ptr, 0x0)) +  \
+							round_factor); \
+					} \
+ \
+ 					if(sizeof(type) < 4) \
+					{ \
+						*out_row++ = CLIP(r, 0, max); \
+						*out_row++ = CLIP(g, 0, max); \
+						*out_row++ = CLIP(b, 0, max); \
+						if(components == 4) *out_row++ = CLIP(a, 0, max); \
+					} \
+					else \
+					{ \
+						*out_row++ = r; \
+						*out_row++ = g; \
+						*out_row++ = b; \
+						if(components == 4) *out_row++ = a; \
+					} \
+                } \
+				else \
+/* Fill with chroma */ \
+				{ \
+					*out_row++ = 0; \
+					*out_row++ = chroma_offset; \
+					*out_row++ = chroma_offset; \
+					if(components == 4) *out_row++ = 0; \
+				} \
+			} \
+			else \
+			{ \
+				out_row += components; \
+			} \
+ \
+/*  increment the transformed coordinates  */ \
+			tx += xinc; \
+			ty += yinc; \
+			tw += winc; \
+		} \
+	} \
+}
+
+
+
+
+// printf("AffineUnit::process_package %d tx1=%d ty1=%d tx2=%d ty2=%d\n",
+// __LINE__, tx1, ty1, tx2, ty2);
+		switch(server->input->get_color_model())
+		{
+			case BC_RGB_FLOAT:
+				TRANSFORM(3, float, float, 0x0, 1.0)
+				break;
+			case BC_RGB888:
+				TRANSFORM(3, unsigned char, int, 0x0, 0xff)
+				break;
+			case BC_RGBA_FLOAT:
+				TRANSFORM(4, float, float, 0x0, 1.0)
+				break;
+			case BC_RGBA8888:
+				TRANSFORM(4, unsigned char, int, 0x0, 0xff)
+				break;
+			case BC_YUV888:
+// DEBUG
+//				TRANSFORM(3, unsigned char, int, 0x80, 0xff)
+{
+	
+	unsigned char **in_rows = (unsigned char**)server->input->get_rows();
+	float round_factor = 0.0;
+	if(sizeof(unsigned char) < 4) round_factor = 0.5;
+	for(int y = ty1; y < ty2; y++)
+	{
+		unsigned char *out_row = (unsigned char*)server->output->get_rows()[y];
+
+		if(!interpolate)
+		{
+        	tx = xinc * (tx1 + 0.5) +
+				m.values[0][1] * (y + pivot_offset_y + 0.5) +
+				m.values[0][2] +
+				pivot_offset_x * xinc;
+        	ty = yinc * (tx1 + 0.5) +
+				m.values[1][1] * (y + pivot_offset_y + 0.5) +
+				m.values[1][2] +
+				pivot_offset_x * yinc;
+        	tw = winc * (tx1 + 0.5) +
+				m.values[2][1] * (y + pivot_offset_y + 0.5) +
+				m.values[2][2] +
+				pivot_offset_x * winc;
+		}
+      	else
+        {
+        	tx = xinc * tx1 +
+				m.values[0][1] * (y + pivot_offset_y) +
+				m.values[0][2] +
+				pivot_offset_x * xinc;
+        	ty = yinc * tx1 +
+				m.values[1][1] * (y + pivot_offset_y) +
+				m.values[1][2] +
+				pivot_offset_x * yinc;
+        	tw = winc * tx1 +
+				m.values[2][1] * (y + pivot_offset_y) +
+				m.values[2][2] +
+				pivot_offset_x * winc;
+        }
+
+
+		out_row += tx1 * 3;
+		for(int x = tx1; x < tx2; x++)
+		{
+/* Normalize homogeneous coords */
+			if(tw == 0.0)
+			{
+				ttx = 0.0;
+				tty = 0.0;
+			}
+			else
+			if(tw != 1.0)
+			{
+				ttx = tx / tw;
+				tty = ty / tw;
+			}
+			else
+			{
+				ttx = tx;
+				tty = ty;
+			}
+			itx = (int)ttx;
+			ity = (int)tty;
+
+			int row1 = ity - 1;
+			int row2 = ity;
+			int row3 = ity + 1;
+			int row4 = ity + 2;
+			CLAMP(row1, min_in_y, max_in_y);
+			CLAMP(row2, min_in_y, max_in_y);
+			CLAMP(row3, min_in_y, max_in_y);
+			CLAMP(row4, min_in_y, max_in_y);
+
+/* Set destination pixels if in clipping region */
+			if(!interpolate &&
+				x >= min_out_x &&
+				x < max_out_x)
+			{
+				if(itx >= min_in_x &&
+					itx <= max_in_x &&
+					ity >= min_in_y &&
+					ity <= max_in_y)
+				{
+					unsigned char *src = in_rows[ity] + itx * 3;
+					*out_row++ = *src++;
+					*out_row++ = *src++;
+					*out_row++ = *src++;
+					if(3 == 4) *out_row++ = *src;
+				}
+				else
+/* Fill with chroma */
+				{
+					*out_row++ = 0;
+					*out_row++ = 0x80;
+					*out_row++ = 0x80;
+					if(3 == 4) *out_row++ = 0;
+				}
+			}
+			else
+/* Bicubic algorithm */
+			if(interpolate && 
+				x >= min_out_x && 
+				x < max_out_x)
+			{
+/* clipping region */
+				if ((itx + 2) >= min_in_x &&
+					(itx - 1) <= max_in_x &&
+                  	(ity + 2) >= min_in_y &&
+					(ity - 1) <= max_in_y)
+                {
+                	float dx, dy;
+
+/* the fractional error */
+                	dx = ttx - itx;
+                	dy = tty - ity;
+
+/* Row and column offsets in cubic block */
+					int col1 = itx - 1;
+					int col2 = itx;
+					int col3 = itx + 1;
+					int col4 = itx + 2;
+					CLAMP(col1, min_in_x, max_in_x);
+					CLAMP(col2, min_in_x, max_in_x);
+					CLAMP(col3, min_in_x, max_in_x);
+					CLAMP(col4, min_in_x, max_in_x);
+					int col1_offset = col1 * 3;
+					int col2_offset = col2 * 3;
+					int col3_offset = col3 * 3;
+					int col4_offset = col4 * 3;
+
+					unsigned char *row1_ptr = in_rows[row1];
+					unsigned char *row2_ptr = in_rows[row2];
+					unsigned char *row3_ptr = in_rows[row3];
+					unsigned char *row4_ptr = in_rows[row4];
+					int r, g, b, a;
+
+					r = (int)(transform_cubic(dy,
+                    	CUBIC_ROW(row1_ptr, 0x0),
+                    	CUBIC_ROW(row2_ptr, 0x0),
+                    	CUBIC_ROW(row3_ptr, 0x0),
+                    	CUBIC_ROW(row4_ptr, 0x0)) +
+						round_factor);
+
+					row1_ptr++;
+					row2_ptr++;
+					row3_ptr++;
+					row4_ptr++;
+					g = (int)(transform_cubic(dy,
+                    	CUBIC_ROW(row1_ptr, 0x80),
+                    	CUBIC_ROW(row2_ptr, 0x80),
+                    	CUBIC_ROW(row3_ptr, 0x80),
+                    	CUBIC_ROW(row4_ptr, 0x80)) +
+						round_factor);
+					g += 0x80;
+
+					row1_ptr++;
+					row2_ptr++;
+					row3_ptr++;
+					row4_ptr++;
+					b = (int)(transform_cubic(dy,
+                    	CUBIC_ROW(row1_ptr, 0x80),
+                    	CUBIC_ROW(row2_ptr, 0x80),
+                    	CUBIC_ROW(row3_ptr, 0x80),
+                    	CUBIC_ROW(row4_ptr, 0x80)) +
+						round_factor);
+					b += 0x80;
+
+					if(3 == 4)
+					{
+						row1_ptr++;
+						row2_ptr++;
+						row3_ptr++;
+						row4_ptr++;
+						a = (int)(transform_cubic(dy,
+                    		CUBIC_ROW(row1_ptr, 0x0),
+                    		CUBIC_ROW(row2_ptr, 0x0),
+                    		CUBIC_ROW(row3_ptr, 0x0),
+                    		CUBIC_ROW(row4_ptr, 0x0)) + 
+							round_factor);
+					}
+
+ 					if(sizeof(unsigned char) < 4)
+					{
+						*out_row++ = CLIP(r, 0, 0xff);
+						*out_row++ = CLIP(g, 0, 0xff);
+						*out_row++ = CLIP(b, 0, 0xff);
+						if(3 == 4) *out_row++ = CLIP(a, 0, 0xff);
+					}
+					else
+					{
+						*out_row++ = r;
+						*out_row++ = g;
+						*out_row++ = b;
+						if(3 == 4) *out_row++ = a;
+					}
+                }
+				else
+/* Fill with chroma */
+				{
+					*out_row++ = 0;
+					*out_row++ = 0x80;
+					*out_row++ = 0x80;
+					if(3 == 4) *out_row++ = 0;
+				}
+			}
+			else
+			{
+				out_row += 3;
+			}
+
+/*  increment the transformed coordinates  */
+			tx += xinc;
+			ty += yinc;
+			tw += winc;
+		}
+	}
+}
+
+				break;
+			case BC_YUVA8888:
+				TRANSFORM(4, unsigned char, int, 0x80, 0xff)
+				break;
+			case BC_RGB161616:
+				TRANSFORM(3, uint16_t, int, 0x0, 0xffff)
+				break;
+			case BC_RGBA16161616:
+				TRANSFORM(4, uint16_t, int, 0x0, 0xffff)
+				break;
+			case BC_YUV161616:
+				TRANSFORM(3, uint16_t, int, 0x8000, 0xffff)
+				break;
+			case BC_YUVA16161616:
+				TRANSFORM(4, uint16_t, int, 0x8000, 0xffff)
+				break;
+		}
+
+	}
+	else
+	{
+		int min_x = server->in_x * AFFINE_OVERSAMPLE;
+		int min_y = server->in_y * AFFINE_OVERSAMPLE;
+		int max_x = server->in_x * AFFINE_OVERSAMPLE + server->in_w * AFFINE_OVERSAMPLE - 1;
+		int max_y = server->in_y * AFFINE_OVERSAMPLE + server->in_h * AFFINE_OVERSAMPLE - 1;
+		float top_w = out_x2 - out_x1;
+		float bottom_w = out_x3 - out_x4;
+		float left_h = out_y4 - out_y1;
+		float right_h = out_y3 - out_y2;
+		float out_w_diff = bottom_w - top_w;
+		float out_left_diff = out_x4 - out_x1;
+		float out_h_diff = right_h - left_h;
+		float out_top_diff = out_y2 - out_y1;
+		float distance1 = DISTANCE(out_x1, out_y1, out_x2, out_y2);
+		float distance2 = DISTANCE(out_x2, out_y2, out_x3, out_y3);
+		float distance3 = DISTANCE(out_x3, out_y3, out_x4, out_y4);
+		float distance4 = DISTANCE(out_x4, out_y4, out_x1, out_y1);
+		float max_v = MAX(distance1, distance3);
+		float max_h = MAX(distance2, distance4);
+		float max_dimension = MAX(max_v, max_h);
+		float min_dimension = MIN(server->in_h, server->in_w);
+		float step = min_dimension / max_dimension / AFFINE_OVERSAMPLE;
+		float x_f = server->in_x;
+		float y_f = server->in_y;
+		float h_f = server->in_h;
+		float w_f = server->in_w;
+
+
+
+		if(server->use_opengl)
+		{
+			return;
+		}
+
+
+
+// Projection
+#define DO_STRETCH(type, components) \
+{ \
+	type **in_rows = (type**)server->input->get_rows(); \
+	type **out_rows = (type**)server->temp->get_rows(); \
+ \
+	for(float in_y = pkg->y1; in_y < pkg->y2; in_y += step) \
+	{ \
+		int i = (int)in_y; \
+		type *in_row = in_rows[i]; \
+		for(float in_x = x_f; in_x < w_f; in_x += step) \
+		{ \
+			int j = (int)in_x; \
+			float in_x_fraction = (in_x - x_f) / w_f; \
+			float in_y_fraction = (in_y - y_f) / h_f; \
+			int out_x = (int)((out_x1 + \
+				out_left_diff * in_y_fraction + \
+				(top_w + out_w_diff * in_y_fraction) * in_x_fraction) *  \
+				AFFINE_OVERSAMPLE); \
+			int out_y = (int)((out_y1 +  \
+				out_top_diff * in_x_fraction + \
+				(left_h + out_h_diff * in_x_fraction) * in_y_fraction) * \
+				AFFINE_OVERSAMPLE); \
+			CLAMP(out_x, min_x, max_x); \
+			CLAMP(out_y, min_y, max_y); \
+			type *dst = out_rows[out_y] + out_x * components; \
+			type *src = in_row + j * components; \
+			dst[0] = src[0]; \
+			dst[1] = src[1]; \
+			dst[2] = src[2]; \
+			if(components == 4) dst[3] = src[3]; \
+		} \
+	} \
+}
+
+		switch(server->input->get_color_model())
+		{
+			case BC_RGB_FLOAT:
+				DO_STRETCH(float, 3)
+				break;
+			case BC_RGB888:
+				DO_STRETCH(unsigned char, 3)
+				break;
+			case BC_RGBA_FLOAT:
+				DO_STRETCH(float, 4)
+				break;
+			case BC_RGBA8888:
+				DO_STRETCH(unsigned char, 4)
+				break;
+			case BC_YUV888:
+				DO_STRETCH(unsigned char, 3)
+				break;
+			case BC_YUVA8888:
+				DO_STRETCH(unsigned char, 4)
+				break;
+			case BC_RGB161616:
+				DO_STRETCH(uint16_t, 3)
+				break;
+			case BC_RGBA16161616:
+				DO_STRETCH(uint16_t, 4)
+				break;
+			case BC_YUV161616:
+				DO_STRETCH(uint16_t, 3)
+				break;
+			case BC_YUVA16161616:
+				DO_STRETCH(uint16_t, 4)
+				break;
+		}
+	}
+
+
+
+
+}
+
+
+
+
+
+
+AffineEngine::AffineEngine(int total_clients,
+	int total_packages)
+ : LoadServer(
+//1, 1 
+total_clients, total_packages 
+)
+{
+	user_in_viewport = 0;
+	user_in_pivot = 0;
+	user_out_viewport = 0;
+	user_out_pivot = 0;
+	use_opengl = 0;
+	in_x = in_y = in_w = in_h = 0;
+	out_x = out_y = out_w = out_h = 0;
+	in_pivot_x = in_pivot_y = 0;
+	out_pivot_x = out_pivot_y = 0;
+	this->total_packages = total_packages;
+}
+
+void AffineEngine::init_packages()
+{
+	for(int i = 0; i < get_total_packages(); i++)
+	{
+		AffinePackage *package = (AffinePackage*)get_package(i);
+		package->y1 = out_y + (out_h * i / get_total_packages());
+		package->y2 = out_y + (out_h * (i + 1) / get_total_packages());
+	}
+}
+
+LoadClient* AffineEngine::new_client()
+{
+	return new AffineUnit(this);
+}
+
+LoadPackage* AffineEngine::new_package()
+{
+	return new AffinePackage;
+}
+
+void AffineEngine::process(VFrame *output,
+	VFrame *input, 
+	VFrame *temp,
+	int mode,
+	float x1, 
+	float y1, 
+	float x2, 
+	float y2, 
+	float x3, 
+	float y3, 
+	float x4, 
+	float y4,
+	int forward)
+{
+
+
+// printf("AffineEngine::process %d %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n",
+// __LINE__,
+// x1, 
+// y1, 
+// x2, 
+// y2, 
+// x3, 
+// y3, 
+// x4, 
+// y4);
+// 
+// printf("AffineEngine::process %d %d %d %d %d\n", 
+// __LINE__,
+// in_x, in_y, in_w, in_h);
+// 
+// printf("AffineEngine::process %d %d %d %d %d\n", 
+// __LINE__,
+// out_x, out_y, out_w, out_h);
+// 
+// printf("AffineEngine::process %d %d %d %d %d\n", 
+// __LINE__,
+// in_pivot_x, in_pivot_y, out_pivot_x, out_pivot_y);
+// 
+// printf("AffineEngine::process %d %d %d %d %d\n", 
+// __LINE__,
+// user_in_pivot,
+// user_out_pivot,
+// user_in_viewport,
+// user_out_viewport);
+
+	this->output = output;
+	this->input = input;
+	this->temp = temp;
+	this->mode = mode;
+	this->x1 = x1;
+	this->y1 = y1;
+	this->x2 = x2;
+	this->y2 = y2;
+	this->x3 = x3;
+	this->y3 = y3;
+	this->x4 = x4;
+	this->y4 = y4;
+	this->forward = forward;
+
+
+	if(!user_in_viewport)
+	{
+		in_x = 0;
+		in_y = 0;
+		in_w = input->get_w();
+		in_h = input->get_h();
+	}
+
+	if(!user_out_viewport)
+	{
+		out_x = 0;
+		out_y = 0;
+		out_w = output->get_w();
+		out_h = output->get_h();
+	}
+
+	if(use_opengl)
+	{
+		set_package_count(1);
+		process_single();
+	}
+	else
+	{
+		set_package_count(total_packages);
+		process_packages();
+	}
+}
+
+
+
+
+void AffineEngine::rotate(VFrame *output,
+	VFrame *input, 
+	float angle)
+{
+	this->output = output;
+	this->input = input;
+	this->temp = 0;
+	this->mode = ROTATE;
+	this->forward = 1;
+
+	if(!user_in_viewport)
+	{
+		in_x = 0;
+		in_y = 0;
+		in_w = input->get_w();
+		in_h = input->get_h();
+// DEBUG
+// in_x = 4;
+// in_w = 2992;
+// in_y = 4;
+// in_h = 2992;
+// printf("AffineEngine::rotate %d %d %d %d %d\n", __LINE__, in_x, in_w, in_y, in_h);
+	}
+
+	if(!user_in_pivot)
+	{
+		in_pivot_x = in_x + in_w / 2;
+		in_pivot_y = in_y + in_h / 2;
+	}
+
+	if(!user_out_viewport)
+	{
+		out_x = 0;
+		out_y = 0;
+		out_w = output->get_w();
+		out_h = output->get_h();
+	}
+
+	if(!user_out_pivot)
+	{
+		out_pivot_x = out_x + out_w / 2;
+		out_pivot_y = out_y + out_h / 2;
+	}
+
+// All subscripts are clockwise around the quadrangle
+	angle = angle * 2 * M_PI / 360;
+	double angle1 = atan((double)(in_pivot_y - in_y) / (double)(in_pivot_x - in_x)) + angle;
+	double angle2 = atan((double)(in_x + in_w - in_pivot_x) / (double)(in_pivot_y - in_y)) + angle;
+	double angle3 = atan((double)(in_y + in_h - in_pivot_y) / (double)(in_x + in_w - in_pivot_x)) + angle;
+	double angle4 = atan((double)(in_pivot_x - in_x) / (double)(in_y + in_h - in_pivot_y)) + angle;
+	double radius1 = DISTANCE(in_x, in_y, in_pivot_x, in_pivot_y);
+	double radius2 = DISTANCE(in_x + in_w, in_y, in_pivot_x, in_pivot_y);
+	double radius3 = DISTANCE(in_x + in_w, in_y + in_h, in_pivot_x, in_pivot_y);
+	double radius4 = DISTANCE(in_x, in_y + in_h, in_pivot_x, in_pivot_y);
+
+	x1 = ((in_pivot_x - in_x) - cos(angle1) * radius1) * 100 / in_w;
+	y1 = ((in_pivot_y - in_y) - sin(angle1) * radius1) * 100 / in_h;
+	x2 = ((in_pivot_x - in_x) + sin(angle2) * radius2) * 100 / in_w;
+	y2 = ((in_pivot_y - in_y) - cos(angle2) * radius2) * 100 / in_h;
+	x3 = ((in_pivot_x - in_x) + cos(angle3) * radius3) * 100 / in_w;
+	y3 = ((in_pivot_y - in_y) + sin(angle3) * radius3) * 100 / in_h;
+	x4 = ((in_pivot_x - in_x) - sin(angle4) * radius4) * 100 / in_w;
+	y4 = ((in_pivot_y - in_y) + cos(angle4) * radius4) * 100 / in_h;
+
+// printf("AffineEngine::rotate angle=%f\n",
+// angle);
+
+// 
+// printf("	angle1=%f angle2=%f angle3=%f angle4=%f\n",
+// angle1 * 360 / 2 / M_PI, 
+// angle2 * 360 / 2 / M_PI, 
+// angle3 * 360 / 2 / M_PI, 
+// angle4 * 360 / 2 / M_PI);
+// 
+// printf("	radius1=%f radius2=%f radius3=%f radius4=%f\n",
+// radius1,
+// radius2,
+// radius3,
+// radius4);
+// 
+// printf("	x1=%f y1=%f x2=%f y2=%f x3=%f y3=%f x4=%f y4=%f\n",
+// x1 * w / 100, 
+// y1 * h / 100, 
+// x2 * w / 100, 
+// y2 * h / 100, 
+// x3 * w / 100, 
+// y3 * h / 100, 
+// x4 * w / 100, 
+// y4 * h / 100);
+
+	if(use_opengl)
+	{
+		set_package_count(1);
+		process_single();
+	}
+	else
+	{
+		set_package_count(total_packages);
+		process_packages();
+	}
+}
+
+void AffineEngine::set_in_viewport(int x, int y, int w, int h)
+{
+	this->in_x = x;
+	this->in_y = y;
+	this->in_w = w;
+	this->in_h = h;
+	this->user_in_viewport = 1;
+}
+
+void AffineEngine::set_out_viewport(int x, int y, int w, int h)
+{
+	this->out_x = x;
+	this->out_y = y;
+	this->out_w = w;
+	this->out_h = h;
+	this->user_out_viewport = 1;
+}
+
+void AffineEngine::set_opengl(int value)
+{
+	this->use_opengl = value;
+}
+
+void AffineEngine::set_in_pivot(int x, int y)
+{
+	this->in_pivot_x = x;
+	this->in_pivot_y = y;
+	this->user_in_pivot = 1;
+}
+
+void AffineEngine::set_out_pivot(int x, int y)
+{
+	this->out_pivot_x = x;
+	this->out_pivot_y = y;
+	this->user_out_pivot = 1;
+}
+
+void AffineEngine::unset_pivot()
+{
+	user_in_pivot = 0;
+	user_out_pivot = 0;
+}
+
+void AffineEngine::unset_viewport()
+{
+	user_in_viewport = 0;
+	user_out_viewport = 0;
+}
+
+
diff --git a/cinelerra/affine.h b/cinelerra/affine.h
new file mode 100644
index 0000000..2eaf485
--- /dev/null
+++ b/cinelerra/affine.h
@@ -0,0 +1,158 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+#ifndef AFFINE_H
+#define AFFINE_H
+
+
+#include "affine.inc"
+#include "loadbalance.h"
+#include "vframe.inc"
+
+// Affine transform library
+
+#define AFFINE_OVERSAMPLE 2
+
+class AffineMatrix
+{
+public:
+	AffineMatrix();
+	void identity();
+	void translate(double x, double y);
+	void scale(double x, double y);
+// Result is put in dst
+	void multiply(AffineMatrix *dst);
+	void copy_from(AffineMatrix *src);
+	void invert(AffineMatrix *dst);
+	void transform_point(float x, float y, float *newx, float *newy);
+	double determinant();
+	void dump();
+	double values[3][3];
+};
+
+class AffinePackage : public LoadPackage
+{
+public:
+	AffinePackage();
+	int y1, y2;
+};
+
+class AffineUnit : public LoadClient
+{
+public:
+	AffineUnit(AffineEngine *server);
+	void process_package(LoadPackage *package);
+	void calculate_matrix(
+		double in_x1,
+		double in_y1,
+		double in_x2,
+		double in_y2,
+		double out_x1,
+		double out_y1,
+		double out_x2,
+		double out_y2,
+		double out_x3,
+		double out_y3,
+		double out_x4,
+		double out_y4,
+		AffineMatrix *result);
+	float transform_cubic(float dx,
+    	float jm1,
+    	float j,
+    	float jp1,
+    	float jp2);
+	AffineEngine *server;
+};
+
+class AffineEngine : public LoadServer
+{
+public:
+	AffineEngine(int total_clients, 
+		int total_packages);
+
+// Range of coords is 0 to 100 for coordinates in the image.
+// The coordinate locations are clockwise around the image.
+	void process(VFrame *output,
+		VFrame *input, 
+		VFrame *temp,
+		int mode,
+		float x1, 
+		float y1, 
+		float x2, 
+		float y2, 
+		float x3, 
+		float y3, 
+		float x4, 
+		float y4,
+		int forward);
+// Do rotation with the affine/perspective transform.
+// This removes some of the extremely faint artifacts in the trig rotation.
+	void rotate(VFrame *output,
+		VFrame *input, 
+		float angle);
+// Set the viewport to transform.  The transform is based on the input viewport.  
+// The output viewport clips the transformed output.
+	void set_in_viewport(int x, int y, int w, int h);
+// Only used by motion tracker.  Not used in OpenGL.
+	void set_out_viewport(int x, int y, int w, int h);
+// For rotation, set the pivot point.  Also affects output in OpenGL.
+// The default is in the middle of the viewport.
+	void set_in_pivot(int x, int y);
+// Set the pivot point in the output.  Only used by motion tracker.
+	void set_out_pivot(int x, int y);
+// Never used
+	void unset_pivot();
+	void unset_viewport();
+// To use OpenGL for the processing, set to 1
+	void set_opengl(int value);
+	void init_packages();
+	LoadClient* new_client();
+	LoadPackage* new_package();
+	VFrame *input, *output, *temp;
+	int mode;
+	enum
+	{
+		PERSPECTIVE,
+		SHEER,
+		STRETCH,
+		ROTATE
+	};
+
+// Transformation coordinates
+	float x1, y1, x2, y2, x3, y3, x4, y4;
+// Viewport coordinates
+	int in_x, in_y, in_w, in_h;
+	int out_x, out_y, out_w, out_h;
+// Pivot coordinates
+	int in_pivot_x, in_pivot_y;
+	int out_pivot_x, out_pivot_y;
+	int user_in_pivot;
+	int user_out_pivot;
+	int user_in_viewport;
+	int user_out_viewport;
+	int forward;
+	int use_opengl;
+	int total_packages;
+};
+
+
+
+#endif
diff --git a/plugins/motion/affine.inc b/cinelerra/affine.inc
similarity index 100%
copy from plugins/motion/affine.inc
copy to cinelerra/affine.inc
diff --git a/cinelerra/cicolors.C b/cinelerra/cicolors.C
new file mode 100644
index 0000000..9d0a78a
--- /dev/null
+++ b/cinelerra/cicolors.C
@@ -0,0 +1,269 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+#include "cicolors.h"
+
+#include <stdio.h>
+
+HSV::HSV()
+{
+}
+
+
+HSV::~HSV()
+{
+}
+
+YUV HSV::yuv_static;
+
+int HSV::rgb_to_hsv(float r, float g, float b, float &h, float &s, float &v)
+{
+    int i;
+	float min, max, delta;
+	float f, p, q, t;
+	min = ((r < g) ? r : g) < b ? ((r < g) ? r : g) : b;
+	max = ((r > g) ? r : g) > b ? ((r > g) ? r : g) : b;
+	v = max; 
+
+	delta = max - min;
+
+	if(max != 0 && delta != 0)
+    {
+	    s = delta / max;               // s
+
+		if(r == max)
+        	h = (g - b) / delta;         // between yellow & magenta
+		else 
+		if(g == max)
+        	h = 2 + (b - r) / delta;     // between cyan & yellow
+		else
+        	h = 4 + (r - g) / delta;     // between magenta & cyan
+
+		h *= 60;                               // degrees
+		if(h < 0)
+        	h += 360;
+	}
+	else 
+	{
+        // r = g = b = 0                // s = 0, v is undefined
+        s = 0;
+        h = -1;
+	}
+	
+	return 0;
+}
+
+int HSV::hsv_to_rgb(float &r, float &g, float &b, float h, float s, float v)
+{
+    int i;
+	float min, max, delta;
+	float f, p, q, t;
+    if(s == 0) 
+	{
+        // achromatic (grey)
+        r = g = b = v;
+        return 0;
+    }
+
+    h /= 60;                        // sector 0 to 5
+    i = (int)h;
+    f = h - i;                      // factorial part of h
+    p = v * (1 - s);
+    q = v * (1 - s * f);
+    t = v * (1 - s * (1 - f));
+
+    switch(i) 
+	{
+        case 0:
+            r = v;
+            g = t;
+            b = p;
+            break;
+        case 1:
+            r = q;
+            g = v;
+            b = p;
+            break;
+        case 2:
+            r = p;
+            g = v;
+            b = t;
+            break;
+        case 3:
+            r = p;
+            g = q;
+            b = v;
+            break;
+        case 4:
+            r = t;
+            g = p;
+            b = v;
+            break;
+        default:                // case 5:
+            r = v;
+            g = p;
+            b = q;
+            break;
+    }
+	return 0;
+}
+
+int HSV::yuv_to_hsv(int y, int u, int v, float &h, float &s, float &va, int max)
+{
+	float r, g, b;
+	int r_i, g_i, b_i;
+
+// 	if(max == 0xffff)
+// 	{
+// 		yuv_static.yuv_to_rgb_16(r_i, g_i, b_i, y, u, v);
+// 	}
+// 	else
+	{
+		yuv_static.yuv_to_rgb_8(r_i, g_i, b_i, y, u, v);
+	}
+	r = (float)r_i / max;
+	g = (float)g_i / max;
+	b = (float)b_i / max;
+
+	float h2, s2, v2;
+	HSV::rgb_to_hsv(r, g, b, h2, s2, v2);
+	h = h2;
+	s = s2;
+	va = v2;
+
+	return 0;
+}
+
+int HSV::hsv_to_yuv(int &y, int &u, int &v, float h, float s, float va, int max)
+{
+	float r, g, b;
+	int r_i, g_i, b_i;
+	HSV::hsv_to_rgb(r, g, b, h, s, va);
+	r = r * max + 0.5;
+	g = g * max + 0.5;
+	b = b * max + 0.5;
+	r_i = (int)CLIP(r, 0, max);
+	g_i = (int)CLIP(g, 0, max);
+	b_i = (int)CLIP(b, 0, max);
+
+	int y2, u2, v2;
+// 	if(max == 0xffff)
+// 		yuv_static.rgb_to_yuv_16(r_i, g_i, b_i, y2, u2, v2);
+// 	else
+		yuv_static.rgb_to_yuv_8(r_i, g_i, b_i, y2, u2, v2);
+	y = y2;
+	u = u2;
+	v = v2;
+
+	return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+YUV::YUV()
+{
+	for(int i = 0; i < 0x100; i++)
+	{
+// compression
+		rtoy_tab_8[i] = (int)(R_TO_Y * 0x100 * i);
+		rtou_tab_8[i] = (int)(R_TO_U * 0x100 * i);
+		rtov_tab_8[i] = (int)(R_TO_V * 0x100 * i);
+
+		gtoy_tab_8[i] = (int)(G_TO_Y * 0x100 * i);
+		gtou_tab_8[i] = (int)(G_TO_U * 0x100 * i);
+		gtov_tab_8[i] = (int)(G_TO_V * 0x100 * i);
+
+		btoy_tab_8[i] = (int)(B_TO_Y * 0x100 * i);
+		btou_tab_8[i] = (int)(B_TO_U * 0x100 * i) + 0x8000;
+		btov_tab_8[i] = (int)(B_TO_V * 0x100 * i) + 0x8000;
+	}
+
+	vtor_8 = &(vtor_tab_8[(0x100) / 2]);
+	vtog_8 = &(vtog_tab_8[(0x100) / 2]);
+	utog_8 = &(utog_tab_8[(0x100) / 2]);
+	utob_8 = &(utob_tab_8[(0x100) / 2]);
+
+	for(int i = (-0x100) / 2; i < (0x100) / 2; i++)
+	{
+// decompression
+		vtor_8[i] = (int)(V_TO_R * 0x100 * i);
+		vtog_8[i] = (int)(V_TO_G * 0x100 * i);
+
+		utog_8[i] = (int)(U_TO_G * 0x100 * i);
+		utob_8[i] = (int)(U_TO_B * 0x100 * i);
+	}
+
+	for(int i = 0; i < 0x10000; i++)
+	{
+// compression
+		rtoy_tab_16[i] = (int)(R_TO_Y * 0x100 * i);
+		rtou_tab_16[i] = (int)(R_TO_U * 0x100 * i);
+		rtov_tab_16[i] = (int)(R_TO_V * 0x100 * i);
+
+		gtoy_tab_16[i] = (int)(G_TO_Y * 0x100 * i);
+		gtou_tab_16[i] = (int)(G_TO_U * 0x100 * i);
+		gtov_tab_16[i] = (int)(G_TO_V * 0x100 * i);
+
+		btoy_tab_16[i] = (int)(B_TO_Y * 0x100 * i);
+		btou_tab_16[i] = (int)(B_TO_U * 0x100 * i) + 0x800000;
+		btov_tab_16[i] = (int)(B_TO_V * 0x100 * i) + 0x800000;
+	}
+
+	vtor_16 = &(vtor_tab_16[(0x10000) / 2]);
+	vtog_16 = &(vtog_tab_16[(0x10000) / 2]);
+	utog_16 = &(utog_tab_16[(0x10000) / 2]);
+	utob_16 = &(utob_tab_16[(0x10000) / 2]);
+
+	for(int i = (-0x10000) / 2; i < (0x10000) / 2; i++)
+	{
+// decompression
+		vtor_16[i] = (int)(V_TO_R * 0x100 * i);
+		vtog_16[i] = (int)(V_TO_G * 0x100 * i);
+
+		utog_16[i] = (int)(U_TO_G * 0x100 * i);
+		utob_16[i] = (int)(U_TO_B * 0x100 * i);
+	}
+}
+
+YUV::~YUV()
+{
+}
diff --git a/cinelerra/cicolors.h b/cinelerra/cicolors.h
new file mode 100644
index 0000000..524bba1
--- /dev/null
+++ b/cinelerra/cicolors.h
@@ -0,0 +1,227 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 1997-2011 Adam Williams <broadcast at earthling dot net>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+#ifndef CICOLORS_H
+#define CICOLORS_H
+
+// Duplicate filename in guicast
+
+#include "clip.h"
+#include "vframe.inc"
+
+#include <stdint.h>
+
+// Compression coefficients straight out of jpeglib
+#define R_TO_Y    0.29900
+#define G_TO_Y    0.58700
+#define B_TO_Y    0.11400
+
+#define R_TO_U    -0.16874
+#define G_TO_U    -0.33126
+#define B_TO_U    0.50000
+
+#define R_TO_V    0.50000
+#define G_TO_V    -0.41869
+#define B_TO_V    -0.08131
+
+// Decompression coefficients straight out of jpeglib
+#define V_TO_R    1.40200
+#define V_TO_G    -0.71414
+
+#define U_TO_G    -0.34414
+#define U_TO_B    1.77200
+
+
+class YUV
+{
+public:
+	YUV();
+	~YUV();
+
+	inline void rgb_to_yuv_8(int &y, int &u, int &v)
+	{
+		int r = y;
+		int g = u;
+		int b = v;
+		y = (rtoy_tab_8[r] + gtoy_tab_8[g] + btoy_tab_8[b]) >> 8;
+		u = (rtou_tab_8[r] + gtou_tab_8[g] + btou_tab_8[b]) >> 8;
+		v = (rtov_tab_8[r] + gtov_tab_8[g] + btov_tab_8[b]) >> 8;
+	};
+
+	inline void rgb_to_yuv_8(int r, int g, int b, int &y, int &u, int &v)
+	{
+		y = (rtoy_tab_8[r] + gtoy_tab_8[g] + btoy_tab_8[b]) >> 8;
+		u = (rtou_tab_8[r] + gtou_tab_8[g] + btou_tab_8[b]) >> 8;
+		v = (rtov_tab_8[r] + gtov_tab_8[g] + btov_tab_8[b]) >> 8;
+	};
+
+	inline void rgb_to_yuv_8(int r, int g, int b, unsigned char &y, unsigned char &u, unsigned char &v)
+	{
+		y = (rtoy_tab_8[r] + gtoy_tab_8[g] + btoy_tab_8[b]) >> 8;
+		u = (rtou_tab_8[r] + gtou_tab_8[g] + btou_tab_8[b]) >> 8;
+		v = (rtov_tab_8[r] + gtov_tab_8[g] + btov_tab_8[b]) >> 8;
+	};
+
+	static inline void rgb_to_yuv_f(float r, float g, float b, float &y, float &u, float &v)
+	{
+		y = r * R_TO_Y + g * G_TO_Y + b * B_TO_Y;
+		u = r * R_TO_U + g * G_TO_U + b * B_TO_U;
+		v = r * R_TO_V + g * G_TO_V + b * B_TO_V;
+	};
+
+	inline void rgb_to_yuv_16(int r, int g, int b, int &y, int &u, int &v)
+	{
+		y = (rtoy_tab_16[r] + gtoy_tab_16[g] + btoy_tab_16[b]) >> 8;
+		u = (rtou_tab_16[r] + gtou_tab_16[g] + btou_tab_16[b]) >> 8;
+		v = (rtov_tab_16[r] + gtov_tab_16[g] + btov_tab_16[b]) >> 8;
+	};
+
+// For easier programming.  Doesn't do anything.
+	inline void rgb_to_yuv_8(float r, float g, float b, float &y, float &u, float &v)
+	{
+	};
+
+	inline void rgb_to_yuv_16(float r, float g, float b, float &y, float &u, float &v)
+	{
+	};
+
+	static inline void rgb_to_yuv_f(int r, int g, int b, int &y, int &u, int &v)
+	{
+	};
+
+	inline void yuv_to_rgb_8(int &r, int &g, int &b)
+	{
+		int y = r;
+		int u = g;
+		int v = b;
+		y = (y << 8) | y;
+		r = (y + vtor_tab_8[v]) >> 8;
+		g = (y + utog_tab_8[u] + vtog_tab_8[v]) >> 8;
+		b = (y + utob_tab_8[u]) >> 8;
+
+		CLAMP(r, 0, 0xff);
+		CLAMP(g, 0, 0xff);
+		CLAMP(b, 0, 0xff);
+	};
+	inline void yuv_to_rgb_8(int &r, int &g, int &b, int y, int u, int v)
+	{
+		y = (y << 8) | y;
+		r = (y + vtor_tab_8[v]) >> 8;
+		g = (y + utog_tab_8[u] + vtog_tab_8[v]) >> 8;
+		b = (y + utob_tab_8[u]) >> 8;
+
+		CLAMP(r, 0, 0xff);
+		CLAMP(g, 0, 0xff);
+		CLAMP(b, 0, 0xff);
+	};
+
+	static inline void yuv_to_rgb_f(float &r, float &g, float &b, float y, float u, float v)
+	{
+		r = y + V_TO_R * v;
+		g = y + U_TO_G * u + V_TO_G * v;
+		b = y + U_TO_B * u;
+	};
+
+	inline void rgb_to_yuv_16(int r, int g, int b, uint16_t &y, uint16_t &u, uint16_t &v)
+	{
+		y = (rtoy_tab_16[r] + gtoy_tab_16[g] + btoy_tab_16[b]) >> 8;
+		u = (rtou_tab_16[r] + gtou_tab_16[g] + btou_tab_16[b]) >> 8;
+		v = (rtov_tab_16[r] + gtov_tab_16[g] + btov_tab_16[b]) >> 8;
+	};
+
+	inline void yuv_to_rgb_16(int &r, int &g, int &b, int y, int u, int v)
+	{
+		y = (y << 8) | y;
+		r = (y + vtor_tab_16[v]) >> 8;
+		g = (y + utog_tab_16[u] + vtog_tab_16[v]) >> 8;
+		b = (y + utob_tab_16[u]) >> 8;
+
+		CLAMP(r, 0, 0xffff);
+		CLAMP(g, 0, 0xffff);
+		CLAMP(b, 0, 0xffff);
+	};
+
+// For easier programming.  Doesn't do anything.
+	inline void yuv_to_rgb_8(float &r, float &g, float &b, float y, float u, float v)
+	{
+	};
+
+// For easier programming.  Doesn't do anything.
+	inline void yuv_to_rgb_16(float &r, float &g, float &b, float y, float u, float v)
+	{
+	};
+
+	static inline void yuv_to_rgb_f(int &r, int &g, int &b, int y, int u, int v)
+	{
+	};
+
+private:
+	int rtoy_tab_8[0x100], gtoy_tab_8[0x100], btoy_tab_8[0x100];
+	int rtou_tab_8[0x100], gtou_tab_8[0x100], btou_tab_8[0x100];
+	int rtov_tab_8[0x100], gtov_tab_8[0x100], btov_tab_8[0x100];
+
+	int vtor_tab_8[0x100], vtog_tab_8[0x100];
+	int utog_tab_8[0x100], utob_tab_8[0x100];
+	int *vtor_8, *vtog_8, *utog_8, *utob_8;
+
+	int rtoy_tab_16[0x10000], gtoy_tab_16[0x10000], btoy_tab_16[0x10000];
+	int rtou_tab_16[0x10000], gtou_tab_16[0x10000], btou_tab_16[0x10000];
+	int rtov_tab_16[0x10000], gtov_tab_16[0x10000], btov_tab_16[0x10000];
+
+	int vtor_tab_16[0x10000], vtog_tab_16[0x10000];
+	int utog_tab_16[0x10000], utob_tab_16[0x10000];
+	int *vtor_16, *vtog_16, *utog_16, *utob_16;
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+class HSV
+{
+public:
+	HSV();
+    ~HSV();
+
+// All units are 0 - 1
+	static int rgb_to_hsv(float r, float g, float b, float &h, float &s, float &v);
+	static int hsv_to_rgb(float &r, float &g, float &b, float h, float s, float v);
+
+// YUV units are 0 - max.  HSV units are 0 - 1
+	static int yuv_to_hsv(int y, int u, int v, float &h, float &s, float &va, int max);
+	static int hsv_to_yuv(int &y, int &u, int &v, float h, float s, float va, int max);
+// Dummies for macros
+	static int yuv_to_hsv(float y, float u, float v, float &h, float &s, float &va, float max) { return 0; };
+	static int hsv_to_yuv(float &y, float &u, float &v, float h, float s, float va, float max) { return 0; };
+	static YUV yuv_static;
+};
+
+
+#endif
diff --git a/cinelerra/cicolors.inc b/cinelerra/cicolors.inc
new file mode 100644
index 0000000..32e3357
--- /dev/null
+++ b/cinelerra/cicolors.inc
@@ -0,0 +1,29 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+#ifndef CICOLORS_INC
+#define CICOLORS_INC
+
+
+class YUV;
+
+
+#endif
diff --git a/cinelerra/keyframe.C b/cinelerra/keyframe.C
index 48df93b..870b3dd 100644
--- a/cinelerra/keyframe.C
+++ b/cinelerra/keyframe.C
@@ -109,6 +109,11 @@ int KeyFrame::operator==(KeyFrame &that)
 }
 
 
+char* KeyFrame::get_data()
+{
+	return data;
+}
+
 void KeyFrame::dump()
 {
 	printf("     position: %lld\n", position);
diff --git a/cinelerra/keyframe.h b/cinelerra/keyframe.h
index 3401dea..2d1635a 100644
--- a/cinelerra/keyframe.h
+++ b/cinelerra/keyframe.h
@@ -45,6 +45,7 @@ public:
 	int operator==(KeyFrame &that);
 	void dump();
 	int identical(KeyFrame *src);
+	char* get_data();
 
 	char data[MESSAGESIZE];
 };
diff --git a/cinelerra/theme.C b/cinelerra/theme.C
index dba3dc7..0421deb 100644
--- a/cinelerra/theme.C
+++ b/cinelerra/theme.C
@@ -60,6 +60,8 @@
 Theme::Theme()
  : BC_Theme()
 {
+	window_border = 10;
+	widget_border = 5;
 	this->mwindow = 0;
 	theme_title = DEFAULT_THEME;
 	data_buffer = 0;
diff --git a/cinelerra/theme.h b/cinelerra/theme.h
index a309eac..f3573f5 100644
--- a/cinelerra/theme.h
+++ b/cinelerra/theme.h
@@ -245,6 +245,8 @@ public:
 	int vtime_x, vtime_y, vtime_w;
 	int vtransport_x, vtransport_y;
 	int vzoom_x, vzoom_y;
+	int window_border;
+	int widget_border;
 
 
 
diff --git a/configure.ac b/configure.ac
index ac106e1..976bbac 100644
--- a/configure.ac
+++ b/configure.ac
@@ -249,6 +249,41 @@ AC_ARG_ENABLE(freetype2,
 	[ 
 	  [freetype2=yes] ],
 	[ PKG_CHECK_MODULES(FREETYPE,freetype2,[freetype2=yes],:) ])
+
+# OpenCV is used by the findobj plugin.  Check if the needed libraries
+# exist.  The functions to look for are picked by random from the
+# libraries, and might not be the exact ones the findobj plugin need.
+AC_CHECK_HEADER(opencv2/legacy/legacy.hpp)
+AC_CHECK_HEADER(opencv2/legacy/compat.hpp)
+AC_CHECK_HEADER(opencv2/core/core_c.h, [opencvh=yes])
+AC_CHECK_LIB(opencv_legacy, cvChangeDetection)
+AC_CHECK_LIB(opencv_objdetect, cvLoadLatentSvmDetector)
+AC_CHECK_LIB(opencv_video, cvCamShift)
+AC_CHECK_LIB(opencv_core, cvReleaseMemStorage, [opencv=yes])
+AC_MSG_CHECKING(for SURF support in opencv)
+AC_TRY_LINK([#include "opencv2/legacy/legacy.hpp"
+#include "opencv2/legacy/compat.hpp"],
+[try  {
+cvExtractSURF(object_image, 
+	0, 
+	&object_keypoints, 
+	&object_descriptors, 
+	storage, 
+	params,
+	0);
+} catch (cv::Exception e) {
+  return 1;
+}
+return 0;],
+	[HAVE_OPENCV_SURF=yes],[HAVE_OPENCV_SURF=no])
+AC_MSG_RESULT([$HAVE_OPENCV_SURF])
+if test yes = "$HAVE_OPENCV_SURF" ; then
+	HAVE_OPENCV_SURF=1
+else
+	HAVE_OPENCV_SURF=0
+fi
+AC_DEFINE_UNQUOTED(HAVE_OPENCV_SURF, $HAVE_OPENCV_SURF,
+	[define if SURF support is compiled into opencv])
 ############## END OF MISC LIBRARIES
 
 LARGEFILE_CFLAGS="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64"
@@ -625,6 +660,7 @@ AC_OUTPUT(Makefile cinelerra-cvs-current.spec po/Makefile.in \
 					plugins/denoisemjpeg/Makefile \
 					plugins/despike/Makefile plugins/dissolve/Makefile plugins/dot/Makefile \
 					plugins/fieldframe/Makefile plugins/flip/Makefile plugins/framefield/Makefile \
+	plugins/findobject/Makefile \
 					plugins/freeverb/Makefile plugins/freezeframe/Makefile plugins/gain/Makefile \
 	plugins/gamma/Makefile \
 					plugins/holo/Makefile plugins/huesaturation/Makefile \
@@ -718,6 +754,8 @@ RPT(libfaac,libfaac libraries)
 RPT(libfaach,libfaac headers)
 RPT(libfaad,libfaad libraries)
 RPT(libfaadh,libfaad headers)
+RPT(opencv,opencv libraries)
+RPT(opencvh,opencv headers)
 mandatory="$succeeded"
 
 echo
diff --git a/debian/control b/debian/control
index 378e7a8..47aad36 100644
--- a/debian/control
+++ b/debian/control
@@ -18,6 +18,7 @@ Build-Depends: debhelper (>= 9), automake,
  libsndfile1-dev, libiec61883-dev (>= 1.0.0), libx264-dev,
  libfaac-dev (>= 1.24), libx11-dev, libxext-dev, libxft-dev,
  libxv-dev, libxxf86vm-dev, libfftw3-dev, libglu1-mesa-dev
+ , libopencv-core-dev, libopencv-objdetect-dev, libopencv-legacy-dev
 Homepage: http://www.cinelerra-cv.org/
 
 Package: cinelerra-cv
diff --git a/guicast/Makefile.am b/guicast/Makefile.am
index e9e14de..c1ba79d 100644
--- a/guicast/Makefile.am
+++ b/guicast/Makefile.am
@@ -8,6 +8,11 @@ libguicast_la_SOURCES = \
 	bcbitmap.C \
 	bcbutton.C \
 	bccapture.C \
+	bccmodels.C \
+	bccmodel_float.C \
+	bccmodel_yuv420p.C \
+	bccmodel_yuv422.C \
+	bccmodel_default.C \
 	bcclipboard.C \
 	bcdelete.C \
 	bcdialog.C \
@@ -79,6 +84,9 @@ noinst_HEADERS = \
 	bcbutton.inc \
 	bccapture.h \
 	bccapture.inc \
+	bccmodel_permutation.h \
+	bccmodels.h \
+	bccmodels.inc \
 	bcclipboard.h \
 	bcclipboard.inc \
 	bcdelete.h \
diff --git a/guicast/bccmodel_default.C b/guicast/bccmodel_default.C
new file mode 100644
index 0000000..6d8b108
--- /dev/null
+++ b/guicast/bccmodel_default.C
@@ -0,0 +1,1518 @@
+/*
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 
+ * USA
+ */
+
+
+#include "bccmodel_permutation.h"
+#include "bccmodels.h"
+
+
+
+
+
+
+
+
+
+// ********************************* YUV101010 -> *****************************
+
+#define READ_YUV101010 \
+	uint64_t y, u, v; \
+	uint32_t input_i = input[0] | \
+		(input[1] << 8) | \
+		(input[2] << 16) | \
+		(input[3] << 24); \
+ \
+	y = ((input_i & 0xffc00000) >> 16) | 0x3f; \
+	u = ((input_i & 0x3ff000) >> 6) | 0x3f; \
+	v = ((input_i & 0xffc) << 4) | 0x3f;
+
+
+
+
+
+
+static inline void transfer_YUV101010_to_RGB8(unsigned char *(*output), unsigned char *input)
+{
+	int r, g, b;
+
+	READ_YUV101010
+
+	y = (y << 8) | (y >> 8);
+
+	YUV_TO_RGB16(y, u, v, r, g, b);
+
+	*(*output)++ = (unsigned char)(((input[0] & 0xc000) >> 8) +
+			    			 ((input[1] & 0xe000) >> 10) +
+		 	    			 ((input[2] & 0xe000) >> 13));
+}
+
+static inline void transfer_YUV101010_to_BGR565(unsigned char *(*output), unsigned char *input)
+{
+	int r, g, b;
+
+	READ_YUV101010
+
+	y = (y << 8) | (y >> 8);
+
+	YUV_TO_RGB16(y, u, v, r, g, b);
+
+	*(uint16_t*)(*output) = (b & 0xf800) |
+			 ((g & 0xfc00) >> 5) |
+			 ((r & 0xf800) >> 11);
+	(*output) += 2;
+}
+
+static inline void transfer_YUV101010_to_RGB565(unsigned char *(*output), unsigned char *input)
+{
+	int r, g, b;
+
+	READ_YUV101010
+
+	y = (y << 8) | (y >> 8);
+
+	YUV_TO_RGB16(y, u, v, r, g, b);
+
+	*(uint16_t*)(*output) = (r & 0xf800) |
+			 ((g & 0xfc00) >> 5) |
+			 ((b & 0xf800) >> 11);
+	(*output) += 2;
+}
+
+static inline void transfer_YUV101010_to_BGR888(unsigned char *(*output), unsigned char *input)
+{
+	int r, g, b;
+
+	READ_YUV101010
+
+	y = (y << 8) | (y >> 8);
+
+	YUV_TO_RGB16(y, u, v, r, g, b);
+
+	*(*output)++ = b >> 8;
+	*(*output)++ = g >> 8;
+	*(*output)++ = r >> 8;
+}
+
+static inline void transfer_YUV101010_to_BGR8888(unsigned char *(*output), unsigned char *input)
+{
+	int r, g, b;
+
+	READ_YUV101010
+
+	y = (y << 8) | (y >> 8);
+
+	YUV_TO_RGB16(y, u, v, r, g, b);
+
+	*(*output)++ = b >> 8;
+	*(*output)++ = g >> 8;
+	*(*output)++ = r >> 8;
+	(*output)++;
+}
+
+static inline void transfer_YUV101010_to_YUV888(unsigned char *(*output), unsigned char *input)
+{
+	READ_YUV101010
+	 
+	*(*output)++ = y >> 8;
+	*(*output)++ = u >> 8;
+	*(*output)++ = v >> 8;
+}
+
+static inline void transfer_YUV101010_to_YUVA8888(unsigned char *(*output), unsigned char *input)
+{
+	READ_YUV101010
+	 
+	*(*output)++ = y >> 8;
+	*(*output)++ = u >> 8;
+	*(*output)++ = v >> 8;
+	*(*output)++ = 0xff;
+}
+
+
+static inline void transfer_YUV101010_to_RGB888(unsigned char *(*output), unsigned char *input)
+{
+	int r, g, b;
+
+	READ_YUV101010
+
+	y = (y << 8) | (y >> 8);
+
+	YUV_TO_RGB16(y, u, v, r, g, b);
+
+	*(*output)++ = r >> 8;
+	*(*output)++ = g >> 8;
+	*(*output)++ = b >> 8;
+}
+
+static inline void transfer_YUV101010_to_RGBA8888(unsigned char *(*output), unsigned char *input)
+{
+	int r, g, b;
+
+	READ_YUV101010
+
+	y = (y << 8) | (y >> 8);
+
+	YUV_TO_RGB16(y, u, v, r, g, b);
+
+	*(*output)++ = r >> 8;
+	*(*output)++ = g >> 8;
+	*(*output)++ = b >> 8;
+	*(*output)++ = 0xff;
+}
+
+static inline void transfer_YUV101010_to_RGB161616(uint16_t *(*output), unsigned char *input)
+{
+	int r, g, b;
+
+	READ_YUV101010
+
+	y = (y << 8) | (y >> 8);
+
+	YUV_TO_RGB16(y, u, v, r, g, b);
+
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+}
+
+static inline void transfer_YUV101010_to_RGBA16161616(uint16_t *(*output), unsigned char *input)
+{
+	int r, g, b;
+
+	READ_YUV101010
+
+	y = (y << 8) | (y >> 8);
+
+	YUV_TO_RGB16(y, u, v, r, g, b);
+
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+	*(*output)++ = 0xffff;
+}
+
+
+
+
+static inline void transfer_YUV101010_to_RGB_FLOAT(float *(*output), 
+	unsigned char *input)
+{
+	float r, g, b;
+	float y_f;
+
+	READ_YUV101010
+
+	y_f = (float)y / 0xffff;
+
+	YUV16_TO_RGB_FLOAT(y_f, u, v, r, g, b);
+
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+}
+
+static inline void transfer_YUV101010_to_RGBA_FLOAT(float *(*output), 
+	unsigned char *input)
+{
+	float r, g, b;
+	float y_f;
+
+	READ_YUV101010
+
+	y_f = (float)y / 0xffff;
+
+	YUV16_TO_RGB_FLOAT(y_f, u, v, r, g, b);
+
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+	*(*output)++ = 1.0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// ******************************** VYU888 -> *********************************
+
+
+static inline void transfer_VYU888_to_RGB8(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = ((int)input[1]) << 16;
+	u = input[2];
+	v = input[0];
+	YUV_TO_RGB(y, u, v, r, g, b);
+
+	*(*output) = (unsigned char)((r & 0xc0) +
+			    			 ((g & 0xe0) >> 2) +
+		 	    			 ((b & 0xe0) >> 5));
+	(*output)++;
+}
+
+static inline void transfer_VYU888_to_BGR565(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = ((int)input[1]) << 16;
+	u = input[2];
+	v = input[0];
+	YUV_TO_RGB(y, u, v, r, g, b);
+	*(uint16_t*)(*output) = ((b & 0xf8) << 8)
+			 + ((g & 0xfc) << 3)
+			 + ((r & 0xf8) >> 3);
+	(*output) += 2;
+}
+
+static inline void transfer_VYU888_to_RGB565(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = ((int)input[1]) << 16;
+	u = input[2];
+	v = input[0];
+	YUV_TO_RGB(y, u, v, r, g, b);
+	*(uint16_t*)(*output) = ((r & 0xf8) << 8)
+			 + ((g & 0xfc) << 3)
+			 + ((b & 0xf8) >> 3);
+	(*output) += 2;
+}
+
+static inline void transfer_VYU888_to_BGR888(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = ((int)input[1]) << 16;
+	u = input[2];
+	v = input[0];
+	YUV_TO_RGB(y, u, v, r, g, b);
+
+	(*output)[2] = r;
+	(*output)[1] = g;
+	(*output)[0] = b;
+	(*output) += 3;
+}
+
+static inline void transfer_VYU888_to_BGR8888(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v;
+	int r, g, b;
+
+	y = ((int)input[1]) << 16;
+	u = input[2];
+	v = input[0];
+	YUV_TO_RGB(y, u, v, r, g, b);
+	(*output)[2] = r;
+	(*output)[1] = g;
+	(*output)[0] = b;
+	(*output) += 4;
+}
+
+
+static inline void transfer_VYU888_to_RGB888(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = ((int)input[1]) << 16;
+	u = input[2];
+	v = input[0];
+	YUV_TO_RGB(y, u, v, r, g, b);
+
+	(*output)[0] = r;
+	(*output)[1] = g;
+	(*output)[2] = b;
+	(*output) += 3;
+}
+
+static inline void transfer_VYU888_to_RGBA8888(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = ((int)input[1]) << 16;
+	u = input[2];
+	v = input[0];
+	YUV_TO_RGB(y, u, v, r, g, b);
+
+	(*output)[0] = r;
+	(*output)[1] = g;
+	(*output)[2] = b;
+	(*output)[3] = 0xff;
+	(*output) += 4;
+}
+
+
+static inline void transfer_VYU888_to_RGB161616(uint16_t *(*output), unsigned char *input)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = (input[1] << 16) | (input[1] << 8) | input[1];
+	u = (input[2] << 8) | input[2];
+	v = (input[0] << 8) | input[0];
+	YUV_TO_RGB16(y, u, v, r, g, b);
+
+	(*output)[0] = r;
+	(*output)[1] = g;
+	(*output)[2] = b;
+	(*output) += 3;
+}
+
+static inline void transfer_VYU888_to_RGBA16161616(uint16_t *(*output), unsigned char *input)
+{
+	int y, u, v;
+	int r, g, b;
+
+	y = (input[1] << 16) | (input[1] << 8) | input[1];
+	u = (input[2] << 8) | input[2];
+	v = (input[0] << 8) | input[0];
+	YUV_TO_RGB16(y, u, v, r, g, b);
+
+	(*output)[0] = r;
+	(*output)[1] = g;
+	(*output)[2] = b;
+	(*output)[3] = 0xffff;
+	(*output) += 3;
+}
+
+
+static inline void transfer_VYU888_to_RGB_FLOAT(float *(*output), unsigned char *input)
+{
+	float y;
+	int u, v;
+	float r, g, b;
+	
+	v = *input++;
+	y = (float)*input++ / 0xff;
+	u = *input;
+	YUV_TO_FLOAT(y, u, v, r, g, b);
+
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+}
+
+static inline void transfer_VYU888_to_RGBA_FLOAT(float *(*output), unsigned char *input)
+{
+	float y;
+	int u, v;
+	float r, g, b;
+	
+	v = *input++;
+	y = (float)*input++ / 0xff;
+	u = *input;
+	YUV_TO_FLOAT(y, u, v, r, g, b);
+
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+	*(*output)++ = 1.0;
+}
+
+
+static inline void transfer_VYU888_to_YUV888(unsigned char *(*output), unsigned char *input)
+{
+	(*output)[0] = input[1];
+	(*output)[1] = input[2];
+	(*output)[2] = input[0];
+	(*output) += 3;
+}
+
+static inline void transfer_VYU888_to_YUVA8888(unsigned char *(*output), unsigned char *input)
+{
+	(*output)[0] = input[1];
+	(*output)[1] = input[2];
+	(*output)[2] = input[0];
+	(*output)[3] = 0xff;
+	(*output) += 4;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// ******************************** UYVA8888 -> *********************************
+
+
+static inline void transfer_UYVA8888_to_RGB8(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v;
+	int r, g, b;
+
+	y = ((int)input[1]) << 16;
+	u = input[0];
+	v = input[2];
+	YUV_TO_RGB(y, u, v, r, g, b);
+
+	r = r * input[3] / 0xff;
+	g = g * input[3] / 0xff;
+	b = b * input[3] / 0xff;
+	*(*output) = (unsigned char)((r & 0xc0) +
+			    			 ((g & 0xe0) >> 2) +
+		 	    			 ((b & 0xe0) >> 5));
+	(*output)++;
+}
+
+static inline void transfer_UYVA8888_to_BGR565(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = ((int)input[1]) << 16;
+	u = input[0];
+	v = input[2];
+	YUV_TO_RGB(y, u, v, r, g, b);
+	r = r * input[3] / 0xff;
+	g = g * input[3] / 0xff;
+	b = b * input[3] / 0xff;
+	*(uint16_t*)(*output) = ((b & 0xf8) << 8)
+			 + ((g & 0xfc) << 3)
+			 + ((r & 0xf8) >> 3);
+	(*output) += 2;
+}
+
+static inline void transfer_UYVA8888_to_RGB565(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = ((int)input[1]) << 16;
+	u = input[0];
+	v = input[2];
+	YUV_TO_RGB(y, u, v, r, g, b);
+	r = r * input[3] / 0xff;
+	g = g * input[3] / 0xff;
+	b = b * input[3] / 0xff;
+	*(uint16_t*)(*output) = ((r & 0xf8) << 8)
+			 + ((g & 0xfc) << 3)
+			 + ((b & 0xf8) >> 3);
+	(*output) += 2;
+}
+
+static inline void transfer_UYVA8888_to_BGR888(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = ((int)input[1]) << 16;
+	u = input[0];
+	v = input[2];
+	YUV_TO_RGB(y, u, v, r, g, b);
+	r = r * input[3] / 0xff;
+	g = g * input[3] / 0xff;
+	b = b * input[3] / 0xff;
+
+	(*output)[2] = r;
+	(*output)[1] = g;
+	(*output)[0] = b;
+	(*output) += 3;
+}
+
+static inline void transfer_UYVA8888_to_BGR8888(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = ((int)input[1]) << 16;
+	u = input[0];
+	v = input[2];
+	YUV_TO_RGB(y, u, v, r, g, b);
+	r = r * input[3] / 0xff;
+	g = g * input[3] / 0xff;
+	b = b * input[3] / 0xff;
+
+	(*output)[2] = r;
+	(*output)[1] = g;
+	(*output)[0] = b;
+	(*output) += 4;
+}
+
+
+static inline void transfer_UYVA8888_to_RGB888(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = ((int)input[1]) << 16;
+	u = input[0];
+	v = input[2];
+	YUV_TO_RGB(y, u, v, r, g, b);
+	r = r * input[3] / 0xff;
+	g = g * input[3] / 0xff;
+	b = b * input[3] / 0xff;
+
+	(*output)[0] = r;
+	(*output)[1] = g;
+	(*output)[2] = b;
+	(*output) += 3;
+}
+
+static inline void transfer_UYVA8888_to_RGBA8888(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = ((int)input[1]) << 16;
+	u = input[0];
+	v = input[2];
+	YUV_TO_RGB(y, u, v, r, g, b);
+
+	(*output)[0] = r;
+	(*output)[1] = g;
+	(*output)[2] = b;
+	(*output)[3] = input[3];
+	(*output) += 4;
+}
+
+
+static inline void transfer_UYVA8888_to_RGB161616(uint16_t *(*output), unsigned char *input)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = ((int)input[1]) << 16;
+	u = (input[0] << 8) | input[0];
+	v = (input[2] << 8) | input[2];
+	YUV_TO_RGB16(y, u, v, r, g, b);
+	r = r * input[3] / 0xff;
+	g = g * input[3] / 0xff;
+	b = b * input[3] / 0xff;
+
+	(*output)[0] = r;
+	(*output)[1] = g;
+	(*output)[2] = b;
+	(*output) += 3;
+}
+
+static inline void transfer_UYVA8888_to_RGBA16161616(uint16_t *(*output), unsigned char *input)
+{
+	int y, u, v;
+	int r, g, b;
+
+	y = ((int)input[1]) << 16;
+	u = (input[0] << 8) | input[0];
+	v = (input[2] << 8) | input[2];
+	YUV_TO_RGB16(y, u, v, r, g, b);
+
+	(*output)[0] = r;
+	(*output)[1] = g;
+	(*output)[2] = b;
+	(*output)[3] = input[3] << 8;
+	(*output) += 4;
+}
+
+static inline void transfer_UYVA8888_to_RGB_FLOAT(float *(*output), unsigned char *input)
+{
+	float y, a;
+	int u, v;
+	float r, g, b;
+	
+	u = *input++;
+	y = (float)*input++ / 0xff;
+	v = *input++;
+	a = (float)*input / 0xff;
+	YUV_TO_FLOAT(y, u, v, r, g, b);
+
+	r = r * a;
+	g = g * a;
+	b = b * a;
+
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+}
+
+static inline void transfer_UYVA8888_to_RGBA_FLOAT(float *(*output), unsigned char *input)
+{
+	float y, a;
+	int u, v;
+	float r, g, b;
+	
+	u = *input++;
+	y = (float)*input++ / 0xff;
+	v = *input++;
+	a = (float)*input / 0xff;
+	YUV_TO_FLOAT(y, u, v, r, g, b);
+
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+	*(*output)++ = a;
+}
+
+
+static inline void transfer_UYVA8888_to_YUV888(unsigned char *(*output), unsigned char *input)
+{
+	int a, anti_a;
+	a = input[3];
+	anti_a = 0xff - a;
+
+	(*output)[0] = (a * input[1]) / 0xff;
+	(*output)[1] = (a * input[0] + anti_a * 0x80) / 0xff;
+	(*output)[2] = (a * input[2] + anti_a * 0x80) / 0xff;
+	(*output) += 3;
+}
+
+static inline void transfer_UYVA8888_to_YUVA8888(unsigned char *(*output), unsigned char *input)
+{
+	(*output)[0] = input[1];
+	(*output)[1] = input[0];
+	(*output)[2] = input[2];
+	(*output)[3] = input[3];
+	(*output) += 4;
+}
+
+
+
+
+
+
+
+
+
+
+
+#define TRANSFER_FRAME_DEFAULT(output, \
+	input, \
+	y_in_offset, \
+	u_in_offset, \
+	v_in_offset, \
+	input_column) \
+{ \
+	register int i, j; \
+ \
+	switch(in_colormodel) \
+	{ \
+		case BC_YUV888: \
+			switch(out_colormodel) \
+			{ \
+				case BC_RGB8: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV888_to_RGB8((output), (input));      \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR565: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV888_to_BGR565((output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB565: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV888_to_RGB565((output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV888_to_BGR888((output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV888_to_BGR8888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV888_to_RGB888((output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV888_to_RGBA8888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_ARGB8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV888_to_ARGB8888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB_FLOAT: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV888_to_RGB_FLOAT((float**)(output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA_FLOAT: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV888_to_RGBA_FLOAT((float**)(output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV101010: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV888_to_YUV101010((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV420P: \
+					TRANSFER_YUV420P_OUT_HEAD \
+					transfer_YUV888_to_YUV420P_YUV422P(output_y, \
+						output_u, \
+						output_v, \
+						(input), \
+						j); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV422P: \
+					TRANSFER_YUV422P_OUT_HEAD \
+					transfer_YUV888_to_YUV420P_YUV422P(output_y, \
+						output_u, \
+						output_v, \
+						(input), \
+						j); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV444P: \
+					TRANSFER_YUV444P_OUT_HEAD \
+					transfer_YUV888_to_YUV444P(output_y, \
+						output_u, \
+						output_v, \
+						(input), \
+						j); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV422: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV888_to_YUV422((output), \
+						(input), \
+						j); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV888_to_YUV888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUVA8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV888_to_YUVA8888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_VYU888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV888_to_VYU888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_UYVA8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV888_to_UYVA8888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+			} \
+			break; \
+ \
+		case BC_YUVA8888: \
+			switch(out_colormodel) \
+			{ \
+				case BC_RGB8: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUVA8888_to_RGB8((output), (input));      \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR565: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUVA8888_to_BGR565((output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB565: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUVA8888_to_RGB565((output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUVA8888_to_BGR888((output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUVA8888_to_BGR8888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUVA8888_to_RGB888((output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUVA8888_to_RGBA8888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_ARGB8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUVA8888_to_ARGB8888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB_FLOAT: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUVA8888_to_RGB_FLOAT((float**)(output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA_FLOAT: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUVA8888_to_RGBA_FLOAT((float**)(output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_VYU888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUVA8888_to_VYU888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUVA8888_to_YUV888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUVA8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUVA8888_to_YUVA8888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_UYVA8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUVA8888_to_UYVA8888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV101010: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUVA8888_to_YUV101010((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV420P: \
+					TRANSFER_YUV420P_OUT_HEAD \
+					transfer_YUVA8888_to_YUV420P_YUV422P(output_y, \
+						output_u, \
+						output_v, \
+						(input), \
+						j); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV422P: \
+					TRANSFER_YUV422P_OUT_HEAD \
+					transfer_YUVA8888_to_YUV420P_YUV422P(output_y, \
+						output_u, \
+						output_v, \
+						(input), \
+						j); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV444P: \
+					TRANSFER_YUV444P_OUT_HEAD \
+					transfer_YUVA8888_to_YUV444P(output_y, \
+						output_u, \
+						output_v, \
+						(input), \
+						j); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV422: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUVA8888_to_YUV422((output), \
+						(input), \
+						j); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+			} \
+			break; \
+ \
+		case BC_YUV101010: \
+			switch(out_colormodel) \
+			{ \
+				case BC_RGB8: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV101010_to_RGB8((output), (input));      \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR565: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV101010_to_BGR565((output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB565: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV101010_to_RGB565((output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV101010_to_BGR888((output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV101010_to_BGR8888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV101010_to_RGB888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV101010_to_RGBA8888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV101010_to_YUV888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUVA8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV101010_to_YUVA8888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB161616: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV101010_to_RGB161616((uint16_t**)(output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA16161616: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV101010_to_RGBA16161616((uint16_t**)(output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB_FLOAT: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV101010_to_RGB_FLOAT((float**)(output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA_FLOAT: \
+					TRANSFER_FRAME_HEAD \
+					transfer_YUV101010_to_RGBA_FLOAT((float**)(output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+			} \
+			break; \
+ \
+		case BC_VYU888: \
+			switch(out_colormodel) \
+			{ \
+				case BC_RGB8: \
+					TRANSFER_FRAME_HEAD \
+					transfer_VYU888_to_RGB8((output), (input));      \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR565: \
+					TRANSFER_FRAME_HEAD \
+					transfer_VYU888_to_BGR565((output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB565: \
+					TRANSFER_FRAME_HEAD \
+					transfer_VYU888_to_RGB565((output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_VYU888_to_BGR888((output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_VYU888_to_BGR8888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_VYU888_to_RGB888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_VYU888_to_RGBA8888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_VYU888_to_YUV888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUVA8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_VYU888_to_YUVA8888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB161616: \
+					TRANSFER_FRAME_HEAD \
+					transfer_VYU888_to_RGB161616((uint16_t**)(output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA16161616: \
+					TRANSFER_FRAME_HEAD \
+					transfer_VYU888_to_RGBA16161616((uint16_t**)(output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB_FLOAT: \
+					TRANSFER_FRAME_HEAD \
+					transfer_VYU888_to_RGB_FLOAT((float**)(output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA_FLOAT: \
+					TRANSFER_FRAME_HEAD \
+					transfer_VYU888_to_RGBA_FLOAT((float**)(output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+			} \
+			break; \
+ \
+		case BC_UYVA8888: \
+			switch(out_colormodel) \
+			{ \
+				case BC_RGB8: \
+					TRANSFER_FRAME_HEAD \
+					transfer_UYVA8888_to_RGB8((output), (input));      \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR565: \
+					TRANSFER_FRAME_HEAD \
+					transfer_UYVA8888_to_BGR565((output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB565: \
+					TRANSFER_FRAME_HEAD \
+					transfer_UYVA8888_to_RGB565((output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_UYVA8888_to_BGR888((output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_UYVA8888_to_BGR8888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_UYVA8888_to_RGB888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_UYVA8888_to_RGBA8888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_UYVA8888_to_YUV888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUVA8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_UYVA8888_to_YUVA8888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB161616: \
+					TRANSFER_FRAME_HEAD \
+					transfer_UYVA8888_to_RGB161616((uint16_t**)(output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA16161616: \
+					TRANSFER_FRAME_HEAD \
+					transfer_UYVA8888_to_RGBA16161616((uint16_t**)(output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB_FLOAT: \
+					TRANSFER_FRAME_HEAD \
+					transfer_UYVA8888_to_RGB_FLOAT((float**)(output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA_FLOAT: \
+					TRANSFER_FRAME_HEAD \
+					transfer_UYVA8888_to_RGBA_FLOAT((float**)(output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+			} \
+			break; \
+ \
+ 		case BC_ARGB8888: \
+ 		case BC_ABGR8888: \
+			switch(out_colormodel) \
+			{ \
+				case BC_ARGB8888: \
+				case BC_ABGR8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_ARGB8888_to_ARGB8888((output), (input)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_ARGB8888_to_RGBA8888((output), (input)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_ARGB8888_to_RGB888((output), (input)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_ARGB8888_to_BGR8888((output), (input)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+			} \
+			break; \
+ \
+		case BC_RGB888: \
+			switch(out_colormodel) \
+			{ \
+				case BC_RGB8: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB888_to_RGB8((output), (input));      \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR565: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB888_to_BGR565((output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB565: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB888_to_RGB565((output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB888_to_BGR888((output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB888_to_RGB888((output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB888_to_RGBA8888((output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_ARGB8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB888_to_ARGB8888((output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB161616: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB888_to_RGB161616((uint16_t**)(output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA16161616: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB888_to_RGBA16161616((uint16_t**)(output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB_FLOAT: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB888_to_RGB_FLOAT((float**)(output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA_FLOAT: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB888_to_RGBA_FLOAT((float**)(output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_ABGR8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB888_to_ABGR8888((output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB888_to_BGR8888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB888_to_YUV888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUVA8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB888_to_YUVA8888((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV101010: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB888_to_YUV101010((output), (input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV420P: \
+					TRANSFER_YUV420P_OUT_HEAD \
+					transfer_RGB888_to_YUV420P_YUV422P(output_y, \
+						output_u, \
+						output_v, \
+						(input), \
+						j); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV422: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB888_to_YUV422((output), (input), j); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV422P: \
+					TRANSFER_YUV422P_OUT_HEAD \
+					transfer_RGB888_to_YUV420P_YUV422P(output_y, \
+						output_u, \
+						output_v, \
+						(input), \
+						j); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV444P: \
+					TRANSFER_YUV444P_OUT_HEAD \
+					transfer_RGB888_to_YUV444P(output_y, \
+						output_u, \
+						output_v, \
+						(input), \
+						j); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+			} \
+			break; \
+ \
+		case BC_RGBA8888: \
+			switch(out_colormodel) \
+			{ \
+				case BC_TRANSPARENCY: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGBA8888_to_TRANSPARENCY((output), (input), &bit_counter); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB8: \
+					if(bg_color > 0) \
+						TRANSFER_FRAME_HEAD \
+						transfer_RGBA8888_to_RGB8bg((output), (input), bg_r, bg_g, bg_b); \
+						TRANSFER_FRAME_TAIL \
+					else \
+						TRANSFER_FRAME_HEAD \
+						transfer_RGBA8888_to_RGB8((output), (input)); \
+						TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR565: \
+					if(bg_color > 0) \
+						TRANSFER_FRAME_HEAD \
+						transfer_RGBA8888_to_BGR565bg((output), (input), bg_r, bg_g, bg_b); \
+						TRANSFER_FRAME_TAIL \
+					else \
+						TRANSFER_FRAME_HEAD \
+						transfer_RGBA8888_to_BGR565((output), (input)); \
+						TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB565: \
+					if(bg_color > 0) \
+						TRANSFER_FRAME_HEAD \
+						transfer_RGBA8888_to_RGB565bg((output), (input), bg_r, bg_g, bg_b); \
+						TRANSFER_FRAME_TAIL \
+					else \
+						TRANSFER_FRAME_HEAD \
+						transfer_RGBA8888_to_RGB565((output), (input)); \
+						TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR888: \
+					if(bg_color > 0) \
+						TRANSFER_FRAME_HEAD \
+						transfer_RGBA8888_to_BGR888bg((output), (input), bg_r, bg_g, bg_b); \
+						TRANSFER_FRAME_TAIL \
+					else \
+						TRANSFER_FRAME_HEAD \
+						transfer_RGBA8888_to_BGR888((output), (input)); \
+						TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB888: \
+					if(bg_color > 0) \
+						TRANSFER_FRAME_HEAD \
+						transfer_RGBA8888_to_RGB888bg((output), (input), bg_r, bg_g, bg_b); \
+						TRANSFER_FRAME_TAIL \
+					else \
+						TRANSFER_FRAME_HEAD \
+						transfer_RGBA8888_to_RGB888((output), (input)); \
+						TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGBA8888_to_RGBA8888((output), (input)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_ARGB8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGBA8888_to_ARGB8888((output), (input)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB161616: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGBA8888_to_RGB161616((uint16_t**)(output), (input)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA16161616: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGBA8888_to_RGBA16161616((uint16_t**)(output), (input)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB_FLOAT: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGBA8888_to_RGB_FLOAT((float**)(output), (input)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA_FLOAT: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGBA8888_to_RGBA_FLOAT((float**)(output), (input)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR8888: \
+					if(bg_color > 0) \
+						TRANSFER_FRAME_HEAD \
+						transfer_RGBA8888_to_BGR8888bg((output), (input), bg_r, bg_g, bg_b); \
+						TRANSFER_FRAME_TAIL \
+					else \
+						TRANSFER_FRAME_HEAD \
+						transfer_RGBA8888_to_BGR8888((output), (input)); \
+						TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGBA8888_to_YUV888((output), (input)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUVA8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGBA8888_to_YUVA8888((output), (input)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV101010: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGBA8888_to_YUV101010((output), (input)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV420P: \
+					TRANSFER_YUV420P_OUT_HEAD \
+					transfer_RGBA888_to_YUV420P_YUV422P(output_y, \
+						output_u, \
+						output_v, \
+						(input), \
+						j); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV422: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGBA888_to_YUV422((output), (input), j); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV422P: \
+					TRANSFER_YUV422P_OUT_HEAD \
+					transfer_RGBA888_to_YUV420P_YUV422P(output_y, \
+						output_u, \
+						output_v, \
+						(input), \
+						j); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV444P: \
+					TRANSFER_YUV444P_OUT_HEAD \
+					transfer_RGBA888_to_YUV444P(output_y, \
+						output_u, \
+						output_v, \
+						(input), \
+						j); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+			} \
+			break; \
+ \
+		case BC_BGR8888: \
+			switch(out_colormodel) \
+			{ \
+				case BC_RGB888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_BGR8888_to_RGB888((output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_BGR8888_to_BGR8888((output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+			} \
+			break; \
+ \
+		case BC_BGR888: \
+			switch(out_colormodel) \
+			{ \
+				case BC_RGB888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_BGR888_to_RGB888((output), (input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+			} \
+			break; \
+	} \
+}
+
+
+
+
+void BC_CModels::cmodel_default(PERMUTATION_ARGS)
+{
+	if(scale)
+	{
+		TRANSFER_FRAME_DEFAULT(&output_row, 
+			input_row + column_table[j] * in_pixelsize,
+			0,
+			0,
+			0,
+			0);
+	}
+	else
+	{
+		TRANSFER_FRAME_DEFAULT(&output_row, 
+			input_row + j * in_pixelsize,
+			0,
+			0,
+			0,
+			0);
+	}
+}
diff --git a/guicast/bccmodel_float.C b/guicast/bccmodel_float.C
new file mode 100644
index 0000000..279ce45
--- /dev/null
+++ b/guicast/bccmodel_float.C
@@ -0,0 +1,746 @@
+#include "bccmodel_permutation.h"
+#include "bccmodels.h"
+#include "clip.h"
+#include "workarounds.h"
+
+// ********************************** RGB FLOAT -> *******************************
+
+
+
+static inline void transfer_RGB_FLOAT_to_RGB8(unsigned char *(*output), float *input)
+{
+	unsigned char r, g, b;
+	r = (unsigned char)(CLIP(input[0], 0, 1) * 0x3);
+	g = (unsigned char)(CLIP(input[1], 0, 1) * 0x7);
+	b = (unsigned char)(CLIP(input[2], 0, 1) * 0x3);
+
+	*(*output) = (r << 6) +
+			     (g << 2) +
+		 	     b;
+	(*output)++;
+}
+
+static inline void transfer_RGB_FLOAT_to_BGR565(unsigned char *(*output), float *input)
+{
+	unsigned char r, g, b;
+	r = (unsigned char)(CLIP(input[0], 0, 1) * 0x1f);
+	g = (unsigned char)(CLIP(input[1], 0, 1) * 0x3f);
+	b = (unsigned char)(CLIP(input[2], 0, 1) * 0x1f);
+
+	*(uint16_t*)(*output) = (b << 11) |
+		(g << 5) |
+		r;
+	(*output) += 2;
+}
+
+static inline void transfer_RGB_FLOAT_to_RGB565(unsigned char *(*output), float *input)
+{
+	unsigned char r, g, b;
+	r = (unsigned char)(CLIP(input[0], 0, 1) * 0x1f);
+	g = (unsigned char)(CLIP(input[1], 0, 1) * 0x3f);
+	b = (unsigned char)(CLIP(input[2], 0, 1) * 0x1f);
+
+	*(uint16_t*)(*output) = (r << 11) |
+		(g << 5) |
+		b;
+	(*output) += 2;
+}
+
+static inline void transfer_RGB_FLOAT_to_BGR888(unsigned char *(*output), 
+	float *input)
+{
+	unsigned char r = (unsigned char)(CLIP(input[0], 0, 1) * 0xff);
+	unsigned char g = (unsigned char)(CLIP(input[1], 0, 1) * 0xff);
+	unsigned char b = (unsigned char)(CLIP(input[2], 0, 1) * 0xff);
+	*(*output)++ = b;
+	*(*output)++ = g;
+	*(*output)++ = r;
+}
+
+static inline void transfer_RGB_FLOAT_to_RGB888(unsigned char *(*output), 
+	float *input)
+{
+	unsigned char r = (unsigned char)(CLIP(input[0], 0, 1) * 0xff);
+	unsigned char g = (unsigned char)(CLIP(input[1], 0, 1) * 0xff);
+	unsigned char b = (unsigned char)(CLIP(input[2], 0, 1) * 0xff);
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+}
+
+static inline void transfer_RGB_FLOAT_to_RGBA8888(unsigned char *(*output), 
+	float *input)
+{
+	unsigned char r = (unsigned char)(CLIP(input[0], 0, 1) * 0xff);
+	unsigned char g = (unsigned char)(CLIP(input[1], 0, 1) * 0xff);
+	unsigned char b = (unsigned char)(CLIP(input[2], 0, 1) * 0xff);
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+	*(*output)++ = 0xff;
+}
+
+static inline void transfer_RGB_FLOAT_to_ARGB8888(unsigned char *(*output), 
+	float *input)
+{
+	unsigned char r = (unsigned char)(CLIP(input[0], 0, 1) * 0xff);
+	unsigned char g = (unsigned char)(CLIP(input[1], 0, 1) * 0xff);
+	unsigned char b = (unsigned char)(CLIP(input[2], 0, 1) * 0xff);
+	*(*output)++ = 0xff;
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+}
+
+static inline void transfer_RGB_FLOAT_to_RGBA_FLOAT(float *(*output), 
+	float *input)
+{
+	*(*output)++ = input[0];
+	*(*output)++ = input[1];
+	*(*output)++ = input[2];
+	*(*output)++ = 1.0;
+}
+
+static inline void transfer_RGB_FLOAT_to_BGR8888(unsigned char *(*output), 
+	float *input)
+{
+	unsigned char r = (unsigned char)(CLIP(input[0], 0, 1) * 0xff);
+	unsigned char g = (unsigned char)(CLIP(input[1], 0, 1) * 0xff);
+	unsigned char b = (unsigned char)(CLIP(input[2], 0, 1) * 0xff);
+	(*output)[0] = b;
+	(*output)[1] = g;
+	(*output)[2] = r;
+	(*output) += 4;
+}
+
+static inline void transfer_RGB_FLOAT_to_YUV888(unsigned char *(*output), 
+	float *input)
+{
+	int y, u, v, r, g, b;
+	r = (int)(CLIP(input[0], 0, 1) * 0xffff);
+	g = (int)(CLIP(input[1], 0, 1) * 0xffff);
+	b = (int)(CLIP(input[2], 0, 1) * 0xffff);
+
+	RGB_TO_YUV16(y, u, v, r, g, b);
+
+	*(*output)++ = y >> 8;
+	*(*output)++ = u >> 8;
+	*(*output)++ = v >> 8;
+}
+
+static inline void transfer_RGB_FLOAT_to_YUVA8888(unsigned char *(*output), 
+	float *input)
+{
+	int y, u, v, r, g, b;
+
+	r = (int)(CLIP(input[0], 0, 1) * 0xffff);
+	g = (int)(CLIP(input[1], 0, 1) * 0xffff);
+	b = (int)(CLIP(input[2], 0, 1) * 0xffff);
+
+	RGB_TO_YUV16(y, u, v, r, g, b);
+
+	*(*output)++ = y >> 8;
+	*(*output)++ = u >> 8;
+	*(*output)++ = v >> 8;
+	*(*output)++ = 255;
+}
+
+
+static inline void transfer_RGB_FLOAT_to_YUV101010(unsigned char *(*output), 
+	float *input)
+{
+	int r, g, b;
+	int y, u, v;
+
+	r = (int)(CLIP(input[0], 0, 1) * 0xffff);
+	g = (int)(CLIP(input[1], 0, 1) * 0xffff);
+	b = (int)(CLIP(input[2], 0, 1) * 0xffff);
+	RGB_TO_YUV16(y, u, v, r, g, b);
+	WRITE_YUV101010(y, u, v);
+}
+
+static inline void transfer_RGB_FLOAT_to_VYU888(unsigned char *(*output), 
+	float *input)
+{
+	int y, u, v, r, g, b;
+	r = (int)(CLIP(input[0], 0, 1) * 0xffff);
+	g = (int)(CLIP(input[1], 0, 1) * 0xffff);
+	b = (int)(CLIP(input[2], 0, 1) * 0xffff);
+
+	RGB_TO_YUV16(y, u, v, r, g, b);
+
+	*(*output)++ = v >> 8;
+	*(*output)++ = y >> 8;
+	*(*output)++ = u >> 8;
+}
+
+static inline void transfer_RGB_FLOAT_to_UYVA8888(unsigned char *(*output), 
+	float *input)
+{
+	int y, u, v, r, g, b;
+
+	r = (int)(CLIP(input[0], 0, 1) * 0xffff);
+	g = (int)(CLIP(input[1], 0, 1) * 0xffff);
+	b = (int)(CLIP(input[2], 0, 1) * 0xffff);
+
+	RGB_TO_YUV16(y, u, v, r, g, b);
+
+	*(*output)++ = u >> 8;
+	*(*output)++ = y >> 8;
+	*(*output)++ = v >> 8;
+	*(*output)++ = 0xff;
+}
+
+
+static inline void transfer_RGB_FLOAT_to_YUV420P_YUV422P(unsigned char *output_y, 
+	unsigned char *output_u, 
+	unsigned char *output_v, 
+	float *input,
+	int output_column)
+{
+	int y, u, v, r, g, b;
+	r = (int)(CLIP(input[0], 0, 1) * 0xffff);
+	g = (int)(CLIP(input[1], 0, 1) * 0xffff);
+	b = (int)(CLIP(input[2], 0, 1) * 0xffff);
+
+	RGB_TO_YUV16(y, u, v, r, g, b);
+
+	output_y[output_column] = y >> 8;
+	output_u[output_column / 2] = u >> 8;
+	output_v[output_column / 2] = v >> 8;
+}
+
+static inline void transfer_RGB_FLOAT_to_YUV422(unsigned char *(*output),
+	float *input,
+	int j)
+{
+	int y, u, v, r, g, b;
+	r = (int)(CLIP(input[0], 0, 1) * 0xffff);
+	g = (int)(CLIP(input[1], 0, 1) * 0xffff);
+	b = (int)(CLIP(input[2], 0, 1) * 0xffff);
+
+	RGB_TO_YUV16(y, u, v, r, g, b);
+	if(!(j & 1))
+	{
+		(*output)[1] = u >> 8;
+		(*output)[3] = v >> 8;
+		(*output)[0] = y >> 8;
+	}
+	else
+	{
+		(*output)[2] = y >> 8;
+		(*output) += 4;
+	}
+}
+
+static inline void transfer_RGB_FLOAT_to_YUV444P(unsigned char *output_y, 
+	unsigned char *output_u, 
+	unsigned char *output_v, 
+	float *input,
+	int output_column)
+{
+	int y, u, v, r, g, b;
+	r = (int)(CLIP(input[0], 0, 1) * 0xffff);
+	g = (int)(CLIP(input[1], 0, 1) * 0xffff);
+	b = (int)(CLIP(input[2], 0, 1) * 0xffff);
+
+	RGB_TO_YUV16(y, u, v, r, g, b);
+
+	output_y[output_column] = y >> 8;
+	output_u[output_column] = u >> 8;
+	output_v[output_column] = v >> 8;
+}
+
+
+
+
+
+
+
+
+
+
+// ****************************** RGBA FLOAT -> *********************************
+
+static inline void transfer_RGBA_FLOAT_to_RGB8(unsigned char *(*output), 
+	float *input)
+{
+	uint32_t r, g, b, a;
+	a = (uint32_t)(CLIP(input[3], 0, 1) * 0x10000);
+	r = (uint32_t)(CLIP(input[0], 0, 1) * 0xff * a);
+	g = (uint32_t)(CLIP(input[1], 0, 1) * 0xff * a);
+	b = (uint32_t)(CLIP(input[2], 0, 1) * 0xff * a);
+
+	*(*output) = (unsigned char)(((r & 0xc00000) >> 16) + 
+				((g & 0xe00000) >> 18) + 
+				((b & 0xe00000) >> 21));
+	(*output)++;
+}
+
+static inline void transfer_RGBA_FLOAT_to_BGR565(unsigned char *(*output), 
+	float *input)
+{
+	uint32_t r, g, b, a;
+	a = (uint32_t)(CLIP(input[3], 0, 1) * 0x10000);
+	r = (uint32_t)(CLIP(input[0], 0, 1) * 0xff * a);
+	g = (uint32_t)(CLIP(input[1], 0, 1) * 0xff * a);
+	b = (uint32_t)(CLIP(input[2], 0, 1) * 0xff * a);
+
+	*(uint16_t*)(*output) = (uint16_t)(((b & 0xf80000) >> 8) + 
+				((g & 0xfc0000) >> 13) + 
+				((r & 0xf80000) >> 19));
+	(*output) += 2;
+}
+
+static inline void transfer_RGBA_FLOAT_to_RGB565(unsigned char *(*output), 
+	float *input)
+{
+	uint32_t r, g, b, a;
+	a = (uint32_t)(CLIP(input[3], 0, 1) * 0x10000);
+	r = (uint32_t)(CLIP(input[0], 0, 1) * 0xff * a);
+	g = (uint32_t)(CLIP(input[1], 0, 1) * 0xff * a);
+	b = (uint32_t)(CLIP(input[2], 0, 1) * 0xff * a);
+
+	*(uint16_t*)(*output) = (uint16_t)(((r & 0xf80000) >> 8) + 
+				((g & 0xfc0000) >> 13) + 
+				((b & 0xf80000) >> 19));
+	(*output) += 2;
+}
+
+static inline void transfer_RGBA_FLOAT_to_BGR888(unsigned char *(*output), 
+	float *input)
+{
+	uint32_t r, g, b, a;
+	a = (uint32_t)(CLIP(input[3], 0, 1) * 0xff);
+	r = (uint32_t)(CLIP(input[0], 0, 1) * a);
+	g = (uint32_t)(CLIP(input[1], 0, 1) * a);
+	b = (uint32_t)(CLIP(input[2], 0, 1) * a);
+
+	*(*output)++ = (unsigned char)b;
+	*(*output)++ = (unsigned char)g;
+	*(*output)++ = (unsigned char)r;
+}
+
+static inline void transfer_RGBA_FLOAT_to_RGB888(unsigned char *(*output), 
+	float *input)
+{
+	uint32_t r, g, b, a;
+	a = (uint32_t)(CLIP(input[3], 0, 1) * 0xff);
+	r = (uint32_t)(CLIP(input[0], 0, 1) * a);
+	g = (uint32_t)(CLIP(input[1], 0, 1) * a);
+	b = (uint32_t)(CLIP(input[2], 0, 1) * a);
+
+	*(*output)++ = (unsigned char)r;
+	*(*output)++ = (unsigned char)g;
+	*(*output)++ = (unsigned char)b;
+}
+
+static inline void transfer_RGBA_FLOAT_to_RGB_FLOAT(float *(*output), 
+	float *input)
+{
+	float a;
+	a = input[3];
+
+	*(*output)++ = input[0] * a;
+	*(*output)++ = input[1] * a;
+	*(*output)++ = input[2] * a;
+}
+
+
+static inline void transfer_RGBA_FLOAT_to_RGBA8888(unsigned char *(*output), 
+	float *input)
+{
+	*(*output)++ = (unsigned char)(CLIP(input[0], 0, 1) * 0xff);
+	*(*output)++ = (unsigned char)(CLIP(input[1], 0, 1) * 0xff);
+	*(*output)++ = (unsigned char)(CLIP(input[2], 0, 1) * 0xff);
+	*(*output)++ = (unsigned char)(CLIP(input[3], 0, 1) * 0xff);
+}
+
+static inline void transfer_RGBA_FLOAT_to_ARGB8888(unsigned char *(*output), 
+	float *input)
+{
+	*(*output)++ = (unsigned char)(CLIP(input[3], 0, 1) * 0xff);
+	*(*output)++ = (unsigned char)(CLIP(input[0], 0, 1) * 0xff);
+	*(*output)++ = (unsigned char)(CLIP(input[1], 0, 1) * 0xff);
+	*(*output)++ = (unsigned char)(CLIP(input[2], 0, 1) * 0xff);
+}
+
+
+static inline void transfer_RGBA_FLOAT_to_BGR8888(unsigned char *(*output), 
+	float *input)
+{
+	uint32_t r, g, b, a;
+	a = (uint32_t)(CLIP(input[3], 0, 1) * 0xff);
+	r = (uint32_t)(CLIP(input[0], 0, 1) * a);
+	g = (uint32_t)(CLIP(input[1], 0, 1) * a);
+	b = (uint32_t)(CLIP(input[2], 0, 1) * a);
+
+	*(*output)++ = (unsigned char)(b);
+	*(*output)++ = (unsigned char)(g);
+	*(*output)++ = (unsigned char)(r);
+	*(*output)++;
+}
+
+static inline void transfer_RGBA_FLOAT_to_YUV888(unsigned char *(*output), 
+	float *input)
+{
+	int y, u, v, r, g, b, a;
+	a = (int)(CLIP(input[3], 0, 1) * 0x101);
+	r = (int)(CLIP(input[0], 0, 1) * 0xff * a);
+	g = (int)(CLIP(input[1], 0, 1) * 0xff * a);
+	b = (int)(CLIP(input[2], 0, 1) * 0xff * a);
+
+	RGB_TO_YUV16(y, u, v, r, g, b);
+
+	*(*output)++ = y >> 8;
+	*(*output)++ = u >> 8;
+	*(*output)++ = v >> 8;
+}
+
+static inline void transfer_RGBA_FLOAT_to_YUVA8888(unsigned char *(*output), 
+	float *input)
+{
+	int y, u, v, r, g, b, a;
+
+	a = (int)(CLIP(input[3], 0, 1) * 0xff);
+	r = (int)(CLIP(input[0], 0, 1) * 0xffff);
+	g = (int)(CLIP(input[1], 0, 1) * 0xffff);
+	b = (int)(CLIP(input[2], 0, 1) * 0xffff);
+
+	RGB_TO_YUV16(y, u, v, r, g, b);
+
+	*(*output)++ = y >> 8;
+	*(*output)++ = u >> 8;
+	*(*output)++ = v >> 8;
+	*(*output)++ = a;
+}
+
+static inline void transfer_RGBA_FLOAT_to_YUV101010(unsigned char *(*output), 
+	float *input)
+{
+	int y, u, v, r, g, b, a;
+
+	a = (int)(CLIP(input[3], 0, 1) * 0x101);
+	r = (int)(CLIP(input[0], 0, 1) * 0xff * a);
+	g = (int)(CLIP(input[1], 0, 1) * 0xff * a);
+	b = (int)(CLIP(input[2], 0, 1) * 0xff * a);
+
+	RGB_TO_YUV16(y, u, v, r, g, b);
+	WRITE_YUV101010(y, u, v);
+}
+
+
+static inline void transfer_RGBA_FLOAT_to_YUV420P_YUV422P(unsigned char *output_y, 
+	unsigned char *output_u, 
+	unsigned char *output_v, 
+	float *input,
+	int output_column)
+{
+	int y, u, v, r, g, b, a;
+	a = (int)(CLIP(input[3], 0, 1) * 0x101);
+	r = (int)(CLIP(input[0], 0, 1) * 0xff * a);
+	g = (int)(CLIP(input[1], 0, 1) * 0xff * a);
+	b = (int)(CLIP(input[2], 0, 1) * 0xff * a);
+
+	RGB_TO_YUV16(y, u, v, r, g, b);
+
+	output_y[output_column] = y >> 8;
+	output_u[output_column / 2] = u >> 8;
+	output_v[output_column / 2] = v >> 8;
+}
+
+static inline void transfer_RGBA_FLOAT_to_YUV422(unsigned char *(*output),
+	float *input,
+	int j)
+{
+	int y, u, v, r, g, b;
+	float a = CLIP(input[3], 0, 1);
+	r = (int)(CLIP(input[0], 0, 1) * a * 0xffff);
+	g = (int)(CLIP(input[1], 0, 1) * a * 0xffff);
+	b = (int)(CLIP(input[2], 0, 1) * a * 0xffff);
+
+	RGB_TO_YUV16(y, u, v, r, g, b);
+	if(!(j & 1))
+	{
+		(*output)[1] = u >> 8;
+		(*output)[3] = v >> 8;
+		(*output)[0] = y >> 8;
+	}
+	else
+	{
+		(*output)[2] = y >> 8;
+		(*output) += 4;
+	}
+}
+
+
+static inline void transfer_RGBA_FLOAT_to_YUV444P(unsigned char *output_y, 
+	unsigned char *output_u, 
+	unsigned char *output_v, 
+	float *input,
+	int output_column)
+{
+	int y, u, v, r, g, b, a;
+	a = (int)(CLIP(input[3], 0, 1) * 0x101);
+	r = (int)(CLIP(input[0], 0, 1) * 0xff * a);
+	g = (int)(CLIP(input[1], 0, 1) * 0xff * a);
+	b = (int)(CLIP(input[2], 0, 1) * 0xff * a);
+
+	RGB_TO_YUV16(y, u, v, r, g, b);
+
+	output_y[output_column] = y >> 8;
+	output_u[output_column] = u >> 8;
+	output_v[output_column] = v >> 8;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#define TRANSFER_DEFAULT(output, \
+	input, \
+	y_in_offset, \
+	u_in_offset, \
+	v_in_offset, \
+	input_column) \
+{ \
+	register int i, j; \
+ \
+	switch(in_colormodel) \
+	{ \
+		case BC_RGB_FLOAT: \
+			switch(out_colormodel) \
+			{ \
+				case BC_RGB8: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB_FLOAT_to_RGB8((output), (float*)(input));      \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR565: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB_FLOAT_to_BGR565((output), (float*)(input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB565: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB_FLOAT_to_RGB565((output), (float*)(input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB_FLOAT_to_BGR888((output), (float*)(input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB_FLOAT_to_BGR8888((output), (float*)(input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB_FLOAT_to_RGB888((output), (float*)(input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB_FLOAT_to_RGBA8888((output), (float*)(input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_ARGB8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB_FLOAT_to_ARGB8888((output), (float*)(input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA_FLOAT: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB_FLOAT_to_RGBA_FLOAT((float**)(output), (float*)(input));    \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB_FLOAT_to_YUV888((output), (float*)(input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUVA8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB_FLOAT_to_YUVA8888((output), (float*)(input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV101010: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB_FLOAT_to_YUV101010((output), (float*)(input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV420P: \
+					TRANSFER_YUV420P_OUT_HEAD \
+					transfer_RGB_FLOAT_to_YUV420P_YUV422P(output_y, \
+						output_u, \
+						output_v, \
+						(float*)(input), \
+						j); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV422P: \
+					TRANSFER_YUV422P_OUT_HEAD \
+					transfer_RGB_FLOAT_to_YUV420P_YUV422P(output_y, \
+						output_u, \
+						output_v, \
+						(float*)(input), \
+						j); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV422: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGB_FLOAT_to_YUV422((output), \
+						(float*)(input), \
+						j); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV444P: \
+					TRANSFER_YUV444P_OUT_HEAD \
+					transfer_RGB_FLOAT_to_YUV444P(output_y, \
+						output_u, \
+						output_v, \
+						(float*)(input), \
+						j); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+			} \
+			break; \
+ \
+		case BC_RGBA_FLOAT: \
+			switch(out_colormodel) \
+			{ \
+				case BC_RGB8: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGBA_FLOAT_to_RGB8((output), (float*)(input)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR565: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGBA_FLOAT_to_BGR565((output), (float*)(input)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB565: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGBA_FLOAT_to_RGB565((output), (float*)(input)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR888:      \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGBA_FLOAT_to_BGR888((output), (float*)(input)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGBA_FLOAT_to_BGR8888((output), (float*)(input)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGBA_FLOAT_to_RGB888((output), (float*)(input)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB_FLOAT: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGBA_FLOAT_to_RGB_FLOAT((float**)(output), (float*)(input)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGBA_FLOAT_to_RGBA8888((output), (float*)(input)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_ARGB8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGBA_FLOAT_to_ARGB8888((output), (float*)(input)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGBA_FLOAT_to_YUV888((output), (float*)(input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUVA8888: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGBA_FLOAT_to_YUVA8888((output), (float*)(input));   \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV101010: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGBA_FLOAT_to_YUV101010((output), (float*)(input)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV420P: \
+					TRANSFER_YUV420P_OUT_HEAD \
+					transfer_RGBA_FLOAT_to_YUV420P_YUV422P(output_y, \
+						output_u, \
+						output_v, \
+						(float*)(input), \
+						j); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV422P: \
+					TRANSFER_YUV422P_OUT_HEAD \
+					transfer_RGBA_FLOAT_to_YUV420P_YUV422P(output_y, \
+						output_u, \
+						output_v, \
+						(float*)(input), \
+						j); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV422: \
+					TRANSFER_FRAME_HEAD \
+					transfer_RGBA_FLOAT_to_YUV422((output), \
+						(float*)(input), \
+						j); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV444P: \
+					TRANSFER_YUV444P_OUT_HEAD \
+					transfer_RGBA_FLOAT_to_YUV444P(output_y, \
+						output_u, \
+						output_v, \
+						(float*)(input), \
+						j); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+			} \
+			break; \
+	} \
+}
+
+
+
+void BC_CModels::cmodel_float(PERMUTATION_ARGS)
+{
+	if(scale)
+	{
+		TRANSFER_DEFAULT(&output_row, 
+			input_row + column_table[j] * in_pixelsize,
+			0,
+			0,
+			0,
+			0);
+	}
+	else
+	{
+		TRANSFER_DEFAULT(&output_row, 
+			input_row + j * in_pixelsize,
+			0,
+			0,
+			0,
+			0);
+	}
+}
+
diff --git a/guicast/bccmodel_permutation.h b/guicast/bccmodel_permutation.h
new file mode 100644
index 0000000..b817a24
--- /dev/null
+++ b/guicast/bccmodel_permutation.h
@@ -0,0 +1,2500 @@
+/*
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 
+ * USA
+ */
+
+
+
+#include "bccmodels.h"
+#include "clip.h"
+#include <stdint.h>
+
+// All variables are unsigned
+// y -> 24 bits u, v, -> 8 bits r, g, b -> 8 bits
+#define YUV_TO_RGB(y, u, v, r, g, b) \
+{ \
+	(r) = ((y + BC_CModels::yuv_table.vtor_tab[v]) >> 16); \
+	(g) = ((y + BC_CModels::yuv_table.utog_tab[u] + BC_CModels::yuv_table.vtog_tab[v]) >> 16); \
+	(b) = ((y + BC_CModels::yuv_table.utob_tab[u]) >> 16); \
+	CLAMP(r, 0, 0xff); \
+	CLAMP(g, 0, 0xff); \
+	CLAMP(b, 0, 0xff); \
+}
+
+// y -> 0 - 1 float
+// u, v, -> 8 bits
+// r, g, b -> float
+#define YUV_TO_FLOAT(y, u, v, r, g, b) \
+{ \
+	(r) = y + BC_CModels::yuv_table.vtor_float_tab[v]; \
+	(g) = y + BC_CModels::yuv_table.utog_float_tab[u] + BC_CModels::yuv_table.vtog_float_tab[v]; \
+	(b) = y + BC_CModels::yuv_table.utob_float_tab[u]; \
+}
+
+// y -> 0 - 1 float
+// u, v, -> 16 bits
+// r, g, b -> float
+#define YUV16_TO_RGB_FLOAT(y, u, v, r, g, b) \
+{ \
+	(r) = y + BC_CModels::yuv_table.v16tor_float_tab[v]; \
+	(g) = y + BC_CModels::yuv_table.u16tog_float_tab[u] + BC_CModels::yuv_table.v16tog_float_tab[v]; \
+	(b) = y + BC_CModels::yuv_table.u16tob_float_tab[u]; \
+}
+
+// y -> 24 bits   u, v-> 16 bits
+#define YUV_TO_RGB16(y, u, v, r, g, b) \
+{ \
+	(r) = ((y + BC_CModels::yuv_table.vtor_tab16[v]) >> 8); \
+	(g) = ((y + BC_CModels::yuv_table.utog_tab16[u] + BC_CModels::yuv_table.vtog_tab16[v]) >> 8); \
+	(b) = ((y + BC_CModels::yuv_table.utob_tab16[u]) >> 8); \
+	CLAMP(r, 0, 0xffff); \
+	CLAMP(g, 0, 0xffff); \
+	CLAMP(b, 0, 0xffff); \
+}
+
+
+
+
+#define RGB_TO_YUV(y, u, v, r, g, b) \
+{ \
+	y = ((BC_CModels::yuv_table.rtoy_tab[r] + BC_CModels::yuv_table.gtoy_tab[g] + BC_CModels::yuv_table.btoy_tab[b]) >> 16); \
+	u = ((BC_CModels::yuv_table.rtou_tab[r] + BC_CModels::yuv_table.gtou_tab[g] + BC_CModels::yuv_table.btou_tab[b]) >> 16); \
+	v = ((BC_CModels::yuv_table.rtov_tab[r] + BC_CModels::yuv_table.gtov_tab[g] + BC_CModels::yuv_table.btov_tab[b]) >> 16); \
+	CLAMP(y, 0, 0xff); \
+	CLAMP(u, 0, 0xff); \
+	CLAMP(v, 0, 0xff); \
+}
+
+// r, g, b -> 16 bits
+#define RGB_TO_YUV16(y, u, v, r, g, b) \
+{ \
+	y = ((BC_CModels::yuv_table.rtoy_tab16[r] + BC_CModels::yuv_table.gtoy_tab16[g] + BC_CModels::yuv_table.btoy_tab16[b]) >> 8); \
+	u = ((BC_CModels::yuv_table.rtou_tab16[r] + BC_CModels::yuv_table.gtou_tab16[g] + BC_CModels::yuv_table.btou_tab16[b]) >> 8); \
+	v = ((BC_CModels::yuv_table.rtov_tab16[r] + BC_CModels::yuv_table.gtov_tab16[g] + BC_CModels::yuv_table.btov_tab16[b]) >> 8); \
+	CLAMP(y, 0, 0xffff); \
+	CLAMP(u, 0, 0xffff); \
+	CLAMP(v, 0, 0xffff); \
+}
+
+#define WRITE_YUV101010(y, u, v) \
+{ \
+	uint32_t output_i = ((y & 0xffc0) << 16) | \
+		((u & 0xffc0) << 6) | \
+		((v & 0xffc0) >> 4); \
+	*(*output)++ = (output_i & 0xff); \
+	*(*output)++ = (output_i & 0xff00) >> 8; \
+	*(*output)++ = (output_i & 0xff0000) >> 16; \
+	*(*output)++ = (output_i & 0xff000000) >> 24; \
+}
+
+
+
+// ****************************** Pixel transfers *****************************
+
+
+
+
+
+
+// ****************************** ARGB8888 -> *********************************
+
+static inline void transfer_ARGB8888_to_ARGB8888(unsigned char *(*output), unsigned char *input)
+{
+	(*output)[0] = input[0];
+	(*output)[1] = input[1];
+	(*output)[2] = input[2];
+	(*output)[3] = input[3];
+	(*output) += 4;
+}
+
+static inline void transfer_ARGB8888_to_RGBA8888(unsigned char *(*output), unsigned char *input)
+{
+	(*output)[0] = input[1];
+	(*output)[1] = input[2];
+	(*output)[2] = input[3];
+	(*output)[3] = input[0];
+	(*output) += 4;
+}
+
+
+static inline void transfer_ARGB8888_to_RGB888(unsigned char *(*output), unsigned char *input)
+{
+	int a = input[0];
+	(*output)[0] = input[1] * a / 0xff;
+	(*output)[1] = input[2] * a / 0xff;
+	(*output)[2] = input[3] * a / 0xff;
+	(*output) += 3;
+}
+
+static inline void transfer_ARGB8888_to_BGR8888(unsigned char *(*output), unsigned char *input)
+{
+	int a = input[0];
+	(*output)[0] = input[3] * a / 0xff;
+	(*output)[1] = input[2] * a / 0xff;
+	(*output)[2] = input[1] * a / 0xff;
+	(*output) += 3;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// ******************************** RGB888 -> *********************************
+
+static inline void transfer_RGB888_to_RGB8(unsigned char *(*output), unsigned char *input)
+{
+	*(*output) = (unsigned char)((input[0] & 0xc0) +
+			    			 ((input[1] & 0xe0) >> 2) +
+		 	    			 ((input[2] & 0xe0) >> 5));
+	(*output)++;
+}
+
+static inline void transfer_RGB888_to_BGR565(unsigned char *(*output), unsigned char *input)
+{
+	uint16_t r, g, b;
+	uint16_t r_s, g_s, b_s;
+	r = *input++;
+	g = *input++;
+	b = *input;
+	
+	r_s  = (r & 0x01) << 7;
+	r_s |= (r & 0x02) << 5;
+	r_s |= (r & 0x04) << 3;
+	r_s |= (r & 0x08) << 1;
+	r_s |= (r & 0x10) >> 1;
+	r_s |= (r & 0x20) >> 3;
+	r_s |= (r & 0x40) >> 5;
+	r_s |= (r & 0x80) >> 7;
+
+	g_s  = (g & 0x01) << 7;
+	g_s |= (g & 0x02) << 5;
+	g_s |= (g & 0x04) << 3;
+	g_s |= (g & 0x08) << 1;
+	g_s |= (g & 0x10) >> 1;
+	g_s |= (g & 0x20) >> 3;
+	g_s |= (g & 0x40) >> 5;
+	g_s |= (g & 0x80) >> 7;
+
+	b_s  = (b & 0x01) << 7;
+	b_s |= (b & 0x02) << 5;
+	b_s |= (b & 0x04) << 3;
+	b_s |= (b & 0x08) << 1;
+	b_s |= (b & 0x10) >> 1;
+	b_s |= (b & 0x20) >> 3;
+	b_s |= (b & 0x40) >> 5;
+	b_s |= (b & 0x80) >> 7;
+
+	*(uint16_t*)(*output) = ((b_s & 0xf8) << 8)
+			 + ((g_s & 0xfc) << 3)
+			 + ((r_s & 0xf8) >> 3);
+	(*output) += 2;
+}
+
+static inline void transfer_RGB888_to_RGB565(unsigned char *(*output), unsigned char *input)
+{
+	uint16_t r, g, b;
+	r = *input++;
+	g = *input++;
+	b = *input;
+	*(uint16_t*)(*output) = ((r & 0xf8) << 8)
+			 + ((g & 0xfc) << 3)
+			 + ((b & 0xf8) >> 3);
+	(*output) += 2;
+}
+
+static inline void transfer_RGB888_to_BGR888(unsigned char *(*output), unsigned char *input)
+{
+	*(*output)++ = input[2];
+	*(*output)++ = input[1];
+	*(*output)++ = input[0];
+}
+
+static inline void transfer_RGB888_to_RGB888(unsigned char *(*output), unsigned char *input)
+{
+	*(*output)++ = *input++;
+	*(*output)++ = *input++;
+	*(*output)++ = *input;
+}
+
+static inline void transfer_RGB888_to_RGBA8888(unsigned char *(*output), unsigned char *input)
+{
+	*(*output)++ = *input++;
+	*(*output)++ = *input++;
+	*(*output)++ = *input;
+	*(*output)++ = 0xff;
+}
+
+static inline void transfer_RGB888_to_ARGB8888(unsigned char *(*output), unsigned char *input)
+{
+	*(*output)++ = 0xff;
+	*(*output)++ = *input++;
+	*(*output)++ = *input++;
+	*(*output)++ = *input;
+}
+
+static inline void transfer_RGB888_to_RGB161616(uint16_t *(*output), unsigned char *input)
+{
+	(*output)[0] = (input[0] << 8) | input[0];
+	(*output)[1] = (input[1] << 8) | input[1];
+	(*output)[2] = (input[2] << 8) | input[2];
+	(*output) += 3;
+}
+
+static inline void transfer_RGB888_to_RGBA16161616(uint16_t *(*output), unsigned char *input)
+{
+	(*output)[0] = (input[0] << 8) | input[0];
+	(*output)[1] = (input[1] << 8) | input[1];
+	(*output)[2] = (input[2] << 8) | input[2];
+	(*output)[3] = 0xffff;
+	(*output) += 4;
+}
+
+static inline void transfer_RGB888_to_RGB_FLOAT(float *(*output), unsigned char *input)
+{
+	*(*output)++ = (float)*input++ / 0xff;
+	*(*output)++ = (float)*input++ / 0xff;
+	*(*output)++ = (float)*input / 0xff;
+}
+
+static inline void transfer_RGB888_to_RGBA_FLOAT(float *(*output), unsigned char *input)
+{
+	*(*output)++ = (float)*input++ / 0xff;
+	*(*output)++ = (float)*input++ / 0xff;
+	*(*output)++ = (float)*input / 0xff;
+	*(*output)++ = 1.0;
+}
+
+static inline void transfer_RGB888_to_ABGR8888(unsigned char *(*output), unsigned char *input)
+{
+	*(*output)++ = 0xff;
+	*(*output)++ = input[2];
+	*(*output)++ = input[1];
+	*(*output)++ = input[0];
+}
+
+static inline void transfer_RGB888_to_BGR8888(unsigned char *(*output), unsigned char *input)
+{
+	*(*output)++ = input[2];
+	*(*output)++ = input[1];
+	*(*output)++ = input[0];
+	(*output)++;
+}
+
+static inline void transfer_RGB888_to_YUV888(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v;
+
+	RGB_TO_YUV(y, u, v, input[0], input[1], input[2]);
+
+	*(*output)++ = y;
+	*(*output)++ = u;
+	*(*output)++ = v;
+}
+
+
+static inline void transfer_RGB888_to_YUV101010(unsigned char *(*output), unsigned char *input)
+{
+	int r, g, b;
+	int y, u, v;
+
+	r = ((uint16_t)input[0]) << 8;
+	g = ((uint16_t)input[1]) << 8;
+	b = ((uint16_t)input[2]) << 8;
+	RGB_TO_YUV16(y, u, v, r, g, b);
+	WRITE_YUV101010(y, u, v);
+}
+
+static inline void transfer_RGB888_to_VYU888(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v;
+
+	RGB_TO_YUV(y, u, v, input[0], input[1], input[2]);
+
+	*(*output)++ = v;
+	*(*output)++ = y;
+	*(*output)++ = u;
+}
+
+static inline void transfer_RGB888_to_UYVA8888(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v;
+
+	RGB_TO_YUV(y, u, v, input[0], input[1], input[2]);
+
+	*(*output)++ = u;
+	*(*output)++ = y;
+	*(*output)++ = v;
+	*(*output)++ = 0xff;
+}
+
+
+
+static inline void transfer_RGB888_to_YUVA8888(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v;
+
+	RGB_TO_YUV(y, u, v, input[0], input[1], input[2]);
+
+	*(*output)++ = y;
+	*(*output)++ = u;
+	*(*output)++ = v;
+	*(*output)++ = 255;
+}
+
+static inline void transfer_RGB888_to_YUV161616(uint16_t *(*output), unsigned char *input)
+{
+	int y, u, v, opacity, r, g, b;
+	
+	r = ((int)input[0] << 8) | input[0];
+	g = ((int)input[1] << 8) | input[1];
+	b = ((int)input[2] << 8) | input[2];
+
+	RGB_TO_YUV16(y, u, v, r, g, b);
+
+	*(*output)++ = y;
+	*(*output)++ = u;
+	*(*output)++ = v;
+}
+
+static inline void transfer_RGB888_to_YUVA16161616(uint16_t *(*output), unsigned char *input)
+{
+	int y, u, v, r, g, b;
+
+	r = (((int)input[0]) << 8) | input[0];
+	g = (((int)input[1]) << 8) | input[1];
+	b = (((int)input[2]) << 8) | input[2];
+	RGB_TO_YUV16(y, u, v, r, g, b);
+
+	*(*output)++ = y;
+	*(*output)++ = u;
+	*(*output)++ = v;
+	*(*output)++ = 0xffff;
+}
+
+static inline void transfer_RGB888_to_YUV420P_YUV422P(unsigned char *output_y, 
+	unsigned char *output_u, 
+	unsigned char *output_v, 
+	unsigned char *input,
+	int output_column)
+{
+	int y, u, v;
+
+	RGB_TO_YUV(y, u, v, input[0], input[1], input[2]);
+
+	output_y[output_column] = y;
+	output_u[output_column / 2] = u;
+	output_v[output_column / 2] = v;
+}
+
+static inline void transfer_RGB888_to_YUV444P(unsigned char *output_y, 
+	unsigned char *output_u, 
+	unsigned char *output_v, 
+	unsigned char *input,
+	int output_column)
+{
+	int y, u, v;
+
+	RGB_TO_YUV(y, u, v, input[0], input[1], input[2]);
+
+	output_y[output_column] = y;
+	output_u[output_column] = u;
+	output_v[output_column] = v;
+}
+
+static inline void transfer_RGB888_to_YUV422(unsigned char *(*output), 
+	unsigned char *input,
+	int j)
+{
+	int y, u, v;
+
+	RGB_TO_YUV(y, u, v, input[0], input[1], input[2]);
+
+	if(!(j & 1))
+	{ 
+// Store U and V for even pixels only
+		 (*output)[1] = u;
+		 (*output)[3] = v;
+		 (*output)[0] = y;
+	}
+	else
+	{ 
+// Store Y and advance output for odd pixels only
+		 (*output)[2] = y;
+		 (*output) += 4;
+	}
+
+}
+
+
+
+
+
+
+
+// *************************** RGBA8888 -> ************************************
+
+static inline void transfer_RGBA8888_to_TRANSPARENCY(unsigned char *(*output), unsigned char *input, int (*bit_counter))
+{
+	if((*bit_counter) == 7) *(*output) = 0;
+
+	if(input[3] < 127) 
+	{
+		*(*output) |= (unsigned char)1 << (7 - (*bit_counter));
+	}
+
+	if((*bit_counter) == 0)
+	{
+		(*output)++;
+		(*bit_counter) = 7;
+	}
+	else
+		(*bit_counter)--;
+}
+
+// These routines blend in a background color since they should be
+// exclusively used for widgets.
+
+static inline void transfer_RGBA8888_to_RGB8bg(unsigned char *(*output), unsigned char *input, int bg_r, int bg_g, int bg_b)
+{
+	unsigned int r, g, b, a, anti_a;
+	a = input[3];
+	anti_a = 255 - a;
+	r = ((unsigned int)input[0] * a + bg_r * anti_a) / 0xff;
+	g = ((unsigned int)input[1] * a + bg_g * anti_a) / 0xff;
+	b = ((unsigned int)input[2] * a + bg_b * anti_a) / 0xff;
+	*(*output) = (unsigned char)((r & 0xc0) + 
+				((g & 0xe0) >> 2) + 
+				((b & 0xe0) >> 5));
+	(*output)++;
+}
+
+static inline void transfer_RGBA8888_to_BGR565bg(unsigned char *(*output), unsigned char *input, int bg_r, int bg_g, int bg_b)
+{
+	unsigned int r, g, b, a, anti_a;
+	a = input[3];
+	anti_a = 255 - a;
+	r = ((unsigned int)input[0] * a + bg_r * anti_a) / 0xff;
+	g = ((unsigned int)input[1] * a + bg_g * anti_a) / 0xff;
+	b = ((unsigned int)input[2] * a + bg_b * anti_a) / 0xff;
+	*(uint16_t*)(*output) = (uint16_t)(((b & 0xf8) << 8) + 
+				((g & 0xfc) << 3) + 
+				((r & 0xf8) >> 3));
+	(*output) += 2;
+}
+
+static inline void transfer_RGBA8888_to_RGB565bg(unsigned char *(*output), unsigned char *input, int bg_r, int bg_g, int bg_b)
+{
+	unsigned int r, g, b, a, anti_a;
+	a = input[3];
+	anti_a = 255 - a;
+	r = ((unsigned int)input[0] * a + bg_r * anti_a) / 0xff;
+	g = ((unsigned int)input[1] * a + bg_g * anti_a) / 0xff;
+	b = ((unsigned int)input[2] * a + bg_b * anti_a) / 0xff;
+	*(uint16_t*)(*output) = (uint16_t)(((r & 0xf8) << 8)+ 
+				((g & 0xfc) << 3) + 
+				((b & 0xf8) >> 3));
+	(*output) += 2;
+}
+
+static inline void transfer_RGBA8888_to_BGR888bg(unsigned char *(*output), unsigned char *input, int bg_r, int bg_g, int bg_b)
+{
+	unsigned int r, g, b, a, anti_a;
+	a = input[3];
+	anti_a = 255 - a;
+	r = ((unsigned int)input[0] * a + bg_r * anti_a) / 0xff;
+	g = ((unsigned int)input[1] * a + bg_g * anti_a) / 0xff;
+	b = ((unsigned int)input[2] * a + bg_b * anti_a) / 0xff;
+	*(*output)++ = b;
+	*(*output)++ = g;
+	*(*output)++ = r;
+}
+
+static inline void transfer_RGBA8888_to_RGB888bg(unsigned char *(*output), unsigned char *input, int bg_r, int bg_g, int bg_b)
+{
+	unsigned int r, g, b, a, anti_a;
+	a = input[3];
+	anti_a = 255 - a;
+	r = ((unsigned int)input[0] * a + bg_r * anti_a) / 0xff;
+	g = ((unsigned int)input[1] * a + bg_g * anti_a) / 0xff;
+	b = ((unsigned int)input[2] * a + bg_b * anti_a) / 0xff;
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+}
+
+static inline void transfer_RGBA8888_to_BGR8888bg(unsigned char *(*output), unsigned char *input, int bg_r, int bg_g, int bg_b)
+{
+	unsigned int r, g, b, a, anti_a;
+	a = input[3];
+	anti_a = 255 - a;
+
+	r = ((unsigned int)input[0] * a + bg_r * anti_a) / 0xff;
+	g = ((unsigned int)input[1] * a + bg_g * anti_a) / 0xff;
+	b = ((unsigned int)input[2] * a + bg_b * anti_a) / 0xff;
+
+	*(*output)++ = b;
+	*(*output)++ = g;
+	*(*output)++ = r;
+	(*output)++;
+}
+
+
+
+
+
+
+
+// These routines blend in a black background
+
+static inline void transfer_RGBA8888_to_RGB8(unsigned char *(*output), unsigned char *input)
+{
+	unsigned int r, g, b, a;
+	a = input[3];
+	r = (unsigned int)input[0] * a;
+	g = (unsigned int)input[1] * a;
+	b = (unsigned int)input[2] * a;
+	*(*output) = (unsigned char)(((r & 0xc000) >> 8) + 
+				((g & 0xe000) >> 10) + 
+				((b & 0xe000) >> 13));
+	(*output)++;
+}
+
+static inline void transfer_RGBA8888_to_BGR565(unsigned char *(*output), unsigned char *input)
+{
+	unsigned int r, g, b, a;
+	a = input[3];
+	r = ((unsigned int)input[0] * a) / 0xff;
+	g = ((unsigned int)input[1] * a) / 0xff;
+	b = ((unsigned int)input[2] * a) / 0xff;
+	*(uint16_t*)(*output) = (uint16_t)(((b & 0xf8) << 8) + 
+				((g & 0xfc) << 3) + 
+				((r & 0xf8) >> 3));
+	(*output) += 2;
+}
+
+static inline void transfer_RGBA8888_to_RGB565(unsigned char *(*output), unsigned char *input)
+{
+	unsigned int r, g, b, a;
+	a = input[3];
+	r = ((unsigned int)input[0] * a) / 0xff;
+	g = ((unsigned int)input[1] * a) / 0xff;
+	b = ((unsigned int)input[2] * a) / 0xff;
+
+
+	*(uint16_t*)(*output) = (uint16_t)(((r & 0xf8) << 8) + 
+				((g & 0xfc) << 3) + 
+				((b & 0xf8) >> 3));
+	(*output) += 2;
+}
+
+static inline void transfer_RGBA8888_to_BGR888(unsigned char *(*output), unsigned char *input)
+{
+	unsigned int r, g, b, a;
+	a = input[3];
+	r = ((unsigned int)input[0] * a) / 0xff;
+	g = ((unsigned int)input[1] * a) / 0xff;
+	b = ((unsigned int)input[2] * a) / 0xff;
+	*(*output)++ = b;
+	*(*output)++ = g;
+	*(*output)++ = r;
+}
+
+static inline void transfer_RGBA8888_to_RGB888(unsigned char *(*output), unsigned char *input)
+{
+	unsigned int r, g, b, a;
+	a = input[3];
+	r = ((unsigned int)input[0] * a) / 0xff;
+	g = ((unsigned int)input[1] * a) / 0xff;
+	b = ((unsigned int)input[2] * a) / 0xff;
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+}
+
+static inline void transfer_RGBA8888_to_RGBA8888(unsigned char *(*output), unsigned char *input)
+{
+	(*output)[0] = input[0];
+	(*output)[1] = input[1];
+	(*output)[2] = input[2];
+	(*output)[3] = input[3];
+	(*output) += 4;
+}
+
+static inline void transfer_RGBA8888_to_ARGB8888(unsigned char *(*output), unsigned char *input)
+{
+	(*output)[0] = input[3];
+	(*output)[1] = input[0];
+	(*output)[2] = input[1];
+	(*output)[3] = input[2];
+	(*output) += 4;
+}
+
+static inline void transfer_RGBA8888_to_RGB161616(uint16_t *(*output), unsigned char *input)
+{
+	int y, u, v, opacity, r, g, b;
+	
+	opacity = input[3];
+	(*output)[0] = (((int)input[0] << 8) | input[0]) * opacity / 0xff;
+	(*output)[1] = (((int)input[1] << 8) | input[1]) * opacity / 0xff;
+	(*output)[2] = (((int)input[2] << 8) | input[2]) * opacity / 0xff;
+	(*output) += 3;
+}
+
+static inline void transfer_RGBA8888_to_RGBA16161616(uint16_t *(*output), unsigned char *input)
+{
+	int y, u, v, r, g, b;
+
+	(*output)[0] = (((int)input[0]) << 8) | input[0];
+	(*output)[1] = (((int)input[1]) << 8) | input[1];
+	(*output)[2] = (((int)input[2]) << 8) | input[2];
+	(*output)[3] = (((int)input[3]) << 8) | input[3];
+	(*output) += 4;
+}
+
+static inline void transfer_RGBA8888_to_RGB_FLOAT(float *(*output), unsigned char *input)
+{
+	float opacity = (float)input[3];
+	*(*output)++ = (float)*input++ * opacity / 0xff / 0xff;
+	*(*output)++ = (float)*input++ * opacity / 0xff / 0xff;
+	*(*output)++ = (float)*input * opacity / 0xff / 0xff;
+}
+
+static inline void transfer_RGBA8888_to_RGBA_FLOAT(float *(*output), unsigned char *input)
+{
+	*(*output)++ = (float)*input++ / 0xff;
+	*(*output)++ = (float)*input++ / 0xff;
+	*(*output)++ = (float)*input++ / 0xff;
+	*(*output)++ = (float)*input / 0xff;
+}
+
+static inline void transfer_RGBA8888_to_BGR8888(unsigned char *(*output), unsigned char *input)
+{
+	unsigned int r, g, b, a;
+	a = input[3];
+	r = ((unsigned int)input[0] * a) / 0xff;
+	g = ((unsigned int)input[1] * a) / 0xff;
+	b = ((unsigned int)input[2] * a) / 0xff;
+	*(*output)++ = b;
+	*(*output)++ = g;
+	*(*output)++ = r;
+	(*output)++;
+}
+
+static inline void transfer_RGBA8888_to_YUV888(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v, a, r, g, b;
+	
+	a = input[3];
+	r = (input[0] * a) / 0xff;
+	g = (input[1] * a) / 0xff;
+	b = (input[2] * a) / 0xff;
+
+	RGB_TO_YUV(y, u, v, input[0], input[1], input[2]);
+
+	*(*output)++ = y;
+	*(*output)++ = u;
+	*(*output)++ = v;
+}
+
+static inline void transfer_RGBA8888_to_YUVA8888(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v;
+
+	RGB_TO_YUV(y, u, v, input[0], input[1], input[2]);
+
+	*(*output)++ = y;
+	*(*output)++ = u;
+	*(*output)++ = v;
+	*(*output)++ = input[3];
+}
+
+static inline void transfer_RGBA8888_to_YUV161616(uint16_t *(*output), unsigned char *input)
+{
+	int y, u, v, opacity, r, g, b;
+	
+	opacity = input[3];
+	r = (((int)input[0] << 8) | input[0]) * opacity / 0xff;
+	g = (((int)input[1] << 8) | input[1]) * opacity / 0xff;
+	b = (((int)input[2] << 8) | input[2]) * opacity / 0xff;
+
+	RGB_TO_YUV16(y, u, v, r, g, b);
+
+	*(*output)++ = y;
+	*(*output)++ = u;
+	*(*output)++ = v;
+}
+
+static inline void transfer_RGBA8888_to_YUVA16161616(uint16_t *(*output), unsigned char *input)
+{
+	int y, u, v, r, g, b;
+
+	r = (((int)input[0]) << 8) | input[0];
+	g = (((int)input[1]) << 8) | input[1];
+	b = (((int)input[2]) << 8) | input[2];
+	RGB_TO_YUV16(y, u, v, r, g, b);
+
+	*(*output)++ = y;
+	*(*output)++ = u;
+	*(*output)++ = v;
+	*(*output)++ = (((int)input[3]) << 8) | input[3];
+}
+
+static inline void transfer_RGBA8888_to_YUV101010(unsigned char *(*output), unsigned char *input)
+{
+	int r, g, b;
+	int y, u, v;
+
+	r = ((uint16_t)input[0] * input[3]) + 0x1fe;
+	g = ((uint16_t)input[1] * input[3]) + 0x1fe;
+	b = ((uint16_t)input[2] * input[3]) + 0x1fe;
+	RGB_TO_YUV16(y, u, v, r, g, b);
+	WRITE_YUV101010(y, u, v);
+}
+
+static inline void transfer_RGBA8888_to_VYU888(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v, a, r, g, b;
+	
+	a = input[3];
+	r = ((input[0] * a) >> 8) + 1;
+	g = ((input[1] * a) >> 8) + 1;
+	b = ((input[2] * a) >> 8) + 1;
+
+	RGB_TO_YUV(y, u, v, input[0], input[1], input[2]);
+
+	*(*output)++ = v;
+	*(*output)++ = y;
+	*(*output)++ = u;
+}
+
+static inline void transfer_RGBA8888_to_UYVA8888(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v;
+
+	RGB_TO_YUV(y, u, v, input[0], input[1], input[2]);
+
+	*(*output)++ = u;
+	*(*output)++ = y;
+	*(*output)++ = v;
+	*(*output)++ = input[3];
+}
+
+static inline void transfer_RGBA888_to_YUV420P_YUV422P(unsigned char *output_y, 
+	unsigned char *output_u, 
+	unsigned char *output_v, 
+	unsigned char *input,
+	int output_column)
+{
+	int y, u, v, a, r, g, b;
+	
+	a = input[3];
+	r = (input[0] * a) / 0xff;
+	g = (input[1] * a) / 0xff;
+	b = (input[2] * a) / 0xff;
+
+	RGB_TO_YUV(y, u, v, r, g, b);
+
+	output_y[output_column] = y;
+	output_u[output_column / 2] = u;
+	output_v[output_column / 2] = v;
+}
+
+static inline void transfer_RGBA888_to_YUV444P(unsigned char *output_y, 
+	unsigned char *output_u, 
+	unsigned char *output_v, 
+	unsigned char *input,
+	int output_column)
+{
+	int y, u, v, a, r, g, b;
+	
+	a = input[3];
+	r = (input[0] * a) / 0xff;
+	g = (input[1] * a) / 0xff;
+	b = (input[2] * a) / 0xff;
+
+	RGB_TO_YUV(y, u, v, r, g, b);
+
+	output_y[output_column] = y;
+	output_u[output_column] = u;
+	output_v[output_column] = v;
+}
+
+static inline void transfer_RGBA888_to_YUV422(unsigned char *(*output), 
+	unsigned char *input,
+	int j)
+{
+	int y, u, v, a, r, g, b;
+	
+	a = input[3];
+	r = (input[0] * a) / 0xff;
+	g = (input[1] * a) / 0xff;
+	b = (input[2] * a) / 0xff;
+
+	RGB_TO_YUV(y, u, v, r, g, b);
+
+	if(!(j & 1))
+	{ 
+// Store U and V for even pixels only
+		 (*output)[1] = u;
+		 (*output)[3] = v;
+		 (*output)[0] = y;
+	}
+	else
+	{ 
+// Store Y and advance output for odd pixels only
+		 (*output)[2] = y;
+		 (*output) += 4;
+	}
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+// ******************************** RGB161616 -> *********************************
+
+static inline void transfer_RGB161616_to_RGB8(unsigned char *(*output), uint16_t *input)
+{
+	*(*output) = (unsigned char)(((input[0] & 0xc000) >> 8) +
+			    			 ((input[1] & 0xe000) >> 10) +
+		 	    			 ((input[2] & 0xe000) >> 13));
+	(*output)++;
+}
+
+static inline void transfer_RGB161616_to_BGR565(unsigned char *(*output), uint16_t *input)
+{
+	uint16_t r, g, b;
+	r = *input++;
+	g = *input++;
+	b = *input;
+	*(uint16_t*)(*output) = (b & 0xf800) |
+			 ((g & 0xfc00) >> 5) |
+			 ((r & 0xf800) >> 11);
+	(*output) += 2;
+}
+
+static inline void transfer_RGB161616_to_RGB565(unsigned char *(*output), uint16_t *input)
+{
+	uint16_t r, g, b;
+	r = *input++;
+	g = *input++;
+	b = *input;
+	*(uint16_t*)(*output) = (r & 0xf800) |
+			 ((g & 0xfc00) >> 5) |
+			 ((b & 0xf800) >> 11);
+	(*output) += 2;
+}
+
+static inline void transfer_RGB161616_to_BGR888(unsigned char *(*output), uint16_t *input)
+{
+	(*output)[0] = input[2] >> 8;
+	(*output)[1] = input[1] >> 8;
+	(*output)[2] = input[0] >> 8;
+	(*output) += 3;
+}
+
+static inline void transfer_RGB161616_to_RGB888(unsigned char *(*output), uint16_t *input)
+{
+	(*output)[0] = input[0] >> 8;
+	(*output)[1] = input[1] >> 8;
+	(*output)[2] = input[2] >> 8;
+	(*output) += 3;
+}
+
+static inline void transfer_RGB161616_to_RGBA8888(unsigned char *(*output), uint16_t *input)
+{
+	(*output)[0] = input[0] >> 8;
+	(*output)[1] = input[1] >> 8;
+	(*output)[2] = input[2] >> 8;
+	(*output)[3] = 0xff;
+	(*output) += 4;
+}
+
+static inline void transfer_RGB161616_to_BGR8888(unsigned char *(*output), uint16_t *input)
+{
+	(*output)[0] = input[2] >> 8;
+	(*output)[1] = input[1] >> 8;
+	(*output)[2] = input[0] >> 8;
+	(*output) += 4;
+}
+
+static inline void transfer_RGB161616_to_YUV888(unsigned char *(*output), uint16_t *input)
+{
+	int y, u, v, r, g, b;
+	r = input[0] >> 8;
+	g = input[1] >> 8;
+	b = input[2] >> 8;
+
+	RGB_TO_YUV(y, u, v, r, g, b);
+
+	(*output)[0] = y;
+	(*output)[1] = u;
+	(*output)[2] = v;
+	(*output) += 3;
+}
+
+static inline void transfer_RGB161616_to_YUVA8888(unsigned char *(*output), uint16_t *input)
+{
+	int y, u, v, r, g, b;
+
+	r = input[0] >> 8;
+	g = input[1] >> 8;
+	b = input[2] >> 8;
+
+	RGB_TO_YUV(y, u, v, r, g, b);
+
+	(*output)[0] = y;
+	(*output)[1] = u;
+	(*output)[2] = v;
+	(*output)[3] = 255;
+	(*output) += 4;
+}
+
+
+static inline void transfer_RGB161616_to_YUV101010(unsigned char *(*output), uint16_t *input)
+{
+	int r, g, b;
+	int y, u, v;
+
+	r = input[0];
+	g = input[1];
+	b = input[2];
+	RGB_TO_YUV16(y, u, v, r, g, b);
+	WRITE_YUV101010(y, u, v);
+}
+
+static inline void transfer_RGB161616_to_VYU888(unsigned char *(*output), uint16_t *input)
+{
+	int y, u, v, r, g, b;
+	r = input[0] >> 8;
+	g = input[1] >> 8;
+	b = input[2] >> 8;
+
+	RGB_TO_YUV(y, u, v, r, g, b);
+
+	(*output)[0] = v;
+	(*output)[1] = y;
+	(*output)[2] = u;
+	(*output) += 3;
+}
+
+static inline void transfer_RGB161616_to_UYVA8888(unsigned char *(*output), uint16_t *input)
+{
+	int y, u, v, r, g, b;
+
+	r = input[0] >> 8;
+	g = input[1] >> 8;
+	b = input[2] >> 8;
+
+	RGB_TO_YUV(y, u, v, r, g, b);
+
+	(*output)[0] = u;
+	(*output)[1] = y;
+	(*output)[2] = v;
+	(*output)[3] = 0xff;
+	(*output) += 4;
+}
+
+
+static inline void transfer_RGB161616_to_YUV420P_YUV422P(unsigned char *output_y, 
+	unsigned char *output_u, 
+	unsigned char *output_v, 
+	uint16_t *input,
+	int output_column)
+{
+	int y, u, v, r, g, b;
+	r = input[0] >> 8;
+	g = input[1] >> 8;
+	b = input[2] >> 8;
+
+	RGB_TO_YUV(y, u, v, r, g, b);
+
+	output_y[output_column] = y;
+	output_u[output_column / 2] = u;
+	output_v[output_column / 2] = v;
+}
+
+static inline void transfer_RGB161616_to_YUV444P(unsigned char *output_y, 
+	unsigned char *output_u, 
+	unsigned char *output_v, 
+	uint16_t *input,
+	int output_column)
+{
+	int y, u, v, r, g, b;
+	r = input[0] >> 8;
+	g = input[1] >> 8;
+	b = input[2] >> 8;
+
+	RGB_TO_YUV(y, u, v, r, g, b);
+
+	output_y[output_column] = y;
+	output_u[output_column] = u;
+	output_v[output_column] = v;
+}
+
+
+// ****************************** RGBA16161616 -> *****************************
+
+static inline void transfer_RGBA16161616_to_RGB8(unsigned char *(*output), uint16_t *input)
+{
+	unsigned int r, g, b, a;
+	a = (input)[3] >> 8;
+	r = (unsigned int)(input)[0] * a;
+	g = (unsigned int)(input)[1] * a;
+	b = (unsigned int)(input)[2] * a;
+
+	*(*output) = (unsigned char)(((r & 0xc00000) >> 16) + 
+				((g & 0xe00000) >> 18) + 
+				((b & 0xe00000) >> 21));
+	(*output)++;
+}
+
+static inline void transfer_RGBA16161616_to_BGR565(unsigned char *(*output), uint16_t *input)
+{
+	unsigned int r, g, b, a;
+	a = (input)[3] >> 8;
+	r = (unsigned int)(input)[0] * a;
+	g = (unsigned int)(input)[1] * a;
+	b = (unsigned int)(input)[2] * a;
+
+	*(uint16_t*)(*output) = (uint16_t)(((b & 0xf80000) >> 8) + 
+				((g & 0xfc0000) >> 13) + 
+				((r & 0xf80000) >> 19));
+	(*output) += 2;
+}
+
+static inline void transfer_RGBA16161616_to_RGB565(unsigned char *(*output), uint16_t *input)
+{
+	unsigned int r, g, b, a;
+	a = (input)[3] >> 8;
+	r = (unsigned int)(input)[0] * a;
+	g = (unsigned int)(input)[1] * a;
+	b = (unsigned int)(input)[2] * a;
+
+	*(uint16_t*)(*output) = (uint16_t)(((r & 0xf80000) >> 8) + 
+				((g & 0xfc0000) >> 13) + 
+				((b & 0xf80000) >> 19));
+	(*output) += 2;
+}
+
+static inline void transfer_RGBA16161616_to_BGR888(unsigned char *(*output), uint16_t *input)
+{
+	uint32_t r, g, b, a;
+	a = input[3];
+	r = (uint32_t)(input)[0] * a;
+	g = (uint32_t)(input)[1] * a;
+	b = (uint32_t)(input)[2] * a;
+
+// For display only
+	(*output)[0] = (unsigned char)(b >> 24);
+	(*output)[1] = (unsigned char)(g >> 24);
+	(*output)[2] = (unsigned char)(r >> 24);
+	(*output) += 3;
+}
+
+static inline void transfer_RGBA16161616_to_RGB888(unsigned char *(*output), uint16_t *input)
+{
+	uint32_t r, g, b, a;
+	a = input[3];
+	r = (unsigned int)(input)[0] * a;
+	g = (unsigned int)(input)[1] * a;
+	b = (unsigned int)(input)[2] * a;
+
+	(*output)[0] = (unsigned char)(r / 0xffffff);
+	(*output)[1] = (unsigned char)(g / 0xffffff);
+	(*output)[2] = (unsigned char)(b / 0xffffff);
+	(*output) += 3;
+}
+
+
+static inline void transfer_RGBA16161616_to_RGBA8888(unsigned char *(*output), unsigned char *input)
+{
+	(*output)[0] = input[0] >> 8;
+	(*output)[1] = input[1] >> 8;
+	(*output)[2] = input[2] >> 8;
+	(*output)[3] = input[3] >> 8;
+	(*output) += 4;
+}
+
+
+static inline void transfer_RGBA16161616_to_BGR8888(unsigned char *(*output), uint16_t *input)
+{
+	uint32_t r, g, b, a;
+	a = input[3];
+	r = (input)[0] * a;
+	g = (input)[1] * a;
+	b = (input)[2] * a;
+
+// For display only
+	(*output)[0] = (unsigned char)(b >> 24);
+	(*output)[1] = (unsigned char)(g >> 24);
+	(*output)[2] = (unsigned char)(r >> 24);
+	(*output) += 4;
+}
+
+static inline void transfer_RGBA16161616_to_YUV101010(unsigned char *(*output), uint16_t *input)
+{
+	uint32_t r, g, b, a, y, u, v;
+
+	a = input[3];
+	r = (uint32_t)input[0] * a / 0xffff;
+	g = (uint32_t)input[1] * a / 0xffff;
+	b = (uint32_t)input[2] * a / 0xffff;
+	RGB_TO_YUV16(y, u, v, r, g, b);
+	WRITE_YUV101010(y, u, v);
+}
+
+
+static inline void transfer_RGBA16161616_to_YUV420P_YUV422P(unsigned char *output_y, 
+	unsigned char *output_u, 
+	unsigned char *output_v, 
+	uint16_t *input,
+	int output_column)
+{
+	uint32_t y, u, v, r, g, b, a;
+	a = input[3];
+	r = (int32_t)input[0] * a / 0xffffff;
+	g = (int32_t)input[1] * a / 0xffffff;
+	b = (int32_t)input[2] * a / 0xffffff;
+
+	RGB_TO_YUV(y, u, v, r, g, b);
+
+	output_y[output_column] = y;
+	output_u[output_column / 2] = u;
+	output_v[output_column / 2] = v;
+}
+
+static inline void transfer_RGBA16161616_to_YUV444P(unsigned char *output_y, 
+	unsigned char *output_u, 
+	unsigned char *output_v, 
+	uint16_t *input,
+	int output_column)
+{
+	uint32_t y, u, v, r, g, b, a;
+	a = input[3];
+	r = (int32_t)input[0] * a / 0xffffff;
+	g = (int32_t)input[1] * a / 0xffffff;
+	b = (int32_t)input[2] * a / 0xffffff;
+
+	RGB_TO_YUV(y, u, v, r, g, b);
+
+	output_y[output_column] = y;
+	output_u[output_column] = u;
+	output_v[output_column] = v;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// ********************************** screen capture *****************************
+
+static inline void transfer_BGR8888_to_RGB888(unsigned char *(*output), unsigned char *input)
+{
+	*(*output)++ = input[2];
+	*(*output)++ = input[1];
+	*(*output)++ = input[0];
+}
+
+static inline void transfer_BGR8888_to_BGR8888(unsigned char *(*output), unsigned char *input)
+{
+	*(*output)++ = input[0];
+	*(*output)++ = input[1];
+	*(*output)++ = input[2];
+	(*output)++;
+}
+
+static inline void transfer_BGR888_to_RGB888(unsigned char *(*output), unsigned char *input)
+{
+	*(*output)++ = input[2];
+	*(*output)++ = input[1];
+	*(*output)++ = input[0];
+}
+
+
+
+
+
+
+
+// ******************************** YUV888 -> *********************************
+
+
+static inline void transfer_YUV888_to_RGB8(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = (input[0] << 16) | (input[0] << 8) | input[0];
+	u = input[1];
+	v = input[2];
+	YUV_TO_RGB(y, u, v, r, g, b);
+
+	*(*output) = (unsigned char)((r & 0xc0) +
+			    			 ((g & 0xe0) >> 2) +
+		 	    			 ((b & 0xe0) >> 5));
+	(*output)++;
+}
+
+static inline void transfer_YUV888_to_BGR565(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = (input[0] << 16) | (input[0] << 8) | input[0];
+	u = input[1];
+	v = input[2];
+	YUV_TO_RGB(y, u, v, r, g, b);
+	*(uint16_t*)(*output) = ((b & 0xf8) << 8)
+			 + ((g & 0xfc) << 3)
+			 + ((r & 0xf8) >> 3);
+	(*output) += 2;
+}
+
+static inline void transfer_YUV888_to_RGB565(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = (input[0] << 16) | (input[0] << 8) | input[0];
+	u = input[1];
+	v = input[2];
+	YUV_TO_RGB(y, u, v, r, g, b);
+	*(uint16_t*)(*output) = ((r & 0xf8) << 8)
+			 + ((g & 0xfc) << 3)
+			 + ((b & 0xf8) >> 3);
+	(*output) += 2;
+}
+
+static inline void transfer_YUV888_to_BGR888(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = (input[0] << 16) | (input[0] << 8) | input[0];
+	u = input[1];
+	v = input[2];
+	YUV_TO_RGB(y, u, v, r, g, b);
+
+	*(*output)++ = b;
+	*(*output)++ = g;
+	*(*output)++ = r;
+}
+
+static inline void transfer_YUV888_to_BGR8888(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v;
+	int r, g, b;
+
+	y = (input[0] << 16) | (input[0] << 8) | input[0];
+	u = input[1];
+	v = input[2];
+	YUV_TO_RGB(y, u, v, r, g, b);
+	*(*output)++ = b;
+	*(*output)++ = g;
+	*(*output)++ = r;
+	(*output)++;
+}
+
+static inline void transfer_YUV888_to_RGB888(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = (input[0] << 16) | (input[0] << 8) | input[0];
+	u = (int)input[1];
+	v = (int)input[2];
+	YUV_TO_RGB(y, u, v, r, g, b);
+
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+}
+
+static inline void transfer_YUV888_to_RGBA8888(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v;
+	int r, g, b;
+
+	y = (input[0] << 16) | (input[0] << 8) | input[0];
+	u = input[1];
+	v = input[2];
+	YUV_TO_RGB(y, u, v, r, g, b);
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+	*(*output)++ = 0xff;
+}
+
+static inline void transfer_YUV888_to_ARGB8888(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v;
+	int r, g, b;
+
+	y = (input[0] << 16) | (input[0] << 8) | input[0];
+	u = input[1];
+	v = input[2];
+	YUV_TO_RGB(y, u, v, r, g, b);
+	*(*output)++ = 0xff;
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+}
+
+static inline void transfer_YUV888_to_RGB_FLOAT(float *(*output), unsigned char *input)
+{
+	float y = (float)input[0] / 0xff;
+	int u = input[1];
+	int v = input[2];
+	float r, g, b;
+	
+	YUV_TO_FLOAT(y, u, v, r, g, b);
+
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+}
+
+static inline void transfer_YUV888_to_RGBA_FLOAT(float *(*output), unsigned char *input)
+{
+	float y = (float)input[0] / 0xff;
+	int u = input[1];
+	int v = input[2];
+	float r, g, b;
+	
+	YUV_TO_FLOAT(y, u, v, r, g, b);
+
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+	*(*output)++ = 1.0;
+}
+
+static inline void transfer_YUV888_to_YUVA8888(unsigned char *(*output), unsigned char *input)
+{
+	*(*output)++ = (int)input[0];
+	*(*output)++ = input[1];
+	*(*output)++ = input[2];
+	*(*output)++ = 0xff;
+}
+
+static inline void transfer_YUV888_to_YUV888(unsigned char *(*output), unsigned char *input)
+{
+	(*output)[0] = (int)input[0];
+	(*output)[1] = input[1];
+	(*output)[2] = input[2];
+	(*output) += 3;
+}
+
+
+static inline void transfer_YUV888_to_VYU888(unsigned char *(*output), unsigned char *input)
+{
+	(*output)[0] = input[2];
+	(*output)[1] = input[0];
+	(*output)[2] = input[1];
+	(*output) += 3;
+}
+
+
+static inline void transfer_YUV888_to_UYVA8888(unsigned char *(*output), unsigned char *input)
+{
+	(*output)[0] = input[1];
+	(*output)[1] = input[0];
+	(*output)[2] = input[2];
+	(*output)[3] = 0xff;
+	(*output) += 4;
+}
+
+
+static inline void transfer_YUV888_to_YUV101010(unsigned char *(*output), unsigned char *input)
+{
+	uint16_t y_i = ((uint16_t)input[0]) << 8;
+	uint16_t u_i = ((uint16_t)input[1]) << 8;
+	uint16_t v_i = ((uint16_t)input[2]) << 8;
+	WRITE_YUV101010(y_i, u_i, v_i);
+}
+
+static inline void transfer_YUV888_to_YUV420P_YUV422P(unsigned char *output_y, 
+	unsigned char *output_u, 
+	unsigned char *output_v, 
+	unsigned char *input,
+	int output_column)
+{
+	output_y[output_column] = input[0];
+	output_u[output_column / 2] = input[1];
+	output_v[output_column / 2] = input[2];
+}
+
+static inline void transfer_YUV888_to_YUV444P(unsigned char *output_y, 
+	unsigned char *output_u, 
+	unsigned char *output_v, 
+	unsigned char *input,
+	int output_column)
+{
+	output_y[output_column] = input[0];
+	output_u[output_column] = input[1];
+	output_v[output_column] = input[2];
+}
+
+static inline void transfer_YUV888_to_YUV422(unsigned char *(*output), 
+	unsigned char *input,
+	int j)
+{
+// Store U and V for even pixels only
+	if(!(j & 1))
+	{
+		(*output)[1] = input[1];
+		(*output)[3] = input[2];
+		(*output)[0] = input[0];
+	}
+	else
+// Store Y and advance output for odd pixels only
+	{
+		(*output)[2] = input[0];
+		(*output) += 4;
+	}
+}
+
+
+
+
+
+
+// ******************************** YUVA8888 -> *******************************
+
+
+
+
+static inline void transfer_YUVA8888_to_RGB8(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v, a;
+	int r, g, b;
+	
+	a = input[3];
+	y = (input[0] << 16) | (input[0] << 8) | input[0];
+	u = input[1];
+	v = input[2];
+	YUV_TO_RGB(y, u, v, r, g, b);
+	
+	r *= a;
+	g *= a;
+	b *= a;
+
+	*(*output) = (unsigned char)(((r & 0xc000) >> 8) + 
+				((g & 0xe000) >> 10) + 
+				((b & 0xe000) >> 13));
+	(*output)++;
+}
+
+static inline void transfer_YUVA8888_to_BGR565(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v, a;
+	int r, g, b;
+	
+	a = input[3];
+	y = (input[0] << 16) | (input[0] << 8) | input[0];
+	u = input[1];
+	v = input[2];
+	YUV_TO_RGB(y, u, v, r, g, b);
+		
+	r *= a;
+	g *= a;
+	b *= a;
+
+	*(uint16_t*)(*output) = (uint16_t)((b & 0xf800) + 
+				((g & 0xfc00) >> 5) + 
+				((r & 0xf800) >> 11));
+	(*output) += 2;
+}
+
+static inline void transfer_YUVA8888_to_RGB565(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v, a;
+	int r, g, b;
+	
+	a = input[3];
+	y = (input[0] << 16) | (input[0] << 8) | input[0];
+	u = input[1];
+	v = input[2];
+	YUV_TO_RGB(y, u, v, r, g, b);
+		
+	r *= a;
+	g *= a;
+	b *= a;
+
+	*(uint16_t*)(*output) = (uint16_t)((r & 0xf800) + 
+				((g & 0xfc00) >> 5) + 
+				((b & 0xf800) >> 11));
+	(*output) += 2;
+}
+
+static inline void transfer_YUVA8888_to_BGR888(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v, a;
+	int r, g, b;
+	
+	a = input[3];
+	y = (input[0] << 16) | (input[0] << 8) | input[0];
+	u = input[1];
+	v = input[2];
+
+	YUV_TO_RGB(y, u, v, r, g, b);
+		
+	r *= a;
+	g *= a;
+	b *= a;
+
+	*(*output)++ = b / 0xff;
+	*(*output)++ = g / 0xff;
+	*(*output)++ = r / 0xff;
+}
+
+
+static inline void transfer_YUVA8888_to_BGR8888(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v, a;
+	int r, g, b;
+
+	a = input[3];
+	y = (input[0] << 16) | (input[0] << 8) | input[0];
+	u = input[1];
+	v = input[2];
+
+	YUV_TO_RGB(y, u, v, r, g, b);
+	
+	r *= a;
+	g *= a;
+	b *= a;
+	*(*output)++ = b / 0xff;
+	*(*output)++ = g / 0xff;
+	*(*output)++ = r / 0xff;
+	(*output)++;
+}
+
+static inline void transfer_YUVA8888_to_RGB888(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v, a;
+	int r, g, b;
+	
+	a = input[3];
+	y = (input[0] << 16) | (input[0] << 8) | input[0];
+	u = input[1];
+	v = input[2];
+
+	YUV_TO_RGB(y, u, v, r, g, b);
+		
+	r *= a;
+	g *= a;
+	b *= a;
+
+	*(*output)++ = r / 0xff;
+	*(*output)++ = g / 0xff;
+	*(*output)++ = b / 0xff;
+}
+
+static inline void transfer_YUVA8888_to_RGBA8888(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v, a;
+	int r, g, b;
+
+	a = input[3];
+	y = (input[0] << 16) | (input[0] << 8) | input[0];
+	u = input[1];
+	v = input[2];
+
+	YUV_TO_RGB(y, u, v, r, g, b);
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+	*(*output)++ = a;
+}
+
+static inline void transfer_YUVA8888_to_ARGB8888(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v, a;
+	int r, g, b;
+
+	a = input[3];
+	y = (input[0] << 16) | (input[0] << 8) | input[0];
+	u = input[1];
+	v = input[2];
+
+	YUV_TO_RGB(y, u, v, r, g, b);
+	*(*output)++ = a;
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+}
+
+static inline void transfer_YUVA8888_to_RGB_FLOAT(float *(*output), unsigned char *input)
+{
+	float y, a;
+	int u, v;
+	float r, g, b;
+
+	a = (float)input[3] / 0xff;
+	y = (float)input[0] / 0xff;
+	u = input[1];
+	v = input[2];
+
+	YUV_TO_FLOAT(y, u, v, r, g, b);
+		
+	r *= a;
+	g *= a;
+	b *= a;
+
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+}
+
+static inline void transfer_YUVA8888_to_RGBA_FLOAT(float *(*output), unsigned char *input)
+{
+	float y = (float)input[0] / 0xff;
+	int u, v;
+	float r, g, b, a;
+
+	a = (float)input[3] / 0xff;
+	u = input[1];
+	v = input[2];
+
+	YUV_TO_FLOAT(y, u, v, r, g, b);
+
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+	*(*output)++ = a;
+}
+
+
+static inline void transfer_YUVA8888_to_VYU888(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v, a, anti_a;
+	a = input[3];
+	anti_a = 0xff - a;
+	y = ((uint32_t)input[0] * a) / 0xff;
+	u = ((uint32_t)input[1] * a + 0x80 * anti_a) / 0xff;
+	v = ((uint32_t)input[2] * a + 0x80 * anti_a) / 0xff;
+	
+	*(*output)++ = v;
+	*(*output)++ = y;
+	*(*output)++ = u;
+}
+
+static inline void transfer_YUVA8888_to_YUV888(unsigned char *(*output), unsigned char *input)
+{
+	int y, u, v, a, anti_a;
+	a = input[3];
+	anti_a = 0xff - a;
+	y = ((uint32_t)input[0] * a) / 0xff;
+	u = ((uint32_t)input[1] * a + 0x80 * anti_a) / 0xff;
+	v = ((uint32_t)input[2] * a + 0x80 * anti_a) / 0xff;
+	
+	*(*output)++ = y;
+	*(*output)++ = u;
+	*(*output)++ = v;
+}
+
+
+static inline void transfer_YUVA8888_to_YUVA8888(unsigned char *(*output), unsigned char *input)
+{
+	*(*output)++ = input[0];
+	*(*output)++ = input[1];
+	*(*output)++ = input[2];
+	*(*output)++ = input[3];
+}
+
+static inline void transfer_YUVA8888_to_UYVA8888(unsigned char *(*output), unsigned char *input)
+{
+	*(*output)++ = input[1];
+	*(*output)++ = input[0];
+	*(*output)++ = input[2];
+	*(*output)++ = input[3];
+}
+
+static inline void transfer_YUVA8888_to_YUV101010(unsigned char *(*output), unsigned char *input)
+{
+	uint16_t y_i = ((uint16_t)input[0] * input[3]) + 0x1fe;
+	uint16_t u_i = ((uint16_t)input[1] * input[3]) + 0x1fe;
+	uint16_t v_i = ((uint16_t)input[2] * input[3]) + 0x1fe;
+	WRITE_YUV101010(y_i, u_i, v_i);
+}
+
+
+static inline void transfer_YUVA8888_to_YUV420P_YUV422P(unsigned char *output_y, 
+	unsigned char *output_u, 
+	unsigned char *output_v, 
+	unsigned char *input,
+	int output_column)
+{
+	int opacity = input[3];
+	int transparency = 0xff - opacity;
+
+	output_y[output_column] =     ((input[0] * opacity) >> 8) + 1;
+	output_u[output_column / 2] = ((input[1] * opacity + 0x80 * transparency) >> 8) + 1;
+	output_v[output_column / 2] = ((input[2] * opacity + 0x80 * transparency) >> 8) + 1;
+}
+
+static inline void transfer_YUVA8888_to_YUV444P(unsigned char *output_y, 
+	unsigned char *output_u, 
+	unsigned char *output_v, 
+	unsigned char *input,
+	int output_column)
+{
+	int opacity = input[3];
+	int transparency = 0xff - opacity;
+
+	output_y[output_column] =     ((input[0] * opacity) >> 8) + 1;
+	output_u[output_column] = ((input[1] * opacity + 0x80 * transparency) >> 8) + 1;
+	output_v[output_column] = ((input[2] * opacity + 0x80 * transparency) >> 8) + 1;
+}
+
+static inline void transfer_YUVA8888_to_YUV422(unsigned char *(*output), 
+	unsigned char *input,
+	int j)
+{
+	int opacity = input[3];
+	int transparency = 0xff - opacity;
+// Store U and V for even pixels only
+	if(!(j & 1))
+	{
+		(*output)[0] = ((input[0] * opacity) >> 8) + 1;
+		(*output)[1] = ((input[1] * opacity + 0x80 * transparency) >> 8) + 1;
+		(*output)[3] = ((input[2] * opacity + 0x80 * transparency) >> 8) + 1;
+	}
+	else
+// Store Y and advance output for odd pixels only
+	{
+		(*output)[2] = ((input[0] * opacity) >> 8) + 1;
+		(*output) += 4;
+	}
+}
+
+
+
+
+
+
+
+
+
+
+// ******************************** YUV161616 -> ******************************
+
+
+static inline void transfer_YUV161616_to_RGB8(unsigned char *(*output), uint16_t *input)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = (((int)input[0]) << 8) | (input[0] >> 8);
+	u = input[1] >> 8;
+	v = input[2] >> 8;
+	YUV_TO_RGB(y, u, v, r, g, b);
+
+	*(*output) = (unsigned char)((r & 0xc0) +
+			    			 ((g & 0xe0) >> 2) +
+		 	    			 ((b & 0xe0) >> 5));
+	(*output)++;
+}
+
+static inline void transfer_YUV161616_to_BGR565(unsigned char *(*output), uint16_t *input)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = (((int)input[0]) << 8) | (input[0] >> 8);
+	u = input[1] >> 8;
+	v = input[2] >> 8;
+	YUV_TO_RGB(y, u, v, r, g, b);
+	*(uint16_t*)(*output) = ((b & 0xf8) << 8)
+			 + ((g & 0xfc) << 3)
+			 + ((r & 0xf8) >> 3);
+	(*output) += 2;
+}
+
+static inline void transfer_YUV161616_to_RGB565(unsigned char *(*output), uint16_t *input)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = (((int)input[0]) << 8) | (input[0] >> 8);
+	u = input[1] >> 8;
+	v = input[2] >> 8;
+	YUV_TO_RGB(y, u, v, r, g, b);
+	*(uint16_t*)(*output) = ((r & 0xf8) << 8)
+			 + ((g & 0xfc) << 3)
+			 + ((b & 0xf8) >> 3);
+	(*output) += 2;
+}
+
+static inline void transfer_YUV161616_to_BGR888(unsigned char *(*output), uint16_t *input)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = (((int)input[0]) << 8) | (input[0] >> 8);
+	u = input[1];
+	v = input[2];
+	YUV_TO_RGB16(y, u, v, r, g, b);
+
+	*(*output)++ = b >> 8;
+	*(*output)++ = g >> 8;
+	*(*output)++ = r >> 8;
+}
+
+static inline void transfer_YUV161616_to_RGB888(unsigned char *(*output), uint16_t *input)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = (((int)input[0]) << 8) | (input[0] >> 8);
+	u = input[1];
+	v = input[2];
+	YUV_TO_RGB16(y, u, v, r, g, b);
+
+	*(*output)++ = r >> 8;
+	*(*output)++ = g >> 8;
+	*(*output)++ = b >> 8;
+}
+
+static inline void transfer_YUV161616_to_RGBA8888(unsigned char *(*output), uint16_t *input)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = (((int)input[0]) << 8) | (input[0] >> 8);
+	u = input[1];
+	v = input[2];
+	YUV_TO_RGB16(y, u, v, r, g, b);
+
+	*(*output)++ = r >> 8;
+	*(*output)++ = g >> 8;
+	*(*output)++ = b >> 8;
+	*(*output)++ = 0xff;
+}
+
+static inline void transfer_YUV161616_to_ARGB8888(unsigned char *(*output), uint16_t *input)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = (((int)input[0]) << 8) | (input[0] >> 8);
+	u = input[1];
+	v = input[2];
+	YUV_TO_RGB16(y, u, v, r, g, b);
+
+	*(*output)++ = 0xff;
+	*(*output)++ = r >> 8;
+	*(*output)++ = g >> 8;
+	*(*output)++ = b >> 8;
+}
+
+static inline void transfer_YUV161616_to_RGB_FLOAT(float *(*output), uint16_t *input)
+{
+	float y = (float)input[0] / 0xffff;
+	int u, v;
+	float r, g, b;
+	
+	u = input[1];
+	v = input[2];
+	YUV16_TO_RGB_FLOAT(y, u, v, r, g, b);
+
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+}
+
+static inline void transfer_YUV161616_to_RGBA_FLOAT(float *(*output), uint16_t *input)
+{
+	float y = (float)input[0] / 0xffff;
+	int u, v;
+	float r, g, b;
+	
+	u = input[1];
+	v = input[2];
+	YUV16_TO_RGB_FLOAT(y, u, v, r, g, b);
+
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+	*(*output)++ = 1.0;
+}
+
+static inline void transfer_YUV161616_to_BGR8888(unsigned char *(*output), uint16_t *input)
+{
+	int y, u, v;
+	int r, g, b;
+
+	y = (((int)input[0]) << 8) | (input[0] >> 8);
+	u = input[1] >> 8;
+	v = input[2] >> 8;
+	YUV_TO_RGB(y, u, v, r, g, b);
+	*(*output)++ = b;
+	*(*output)++ = g;
+	*(*output)++ = r;
+	(*output)++;
+}
+
+static inline void transfer_YUV161616_to_YUV161616(uint16_t *(*output), uint16_t *input)
+{
+	(*output)[0] = input[0];
+	(*output)[1] = input[1];
+	(*output)[2] = input[2];
+	(*output) += 3;
+}
+
+static inline void transfer_YUV161616_to_YUVA8888(unsigned char *(*output), uint16_t *input)
+{
+	(*output)[0] = input[0] >> 8;
+	(*output)[1] = input[1] >> 8;
+	(*output)[2] = input[2] >> 8;
+	(*output)[3] = 255;
+	(*output) += 4;
+}
+
+
+static inline void transfer_YUV161616_to_VYU888(unsigned char *(*output), uint16_t *input)
+{
+	(*output)[0] = input[2] >> 8;
+	(*output)[1] = input[0] >> 8;
+	(*output)[2] = input[1] >> 8;
+	(*output) += 3;
+}
+
+
+static inline void transfer_YUV161616_to_UYVA8888(unsigned char *(*output), uint16_t *input)
+{
+	(*output)[0] = input[1] >> 8;
+	(*output)[1] = input[0] >> 8;
+	(*output)[2] = input[2] >> 8;
+	(*output)[3] = input[3] >> 8;
+	(*output) += 4;
+}
+
+static inline void transfer_YUV161616_to_YUV101010(unsigned char *(*output), uint16_t *input)
+{
+	uint16_t y_i = input[0];
+	uint16_t u_i = input[1];
+	uint16_t v_i = input[2];
+	WRITE_YUV101010(y_i, u_i, v_i);
+}
+
+static inline void transfer_YUV161616_to_YUV420P_YUV422P(unsigned char *output_y, 
+	unsigned char *output_u, 
+	unsigned char *output_v, 
+	uint16_t *input,
+	int output_column)
+{
+	output_y[output_column] = input[0] >> 8;
+	output_u[output_column / 2] = input[1] >> 8;
+	output_v[output_column / 2] = input[2] >> 8;
+}
+
+static inline void transfer_YUV161616_to_YUV444P(unsigned char *output_y, 
+	unsigned char *output_u, 
+	unsigned char *output_v, 
+	uint16_t *input,
+	int output_column)
+{
+	output_y[output_column] = input[0] >> 8;
+	output_u[output_column] = input[1] >> 8;
+	output_v[output_column] = input[2] >> 8;
+}
+
+static inline void transfer_YUV161616_to_YUV422(unsigned char *(*output), 
+	uint16_t *input,
+	int j)
+{
+// Store U and V for even pixels only
+	if(!(j & 1))
+	{
+		(*output)[1] = input[1] >> 8;
+		(*output)[3] = input[2] >> 8;
+		(*output)[0] = input[0] >> 8;
+	}
+	else
+// Store Y and advance output for odd pixels only
+	{
+		(*output)[2] = input[0] >> 8;
+		(*output) += 4;
+	}
+}
+
+
+
+
+
+
+
+
+
+
+
+// ******************************** YUVA16161616 -> ***************************
+
+
+
+
+static inline void transfer_YUVA16161616_to_RGB8(unsigned char *(*output), uint16_t *input)
+{
+	int y, u, v, a;
+	int r, g, b;
+	
+	a = input[3];
+	y = (((int)input[0]) << 8) | (input[0] >> 8);
+	u = input[1] >> 8;
+	v = input[2] >> 8;
+	YUV_TO_RGB(y, u, v, r, g, b);
+	
+	r *= a;
+	g *= a;
+	b *= a;
+
+	*(*output) = (unsigned char)(((r & 0xc000) >> 8) + 
+				((g & 0xe000) >> 10) + 
+				((b & 0xe000) >> 13));
+	(*output)++;
+}
+
+static inline void transfer_YUVA16161616_to_BGR565(unsigned char *(*output), uint16_t *input)
+{
+	int y, u, v, a;
+	int r, g, b;
+	
+	a = input[3] >> 8;
+	y = (((int)input[0]) << 8) | (input[0] >> 8);
+	u = input[1] >> 8;
+	v = input[2] >> 8;
+	YUV_TO_RGB(y, u, v, r, g, b);
+		
+	r *= a;
+	g *= a;
+	b *= a;
+
+	*(uint16_t*)(*output) = (uint16_t)((b & 0xf800) + 
+				((g & 0xfc00) >> 5) + 
+				((r & 0xf800) >> 11));
+	(*output) += 2;
+}
+
+static inline void transfer_YUVA16161616_to_RGB565(unsigned char *(*output), uint16_t *input)
+{
+	int y, u, v, a;
+	int r, g, b;
+	
+	a = input[3] >> 8;
+	y = (((int)input[0]) << 8) | (input[0] >> 8);
+	u = input[1] >> 8;
+	v = input[2] >> 8;
+	YUV_TO_RGB(y, u, v, r, g, b);
+		
+	r *= a;
+	g *= a;
+	b *= a;
+
+	*(uint16_t*)(*output) = (uint16_t)((r & 0xf800) + 
+				((g & 0xfc00) >> 5) + 
+				((b & 0xf800) >> 11));
+	(*output) += 2;
+}
+
+static inline void transfer_YUVA16161616_to_BGR888(unsigned char *(*output), uint16_t *input)
+{
+	int y, u, v, a;
+	int r, g, b;
+	
+	a = input[3];
+	y = (((int)input[0]) << 8) | (input[0] >> 8);
+	u = input[1];
+	v = input[2];
+
+	YUV_TO_RGB16(y, u, v, r, g, b);
+		
+	r *= a;
+	g *= a;
+	b *= a;
+
+	*(*output)++ = b / 0xffff00;
+	*(*output)++ = g / 0xffff00;
+	*(*output)++ = r / 0xffff00;
+}
+
+static inline void transfer_YUVA16161616_to_RGB888(unsigned char *(*output), uint16_t *input)
+{
+	unsigned int y, u, v, a;
+	unsigned int r, g, b;
+
+	a = input[3];
+	y = (((int)input[0]) << 8) | (input[0] >> 8);
+	u = input[1];
+	v = input[2];
+
+	YUV_TO_RGB16(y, u, v, r, g, b);
+	
+	r *= a;
+	g *= a;
+	b *= a;
+	r /= 0xffff00;
+	g /= 0xffff00;
+	b /= 0xffff00;
+
+	CLAMP(r, 0, 0xff);
+	CLAMP(g, 0, 0xff);
+	CLAMP(b, 0, 0xff);
+
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+}
+
+static inline void transfer_YUVA16161616_to_RGBA8888(unsigned char *(*output), uint16_t *input)
+{
+	unsigned int y, u, v;
+	unsigned int r, g, b;
+	
+	y = (((int)input[0]) << 8) | (input[0] >> 8);
+	u = input[1];
+	v = input[2];
+
+	YUV_TO_RGB16(y, u, v, r, g, b);
+
+	*(*output)++ = (r >> 8);
+	*(*output)++ = (g >> 8);
+	*(*output)++ = (b >> 8);
+	*(*output)++ = input[3] >> 8;
+}
+
+static inline void transfer_YUVA16161616_to_ARGB8888(unsigned char *(*output), uint16_t *input)
+{
+	unsigned int y, u, v;
+	unsigned int r, g, b;
+	
+	y = (((int)input[0]) << 8) | (input[0] >> 8);
+	u = input[1];
+	v = input[2];
+
+	YUV_TO_RGB16(y, u, v, r, g, b);
+
+	*(*output)++ = input[3] >> 8;
+	*(*output)++ = (r >> 8);
+	*(*output)++ = (g >> 8);
+	*(*output)++ = (b >> 8);
+}
+
+static inline void transfer_YUVA16161616_to_RGB_FLOAT(float *(*output), 
+	uint16_t *input)
+{
+	float y;
+	int u, v;
+	float r, g, b, a;
+
+	y = (float)input[0] / 0xffff;
+	u = input[1];
+	v = input[2];
+	a = (float)input[3] / 0xffff;
+
+	YUV16_TO_RGB_FLOAT(y, u, v, r, g, b);
+	
+	r *= a;
+	g *= a;
+	b *= a;
+
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+}
+
+static inline void transfer_YUVA16161616_to_RGBA_FLOAT(float *(*output), 
+	uint16_t *input)
+{
+	float y;
+	int u, v;
+	float r, g, b, a;
+	
+	y = (float)input[0] / 0xffff;
+	u = input[1];
+	v = input[2];
+	a = (float)input[3] / 0xffff;
+
+	YUV16_TO_RGB_FLOAT(y, u, v, r, g, b);
+
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+	*(*output)++ = a;
+}
+
+static inline void transfer_YUVA16161616_to_BGR8888(unsigned char *(*output), 
+	uint16_t *input)
+{
+	int y, u, v, a;
+	int64_t r, g, b;
+
+	a = input[3];
+	y = (((int)input[0]) << 8) | (input[0] >> 8);
+	u = input[1] >> 8;
+	v = input[2] >> 8;
+
+	YUV_TO_RGB(y, u, v, r, g, b);
+
+	r *= a;
+	g *= a;
+	b *= a;
+	b /= 0xffff;
+	g /= 0xffff;
+	r /= 0xffff;
+
+	*(*output)++ = b;
+	*(*output)++ = g;
+	*(*output)++ = r;
+	(*output)++;
+}
+
+
+static inline void transfer_YUVA16161616_to_VYU888(unsigned char *(*output), uint16_t *input)
+{
+	int y, u, v, a, anti_a;
+	a = input[3];
+	anti_a = 0xffff - a;
+	y = ((uint32_t)input[0] * a) / 0xffff00;
+	u = ((uint32_t)input[1] * a + 0x8000 * anti_a) / 0xffff00;
+	v = ((uint32_t)input[2] * a + 0x8000 * anti_a) / 0xffff00;
+
+	*(*output)++ = v;
+	*(*output)++ = y;
+	*(*output)++ = u;
+}
+
+
+static inline void transfer_YUVA16161616_to_YUVA16161616(uint16_t *(*output), uint16_t *input)
+{
+	(*output)[0] = input[0];
+	(*output)[1] = input[1];
+	(*output)[2] = input[2];
+	(*output)[3] = input[3];
+	(*output) += 4;
+}
+
+static inline void transfer_YUVA16161616_to_UYVA8888(unsigned char *(*output), uint16_t *input)
+{
+	(*output)[0] = input[1] >> 8;
+	(*output)[1] = input[0] >> 8;
+	(*output)[2] = input[2] >> 8;
+	(*output)[3] = input[3] >> 8;
+	(*output) += 4;
+}
+
+
+static inline void transfer_YUVA16161616_to_YUV101010(unsigned char *(*output), uint16_t *input)
+{
+	int64_t opacity = input[3];
+	int64_t transparency = 0xffff - opacity;
+	uint16_t y_i = ((int64_t)input[0] * opacity + (int64_t)0x8000 * transparency) / 0xffff;
+	uint16_t u_i = ((int64_t)input[1] * opacity + (int64_t)0x8000 * transparency) / 0xffff;
+	uint16_t v_i = ((int64_t)input[2] * opacity + (int64_t)0x8000 * transparency) / 0xffff;
+	WRITE_YUV101010(y_i, u_i, v_i);
+}
+
+static inline void transfer_YUVA16161616_to_YUV420P_YUV422P(unsigned char *output_y, 
+	unsigned char *output_u, 
+	unsigned char *output_v, 
+	uint16_t *input,
+	int output_column)
+{
+	int64_t opacity = input[3];
+	int64_t transparency = 0xffff - opacity;
+
+	output_y[output_column] =     ((int64_t)input[0] * opacity) / 0xffff00;
+	output_u[output_column / 2] = ((int64_t)input[1] * opacity + 0x8000 * transparency) / 0xffff00;
+	output_v[output_column / 2] = ((int64_t)input[2] * opacity + 0x8000 * transparency) / 0xffff00;
+}
+
+static inline void transfer_YUVA16161616_to_YUV444P(unsigned char *output_y, 
+	unsigned char *output_u, 
+	unsigned char *output_v, 
+	uint16_t *input,
+	int output_column)
+{
+	int64_t opacity = input[3];
+	int64_t transparency = 0xffff - opacity;
+
+	output_y[output_column] = ((int64_t)input[0] * opacity) / 0xffff00;
+	output_u[output_column] = ((int64_t)input[1] * opacity + 0x8000 * transparency) / 0xffff00;
+	output_v[output_column] = ((int64_t)input[2] * opacity + 0x8000 * transparency) / 0xffff00;
+}
+
+static inline void transfer_YUVA16161616_to_YUV422(unsigned char *(*output), 
+	uint16_t *input,
+	int j)
+{
+	int64_t opacity = input[3];
+	int64_t transparency = 0xffff - opacity;
+
+// Store U and V for even pixels only
+	if(!(j & 1))
+	{
+		(*output)[0] = ((int64_t)input[0] * opacity) / 0xffff00;
+		(*output)[1] = ((int64_t)input[1] * opacity + 0x8000 * transparency) / 0xffff00;
+		(*output)[3] = ((int64_t)input[2] * opacity + 0x8000 * transparency) / 0xffff00;
+	}
+	else
+// Store Y and advance output for odd pixels only
+	{
+		(*output)[2] = (input[0] * opacity) / 0xffff00;
+		(*output) += 4;
+	}
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// ******************************** Loops *************************************
+
+#define TRANSFER_FRAME_HEAD \
+	for(i = 0; i < out_h; i++) \
+	{ \
+		unsigned char *output_row = output_rows[i + out_y] + out_x * out_pixelsize; \
+		unsigned char *input_row = input_rows[row_table[i]]; \
+		int bit_counter = 7; \
+		for(j = 0; j < out_w; j++) \
+		{
+
+#define TRANSFER_FRAME_TAIL \
+		} \
+	}
+
+#define TRANSFER_YUV420P_OUT_HEAD \
+	for(i = 0; i < out_h; i++) \
+	{ \
+		unsigned char *input_row = input_rows[row_table[i]]; \
+		unsigned char *output_y = out_y_plane + i * total_out_w + out_x; \
+		unsigned char *output_u = out_u_plane + i / 2 * total_out_w / 2 + out_x / 2; \
+		unsigned char *output_v = out_v_plane + i / 2 * total_out_w / 2 + out_x / 2; \
+		for(j = 0; j < out_w; j++) \
+		{
+
+#define TRANSFER_YUV422P_OUT_HEAD \
+	for(i = 0; i < out_h; i++) \
+	{ \
+		unsigned char *input_row = input_rows[row_table[i]]; \
+		unsigned char *output_y = out_y_plane + i * total_out_w + out_x; \
+		unsigned char *output_u = out_u_plane + i * total_out_w / 2 + out_x / 2; \
+		unsigned char *output_v = out_v_plane + i * total_out_w / 2 + out_x / 2; \
+		for(j = 0; j < out_w; j++) \
+		{
+
+#define TRANSFER_YUV444P_OUT_HEAD \
+	for(i = 0; i < out_h; i++) \
+	{ \
+		unsigned char *input_row = input_rows[row_table[i]]; \
+		unsigned char *output_y = out_y_plane + i * total_out_w + out_x; \
+		unsigned char *output_u = out_u_plane + i * total_out_w + out_x; \
+		unsigned char *output_v = out_v_plane + i * total_out_w + out_x; \
+		for(j = 0; j < out_w; j++) \
+		{
+
+
+#define TRANSFER_YUV422_IN_HEAD \
+	for(i = 0; i < out_h; i++) \
+	{ \
+		unsigned char *output_row = output_rows[i + out_y] + ((out_x * out_pixelsize) & 0xfffffffc); \
+		unsigned char *input_y = in_y_plane + row_table[i] * total_in_w; \
+		unsigned char *input_u = in_u_plane + row_table[i] * (total_in_w / 2); \
+		unsigned char *input_v = in_v_plane + row_table[i] * (total_in_w / 2); \
+		for(j = 0; j < out_w; j++) \
+		{
+
+
+
+
+
+// ******************************** Permutation *******************************
+
+
diff --git a/guicast/bccmodel_yuv420p.C b/guicast/bccmodel_yuv420p.C
new file mode 100644
index 0000000..f0e6c5b
--- /dev/null
+++ b/guicast/bccmodel_yuv420p.C
@@ -0,0 +1,1395 @@
+/*
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 
+ * USA
+ */
+
+
+
+#include "bccmodel_permutation.h"
+#include "bccmodels.h"
+#include <stdio.h>
+
+
+
+
+#define TRANSFER_YUV420P_IN_HEAD \
+/* Kludge to get frequent, odd sized photos to stop crashing. */ \
+	if(out_h % 2) out_h--; \
+	for(i = 0; i < out_h; i++) \
+	{ \
+		unsigned char *output_row = output_rows[i + out_y] + out_x * out_pixelsize; \
+		unsigned char *input_y = in_y_plane + row_table[i] * total_in_w; \
+		unsigned char *input_u = in_u_plane + (row_table[i] / 2) * (total_in_w / 2); \
+		unsigned char *input_v = in_v_plane + (row_table[i] / 2) * (total_in_w / 2); \
+		for(j = 0; j < out_w; j++) \
+		{
+
+
+#define TRANSFER_YUV9P_IN_HEAD \
+	for(i = 0; i < out_h; i++) \
+	{ \
+		unsigned char *output_row = output_rows[i + out_y] + out_x * out_pixelsize; \
+		unsigned char *input_y = in_y_plane + row_table[i] * total_in_w; \
+		unsigned char *input_u = in_u_plane + (row_table[i] / 4) * (total_in_w / 4); \
+		unsigned char *input_v = in_v_plane + (row_table[i] / 4) * (total_in_w / 4); \
+		for(j = 0; j < out_w; j++) \
+		{
+
+
+#define TRANSFER_YUV422P_IN_HEAD \
+	for(i = 0; i < out_h; i++) \
+	{ \
+		unsigned char *output_row = output_rows[i + out_y] + out_x * out_pixelsize; \
+		unsigned char *input_y = in_y_plane + row_table[i] * total_in_w; \
+		unsigned char *input_u = in_u_plane + row_table[i] * (total_in_w / 2); \
+		unsigned char *input_v = in_v_plane + row_table[i] * (total_in_w / 2); \
+		for(j = 0; j < out_w; j++) \
+		{
+
+
+
+
+#define TRANSFER_YUV444P_IN_HEAD \
+	for(i = 0; i < out_h; i++) \
+	{ \
+		unsigned char *output_row = output_rows[i + out_y] + out_x * out_pixelsize; \
+		unsigned char *input_y = in_y_plane + row_table[i] * total_in_w; \
+		unsigned char *input_u = in_u_plane + row_table[i] * total_in_w; \
+		unsigned char *input_v = in_v_plane + row_table[i] * total_in_w; \
+		for(j = 0; j < out_w; j++) \
+		{
+
+
+static inline void transfer_YUV_PLANAR_to_RGB8(unsigned char *(*output), 
+	unsigned char *input_y,
+	unsigned char *input_u,
+	unsigned char *input_v)
+{
+	int y, u, v, r, g, b;
+	
+	y = (*input_y << 16) | (*input_y << 8) | *input_y;
+	u = *input_u;
+	v = *input_v;
+	YUV_TO_RGB(y, u, v, r, g, b)
+
+	*(*output) = (unsigned char)((r & 0xc0) +
+			    			 ((g & 0xe0) >> 2) +
+		 	    			 ((b & 0xe0) >> 5));
+	(*output)++;
+}
+
+static inline void transfer_YUV_PLANAR_to_BGR565(unsigned char *(*output), 
+	unsigned char *input_y,
+	unsigned char *input_u,
+	unsigned char *input_v)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = (*input_y << 16) | (*input_y << 8) | *input_y;
+	u = *input_u;
+	v = *input_v;
+	YUV_TO_RGB(y, u, v, r, g, b)
+
+	*(uint16_t*)(*output) = ((b & 0xf8) << 8)
+			 + ((g & 0xfc) << 3)
+			 + ((r & 0xf8) >> 3);
+	(*output) += 2;
+}
+
+static inline void transfer_YUV_PLANAR_to_RGB565(unsigned char *(*output), 
+	unsigned char *input_y,
+	unsigned char *input_u,
+	unsigned char *input_v)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = (*input_y << 16) | (*input_y << 8) | *input_y;
+	u = *input_u;
+	v = *input_v;
+	YUV_TO_RGB(y, u, v, r, g, b)
+
+	*(uint16_t*)(*output) = ((r & 0xf8) << 8)
+			 + ((g & 0xfc) << 3)
+			 + ((b & 0xf8) >> 3);
+	(*output) += 2;
+}
+
+static inline void transfer_YUV_PLANAR_to_BGR888(unsigned char *(*output), 
+	unsigned char *input_y,
+	unsigned char *input_u,
+	unsigned char *input_v)
+{
+	int y, u, v;
+	int r, g, b;
+	
+	y = (*input_y << 16) | (*input_y << 8) | *input_y;
+	u = *input_u;
+	v = *input_v;
+	YUV_TO_RGB(y, u, v, r, g, b)
+
+	(*output)[0] = b;
+	(*output)[1] = g;
+	(*output)[2] = r;
+	(*output) += 3;
+}
+
+static inline void transfer_YUV_PLANAR_to_BGR8888(unsigned char *(*output), 
+	unsigned char *input_y,
+	unsigned char *input_u,
+	unsigned char *input_v)
+{
+	int y, u, v;
+	int r, g, b;
+
+	y = (*input_y << 16) | (*input_y << 8) | *input_y;
+	u = *input_u;
+	v = *input_v;
+	YUV_TO_RGB(y, u, v, r, g, b)
+
+	(*output)[0] = b;
+	(*output)[1] = g;
+	(*output)[2] = r;
+	(*output) += 4;
+}
+
+static inline void transfer_YUV_PLANAR_to_RGB888(unsigned char *(*output), 
+	unsigned char *input_y,
+	unsigned char *input_u,
+	unsigned char *input_v)
+{
+// Signedness is important
+	int y, u, v, r, g, b;
+
+	y = (*input_y << 16) | (*input_y << 8) | *input_y;
+	u = *input_u;
+	v = *input_v;
+	YUV_TO_RGB(y, u, v, r, g, b)
+
+	(*output)[0] = r;
+	(*output)[1] = g;
+	(*output)[2] = b;
+	(*output) += 3;
+}
+
+static inline void transfer_YUV_PLANAR_to_ARGB8888(unsigned char *(*output), 
+	unsigned char *input_y,
+	unsigned char *input_u,
+	unsigned char *input_v)
+{
+// Signedness is important
+	int y, u, v, r, g, b;
+
+	y = (*input_y << 16) | (*input_y << 8) | *input_y;
+	u = *input_u;
+	v = *input_v;
+	YUV_TO_RGB(y, u, v, r, g, b)
+
+	(*output)[0] = 0xff;
+	(*output)[1] = r;
+	(*output)[2] = g;
+	(*output)[3] = b;
+	(*output) += 4;
+}
+
+static inline void transfer_YUV_PLANAR_to_ABGR8888(unsigned char *(*output), 
+	unsigned char *input_y,
+	unsigned char *input_u,
+	unsigned char *input_v)
+{
+// Signedness is important
+	int y, u, v, r, g, b;
+
+	y = (*input_y << 16) | (*input_y << 8) | *input_y;
+	u = *input_u;
+	v = *input_v;
+	YUV_TO_RGB(y, u, v, r, g, b)
+
+	(*output)[0] = 0xff;
+	(*output)[3] = r;
+	(*output)[2] = g;
+	(*output)[1] = b;
+	(*output) += 4;
+}
+
+static inline void transfer_YUV_PLANAR_to_RGBA8888(unsigned char *(*output), 
+	unsigned char *input_y,
+	unsigned char *input_u,
+	unsigned char *input_v)
+{
+// Signedness is important
+	int y, u, v;
+	int r, g, b;
+
+	y = (*input_y << 16) | (*input_y << 8) | *input_y;
+	u = *input_u;
+	v = *input_v;
+	YUV_TO_RGB(y, u, v, r, g, b)
+
+	(*output)[0] = r;
+	(*output)[1] = g;
+	(*output)[2] = b;
+	(*output)[3] = 0xff;
+	(*output) += 4;
+}
+
+static inline void transfer_YUV_PLANAR_to_RGB161616(uint16_t *(*output), 
+	unsigned char *input_y,
+	unsigned char *input_u,
+	unsigned char *input_v)
+{
+// Signedness is important
+	int y, u, v;
+	int r, g, b;
+	y = (*input_y << 16) | (*input_y << 8) | *input_y;
+	u = (*input_u << 8) | *input_u;
+	v = (*input_v << 8) | *input_v;
+	YUV_TO_RGB16(y, u, v, r, g, b)
+	(*output)[0] = r;
+	(*output)[1] = g;
+	(*output)[2] = b;
+
+	(*output) += 3;
+}
+
+
+static inline void transfer_YUV_PLANAR_to_RGBA16161616(uint16_t *(*output), 
+	unsigned char *input_y,
+	unsigned char *input_u,
+	unsigned char *input_v)
+{
+// Signedness is important
+	int y, u, v;
+	int r, g, b;
+	y = (*input_y << 16) | (*input_y << 8) | *input_y;
+	u = (*input_u << 8) | *input_u;
+	v = (*input_v << 8) | *input_v;
+	YUV_TO_RGB16(y, u, v, r, g, b)
+
+	(*output)[0] = r;
+	(*output)[1] = g;
+	(*output)[2] = b;
+	(*output)[3] = 0xffff;
+
+	(*output) += 4;
+}
+
+
+static inline void transfer_YUV_PLANAR_to_RGB_FLOAT(float *(*output), 
+	unsigned char *input_y,
+	unsigned char *input_u,
+	unsigned char *input_v)
+{
+// Signedness is important
+	float y = (float)*input_y / 0xff;
+	int u, v;
+	float r, g, b;
+	u = *input_u;
+	v = *input_v;
+	YUV_TO_FLOAT(y, u, v, r, g, b)
+
+	(*output)[0] = r;
+	(*output)[1] = g;
+	(*output)[2] = b;
+	(*output) += 3;
+}
+
+
+static inline void transfer_YUV_PLANAR_to_RGBA_FLOAT(float *(*output), 
+	unsigned char *input_y,
+	unsigned char *input_u,
+	unsigned char *input_v)
+{
+// Signedness is important
+	float y = (float)*input_y / 0xff;
+	int u, v;
+	float r, g, b;
+	u = *input_u;
+	v = *input_v;
+	YUV_TO_FLOAT(y, u, v, r, g, b)
+//printf("transfer_YUV_PLANAR_to_RGBA_FLOAT 1 %p\n", (*output));
+
+	(*output)[0] = r;
+	(*output)[1] = g;
+	(*output)[2] = b;
+	(*output)[3] = 1.0;
+	(*output) += 4;
+//printf("transfer_YUV_PLANAR_to_RGBA_FLOAT 2 %p\n", (*output));
+}
+
+
+
+static inline void transfer_YUV_PLANAR_to_YUV888(unsigned char *(*output), 
+	unsigned char *input_y,
+	unsigned char *input_u,
+	unsigned char *input_v)
+{
+	(*output)[0] = *input_y;
+	(*output)[1] = *input_u;
+	(*output)[2] = *input_v;
+	(*output) += 3;
+}
+
+static inline void transfer_YUV_PLANAR_to_YUV161616(uint16_t *(*output), 
+	unsigned char *input_y,
+	unsigned char *input_u,
+	unsigned char *input_v)
+{
+	(*output)[0] = (*input_y << 8) | *input_y;
+	(*output)[1] = (*input_u << 8) | *input_u;
+	(*output)[2] = (*input_v << 8) | *input_v;
+	(*output) += 3;
+}
+
+static inline void transfer_YUV_PLANAR_to_YUVA8888(unsigned char *(*output), 
+	unsigned char *input_y,
+	unsigned char *input_u,
+	unsigned char *input_v)
+{
+	(*output)[0] = *input_y;
+	(*output)[1] = *input_u;
+	(*output)[2] = *input_v;
+	(*output)[3] = 0xff;
+	(*output) += 4;
+}
+
+static inline void transfer_YUV_PLANAR_to_YUVA16161616(uint16_t *(*output), 
+	unsigned char *input_y,
+	unsigned char *input_u,
+	unsigned char *input_v)
+{
+	(*output)[0] = (((uint16_t)*input_y) << 8) | *input_y;
+	(*output)[1] = (((uint16_t)*input_u) << 8) | *input_u;
+	(*output)[2] = (((uint16_t)*input_v) << 8) | *input_v;
+
+	(*output)[3] = 0xffff;
+	(*output) += 4;
+}
+
+static inline void transfer_YUV_PLANAR_to_YUV420P(unsigned char *input_y,
+	unsigned char *input_u,
+	unsigned char *input_v,
+	unsigned char *output_y,
+	unsigned char *output_u,
+	unsigned char *output_v,
+	int j)
+{
+	output_y[j] = *input_y;
+	output_u[j / 2] = *input_u;
+	output_v[j / 2] = *input_v;
+}
+
+static inline void transfer_YUV_PLANAR_to_YUV444P(unsigned char *input_y,
+	unsigned char *input_u,
+	unsigned char *input_v,
+	unsigned char *output_y,
+	unsigned char *output_u,
+	unsigned char *output_v,
+	int j)
+{
+	output_y[j] = *input_y;
+	output_u[j] = *input_u;
+	output_v[j] = *input_v;
+}
+
+static inline void transfer_YUV_PLANAR_to_YUV422(unsigned char *(*output), 
+	unsigned char *input_y,
+	unsigned char *input_u,
+	unsigned char *input_v,
+	int j)
+{
+// Store U and V for even pixels only
+	if(!(j & 1))
+	{
+		(*output)[1] = *input_u;
+		(*output)[3] = *input_v;
+		(*output)[0] = *input_y;
+	}
+	else
+// Store Y and advance output for odd pixels only
+	{
+		(*output)[2] = *input_y;
+		(*output) += 4;
+	}
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// ******************************** YUV444P -> ********************************
+
+static inline void transfer_YUV444P_to_YUV444P(unsigned char *input_y,
+	unsigned char *input_u,
+	unsigned char *input_v,
+	unsigned char *output_y,
+	unsigned char *output_u,
+	unsigned char *output_v,
+	int j)
+{
+	output_y[j] = *input_y;
+	output_u[j] = *input_u;
+	output_v[j] = *input_v;
+}
+
+
+
+
+#define TRANSFER_FRAME_DEFAULT(output, \
+	input, \
+	y_in_offset, \
+	u_in_offset, \
+	v_in_offset, \
+	input_column) \
+{ \
+	register int i, j; \
+ \
+	switch(in_colormodel) \
+	{ \
+		case BC_YUV420P: \
+			switch(out_colormodel) \
+			{ \
+				case BC_RGB8: \
+					TRANSFER_YUV420P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGB8((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR565: \
+					TRANSFER_YUV420P_IN_HEAD \
+					transfer_YUV_PLANAR_to_BGR565((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB565: \
+					TRANSFER_YUV420P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGB565((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR888:      \
+					TRANSFER_YUV420P_IN_HEAD \
+					transfer_YUV_PLANAR_to_BGR888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR8888: \
+					TRANSFER_YUV420P_IN_HEAD \
+					transfer_YUV_PLANAR_to_BGR8888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV420P: \
+					for(i = 0; i < out_h; i++) \
+					{ \
+						unsigned char *output_y = out_y_plane + i * total_out_w; \
+						unsigned char *output_u = out_u_plane + i / 2 * total_out_w / 2; \
+						unsigned char *output_v = out_v_plane + i / 2 * total_out_w / 2; \
+						unsigned char *input_y = in_y_plane + row_table[i] * total_in_w; \
+						unsigned char *input_u = in_u_plane + row_table[i] / 2 * total_in_w / 2; \
+						unsigned char *input_v = in_v_plane + row_table[i] / 2 * total_in_w / 2; \
+						for(j = 0; j < out_w; j++) \
+						{ \
+							transfer_YUV_PLANAR_to_YUV420P(input_y + (y_in_offset), \
+								input_u + (u_in_offset), \
+								input_v + (v_in_offset), \
+								output_y, \
+								output_u, \
+								output_v, \
+								j); \
+						} \
+					} \
+					break; \
+				case BC_YUV422: \
+					TRANSFER_YUV420P_IN_HEAD \
+					transfer_YUV_PLANAR_to_YUV422((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset), \
+						j); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV422P: \
+					for(i = 0; i < out_h; i++) \
+					{ \
+						unsigned char *output_y = out_y_plane + i * total_out_w; \
+						unsigned char *output_u = out_u_plane + i * total_out_w / 2; \
+						unsigned char *output_v = out_v_plane + i * total_out_w / 2; \
+						unsigned char *input_y = in_y_plane + row_table[i] * total_in_w; \
+						unsigned char *input_u = in_u_plane + row_table[i] / 2 * total_in_w / 2; \
+						unsigned char *input_v = in_v_plane + row_table[i] / 2 * total_in_w / 2; \
+						for(j = 0; j < out_w; j++) \
+						{ \
+							transfer_YUV_PLANAR_to_YUV420P(input_y + (y_in_offset), \
+								input_u + (u_in_offset), \
+								input_v + (v_in_offset), \
+								output_y, \
+								output_u, \
+								output_v, \
+								j); \
+						} \
+					} \
+					break; \
+				case BC_YUV444P: \
+					for(i = 0; i < out_h; i++) \
+					{ \
+						unsigned char *output_y = out_y_plane + i * total_out_w; \
+						unsigned char *output_u = out_u_plane + i * total_out_w; \
+						unsigned char *output_v = out_v_plane + i * total_out_w; \
+						unsigned char *input_y = in_y_plane + row_table[i] * total_in_w; \
+						unsigned char *input_u = in_u_plane + row_table[i] / 2 * total_in_w / 2; \
+						unsigned char *input_v = in_v_plane + row_table[i] / 2 * total_in_w / 2; \
+						for(j = 0; j < out_w; j++) \
+						{ \
+							transfer_YUV_PLANAR_to_YUV444P(input_y + (y_in_offset), \
+								input_u + (u_in_offset), \
+								input_v + (v_in_offset), \
+								output_y, \
+								output_u, \
+								output_v, \
+								j); \
+						} \
+					} \
+					break; \
+				case BC_RGB888:      \
+					TRANSFER_YUV420P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGB888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_ARGB8888:      \
+					TRANSFER_YUV420P_IN_HEAD \
+					transfer_YUV_PLANAR_to_ARGB8888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_ABGR8888:      \
+					TRANSFER_YUV420P_IN_HEAD \
+					transfer_YUV_PLANAR_to_ABGR8888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA8888:      \
+					TRANSFER_YUV420P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGBA8888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB161616:      \
+					TRANSFER_YUV420P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGB161616((uint16_t**)(output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA16161616:      \
+					TRANSFER_YUV420P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGBA16161616((uint16_t**)(output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB_FLOAT:      \
+					TRANSFER_YUV420P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGB_FLOAT((float**)(output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA_FLOAT:      \
+					TRANSFER_YUV420P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGBA_FLOAT((float**)(output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV888: \
+					TRANSFER_YUV420P_IN_HEAD \
+					transfer_YUV_PLANAR_to_YUV888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUVA8888: \
+					TRANSFER_YUV420P_IN_HEAD \
+					transfer_YUV_PLANAR_to_YUVA8888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV161616: \
+					TRANSFER_YUV420P_IN_HEAD \
+					transfer_YUV_PLANAR_to_YUV161616((uint16_t**)(output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUVA16161616: \
+					TRANSFER_YUV420P_IN_HEAD \
+					transfer_YUV_PLANAR_to_YUVA16161616((uint16_t**)(output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+			} \
+			break; \
+ \
+		case BC_YUV9P: \
+			switch(out_colormodel) \
+			{ \
+				case BC_RGB8: \
+					TRANSFER_YUV9P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGB8((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR565: \
+					TRANSFER_YUV9P_IN_HEAD \
+					transfer_YUV_PLANAR_to_BGR565((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB565: \
+					TRANSFER_YUV9P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGB565((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR888:      \
+					TRANSFER_YUV9P_IN_HEAD \
+					transfer_YUV_PLANAR_to_BGR888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR8888: \
+					TRANSFER_YUV9P_IN_HEAD \
+					transfer_YUV_PLANAR_to_BGR8888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV420P: \
+					for(i = 0; i < out_h; i++) \
+					{ \
+						unsigned char *output_y = out_y_plane + i * total_out_w; \
+						unsigned char *output_u = out_u_plane + i / 2 * total_out_w / 2; \
+						unsigned char *output_v = out_v_plane + i / 2 * total_out_w / 2; \
+						unsigned char *input_y = in_y_plane + row_table[i] * total_in_w; \
+						unsigned char *input_u = in_u_plane + row_table[i] / 2 * total_in_w / 2; \
+						unsigned char *input_v = in_v_plane + row_table[i] / 2 * total_in_w / 2; \
+						for(j = 0; j < out_w; j++) \
+						{ \
+							transfer_YUV_PLANAR_to_YUV420P(input_y + (y_in_offset), \
+								input_u + (u_in_offset), \
+								input_v + (v_in_offset), \
+								output_y, \
+								output_u, \
+								output_v, \
+								j); \
+						} \
+					} \
+					break; \
+				case BC_YUV422: \
+					TRANSFER_YUV9P_IN_HEAD \
+					transfer_YUV_PLANAR_to_YUV422((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset), \
+						j); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV422P: \
+					for(i = 0; i < out_h; i++) \
+					{ \
+						unsigned char *output_y = out_y_plane + i * total_out_w; \
+						unsigned char *output_u = out_u_plane + i * total_out_w / 2; \
+						unsigned char *output_v = out_v_plane + i * total_out_w / 2; \
+						unsigned char *input_y = in_y_plane + row_table[i] * total_in_w; \
+						unsigned char *input_u = in_u_plane + row_table[i] / 2 * total_in_w / 2; \
+						unsigned char *input_v = in_v_plane + row_table[i] / 2 * total_in_w / 2; \
+						for(j = 0; j < out_w; j++) \
+						{ \
+							transfer_YUV_PLANAR_to_YUV420P(input_y + (y_in_offset), \
+								input_u + (u_in_offset), \
+								input_v + (v_in_offset), \
+								output_y, \
+								output_u, \
+								output_v, \
+								j); \
+						} \
+					} \
+					break; \
+				case BC_YUV444P: \
+					for(i = 0; i < out_h; i++) \
+					{ \
+						unsigned char *output_y = out_y_plane + i * total_out_w; \
+						unsigned char *output_u = out_u_plane + i * total_out_w; \
+						unsigned char *output_v = out_v_plane + i * total_out_w; \
+						unsigned char *input_y = in_y_plane + row_table[i] * total_in_w; \
+						unsigned char *input_u = in_u_plane + row_table[i] / 2 * total_in_w / 2; \
+						unsigned char *input_v = in_v_plane + row_table[i] / 2 * total_in_w / 2; \
+						for(j = 0; j < out_w; j++) \
+						{ \
+							transfer_YUV_PLANAR_to_YUV444P(input_y + (y_in_offset), \
+								input_u + (u_in_offset), \
+								input_v + (v_in_offset), \
+								output_y, \
+								output_u, \
+								output_v, \
+								j); \
+						} \
+					} \
+					break; \
+				case BC_RGB888:      \
+					TRANSFER_YUV9P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGB888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_ARGB8888:      \
+					TRANSFER_YUV9P_IN_HEAD \
+					transfer_YUV_PLANAR_to_ARGB8888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_ABGR8888:      \
+					TRANSFER_YUV9P_IN_HEAD \
+					transfer_YUV_PLANAR_to_ABGR8888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA8888:      \
+					TRANSFER_YUV9P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGBA8888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB161616:      \
+					TRANSFER_YUV9P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGB161616((uint16_t**)(output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA16161616:      \
+					TRANSFER_YUV9P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGBA16161616((uint16_t**)(output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB_FLOAT:      \
+					TRANSFER_YUV9P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGB_FLOAT((float**)(output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA_FLOAT:      \
+					TRANSFER_YUV9P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGBA_FLOAT((float**)(output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV888: \
+					TRANSFER_YUV9P_IN_HEAD \
+					transfer_YUV_PLANAR_to_YUV888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUVA8888: \
+					TRANSFER_YUV9P_IN_HEAD \
+					transfer_YUV_PLANAR_to_YUVA8888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV161616: \
+					TRANSFER_YUV9P_IN_HEAD \
+					transfer_YUV_PLANAR_to_YUV161616((uint16_t**)(output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUVA16161616: \
+					TRANSFER_YUV9P_IN_HEAD \
+					transfer_YUV_PLANAR_to_YUVA16161616((uint16_t**)(output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+			} \
+			break; \
+ \
+		case BC_YUV422P: \
+			switch(out_colormodel) \
+			{ \
+				case BC_RGB8: \
+					TRANSFER_YUV422P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGB8((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR565: \
+					TRANSFER_YUV422P_IN_HEAD \
+					transfer_YUV_PLANAR_to_BGR565((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB565: \
+					TRANSFER_YUV422P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGB565((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR888:      \
+					TRANSFER_YUV422P_IN_HEAD \
+					transfer_YUV_PLANAR_to_BGR888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR8888: \
+					TRANSFER_YUV422P_IN_HEAD \
+					transfer_YUV_PLANAR_to_BGR8888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB888:      \
+					TRANSFER_YUV422P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGB888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_ARGB8888:      \
+					TRANSFER_YUV422P_IN_HEAD \
+					transfer_YUV_PLANAR_to_ARGB8888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_ABGR8888:      \
+					TRANSFER_YUV422P_IN_HEAD \
+					transfer_YUV_PLANAR_to_ABGR8888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA8888:      \
+					TRANSFER_YUV422P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGBA8888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB161616:      \
+					TRANSFER_YUV422P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGB161616((uint16_t**)(output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA16161616:      \
+					TRANSFER_YUV422P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGBA16161616((uint16_t**)(output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB_FLOAT:      \
+					TRANSFER_YUV422P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGB_FLOAT((float**)(output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA_FLOAT:      \
+					TRANSFER_YUV422P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGBA_FLOAT((float**)(output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV888: \
+					TRANSFER_YUV422P_IN_HEAD \
+					transfer_YUV_PLANAR_to_YUV888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUVA8888: \
+					TRANSFER_YUV422P_IN_HEAD \
+					transfer_YUV_PLANAR_to_YUVA8888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV161616: \
+					TRANSFER_YUV422P_IN_HEAD \
+					transfer_YUV_PLANAR_to_YUV161616((uint16_t**)(output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUVA16161616: \
+					TRANSFER_YUV422P_IN_HEAD \
+					transfer_YUV_PLANAR_to_YUVA16161616((uint16_t**)(output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV420P: \
+					for(i = 0; i < out_h; i++) \
+					{ \
+						unsigned char *output_y = out_y_plane + i * total_out_w; \
+						unsigned char *output_u = out_u_plane + i / 2 * total_out_w / 2; \
+						unsigned char *output_v = out_v_plane + i / 2 * total_out_w / 2; \
+						unsigned char *input_y = in_y_plane + row_table[i] * total_in_w; \
+						unsigned char *input_u = in_u_plane + row_table[i] * total_in_w / 2; \
+						unsigned char *input_v = in_v_plane + row_table[i] * total_in_w / 2; \
+						for(j = 0; j < out_w; j++) \
+						{ \
+							transfer_YUV_PLANAR_to_YUV420P(input_y + (y_in_offset), \
+								input_u + (u_in_offset), \
+								input_v + (v_in_offset), \
+								output_y, \
+								output_u, \
+								output_v, \
+								j); \
+						} \
+					} \
+					break; \
+				case BC_YUV422: \
+					TRANSFER_YUV422_IN_HEAD \
+					transfer_YUV_PLANAR_to_YUV422((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset), \
+						j); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV422P: \
+					for(i = 0; i < out_h; i++) \
+					{ \
+						unsigned char *output_y = out_y_plane + i * total_out_w; \
+						unsigned char *output_u = out_u_plane + i * total_out_w / 2; \
+						unsigned char *output_v = out_v_plane + i * total_out_w / 2; \
+						unsigned char *input_y = in_y_plane + row_table[i] * total_in_w; \
+						unsigned char *input_u = in_u_plane + row_table[i] * total_in_w / 2; \
+						unsigned char *input_v = in_v_plane + row_table[i] * total_in_w / 2; \
+						for(j = 0; j < out_w; j++) \
+						{ \
+							transfer_YUV_PLANAR_to_YUV420P(input_y + (y_in_offset), \
+								input_u + (u_in_offset), \
+								input_v + (v_in_offset), \
+								output_y, \
+								output_u, \
+								output_v, \
+								j); \
+						} \
+					} \
+					break; \
+				case BC_YUV444P: \
+					for(i = 0; i < out_h; i++) \
+					{ \
+						unsigned char *output_y = out_y_plane + i * total_out_w; \
+						unsigned char *output_u = out_u_plane + i * total_out_w; \
+						unsigned char *output_v = out_v_plane + i * total_out_w; \
+						unsigned char *input_y = in_y_plane + row_table[i] * total_in_w; \
+						unsigned char *input_u = in_u_plane + row_table[i] * total_in_w / 2; \
+						unsigned char *input_v = in_v_plane + row_table[i] * total_in_w / 2; \
+						for(j = 0; j < out_w; j++) \
+						{ \
+							transfer_YUV_PLANAR_to_YUV444P(input_y + (y_in_offset), \
+								input_u + (u_in_offset), \
+								input_v + (v_in_offset), \
+								output_y, \
+								output_u, \
+								output_v, \
+								j); \
+						} \
+					} \
+					break; \
+			} \
+			break; \
+ \
+ \
+		case BC_YUV444P: \
+			switch(out_colormodel) \
+			{ \
+				case BC_RGB8: \
+					TRANSFER_YUV444P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGB8((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR565: \
+					TRANSFER_YUV444P_IN_HEAD \
+					transfer_YUV_PLANAR_to_BGR565((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB565: \
+					TRANSFER_YUV444P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGB565((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR888:      \
+					TRANSFER_YUV444P_IN_HEAD \
+					transfer_YUV_PLANAR_to_BGR888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_BGR8888: \
+					TRANSFER_YUV444P_IN_HEAD \
+					transfer_YUV_PLANAR_to_BGR8888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB888:      \
+					TRANSFER_YUV444P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGB888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_ARGB8888:      \
+					TRANSFER_YUV444P_IN_HEAD \
+					transfer_YUV_PLANAR_to_ARGB8888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_ABGR8888:      \
+					TRANSFER_YUV444P_IN_HEAD \
+					transfer_YUV_PLANAR_to_ABGR8888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA8888:      \
+					TRANSFER_YUV444P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGBA8888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB161616:      \
+					TRANSFER_YUV444P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGB161616((uint16_t**)(output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA16161616:      \
+					TRANSFER_YUV444P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGBA16161616((uint16_t**)(output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGB_FLOAT:      \
+					TRANSFER_YUV444P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGB_FLOAT((float**)(output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_RGBA_FLOAT:      \
+					TRANSFER_YUV444P_IN_HEAD \
+					transfer_YUV_PLANAR_to_RGBA_FLOAT((float**)(output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV888: \
+					TRANSFER_YUV444P_IN_HEAD \
+					transfer_YUV_PLANAR_to_YUV888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUVA8888: \
+					TRANSFER_YUV444P_IN_HEAD \
+					transfer_YUV_PLANAR_to_YUVA8888((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV161616: \
+					TRANSFER_YUV444P_IN_HEAD \
+					transfer_YUV_PLANAR_to_YUV161616((uint16_t**)(output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUVA16161616: \
+					TRANSFER_YUV444P_IN_HEAD \
+					transfer_YUV_PLANAR_to_YUVA16161616((uint16_t**)(output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset)); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV420P: \
+					for(i = 0; i < out_h; i++) \
+					{ \
+						unsigned char *output_y = out_y_plane + i * total_out_w; \
+						unsigned char *output_u = out_u_plane + i / 2 * total_out_w / 2; \
+						unsigned char *output_v = out_v_plane + i / 2 * total_out_w / 2; \
+						unsigned char *input_y = in_y_plane + row_table[i] * total_in_w; \
+						unsigned char *input_u = in_u_plane + row_table[i] * total_in_w; \
+						unsigned char *input_v = in_v_plane + row_table[i] * total_in_w; \
+						for(j = 0; j < out_w; j++) \
+						{ \
+							transfer_YUV_PLANAR_to_YUV420P(input_y + (y_in_offset), \
+								input_u + (u_in_offset), \
+								input_v + (v_in_offset), \
+								output_y, \
+								output_u, \
+								output_v, \
+								j); \
+						} \
+					} \
+					break; \
+				case BC_YUV422: \
+					TRANSFER_YUV444P_IN_HEAD \
+					transfer_YUV_PLANAR_to_YUV422((output), \
+						input_y + (y_in_offset), \
+						input_u + (u_in_offset), \
+						input_v + (v_in_offset), \
+						j); \
+					TRANSFER_FRAME_TAIL \
+					break; \
+				case BC_YUV422P: \
+					for(i = 0; i < out_h; i++) \
+					{ \
+						unsigned char *output_y = out_y_plane + i * total_out_w; \
+						unsigned char *output_u = out_u_plane + i * total_out_w / 2; \
+						unsigned char *output_v = out_v_plane + i * total_out_w / 2; \
+						unsigned char *input_y = in_y_plane + row_table[i] * total_in_w; \
+						unsigned char *input_u = in_u_plane + row_table[i] * total_in_w; \
+						unsigned char *input_v = in_v_plane + row_table[i] * total_in_w; \
+						for(j = 0; j < out_w; j++) \
+						{ \
+							transfer_YUV_PLANAR_to_YUV420P(input_y + (y_in_offset), \
+								input_u + (u_in_offset), \
+								input_v + (v_in_offset), \
+								output_y, \
+								output_u, \
+								output_v, \
+								j); \
+						} \
+					} \
+					break; \
+				case BC_YUV444P: \
+					for(i = 0; i < out_h; i++) \
+					{ \
+						unsigned char *output_y = out_y_plane + i * total_out_w; \
+						unsigned char *output_u = out_u_plane + i * total_out_w; \
+						unsigned char *output_v = out_v_plane + i * total_out_w; \
+						unsigned char *input_y = in_y_plane + row_table[i] * total_in_w; \
+						unsigned char *input_u = in_u_plane + row_table[i] * total_in_w; \
+						unsigned char *input_v = in_v_plane + row_table[i] * total_in_w; \
+						for(j = 0; j < out_w; j++) \
+						{ \
+							transfer_YUV444P_to_YUV444P(input_y + (y_in_offset), \
+								input_u + (u_in_offset), \
+								input_v + (v_in_offset), \
+								output_y, \
+								output_u, \
+								output_v, \
+								j); \
+						} \
+					} \
+					break; \
+			} \
+			break; \
+	} \
+}
+
+void BC_CModels::yuv420p(PERMUTATION_ARGS)
+{
+	if(scale)
+	{
+		TRANSFER_FRAME_DEFAULT(&output_row, 
+			input_row + column_table[j] * in_pixelsize,
+			column_table[j],
+			column_table[j] / 2,
+			column_table[j] / 2,
+			0);
+	}
+	else
+	{
+		TRANSFER_FRAME_DEFAULT(&output_row, 
+			input_row + j * in_pixelsize,
+			j,
+			j / 2,
+			j / 2,
+			0);
+	}
+}
+
+void BC_CModels::yuv9p(PERMUTATION_ARGS)
+{
+	if(scale)
+	{
+		TRANSFER_FRAME_DEFAULT(&output_row, 
+			input_row + column_table[j] * in_pixelsize,
+			column_table[j],
+			column_table[j] / 4,
+			column_table[j] / 4,
+			0);
+	}
+	else
+	{
+		TRANSFER_FRAME_DEFAULT(&output_row, 
+			input_row + j * in_pixelsize,
+			j,
+			j / 4,
+			j / 4,
+			0);
+	}
+}
+
+void BC_CModels::yuv444p(PERMUTATION_ARGS)
+{
+	if(scale)
+	{
+		TRANSFER_FRAME_DEFAULT(&output_row, 
+			input_row + column_table[j] * in_pixelsize,
+			column_table[j],
+			column_table[j],
+			column_table[j],
+			0);
+	}
+	else
+	{
+		TRANSFER_FRAME_DEFAULT(&output_row, 
+			input_row + j * in_pixelsize,
+			j,
+			j,
+			j,
+			0);
+	}
+}
diff --git a/guicast/bccmodel_yuv422.C b/guicast/bccmodel_yuv422.C
new file mode 100644
index 0000000..e98834d
--- /dev/null
+++ b/guicast/bccmodel_yuv422.C
@@ -0,0 +1,551 @@
+/*
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 
+ * USA
+ */
+
+
+#include "bccmodel_permutation.h"
+#include "bccmodels.h"
+
+
+
+static inline void transfer_YUV422_to_RGB8(unsigned char *(*output), 
+	unsigned char *input, 
+	int column)
+{
+	int y, u, v;
+	int r, g, b;
+
+// Even pixel
+	if(!(column & 1))
+		y = (int)(input[0]) << 16;
+	else
+// Odd pixel
+		y = (int)(input[2]) << 16;
+
+	u = input[1];
+	v = input[3];
+	YUV_TO_RGB(y, u, v, r, g, b)
+
+	*(*output) = (unsigned char)((r & 0xc0) +
+			    			 ((g & 0xe0) >> 2) +
+		 	    			 ((b & 0xe0) >> 5));
+	(*output)++;
+}
+
+static inline void transfer_YUV422_to_BGR565(unsigned char *(*output), 
+	unsigned char *input, 
+	int column)
+{
+	int y, u, v;
+	int r, g, b;
+
+// Even pixel
+	if(!(column & 1))
+		y = (int)(input[0]) << 16;
+	else
+// Odd pixel
+		y = (int)(input[2]) << 16;
+	u = input[1];
+	v = input[3];
+	YUV_TO_RGB(y, u, v, r, g, b)
+
+	*(uint16_t*)(*output) = ((b & 0xf8) << 8)
+			 + ((g & 0xfc) << 3)
+			 + ((r & 0xf8) >> 3);
+	(*output) += 2;
+}
+
+static inline void transfer_YUV422_to_RGB565(unsigned char *(*output), 
+	unsigned char *input, 
+	int column)
+{
+	int y, u, v;
+	int r, g, b;
+
+// Even pixel
+	if(!(column & 1))
+		y = (int)(input[0]) << 16;
+	else
+// Odd pixel
+		y = (int)(input[2]) << 16;
+	u = input[1];
+	v = input[3];
+	YUV_TO_RGB(y, u, v, r, g, b)
+
+	*(uint16_t*)(*output) = ((r & 0xf8) << 8)
+			 + ((g & 0xfc) << 3)
+			 + ((b & 0xf8) >> 3);
+	(*output) += 2;
+}
+
+static inline void transfer_YUV422_to_BGR888(unsigned char *(*output), 
+	unsigned char *input, 
+	int column)
+{
+	int y, u, v;
+	int r, g, b;
+
+// Even pixel
+	if(!(column & 1))
+		y = (int)(input[0]) << 16;
+	else
+// Odd pixel
+		y = (int)(input[2]) << 16;
+	u = input[1];
+	v = input[3];
+	YUV_TO_RGB(y, u, v, r, g, b)
+
+	(*output)[0] = b;
+	(*output)[1] = g;
+	(*output)[2] = r;
+	(*output) += 3;
+}
+
+static inline void transfer_YUV422_to_RGB888(unsigned char *(*output), 
+	unsigned char *input, 
+	int column)
+{
+	int y, u, v;
+	int r, g, b;
+
+// Even pixel
+	if(!(column & 1))
+		y = (input[0] << 16) | (input[0] << 8) | input[0];
+	else
+// Odd pixel
+		y = (input[2] << 16) | (input[2] << 8) | input[2];
+	u = input[1];
+	v = input[3];
+	YUV_TO_RGB(y, u, v, r, g, b)
+
+	(*output)[0] = r;
+	(*output)[1] = g;
+	(*output)[2] = b;
+	(*output) += 3;
+}
+
+static inline void transfer_YUV422_to_RGBA8888(unsigned char *(*output), 
+	unsigned char *input, 
+	int column)
+{
+	int y, u, v;
+	int r, g, b;
+
+// Even pixel
+	if(!(column & 1))
+		y = (input[0] << 16) | (input[0] << 8) | input[0];
+	else
+// Odd pixel
+		y = (input[2] << 16) | (input[2] << 8) | input[2];
+	u = input[1];
+	v = input[3];
+	YUV_TO_RGB(y, u, v, r, g, b)
+
+	(*output)[0] = r;
+	(*output)[1] = g;
+	(*output)[2] = b;
+	(*output)[3] = 0xff;
+	(*output) += 4;
+}
+
+static inline void transfer_YUV422_to_RGB161616(uint16_t *(*output), 
+	unsigned char *input, 
+	int column)
+{
+	int y, u, v;
+	int r, g, b;
+
+// Even pixel
+	if(!(column & 1))
+		y = (input[0] << 16) | (input[0] << 8) | input[0];
+	else
+// Odd pixel
+		y = (input[2] << 16) | (input[2] << 8) | input[2];
+	u = (input[1] << 8) | input[1];
+	v = (input[3] << 8) | input[3];
+	YUV_TO_RGB16(y, u, v, r, g, b)
+
+	(*output)[0] = r;
+	(*output)[1] = g;
+	(*output)[2] = b;
+	(*output) += 3;
+}
+
+static inline void transfer_YUV422_to_RGBA16161616(uint16_t *(*output), 
+	unsigned char *input, 
+	int column)
+{
+	int y, u, v;
+	int r, g, b;
+
+// Even pixel
+	if(!(column & 1))
+		y = (input[0] << 16) | (input[0] << 8) | input[0];
+	else
+// Odd pixel
+		y = (input[2] << 16) | (input[2] << 8) | input[2];
+	u = (input[1] << 8) | input[1];
+	v = (input[3] << 8) | input[3];
+	YUV_TO_RGB16(y, u, v, r, g, b)
+
+	(*output)[0] = r;
+	(*output)[1] = g;
+	(*output)[2] = b;
+	(*output)[3] = 0xffff;
+	(*output) += 4;
+}
+
+static inline void transfer_YUV422_to_RGB_FLOAT(float* *output, 
+	unsigned char *input, 
+	int column)
+{
+	float y;
+// Signedness is important
+	int u, v;
+	float r, g, b;
+
+// Even pixel
+	if(!(column & 1))
+		y = (float)input[0] / 0xff;
+	else
+// Odd pixel
+		y = (float)input[2] / 0xff;
+	u = input[1];
+	v = input[3];
+	YUV_TO_FLOAT(y, u, v, r, g, b)
+
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+}
+
+static inline void transfer_YUV422_to_RGBA_FLOAT(float* *output, 
+	unsigned char *input, 
+	int column)
+{
+	float y;
+// Signedness is important
+	int u, v;
+	float r, g, b;
+
+// Even pixel
+	if(!(column & 1))
+		y = (float)input[0] / 0xff;
+	else
+// Odd pixel
+		y = (float)input[2] / 0xff;
+	u = input[1];
+	v = input[3];
+	YUV_TO_FLOAT(y, u, v, r, g, b)
+
+	*(*output)++ = r;
+	*(*output)++ = g;
+	*(*output)++ = b;
+	*(*output)++ = 1.0;
+}
+
+static inline void transfer_YUV422_to_YUV888(unsigned char *(*output), 
+	unsigned char *input, 
+	int column)
+{
+// Even pixel
+	if(!(column & 1))
+		(*output)[0] = input[0];
+	else
+// Odd pixel
+		(*output)[0] = input[2];
+
+	(*output)[1] = input[1];
+	(*output)[2] = input[3];
+	(*output) += 3;
+}
+
+static inline void transfer_YUV422_to_YUVA8888(unsigned char *(*output), 
+	unsigned char *input, 
+	int column)
+{
+// Even pixel
+	if(!(column & 1))
+		(*output)[0] = input[0];
+	else
+// Odd pixel
+		(*output)[0] = input[2];
+
+	(*output)[1] = input[1];
+	(*output)[2] = input[3];
+	(*output)[3] = 255;
+	(*output) += 4;
+}
+
+static inline void transfer_YUV422_to_YUV161616(uint16_t *(*output), 
+	unsigned char *input, 
+	int column)
+{
+// Even pixel
+	if(!(column & 1))
+		(*output)[0] = (input[0] << 8) | input[0];
+	else
+// Odd pixel
+		(*output)[0] = (input[2] << 8) | input[2];
+
+	(*output)[1] = (input[1] << 8) | input[1];
+	(*output)[2] = (input[3] << 8) | input[3];
+	(*output) += 3;
+}
+
+static inline void transfer_YUV422_to_YUVA16161616(uint16_t *(*output), 
+	unsigned char *input, 
+	int column)
+{
+// Even pixel
+	if(!(column & 1))
+		(*output)[0] = (input[0] << 8) | input[0];
+	else
+// Odd pixel
+		(*output)[0] = (input[2] << 8) | input[2];
+
+	(*output)[1] = (input[1] << 8) | input[1];
+	(*output)[2] = (input[3] << 8) | input[3];
+	(*output)[3] = 0xffff;
+	(*output) += 4;
+}
+
+static inline void transfer_YUV422_to_BGR8888(unsigned char *(*output), 
+	unsigned char *input, 
+	int column)
+{
+	int y, u, v;
+	int r, g, b;
+
+// Even pixel
+	if(!(column & 1))
+		y = (int)(input[0]) << 16;
+	else
+// Odd pixel
+		y = (int)(input[2]) << 16;
+	u = input[1];
+	v = input[3];
+
+	YUV_TO_RGB(y, u, v, r, g, b)
+
+	(*output)[0] = b;
+	(*output)[1] = g;
+	(*output)[2] = r;
+	(*output) += 4;
+}
+
+
+static inline void transfer_YUV422_to_YUV422P(unsigned char *output_y, 
+	unsigned char *output_u, 
+	unsigned char *output_v, 
+	unsigned char *input,
+	int output_column)
+{
+// Store U and V for even pixels only
+	if(!(output_column & 1))
+	{
+		output_y[output_column] = input[0];
+		output_u[output_column / 2] = input[1];
+		output_v[output_column / 2] = input[3];
+	}
+	else
+// Store Y and advance output for odd pixels only
+	{
+		output_y[output_column] = input[2];
+	}
+}
+
+static inline void transfer_YUV422_to_YUV420P(unsigned char *output_y, 
+	unsigned char *output_u, 
+	unsigned char *output_v, 
+	unsigned char *input,
+	int output_column,
+	int output_row)
+{
+// Even column
+	if(!(output_column & 1))
+	{
+		output_y[output_column] = input[0];
+// Store U and V for even columns and even rows only
+		if(!(output_row & 1))
+		{
+			output_u[output_column / 2] = input[1];
+			output_v[output_column / 2] = input[3];
+		}
+	}
+	else
+// Odd column
+	{
+		output_y[output_column] = input[2];
+	}
+}
+
+static inline void transfer_YUV422_to_YUV422(unsigned char *(*output), 
+	unsigned char *input,
+	int j)
+{
+// Store U and V for even pixels only
+	if(!(j & 1))
+	{
+		(*output)[0] = input[0];
+		(*output)[1] = input[1];
+		(*output)[3] = input[3];
+	}
+	else
+// Store Y and advance output for odd pixels only
+	{
+		(*output)[2] = input[2];
+		(*output) += 4;
+	}
+}
+
+
+
+
+
+
+#define TRANSFER_FRAME_DEFAULT(output, \
+	input, \
+	y_in_offset, \
+	u_in_offset, \
+	v_in_offset, \
+	input_column) \
+{ \
+	register int i, j; \
+ \
+	switch(out_colormodel) \
+	{ \
+		case BC_RGB8: \
+			TRANSFER_FRAME_HEAD \
+			transfer_YUV422_to_RGB8((output), (input), (input_column)); \
+			TRANSFER_FRAME_TAIL \
+			break; \
+		case BC_BGR565: \
+		case BC_RGB565: \
+			TRANSFER_FRAME_HEAD \
+			transfer_YUV422_to_RGB565((output), (input), (input_column)); \
+			TRANSFER_FRAME_TAIL \
+			break; \
+		case BC_RGB888:      \
+			TRANSFER_FRAME_HEAD \
+			transfer_YUV422_to_RGB888((output), (input), (input_column)); \
+			TRANSFER_FRAME_TAIL \
+			break; \
+		case BC_RGBA8888:      \
+			TRANSFER_FRAME_HEAD \
+			transfer_YUV422_to_RGBA8888((output), (input), (input_column)); \
+			TRANSFER_FRAME_TAIL \
+			break; \
+		case BC_YUV888:      \
+			TRANSFER_FRAME_HEAD \
+			transfer_YUV422_to_YUV888((output), (input), (input_column)); \
+			TRANSFER_FRAME_TAIL \
+			break; \
+		case BC_YUVA8888:      \
+			TRANSFER_FRAME_HEAD \
+			transfer_YUV422_to_YUVA8888((output), (input), (input_column)); \
+			TRANSFER_FRAME_TAIL \
+			break; \
+		case BC_RGB161616:      \
+			TRANSFER_FRAME_HEAD \
+			transfer_YUV422_to_RGB161616((uint16_t**)(output), (input), (input_column)); \
+			TRANSFER_FRAME_TAIL \
+			break; \
+		case BC_RGBA16161616:      \
+			TRANSFER_FRAME_HEAD \
+			transfer_YUV422_to_RGBA16161616((uint16_t**)(output), (input), (input_column)); \
+			TRANSFER_FRAME_TAIL \
+			break; \
+		case BC_RGB_FLOAT:      \
+			TRANSFER_FRAME_HEAD \
+			transfer_YUV422_to_RGB_FLOAT((float**)(output), (input), (input_column)); \
+			TRANSFER_FRAME_TAIL \
+			break; \
+		case BC_RGBA_FLOAT:      \
+			TRANSFER_FRAME_HEAD \
+			transfer_YUV422_to_RGBA_FLOAT((float**)(output), (input), (input_column)); \
+			TRANSFER_FRAME_TAIL \
+			break; \
+		case BC_YUV161616:      \
+			TRANSFER_FRAME_HEAD \
+			transfer_YUV422_to_YUV161616((uint16_t**)(output), (input), (input_column)); \
+			TRANSFER_FRAME_TAIL \
+			break; \
+		case BC_YUVA16161616:      \
+			TRANSFER_FRAME_HEAD \
+			transfer_YUV422_to_YUVA16161616((uint16_t**)(output), (input), (input_column)); \
+			TRANSFER_FRAME_TAIL \
+			break; \
+		case BC_BGR888:      \
+			TRANSFER_FRAME_HEAD \
+			transfer_YUV422_to_BGR888((output), (input), (input_column)); \
+			TRANSFER_FRAME_TAIL \
+			break; \
+		case BC_BGR8888: \
+			TRANSFER_FRAME_HEAD \
+			transfer_YUV422_to_BGR8888((output), (input), (input_column)); \
+			TRANSFER_FRAME_TAIL \
+			break; \
+		case BC_YUV422P: \
+			TRANSFER_YUV422P_OUT_HEAD \
+			transfer_YUV422_to_YUV422P(output_y, \
+				output_u, \
+				output_v, \
+				(input), \
+				j); \
+			TRANSFER_FRAME_TAIL \
+			break; \
+		case BC_YUV422: \
+			TRANSFER_FRAME_HEAD \
+			transfer_YUV422_to_YUV422((output), \
+				(input), \
+				j); \
+			TRANSFER_FRAME_TAIL \
+			break; \
+		case BC_YUV420P: \
+			TRANSFER_YUV420P_OUT_HEAD \
+			transfer_YUV422_to_YUV420P(output_y, \
+				output_u, \
+				output_v, \
+				(input), \
+				j, \
+				i); \
+			TRANSFER_FRAME_TAIL \
+			break; \
+	} \
+}
+
+void BC_CModels::yuv422(PERMUTATION_ARGS)
+{
+	if(scale)
+	{
+		TRANSFER_FRAME_DEFAULT(&output_row, 
+			input_row + ((column_table[j] * in_pixelsize) & 0xfffffffc),
+			0,
+			0,
+			0,
+			column_table[j]);
+	}
+	else
+	{
+		TRANSFER_FRAME_DEFAULT(&output_row, 
+			input_row + ((j * in_pixelsize) & 0xfffffffc),
+			0,
+			0,
+			0,
+			j);
+	}
+}
diff --git a/guicast/bccmodels.C b/guicast/bccmodels.C
new file mode 100755
index 0000000..71a5d5f
--- /dev/null
+++ b/guicast/bccmodels.C
@@ -0,0 +1,544 @@
+/*
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 
+ * USA
+ */
+
+
+
+#include "bccmodels.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+
+// Compression coefficients straight out of jpeglib
+#define R_TO_Y    0.29900
+#define G_TO_Y    0.58700
+#define B_TO_Y    0.11400
+
+#define R_TO_U    -0.16874
+#define G_TO_U    -0.33126
+#define B_TO_U    0.50000
+
+#define R_TO_V    0.50000
+#define G_TO_V    -0.41869
+#define B_TO_V    -0.08131
+
+// Decompression coefficients straight out of jpeglib
+#define V_TO_R    1.40200
+#define V_TO_G    -0.71414
+
+#define U_TO_G    -0.34414
+#define U_TO_B    1.77200
+
+
+
+
+
+
+BC_CModels::YuvTables BC_CModels::yuv_table;
+
+
+
+
+
+BC_CModels::BC_CModels()
+{
+	init_yuv();
+}
+
+void BC_CModels::init_yuv()
+{
+	int i;
+
+/* compression */
+	for(i = 0; i < 0x100; i++)
+	{
+		yuv_table.rtoy_tab[i] = (int)(R_TO_Y * 0x10000 * i);
+		yuv_table.rtou_tab[i] = (int)(R_TO_U * 0x10000 * i);
+		yuv_table.rtov_tab[i] = (int)(R_TO_V * 0x10000 * i);
+
+		yuv_table.gtoy_tab[i] = (int)(G_TO_Y * 0x10000 * i);
+		yuv_table.gtou_tab[i] = (int)(G_TO_U * 0x10000 * i);
+		yuv_table.gtov_tab[i] = (int)(G_TO_V * 0x10000 * i);
+
+		yuv_table.btoy_tab[i] = (int)(B_TO_Y * 0x10000 * i);
+		yuv_table.btou_tab[i] = (int)(B_TO_U * 0x10000 * i) + 0x800000;
+		yuv_table.btov_tab[i] = (int)(B_TO_V * 0x10000 * i) + 0x800000;
+	}
+
+/* compression */
+	for(i = 0; i < 0x10000; i++)
+	{
+		yuv_table.rtoy_tab16[i] = (int)(R_TO_Y * 0x100 * i);
+		yuv_table.rtou_tab16[i] = (int)(R_TO_U * 0x100 * i);
+		yuv_table.rtov_tab16[i] = (int)(R_TO_V * 0x100 * i);
+
+		yuv_table.gtoy_tab16[i] = (int)(G_TO_Y * 0x100 * i);
+		yuv_table.gtou_tab16[i] = (int)(G_TO_U * 0x100 * i);
+		yuv_table.gtov_tab16[i] = (int)(G_TO_V * 0x100 * i);
+
+		yuv_table.btoy_tab16[i] = (int)(B_TO_Y * 0x100 * i);
+		yuv_table.btou_tab16[i] = (int)(B_TO_U * 0x100 * i) + 0x800000;
+		yuv_table.btov_tab16[i] = (int)(B_TO_V * 0x100 * i) + 0x800000;
+	}
+
+
+
+
+/* decompression */
+	yuv_table.vtor = &(yuv_table.vtor_tab[0x80]);
+	yuv_table.vtog = &(yuv_table.vtog_tab[0x80]);
+	yuv_table.utog = &(yuv_table.utog_tab[0x80]);
+	yuv_table.utob = &(yuv_table.utob_tab[0x80]);
+	for(i = -0x80; i < 0x80; i++)
+	{
+		yuv_table.vtor[i] = (int)(V_TO_R * 0x10000 * i);
+		yuv_table.vtog[i] = (int)(V_TO_G * 0x10000 * i);
+
+		yuv_table.utog[i] = (int)(U_TO_G * 0x10000 * i);
+		yuv_table.utob[i] = (int)(U_TO_B * 0x10000 * i);
+	}
+
+
+/* decompression */
+	yuv_table.vtor_float = &(yuv_table.vtor_float_tab[0x80]);
+	yuv_table.vtog_float = &(yuv_table.vtog_float_tab[0x80]);
+	yuv_table.utog_float = &(yuv_table.utog_float_tab[0x80]);
+	yuv_table.utob_float = &(yuv_table.utob_float_tab[0x80]);
+	for(i = -0x80; i < 0x80; i++)
+	{
+		yuv_table.vtor_float[i] = V_TO_R * i / 0xff;
+		yuv_table.vtog_float[i] = V_TO_G * i / 0xff;
+
+		yuv_table.utog_float[i] = U_TO_G * i / 0xff;
+		yuv_table.utob_float[i] = U_TO_B * i / 0xff;
+	}
+
+
+/* decompression */
+	yuv_table.vtor16 = &(yuv_table.vtor_tab16[0x8000]);
+	yuv_table.vtog16 = &(yuv_table.vtog_tab16[0x8000]);
+	yuv_table.utog16 = &(yuv_table.utog_tab16[0x8000]);
+	yuv_table.utob16 = &(yuv_table.utob_tab16[0x8000]);
+	for(i = -0x8000; i < 0x8000; i++)
+	{
+		yuv_table.vtor16[i] = (int)(V_TO_R * 0x100 * i);
+		yuv_table.vtog16[i] = (int)(V_TO_G * 0x100 * i);
+
+		yuv_table.utog16[i] = (int)(U_TO_G * 0x100 * i);
+		yuv_table.utob16[i] = (int)(U_TO_B * 0x100 * i);
+	}
+
+
+/* decompression */
+	yuv_table.v16tor_float = &(yuv_table.v16tor_float_tab[0x8000]);
+	yuv_table.v16tog_float = &(yuv_table.v16tog_float_tab[0x8000]);
+	yuv_table.u16tog_float = &(yuv_table.u16tog_float_tab[0x8000]);
+	yuv_table.u16tob_float = &(yuv_table.u16tob_float_tab[0x8000]);
+	for(i = -0x8000; i < 0x8000; i++)
+	{
+		yuv_table.v16tor_float[i] = V_TO_R * i / 0xffff;
+		yuv_table.v16tog_float[i] = V_TO_G * i / 0xffff;
+
+		yuv_table.u16tog_float[i] = U_TO_G * i / 0xffff;
+		yuv_table.u16tob_float[i] = U_TO_B * i / 0xffff;
+	}
+}
+
+
+
+
+int BC_CModels::is_planar(int colormodel)
+{
+	switch(colormodel)
+	{
+		case BC_YUV420P:      return 1; break;
+		case BC_YUV422P:      return 1; break;
+		case BC_YUV444P:      return 1; break;
+		case BC_YUV411P:      return 1; break;
+	}
+	return 0;
+}
+
+int BC_CModels::components(int colormodel)
+{
+	switch(colormodel)
+	{
+		case BC_A8:           return 1; break;
+		case BC_A16:          return 1; break;
+		case BC_A_FLOAT:      return 1; break;
+		case BC_RGB888:       return 3; break;
+		case BC_RGBA8888:     return 4; break;
+		case BC_RGB161616:    return 3; break;
+		case BC_RGBA16161616: return 4; break;
+		case BC_YUV888:       return 3; break;
+		case BC_YUVA8888:     return 4; break;
+		case BC_YUV161616:    return 3; break;
+		case BC_YUVA16161616: return 4; break;
+		case BC_YUV101010:    return 3; break;
+		case BC_RGB_FLOAT:    return 3; break;
+		case BC_RGBA_FLOAT:   return 4; break;
+	}
+}
+
+int BC_CModels::calculate_pixelsize(int colormodel)
+{
+	switch(colormodel)
+	{
+		case BC_A8:           return 1; break;
+		case BC_A16:          return 2; break;
+		case BC_A_FLOAT:      return 4; break;
+		case BC_TRANSPARENCY: return 1; break;
+		case BC_COMPRESSED:   return 1; break;
+		case BC_RGB8:         return 1; break;
+		case BC_RGB565:       return 2; break;
+		case BC_BGR565:       return 2; break;
+		case BC_BGR888:       return 3; break;
+		case BC_BGR8888:      return 4; break;
+// Working bitmaps are packed to simplify processing
+		case BC_RGB888:       return 3; break;
+		case BC_ARGB8888:     return 4; break;
+		case BC_ABGR8888:     return 4; break;
+		case BC_RGBA8888:     return 4; break;
+		case BC_RGB161616:    return 6; break;
+		case BC_RGBA16161616: return 8; break;
+		case BC_YUV888:       return 3; break;
+		case BC_YUVA8888:     return 4; break;
+		case BC_YUV161616:    return 6; break;
+		case BC_YUVA16161616: return 8; break;
+		case BC_YUV101010:    return 4; break;
+		case BC_VYU888:       return 3; break;
+		case BC_UYVA8888:     return 4; break;
+		case BC_RGB_FLOAT:    return 12; break;
+		case BC_RGBA_FLOAT:   return 16; break;
+// Planar
+		case BC_YUV420P:      return 1; break;
+		case BC_YUV422P:      return 1; break;
+		case BC_YUV444P:      return 1; break;
+		case BC_YUV422:       return 2; break;
+		case BC_YUV411P:      return 1; break;
+		case BC_YUV9P:        return 1; break;
+	}
+	return 0;
+}
+
+int BC_CModels::calculate_max(int colormodel)
+{
+	switch(colormodel)
+	{
+// Working bitmaps are packed to simplify processing
+		case BC_A8:           return 0xff; break;
+		case BC_A16:          return 0xffff; break;
+		case BC_A_FLOAT:      return 1; break;
+		case BC_RGB888:       return 0xff; break;
+		case BC_RGBA8888:     return 0xff; break;
+		case BC_RGB161616:    return 0xffff; break;
+		case BC_RGBA16161616: return 0xffff; break;
+		case BC_YUV888:       return 0xff; break;
+		case BC_YUVA8888:     return 0xff; break;
+		case BC_YUV161616:    return 0xffff; break;
+		case BC_YUVA16161616: return 0xffff; break;
+		case BC_RGB_FLOAT:    return 1; break;
+		case BC_RGBA_FLOAT:   return 1; break;
+	}
+	return 0;
+}
+
+int BC_CModels::calculate_datasize(int w, int h, int bytes_per_line, int color_model)
+{
+	if(bytes_per_line < 0) bytes_per_line = w * 
+		calculate_pixelsize(color_model);
+	switch(color_model)
+	{
+		case BC_YUV420P:
+		case BC_YUV411P:
+			return w * h + w * h / 2 + 4;
+			break;
+
+		case BC_YUV422P:
+			return w * h * 2 + 4;
+			break;
+
+		case BC_YUV444P:
+			return w * h * 3 + 4;
+			break;
+
+		default:
+			return h * bytes_per_line + 4;
+			break;
+	}
+	return 0;
+}
+
+
+static void get_scale_tables(int **column_table, 
+	int **row_table, 
+	int in_x1, 
+	int in_y1, 
+	int in_x2, 
+	int in_y2,
+	int out_x1, 
+	int out_y1, 
+	int out_x2, 
+	int out_y2)
+{
+	int y_out, i;
+	float w_in = in_x2 - in_x1;
+	float h_in = in_y2 - in_y1;
+	int w_out = out_x2 - out_x1;
+	int h_out = out_y2 - out_y1;
+
+	float hscale = w_in / w_out;
+	float vscale = h_in / h_out;
+
+/* + 1 so we don't overflow when calculating in advance */
+	(*column_table) = (int*)malloc(sizeof(int) * (w_out + 1));
+	(*row_table) = (int*)malloc(sizeof(int) * h_out);
+	for(i = 0; i < w_out; i++)
+	{
+		(*column_table)[i] = (int)(hscale * i) + in_x1;
+	}
+
+	for(i = 0; i < h_out; i++)
+	{
+		(*row_table)[i] = (int)(vscale * i) + in_y1;
+//printf("get_scale_tables %d %d\n", (*row_table)[i], i);
+	}
+}
+
+void BC_CModels::transfer(unsigned char **output_rows, 
+	unsigned char **input_rows,
+	unsigned char *out_y_plane,
+	unsigned char *out_u_plane,
+	unsigned char *out_v_plane,
+	unsigned char *in_y_plane,
+	unsigned char *in_u_plane,
+	unsigned char *in_v_plane,
+	int in_x, 
+	int in_y, 
+	int in_w, 
+	int in_h,
+	int out_x, 
+	int out_y, 
+	int out_w, 
+	int out_h,
+	int in_colormodel, 
+	int out_colormodel,
+	int bg_color,
+	int in_rowspan,
+	int out_rowspan)
+{
+	int *column_table;
+	int *row_table;
+	int scale;
+	int bg_r, bg_g, bg_b;
+	int in_pixelsize = calculate_pixelsize(in_colormodel);
+	int out_pixelsize = calculate_pixelsize(out_colormodel);
+
+	bg_r = (bg_color & 0xff0000) >> 16;
+	bg_g = (bg_color & 0xff00) >> 8;
+	bg_b = (bg_color & 0xff);
+
+// Get scaling
+	scale = (out_w != in_w) || (in_x != 0);
+	get_scale_tables(&column_table, &row_table, 
+		in_x, in_y, in_x + in_w, in_y + in_h,
+		out_x, out_y, out_x + out_w, out_y + out_h);
+
+
+// printf("BC_CModels::transfer %d %d %d %d,%d %d,%d %d,%d %d,%d\n", 
+// __LINE__,
+// in_colormodel, 
+// out_colormodel, 
+// out_x, 
+// out_y, 
+// out_w, 
+// out_h, 
+// in_x, 
+// in_y, 
+// in_w, 
+// in_h);
+
+
+
+#define PERMUTATION_VALUES \
+	output_rows,  \
+	input_rows, \
+	out_y_plane, \
+	out_u_plane, \
+	out_v_plane, \
+	in_y_plane, \
+	in_u_plane, \
+	in_v_plane, \
+	in_x,  \
+	in_y,  \
+	in_w,  \
+	in_h, \
+	out_x,  \
+	out_y,  \
+	out_w,  \
+	out_h, \
+	in_colormodel,  \
+	out_colormodel, \
+	bg_color, \
+	in_rowspan, \
+	out_rowspan, \
+	scale, \
+	out_pixelsize, \
+	in_pixelsize, \
+	row_table, \
+	column_table, \
+	bg_r, \
+	bg_g, \
+	bg_b
+
+// Handle planar cmodels separately
+	switch(in_colormodel)
+	{
+		case BC_RGB_FLOAT:
+		case BC_RGBA_FLOAT:
+			cmodel_float(PERMUTATION_VALUES);
+			break;
+
+		case BC_YUV420P:
+		case BC_YUV422P:
+			yuv420p(PERMUTATION_VALUES);
+			break;
+
+		case BC_YUV9P:
+			yuv9p(PERMUTATION_VALUES);
+			break;
+
+		case BC_YUV444P:
+			yuv444p(PERMUTATION_VALUES);
+			break;
+
+		case BC_YUV422:
+			yuv422(PERMUTATION_VALUES);
+			break;
+
+		default:
+			cmodel_default(PERMUTATION_VALUES);
+			break;
+	}
+
+/*
+ * printf("transfer 100 %d %d\n", 
+ * in_colormodel, 
+ * out_colormodel);
+ */
+
+	free(column_table);
+	free(row_table);
+}
+
+int BC_CModels::bc_to_x(int color_model)
+{
+	switch(color_model)
+	{
+		case BC_YUV420P:
+			return FOURCC_YV12;
+			break;
+		case BC_YUV422:
+			return FOURCC_YUV2;
+			break;
+	}
+	return -1;
+}
+
+void BC_CModels::to_text(char *string, int cmodel)
+{
+	switch(cmodel)
+	{
+		case BC_RGB888:       strcpy(string, "RGB-8 Bit");   break;
+		case BC_RGBA8888:     strcpy(string, "RGBA-8 Bit");  break;
+		case BC_RGB161616:    strcpy(string, "RGB-16 Bit");  break;
+		case BC_RGBA16161616: strcpy(string, "RGBA-16 Bit"); break;
+		case BC_YUV888:       strcpy(string, "YUV-8 Bit");   break;
+		case BC_YUVA8888:     strcpy(string, "YUVA-8 Bit");  break;
+		case BC_YUV161616:    strcpy(string, "YUV-16 Bit");  break;
+		case BC_YUVA16161616: strcpy(string, "YUVA-16 Bit"); break;
+		case BC_RGB_FLOAT:    strcpy(string, "RGB-FLOAT");   break;
+		case BC_RGBA_FLOAT:   strcpy(string, "RGBA-FLOAT");  break;
+		default: strcpy(string, "RGB-8 Bit"); break;
+	}
+}
+
+int BC_CModels::from_text(const char *text)
+{
+	if(!strcasecmp(text, "RGB-8 Bit"))   return BC_RGB888;
+	if(!strcasecmp(text, "RGBA-8 Bit"))  return BC_RGBA8888;
+	if(!strcasecmp(text, "RGB-16 Bit"))  return BC_RGB161616;
+	if(!strcasecmp(text, "RGBA-16 Bit")) return BC_RGBA16161616;
+	if(!strcasecmp(text, "RGB-FLOAT"))   return BC_RGB_FLOAT;
+	if(!strcasecmp(text, "RGBA-FLOAT"))  return BC_RGBA_FLOAT;
+	if(!strcasecmp(text, "YUV-8 Bit"))   return BC_YUV888;
+	if(!strcasecmp(text, "YUVA-8 Bit"))  return BC_YUVA8888;
+	if(!strcasecmp(text, "YUV-16 Bit"))  return BC_YUV161616;
+	if(!strcasecmp(text, "YUVA-16 Bit")) return BC_YUVA16161616;
+	return BC_RGB888;
+}
+
+int BC_CModels::has_alpha(int colormodel)
+{
+	switch(colormodel)
+	{
+		case BC_YUVA8888:
+		case BC_RGBA8888:
+		case BC_RGBA_FLOAT:
+			return 1;
+	}
+	return 0;
+}
+
+int BC_CModels::is_float(int colormodel)
+{
+	switch(colormodel)
+	{
+		case BC_RGB_FLOAT:
+		case BC_RGBA_FLOAT:
+			return 1;
+	}
+	return 0;
+}
+
+int BC_CModels::is_yuv(int colormodel)
+{
+	switch(colormodel)
+	{
+		case BC_YUV888:
+		case BC_YUVA8888:
+		case BC_YUV161616:
+		case BC_YUVA16161616:
+		case BC_YUV422:
+		case BC_YUV420P:
+		case BC_YUV422P:
+		case BC_YUV444P:
+		case BC_YUV411P:
+			return 1;
+			break;
+		
+		default:
+			return 0;
+			break;
+	}
+}
+
+
+
+
+
diff --git a/guicast/bccmodels.h b/guicast/bccmodels.h
new file mode 100644
index 0000000..d1c4ce3
--- /dev/null
+++ b/guicast/bccmodels.h
@@ -0,0 +1,216 @@
+/*
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 
+ * USA
+ */
+ 
+ 
+#ifndef BCCMODELS_H
+#define BCCMODELS_H
+
+
+
+
+// Colormodels
+// Must match colormodels.h in quicktime
+#ifndef BC_TRANSPARENCY
+
+
+#define BC_TRANSPARENCY 0
+#define BC_COMPRESSED   1
+#define BC_RGB8         2
+#define BC_RGB565       3
+#define BC_BGR565       4
+#define BC_BGR888       5
+#define BC_BGR8888      6
+// Working bitmaps are packed to simplify processing
+#define BC_RGB888       9
+#define BC_RGBA8888     10
+#define BC_ARGB8888     20
+#define BC_ABGR8888     21
+#define BC_RGB161616    11
+#define BC_RGBA16161616 12
+#define BC_YUV888       13
+#define BC_YUVA8888     14
+#define BC_YUV161616    15
+#define BC_YUVA16161616 16
+#define BC_YUV422       19
+#define BC_A8           22
+#define BC_A16          23
+#define BC_A_FLOAT      31
+#define BC_YUV101010    24
+#define BC_VYU888       25
+#define BC_UYVA8888     26
+#define BC_RGB_FLOAT    29
+#define BC_RGBA_FLOAT   30
+// Planar
+#define BC_YUV420P      7
+#define BC_YUV422P      17
+#define BC_YUV444P      27
+#define BC_YUV411P      18
+#define BC_YUV9P        28     // Disasterous cmodel from Sorenson
+
+// Colormodels purely used by Quicktime are done in Quicktime.
+
+// For communication with the X Server
+#define FOURCC_YV12 0x32315659  /* YV12   YUV420P */
+#define FOURCC_YUV2 0x32595559  /* YUV2   YUV422 */
+#define FOURCC_I420 0x30323449  /* I420   Intel Indeo 4 */
+
+
+#endif // !BC_TRANSPARENCY
+
+
+
+
+
+#ifndef PERMUTATION_ARGS
+
+
+
+#define PERMUTATION_ARGS \
+	unsigned char **output_rows,  \
+	unsigned char **input_rows, \
+	unsigned char *out_y_plane, \
+	unsigned char *out_u_plane, \
+	unsigned char *out_v_plane, \
+	unsigned char *in_y_plane, \
+	unsigned char *in_u_plane, \
+	unsigned char *in_v_plane, \
+	int in_x,  \
+	int in_y,  \
+	int in_w,  \
+	int in_h, \
+	int out_x,  \
+	int out_y,  \
+	int out_w,  \
+	int out_h, \
+	int in_colormodel,  \
+	int out_colormodel, \
+	int bg_color, \
+	int total_in_w, \
+	int total_out_w, \
+	int scale, \
+	int out_pixelsize, \
+	int in_pixelsize, \
+	int *row_table, \
+	int *column_table, \
+	int bg_r, \
+	int bg_g, \
+	int bg_b
+
+
+
+#endif // !PERMUTATION_ARGS
+
+
+
+
+
+
+
+
+// Access with BC_WindowBase::cmodels
+class BC_CModels
+{
+public:
+	BC_CModels();
+
+
+
+	class YuvTables
+	{
+	public:
+		int rtoy_tab[0x100], gtoy_tab[0x100], btoy_tab[0x100];
+		int rtou_tab[0x100], gtou_tab[0x100], btou_tab[0x100];
+		int rtov_tab[0x100], gtov_tab[0x100], btov_tab[0x100];
+
+		int vtor_tab[0x100], vtog_tab[0x100];
+		int utog_tab[0x100], utob_tab[0x100];
+
+// Used by init_yuv only
+		int *vtor, *vtog, *utog, *utob;
+
+		float vtor_float_tab[0x100], vtog_float_tab[0x100];
+		float utog_float_tab[0x100], utob_float_tab[0x100];
+		float *vtor_float, *vtog_float, *utog_float, *utob_float;
+
+		int rtoy_tab16[0x10000], gtoy_tab16[0x10000], btoy_tab16[0x10000];
+		int rtou_tab16[0x10000], gtou_tab16[0x10000], btou_tab16[0x10000];
+		int rtov_tab16[0x10000], gtov_tab16[0x10000], btov_tab16[0x10000];
+
+		int vtor_tab16[0x10000], vtog_tab16[0x10000];
+		int utog_tab16[0x10000], utob_tab16[0x10000];
+		int *vtor16, *vtog16, *utog16, *utob16;
+
+		float v16tor_float_tab[0x10000], v16tog_float_tab[0x10000];
+		float u16tog_float_tab[0x10000], u16tob_float_tab[0x10000];
+		float *v16tor_float, *v16tog_float, *u16tog_float, *u16tob_float;
+	};
+
+	static YuvTables yuv_table;
+
+	static int calculate_pixelsize(int colormodel);
+	static int calculate_datasize(int w, int h, int bytes_per_line, int color_model);
+	static int calculate_max(int colormodel);
+	static int components(int colormodel);
+	static int is_yuv(int colormodel);
+	static int has_alpha(int colormodel);
+	static int is_float(int colormodel);
+
+	// Tell when to use plane arguments or row pointer arguments to functions
+	static int is_planar(int color_model);
+	static void to_text(char *string, int cmodel);
+	static int from_text(const char *text);
+
+
+
+	static void transfer(unsigned char **output_rows, /* Leave NULL if non existent */
+		unsigned char **input_rows,
+		unsigned char *out_y_plane, /* Leave NULL if non existent */
+		unsigned char *out_u_plane,
+		unsigned char *out_v_plane,
+		unsigned char *in_y_plane, /* Leave NULL if non existent */
+		unsigned char *in_u_plane,
+		unsigned char *in_v_plane,
+		int in_x,        /* Dimensions to capture from input frame */
+		int in_y, 
+		int in_w, 
+		int in_h,
+		int out_x,       /* Dimensions to project on output frame */
+		int out_y, 
+		int out_w, 
+		int out_h,
+		int in_colormodel, 
+		int out_colormodel,
+		int bg_color,         /* When transfering BC_RGBA8888 to non-alpha this is the background color in 0xRRGGBB hex */
+		int in_rowspan,       /* For planar use the luma rowspan */
+		int out_rowspan);     /* For planar use the luma rowspan */
+
+	static void init_yuv();
+	static int bc_to_x(int color_model);
+
+
+
+	static void cmodel_default(PERMUTATION_ARGS);
+	static void cmodel_float(PERMUTATION_ARGS);
+	static void yuv420p(PERMUTATION_ARGS);
+	static void yuv9p(PERMUTATION_ARGS);
+	static void yuv444p(PERMUTATION_ARGS);
+	static void yuv422(PERMUTATION_ARGS);
+
+};
+
+
+#endif
diff --git a/guicast/bccmodels.inc b/guicast/bccmodels.inc
new file mode 100644
index 0000000..f7d0106
--- /dev/null
+++ b/guicast/bccmodels.inc
@@ -0,0 +1,13 @@
+#ifndef BCCMODELS_INC
+#define BCCMODELS_INC
+
+
+
+
+class BC_CModels;
+
+
+
+#endif
+
+
diff --git a/guicast/bcwindowbase.h b/guicast/bcwindowbase.h
index 31e7525..62a29a2 100644
--- a/guicast/bcwindowbase.h
+++ b/guicast/bcwindowbase.h
@@ -44,6 +44,7 @@
 #include "bcbutton.inc"
 #include "bccapture.inc"
 #include "bcclipboard.inc"
+#include "bccmodels.inc"
 #include "bcdragwindow.inc"
 #include "bcfilebox.inc"
 #include "bclistbox.inc"
diff --git a/guicast/vframe.C b/guicast/vframe.C
index a07fb62..6d24245 100644
--- a/guicast/vframe.C
+++ b/guicast/vframe.C
@@ -75,6 +75,23 @@ VFrame::VFrame(VFrame &frame)
 	copy_stacks(&frame);
 }
 
+VFrame::VFrame(int w, 
+	int h, 
+	int color_model)
+ {
+	reset_parameters(1);
+	params = new BC_Hash;
+	allocate_data(data, 
+	      /* shmid = -1, */
+		0, 
+		0, 
+		0, 
+		w, 
+		h, 
+		color_model, 
+		-1);
+}
+
 VFrame::VFrame(unsigned char *data, 
 	int w, 
 	int h, 
diff --git a/guicast/vframe.h b/guicast/vframe.h
index 5d55d55..c99ad0a 100644
--- a/guicast/vframe.h
+++ b/guicast/vframe.h
@@ -28,6 +28,7 @@
 #include "bctexture.inc"
 #include "bcwindowbase.inc"
 #include "colormodels.h"
+#include "bccmodels.h"
 #include "vframe.inc"
 
 class PngReadFunction;
@@ -43,6 +44,10 @@ class VFrame
 public:
 // Create new frame with shared data if *data is nonzero.
 // Pass 0 to *data if private data is desired.
+	VFrame(int w, 
+		int h, 
+		int color_model);
+
 	VFrame(unsigned char *data, 
 		int w, 
 		int h, 
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index ccf28a7..185a169 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -38,6 +38,7 @@ SUBDIRS= \
 	dot \
 	downsample \
 	fieldframe \
+	findobject \
 	flash \
 	flip \
 	framefield \
diff --git a/plugins/bluebanana/bluebananaslider.C b/plugins/bluebanana/bluebananaslider.C
index 7dab0c4..1fa5e31 100644
--- a/plugins/bluebanana/bluebananaslider.C
+++ b/plugins/bluebanana/bluebananaslider.C
@@ -471,7 +471,7 @@ void BluebananaSlider::update(){
   int nty = Z1+1;
 
   if(!trough){
-    trough = new VFrame(NULL,ntw,nth);
+    trough = new VFrame((unsigned char*)NULL,ntw,nth);
   }
 
   if(!trough){
@@ -1506,7 +1506,7 @@ void BluebananaSliderChannel::update(){
   /* the trough in the three-part hist slider is slightly smaller than
      the full slider range, and cut into three sections */
   if(!trough){
-    trough = new VFrame(NULL,ntw,nth);
+    trough = new VFrame((unsigned char*)0, ntw,nth);
   }
 
   if(!trough){
@@ -1961,7 +1961,7 @@ void BluebananaSliderFill::update(){
   /* the trough in the two-part contour slider is slightly smaller than
      the full slider range, and cut into two sections */
   if(!trough){
-    trough = new VFrame(NULL,ntw,nth);
+    trough = new VFrame((unsigned char*)0, ntw,nth);
   }
 
   /* Unlike the hist slider, we just drop the three pixel columns in the center */
diff --git a/plugins/findobject/Makefile.am b/plugins/findobject/Makefile.am
new file mode 100644
index 0000000..7297dd3
--- /dev/null
+++ b/plugins/findobject/Makefile.am
@@ -0,0 +1,11 @@
+plugin_LTLIBRARIES = findobject.la
+findobject_la_LDFLAGS = -avoid-version -module -shared 
+findobject_la_LIBADD = -lopencv_legacy -lopencv_objdetect -lopencv_core
+findobject_la_SOURCES = findobject.C findobjectwindow.C surfscan.C
+
+AM_CXXFLAGS = $(LARGEFILE_CFLAGS)
+
+AM_CPPFLAGS = -I$(top_srcdir)/guicast -I$(top_srcdir)/cinelerra -I$(top_srcdir)/quicktime
+LIBTOOL = $(SHELL) $(top_builddir)/libtool $(LTCXX_FLAGS)
+
+noinst_HEADERS = findobject.h findobjectwindow.h surfscan.h
diff --git a/plugins/findobject/findobject.C b/plugins/findobject/findobject.C
new file mode 100644
index 0000000..18c2af8
--- /dev/null
+++ b/plugins/findobject/findobject.C
@@ -0,0 +1,1423 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 1997-2012 Adam Williams <broadcast at earthling dot net>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+
+// This is mainly a test for object tracking
+
+#include "affine.h"
+#include "cicolors.h"
+#include "clip.h"
+#include "filexml.h"
+#include "keyframe.h"
+#include "language.h"
+#include "findobject.h"
+#include "findobjectwindow.h"
+#include "mutex.h"
+#include "overlayframe.h"
+#include "surfscan.h"
+#include "transportque.h"
+#include "bchash.h"
+#include "bcdisplayinfo.h"
+
+// Needed with OpenCV version 2.4.8
+#include "opencv2/legacy/legacy.hpp"
+#include "opencv2/legacy/compat.hpp"
+
+#include "opencv2/video/tracking.hpp"
+#include "opencv2/video/background_segm.hpp"
+
+
+#include <errno.h>
+#include <unistd.h>
+
+REGISTER_PLUGIN(FindObjectMain)
+
+
+
+FindObjectConfig::FindObjectConfig()
+{
+	global_range_w = 5;
+	global_range_h = 5;
+	draw_keypoints = 1;
+	draw_border = 1;
+	replace_object = 0;
+	draw_object_border = 1;
+	global_block_w = MIN_BLOCK;
+	global_block_h = MIN_BLOCK;
+	block_x = 50;
+	block_y = 50;
+	object_layer = 0;
+	replace_layer = 1;
+	scene_layer = 2;
+	algorithm = NO_ALGORITHM;
+	vmin = 10;
+	vmax = 256;
+	smin = 30;
+	blend = 100;
+}
+
+void FindObjectConfig::boundaries()
+{
+	CLAMP(global_range_w, MIN_RADIUS, MAX_RADIUS);
+	CLAMP(global_range_h, MIN_RADIUS, MAX_RADIUS);
+	CLAMP(global_block_w, MIN_BLOCK, MAX_BLOCK);
+	CLAMP(global_block_h, MIN_BLOCK, MAX_BLOCK);
+	CLAMP(block_x, 0, 100);
+	CLAMP(block_y, 0, 100);
+	CLAMP(object_layer, MIN_LAYER, MAX_LAYER);
+	CLAMP(replace_layer, MIN_LAYER, MAX_LAYER);
+	CLAMP(scene_layer, MIN_LAYER, MAX_LAYER);
+	CLAMP(vmin, MIN_CAMSHIFT, MAX_CAMSHIFT);
+	CLAMP(vmax, MIN_CAMSHIFT, MAX_CAMSHIFT);
+	CLAMP(smin, MIN_CAMSHIFT, MAX_CAMSHIFT);
+	CLAMP(blend, MIN_BLEND, MAX_BLEND);
+}
+
+int FindObjectConfig::equivalent(FindObjectConfig &that)
+{
+	int result = 
+		global_range_w == that.global_range_w &&
+		global_range_h == that.global_range_h &&
+		draw_keypoints == that.draw_keypoints &&
+		draw_border == that.draw_border &&
+		replace_object == that.replace_object &&
+		draw_object_border == that.draw_object_border &&
+		global_block_w == that.global_block_w &&
+		global_block_h == that.global_block_h &&
+		block_x == that.block_x &&
+		block_y == that.block_y &&
+		object_layer == that.object_layer &&
+		replace_layer == that.replace_layer &&
+		scene_layer == that.scene_layer &&
+		algorithm == that.algorithm &&
+		vmin == that.vmin &&
+		vmax == that.vmax &&
+		smin == that.smin &&
+		blend == that.blend;
+	return result;
+}
+
+void FindObjectConfig::copy_from(FindObjectConfig &that)
+{
+	global_range_w = that.global_range_w;
+	global_range_h = that.global_range_h;
+	draw_keypoints = that.draw_keypoints;
+	draw_border = that.draw_border;
+	replace_object = that.replace_object;
+	draw_object_border = that.draw_object_border;
+	global_block_w = that.global_block_w;
+	global_block_h = that.global_block_h;
+	block_x = that.block_x;
+	block_y = that.block_y;
+	object_layer = that.object_layer;
+	replace_layer = that.replace_layer;
+	scene_layer = that.scene_layer;
+	algorithm = that.algorithm;
+	vmin = that.vmin;
+	vmax = that.vmax;
+	smin = that.smin;
+	blend = that.blend;
+}
+
+void FindObjectConfig::interpolate(FindObjectConfig &prev, 
+	FindObjectConfig &next, 
+	int64_t prev_frame, 
+	int64_t next_frame, 
+	int64_t current_frame)
+{
+	copy_from(prev);
+}
+
+
+
+
+
+
+
+
+FindObjectMain::FindObjectMain(PluginServer *server)
+ : PluginVClient(server)
+{
+	PLUGIN_CONSTRUCTOR_MACRO
+	bzero(&blob_param, sizeof(CvBlobTrackerAutoParam1));
+	blob_pTracker = 0;
+
+
+	object_image = 0;
+	prev_object = 0;
+	scene_image = 0;
+	object_image_w = 0;
+	object_image_h = 0;
+	scene_image_w = 0;
+	scene_image_h = 0;
+	storage = 0;
+	object_keypoints = 0;
+	object_descriptors = 0;
+	scene_keypoints = 0;
+	scene_descriptors = 0;
+	affine = 0;
+	temp = 0;
+	overlayer = 0;
+	init_border = 1;
+}
+
+FindObjectMain::~FindObjectMain()
+{
+// This releases all the arrays
+	if(storage) cvReleaseMemStorage(&storage);
+	if(object_image) cvReleaseImage(&object_image);
+	if(scene_image) cvReleaseImage(&scene_image);
+	if(prev_object) delete [] prev_object;
+	delete affine;
+	delete temp;
+	delete overlayer;
+	
+    if(blob_param.pBT) cvReleaseBlobTracker(&blob_param.pBT);
+    if(blob_param.pBD) cvReleaseBlobDetector(&blob_param.pBD);
+    if(blob_param.pBTGen) cvReleaseBlobTrackGen(&blob_param.pBTGen);
+    if(blob_param.pBTA) cvReleaseBlobTrackAnalysis(&blob_param.pBTA);
+    if(blob_param.pFG) cvReleaseFGDetector(&blob_param.pFG);
+    if(blob_pTracker) cvReleaseBlobTrackerAuto(&blob_pTracker);
+
+    PLUGIN_DESTRUCTOR_MACRO
+}
+
+const char* FindObjectMain::plugin_title() { return N_("Find Object"); }
+int FindObjectMain::is_realtime() { return 1; }
+int FindObjectMain::is_multichannel() { return 1; }
+
+
+PLUGIN_THREAD_OBJECT(FindObjectMain, FindObjectThread, FindObjectWindow)
+
+SHOW_GUI_MACRO(FindObjectMain, FindObjectThread)
+RAISE_WINDOW_MACRO(FindObjectMain)
+SET_STRING_MACRO(FindObjectMain)
+LOAD_CONFIGURATION_MACRO(FindObjectMain, FindObjectConfig)
+
+VFrame* FindObjectMain::new_picon() { return NULL; }
+
+void FindObjectMain::update_gui()
+{
+	if(thread)
+	{
+		if(load_configuration())
+		{
+			thread->window->lock_window("FindObjectMain::update_gui");
+			
+			char string[BCTEXTLEN];
+
+			((FindObjectWindow*)thread->window)->global_range_w->update(config.global_range_w);
+			((FindObjectWindow*)thread->window)->global_range_h->update(config.global_range_h);
+			((FindObjectWindow*)thread->window)->global_block_w->update(config.global_block_w);
+			((FindObjectWindow*)thread->window)->global_block_h->update(config.global_block_h);
+			((FindObjectWindow*)thread->window)->block_x->update(config.block_x);
+			((FindObjectWindow*)thread->window)->block_y->update(config.block_y);
+			((FindObjectWindow*)thread->window)->block_x_text->update((float)config.block_x);
+			((FindObjectWindow*)thread->window)->block_y_text->update((float)config.block_y);
+
+			((FindObjectWindow*)thread->window)->draw_keypoints->update(config.draw_keypoints);
+			((FindObjectWindow*)thread->window)->draw_border->update(config.draw_border);
+			((FindObjectWindow*)thread->window)->replace_object->update(config.replace_object);
+			((FindObjectWindow*)thread->window)->draw_object_border->update(config.draw_object_border);
+
+
+			((FindObjectWindow*)thread->window)->object_layer->update(
+				(int64_t)config.object_layer);
+			((FindObjectWindow*)thread->window)->replace_layer->update(
+				(int64_t)config.replace_layer);
+			((FindObjectWindow*)thread->window)->scene_layer->update(
+				(int64_t)config.scene_layer);
+			((FindObjectWindow*)thread->window)->algorithm->set_text(
+				FindObjectAlgorithm::to_text(config.algorithm));
+
+			((FindObjectWindow*)thread->window)->vmin->update(
+				(int64_t)config.vmin);
+			((FindObjectWindow*)thread->window)->vmax->update(
+				(int64_t)config.vmax);
+			((FindObjectWindow*)thread->window)->smin->update(
+				(int64_t)config.smin);
+			((FindObjectWindow*)thread->window)->blend->update(
+				(int64_t)config.blend);
+
+			((FindObjectWindow*)thread->window)->flush();
+			thread->window->unlock_window();
+		}
+// printf("FindObjectMain::update_gui %d %d %d %d\n", 
+// __LINE__, 
+// config.mode1,
+// config.mode2,
+// config.mode3);
+	}
+}
+
+
+
+
+void FindObjectMain::save_data(KeyFrame *keyframe)
+{
+	FileXML output;
+
+// cause data to be stored directly in text
+	output.set_shared_string(keyframe->get_data(), MESSAGESIZE);
+	output.tag.set_title("FINDOBJECT");
+
+	output.tag.set_property("GLOBAL_BLOCK_W", config.global_block_w);
+	output.tag.set_property("GLOBAL_BLOCK_H", config.global_block_h);
+	output.tag.set_property("BLOCK_X", config.block_x);
+	output.tag.set_property("BLOCK_Y", config.block_y);
+	output.tag.set_property("GLOBAL_RANGE_W", config.global_range_w);
+	output.tag.set_property("GLOBAL_RANGE_H", config.global_range_h);
+	output.tag.set_property("DRAW_KEYPOINTS", config.draw_keypoints);
+	output.tag.set_property("DRAW_BORDER", config.draw_border);
+	output.tag.set_property("REPLACE_OBJECT", config.replace_object);
+	output.tag.set_property("DRAW_OBJECT_BORDER", config.draw_object_border);
+	output.tag.set_property("OBJECT_LAYER", config.object_layer);
+	output.tag.set_property("REPLACE_LAYER", config.replace_layer);
+	output.tag.set_property("SCENE_LAYER", config.scene_layer);
+	output.tag.set_property("ALGORITHM", config.algorithm);
+	output.tag.set_property("VMIN", config.vmin);
+	output.tag.set_property("VMAX", config.vmax);
+	output.tag.set_property("SMIN", config.smin);
+	output.tag.set_property("BLEND", config.blend);
+	output.append_tag();
+	output.terminate_string();
+}
+
+void FindObjectMain::read_data(KeyFrame *keyframe)
+{
+	FileXML input;
+
+	input.set_shared_string(keyframe->get_data(), strlen(keyframe->get_data()));
+
+	int result = 0;
+
+	while(!result)
+	{
+		result = input.read_tag();
+
+		if(!result)
+		{
+			if(input.tag.title_is("FINDOBJECT"))
+			{
+				config.global_block_w = input.tag.get_property("GLOBAL_BLOCK_W", config.global_block_w);
+				config.global_block_h = input.tag.get_property("GLOBAL_BLOCK_H", config.global_block_h);
+				config.block_x = input.tag.get_property("BLOCK_X", config.block_x);
+				config.block_y = input.tag.get_property("BLOCK_Y", config.block_y);
+				config.global_range_w = input.tag.get_property("GLOBAL_RANGE_W", config.global_range_w);
+				config.global_range_h = input.tag.get_property("GLOBAL_RANGE_H", config.global_range_h);
+				config.draw_keypoints = input.tag.get_property("DRAW_KEYPOINTS", config.draw_keypoints);
+				config.draw_border = input.tag.get_property("DRAW_BORDER", config.draw_border);
+				config.replace_object = input.tag.get_property("REPLACE_OBJECT", config.replace_object);
+				config.draw_object_border = input.tag.get_property("DRAW_OBJECT_BORDER", config.draw_object_border);
+				config.object_layer = input.tag.get_property("OBJECT_LAYER", config.object_layer);
+				config.replace_layer = input.tag.get_property("REPLACE_LAYER", config.replace_layer);
+				config.scene_layer = input.tag.get_property("SCENE_LAYER", config.scene_layer);
+				config.algorithm = input.tag.get_property("ALGORITHM", config.algorithm);
+				config.vmin = input.tag.get_property("VMIN", config.vmin);
+				config.vmax = input.tag.get_property("VMAX", config.vmax);
+				config.smin = input.tag.get_property("SMIN", config.smin);
+				config.blend = input.tag.get_property("BLEND", config.blend);
+			}
+		}
+	}
+	config.boundaries();
+}
+
+
+
+
+
+void FindObjectMain::draw_pixel(VFrame *frame, int x, int y)
+{
+	if(!(x >= 0 && y >= 0 && x < frame->get_w() && y < frame->get_h())) return;
+
+#define DRAW_PIXEL(x, y, components, do_yuv, max, type) \
+{ \
+	type **rows = (type**)frame->get_rows(); \
+	rows[y][x * components] = max - rows[y][x * components]; \
+	if(!do_yuv) \
+	{ \
+		rows[y][x * components + 1] = max - rows[y][x * components + 1]; \
+		rows[y][x * components + 2] = max - rows[y][x * components + 2]; \
+	} \
+	else \
+	{ \
+		rows[y][x * components + 1] = (max / 2 + 1) - rows[y][x * components + 1]; \
+		rows[y][x * components + 2] = (max / 2 + 1) - rows[y][x * components + 2]; \
+	} \
+	if(components == 4) \
+		rows[y][x * components + 3] = max; \
+}
+
+
+	switch(frame->get_color_model())
+	{
+		case BC_RGB888:
+			DRAW_PIXEL(x, y, 3, 0, 0xff, unsigned char);
+			break;
+		case BC_RGBA8888:
+			DRAW_PIXEL(x, y, 4, 0, 0xff, unsigned char);
+			break;
+		case BC_RGB_FLOAT:
+			DRAW_PIXEL(x, y, 3, 0, 1.0, float);
+			break;
+		case BC_RGBA_FLOAT:
+			DRAW_PIXEL(x, y, 4, 0, 1.0, float);
+			break;
+		case BC_YUV888:
+			DRAW_PIXEL(x, y, 3, 1, 0xff, unsigned char);
+			break;
+		case BC_YUVA8888:
+			DRAW_PIXEL(x, y, 4, 1, 0xff, unsigned char);
+			break;
+		case BC_RGB161616:
+			DRAW_PIXEL(x, y, 3, 0, 0xffff, uint16_t);
+			break;
+		case BC_YUV161616:
+			DRAW_PIXEL(x, y, 3, 1, 0xffff, uint16_t);
+			break;
+		case BC_RGBA16161616:
+			DRAW_PIXEL(x, y, 4, 0, 0xffff, uint16_t);
+			break;
+		case BC_YUVA16161616:
+			DRAW_PIXEL(x, y, 4, 1, 0xffff, uint16_t);
+			break;
+	}
+}
+
+
+void FindObjectMain::draw_line(VFrame *frame, int x1, int y1, int x2, int y2)
+{
+	int w = labs(x2 - x1);
+	int h = labs(y2 - y1);
+//printf("FindObjectMain::draw_line 1 %d %d %d %d\n", x1, y1, x2, y2);
+
+	if(!w && !h)
+	{
+		draw_pixel(frame, x1, y1);
+	}
+	else
+	if(w > h)
+	{
+// Flip coordinates so x1 < x2
+		if(x2 < x1)
+		{
+			y2 ^= y1;
+			y1 ^= y2;
+			y2 ^= y1;
+			x1 ^= x2;
+			x2 ^= x1;
+			x1 ^= x2;
+		}
+		int numerator = y2 - y1;
+		int denominator = x2 - x1;
+		for(int i = x1; i <= x2; i++)
+		{
+			int y = y1 + (int64_t)(i - x1) * (int64_t)numerator / (int64_t)denominator;
+			draw_pixel(frame, i, y);
+		}
+	}
+	else
+	{
+// Flip coordinates so y1 < y2
+		if(y2 < y1)
+		{
+			y2 ^= y1;
+			y1 ^= y2;
+			y2 ^= y1;
+			x1 ^= x2;
+			x2 ^= x1;
+			x1 ^= x2;
+		}
+		int numerator = x2 - x1;
+		int denominator = y2 - y1;
+		for(int i = y1; i <= y2; i++)
+		{
+			int x = x1 + (int64_t)(i - y1) * (int64_t)numerator / (int64_t)denominator;
+			draw_pixel(frame, x, i);
+		}
+	}
+//printf("FindObjectMain::draw_line 2\n");
+}
+
+void FindObjectMain::draw_rect(VFrame *frame, int x1, int y1, int x2, int y2)
+{
+	draw_line(frame, x1, y1, x2, y1);
+	draw_line(frame, x2, y1 + 1, x2, y2);
+	draw_line(frame, x2 - 1, y2, x1, y2);
+	draw_line(frame, x1, y2 - 1, x1, y1 + 1);
+}
+
+
+
+// Convert to greyscale & crop
+void FindObjectMain::grey_crop(unsigned char *dst, 
+	VFrame *src, 
+	int x1, 
+	int y1,
+	int x2,
+	int y2,
+	int dst_w,
+	int dst_h)
+{
+// Dimensions of dst frame
+	int w = x2 - x1;
+	int h = y2 - y1;
+
+	bzero(dst, dst_w * dst_h);
+
+//printf("FindObjectMain::grey_crop %d %d %d\n", __LINE__, w, h);
+	for(int i = 0; i < h; i++)
+	{
+
+#define RGB_TO_VALUE(r, g, b) \
+((r) * R_TO_Y + (g) * G_TO_Y + (b) * B_TO_Y)
+
+
+#define CONVERT(in_type, max, components, is_yuv) \
+{ \
+	in_type *input = ((in_type*)src->get_rows()[i + y1]) + x1 * components; \
+	unsigned char *output = dst + i * dst_w; \
+ \
+	for(int j = 0; j < w; j++) \
+	{ \
+/* Y channel only */ \
+		if(is_yuv) \
+		{ \
+			*output = *input; \
+		} \
+/* RGB */ \
+		else \
+		{ \
+			float r = (float)input[0] / max; \
+			float g = (float)input[1] / max; \
+			float b = (float)input[2] / max; \
+			*output = RGB_TO_VALUE(r, g, b); \
+		} \
+ \
+		input += components; \
+		output++; \
+	} \
+}
+		switch(src->get_color_model())
+		{
+			case BC_RGB888:
+			{
+				CONVERT(unsigned char, 0xff, 3, 0)
+				break;
+			}
+
+			case BC_RGBA8888:
+			{
+				CONVERT(unsigned char, 0xff, 4, 0)
+				break;
+			}
+
+			case BC_RGB_FLOAT:
+			{
+				CONVERT(float, 1.0, 3, 0)
+				break;
+			}
+
+			case BC_RGBA_FLOAT:
+			{
+				CONVERT(float, 1.0, 4, 0)
+				break;
+			}
+
+			case BC_YUV888:
+			{
+				CONVERT(unsigned char, 0xff, 3, 1)
+				break;
+			}
+
+			case BC_YUVA8888:
+			{
+				CONVERT(unsigned char, 0xff, 4, 1)
+				break;
+			}
+		}
+	}
+}
+
+
+void FindObjectMain::process_surf()
+{
+
+	if(!object_image)
+	{
+// Only does greyscale
+		object_image = cvCreateImage( 
+			cvSize(object_image_w, object_image_h), 
+			8, 
+			1);
+	}
+
+	if(!scene_image)
+	{
+// Only does greyscale
+		scene_image = cvCreateImage( 
+			cvSize(scene_image_w, scene_image_h), 
+			8, 
+			1);
+	}
+
+// Select only region with image size
+// Does this do anything?
+	cvSetImageROI( object_image, cvRect( 0, 0, object_w, object_h ) );
+	cvSetImageROI( scene_image, cvRect( 0, 0, scene_w, scene_h ) );
+
+	if(!prev_object) prev_object = new unsigned char[object_image_w * object_image_h];
+	memcpy(prev_object, object_image->imageData, object_image_w * object_image_h);
+	grey_crop((unsigned char*)scene_image->imageData, 
+		get_input(scene_layer), 
+		scene_x1, 
+		scene_y1, 
+		scene_x2, 
+		scene_y2,
+		scene_image_w,
+		scene_image_h);
+
+
+	grey_crop((unsigned char*)object_image->imageData, 
+		get_input(object_layer), 
+		object_x1, 
+		object_y1, 
+		object_x2, 
+		object_y2,
+		object_image_w,
+		object_image_h);
+
+
+	if(!storage) storage = cvCreateMemStorage(0);
+	CvSURFParams params = cvSURFParams(500, 1);
+
+
+//printf("FindObjectMain::process_surf %d\n", __LINE__);
+
+// Only compute keypoints if the image changed
+	if(memcmp(prev_object, object_image->imageData, object_image_w * object_image_h))
+	{
+		if(object_keypoints) cvClearSeq(object_keypoints);
+		if(object_descriptors) cvClearSeq(object_descriptors);
+		cvExtractSURF(object_image, 
+			0, 
+			&object_keypoints, 
+			&object_descriptors, 
+			storage, 
+			params,
+			0);
+	}
+
+//printf("FindObjectMain::process_surf %d object keypoints=%d\n", __LINE__, object_keypoints->total);
+// Draw the keypoints
+// 		for(int i = 0; i < object_keypoints->total; i++)
+// 		{
+//         	CvSURFPoint* r1 = (CvSURFPoint*)cvGetSeqElem( object_keypoints, i );
+// 			int size = r1->size / 4;
+// 			draw_rect(frame[object_layer], 
+//   				r1->pt.x + object_x1 - size, 
+//   				r1->pt.y + object_y1 - size, 
+//   				r1->pt.x + object_x1 + size, 
+//  				r1->pt.y + object_y1 + size);
+// 		}
+
+
+//printf("FindObjectMain::process_surf %d\n", __LINE__);
+
+// TODO: make the surf data persistent & check for image changes instead
+	if(scene_keypoints) cvClearSeq(scene_keypoints);
+	if(scene_descriptors) cvClearSeq(scene_descriptors);
+	cvExtractSURF(scene_image, 
+		0, 
+		&scene_keypoints, 
+		&scene_descriptors, 
+		storage, 
+		params,
+		0);
+
+// Draw the keypoints
+// 		for(int i = 0; i < scene_keypoints->total; i++)
+// 		{
+//         	CvSURFPoint* r1 = (CvSURFPoint*)cvGetSeqElem( scene_keypoints, i );
+// 			int size = r1->size / 4;
+// 			draw_rect(frame[scene_layer], 
+//   				r1->pt.x + scene_x1 - size, 
+//   				r1->pt.y + scene_y1 - size, 
+//   				r1->pt.x + scene_x1 + size, 
+//  				r1->pt.y + scene_y1 + size);
+// 		}
+
+// printf("FindObjectMain::process_surf %d %d %d scene keypoints=%d\n", 
+// __LINE__, 
+// scene_w,
+// scene_h,
+// scene_keypoints->total);
+
+	int *point_pairs = 0;
+	int total_pairs = 0;
+	CvPoint src_corners[4] = 
+	{
+		{ 0, 0 }, 
+		{ object_w, 0 }, 
+		{ object_w, object_h }, 
+		{ 0, object_h }
+	};
+
+	CvPoint dst_corners[4] = 
+	{
+		{ 0, 0 },
+		{ 0, 0 },
+		{ 0, 0 },
+		{ 0, 0 }
+	};
+
+//printf("FindObjectMain::process_surf %d\n", __LINE__);
+	if(scene_keypoints->total &&
+		object_keypoints->total &&
+		locatePlanarObject(object_keypoints, 
+		object_descriptors, 
+		scene_keypoints, 
+		scene_descriptors, 
+		src_corners, 
+		dst_corners,
+		&point_pairs,
+		&total_pairs))
+	{
+
+
+
+
+
+// Draw keypoints in the scene & object layer
+		if(config.draw_keypoints)
+		{
+//printf("FindObjectMain::process_surf %d total pairs=%d\n", __LINE__, total_pairs);
+			for(int i = 0; i < total_pairs; i++)
+			{
+        		CvSURFPoint* r1 = (CvSURFPoint*)cvGetSeqElem( object_keypoints, point_pairs[i * 2] );
+        		CvSURFPoint* r2 = (CvSURFPoint*)cvGetSeqElem( scene_keypoints, point_pairs[i * 2 + 1] );
+
+
+				int size = r2->size * 1.2 / 9 * 2;
+				draw_rect(get_input(scene_layer), 
+  					r2->pt.x + scene_x1 - size, 
+  					r2->pt.y + scene_y1 - size, 
+  					r2->pt.x + scene_x1 + size, 
+ 					r2->pt.y + scene_y1 + size);
+				draw_rect(get_input(object_layer), 
+  					r1->pt.x + object_x1 - size, 
+  					r1->pt.y + object_y1 - size, 
+  					r1->pt.x + object_x1 + size, 
+ 					r1->pt.y + object_y1 + size);
+			}
+		}
+
+
+//printf("FindObjectMain::process_surf %d\n", __LINE__);
+// Get object outline in the scene layer
+		border_x1 = dst_corners[0].x + scene_x1;
+		border_y1 = dst_corners[0].y + scene_y1;
+		border_x2 = dst_corners[1].x + scene_x1;
+		border_y2 = dst_corners[1].y + scene_y1;
+		border_x3 = dst_corners[2].x + scene_x1;
+		border_y3 = dst_corners[2].y + scene_y1;
+		border_x4 = dst_corners[3].x + scene_x1;
+		border_y4 = dst_corners[3].y + scene_y1;
+//printf("FindObjectMain::process_surf %d\n", __LINE__);
+
+
+		
+	}
+//printf("FindObjectMain::process_surf %d\n", __LINE__);
+
+
+
+// for(int i = 0; i < object_y2 - object_y1; i++)
+// {
+// 	unsigned char *dst = get_input(object_layer)->get_rows()[i];
+// 	unsigned char *src = (unsigned char*)object_image->imageData + i * (object_x2 - object_x1);
+// 	for(int j = 0; j < object_x2 - object_x1; j++)
+// 	{
+// 		*dst++ = *src;
+// 		*dst++ = 0x80;
+// 		*dst++ = 0x80;
+// 		src++;
+// 	}
+// }
+
+
+// Frees the image structures
+	if(point_pairs) free(point_pairs);
+}
+
+
+
+void FindObjectMain::process_camshift()
+{
+// Some user defined parameters
+	int vmin = config.vmin;
+	int vmax = config.vmax;
+	int smin = config.smin;
+	float hranges[] = { 0, 180 };
+	const float* phranges = hranges;
+
+
+// Create aligned, RGB images
+	if(!object_image)
+	{
+		object_image = cvCreateImage( 
+			cvSize(object_image_w, object_image_h), 
+			8, 
+			3);
+	}
+
+	if(!scene_image)
+	{
+		scene_image = cvCreateImage( 
+			cvSize(scene_image_w, scene_image_h), 
+			8, 
+			3);
+	}
+
+// Temporary row pointers
+	unsigned char **object_rows = new unsigned char*[object_image_h];
+	unsigned char **scene_rows = new unsigned char*[scene_image_h];
+	for(int i = 0; i < object_image_h; i++)
+	{
+		object_rows[i] = (unsigned char*)(object_image->imageData + i * object_image_w * 3);
+	}
+	for(int i = 0; i < scene_image_h; i++)
+	{
+		scene_rows[i] = (unsigned char*)(scene_image->imageData + i * scene_image_w * 3);
+	}
+
+// Transfer object & scene to RGB images for OpenCV
+	if(!prev_object) prev_object = new unsigned char[object_image_w * object_image_h * 3];
+// Back up old object image
+	memcpy(prev_object, object_image->imageData, object_image_w * object_image_h * 3);
+
+	BC_CModels::transfer(object_rows,
+		get_input(object_layer)->get_rows(),
+		0,
+		0,
+		0,
+		0,
+		0,
+		0,
+		object_x1,
+		object_y1,
+		object_w,
+		object_h,
+		0,
+		0,
+		object_w,
+		object_h,
+		get_input(object_layer)->get_color_model(),
+		BC_RGB888,
+		0,
+		0,
+		0);
+	BC_CModels::transfer(scene_rows,
+		get_input(scene_layer)->get_rows(),
+		0,
+		0,
+		0,
+		0,
+		0,
+		0,
+		scene_x1,
+		scene_y1,
+		scene_w,
+		scene_h,
+		0,
+		0,
+		scene_w,
+		scene_h,
+		get_input(scene_layer)->get_color_model(),
+		BC_RGB888,
+		0,
+		0,
+		0);
+
+	delete [] object_rows;
+	delete [] scene_rows;
+
+// from camshiftdemo.cpp
+// Compute new object	
+	if(memcmp(prev_object, 
+		object_image->imageData, 
+		object_image_w * object_image_h * 3) ||
+		!hist.dims)
+	{
+		Mat image(object_image);
+		Mat hsv, hue, mask;
+		cvtColor(image, hsv, CV_RGB2HSV);
+    	int _vmin = vmin, _vmax = vmax;
+//printf("FindObjectMain::process_camshift %d\n", __LINE__);
+
+    	inRange(hsv, 
+			Scalar(0, smin, MIN(_vmin,_vmax)),
+        	Scalar(180, 256, MAX(_vmin, _vmax)), 
+			mask);
+    	int ch[] = { 0, 0 };
+    	hue.create(hsv.size(), hsv.depth());
+    	mixChannels(&hsv, 1, &hue, 1, ch, 1);
+
+		Rect selection = Rect(0, 0, object_w, object_h);
+		trackWindow = selection;
+		int hsize = 16;
+		Mat roi(hue, selection), maskroi(mask, selection);
+		calcHist(&roi, 1, 0, maskroi, hist, 1, &hsize, &phranges);
+		normalize(hist, hist, 0, 255, CV_MINMAX);
+	}
+
+
+// compute scene
+	Mat image(scene_image);
+	Mat hsv, hue, mask, backproj;
+	cvtColor(image, hsv, CV_RGB2HSV);
+    int _vmin = vmin, _vmax = vmax;
+
+    inRange(hsv, 
+		Scalar(0, smin, MIN(_vmin,_vmax)),
+        Scalar(180, 256, MAX(_vmin, _vmax)), 
+		mask);
+    int ch[] = {0, 0};
+    hue.create(hsv.size(), hsv.depth());
+    mixChannels(&hsv, 1, &hue, 1, ch, 1);
+	
+//printf("FindObjectMain::process_camshift %d %d %d\n", __LINE__, hist.dims, hist.size[1]);
+	RotatedRect trackBox = RotatedRect(
+		Point2f((object_x1 + object_x2) / 2, (object_y1 + object_y2) / 2), 
+		Size2f(object_w, object_h), 
+		0);
+	trackWindow = Rect(0, 
+		0,
+        scene_w, 
+		scene_h);
+	if(hist.dims > 0)
+	{
+		
+
+		calcBackProject(&hue, 1, 0, hist, backproj, &phranges);
+		backproj &= mask;
+//printf("FindObjectMain::process_camshift %d\n", __LINE__);
+// 		if(trackWindow.width <= 0 ||
+// 			trackWindow.height <= 0)
+// 		{
+// 			trackWindow.width = object_w;
+// 			trackWindow.height = object_h;
+// 		}
+
+		trackBox = CamShift(backproj, 
+			trackWindow,
+        	TermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ));
+//printf("FindObjectMain::process_camshift %d\n", __LINE__);
+
+
+//     	if( trackWindow.area() <= 1 )
+//     	{
+//         	int cols = backproj.cols;
+// 			int rows = backproj.rows;
+// 			int r = (MIN(cols, rows) + 5) / 6;
+//         	trackWindow = Rect(trackWindow.x - r, trackWindow.y - r,
+//                         	   trackWindow.x + r, trackWindow.y + r) &
+//                     	  Rect(0, 0, cols, rows);
+//     	}
+	}
+// printf("FindObjectMain::process_camshift %d %d %d %d %d\n", 
+// __LINE__,
+// trackWindow.x,
+// trackWindow.y,
+// trackWindow.width,
+// trackWindow.height);
+
+
+// Draw mask over scene
+	if(config.draw_keypoints)
+	{
+		for(int i = 0; i < scene_h; i++)
+		{
+			switch(get_input(scene_layer)->get_color_model())
+			{
+				case BC_YUV888:
+				{
+					unsigned char *input = backproj.data + i * scene_image_w;
+					unsigned char *output = get_input(scene_layer)->get_rows()[i + scene_y1] + scene_x1 * 3;
+					for(int j = 0; j < scene_w; j++)
+					{
+						output[0] = *input;
+						output[1] = 0x80;
+						output[2] = 0x80;
+						output += 3;
+						input++;
+					}
+					break;
+				}
+			}
+		}
+	}
+
+// Get object outline in the scene layer
+// printf("FindObjectMain::process_camshift %d %d %d %d %d %d\n", 
+// __LINE__,
+// (int)trackBox.center.x,
+// (int)trackBox.center.y,
+// (int)trackBox.size.width,
+// (int)trackBox.size.height,
+// (int)trackBox.angle);
+	double angle = trackBox.angle * 2 * M_PI / 360;
+	double angle1 = atan2(-(double)trackBox.size.height / 2, -(double)trackBox.size.width / 2) + angle;
+	double angle2 = atan2(-(double)trackBox.size.height / 2, (double)trackBox.size.width / 2) + angle;
+	double angle3 = atan2((double)trackBox.size.height / 2, (double)trackBox.size.width / 2) + angle;
+	double angle4 = atan2((double)trackBox.size.height / 2, -(double)trackBox.size.width / 2) + angle;
+	double radius = sqrt(SQR(trackBox.size.height / 2) + SQR(trackBox.size.width / 2));
+	border_x1 = (int)(trackBox.center.x + cos(angle1) * radius) + scene_x1;
+	border_y1 = (int)(trackBox.center.y + sin(angle1) * radius) + scene_y1;
+	border_x2 = (int)(trackBox.center.x + cos(angle2) * radius) + scene_x1;
+	border_y2 = (int)(trackBox.center.y + sin(angle2) * radius) + scene_y1;
+	border_x3 = (int)(trackBox.center.x + cos(angle3) * radius) + scene_x1;
+	border_y3 = (int)(trackBox.center.y + sin(angle3) * radius) + scene_y1;
+	border_x4 = (int)(trackBox.center.x + cos(angle4) * radius) + scene_x1;
+	border_y4 = (int)(trackBox.center.y + sin(angle4) * radius) + scene_y1;
+
+}
+
+
+#define APPLY_MASK(type, max, components, do_yuv) \
+{ \
+	type *output_row = (type*)get_input(scene_layer)->get_rows()[i]; \
+	unsigned char *mask_row = mask_rows[i]; \
+	int chroma_offset = (int)(max + 1) / 2; \
+ \
+	for(int j  = 0; j < scene_w; j++) \
+	{ \
+		if(components == 4) \
+		{ \
+			output_row[j * 4 + 3] = output_row[j * 4 + 3] * mask_row[j] / 255; \
+		} \
+		else \
+		{ \
+			output_row[j * 3] = output_row[j * 3] * mask_row[j] / 255; \
+			output_row[j * 3 + 1] = output_row[j * 3 + 1] * mask_row[j] / 255; \
+			output_row[j * 3 + 2] = output_row[j * 3 + 2] * mask_row[j] / 255; \
+ \
+			if(do_yuv) \
+			{ \
+				output_row[j * 3 + 1] += chroma_offset * (255 - mask_row[j]) / 255; \
+				output_row[j * 3 + 2] += chroma_offset * (255 - mask_row[j]) / 255; \
+			} \
+		} \
+	} \
+}
+
+
+
+// blobtrack_sample.cpp
+void FindObjectMain::process_blob()
+{
+	if(!blob_initialized)
+	{
+		blob_initialized = 1;
+		
+		blob_param.FGTrainFrames = 5;
+
+
+/* Create FG Detection module: */
+		blob_param.pFG = cvCreateFGDetectorBase(CV_BG_MODEL_FGD, NULL);
+/* Create Blob Entrance Detection module: */
+        blob_param.pBD = cvCreateBlobDetectorCC();
+/* Create blob tracker module: */
+        blob_param.pBT = cvCreateBlobTrackerCCMSPF();
+/* Create whole pipline: */
+        blob_pTracker = cvCreateBlobTrackerAuto1(&blob_param);
+		
+	}
+
+
+/* Process: */
+	IplImage*   pMask = NULL;
+
+// Create aligned, RGB images
+	if(!scene_image)
+	{
+		scene_image = cvCreateImage( 
+			cvSize(scene_image_w, scene_image_h), 
+			8, 
+			3);
+	}
+
+// Temporary row pointers
+	unsigned char **scene_rows = new unsigned char*[scene_image_h];
+	for(int i = 0; i < scene_image_h; i++)
+	{
+		scene_rows[i] = (unsigned char*)(scene_image->imageData + i * scene_image_w * 3);
+	}
+
+	BC_CModels::transfer(scene_rows,
+		get_input(scene_layer)->get_rows(),
+		0,
+		0,
+		0,
+		0,
+		0,
+		0,
+		scene_x1,
+		scene_y1,
+		scene_w,
+		scene_h,
+		0,
+		0,
+		scene_w,
+		scene_h,
+		get_input(scene_layer)->get_color_model(),
+		BC_RGB888,
+		0,
+		0,
+		0);
+
+	delete [] scene_rows;
+
+    blob_pTracker->Process(scene_image, pMask);
+printf("FindObjectMain::process_blob %d %jd %d\n", __LINE__, get_source_position(), blob_pTracker->GetBlobNum());
+
+
+#if 0
+	if(blob_pTracker->GetFGMask())
+	{
+		IplImage* pFG = blob_pTracker->GetFGMask();
+printf("FindObjectMain::process_blob %d %ld\n", __LINE__, get_source_position());
+		
+// Temporary row pointers
+		unsigned char **mask_rows = new unsigned char*[scene_image_h];
+		for(int i = 0; i < scene_image_h; i++)
+		{
+			mask_rows[i] = (unsigned char*)(pFG->imageData + i * scene_image_w);
+		}
+
+		for(int i = 0; i < scene_image_h; i++)
+		{
+			switch(get_input(scene_layer)->get_color_model())
+			{
+				case BC_RGB888:
+					APPLY_MASK(unsigned char, 0xff, 3, 0)
+					break;
+				case BC_RGB_FLOAT:
+					APPLY_MASK(float, 1.0, 3, 0)
+					break;
+				case BC_YUV888:
+					APPLY_MASK(unsigned char, 0xff, 3, 1)
+					break;
+				case BC_RGBA8888:
+					APPLY_MASK(unsigned char, 0xff, 4, 0)
+					break;
+				case BC_RGBA_FLOAT:
+					APPLY_MASK(float, 1.0, 4, 0)
+					break;
+				case BC_YUVA8888:
+					APPLY_MASK(unsigned char, 0xff, 4, 1)
+					break;
+			}
+		}
+
+		delete [] mask_rows;
+
+		
+	}
+#endif
+	
+
+}
+
+
+
+
+
+
+
+int FindObjectMain::process_buffer(VFrame **frame,
+	int64_t start_position,
+	double frame_rate)
+{
+	int prev_algorithm = config.algorithm;
+	if(load_configuration())
+	{
+		init_border = 1;
+	}
+
+	w = frame[0]->get_w();
+	h = frame[0]->get_h();
+//printf("FindObjectMain::process_buffer %d\n", __LINE__);
+
+
+// Get the layer containing the object.
+	object_layer = config.object_layer;
+// Get the layer to search in.
+	scene_layer = config.scene_layer;
+// Get the layer with the replacement object
+	replace_layer = config.replace_layer;
+
+	object_layer = MIN(object_layer, PluginClient::get_total_buffers() - 1);
+	scene_layer = MIN(scene_layer, PluginClient::get_total_buffers() - 1);
+	replace_layer = MIN(replace_layer, PluginClient::get_total_buffers() - 1);
+
+// printf("FindObjectMain::process_buffer %d %d %d %d %d %d\n", 
+// __LINE__,
+// PluginClient::get_total_buffers(),
+// config.object_layer,
+// config.scene_layer,
+// object_layer,
+// scene_layer);
+// 
+// Create cropped images
+// TODO: use oblique corners & affine transform
+	object_w = (int)(config.global_block_w * w / 100);
+	object_h = (int)(config.global_block_h * h / 100);
+
+	object_x1 = (int)(config.block_x * w / 100 - object_w / 2);
+	object_y1 = (int)(config.block_y * h / 100 - object_h / 2);
+	object_x2 = object_x1 + object_w;
+	object_y2 = object_y1 + object_h;
+	CLAMP(object_x1, 0, frame[0]->get_w() - 1);
+	CLAMP(object_x2, 0, frame[0]->get_w() - 1);
+	CLAMP(object_y1, 0, frame[0]->get_h() - 1);
+	CLAMP(object_y2, 0, frame[0]->get_h() - 1);
+	object_w = object_x2 - object_x1;
+	object_h = object_y2 - object_y1;
+
+
+	scene_w = (int)(config.global_range_w * w / 100);
+	scene_h = (int)(config.global_range_h * h / 100);
+	scene_x1 = (int)(config.block_x * w / 100 - scene_w / 2);
+	scene_y1 = (int)(config.block_y * h / 100 - scene_h / 2);
+	scene_x2 = scene_x1 + scene_w;
+	scene_y2 = scene_y1 + scene_h;
+	CLAMP(scene_x1, 0, frame[0]->get_w() - 1);
+	CLAMP(scene_x2, 0, frame[0]->get_w() - 1);
+	CLAMP(scene_y1, 0, frame[0]->get_h() - 1);
+	CLAMP(scene_y2, 0, frame[0]->get_h() - 1);
+	scene_w = scene_x2 - scene_x1;
+	scene_h = scene_y2 - scene_y1;
+
+// Get quantized sizes
+	int object_image_w = object_w;
+	int object_image_h = object_h;
+	int scene_image_w = scene_w;
+	int scene_image_h = scene_h;
+	if(object_w % QUANTIZE) object_image_w += QUANTIZE - (object_w % QUANTIZE);
+	if(object_h % QUANTIZE) object_image_h += QUANTIZE - (object_h % QUANTIZE);
+	if(scene_w % QUANTIZE) scene_image_w += QUANTIZE - (scene_w % QUANTIZE);
+	if(scene_h % QUANTIZE) scene_image_h += QUANTIZE - (scene_h % QUANTIZE);
+
+	if(object_image && 
+		(object_image_w != this->object_image_w ||
+		object_image_h != this->object_image_h ||
+		prev_algorithm != config.algorithm))
+	{
+		cvReleaseImage(&object_image);
+		object_image = 0;
+		delete [] prev_object;
+		prev_object = 0;
+	}
+	this->object_image_w = object_image_w;
+	this->object_image_h = object_image_h;
+
+	if(scene_image && 
+		(scene_image_w != this->scene_image_w ||
+		scene_image_h != this->scene_image_h ||
+		prev_algorithm != config.algorithm))
+	{
+		cvReleaseImage(&scene_image);
+		scene_image = 0;
+	}
+	this->scene_image_w = scene_image_w;
+	this->scene_image_h = scene_image_h;
+
+
+
+
+//printf("FindObjectMain::process_buffer %d object_w=%d object_h=%d object_image_w=%d object_image_h=%d\n", __LINE__, object_w, object_h, object_image_w, object_image_h);
+//printf("FindObjectMain::process_buffer %d scene_w=%d scene_h=%d scene_image_w=%d scene_image_h=%d\n", __LINE__, scene_w, scene_h, scene_image_w, scene_image_h);
+//printf("FindObjectMain::process_buffer %d total_layers=%d\n", __LINE__, get_total_buffers());
+
+// Read in the input frames
+	for(int i = 0; i < PluginClient::get_total_buffers(); i++)
+	{
+		read_frame(frame[i], 
+			i, 
+			start_position, 
+			frame_rate);
+	}
+
+
+// Search for object
+	if(config.algorithm != NO_ALGORITHM &&
+		(config.replace_object ||
+		config.draw_border ||
+		config.draw_keypoints))
+	{
+
+
+		switch(config.algorithm)
+		{
+#if HAVE_OPENCV_SURF
+			case ALGORITHM_SURF:
+				process_surf();
+				break;
+#endif
+
+			case ALGORITHM_CAMSHIFT:
+				process_camshift();
+				break;
+				
+			case ALGORITHM_BLOB:
+				process_blob();
+				break;
+		}
+
+
+		if(init_border)
+		{
+			border_x1_accum = border_x1;
+			border_y1_accum = border_y1;
+			border_x2_accum = border_x2;
+			border_y2_accum = border_y2;
+			border_x3_accum = border_x3;
+			border_y3_accum = border_y3;
+			border_x4_accum = border_x4;
+			border_y4_accum = border_y4;
+			init_border = 0;
+		}
+		else
+		{
+			border_x1_accum = (float)border_x1 * config.blend / 100 + 
+				border_x1_accum * (100 - config.blend) / 100;
+			border_y1_accum = (float)border_y1 * config.blend / 100 + 
+				border_y1_accum * (100 - config.blend) / 100;
+			border_x2_accum = (float)border_x2 * config.blend / 100 + 
+				border_x2_accum * (100 - config.blend) / 100;
+			border_y2_accum = (float)border_y2 * config.blend / 100 + 
+				border_y2_accum * (100 - config.blend) / 100;
+			border_x3_accum = (float)border_x3 * config.blend / 100 + 
+				border_x3_accum * (100 - config.blend) / 100;
+			border_y3_accum = (float)border_y3 * config.blend / 100 + 
+				border_y3_accum * (100 - config.blend) / 100;
+			border_x4_accum = (float)border_x4 * config.blend / 100 + 
+				border_x4_accum * (100 - config.blend) / 100;
+			border_y4_accum = (float)border_y4 * config.blend / 100 + 
+				border_y4_accum * (100 - config.blend) / 100;
+		}
+
+// Replace object in the scene layer
+		if(config.replace_object)
+		{
+
+// Some trickery to get the affine transform to alpha blend into the output
+			if(!affine) affine = new AffineEngine(get_project_smp() + 1,
+				get_project_smp() + 1);
+
+//printf("FindObjectMain::process_surf %d replace_layer=%d\n", __LINE__, replace_layer);
+			if(!temp)
+				temp = new VFrame(w, 
+					h, 
+					get_input(scene_layer)->get_color_model());
+			if(!overlayer)
+				overlayer = new OverlayFrame(get_project_smp() + 1);
+
+			temp->clear_frame();
+			affine->process(temp,
+				get_input(replace_layer),
+				0, 
+				AffineEngine::PERSPECTIVE,
+				border_x1_accum * 100 / w,
+				border_y1_accum * 100 / h,
+				border_x2_accum * 100 / w,
+				border_y2_accum * 100 / h,
+				border_x3_accum * 100 / w,
+				border_y3_accum * 100 / h,
+				border_x4_accum * 100 / w,
+				border_y4_accum * 100 / h,
+				1);
+
+			overlayer->overlay(get_input(scene_layer), 
+				temp, 
+				0, 
+				0, 
+				w, 
+				h, 
+				0, 
+				0, 
+				w, 
+				h, 
+				1,        // 0 - 1
+				TRANSFER_NORMAL,
+				NEAREST_NEIGHBOR);
+		}
+
+
+		if(config.draw_border)
+		{
+			draw_line(get_input(scene_layer), 
+				border_x1_accum, 
+				border_y1_accum, 
+				border_x2_accum, 
+				border_y2_accum);
+			draw_line(get_input(scene_layer), 
+				border_x2_accum, 
+				border_y2_accum, 
+				border_x3_accum, 
+				border_y3_accum);
+			draw_line(get_input(scene_layer), 
+				border_x3_accum, 
+				border_y3_accum, 
+				border_x4_accum, 
+				border_y4_accum);
+			draw_line(get_input(scene_layer), 
+				border_x4_accum, 
+				border_y4_accum, 
+				border_x1_accum, 
+				border_y1_accum);
+		}
+
+	}
+
+// Draw object outline in the object layer
+	if(config.draw_object_border)
+	{
+		draw_line(frame[object_layer], object_x1, object_y1, object_x2, object_y1);
+		draw_line(frame[object_layer], object_x2, object_y1, object_x2, object_y2);
+		draw_line(frame[object_layer], object_x2, object_y2, object_x1, object_y2);
+		draw_line(frame[object_layer], object_x1, object_y2, object_x1, object_y1);
+
+		draw_line(frame[object_layer], scene_x1, scene_y1, scene_x2, scene_y1);
+		draw_line(frame[object_layer], scene_x2, scene_y1, scene_x2, scene_y2);
+		draw_line(frame[object_layer], scene_x2, scene_y2, scene_x1, scene_y2);
+		draw_line(frame[object_layer], scene_x1, scene_y2, scene_x1, scene_y1);
+	}
+
+
+
+
+	return 0;
+}
+
+
diff --git a/plugins/findobject/findobject.h b/plugins/findobject/findobject.h
new file mode 100644
index 0000000..c406ba1
--- /dev/null
+++ b/plugins/findobject/findobject.h
@@ -0,0 +1,280 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 1997-2012 Adam Williams <broadcast at earthling dot net>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+
+
+// This is mainly a test for object tracking
+
+
+
+
+#ifndef FINDOBJECT_H
+#define FINDOBJECT_H
+
+#include "config.h"
+
+#include <math.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "affine.inc"
+#include "bchash.inc"
+#include "filexml.inc"
+#include "keyframe.inc"
+#include "findobjectwindow.inc"
+#include "overlayframe.inc"
+#include "pluginvclient.h"
+#include "vframe.inc"
+
+#include "opencv2/core/core_c.h"
+#include "opencv2/objdetect/objdetect.hpp"
+#include "opencv2/core/mat.hpp"
+#include "opencv2/imgproc/types_c.h"
+#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/legacy/blobtrack.hpp"
+
+class FindObjectMain;
+class FindObjectWindow;
+class FindObjectThread;
+
+using namespace cv;
+
+
+
+
+// Limits of global range in percent
+#define MIN_RADIUS 1
+#define MAX_RADIUS 200
+
+// Limits of block size in percent.
+#define MIN_BLOCK 1
+#define MAX_BLOCK 100
+
+#define MIN_LAYER 0
+#define MAX_LAYER 255
+
+#define MIN_BLEND 1
+#define MAX_BLEND 100
+
+// Sizes must be quantized a certain amount for OpenCV
+#define QUANTIZE 8
+
+// Storage for results
+#define FINDOBJECT_FILE "/tmp/findobject"
+
+#define MIN_CAMSHIFT 0
+#define MAX_CAMSHIFT 256
+
+
+#define NO_ALGORITHM 0
+#if HAVE_OPENCV_SURF
+#define ALGORITHM_SURF 1
+#endif
+#define ALGORITHM_CAMSHIFT 2
+#define ALGORITHM_BLOB 3
+
+class FindObjectConfig
+{
+public:
+	FindObjectConfig();
+
+	int equivalent(FindObjectConfig &that);
+	void copy_from(FindObjectConfig &that);
+	void interpolate(FindObjectConfig &prev, 
+		FindObjectConfig &next, 
+		int64_t prev_frame, 
+		int64_t next_frame, 
+		int64_t current_frame);
+	void boundaries();
+
+	int global_range_w;
+	int global_range_h;
+// Block size as percent of image size
+// Object must be a rectangle for the algorithm to work,
+// so no oblique edges unless we also do an affine transform.
+	float global_block_w;
+	float global_block_h;
+// Block position in percentage 0 - 100
+	float block_x;
+	float block_y;
+// Draw key points
+	int draw_keypoints;
+// Draw border over object in scene layer
+	int draw_border;
+// Draw transparency over object in object layer
+	int replace_object;
+// Draw border over object
+	int draw_object_border;
+
+// Which layer is the object 0 or 1
+	int object_layer;
+// Which layer replaces the object
+	int replace_layer;
+// Which layer is the object searched for in
+	int scene_layer;
+
+	int algorithm;
+// Camshift parameters
+	int vmin, vmax, smin;
+// Amount to blend new object position in
+	int blend;
+};
+
+
+
+
+class FindObjectMain : public PluginVClient
+{
+public:
+	FindObjectMain(PluginServer *server);
+	~FindObjectMain();
+
+	int process_buffer(VFrame **frame,
+		int64_t start_position,
+		double frame_rate);
+	void draw_vectors(VFrame *frame);
+	int is_multichannel();
+	int is_realtime();
+	void save_data(KeyFrame *keyframe);
+	void read_data(KeyFrame *keyframe);
+	void update_gui();
+// Calculate frame to copy from and frame to move
+	void calculate_pointers(VFrame **frame, VFrame **src, VFrame **dst);
+	void allocate_temp(int w, int h, int color_model);
+
+	PLUGIN_CLASS_MEMBERS(FindObjectConfig, FindObjectThread)
+
+
+	AffineEngine *affine;
+// Temporary for affine overlay
+	VFrame *temp;
+	OverlayFrame *overlayer;
+
+	static void draw_pixel(VFrame *frame, int x, int y);
+	static void draw_line(VFrame *frame, int x1, int y1, int x2, int y2);
+	static void draw_rect(VFrame *frame, int x1, int y1, int x2, int y2);
+
+	void grey_crop(unsigned char *dst, 
+		VFrame *src, 
+		int x1, 
+		int y1,
+		int x2,
+		int y2,
+		int dst_w,
+		int dst_h);
+
+
+
+	void process_surf();
+	void process_camshift();
+	void process_blob();
+
+
+
+// clamped coordinates
+	int object_w;
+	int object_h;
+	int object_x1;
+	int object_y1;
+	int object_x2;
+	int object_y2;
+	int scene_w;
+	int scene_h;
+	int scene_x1;
+	int scene_y1;
+	int scene_x2;
+	int scene_y2;
+// input frame size
+	int w, h;
+// clamped layers
+	int object_layer;
+	int scene_layer;
+	int replace_layer;
+
+// Latest coordinates of object in scene
+	int border_x1;
+	int border_y1;
+	int border_x2;
+	int border_y2;
+	int border_x3;
+	int border_y3;
+	int border_x4;
+	int border_y4;
+// Coordinates of object in scene with blending
+	float border_x1_accum;
+	float border_y1_accum;
+	float border_x2_accum;
+	float border_y2_accum;
+	float border_x3_accum;
+	float border_y3_accum;
+	float border_x4_accum;
+	float border_y4_accum;
+	int init_border;
+
+
+	IplImage *object_image;
+	IplImage *scene_image;
+
+
+// Comparison with current object_image
+	unsigned char *prev_object;
+// Quantized sizes
+	int object_image_w;
+	int object_image_h;
+	int scene_image_w;
+	int scene_image_h;
+	CvSeq *object_keypoints;
+	CvSeq *object_descriptors;
+	CvSeq *scene_keypoints;
+	CvSeq *scene_descriptors;
+	CvMemStorage *storage;
+
+// camshift
+// object histogram
+	Mat hist;
+	Rect trackWindow;
+
+
+// Blob
+	int blob_initialized;
+	CvBlobTrackerAutoParam1 blob_param;
+	CvBlobTrackerAuto* blob_pTracker;
+	
+	
+};
+
+PLUGIN_THREAD_HEADER(FindObjectMain, FindObjectThread, FindObjectWindow)
+
+
+
+
+
+
+
+
+
+#endif
+
+
+
+
+
+
diff --git a/plugins/findobject/findobject.inc b/plugins/findobject/findobject.inc
new file mode 100644
index 0000000..c5381a9
--- /dev/null
+++ b/plugins/findobject/findobject.inc
@@ -0,0 +1,30 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 1997-2012 Adam Williams <broadcast at earthling dot net>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+#ifndef FINDOBJECT_INC
+#define FINDOBJECT_INC
+
+
+class FindObjectConfig;
+class FindObjectMain;
+
+
+#endif
diff --git a/plugins/findobject/findobjectwindow.C b/plugins/findobject/findobjectwindow.C
new file mode 100644
index 0000000..3974d35
--- /dev/null
+++ b/plugins/findobject/findobjectwindow.C
@@ -0,0 +1,613 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 1997-2012 Adam Williams <broadcast at earthling dot net>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+#include "bcdisplayinfo.h"
+#include "clip.h"
+#include "language.h"
+#include "findobject.h"
+#include "findobjectwindow.h"
+#include "theme.h"
+
+WINDOW_CLOSE_EVENT(FindObjectWindow)
+
+FindObjectWindow::FindObjectWindow(FindObjectMain *plugin, int x, int y)
+ : BC_Window(plugin->get_gui_string(),
+	x,
+	y,
+ 	300, 
+	550, 
+	300,
+	550,
+	0,
+	0,
+	1)
+{
+	this->plugin = plugin; 
+}
+
+FindObjectWindow::~FindObjectWindow()
+{
+}
+
+void FindObjectWindow::create_objects()
+{
+	int x1 = 10, x = 10, y = 10;
+	int x2 = 310;
+	BC_Title *title;
+
+
+	add_subwindow(title = new BC_Title(x1, 
+		y, 
+		_("Algorithm:")));
+	add_subwindow(algorithm = new FindObjectAlgorithm(plugin, 
+		this,
+		x1 + title->get_w() + 10, 
+		y));
+	algorithm->create_objects();
+	y += algorithm->get_h() + plugin->get_theme()->widget_border;
+
+
+	add_subwindow(title = new BC_Title(x1, 
+		y, 
+		_("Search radius:\n(W/H Percent of image)")));
+	add_subwindow(global_range_w = new FindObjectGlobalRange(plugin, 
+		x1 + title->get_w() + 10, 
+		y,
+		&plugin->config.global_range_w));
+	add_subwindow(global_range_h = new FindObjectGlobalRange(plugin, 
+		x1 + title->get_w() + 10 + global_range_w->get_w(), 
+		y,
+		&plugin->config.global_range_h));
+
+	y += 50;
+	add_subwindow(title = new BC_Title(x1, 
+		y, 
+		_("Object size:\n(W/H Percent of image)")));
+	add_subwindow(global_block_w = new FindObjectBlockSize(plugin, 
+		x1 + title->get_w() + 10, 
+		y,
+		&plugin->config.global_block_w));
+	add_subwindow(global_block_h = new FindObjectBlockSize(plugin, 
+		x1 + title->get_w() + 10 + global_block_w->get_w(), 
+		y,
+		&plugin->config.global_block_h));
+
+	y += 40;
+	add_subwindow(title = new BC_Title(x, y + 10, _("Block X:")));
+	add_subwindow(block_x = new FindObjectBlockCenter(plugin, 
+		this, 
+		x + title->get_w() + 10, 
+		y,
+		&plugin->config.block_x));
+	add_subwindow(block_x_text = new FindObjectBlockCenterText(plugin, 
+		this, 
+		x + title->get_w() + 10 + block_x->get_w() + 10, 
+		y + 10,
+		&plugin->config.block_x));
+	block_x->center_text = block_x_text;
+	block_x_text->center = block_x;
+
+	y += 40;
+	add_subwindow(title = new BC_Title(x, y + 10, _("Block Y:")));
+	add_subwindow(block_y = new FindObjectBlockCenter(plugin, 
+		this, 
+		x + title->get_w() + 10, 
+		y,
+		&plugin->config.block_y));
+	add_subwindow(block_y_text = new FindObjectBlockCenterText(plugin, 
+		this, 
+		x + title->get_w() + 10 + block_y->get_w() + 10, 
+		y + 10,
+		&plugin->config.block_y));
+	block_y->center_text = block_y_text;
+	block_y_text->center = block_y;
+
+
+	y += 40;
+	add_subwindow(draw_keypoints = new FindObjectDrawKeypoints(plugin,
+		this,
+		x,
+		y));
+
+	y += draw_keypoints->get_h() + plugin->get_theme()->widget_border;
+	add_subwindow(draw_border = new FindObjectDrawBorder(plugin,
+		this,
+		x,
+		y));
+
+	y += draw_keypoints->get_h() + plugin->get_theme()->widget_border;
+	add_subwindow(replace_object = new FindObjectReplace(plugin,
+		this,
+		x,
+		y));
+
+	y += draw_keypoints->get_h() + plugin->get_theme()->widget_border;
+	add_subwindow(draw_object_border = new FindObjectDrawObjectBorder(plugin,
+		this,
+		x,
+		y));
+
+
+	y += draw_keypoints->get_h() + plugin->get_theme()->widget_border;
+	add_subwindow(title = new BC_Title(x, y, _("Object layer:")));
+	object_layer = new FindObjectLayer(plugin, 
+		this,
+		x + title->get_w() + 10, 
+		y,
+		&plugin->config.object_layer);
+	object_layer->create_objects();
+	y += object_layer->get_h() + plugin->get_theme()->widget_border;
+
+	add_subwindow(title = new BC_Title(x, y, _("Replacement object layer:")));
+	replace_layer = new FindObjectLayer(plugin, 
+		this,
+		x + title->get_w() + 10, 
+		y,
+		&plugin->config.replace_layer);
+	replace_layer->create_objects();
+	y += replace_layer->get_h() + plugin->get_theme()->widget_border;
+
+	add_subwindow(title = new BC_Title(x, y, _("Output/scene layer:")));
+	scene_layer = new FindObjectLayer(plugin, 
+		this,
+		x + title->get_w() + 10, 
+		y,
+		&plugin->config.scene_layer);
+	scene_layer->create_objects();
+	y += scene_layer->get_h() + plugin->get_theme()->widget_border;
+
+
+	add_subwindow(title = new BC_Title(x, y + 10, _("Object blend amount:")));
+	add_subwindow(blend = new FindObjectBlend(plugin, 
+		x + title->get_w() + plugin->get_theme()->widget_border, 
+		y,
+		&plugin->config.blend));
+	y += blend->get_h();
+
+
+	add_subwindow(title = new BC_Title(x, y + 10, _("Camshift VMIN:")));
+	add_subwindow(vmin = new FindObjectCamParam(plugin, 
+		x + title->get_w() + plugin->get_theme()->widget_border, 
+		y,
+		&plugin->config.vmin));
+	y += vmin->get_h() * 2 / 3;
+
+	add_subwindow(title = new BC_Title(x, y + 10, _("Camshift VMAX:")));
+	add_subwindow(vmax = new FindObjectCamParam(plugin, 
+		x + title->get_w() + vmin->get_w() + plugin->get_theme()->widget_border, 
+		y,
+		&plugin->config.vmax));
+	y += vmin->get_h() * 2 / 3;
+
+	add_subwindow(title = new BC_Title(x, y + 10, _("Camshift SMIN:")));
+	add_subwindow(smin = new FindObjectCamParam(plugin, 
+		x + title->get_w() + plugin->get_theme()->widget_border, 
+		y,
+		&plugin->config.smin));
+	y += vmin->get_h();
+
+
+
+	show_window(1);
+}
+
+
+
+
+
+
+
+FindObjectGlobalRange::FindObjectGlobalRange(FindObjectMain *plugin, 
+	int x, 
+	int y,
+	int *value)
+ : BC_IPot(x, 
+		y, 
+		(int64_t)*value,
+		(int64_t)MIN_RADIUS,
+		(int64_t)MAX_RADIUS)
+{
+	this->plugin = plugin;
+	this->value = value;
+}
+
+
+int FindObjectGlobalRange::handle_event()
+{
+	*value = (int)get_value();
+	plugin->send_configure_change();
+	return 1;
+}
+
+
+
+
+
+FindObjectBlockSize::FindObjectBlockSize(FindObjectMain *plugin, 
+	int x, 
+	int y,
+	float *value)
+ : BC_FPot(x, 
+		y, 
+		(float)*value,
+		(float)MIN_BLOCK,
+		(float)MAX_BLOCK)
+{
+	this->plugin = plugin;
+	this->value = value;
+	set_precision(0.1);
+}
+
+
+
+int FindObjectBlockSize::handle_event()
+{
+	*value = get_value();
+	plugin->send_configure_change();
+	return 1;
+}
+
+
+
+
+
+
+
+FindObjectBlockCenter::FindObjectBlockCenter(FindObjectMain *plugin, 
+	FindObjectWindow *gui,
+	int x, 
+	int y,
+	float *value)
+ : BC_FPot(x,
+ 	y,
+	*value,
+	(float)0, 
+	(float)100)
+{
+	this->plugin = plugin;
+	this->gui = gui;
+	this->value = value;
+	set_precision(0.1);
+}
+
+int FindObjectBlockCenter::handle_event()
+{
+	*value = get_value();
+	center_text->update(*value);
+	plugin->send_configure_change();
+	return 1;
+}
+
+
+
+
+
+
+FindObjectBlockCenterText::FindObjectBlockCenterText(FindObjectMain *plugin, 
+	FindObjectWindow *gui,
+	int x, 
+	int y,
+	float *value)
+ : BC_TextBox(x,
+ 	y,
+	75,
+	1,
+	*value)
+{
+	this->plugin = plugin;
+	this->gui = gui;
+	this->value = value;
+	set_precision(1);
+}
+
+int FindObjectBlockCenterText::handle_event()
+{
+	*value = atof(get_text());
+	center->update(*value);
+	plugin->send_configure_change();
+	return 1;
+}
+
+
+
+
+
+
+
+FindObjectDrawBorder::FindObjectDrawBorder(FindObjectMain *plugin, 
+	FindObjectWindow *gui,
+	int x, 
+	int y)
+ : BC_CheckBox(x,
+ 	y, 
+	plugin->config.draw_border,
+	_("Draw border"))
+{
+	this->gui = gui;
+	this->plugin = plugin;
+}
+
+int FindObjectDrawBorder::handle_event()
+{
+	plugin->config.draw_border = get_value();
+	plugin->send_configure_change();
+	return 1;
+}
+
+
+
+
+
+
+FindObjectDrawKeypoints::FindObjectDrawKeypoints(FindObjectMain *plugin, 
+	FindObjectWindow *gui,
+	int x, 
+	int y)
+ : BC_CheckBox(x,
+ 	y, 
+	plugin->config.draw_keypoints,
+	_("Draw keypoints"))
+{
+	this->gui = gui;
+	this->plugin = plugin;
+}
+
+int FindObjectDrawKeypoints::handle_event()
+{
+	plugin->config.draw_keypoints = get_value();
+	plugin->send_configure_change();
+	return 1;
+}
+
+
+
+
+FindObjectReplace::FindObjectReplace(FindObjectMain *plugin, 
+	FindObjectWindow *gui,
+	int x, 
+	int y)
+ : BC_CheckBox(x,
+ 	y, 
+	plugin->config.replace_object,
+	_("Replace object"))
+{
+	this->gui = gui;
+	this->plugin = plugin;
+}
+
+int FindObjectReplace::handle_event()
+{
+	plugin->config.replace_object = get_value();
+	plugin->send_configure_change();
+	return 1;
+}
+
+
+
+
+
+
+FindObjectDrawObjectBorder::FindObjectDrawObjectBorder(FindObjectMain *plugin, 
+	FindObjectWindow *gui,
+	int x, 
+	int y)
+ : BC_CheckBox(x,
+ 	y, 
+	plugin->config.draw_object_border,
+	_("Draw object border"))
+{
+	this->gui = gui;
+	this->plugin = plugin;
+}
+
+int FindObjectDrawObjectBorder::handle_event()
+{
+	plugin->config.draw_object_border = get_value();
+	plugin->send_configure_change();
+	return 1;
+}
+
+
+
+
+
+
+FindObjectLayer::FindObjectLayer(FindObjectMain *plugin, 
+	FindObjectWindow *gui, 
+	int x, 
+	int y,
+	int *value)
+ : BC_TumbleTextBox(gui,
+ 	*value,
+	MIN_LAYER,
+	MAX_LAYER,
+ 	x, 
+ 	y, 
+	calculate_w(gui))
+{
+	this->plugin = plugin;
+	this->gui = gui;
+	this->value = value;
+}
+
+int FindObjectLayer::handle_event()
+{
+	*value = atoi(get_text());
+	plugin->send_configure_change();
+	return 1;
+}
+
+int FindObjectLayer::calculate_w(FindObjectWindow *gui)
+{
+	int result = 0;
+	result = gui->get_text_width(MEDIUMFONT, "000");
+	return result + 50;
+}
+
+
+
+
+
+
+
+
+FindObjectAlgorithm::FindObjectAlgorithm(FindObjectMain *plugin, FindObjectWindow *gui, int x, int y)
+ : BC_PopupMenu(x, 
+ 	y, 
+	calculate_w(gui),
+	to_text(plugin->config.algorithm))
+{
+	this->plugin = plugin;
+	this->gui = gui;
+}
+
+int FindObjectAlgorithm::handle_event()
+{
+	plugin->config.algorithm = from_text(get_text());
+	plugin->send_configure_change();
+	return 1;
+}
+
+void FindObjectAlgorithm::create_objects()
+{
+	add_item(new BC_MenuItem(to_text(NO_ALGORITHM)));
+#if HAVE_OPENCV_SURF
+	add_item(new BC_MenuItem(to_text(ALGORITHM_SURF)));
+#endif
+	add_item(new BC_MenuItem(to_text(ALGORITHM_CAMSHIFT)));
+	add_item(new BC_MenuItem(to_text(ALGORITHM_BLOB)));
+}
+
+int FindObjectAlgorithm::from_text(char *text)
+{
+	if(!strcmp(text, _("Don't Calculate"))) return NO_ALGORITHM;
+#if HAVE_OPENCV_SURF
+	if(!strcmp(text, _("SURF"))) return ALGORITHM_SURF;
+#endif
+	if(!strcmp(text, _("CAMSHIFT"))) return ALGORITHM_CAMSHIFT;
+	if(!strcmp(text, _("Blob"))) return ALGORITHM_BLOB;
+	return ALGORITHM_CAMSHIFT;
+}
+
+char* FindObjectAlgorithm::to_text(int mode)
+{
+	switch(mode)
+	{
+		case NO_ALGORITHM:
+			return _("Don't Calculate");
+			break;
+#if HAVE_OPENCV_SURF
+		case ALGORITHM_SURF:
+			return _("SURF");
+			break;
+#endif
+		case ALGORITHM_BLOB:
+			return _("Blob");
+			break;
+		case ALGORITHM_CAMSHIFT:
+		default:
+			return _("CAMSHIFT");
+			break;
+	}
+}
+
+int FindObjectAlgorithm::calculate_w(FindObjectWindow *gui)
+{
+	int result = 0;
+	result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(NO_ALGORITHM)));
+#if HAVE_OPENCV_SURF
+	result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(ALGORITHM_SURF)));
+#endif
+	result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(ALGORITHM_CAMSHIFT)));
+	result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(ALGORITHM_BLOB)));
+	return result + 50;
+}
+
+
+
+
+
+
+
+
+FindObjectCamParam::FindObjectCamParam(FindObjectMain *plugin, 
+	int x, 
+	int y,
+	int *value)
+ : BC_IPot(x, 
+		y, 
+		(int64_t)*value,
+		(int64_t)MIN_CAMSHIFT,
+		(int64_t)MAX_CAMSHIFT)
+{
+	this->plugin = plugin;
+	this->value = value;
+}
+
+
+int FindObjectCamParam::handle_event()
+{
+	*value = (int)get_value();
+	plugin->send_configure_change();
+	return 1;
+}
+
+
+
+
+
+
+
+
+FindObjectBlend::FindObjectBlend(FindObjectMain *plugin, 
+	int x, 
+	int y,
+	int *value)
+ : BC_IPot(x, 
+		y, 
+		(int64_t)*value,
+		(int64_t)MIN_BLEND,
+		(int64_t)MAX_BLEND)
+{
+	this->plugin = plugin;
+	this->value = value;
+}
+
+
+int FindObjectBlend::handle_event()
+{
+	*value = (int)get_value();
+	plugin->send_configure_change();
+	return 1;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/findobject/findobjectwindow.h b/plugins/findobject/findobjectwindow.h
new file mode 100644
index 0000000..3c9d89b
--- /dev/null
+++ b/plugins/findobject/findobjectwindow.h
@@ -0,0 +1,237 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 1997-2012 Adam Williams <broadcast at earthling dot net>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+ 
+
+#ifndef FINDOBJECTWINDOW_H
+#define FINDOBJECTWINDOW_H
+
+#include "guicast.h"
+#include "findobject.inc"
+
+class FindObjectLayer : public BC_TumbleTextBox
+{
+public:
+	FindObjectLayer(FindObjectMain *plugin, 
+		FindObjectWindow *gui, 
+		int x, 
+		int y,
+		int *value);
+	int handle_event();
+	static int calculate_w(FindObjectWindow *gui);
+	FindObjectMain *plugin;
+	FindObjectWindow *gui;
+	int *value;
+};
+
+class FindObjectGlobalRange : public BC_IPot
+{
+public:
+	FindObjectGlobalRange(FindObjectMain *plugin, 
+		int x, 
+		int y,
+		int *value);
+	int handle_event();
+	FindObjectMain *plugin;
+	int *value;
+};
+
+class FindObjectBlockSize : public BC_FPot
+{
+public:
+	FindObjectBlockSize(FindObjectMain *plugin, 
+		int x, 
+		int y,
+		float *value);
+	int handle_event();
+	FindObjectMain *plugin;
+	float *value;
+};
+
+class FindObjectBlockCenterText;
+
+class FindObjectBlockCenter : public BC_FPot
+{
+public:
+	FindObjectBlockCenter(FindObjectMain *plugin, 
+		FindObjectWindow *gui,
+		int x, 
+		int y,
+		float *value);
+	int handle_event();
+	FindObjectWindow *gui;
+	FindObjectMain *plugin;
+	FindObjectBlockCenterText *center_text;
+	float *value;
+};
+
+class FindObjectBlockCenterText : public BC_TextBox
+{
+public:
+	FindObjectBlockCenterText(FindObjectMain *plugin, 
+		FindObjectWindow *gui,
+		int x, 
+		int y,
+		float *value);
+	int handle_event();
+	FindObjectWindow *gui;
+	FindObjectMain *plugin;
+	FindObjectBlockCenter *center;
+	float *value;
+};
+
+
+
+class FindObjectDrawBorder : public BC_CheckBox
+{
+public:
+	FindObjectDrawBorder(FindObjectMain *plugin, 
+		FindObjectWindow *gui,
+		int x, 
+		int y);
+	int handle_event();
+	FindObjectMain *plugin;
+	FindObjectWindow *gui;
+};
+
+class FindObjectDrawKeypoints : public BC_CheckBox
+{
+public:
+	FindObjectDrawKeypoints(FindObjectMain *plugin, 
+		FindObjectWindow *gui,
+		int x, 
+		int y);
+	int handle_event();
+	FindObjectMain *plugin;
+	FindObjectWindow *gui;
+};
+
+class FindObjectReplace : public BC_CheckBox
+{
+public:
+	FindObjectReplace(FindObjectMain *plugin, 
+		FindObjectWindow *gui,
+		int x, 
+		int y);
+	int handle_event();
+	FindObjectMain *plugin;
+	FindObjectWindow *gui;
+};
+
+
+class FindObjectDrawObjectBorder : public BC_CheckBox
+{
+public:
+	FindObjectDrawObjectBorder(FindObjectMain *plugin, 
+		FindObjectWindow *gui,
+		int x, 
+		int y);
+	int handle_event();
+	FindObjectMain *plugin;
+	FindObjectWindow *gui;
+};
+
+
+
+
+class FindObjectAlgorithm : public BC_PopupMenu
+{
+public:
+	FindObjectAlgorithm(FindObjectMain *plugin, 
+		FindObjectWindow *gui, 
+		int x, 
+		int y);
+	int handle_event();
+	void create_objects();
+	static int calculate_w(FindObjectWindow *gui);
+	static int from_text(char *text);
+	static char* to_text(int mode);
+	FindObjectMain *plugin;
+	FindObjectWindow *gui;
+};
+
+
+class FindObjectCamParam : public BC_IPot
+{
+public:
+	FindObjectCamParam(FindObjectMain *plugin, 
+		int x, 
+		int y,
+		int *value);
+	int handle_event();
+	FindObjectMain *plugin;
+	int *value;
+};
+
+
+class FindObjectBlend : public BC_IPot
+{
+public:
+	FindObjectBlend(FindObjectMain *plugin, 
+		int x, 
+		int y,
+		int *value);
+	int handle_event();
+	FindObjectMain *plugin;
+	int *value;
+};
+
+
+class FindObjectWindow : public BC_Window
+{
+public:
+	FindObjectWindow(FindObjectMain *plugin, int x, int y);
+	~FindObjectWindow();
+
+	void create_objects();
+	int close_event();
+	char* get_radius_title();
+
+	FindObjectGlobalRange *global_range_w;
+	FindObjectGlobalRange *global_range_h;
+	FindObjectBlockSize *global_block_w;
+	FindObjectBlockSize *global_block_h;
+	FindObjectBlockCenter *block_x;
+	FindObjectBlockCenter *block_y;
+	FindObjectBlockCenterText *block_x_text;
+	FindObjectBlockCenterText *block_y_text;
+	FindObjectDrawKeypoints *draw_keypoints;
+	FindObjectDrawBorder *draw_border;
+	FindObjectReplace *replace_object;
+	FindObjectDrawObjectBorder *draw_object_border;
+	FindObjectLayer *object_layer;
+	FindObjectLayer *scene_layer;
+	FindObjectLayer *replace_layer;
+	FindObjectAlgorithm *algorithm;
+	FindObjectCamParam *vmin;
+	FindObjectCamParam *vmax;
+	FindObjectCamParam *smin;
+	FindObjectBlend *blend;
+	FindObjectMain *plugin;
+};
+
+
+
+
+
+#endif // FINDOBJECTWINDOW_H
+
+
+
diff --git a/plugins/findobject/findobjectwindow.inc b/plugins/findobject/findobjectwindow.inc
new file mode 100644
index 0000000..a266383
--- /dev/null
+++ b/plugins/findobject/findobjectwindow.inc
@@ -0,0 +1,28 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 1997-2012 Adam Williams <broadcast at earthling dot net>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+#ifndef FINDOBJECTWINDOW_INC
+#define FINDOBJECTWINDOW_INC
+
+class FindObjectWindow;
+class FindObjectThread;
+
+#endif
diff --git a/plugins/findobject/surfscan.C b/plugins/findobject/surfscan.C
new file mode 100644
index 0000000..7511792
--- /dev/null
+++ b/plugins/findobject/surfscan.C
@@ -0,0 +1,268 @@
+#include "surfscan.h"
+
+// Needed with OpenCV version 2.4.8 
+#include "opencv2/legacy/compat.hpp"
+
+#include "opencv2/calib3d/calib3d.hpp"
+#include "opencv2/objdetect/objdetect.hpp"
+#include "opencv2/features2d/features2d.hpp"
+
+
+#include <iostream>
+#include <vector>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+
+
+using namespace std;
+
+
+// define whether to use approximate nearest-neighbor search
+#define USE_FLANN
+
+
+double
+compareSURFDescriptors( const float* d1, const float* d2, double best, int length )
+{
+    double total_cost = 0;
+    assert( length % 4 == 0 );
+    for( int i = 0; i < length; i += 4 )
+    {
+        double t0 = d1[i  ] - d2[i  ];
+        double t1 = d1[i+1] - d2[i+1];
+        double t2 = d1[i+2] - d2[i+2];
+        double t3 = d1[i+3] - d2[i+3];
+        total_cost += t0*t0 + t1*t1 + t2*t2 + t3*t3;
+        if( total_cost > best )
+            break;
+    }
+    return total_cost;
+}
+
+
+int
+naiveNearestNeighbor( const float* vec, int laplacian,
+                      const CvSeq* model_keypoints,
+                      const CvSeq* model_descriptors )
+{
+    int length = (int)(model_descriptors->elem_size/sizeof(float));
+    int i, neighbor = -1;
+    double d, dist1 = 1e6, dist2 = 1e6;
+    CvSeqReader reader, kreader;
+    cvStartReadSeq( model_keypoints, &kreader, 0 );
+    cvStartReadSeq( model_descriptors, &reader, 0 );
+
+    for( i = 0; i < model_descriptors->total; i++ )
+    {
+        const CvSURFPoint* kp = (const CvSURFPoint*)kreader.ptr;
+        const float* mvec = (const float*)reader.ptr;
+    	CV_NEXT_SEQ_ELEM( kreader.seq->elem_size, kreader );
+        CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
+        if( laplacian != kp->laplacian )
+            continue;
+        d = compareSURFDescriptors( vec, mvec, dist2, length );
+        if( d < dist1 )
+        {
+            dist2 = dist1;
+            dist1 = d;
+            neighbor = i;
+        }
+        else if ( d < dist2 )
+            dist2 = d;
+    }
+    if ( dist1 < 0.6*dist2 )
+        return neighbor;
+    return -1;
+}
+
+void
+findPairs( const CvSeq* objectKeypoints, const CvSeq* objectDescriptors,
+           const CvSeq* imageKeypoints, const CvSeq* imageDescriptors, vector<int>& ptpairs )
+{
+    int i;
+    CvSeqReader reader, kreader;
+    cvStartReadSeq( objectKeypoints, &kreader );
+    cvStartReadSeq( objectDescriptors, &reader );
+    ptpairs.clear();
+
+    for( i = 0; i < objectDescriptors->total; i++ )
+    {
+        const CvSURFPoint* kp = (const CvSURFPoint*)kreader.ptr;
+        const float* descriptor = (const float*)reader.ptr;
+        CV_NEXT_SEQ_ELEM( kreader.seq->elem_size, kreader );
+        CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
+        int nearest_neighbor = naiveNearestNeighbor( descriptor, kp->laplacian, imageKeypoints, imageDescriptors );
+        if( nearest_neighbor >= 0 )
+        {
+            ptpairs.push_back(i);
+            ptpairs.push_back(nearest_neighbor);
+        }
+    }
+}
+
+
+void
+flannFindPairs( const CvSeq*, 
+	const CvSeq* objectDescriptors,
+    const CvSeq*, 
+	const CvSeq* imageDescriptors, 
+	vector<int>& ptpairs )
+{
+	int length = (int)(objectDescriptors->elem_size/sizeof(float));
+
+    cv::Mat m_object(objectDescriptors->total, length, CV_32F);
+	cv::Mat m_image(imageDescriptors->total, length, CV_32F);
+
+
+	// copy descriptors
+    CvSeqReader obj_reader;
+	float* obj_ptr = m_object.ptr<float>(0);
+    cvStartReadSeq( objectDescriptors, &obj_reader );
+    for(int i = 0; i < objectDescriptors->total; i++ )
+    {
+        const float* descriptor = (const float*)obj_reader.ptr;
+        CV_NEXT_SEQ_ELEM( obj_reader.seq->elem_size, obj_reader );
+        memcpy(obj_ptr, descriptor, length*sizeof(float));
+        obj_ptr += length;
+    }
+    CvSeqReader img_reader;
+	float* img_ptr = m_image.ptr<float>(0);
+    cvStartReadSeq( imageDescriptors, &img_reader );
+    for(int i = 0; i < imageDescriptors->total; i++ )
+    {
+        const float* descriptor = (const float*)img_reader.ptr;
+        CV_NEXT_SEQ_ELEM( img_reader.seq->elem_size, img_reader );
+        memcpy(img_ptr, descriptor, length*sizeof(float));
+        img_ptr += length;
+    }
+
+    // find nearest neighbors using FLANN
+    cv::Mat m_indices(objectDescriptors->total, 2, CV_32S);
+    cv::Mat m_dists(objectDescriptors->total, 2, CV_32F);
+    cv::flann::Index flann_index(m_image, cv::flann::KDTreeIndexParams(4));  // using 4 randomized kdtrees
+    flann_index.knnSearch(m_object, m_indices, m_dists, 2, cv::flann::SearchParams(64) ); // maximum number of leafs checked
+
+    int* indices_ptr = m_indices.ptr<int>(0);
+    float* dists_ptr = m_dists.ptr<float>(0);
+//printf("flannFindPairs %d m_indices.rows=%d\n", __LINE__, m_indices.rows);
+    for (int i = 0; i < m_indices.rows; ++i) 
+	{
+//printf("flannFindPairs %d dists=%f %f\n", __LINE__, dists_ptr[2 * i], 0.6 * dists_ptr[2 * i + 1]);
+    	if (dists_ptr[2 * i] < 0.6 * dists_ptr[2 * i + 1]) 
+		{
+//printf("flannFindPairs %d pairs=%d\n", __LINE__, ptpairs.size());
+    		ptpairs.push_back(i);
+    		ptpairs.push_back(indices_ptr[2*i]);
+    	}
+    }
+}
+
+
+/* a rough implementation for object location */
+int
+locatePlanarObject(const CvSeq* objectKeypoints, 
+	const CvSeq* objectDescriptors,
+    const CvSeq* imageKeypoints, 
+	const CvSeq* imageDescriptors,
+    const CvPoint src_corners[4], 
+	CvPoint dst_corners[4],
+	int *(*point_pairs),
+	int (*total_pairs))
+{
+    double h[9];
+    CvMat _h = cvMat(3, 3, CV_64F, h);
+    vector<int> ptpairs;
+    vector<CvPoint2D32f> pt1, pt2;
+    CvMat _pt1, _pt2;
+    int i, n;
+	
+	(*point_pairs) = 0;
+	(*total_pairs) = 0;
+
+#ifdef USE_FLANN
+    flannFindPairs( objectKeypoints, objectDescriptors, imageKeypoints, imageDescriptors, ptpairs );
+#else
+    findPairs( objectKeypoints, objectDescriptors, imageKeypoints, imageDescriptors, ptpairs );
+#endif
+
+
+// Store keypoints
+	(*point_pairs) = (int*)calloc(ptpairs.size(), sizeof(int));
+	(*total_pairs) = ptpairs.size() / 2;
+	
+	
+    for(int i = 0; i < (int)ptpairs.size(); i++)
+    {
+		(*point_pairs)[i] = ptpairs[i];
+    }
+
+
+
+    n = (int)(ptpairs.size()/2);
+    if( n < 4 )
+        return 0;
+
+    pt1.resize(n);
+    pt2.resize(n);
+    for( i = 0; i < n; i++ )
+    {
+        pt1[i] = ((CvSURFPoint*)cvGetSeqElem(objectKeypoints,ptpairs[i*2]))->pt;
+        pt2[i] = ((CvSURFPoint*)cvGetSeqElem(imageKeypoints,ptpairs[i*2+1]))->pt;
+    }
+
+    _pt1 = cvMat(1, n, CV_32FC2, &pt1[0] );
+    _pt2 = cvMat(1, n, CV_32FC2, &pt2[0] );
+    if( !cvFindHomography( &_pt1, &_pt2, &_h, CV_RANSAC, 5 ))
+        return 0;
+
+    for( i = 0; i < 4; i++ )
+    {
+        double x = src_corners[i].x, y = src_corners[i].y;
+        double Z = 1./(h[6]*x + h[7]*y + h[8]);
+        double X = (h[0]*x + h[1]*y + h[2])*Z;
+        double Y = (h[3]*x + h[4]*y + h[5])*Z;
+        dst_corners[i] = cvPoint(cvRound(X), cvRound(Y));
+    }
+
+    return 1;
+}
+
+
+void locate_points(const CvSeq* objectKeypoints, 
+	const CvSeq* objectDescriptors,
+    const CvSeq* imageKeypoints, 
+	const CvSeq* imageDescriptors,
+	int *(*points),
+	int *(*sizes),
+	int (*total_points))
+{
+	vector<int> ptpairs;
+	
+#ifdef USE_FLANN
+    flannFindPairs( objectKeypoints, objectDescriptors, imageKeypoints, imageDescriptors, ptpairs );
+#else
+    findPairs( objectKeypoints, objectDescriptors, imageKeypoints, imageDescriptors, ptpairs );
+#endif
+
+	(*points) = (int*)calloc(ptpairs.size(), sizeof(int) * 2);
+	(*sizes) = (int*)calloc(ptpairs.size(), sizeof(int));
+	(*total_points) = ptpairs.size();
+	
+	
+    for(int i = 0; i < (int)ptpairs.size(); i += 2 )
+    {
+        CvSURFPoint* r1 = (CvSURFPoint*)cvGetSeqElem( objectKeypoints, ptpairs[i] );
+        CvSURFPoint* r2 = (CvSURFPoint*)cvGetSeqElem( imageKeypoints, ptpairs[i+1] );
+        
+		
+		(*points)[i * 2] = r2->pt.x;
+		(*points)[i * 2 + 1] = r2->pt.y;
+		(*sizes)[i] = r2->size;
+    }
+}
+
+
+
+
diff --git a/plugins/findobject/surfscan.h b/plugins/findobject/surfscan.h
new file mode 100644
index 0000000..24b4685
--- /dev/null
+++ b/plugins/findobject/surfscan.h
@@ -0,0 +1,46 @@
+#ifndef SURFSCAN_H
+#define SURFSCAN_H
+
+
+// Wrapper & extra functions for object tracking
+
+
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "opencv2/core/core_c.h"
+
+
+int locatePlanarObject(const CvSeq* objectKeypoints, 
+	const CvSeq* objectDescriptors,
+    const CvSeq* imageKeypoints, 
+	const CvSeq* imageDescriptors,
+    const CvPoint src_corners[4], 
+	CvPoint dst_corners[4],
+	int *(*point_pairs),
+	int (*total_pairs));
+
+void locate_points(const CvSeq* objectKeypoints, 
+	const CvSeq* objectDescriptors,
+    const CvSeq* imageKeypoints, 
+	const CvSeq* imageDescriptors,
+	int *(*points),
+	int *(*sizes),
+	int *total_points);
+
+
+#ifdef __cplusplus
+
+}
+#endif
+
+
+
+
+#endif
+
+


hooks/post-receive
-- 
CinelerraCV.git (CinelerraCV)

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "CinelerraCV.git" (CinelerraCV).



More information about the cinelerra-commits mailing list